├── .codecov.yml ├── .github ├── dependabot.yml └── workflows │ ├── linter.yml │ └── tests.yml ├── .gitignore ├── .golangci.yml ├── AUTHORS ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── example ├── actionpermissions │ └── main.go ├── appengine │ ├── app.go │ └── app.yaml ├── basicauth │ └── main.go ├── codespaces │ ├── newreposecretwithxcrypto │ │ └── main.go │ └── newusersecretwithxcrypto │ │ └── main.go ├── commitpr │ └── main.go ├── go.mod ├── go.sum ├── listenvironments │ └── main.go ├── migrations │ └── main.go ├── newfilewithappauth │ └── main.go ├── newrepo │ └── main.go ├── newreposecretwithlibsodium │ ├── go.mod │ ├── go.sum │ └── main.go ├── newreposecretwithxcrypto │ └── main.go ├── ratelimit │ └── main.go ├── simple │ └── main.go ├── tokenauth │ └── main.go ├── topics │ └── main.go └── verifyartifact │ ├── main.go │ └── trusted-root-public-good.json ├── github ├── actions.go ├── actions_artifacts.go ├── actions_artifacts_test.go ├── actions_cache.go ├── actions_cache_test.go ├── actions_oidc.go ├── actions_oidc_test.go ├── actions_permissions_enterprise.go ├── actions_permissions_enterprise_test.go ├── actions_permissions_orgs.go ├── actions_permissions_orgs_test.go ├── actions_required_workflows.go ├── actions_required_workflows_test.go ├── actions_runner_groups.go ├── actions_runner_groups_test.go ├── actions_runners.go ├── actions_runners_test.go ├── actions_secrets.go ├── actions_secrets_test.go ├── actions_variables.go ├── actions_variables_test.go ├── actions_workflow_jobs.go ├── actions_workflow_jobs_test.go ├── actions_workflow_runs.go ├── actions_workflow_runs_test.go ├── actions_workflows.go ├── actions_workflows_test.go ├── activity.go ├── activity_events.go ├── activity_events_test.go ├── activity_notifications.go ├── activity_notifications_test.go ├── activity_star.go ├── activity_star_test.go ├── activity_test.go ├── activity_watching.go ├── activity_watching_test.go ├── admin.go ├── admin_orgs.go ├── admin_orgs_test.go ├── admin_stats.go ├── admin_stats_test.go ├── admin_test.go ├── admin_users.go ├── admin_users_test.go ├── apps.go ├── apps_hooks.go ├── apps_hooks_deliveries.go ├── apps_hooks_deliveries_test.go ├── apps_hooks_test.go ├── apps_installation.go ├── apps_installation_test.go ├── apps_manifest.go ├── apps_manifest_test.go ├── apps_marketplace.go ├── apps_marketplace_test.go ├── apps_test.go ├── attestations.go ├── authorizations.go ├── authorizations_test.go ├── billing.go ├── billing_test.go ├── checks.go ├── checks_test.go ├── code_scanning.go ├── code_scanning_test.go ├── codesofconduct.go ├── codesofconduct_test.go ├── codespaces.go ├── codespaces_secrets.go ├── codespaces_secrets_test.go ├── codespaces_test.go ├── copilot.go ├── copilot_test.go ├── dependabot.go ├── dependabot_alerts.go ├── dependabot_alerts_test.go ├── dependabot_secrets.go ├── dependabot_secrets_test.go ├── dependency_graph.go ├── dependency_graph_snapshots.go ├── dependency_graph_snapshots_test.go ├── dependency_graph_test.go ├── doc.go ├── emojis.go ├── emojis_test.go ├── enterprise.go ├── enterprise_actions_runner_groups.go ├── enterprise_actions_runner_groups_test.go ├── enterprise_actions_runners.go ├── enterprise_actions_runners_test.go ├── enterprise_audit_log.go ├── enterprise_audit_log_test.go ├── enterprise_code_security_and_analysis.go ├── enterprise_code_security_and_analysis_test.go ├── enterprise_properties.go ├── enterprise_properties_test.go ├── event.go ├── event_test.go ├── event_types.go ├── event_types_test.go ├── examples_test.go ├── gen-accessors.go ├── gen-stringify-test.go ├── gists.go ├── gists_comments.go ├── gists_comments_test.go ├── gists_test.go ├── git.go ├── git_blobs.go ├── git_blobs_test.go ├── git_commits.go ├── git_commits_test.go ├── git_refs.go ├── git_refs_test.go ├── git_tags.go ├── git_tags_test.go ├── git_trees.go ├── git_trees_test.go ├── github-accessors.go ├── github-accessors_test.go ├── github-stringify_test.go ├── github.go ├── github_test.go ├── gitignore.go ├── gitignore_test.go ├── interactions.go ├── interactions_orgs.go ├── interactions_orgs_test.go ├── interactions_repos.go ├── interactions_repos_test.go ├── interactions_test.go ├── issue_import.go ├── issue_import_test.go ├── issues.go ├── issues_assignees.go ├── issues_assignees_test.go ├── issues_comments.go ├── issues_comments_test.go ├── issues_events.go ├── issues_events_test.go ├── issues_labels.go ├── issues_labels_test.go ├── issues_milestones.go ├── issues_milestones_test.go ├── issues_test.go ├── issues_timeline.go ├── issues_timeline_test.go ├── licenses.go ├── licenses_test.go ├── markdown.go ├── markdown_test.go ├── messages.go ├── messages_test.go ├── meta.go ├── meta_test.go ├── migrations.go ├── migrations_source_import.go ├── migrations_source_import_test.go ├── migrations_test.go ├── migrations_user.go ├── migrations_user_test.go ├── orgs.go ├── orgs_actions_allowed.go ├── orgs_actions_allowed_test.go ├── orgs_actions_permissions.go ├── orgs_actions_permissions_test.go ├── orgs_attestations.go ├── orgs_attestations_test.go ├── orgs_audit_log.go ├── orgs_audit_log_test.go ├── orgs_codesecurity_configurations.go ├── orgs_codesecurity_configurations_test.go ├── orgs_credential_authorizations.go ├── orgs_credential_authorizations_test.go ├── orgs_custom_repository_roles.go ├── orgs_custom_repository_roles_test.go ├── orgs_hooks.go ├── orgs_hooks_configuration.go ├── orgs_hooks_configuration_test.go ├── orgs_hooks_deliveries.go ├── orgs_hooks_deliveries_test.go ├── orgs_hooks_test.go ├── orgs_members.go ├── orgs_members_test.go ├── orgs_organization_roles.go ├── orgs_organization_roles_test.go ├── orgs_outside_collaborators.go ├── orgs_outside_collaborators_test.go ├── orgs_packages.go ├── orgs_packages_test.go ├── orgs_personal_access_tokens.go ├── orgs_personal_access_tokens_test.go ├── orgs_properties.go ├── orgs_properties_test.go ├── orgs_rules.go ├── orgs_rules_test.go ├── orgs_security_managers.go ├── orgs_security_managers_test.go ├── orgs_test.go ├── orgs_users_blocking.go ├── orgs_users_blocking_test.go ├── packages.go ├── packages_test.go ├── pulls.go ├── pulls_comments.go ├── pulls_comments_test.go ├── pulls_reviewers.go ├── pulls_reviewers_test.go ├── pulls_reviews.go ├── pulls_reviews_test.go ├── pulls_test.go ├── pulls_threads.go ├── pulls_threads_test.go ├── rate_limit.go ├── rate_limit_test.go ├── reactions.go ├── reactions_test.go ├── repos.go ├── repos_actions_access.go ├── repos_actions_access_test.go ├── repos_actions_allowed.go ├── repos_actions_allowed_test.go ├── repos_actions_permissions.go ├── repos_actions_permissions_test.go ├── repos_attestations.go ├── repos_attestations_test.go ├── repos_autolinks.go ├── repos_autolinks_test.go ├── repos_codeowners.go ├── repos_codeowners_test.go ├── repos_collaborators.go ├── repos_collaborators_test.go ├── repos_comments.go ├── repos_comments_test.go ├── repos_commits.go ├── repos_commits_test.go ├── repos_community_health.go ├── repos_community_health_test.go ├── repos_contents.go ├── repos_contents_test.go ├── repos_deployment_branch_policies.go ├── repos_deployment_branch_policies_test.go ├── repos_deployment_protection_rules.go ├── repos_deployment_protection_rules_test.go ├── repos_deployments.go ├── repos_deployments_test.go ├── repos_environments.go ├── repos_environments_test.go ├── repos_forks.go ├── repos_forks_test.go ├── repos_hooks.go ├── repos_hooks_configuration.go ├── repos_hooks_configuration_test.go ├── repos_hooks_deliveries.go ├── repos_hooks_deliveries_test.go ├── repos_hooks_test.go ├── repos_invitations.go ├── repos_invitations_test.go ├── repos_keys.go ├── repos_keys_test.go ├── repos_lfs.go ├── repos_lfs_test.go ├── repos_merging.go ├── repos_merging_test.go ├── repos_pages.go ├── repos_pages_test.go ├── repos_prereceive_hooks.go ├── repos_prereceive_hooks_test.go ├── repos_properties.go ├── repos_properties_test.go ├── repos_releases.go ├── repos_releases_test.go ├── repos_rules.go ├── repos_rules_test.go ├── repos_stats.go ├── repos_stats_test.go ├── repos_statuses.go ├── repos_statuses_test.go ├── repos_tags.go ├── repos_tags_test.go ├── repos_test.go ├── repos_traffic.go ├── repos_traffic_test.go ├── scim.go ├── scim_test.go ├── search.go ├── search_test.go ├── secret_scanning.go ├── secret_scanning_test.go ├── security_advisories.go ├── security_advisories_test.go ├── strings.go ├── strings_test.go ├── teams.go ├── teams_discussion_comments.go ├── teams_discussion_comments_test.go ├── teams_discussions.go ├── teams_discussions_test.go ├── teams_members.go ├── teams_members_test.go ├── teams_test.go ├── timestamp.go ├── timestamp_test.go ├── users.go ├── users_administration.go ├── users_administration_test.go ├── users_attestations.go ├── users_attestations_test.go ├── users_blocking.go ├── users_blocking_test.go ├── users_emails.go ├── users_emails_test.go ├── users_followers.go ├── users_followers_test.go ├── users_gpg_keys.go ├── users_gpg_keys_test.go ├── users_keys.go ├── users_keys_test.go ├── users_packages.go ├── users_packages_test.go ├── users_ssh_signing_keys.go ├── users_ssh_signing_keys_test.go ├── users_test.go ├── with_appengine.go └── without_appengine.go ├── go.mod ├── go.sum ├── openapi_operations.yaml ├── scrape ├── README.md ├── apps.go ├── apps_test.go ├── example │ └── scrape │ │ └── main.go ├── forms.go ├── forms_test.go ├── go.mod ├── go.sum ├── payment.go ├── scrape.go ├── scrape_test.go └── testdata │ ├── access-restrictions-disabled.html │ └── access-restrictions-enabled.html ├── script ├── fmt.sh ├── generate.sh ├── lint.sh ├── metadata.sh └── test.sh ├── test ├── README.md ├── fields │ └── fields.go └── integration │ ├── activity_test.go │ ├── audit_log_test.go │ ├── authorizations_test.go │ ├── doc.go │ ├── github_test.go │ ├── issues_test.go │ ├── misc_test.go │ ├── pulls_test.go │ ├── repos_test.go │ └── users_test.go └── tools ├── go.mod ├── go.sum └── metadata ├── main.go ├── main_test.go ├── metadata.go ├── metadata_test.go ├── openapi.go └── testdata ├── format └── openapi_operations.yaml ├── golden ├── TestFormat │ └── openapi_operations.yaml ├── TestUpdateGo │ └── valid │ │ └── github │ │ └── a.go └── TestUpdateOpenAPI │ └── openapi_operations.yaml ├── unused ├── github │ └── a.go └── openapi_operations.yaml ├── update-go ├── invalid │ ├── github │ │ └── a.go │ └── openapi_operations.yaml └── valid │ ├── github │ ├── a.go │ └── ignoreme.txt │ └── openapi_operations.yaml └── update-openapi └── openapi_operations.yaml /.codecov.yml: -------------------------------------------------------------------------------- 1 | ignore: 2 | # ignore auto-generated code 3 | - "github/github-accessors.go" 4 | # ignore experimental scrape package 5 | - "scrape" 6 | # ignore tools 7 | - "tools" 8 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: gomod 4 | directory: / 5 | schedule: 6 | interval: weekly 7 | - package-ecosystem: gomod 8 | directory: scrape 9 | schedule: 10 | interval: weekly 11 | - package-ecosystem: gomod 12 | directory: tools 13 | schedule: 14 | interval: weekly 15 | - package-ecosystem: github-actions 16 | directory: / 17 | schedule: 18 | interval: weekly 19 | -------------------------------------------------------------------------------- /.github/workflows/linter.yml: -------------------------------------------------------------------------------- 1 | on: [push, pull_request] 2 | name: linter 3 | 4 | permissions: 5 | contents: read 6 | 7 | jobs: 8 | lint: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v4 12 | - uses: actions/setup-go@v5 13 | with: 14 | go-version: 1.x 15 | cache-dependency-path: "**/go.sum" 16 | - run: script/lint.sh 17 | env: 18 | CHECK_GITHUB_OPENAPI: 1 19 | GITHUB_TOKEN: ${{ github.token }} 20 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | concurrency: 2 | group: ${{ github.repository }}-${{ github.workflow }}-${{ github.ref }} 3 | cancel-in-progress: true 4 | 5 | on: 6 | push: 7 | branches: 8 | - master 9 | pull_request: 10 | branches: 11 | - master 12 | 13 | name: tests 14 | env: 15 | GO111MODULE: on 16 | 17 | permissions: 18 | contents: read 19 | 20 | jobs: 21 | test: 22 | defaults: 23 | run: 24 | shell: bash 25 | strategy: 26 | matrix: 27 | go-version: [1.x, 1.22.x] 28 | platform: [ubuntu-latest] 29 | include: 30 | # include windows, but only with the latest Go version, since there 31 | # is very little in the library that is platform specific 32 | - go-version: 1.x 33 | platform: windows-latest 34 | 35 | # only update test coverage stats with the most recent go version on linux 36 | - go-version: 1.x 37 | platform: ubuntu-latest 38 | update-coverage: true 39 | runs-on: ${{ matrix.platform }} 40 | 41 | steps: 42 | - uses: actions/setup-go@v5 43 | with: 44 | go-version: ${{ matrix.go-version }} 45 | - uses: actions/checkout@v4 46 | 47 | # Get values for cache paths to be used in later steps 48 | - id: cache-paths 49 | run: | 50 | echo "go-cache=$(go env GOCACHE)" >> $GITHUB_OUTPUT 51 | echo "go-mod-cache=$(go env GOMODCACHE)" >> $GITHUB_OUTPUT 52 | 53 | - name: Cache go modules 54 | uses: actions/cache@v4 55 | with: 56 | path: | 57 | ${{ steps.cache-paths.outputs.go-cache }} 58 | ${{ steps.cache-paths.outputs.go-mod-cache }} 59 | key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} 60 | restore-keys: ${{ runner.os }}-go- 61 | 62 | - name: Run go test 63 | run: | 64 | if [ -n "${{ matrix.update-coverage }}" ]; then 65 | script/test.sh -race -covermode atomic -coverprofile coverage.txt ./... 66 | exit 67 | fi 68 | script/test.sh -race -covermode atomic ./... 69 | 70 | - name: Ensure integration tests build 71 | # don't actually run tests since they hit live GitHub API 72 | run: go test -v -tags=integration -run=^$ ./test/integration 73 | 74 | - name: Upload coverage to Codecov 75 | if: ${{ matrix.update-coverage }} 76 | uses: codecov/codecov-action@1e68e06f1dbfde0e4cefc87efeba9e4643565303 #v5.1.2 77 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.sh 2 | !/script/*.sh 3 | *.test 4 | .*.local 5 | coverage.out 6 | /bin 7 | # intellij files 8 | .idea/ 9 | vendor/ 10 | .DS_Store 11 | .vscode 12 | # vim temp files 13 | *.swp 14 | 15 | # goenv local version. See https://github.com/syndbg/goenv/blob/master/COMMANDS.md#goenv-local for more info. 16 | .go-version 17 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | run: 2 | build-tags: 3 | - integration 4 | timeout: 10m 5 | linters: 6 | enable: 7 | - canonicalheader 8 | - dogsled 9 | - dupl 10 | - gci 11 | - gocritic 12 | - godot 13 | - gofmt 14 | - goimports 15 | - gosec 16 | - misspell 17 | - nakedret 18 | - perfsprint 19 | - paralleltest 20 | - revive 21 | - stylecheck 22 | - tparallel 23 | - unconvert 24 | - unparam 25 | - whitespace 26 | linters-settings: 27 | gocritic: 28 | disable-all: true 29 | enabled-checks: 30 | - commentedOutCode 31 | - commentFormatting 32 | gosec: 33 | excludes: 34 | # duplicates errcheck 35 | - G104 36 | # int(os.Stdin.Fd()) 37 | - G115 38 | perfsprint: 39 | errorf: true 40 | strconcat: false 41 | revive: 42 | rules: 43 | - name: blank-imports 44 | - name: bool-literal-in-expr 45 | - name: context-as-argument 46 | - name: context-keys-type 47 | - name: dot-imports 48 | - name: early-return 49 | - name: empty-block 50 | - name: error-naming 51 | - name: error-return 52 | - name: error-strings 53 | - name: errorf 54 | - name: filename-format 55 | arguments: 56 | - "^[_a-z][_a-z0-9]*.go$" 57 | - name: increment-decrement 58 | - name: indent-error-flow 59 | - name: package-comments 60 | - name: range 61 | - name: receiver-naming 62 | - name: redefines-builtin-id 63 | - name: superfluous-else 64 | - name: time-equal 65 | - name: time-naming 66 | - name: unexported-naming 67 | - name: unexported-return 68 | - name: unreachable-code 69 | - name: var-declaration 70 | - name: var-naming 71 | issues: 72 | exclude-use-default: false 73 | exclude-rules: 74 | - linters: 75 | - dupl 76 | - unparam 77 | - gosec 78 | - dogsled 79 | path: _test\.go 80 | 81 | # We need to pass nil Context in order to test DoBare erroring on nil ctx. 82 | - linters: [ staticcheck ] 83 | text: 'SA1012: do not pass a nil Context' 84 | path: _test\.go 85 | 86 | # We need to use sha1 for validating signatures 87 | - linters: [ gosec ] 88 | text: 'G505: Blocklisted import crypto/sha1: weak cryptographic primitive' 89 | 90 | # This is adapted from golangci-lint's default exclusions. It disables linting for error checks on 91 | # os.RemoveAll, fmt.Fprint*, fmt.Scanf, and any function ending in "Close". 92 | - linters: [ errcheck ] 93 | text: Error return value of .(.*Close|fmt\.Fprint.*|fmt\.Scanf|os\.Remove(All)?). is not checked 94 | 95 | # We don't care about file inclusion via variable in examples or internal tools. 96 | - linters: [ gosec ] 97 | text: 'G304: Potential file inclusion via variable' 98 | path: '^(example|tools)\/' 99 | 100 | # We don't run parallel integration tests 101 | - linters: [ paralleltest, tparallel ] 102 | path: '^test/integration' 103 | 104 | # Because fmt.Sprint(reset.Unix())) is more readable than strconv.FormatInt(reset.Unix(), 10). 105 | - linters: [ perfsprint] 106 | text: 'fmt.Sprint.* can be replaced with faster strconv.FormatInt' 107 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 The go-github AUTHORS. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /example/actionpermissions/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | // The actionpermissions command utilizes go-github as a cli tool for 7 | // changing GitHub Actions related permission settings for a repository. 8 | package main 9 | 10 | import ( 11 | "context" 12 | "flag" 13 | "fmt" 14 | "log" 15 | "os" 16 | 17 | "github.com/google/go-github/v68/github" 18 | ) 19 | 20 | var ( 21 | name = flag.String("name", "", "repo to change Actions permissions.") 22 | owner = flag.String("owner", "", "owner of targeted repo.") 23 | ) 24 | 25 | func main() { 26 | flag.Parse() 27 | token := os.Getenv("GITHUB_AUTH_TOKEN") 28 | if token == "" { 29 | log.Fatal("Unauthorized: No token present") 30 | } 31 | if *name == "" { 32 | log.Fatal("No name: repo name must be given") 33 | } 34 | if *owner == "" { 35 | log.Fatal("No owner: owner of repo must be given") 36 | } 37 | ctx := context.Background() 38 | client := github.NewClient(nil).WithAuthToken(token) 39 | 40 | actionsPermissionsRepository, _, err := client.Repositories.GetActionsPermissions(ctx, *owner, *name) 41 | if err != nil { 42 | log.Fatal(err) 43 | } 44 | 45 | fmt.Printf("Current ActionsPermissions %s\n", actionsPermissionsRepository.String()) 46 | 47 | actionsPermissionsRepository = &github.ActionsPermissionsRepository{Enabled: github.Ptr(true), AllowedActions: github.Ptr("selected")} 48 | _, _, err = client.Repositories.EditActionsPermissions(ctx, *owner, *name, *actionsPermissionsRepository) 49 | if err != nil { 50 | log.Fatal(err) 51 | } 52 | 53 | fmt.Printf("Current ActionsPermissions %s\n", actionsPermissionsRepository.String()) 54 | 55 | actionsAllowed, _, err := client.Repositories.GetActionsAllowed(ctx, *owner, *name) 56 | if err != nil { 57 | log.Fatal(err) 58 | } 59 | 60 | fmt.Printf("Current ActionsAllowed %s\n", actionsAllowed.String()) 61 | 62 | actionsAllowed = &github.ActionsAllowed{GithubOwnedAllowed: github.Ptr(true), VerifiedAllowed: github.Ptr(false), PatternsAllowed: []string{"a/b"}} 63 | _, _, err = client.Repositories.EditActionsAllowed(ctx, *owner, *name, *actionsAllowed) 64 | if err != nil { 65 | log.Fatal(err) 66 | } 67 | 68 | fmt.Printf("Current ActionsAllowed %s\n", actionsAllowed.String()) 69 | 70 | actionsPermissionsRepository = &github.ActionsPermissionsRepository{Enabled: github.Ptr(true), AllowedActions: github.Ptr("all")} 71 | _, _, err = client.Repositories.EditActionsPermissions(ctx, *owner, *name, *actionsPermissionsRepository) 72 | if err != nil { 73 | log.Fatal(err) 74 | } 75 | 76 | fmt.Printf("Current ActionsPermissions %s\n", actionsPermissionsRepository.String()) 77 | } 78 | -------------------------------------------------------------------------------- /example/appengine/app.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | // Package demo provides an app that shows how to use the github package on 7 | // Google App Engine. 8 | package demo 9 | 10 | import ( 11 | "fmt" 12 | "net/http" 13 | "os" 14 | 15 | "github.com/google/go-github/v68/github" 16 | "google.golang.org/appengine" 17 | "google.golang.org/appengine/log" 18 | ) 19 | 20 | func init() { 21 | http.HandleFunc("/", handler) 22 | } 23 | 24 | func handler(w http.ResponseWriter, r *http.Request) { 25 | if r.URL.Path != "/" { 26 | http.NotFound(w, r) 27 | return 28 | } 29 | 30 | ctx := appengine.NewContext(r) 31 | client := github.NewClient(nil).WithAuthToken(os.Getenv("GITHUB_AUTH_TOKEN")) 32 | 33 | commits, _, err := client.Repositories.ListCommits(ctx, "google", "go-github", nil) 34 | if err != nil { 35 | log.Errorf(ctx, "ListCommits: %v", err) 36 | http.Error(w, err.Error(), http.StatusInternalServerError) 37 | return 38 | } 39 | 40 | w.Header().Set("Content-Type", "text/plain; charset=utf-8") 41 | for _, commit := range commits { 42 | fmt.Fprintln(w, commit.GetHTMLURL()) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /example/appengine/app.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2017 The go-github AUTHORS. All rights reserved. 2 | # 3 | # Use of this source code is governed by a BSD-style 4 | # license that can be found in the LICENSE file. 5 | 6 | runtime: go 7 | api_version: go1 8 | 9 | handlers: 10 | - url: /.* 11 | script: _go_app 12 | 13 | env_variables: 14 | GITHUB_AUTH_TOKEN: "-your-auth-token-here-" 15 | -------------------------------------------------------------------------------- /example/basicauth/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | // The basicauth command demonstrates using the github.BasicAuthTransport, 7 | // including handling two-factor authentication. This won't currently work for 8 | // accounts that use SMS to receive one-time passwords. 9 | // 10 | // Deprecation Notice: GitHub will discontinue password authentication to the API. 11 | // You must now authenticate to the GitHub API with an API token, such as an OAuth access token, 12 | // GitHub App installation access token, or personal access token, depending on what you need to do with the token. 13 | // Password authentication to the API will be removed on November 13, 2020. 14 | // See the tokenauth example for details. 15 | package main 16 | 17 | import ( 18 | "bufio" 19 | "context" 20 | "fmt" 21 | "os" 22 | "strings" 23 | 24 | "github.com/google/go-github/v68/github" 25 | "golang.org/x/term" 26 | ) 27 | 28 | func main() { 29 | r := bufio.NewReader(os.Stdin) 30 | fmt.Print("GitHub Username: ") 31 | username, _ := r.ReadString('\n') 32 | 33 | fmt.Print("GitHub Password: ") 34 | password, _ := term.ReadPassword(int(os.Stdin.Fd())) 35 | 36 | tp := github.BasicAuthTransport{ 37 | Username: strings.TrimSpace(username), 38 | Password: strings.TrimSpace(string(password)), 39 | } 40 | 41 | client := github.NewClient(tp.Client()) 42 | ctx := context.Background() 43 | user, _, err := client.Users.Get(ctx, "") 44 | 45 | // Is this a two-factor auth error? If so, prompt for OTP and try again. 46 | if _, ok := err.(*github.TwoFactorAuthError); ok { 47 | fmt.Print("\nGitHub OTP: ") 48 | otp, _ := r.ReadString('\n') 49 | tp.OTP = strings.TrimSpace(otp) 50 | user, _, err = client.Users.Get(ctx, "") 51 | } 52 | 53 | if err != nil { 54 | fmt.Printf("\nerror: %v\n", err) 55 | return 56 | } 57 | 58 | fmt.Printf("\n%v\n", github.Stringify(user)) 59 | } 60 | -------------------------------------------------------------------------------- /example/listenvironments/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | // listenvironments is an example of how to use ListEnvironments method with EnvironmentListOptions. 7 | // It's runnable with the following command: 8 | // 9 | // export GITHUB_TOKEN=your_token 10 | // export GITHUB_REPOSITORY_OWNER=your_owner 11 | // export GITHUB_REPOSITORY_NAME=your_repo 12 | // go run . 13 | package main 14 | 15 | import ( 16 | "context" 17 | "fmt" 18 | "log" 19 | "os" 20 | 21 | "github.com/google/go-github/v68/github" 22 | ) 23 | 24 | func main() { 25 | token := os.Getenv("GITHUB_AUTH_TOKEN") 26 | repo := os.Getenv("GITHUB_REPOSITORY_NAME") 27 | owner := os.Getenv("GITHUB_REPOSITORY_OWNER") 28 | 29 | if token == "" { 30 | log.Fatal("Unauthorized: No token present") 31 | } 32 | 33 | ctx := context.Background() 34 | client := github.NewClient(nil).WithAuthToken(token) 35 | 36 | expectedPageSize := 2 37 | 38 | opts := &github.EnvironmentListOptions{ListOptions: github.ListOptions{PerPage: expectedPageSize}} 39 | envResponse, _, err := client.Repositories.ListEnvironments(ctx, owner, repo, opts) 40 | if err != nil { 41 | log.Fatal(err) 42 | } 43 | 44 | if len(envResponse.Environments) != expectedPageSize { 45 | log.Fatal("Unexpected number of environments returned") 46 | } 47 | 48 | // The number of environments here should be equal to expectedPageSize 49 | fmt.Printf("%d environments returned\n", len(envResponse.Environments)) 50 | } 51 | -------------------------------------------------------------------------------- /example/migrations/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | // migrations demonstrates the functionality of 7 | // the user data migration API for the authenticated GitHub 8 | // user and lists all the user migrations. 9 | package main 10 | 11 | import ( 12 | "context" 13 | "fmt" 14 | 15 | "github.com/google/go-github/v68/github" 16 | ) 17 | 18 | func fetchAllUserMigrations() ([]*github.UserMigration, error) { 19 | ctx := context.Background() 20 | client := github.NewClient(nil).WithAuthToken("") 21 | 22 | migrations, _, err := client.Migrations.ListUserMigrations(ctx, &github.ListOptions{Page: 1}) 23 | return migrations, err 24 | } 25 | 26 | func main() { 27 | migrations, err := fetchAllUserMigrations() 28 | if err != nil { 29 | fmt.Printf("Error %v\n", err) 30 | return 31 | } 32 | 33 | for i, m := range migrations { 34 | fmt.Printf("%v. %v", i+1, m.GetID()) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /example/newfilewithappauth/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | // newfilewithappauth demonstrates the functionality of GitHub's app authentication 7 | // methods by fetching an installation access token and reauthenticating to GitHub 8 | // with OAuth configurations. 9 | package main 10 | 11 | import ( 12 | "context" 13 | "log" 14 | "net/http" 15 | "os" 16 | "time" 17 | 18 | "github.com/bradleyfalzon/ghinstallation/v2" 19 | "github.com/google/go-github/v68/github" 20 | ) 21 | 22 | func main() { 23 | const gitHost = "https://git.api.com" 24 | 25 | privatePem, err := os.ReadFile("path/to/pem") 26 | if err != nil { 27 | log.Fatalf("failed to read pem: %v", err) 28 | } 29 | 30 | itr, err := ghinstallation.NewAppsTransport(http.DefaultTransport, 10, privatePem) 31 | if err != nil { 32 | log.Fatalf("failed to create app transport: %v\n", err) 33 | } 34 | itr.BaseURL = gitHost 35 | 36 | // create git client with app transport 37 | client, err := github.NewClient( 38 | &http.Client{ 39 | Transport: itr, 40 | Timeout: time.Second * 30, 41 | }, 42 | ).WithEnterpriseURLs(gitHost, gitHost) 43 | 44 | if err != nil { 45 | log.Fatalf("failed to create git client for app: %v\n", err) 46 | } 47 | 48 | installations, _, err := client.Apps.ListInstallations(context.Background(), &github.ListOptions{}) 49 | if err != nil { 50 | log.Fatalf("failed to list installations: %v\n", err) 51 | } 52 | 53 | // capture our installationId for our app 54 | // we need this for the access token 55 | var installID int64 56 | for _, val := range installations { 57 | installID = val.GetID() 58 | } 59 | 60 | token, _, err := client.Apps.CreateInstallationToken( 61 | context.Background(), 62 | installID, 63 | &github.InstallationTokenOptions{}) 64 | if err != nil { 65 | log.Fatalf("failed to create installation token: %v\n", err) 66 | } 67 | 68 | apiClient, err := github.NewClient(nil).WithAuthToken( 69 | token.GetToken(), 70 | ).WithEnterpriseURLs(gitHost, gitHost) 71 | if err != nil { 72 | log.Fatalf("failed to create new git client with token: %v\n", err) 73 | } 74 | 75 | _, resp, err := apiClient.Repositories.CreateFile( 76 | context.Background(), 77 | "repoOwner", 78 | "sample-repo", 79 | "example/foo.txt", 80 | &github.RepositoryContentFileOptions{ 81 | Content: []byte("foo"), 82 | Message: github.Ptr("sample commit"), 83 | SHA: nil, 84 | }) 85 | if err != nil { 86 | log.Fatalf("failed to create new file: %v\n", err) 87 | } 88 | 89 | log.Printf("file written status code: %v", resp.StatusCode) 90 | } 91 | -------------------------------------------------------------------------------- /example/newrepo/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | // The newrepo command utilizes go-github as a cli tool for 7 | // creating new repositories. It takes an auth token as 8 | // an environment variable and creates the new repo under 9 | // the account affiliated with that token. 10 | package main 11 | 12 | import ( 13 | "context" 14 | "flag" 15 | "fmt" 16 | "log" 17 | "os" 18 | 19 | "github.com/google/go-github/v68/github" 20 | ) 21 | 22 | var ( 23 | name = flag.String("name", "", "Name of repo to create in authenticated user's GitHub account.") 24 | description = flag.String("description", "", "Description of created repo.") 25 | private = flag.Bool("private", false, "Will created repo be private.") 26 | autoInit = flag.Bool("auto-init", false, "Pass true to create an initial commit with empty README.") 27 | ) 28 | 29 | func main() { 30 | flag.Parse() 31 | token := os.Getenv("GITHUB_AUTH_TOKEN") 32 | if token == "" { 33 | log.Fatal("Unauthorized: No token present") 34 | } 35 | if *name == "" { 36 | log.Fatal("No name: New repos must be given a name") 37 | } 38 | ctx := context.Background() 39 | client := github.NewClient(nil).WithAuthToken(token) 40 | 41 | r := &github.Repository{Name: name, Private: private, Description: description, AutoInit: autoInit} 42 | repo, _, err := client.Repositories.Create(ctx, "", r) 43 | if err != nil { 44 | log.Fatal(err) 45 | } 46 | fmt.Printf("Successfully created new repo: %v\n", repo.GetName()) 47 | } 48 | -------------------------------------------------------------------------------- /example/newreposecretwithlibsodium/go.mod: -------------------------------------------------------------------------------- 1 | module newreposecretwithlibsodium 2 | 3 | go 1.22.10 4 | 5 | require ( 6 | github.com/GoKillers/libsodium-go v0.0.0-20171022220152-dd733721c3cb 7 | github.com/google/go-github/v68 v68.0.0 8 | ) 9 | 10 | require github.com/google/go-querystring v1.1.0 // indirect 11 | 12 | // Use version at HEAD, not the latest published. 13 | replace github.com/google/go-github/v68 => ../.. 14 | -------------------------------------------------------------------------------- /example/newreposecretwithlibsodium/go.sum: -------------------------------------------------------------------------------- 1 | github.com/GoKillers/libsodium-go v0.0.0-20171022220152-dd733721c3cb h1:ilqSFSbR1fq6x88heeHrvAqlg+ES+tZk2ZcaCmiH1gI= 2 | github.com/GoKillers/libsodium-go v0.0.0-20171022220152-dd733721c3cb/go.mod h1:72TQeEkiDH9QMXZa5nJJvZre0UjqqO67X2QEIoOwCRU= 3 | github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 4 | github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= 5 | github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 6 | github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= 7 | github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= 8 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 9 | -------------------------------------------------------------------------------- /example/ratelimit/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | // The ratelimit command demonstrates using the github_ratelimit.SecondaryRateLimitWaiter. 7 | // By using the waiter, the client automatically sleeps and retry requests 8 | // when it hits secondary rate limits. 9 | package main 10 | 11 | import ( 12 | "context" 13 | "fmt" 14 | 15 | "github.com/gofri/go-github-ratelimit/github_ratelimit" 16 | "github.com/google/go-github/v68/github" 17 | ) 18 | 19 | func main() { 20 | var username string 21 | fmt.Print("Enter GitHub username: ") 22 | fmt.Scanf("%s", &username) 23 | 24 | rateLimiter, err := github_ratelimit.NewRateLimitWaiterClient(nil) 25 | if err != nil { 26 | fmt.Printf("Error: %v\n", err) 27 | return 28 | } 29 | 30 | client := github.NewClient(rateLimiter) 31 | 32 | // arbitrary usage of the client 33 | organizations, _, err := client.Organizations.List(context.Background(), username, nil) 34 | if err != nil { 35 | fmt.Printf("Error: %v\n", err) 36 | return 37 | } 38 | 39 | for i, organization := range organizations { 40 | fmt.Printf("%v. %v\n", i+1, organization.GetLogin()) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /example/simple/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | // The simple command demonstrates a simple functionality which 7 | // prompts the user for a GitHub username and lists all the public 8 | // organization memberships of the specified username. 9 | package main 10 | 11 | import ( 12 | "context" 13 | "fmt" 14 | 15 | "github.com/google/go-github/v68/github" 16 | ) 17 | 18 | // Fetch all the public organizations' membership of a user. 19 | func fetchOrganizations(username string) ([]*github.Organization, error) { 20 | client := github.NewClient(nil) 21 | orgs, _, err := client.Organizations.List(context.Background(), username, nil) 22 | return orgs, err 23 | } 24 | 25 | func main() { 26 | var username string 27 | fmt.Print("Enter GitHub username: ") 28 | fmt.Scanf("%s", &username) 29 | 30 | organizations, err := fetchOrganizations(username) 31 | if err != nil { 32 | fmt.Printf("Error: %v\n", err) 33 | return 34 | } 35 | 36 | for i, organization := range organizations { 37 | fmt.Printf("%v. %v\n", i+1, organization.GetLogin()) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /example/tokenauth/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | // The tokenauth command demonstrates using a Personal Access Token (PAT) to 7 | // authenticate with GitHub. 8 | // You can test out a GitHub Personal Access Token using this simple example. 9 | // You can generate them here: https://github.com/settings/tokens 10 | package main 11 | 12 | import ( 13 | "context" 14 | "fmt" 15 | "log" 16 | "os" 17 | 18 | "github.com/google/go-github/v68/github" 19 | "golang.org/x/term" 20 | ) 21 | 22 | func main() { 23 | fmt.Print("GitHub Token: ") 24 | token, _ := term.ReadPassword(int(os.Stdin.Fd())) 25 | fmt.Println() 26 | 27 | ctx := context.Background() 28 | client := github.NewClient(nil).WithAuthToken(string(token)) 29 | 30 | user, resp, err := client.Users.Get(ctx, "") 31 | if err != nil { 32 | fmt.Printf("\nerror: %v\n", err) 33 | return 34 | } 35 | 36 | // Rate.Limit should most likely be 5000 when authorized. 37 | log.Printf("Rate: %#v\n", resp.Rate) 38 | 39 | // If a Token Expiration has been set, it will be displayed. 40 | if !resp.TokenExpiration.IsZero() { 41 | log.Printf("Token Expiration: %v\n", resp.TokenExpiration) 42 | } 43 | 44 | fmt.Printf("\n%v\n", github.Stringify(user)) 45 | } 46 | -------------------------------------------------------------------------------- /example/topics/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | // The simple command demonstrates the functionality that 7 | // prompts the user for a GitHub topic and lists all the entities 8 | // that are related to the specified topic or subject. 9 | package main 10 | 11 | import ( 12 | "context" 13 | "fmt" 14 | 15 | "github.com/google/go-github/v68/github" 16 | ) 17 | 18 | // Fetch and lists all the public topics associated with the specified GitHub topic. 19 | func fetchTopics(topic string) (*github.TopicsSearchResult, error) { 20 | client := github.NewClient(nil) 21 | topics, _, err := client.Search.Topics(context.Background(), topic, nil) 22 | return topics, err 23 | } 24 | 25 | func main() { 26 | var topic string 27 | fmt.Print("Enter GitHub topic: ") 28 | fmt.Scanf("%s", &topic) 29 | 30 | topics, err := fetchTopics(topic) 31 | if err != nil { 32 | fmt.Printf("Error: %v\n", err) 33 | return 34 | } 35 | 36 | for _, topic := range topics.Topics { 37 | fmt.Println(*topic.Name) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /github/actions.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | // ActionsService handles communication with the actions related 9 | // methods of the GitHub API. 10 | // 11 | // GitHub API docs: https://docs.github.com/rest/actions/ 12 | type ActionsService service 13 | -------------------------------------------------------------------------------- /github/activity.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import "context" 9 | 10 | // ActivityService handles communication with the activity related 11 | // methods of the GitHub API. 12 | // 13 | // GitHub API docs: https://docs.github.com/rest/activity/ 14 | type ActivityService service 15 | 16 | // FeedLink represents a link to a related resource. 17 | type FeedLink struct { 18 | HRef *string `json:"href,omitempty"` 19 | Type *string `json:"type,omitempty"` 20 | } 21 | 22 | // Feeds represents timeline resources in Atom format. 23 | type Feeds struct { 24 | TimelineURL *string `json:"timeline_url,omitempty"` 25 | UserURL *string `json:"user_url,omitempty"` 26 | CurrentUserPublicURL *string `json:"current_user_public_url,omitempty"` 27 | CurrentUserURL *string `json:"current_user_url,omitempty"` 28 | CurrentUserActorURL *string `json:"current_user_actor_url,omitempty"` 29 | CurrentUserOrganizationURL *string `json:"current_user_organization_url,omitempty"` 30 | CurrentUserOrganizationURLs []string `json:"current_user_organization_urls,omitempty"` 31 | Links *FeedLinks `json:"_links,omitempty"` 32 | } 33 | 34 | // FeedLinks represents the links in a Feed. 35 | type FeedLinks struct { 36 | Timeline *FeedLink `json:"timeline,omitempty"` 37 | User *FeedLink `json:"user,omitempty"` 38 | CurrentUserPublic *FeedLink `json:"current_user_public,omitempty"` 39 | CurrentUser *FeedLink `json:"current_user,omitempty"` 40 | CurrentUserActor *FeedLink `json:"current_user_actor,omitempty"` 41 | CurrentUserOrganization *FeedLink `json:"current_user_organization,omitempty"` 42 | CurrentUserOrganizations []*FeedLink `json:"current_user_organizations,omitempty"` 43 | } 44 | 45 | // ListFeeds lists all the feeds available to the authenticated user. 46 | // 47 | // GitHub provides several timeline resources in Atom format: 48 | // 49 | // Timeline: The GitHub global public timeline 50 | // User: The public timeline for any user, using URI template 51 | // Current user public: The public timeline for the authenticated user 52 | // Current user: The private timeline for the authenticated user 53 | // Current user actor: The private timeline for activity created by the 54 | // authenticated user 55 | // Current user organizations: The private timeline for the organizations 56 | // the authenticated user is a member of. 57 | // 58 | // Note: Private feeds are only returned when authenticating via Basic Auth 59 | // since current feed URIs use the older, non revocable auth tokens. 60 | // 61 | // GitHub API docs: https://docs.github.com/rest/activity/feeds#get-feeds 62 | // 63 | //meta:operation GET /feeds 64 | func (s *ActivityService) ListFeeds(ctx context.Context) (*Feeds, *Response, error) { 65 | req, err := s.client.NewRequest("GET", "feeds", nil) 66 | if err != nil { 67 | return nil, nil, err 68 | } 69 | 70 | f := &Feeds{} 71 | resp, err := s.client.Do(ctx, req, f) 72 | if err != nil { 73 | return nil, resp, err 74 | } 75 | 76 | return f, resp, nil 77 | } 78 | -------------------------------------------------------------------------------- /github/admin_orgs.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | "fmt" 11 | ) 12 | 13 | // createOrgRequest is a subset of Organization and is used internally 14 | // by CreateOrg to pass only the known fields for the endpoint. 15 | type createOrgRequest struct { 16 | Login *string `json:"login,omitempty"` 17 | Admin *string `json:"admin,omitempty"` 18 | } 19 | 20 | // CreateOrg creates a new organization in GitHub Enterprise. 21 | // 22 | // Note that only a subset of the org fields are used and org must 23 | // not be nil. 24 | // 25 | // GitHub API docs: https://docs.github.com/enterprise-server@3.15/rest/enterprise-admin/orgs#create-an-organization 26 | // 27 | //meta:operation POST /admin/organizations 28 | func (s *AdminService) CreateOrg(ctx context.Context, org *Organization, admin string) (*Organization, *Response, error) { 29 | u := "admin/organizations" 30 | 31 | orgReq := &createOrgRequest{ 32 | Login: org.Login, 33 | Admin: &admin, 34 | } 35 | 36 | req, err := s.client.NewRequest("POST", u, orgReq) 37 | if err != nil { 38 | return nil, nil, err 39 | } 40 | 41 | o := new(Organization) 42 | resp, err := s.client.Do(ctx, req, o) 43 | if err != nil { 44 | return nil, resp, err 45 | } 46 | 47 | return o, resp, nil 48 | } 49 | 50 | // renameOrgRequest is a subset of Organization and is used internally 51 | // by RenameOrg and RenameOrgByName to pass only the known fields for the endpoint. 52 | type renameOrgRequest struct { 53 | Login *string `json:"login,omitempty"` 54 | } 55 | 56 | // RenameOrgResponse is the response given when renaming an Organization. 57 | type RenameOrgResponse struct { 58 | Message *string `json:"message,omitempty"` 59 | URL *string `json:"url,omitempty"` 60 | } 61 | 62 | // RenameOrg renames an organization in GitHub Enterprise. 63 | // 64 | // GitHub API docs: https://docs.github.com/enterprise-server@3.15/rest/enterprise-admin/orgs#update-an-organization-name 65 | // 66 | //meta:operation PATCH /admin/organizations/{org} 67 | func (s *AdminService) RenameOrg(ctx context.Context, org *Organization, newName string) (*RenameOrgResponse, *Response, error) { 68 | return s.RenameOrgByName(ctx, *org.Login, newName) 69 | } 70 | 71 | // RenameOrgByName renames an organization in GitHub Enterprise using its current name. 72 | // 73 | // GitHub API docs: https://docs.github.com/enterprise-server@3.15/rest/enterprise-admin/orgs#update-an-organization-name 74 | // 75 | //meta:operation PATCH /admin/organizations/{org} 76 | func (s *AdminService) RenameOrgByName(ctx context.Context, org, newName string) (*RenameOrgResponse, *Response, error) { 77 | u := fmt.Sprintf("admin/organizations/%v", org) 78 | 79 | orgReq := &renameOrgRequest{ 80 | Login: &newName, 81 | } 82 | 83 | req, err := s.client.NewRequest("PATCH", u, orgReq) 84 | if err != nil { 85 | return nil, nil, err 86 | } 87 | 88 | o := new(RenameOrgResponse) 89 | resp, err := s.client.Do(ctx, req, o) 90 | if err != nil { 91 | return nil, resp, err 92 | } 93 | 94 | return o, resp, nil 95 | } 96 | -------------------------------------------------------------------------------- /github/apps_hooks.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | ) 11 | 12 | // GetHookConfig returns the webhook configuration for a GitHub App. 13 | // The underlying transport must be authenticated as an app. 14 | // 15 | // GitHub API docs: https://docs.github.com/rest/apps/webhooks#get-a-webhook-configuration-for-an-app 16 | // 17 | //meta:operation GET /app/hook/config 18 | func (s *AppsService) GetHookConfig(ctx context.Context) (*HookConfig, *Response, error) { 19 | req, err := s.client.NewRequest("GET", "app/hook/config", nil) 20 | if err != nil { 21 | return nil, nil, err 22 | } 23 | 24 | config := new(HookConfig) 25 | resp, err := s.client.Do(ctx, req, &config) 26 | if err != nil { 27 | return nil, resp, err 28 | } 29 | 30 | return config, resp, nil 31 | } 32 | 33 | // UpdateHookConfig updates the webhook configuration for a GitHub App. 34 | // The underlying transport must be authenticated as an app. 35 | // 36 | // GitHub API docs: https://docs.github.com/rest/apps/webhooks#update-a-webhook-configuration-for-an-app 37 | // 38 | //meta:operation PATCH /app/hook/config 39 | func (s *AppsService) UpdateHookConfig(ctx context.Context, config *HookConfig) (*HookConfig, *Response, error) { 40 | req, err := s.client.NewRequest("PATCH", "app/hook/config", config) 41 | if err != nil { 42 | return nil, nil, err 43 | } 44 | 45 | c := new(HookConfig) 46 | resp, err := s.client.Do(ctx, req, c) 47 | if err != nil { 48 | return nil, resp, err 49 | } 50 | 51 | return c, resp, nil 52 | } 53 | -------------------------------------------------------------------------------- /github/apps_hooks_deliveries.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | "fmt" 11 | ) 12 | 13 | // ListHookDeliveries lists deliveries of an App webhook. 14 | // 15 | // GitHub API docs: https://docs.github.com/rest/apps/webhooks#list-deliveries-for-an-app-webhook 16 | // 17 | //meta:operation GET /app/hook/deliveries 18 | func (s *AppsService) ListHookDeliveries(ctx context.Context, opts *ListCursorOptions) ([]*HookDelivery, *Response, error) { 19 | u, err := addOptions("app/hook/deliveries", opts) 20 | if err != nil { 21 | return nil, nil, err 22 | } 23 | 24 | req, err := s.client.NewRequest("GET", u, nil) 25 | if err != nil { 26 | return nil, nil, err 27 | } 28 | 29 | deliveries := []*HookDelivery{} 30 | resp, err := s.client.Do(ctx, req, &deliveries) 31 | if err != nil { 32 | return nil, resp, err 33 | } 34 | 35 | return deliveries, resp, nil 36 | } 37 | 38 | // GetHookDelivery returns the App webhook delivery with the specified ID. 39 | // 40 | // GitHub API docs: https://docs.github.com/rest/apps/webhooks#get-a-delivery-for-an-app-webhook 41 | // 42 | //meta:operation GET /app/hook/deliveries/{delivery_id} 43 | func (s *AppsService) GetHookDelivery(ctx context.Context, deliveryID int64) (*HookDelivery, *Response, error) { 44 | u := fmt.Sprintf("app/hook/deliveries/%v", deliveryID) 45 | req, err := s.client.NewRequest("GET", u, nil) 46 | if err != nil { 47 | return nil, nil, err 48 | } 49 | 50 | h := new(HookDelivery) 51 | resp, err := s.client.Do(ctx, req, h) 52 | if err != nil { 53 | return nil, resp, err 54 | } 55 | 56 | return h, resp, nil 57 | } 58 | 59 | // RedeliverHookDelivery redelivers a delivery for an App webhook. 60 | // 61 | // GitHub API docs: https://docs.github.com/rest/apps/webhooks#redeliver-a-delivery-for-an-app-webhook 62 | // 63 | //meta:operation POST /app/hook/deliveries/{delivery_id}/attempts 64 | func (s *AppsService) RedeliverHookDelivery(ctx context.Context, deliveryID int64) (*HookDelivery, *Response, error) { 65 | u := fmt.Sprintf("app/hook/deliveries/%v/attempts", deliveryID) 66 | req, err := s.client.NewRequest("POST", u, nil) 67 | if err != nil { 68 | return nil, nil, err 69 | } 70 | 71 | h := new(HookDelivery) 72 | resp, err := s.client.Do(ctx, req, h) 73 | if err != nil { 74 | return nil, resp, err 75 | } 76 | 77 | return h, resp, nil 78 | } 79 | -------------------------------------------------------------------------------- /github/apps_hooks_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | "fmt" 11 | "net/http" 12 | "testing" 13 | 14 | "github.com/google/go-cmp/cmp" 15 | ) 16 | 17 | func TestAppsService_GetHookConfig(t *testing.T) { 18 | t.Parallel() 19 | client, mux, _ := setup(t) 20 | 21 | mux.HandleFunc("/app/hook/config", func(w http.ResponseWriter, r *http.Request) { 22 | testMethod(t, r, "GET") 23 | fmt.Fprint(w, `{ 24 | "content_type": "json", 25 | "insecure_ssl": "0", 26 | "secret": "********", 27 | "url": "https://example.com/webhook" 28 | }`) 29 | }) 30 | 31 | ctx := context.Background() 32 | config, _, err := client.Apps.GetHookConfig(ctx) 33 | if err != nil { 34 | t.Errorf("Apps.GetHookConfig returned error: %v", err) 35 | } 36 | 37 | want := &HookConfig{ 38 | ContentType: Ptr("json"), 39 | InsecureSSL: Ptr("0"), 40 | Secret: Ptr("********"), 41 | URL: Ptr("https://example.com/webhook"), 42 | } 43 | if !cmp.Equal(config, want) { 44 | t.Errorf("Apps.GetHookConfig returned %+v, want %+v", config, want) 45 | } 46 | 47 | const methodName = "GetHookConfig" 48 | testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 49 | got, resp, err := client.Apps.GetHookConfig(ctx) 50 | if got != nil { 51 | t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 52 | } 53 | return resp, err 54 | }) 55 | } 56 | 57 | func TestAppsService_UpdateHookConfig(t *testing.T) { 58 | t.Parallel() 59 | client, mux, _ := setup(t) 60 | 61 | input := &HookConfig{ 62 | ContentType: Ptr("json"), 63 | InsecureSSL: Ptr("1"), 64 | Secret: Ptr("s"), 65 | URL: Ptr("u"), 66 | } 67 | 68 | mux.HandleFunc("/app/hook/config", func(w http.ResponseWriter, r *http.Request) { 69 | testMethod(t, r, "PATCH") 70 | testBody(t, r, `{"content_type":"json","insecure_ssl":"1","url":"u","secret":"s"}`+"\n") 71 | fmt.Fprint(w, `{ 72 | "content_type": "json", 73 | "insecure_ssl": "1", 74 | "secret": "********", 75 | "url": "u" 76 | }`) 77 | }) 78 | 79 | ctx := context.Background() 80 | config, _, err := client.Apps.UpdateHookConfig(ctx, input) 81 | if err != nil { 82 | t.Errorf("Apps.UpdateHookConfig returned error: %v", err) 83 | } 84 | 85 | want := &HookConfig{ 86 | ContentType: Ptr("json"), 87 | InsecureSSL: Ptr("1"), 88 | Secret: Ptr("********"), 89 | URL: Ptr("u"), 90 | } 91 | if !cmp.Equal(config, want) { 92 | t.Errorf("Apps.UpdateHookConfig returned %+v, want %+v", config, want) 93 | } 94 | 95 | const methodName = "UpdateHookConfig" 96 | testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 97 | got, resp, err := client.Apps.UpdateHookConfig(ctx, input) 98 | if got != nil { 99 | t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 100 | } 101 | return resp, err 102 | }) 103 | } 104 | -------------------------------------------------------------------------------- /github/apps_manifest.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | "fmt" 11 | ) 12 | 13 | // AppConfig describes the configuration of a GitHub App. 14 | type AppConfig struct { 15 | ID *int64 `json:"id,omitempty"` 16 | Slug *string `json:"slug,omitempty"` 17 | NodeID *string `json:"node_id,omitempty"` 18 | Owner *User `json:"owner,omitempty"` 19 | Name *string `json:"name,omitempty"` 20 | Description *string `json:"description,omitempty"` 21 | ExternalURL *string `json:"external_url,omitempty"` 22 | HTMLURL *string `json:"html_url,omitempty"` 23 | CreatedAt *Timestamp `json:"created_at,omitempty"` 24 | UpdatedAt *Timestamp `json:"updated_at,omitempty"` 25 | ClientID *string `json:"client_id,omitempty"` 26 | ClientSecret *string `json:"client_secret,omitempty"` 27 | WebhookSecret *string `json:"webhook_secret,omitempty"` 28 | PEM *string `json:"pem,omitempty"` 29 | } 30 | 31 | // CompleteAppManifest completes the App manifest handshake flow for the given 32 | // code. 33 | // 34 | // GitHub API docs: https://docs.github.com/rest/apps/apps#create-a-github-app-from-a-manifest 35 | // 36 | //meta:operation POST /app-manifests/{code}/conversions 37 | func (s *AppsService) CompleteAppManifest(ctx context.Context, code string) (*AppConfig, *Response, error) { 38 | u := fmt.Sprintf("app-manifests/%s/conversions", code) 39 | req, err := s.client.NewRequest("POST", u, nil) 40 | if err != nil { 41 | return nil, nil, err 42 | } 43 | 44 | cfg := new(AppConfig) 45 | resp, err := s.client.Do(ctx, req, cfg) 46 | if err != nil { 47 | return nil, resp, err 48 | } 49 | 50 | return cfg, resp, nil 51 | } 52 | -------------------------------------------------------------------------------- /github/attestations.go: -------------------------------------------------------------------------------- 1 | // Copyright 2024 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "encoding/json" 10 | ) 11 | 12 | // Attestation represents an artifact attestation associated with a repository. 13 | // The provided bundle can be used to verify the provenance of artifacts. 14 | // 15 | // https://docs.github.com/en/actions/security-for-github-actions/using-artifact-attestations/using-artifact-attestations-to-establish-provenance-for-builds 16 | type Attestation struct { 17 | // The attestation's Sigstore Bundle. 18 | // Refer to the sigstore bundle specification for more info: 19 | // https://github.com/sigstore/protobuf-specs/blob/main/protos/sigstore_bundle.proto 20 | Bundle json.RawMessage `json:"bundle"` 21 | RepositoryID int64 `json:"repository_id"` 22 | } 23 | 24 | // AttestationsResponse represents a collection of artifact attestations. 25 | type AttestationsResponse struct { 26 | Attestations []*Attestation `json:"attestations"` 27 | } 28 | -------------------------------------------------------------------------------- /github/codesofconduct.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | "fmt" 11 | ) 12 | 13 | // CodesOfConductService provides access to code-of-conduct-related functions in the GitHub API. 14 | type CodesOfConductService service 15 | 16 | // CodeOfConduct represents a code of conduct. 17 | type CodeOfConduct struct { 18 | Name *string `json:"name,omitempty"` 19 | Key *string `json:"key,omitempty"` 20 | URL *string `json:"url,omitempty"` 21 | Body *string `json:"body,omitempty"` 22 | } 23 | 24 | func (c *CodeOfConduct) String() string { 25 | return Stringify(c) 26 | } 27 | 28 | // List returns all codes of conduct. 29 | // 30 | // GitHub API docs: https://docs.github.com/rest/codes-of-conduct/codes-of-conduct#get-all-codes-of-conduct 31 | // 32 | //meta:operation GET /codes_of_conduct 33 | func (s *CodesOfConductService) List(ctx context.Context) ([]*CodeOfConduct, *Response, error) { 34 | req, err := s.client.NewRequest("GET", "codes_of_conduct", nil) 35 | if err != nil { 36 | return nil, nil, err 37 | } 38 | 39 | // TODO: remove custom Accept header when this API fully launches. 40 | req.Header.Set("Accept", mediaTypeCodesOfConductPreview) 41 | 42 | var cs []*CodeOfConduct 43 | resp, err := s.client.Do(ctx, req, &cs) 44 | if err != nil { 45 | return nil, resp, err 46 | } 47 | 48 | return cs, resp, nil 49 | } 50 | 51 | // ListCodesOfConduct returns all codes of conduct. 52 | // 53 | // Deprecated: Use CodesOfConductService.List instead. 54 | func (c *Client) ListCodesOfConduct(ctx context.Context) ([]*CodeOfConduct, *Response, error) { 55 | return c.CodesOfConduct.List(ctx) 56 | } 57 | 58 | // Get returns an individual code of conduct. 59 | // 60 | // GitHub API docs: https://docs.github.com/rest/codes-of-conduct/codes-of-conduct#get-a-code-of-conduct 61 | // 62 | //meta:operation GET /codes_of_conduct/{key} 63 | func (s *CodesOfConductService) Get(ctx context.Context, key string) (*CodeOfConduct, *Response, error) { 64 | u := fmt.Sprintf("codes_of_conduct/%s", key) 65 | req, err := s.client.NewRequest("GET", u, nil) 66 | if err != nil { 67 | return nil, nil, err 68 | } 69 | 70 | // TODO: remove custom Accept header when this API fully launches. 71 | req.Header.Set("Accept", mediaTypeCodesOfConductPreview) 72 | 73 | coc := new(CodeOfConduct) 74 | resp, err := s.client.Do(ctx, req, coc) 75 | if err != nil { 76 | return nil, resp, err 77 | } 78 | 79 | return coc, resp, nil 80 | } 81 | 82 | // GetCodeOfConduct returns an individual code of conduct. 83 | // 84 | // Deprecated: Use CodesOfConductService.Get instead. 85 | func (c *Client) GetCodeOfConduct(ctx context.Context, key string) (*CodeOfConduct, *Response, error) { 86 | return c.CodesOfConduct.Get(ctx, key) 87 | } 88 | -------------------------------------------------------------------------------- /github/codesofconduct_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | "fmt" 11 | "net/http" 12 | "testing" 13 | 14 | "github.com/google/go-cmp/cmp" 15 | ) 16 | 17 | func TestCodesOfConductService_List(t *testing.T) { 18 | t.Parallel() 19 | client, mux, _ := setup(t) 20 | 21 | mux.HandleFunc("/codes_of_conduct", func(w http.ResponseWriter, r *http.Request) { 22 | testMethod(t, r, "GET") 23 | testHeader(t, r, "Accept", mediaTypeCodesOfConductPreview) 24 | fmt.Fprint(w, `[{ 25 | "key": "key", 26 | "name": "name", 27 | "url": "url"} 28 | ]`) 29 | }) 30 | 31 | ctx := context.Background() 32 | cs, _, err := client.ListCodesOfConduct(ctx) 33 | assertNilError(t, err) 34 | 35 | want := []*CodeOfConduct{ 36 | { 37 | Key: Ptr("key"), 38 | Name: Ptr("name"), 39 | URL: Ptr("url"), 40 | }} 41 | if !cmp.Equal(want, cs) { 42 | t.Errorf("returned %+v, want %+v", cs, want) 43 | } 44 | 45 | const methodName = "List" 46 | testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 47 | got, resp, err := client.CodesOfConduct.List(ctx) 48 | if got != nil { 49 | t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 50 | } 51 | return resp, err 52 | }) 53 | } 54 | 55 | func TestCodesOfConductService_Get(t *testing.T) { 56 | t.Parallel() 57 | client, mux, _ := setup(t) 58 | 59 | mux.HandleFunc("/codes_of_conduct/k", func(w http.ResponseWriter, r *http.Request) { 60 | testMethod(t, r, "GET") 61 | testHeader(t, r, "Accept", mediaTypeCodesOfConductPreview) 62 | fmt.Fprint(w, `{ 63 | "key": "key", 64 | "name": "name", 65 | "url": "url", 66 | "body": "body"}`, 67 | ) 68 | }) 69 | 70 | ctx := context.Background() 71 | coc, _, err := client.GetCodeOfConduct(ctx, "k") 72 | assertNilError(t, err) 73 | 74 | want := &CodeOfConduct{ 75 | Key: Ptr("key"), 76 | Name: Ptr("name"), 77 | URL: Ptr("url"), 78 | Body: Ptr("body"), 79 | } 80 | if !cmp.Equal(want, coc) { 81 | t.Errorf("returned %+v, want %+v", coc, want) 82 | } 83 | 84 | const methodName = "Get" 85 | testBadOptions(t, methodName, func() (err error) { 86 | _, _, err = client.CodesOfConduct.Get(ctx, "\n") 87 | return err 88 | }) 89 | 90 | testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 91 | got, resp, err := client.CodesOfConduct.Get(ctx, "k") 92 | if got != nil { 93 | t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 94 | } 95 | return resp, err 96 | }) 97 | } 98 | 99 | func TestCodeOfConduct_Marshal(t *testing.T) { 100 | t.Parallel() 101 | testJSONMarshal(t, &CodeOfConduct{}, "{}") 102 | 103 | a := &CodeOfConduct{ 104 | Name: Ptr("name"), 105 | Key: Ptr("key"), 106 | URL: Ptr("url"), 107 | Body: Ptr("body"), 108 | } 109 | 110 | want := `{ 111 | "name": "name", 112 | "key": "key", 113 | "url": "url", 114 | "body": "body" 115 | }` 116 | 117 | testJSONMarshal(t, a, want) 118 | } 119 | -------------------------------------------------------------------------------- /github/dependabot.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | // DependabotService handles communication with the Dependabot related 9 | // methods of the GitHub API. 10 | // 11 | // GitHub API docs: https://docs.github.com/rest/dependabot/ 12 | type DependabotService service 13 | -------------------------------------------------------------------------------- /github/dependency_graph.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | "fmt" 11 | ) 12 | 13 | type DependencyGraphService service 14 | 15 | // SBOM represents a software bill of materials, which describes the 16 | // packages/libraries that a repository depends on. 17 | type SBOM struct { 18 | SBOM *SBOMInfo `json:"sbom,omitempty"` 19 | } 20 | 21 | // CreationInfo represents when the SBOM was created and who created it. 22 | type CreationInfo struct { 23 | Created *Timestamp `json:"created,omitempty"` 24 | Creators []string `json:"creators,omitempty"` 25 | } 26 | 27 | // RepoDependencies represents the dependencies of a repo. 28 | type RepoDependencies struct { 29 | SPDXID *string `json:"SPDXID,omitempty"` 30 | // Package name 31 | Name *string `json:"name,omitempty"` 32 | VersionInfo *string `json:"versionInfo,omitempty"` 33 | DownloadLocation *string `json:"downloadLocation,omitempty"` 34 | FilesAnalyzed *bool `json:"filesAnalyzed,omitempty"` 35 | LicenseConcluded *string `json:"licenseConcluded,omitempty"` 36 | LicenseDeclared *string `json:"licenseDeclared,omitempty"` 37 | } 38 | 39 | // SBOMInfo represents a software bill of materials (SBOM) using SPDX. 40 | // SPDX is an open standard for SBOMs that 41 | // identifies and catalogs components, licenses, copyrights, security 42 | // references, and other metadata relating to software. 43 | type SBOMInfo struct { 44 | SPDXID *string `json:"SPDXID,omitempty"` 45 | SPDXVersion *string `json:"spdxVersion,omitempty"` 46 | CreationInfo *CreationInfo `json:"creationInfo,omitempty"` 47 | 48 | // Repo name 49 | Name *string `json:"name,omitempty"` 50 | DataLicense *string `json:"dataLicense,omitempty"` 51 | DocumentDescribes []string `json:"documentDescribes,omitempty"` 52 | DocumentNamespace *string `json:"documentNamespace,omitempty"` 53 | 54 | // List of packages dependencies 55 | Packages []*RepoDependencies `json:"packages,omitempty"` 56 | } 57 | 58 | func (s SBOM) String() string { 59 | return Stringify(s) 60 | } 61 | 62 | // GetSBOM fetches the software bill of materials for a repository. 63 | // 64 | // GitHub API docs: https://docs.github.com/rest/dependency-graph/sboms#export-a-software-bill-of-materials-sbom-for-a-repository 65 | // 66 | //meta:operation GET /repos/{owner}/{repo}/dependency-graph/sbom 67 | func (s *DependencyGraphService) GetSBOM(ctx context.Context, owner, repo string) (*SBOM, *Response, error) { 68 | u := fmt.Sprintf("repos/%v/%v/dependency-graph/sbom", owner, repo) 69 | 70 | req, err := s.client.NewRequest("GET", u, nil) 71 | if err != nil { 72 | return nil, nil, err 73 | } 74 | 75 | var sbom *SBOM 76 | resp, err := s.client.Do(ctx, req, &sbom) 77 | if err != nil { 78 | return nil, resp, err 79 | } 80 | 81 | return sbom, resp, nil 82 | } 83 | -------------------------------------------------------------------------------- /github/dependency_graph_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | "fmt" 11 | "net/http" 12 | "testing" 13 | "time" 14 | 15 | "github.com/google/go-cmp/cmp" 16 | ) 17 | 18 | func TestDependencyGraphService_GetSBOM(t *testing.T) { 19 | t.Parallel() 20 | client, mux, _ := setup(t) 21 | 22 | mux.HandleFunc("/repos/owner/repo/dependency-graph/sbom", func(w http.ResponseWriter, r *http.Request) { 23 | testMethod(t, r, "GET") 24 | fmt.Fprint(w, `{ 25 | "sbom":{ 26 | "creationInfo":{ 27 | "created":"2021-09-01T00:00:00Z" 28 | }, 29 | "name":"owner/repo", 30 | "packages":[ 31 | { 32 | "name":"rubygems:rails", 33 | "versionInfo":"1.0.0" 34 | } 35 | ] 36 | } 37 | }`) 38 | }) 39 | 40 | ctx := context.Background() 41 | sbom, _, err := client.DependencyGraph.GetSBOM(ctx, "owner", "repo") 42 | if err != nil { 43 | t.Errorf("DependencyGraph.GetSBOM returned error: %v", err) 44 | } 45 | 46 | testTime := time.Date(2021, 9, 1, 0, 0, 0, 0, time.UTC) 47 | want := &SBOM{ 48 | &SBOMInfo{ 49 | CreationInfo: &CreationInfo{ 50 | Created: &Timestamp{testTime}, 51 | }, 52 | Name: Ptr("owner/repo"), 53 | Packages: []*RepoDependencies{ 54 | { 55 | Name: Ptr("rubygems:rails"), 56 | VersionInfo: Ptr("1.0.0"), 57 | }, 58 | }, 59 | }, 60 | } 61 | 62 | if !cmp.Equal(sbom, want) { 63 | t.Errorf("DependencyGraph.GetSBOM returned %+v, want %+v", sbom, want) 64 | } 65 | 66 | const methodName = "GetSBOM" 67 | testBadOptions(t, methodName, func() (err error) { 68 | _, _, err = client.DependencyGraph.GetSBOM(ctx, "\n", "\n") 69 | return err 70 | }) 71 | 72 | testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 73 | got, resp, err := client.DependencyGraph.GetSBOM(ctx, "owner", "repo") 74 | if got != nil { 75 | t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 76 | } 77 | return resp, err 78 | }) 79 | } 80 | -------------------------------------------------------------------------------- /github/emojis.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | ) 11 | 12 | // EmojisService provides access to emoji-related functions in the GitHub API. 13 | type EmojisService service 14 | 15 | // List returns the emojis available to use on GitHub. 16 | // 17 | // GitHub API docs: https://docs.github.com/rest/emojis/emojis#get-emojis 18 | // 19 | //meta:operation GET /emojis 20 | func (s *EmojisService) List(ctx context.Context) (map[string]string, *Response, error) { 21 | req, err := s.client.NewRequest("GET", "emojis", nil) 22 | if err != nil { 23 | return nil, nil, err 24 | } 25 | 26 | var emoji map[string]string 27 | resp, err := s.client.Do(ctx, req, &emoji) 28 | if err != nil { 29 | return nil, resp, err 30 | } 31 | 32 | return emoji, resp, nil 33 | } 34 | 35 | // ListEmojis returns the emojis available to use on GitHub. 36 | // 37 | // Deprecated: Use EmojisService.List instead. 38 | func (c *Client) ListEmojis(ctx context.Context) (map[string]string, *Response, error) { 39 | return c.Emojis.List(ctx) 40 | } 41 | -------------------------------------------------------------------------------- /github/emojis_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | "fmt" 11 | "net/http" 12 | "testing" 13 | 14 | "github.com/google/go-cmp/cmp" 15 | ) 16 | 17 | func TestEmojisService_List(t *testing.T) { 18 | t.Parallel() 19 | client, mux, _ := setup(t) 20 | 21 | mux.HandleFunc("/emojis", func(w http.ResponseWriter, r *http.Request) { 22 | testMethod(t, r, "GET") 23 | fmt.Fprint(w, `{"+1": "+1.png"}`) 24 | }) 25 | 26 | ctx := context.Background() 27 | emoji, _, err := client.ListEmojis(ctx) 28 | if err != nil { 29 | t.Errorf("List returned error: %v", err) 30 | } 31 | 32 | want := map[string]string{"+1": "+1.png"} 33 | if !cmp.Equal(want, emoji) { 34 | t.Errorf("List returned %+v, want %+v", emoji, want) 35 | } 36 | 37 | const methodName = "List" 38 | testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 39 | got, resp, err := client.Emojis.List(ctx) 40 | if got != nil { 41 | t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 42 | } 43 | return resp, err 44 | }) 45 | } 46 | -------------------------------------------------------------------------------- /github/enterprise.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | // EnterpriseService provides access to the enterprise related functions 9 | // in the GitHub API. 10 | // 11 | // GitHub API docs: https://docs.github.com/rest/enterprise-admin/ 12 | type EnterpriseService service 13 | -------------------------------------------------------------------------------- /github/enterprise_audit_log.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | "fmt" 11 | ) 12 | 13 | // GetAuditLog gets the audit-log entries for an organization. 14 | // 15 | // GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/enterprise-admin/audit-log#get-the-audit-log-for-an-enterprise 16 | // 17 | //meta:operation GET /enterprises/{enterprise}/audit-log 18 | func (s *EnterpriseService) GetAuditLog(ctx context.Context, enterprise string, opts *GetAuditLogOptions) ([]*AuditEntry, *Response, error) { 19 | u := fmt.Sprintf("enterprises/%v/audit-log", enterprise) 20 | u, err := addOptions(u, opts) 21 | if err != nil { 22 | return nil, nil, err 23 | } 24 | 25 | req, err := s.client.NewRequest("GET", u, nil) 26 | if err != nil { 27 | return nil, nil, err 28 | } 29 | 30 | var auditEntries []*AuditEntry 31 | resp, err := s.client.Do(ctx, req, &auditEntries) 32 | if err != nil { 33 | return nil, resp, err 34 | } 35 | 36 | return auditEntries, resp, nil 37 | } 38 | -------------------------------------------------------------------------------- /github/enterprise_audit_log_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 The go-github AUTHORS. All rights reserved. 2 | // 3 | // `Use` of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | "fmt" 11 | "net/http" 12 | "testing" 13 | "time" 14 | ) 15 | 16 | func TestEnterpriseService_GetAuditLog(t *testing.T) { 17 | t.Parallel() 18 | client, mux, _ := setup(t) 19 | 20 | mux.HandleFunc("/enterprises/e/audit-log", func(w http.ResponseWriter, r *http.Request) { 21 | testMethod(t, r, "GET") 22 | 23 | fmt.Fprint(w, `[ 24 | { 25 | "workflow_id": 123456, 26 | "head_branch": "master", 27 | "org": "o", 28 | "trigger_id": null, 29 | "repo": "o/blue-crayon-1", 30 | "created_at": 1615077308538, 31 | "head_sha": "5acdeadbeef64d1a62388e901e5cdc9358644b37", 32 | "conclusion": "success", 33 | "actor": "testactor", 34 | "completed_at": "2021-03-07T00:35:08.000Z", 35 | "@timestamp": 1615077308538, 36 | "name": "Code scanning - action", 37 | "action": "workflows.completed_workflow_run", 38 | "started_at": "2021-03-07T00:33:04.000Z", 39 | "event": "schedule", 40 | "workflow_run_id": 628312345, 41 | "_document_id": "beeZYapIUe-wKg5-beadb33" 42 | } 43 | ]`) 44 | }) 45 | getOpts := GetAuditLogOptions{ 46 | Include: Ptr("all"), 47 | Phrase: Ptr("action:workflows"), 48 | Order: Ptr("asc"), 49 | } 50 | ctx := context.Background() 51 | auditEntries, _, err := client.Enterprise.GetAuditLog(ctx, "e", &getOpts) 52 | if err != nil { 53 | t.Errorf("Enterprise.GetAuditLog returned error: %v", err) 54 | } 55 | timestamp := time.Unix(0, 1615077308538*1e6) 56 | want := []*AuditEntry{ 57 | { 58 | Timestamp: &Timestamp{timestamp}, 59 | DocumentID: Ptr("beeZYapIUe-wKg5-beadb33"), 60 | Action: Ptr("workflows.completed_workflow_run"), 61 | Actor: Ptr("testactor"), 62 | CreatedAt: &Timestamp{timestamp}, 63 | Org: Ptr("o"), 64 | AdditionalFields: map[string]interface{}{ 65 | "completed_at": "2021-03-07T00:35:08.000Z", 66 | "conclusion": "success", 67 | "event": "schedule", 68 | "head_branch": "master", 69 | "head_sha": "5acdeadbeef64d1a62388e901e5cdc9358644b37", 70 | "name": "Code scanning - action", 71 | "repo": "o/blue-crayon-1", 72 | "started_at": "2021-03-07T00:33:04.000Z", 73 | "workflow_id": float64(123456), 74 | "workflow_run_id": float64(628312345), 75 | }, 76 | }, 77 | } 78 | 79 | assertNoDiff(t, want, auditEntries) 80 | 81 | const methodName = "GetAuditLog" 82 | testBadOptions(t, methodName, func() (err error) { 83 | _, _, err = client.Enterprise.GetAuditLog(ctx, "\n", &getOpts) 84 | return err 85 | }) 86 | 87 | testNewRequestAndDoFailureCategory(t, methodName, client, AuditLogCategory, func() (*Response, error) { 88 | got, resp, err := client.Enterprise.GetAuditLog(ctx, "o", &GetAuditLogOptions{}) 89 | if got != nil { 90 | t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 91 | } 92 | return resp, err 93 | }) 94 | } 95 | -------------------------------------------------------------------------------- /github/event.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "encoding/json" 10 | ) 11 | 12 | // Event represents a GitHub event. 13 | type Event struct { 14 | Type *string `json:"type,omitempty"` 15 | Public *bool `json:"public,omitempty"` 16 | RawPayload *json.RawMessage `json:"payload,omitempty"` 17 | Repo *Repository `json:"repo,omitempty"` 18 | Actor *User `json:"actor,omitempty"` 19 | Org *Organization `json:"org,omitempty"` 20 | CreatedAt *Timestamp `json:"created_at,omitempty"` 21 | ID *string `json:"id,omitempty"` 22 | } 23 | 24 | func (e Event) String() string { 25 | return Stringify(e) 26 | } 27 | 28 | // ParsePayload parses the event payload. For recognized event types, 29 | // a value of the corresponding struct type will be returned. 30 | func (e *Event) ParsePayload() (interface{}, error) { 31 | // It would be nice if e.Type were the snake_case name of the event, 32 | // but the existing interface uses the struct name instead. 33 | payload := EventForType(typeToMessageMapping[e.GetType()]) 34 | 35 | if err := json.Unmarshal(e.GetRawPayload(), &payload); err != nil { 36 | return nil, err 37 | } 38 | 39 | return payload, nil 40 | } 41 | 42 | // Payload returns the parsed event payload. For recognized event types, 43 | // a value of the corresponding struct type will be returned. 44 | // 45 | // Deprecated: Use ParsePayload instead, which returns an error 46 | // rather than panics if JSON unmarshaling raw payload fails. 47 | func (e *Event) Payload() (payload interface{}) { 48 | var err error 49 | payload, err = e.ParsePayload() 50 | if err != nil { 51 | panic(err) 52 | } 53 | return payload 54 | } 55 | -------------------------------------------------------------------------------- /github/git.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | // GitService handles communication with the git data related 9 | // methods of the GitHub API. 10 | // 11 | // GitHub API docs: https://docs.github.com/rest/git/ 12 | type GitService service 13 | -------------------------------------------------------------------------------- /github/git_blobs.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "bytes" 10 | "context" 11 | "fmt" 12 | ) 13 | 14 | // Blob represents a blob object. 15 | type Blob struct { 16 | Content *string `json:"content,omitempty"` 17 | Encoding *string `json:"encoding,omitempty"` 18 | SHA *string `json:"sha,omitempty"` 19 | Size *int `json:"size,omitempty"` 20 | URL *string `json:"url,omitempty"` 21 | NodeID *string `json:"node_id,omitempty"` 22 | } 23 | 24 | // GetBlob fetches a blob from a repo given a SHA. 25 | // 26 | // GitHub API docs: https://docs.github.com/rest/git/blobs#get-a-blob 27 | // 28 | //meta:operation GET /repos/{owner}/{repo}/git/blobs/{file_sha} 29 | func (s *GitService) GetBlob(ctx context.Context, owner string, repo string, sha string) (*Blob, *Response, error) { 30 | u := fmt.Sprintf("repos/%v/%v/git/blobs/%v", owner, repo, sha) 31 | req, err := s.client.NewRequest("GET", u, nil) 32 | if err != nil { 33 | return nil, nil, err 34 | } 35 | 36 | blob := new(Blob) 37 | resp, err := s.client.Do(ctx, req, blob) 38 | if err != nil { 39 | return nil, resp, err 40 | } 41 | 42 | return blob, resp, nil 43 | } 44 | 45 | // GetBlobRaw fetches a blob's contents from a repo. 46 | // Unlike GetBlob, it returns the raw bytes rather than the base64-encoded data. 47 | // 48 | // GitHub API docs: https://docs.github.com/rest/git/blobs#get-a-blob 49 | // 50 | //meta:operation GET /repos/{owner}/{repo}/git/blobs/{file_sha} 51 | func (s *GitService) GetBlobRaw(ctx context.Context, owner, repo, sha string) ([]byte, *Response, error) { 52 | u := fmt.Sprintf("repos/%v/%v/git/blobs/%v", owner, repo, sha) 53 | req, err := s.client.NewRequest("GET", u, nil) 54 | if err != nil { 55 | return nil, nil, err 56 | } 57 | 58 | req.Header.Set("Accept", "application/vnd.github.v3.raw") 59 | 60 | var buf bytes.Buffer 61 | resp, err := s.client.Do(ctx, req, &buf) 62 | if err != nil { 63 | return nil, resp, err 64 | } 65 | 66 | return buf.Bytes(), resp, nil 67 | } 68 | 69 | // CreateBlob creates a blob object. 70 | // 71 | // GitHub API docs: https://docs.github.com/rest/git/blobs#create-a-blob 72 | // 73 | //meta:operation POST /repos/{owner}/{repo}/git/blobs 74 | func (s *GitService) CreateBlob(ctx context.Context, owner string, repo string, blob *Blob) (*Blob, *Response, error) { 75 | u := fmt.Sprintf("repos/%v/%v/git/blobs", owner, repo) 76 | req, err := s.client.NewRequest("POST", u, blob) 77 | if err != nil { 78 | return nil, nil, err 79 | } 80 | 81 | t := new(Blob) 82 | resp, err := s.client.Do(ctx, req, t) 83 | if err != nil { 84 | return nil, resp, err 85 | } 86 | 87 | return t, resp, nil 88 | } 89 | -------------------------------------------------------------------------------- /github/git_tags.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | "fmt" 11 | ) 12 | 13 | // Tag represents a tag object. 14 | type Tag struct { 15 | Tag *string `json:"tag,omitempty"` 16 | SHA *string `json:"sha,omitempty"` 17 | URL *string `json:"url,omitempty"` 18 | Message *string `json:"message,omitempty"` 19 | Tagger *CommitAuthor `json:"tagger,omitempty"` 20 | Object *GitObject `json:"object,omitempty"` 21 | Verification *SignatureVerification `json:"verification,omitempty"` 22 | NodeID *string `json:"node_id,omitempty"` 23 | } 24 | 25 | // createTagRequest represents the body of a CreateTag request. This is mostly 26 | // identical to Tag with the exception that the object SHA and Type are 27 | // top-level fields, rather than being nested inside a JSON object. 28 | type createTagRequest struct { 29 | Tag *string `json:"tag,omitempty"` 30 | Message *string `json:"message,omitempty"` 31 | Object *string `json:"object,omitempty"` 32 | Type *string `json:"type,omitempty"` 33 | Tagger *CommitAuthor `json:"tagger,omitempty"` 34 | } 35 | 36 | // GetTag fetches a tag from a repo given a SHA. 37 | // 38 | // GitHub API docs: https://docs.github.com/rest/git/tags#get-a-tag 39 | // 40 | //meta:operation GET /repos/{owner}/{repo}/git/tags/{tag_sha} 41 | func (s *GitService) GetTag(ctx context.Context, owner string, repo string, sha string) (*Tag, *Response, error) { 42 | u := fmt.Sprintf("repos/%v/%v/git/tags/%v", owner, repo, sha) 43 | req, err := s.client.NewRequest("GET", u, nil) 44 | if err != nil { 45 | return nil, nil, err 46 | } 47 | 48 | tag := new(Tag) 49 | resp, err := s.client.Do(ctx, req, tag) 50 | if err != nil { 51 | return nil, resp, err 52 | } 53 | 54 | return tag, resp, nil 55 | } 56 | 57 | // CreateTag creates a tag object. 58 | // 59 | // GitHub API docs: https://docs.github.com/rest/git/tags#create-a-tag-object 60 | // 61 | //meta:operation POST /repos/{owner}/{repo}/git/tags 62 | func (s *GitService) CreateTag(ctx context.Context, owner string, repo string, tag *Tag) (*Tag, *Response, error) { 63 | u := fmt.Sprintf("repos/%v/%v/git/tags", owner, repo) 64 | 65 | // convert Tag into a createTagRequest 66 | tagRequest := &createTagRequest{ 67 | Tag: tag.Tag, 68 | Message: tag.Message, 69 | Tagger: tag.Tagger, 70 | } 71 | if tag.Object != nil { 72 | tagRequest.Object = tag.Object.SHA 73 | tagRequest.Type = tag.Object.Type 74 | } 75 | 76 | req, err := s.client.NewRequest("POST", u, tagRequest) 77 | if err != nil { 78 | return nil, nil, err 79 | } 80 | 81 | t := new(Tag) 82 | resp, err := s.client.Do(ctx, req, t) 83 | if err != nil { 84 | return nil, resp, err 85 | } 86 | 87 | return t, resp, nil 88 | } 89 | -------------------------------------------------------------------------------- /github/gitignore.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | "fmt" 11 | ) 12 | 13 | // GitignoresService provides access to the gitignore related functions in the 14 | // GitHub API. 15 | // 16 | // GitHub API docs: https://docs.github.com/rest/gitignore/ 17 | type GitignoresService service 18 | 19 | // Gitignore represents a .gitignore file as returned by the GitHub API. 20 | type Gitignore struct { 21 | Name *string `json:"name,omitempty"` 22 | Source *string `json:"source,omitempty"` 23 | } 24 | 25 | func (g Gitignore) String() string { 26 | return Stringify(g) 27 | } 28 | 29 | // List all available Gitignore templates. 30 | // 31 | // GitHub API docs: https://docs.github.com/rest/gitignore/gitignore#get-all-gitignore-templates 32 | // 33 | //meta:operation GET /gitignore/templates 34 | func (s *GitignoresService) List(ctx context.Context) ([]string, *Response, error) { 35 | req, err := s.client.NewRequest("GET", "gitignore/templates", nil) 36 | if err != nil { 37 | return nil, nil, err 38 | } 39 | 40 | var availableTemplates []string 41 | resp, err := s.client.Do(ctx, req, &availableTemplates) 42 | if err != nil { 43 | return nil, resp, err 44 | } 45 | 46 | return availableTemplates, resp, nil 47 | } 48 | 49 | // Get a Gitignore by name. 50 | // 51 | // GitHub API docs: https://docs.github.com/rest/gitignore/gitignore#get-a-gitignore-template 52 | // 53 | //meta:operation GET /gitignore/templates/{name} 54 | func (s *GitignoresService) Get(ctx context.Context, name string) (*Gitignore, *Response, error) { 55 | u := fmt.Sprintf("gitignore/templates/%v", name) 56 | req, err := s.client.NewRequest("GET", u, nil) 57 | if err != nil { 58 | return nil, nil, err 59 | } 60 | 61 | gitignore := new(Gitignore) 62 | resp, err := s.client.Do(ctx, req, gitignore) 63 | if err != nil { 64 | return nil, resp, err 65 | } 66 | 67 | return gitignore, resp, nil 68 | } 69 | -------------------------------------------------------------------------------- /github/gitignore_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | "fmt" 11 | "net/http" 12 | "testing" 13 | 14 | "github.com/google/go-cmp/cmp" 15 | ) 16 | 17 | func TestGitignoresService_List(t *testing.T) { 18 | t.Parallel() 19 | client, mux, _ := setup(t) 20 | 21 | mux.HandleFunc("/gitignore/templates", func(w http.ResponseWriter, r *http.Request) { 22 | testMethod(t, r, "GET") 23 | fmt.Fprint(w, `["C", "Go"]`) 24 | }) 25 | 26 | ctx := context.Background() 27 | available, _, err := client.Gitignores.List(ctx) 28 | if err != nil { 29 | t.Errorf("Gitignores.List returned error: %v", err) 30 | } 31 | 32 | want := []string{"C", "Go"} 33 | if !cmp.Equal(available, want) { 34 | t.Errorf("Gitignores.List returned %+v, want %+v", available, want) 35 | } 36 | 37 | const methodName = "List" 38 | testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 39 | got, resp, err := client.Gitignores.List(ctx) 40 | if got != nil { 41 | t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 42 | } 43 | return resp, err 44 | }) 45 | } 46 | 47 | func TestGitignoresService_Get(t *testing.T) { 48 | t.Parallel() 49 | client, mux, _ := setup(t) 50 | 51 | mux.HandleFunc("/gitignore/templates/name", func(w http.ResponseWriter, r *http.Request) { 52 | testMethod(t, r, "GET") 53 | fmt.Fprint(w, `{"name":"Name","source":"template source"}`) 54 | }) 55 | 56 | ctx := context.Background() 57 | gitignore, _, err := client.Gitignores.Get(ctx, "name") 58 | if err != nil { 59 | t.Errorf("Gitignores.List returned error: %v", err) 60 | } 61 | 62 | want := &Gitignore{Name: Ptr("Name"), Source: Ptr("template source")} 63 | if !cmp.Equal(gitignore, want) { 64 | t.Errorf("Gitignores.Get returned %+v, want %+v", gitignore, want) 65 | } 66 | 67 | const methodName = "Get" 68 | testBadOptions(t, methodName, func() (err error) { 69 | _, _, err = client.Gitignores.Get(ctx, "\n") 70 | return err 71 | }) 72 | 73 | testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 74 | got, resp, err := client.Gitignores.Get(ctx, "name") 75 | if got != nil { 76 | t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 77 | } 78 | return resp, err 79 | }) 80 | } 81 | 82 | func TestGitignoresService_Get_invalidTemplate(t *testing.T) { 83 | t.Parallel() 84 | client, _, _ := setup(t) 85 | 86 | ctx := context.Background() 87 | _, _, err := client.Gitignores.Get(ctx, "%") 88 | testURLParseError(t, err) 89 | } 90 | 91 | func TestGitignore_Marshal(t *testing.T) { 92 | t.Parallel() 93 | testJSONMarshal(t, &Gitignore{}, "{}") 94 | 95 | u := &Gitignore{ 96 | Name: Ptr("name"), 97 | Source: Ptr("source"), 98 | } 99 | 100 | want := `{ 101 | "name": "name", 102 | "source": "source" 103 | }` 104 | 105 | testJSONMarshal(t, u, want) 106 | } 107 | -------------------------------------------------------------------------------- /github/interactions.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | // InteractionsService handles communication with the repository and organization related 9 | // methods of the GitHub API. 10 | // 11 | // GitHub API docs: https://docs.github.com/rest/interactions/ 12 | type InteractionsService service 13 | 14 | // InteractionRestriction represents the interaction restrictions for repository and organization. 15 | type InteractionRestriction struct { 16 | // Specifies the group of GitHub users who can 17 | // comment, open issues, or create pull requests for the given repository. 18 | // Possible values are: "existing_users", "contributors_only" and "collaborators_only". 19 | Limit *string `json:"limit,omitempty"` 20 | 21 | // Origin specifies the type of the resource to interact with. 22 | // Possible values are: "repository" and "organization". 23 | Origin *string `json:"origin,omitempty"` 24 | 25 | // ExpiresAt specifies the time after which the interaction restrictions expire. 26 | // The default expiry time is 24 hours from the time restriction is created. 27 | ExpiresAt *Timestamp `json:"expires_at,omitempty"` 28 | } 29 | -------------------------------------------------------------------------------- /github/interactions_orgs.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | "fmt" 11 | ) 12 | 13 | // GetRestrictionsForOrg fetches the interaction restrictions for an organization. 14 | // 15 | // GitHub API docs: https://docs.github.com/rest/interactions/orgs#get-interaction-restrictions-for-an-organization 16 | // 17 | //meta:operation GET /orgs/{org}/interaction-limits 18 | func (s *InteractionsService) GetRestrictionsForOrg(ctx context.Context, organization string) (*InteractionRestriction, *Response, error) { 19 | u := fmt.Sprintf("orgs/%v/interaction-limits", organization) 20 | req, err := s.client.NewRequest("GET", u, nil) 21 | if err != nil { 22 | return nil, nil, err 23 | } 24 | 25 | // TODO: remove custom Accept header when this API fully launches. 26 | req.Header.Set("Accept", mediaTypeInteractionRestrictionsPreview) 27 | 28 | organizationInteractions := new(InteractionRestriction) 29 | 30 | resp, err := s.client.Do(ctx, req, organizationInteractions) 31 | if err != nil { 32 | return nil, resp, err 33 | } 34 | 35 | return organizationInteractions, resp, nil 36 | } 37 | 38 | // UpdateRestrictionsForOrg adds or updates the interaction restrictions for an organization. 39 | // 40 | // limit specifies the group of GitHub users who can comment, open issues, or create pull requests 41 | // in public repositories for the given organization. 42 | // Possible values are: "existing_users", "contributors_only", "collaborators_only". 43 | // 44 | // GitHub API docs: https://docs.github.com/rest/interactions/orgs#set-interaction-restrictions-for-an-organization 45 | // 46 | //meta:operation PUT /orgs/{org}/interaction-limits 47 | func (s *InteractionsService) UpdateRestrictionsForOrg(ctx context.Context, organization, limit string) (*InteractionRestriction, *Response, error) { 48 | u := fmt.Sprintf("orgs/%v/interaction-limits", organization) 49 | 50 | interaction := &InteractionRestriction{Limit: Ptr(limit)} 51 | 52 | req, err := s.client.NewRequest("PUT", u, interaction) 53 | if err != nil { 54 | return nil, nil, err 55 | } 56 | 57 | // TODO: remove custom Accept header when this API fully launches. 58 | req.Header.Set("Accept", mediaTypeInteractionRestrictionsPreview) 59 | 60 | organizationInteractions := new(InteractionRestriction) 61 | 62 | resp, err := s.client.Do(ctx, req, organizationInteractions) 63 | if err != nil { 64 | return nil, resp, err 65 | } 66 | 67 | return organizationInteractions, resp, nil 68 | } 69 | 70 | // RemoveRestrictionsFromOrg removes the interaction restrictions for an organization. 71 | // 72 | // GitHub API docs: https://docs.github.com/rest/interactions/orgs#remove-interaction-restrictions-for-an-organization 73 | // 74 | //meta:operation DELETE /orgs/{org}/interaction-limits 75 | func (s *InteractionsService) RemoveRestrictionsFromOrg(ctx context.Context, organization string) (*Response, error) { 76 | u := fmt.Sprintf("orgs/%v/interaction-limits", organization) 77 | req, err := s.client.NewRequest("DELETE", u, nil) 78 | if err != nil { 79 | return nil, err 80 | } 81 | 82 | // TODO: remove custom Accept header when this API fully launches. 83 | req.Header.Set("Accept", mediaTypeInteractionRestrictionsPreview) 84 | 85 | return s.client.Do(ctx, req, nil) 86 | } 87 | -------------------------------------------------------------------------------- /github/interactions_repos.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | "fmt" 11 | ) 12 | 13 | // GetRestrictionsForRepo fetches the interaction restrictions for a repository. 14 | // 15 | // GitHub API docs: https://docs.github.com/rest/interactions/repos#get-interaction-restrictions-for-a-repository 16 | // 17 | //meta:operation GET /repos/{owner}/{repo}/interaction-limits 18 | func (s *InteractionsService) GetRestrictionsForRepo(ctx context.Context, owner, repo string) (*InteractionRestriction, *Response, error) { 19 | u := fmt.Sprintf("repos/%v/%v/interaction-limits", owner, repo) 20 | req, err := s.client.NewRequest("GET", u, nil) 21 | if err != nil { 22 | return nil, nil, err 23 | } 24 | 25 | // TODO: remove custom Accept header when this API fully launches. 26 | req.Header.Set("Accept", mediaTypeInteractionRestrictionsPreview) 27 | 28 | repositoryInteractions := new(InteractionRestriction) 29 | 30 | resp, err := s.client.Do(ctx, req, repositoryInteractions) 31 | if err != nil { 32 | return nil, resp, err 33 | } 34 | 35 | return repositoryInteractions, resp, nil 36 | } 37 | 38 | // UpdateRestrictionsForRepo adds or updates the interaction restrictions for a repository. 39 | // 40 | // limit specifies the group of GitHub users who can comment, open issues, or create pull requests 41 | // for the given repository. 42 | // Possible values are: "existing_users", "contributors_only", "collaborators_only". 43 | // 44 | // GitHub API docs: https://docs.github.com/rest/interactions/repos#set-interaction-restrictions-for-a-repository 45 | // 46 | //meta:operation PUT /repos/{owner}/{repo}/interaction-limits 47 | func (s *InteractionsService) UpdateRestrictionsForRepo(ctx context.Context, owner, repo, limit string) (*InteractionRestriction, *Response, error) { 48 | u := fmt.Sprintf("repos/%v/%v/interaction-limits", owner, repo) 49 | 50 | interaction := &InteractionRestriction{Limit: Ptr(limit)} 51 | 52 | req, err := s.client.NewRequest("PUT", u, interaction) 53 | if err != nil { 54 | return nil, nil, err 55 | } 56 | 57 | // TODO: remove custom Accept header when this API fully launches. 58 | req.Header.Set("Accept", mediaTypeInteractionRestrictionsPreview) 59 | 60 | repositoryInteractions := new(InteractionRestriction) 61 | 62 | resp, err := s.client.Do(ctx, req, repositoryInteractions) 63 | if err != nil { 64 | return nil, resp, err 65 | } 66 | 67 | return repositoryInteractions, resp, nil 68 | } 69 | 70 | // RemoveRestrictionsFromRepo removes the interaction restrictions for a repository. 71 | // 72 | // GitHub API docs: https://docs.github.com/rest/interactions/repos#remove-interaction-restrictions-for-a-repository 73 | // 74 | //meta:operation DELETE /repos/{owner}/{repo}/interaction-limits 75 | func (s *InteractionsService) RemoveRestrictionsFromRepo(ctx context.Context, owner, repo string) (*Response, error) { 76 | u := fmt.Sprintf("repos/%v/%v/interaction-limits", owner, repo) 77 | req, err := s.client.NewRequest("DELETE", u, nil) 78 | if err != nil { 79 | return nil, err 80 | } 81 | 82 | // TODO: remove custom Accept header when this API fully launches. 83 | req.Header.Set("Accept", mediaTypeInteractionRestrictionsPreview) 84 | 85 | return s.client.Do(ctx, req, nil) 86 | } 87 | -------------------------------------------------------------------------------- /github/interactions_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import "testing" 9 | 10 | func TestInteractionRestriction_Marshal(t *testing.T) { 11 | t.Parallel() 12 | testJSONMarshal(t, &InteractionRestriction{}, "{}") 13 | 14 | u := &InteractionRestriction{ 15 | Limit: Ptr("limit"), 16 | Origin: Ptr("origin"), 17 | ExpiresAt: &Timestamp{referenceTime}, 18 | } 19 | 20 | want := `{ 21 | "limit": "limit", 22 | "origin": "origin", 23 | "expires_at": ` + referenceTimeStr + ` 24 | }` 25 | 26 | testJSONMarshal(t, u, want) 27 | } 28 | -------------------------------------------------------------------------------- /github/licenses.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | "fmt" 11 | ) 12 | 13 | // LicensesService handles communication with the license related 14 | // methods of the GitHub API. 15 | // 16 | // GitHub API docs: https://docs.github.com/rest/licenses/ 17 | type LicensesService service 18 | 19 | // RepositoryLicense represents the license for a repository. 20 | type RepositoryLicense struct { 21 | Name *string `json:"name,omitempty"` 22 | Path *string `json:"path,omitempty"` 23 | 24 | SHA *string `json:"sha,omitempty"` 25 | Size *int `json:"size,omitempty"` 26 | URL *string `json:"url,omitempty"` 27 | HTMLURL *string `json:"html_url,omitempty"` 28 | GitURL *string `json:"git_url,omitempty"` 29 | DownloadURL *string `json:"download_url,omitempty"` 30 | Type *string `json:"type,omitempty"` 31 | Content *string `json:"content,omitempty"` 32 | Encoding *string `json:"encoding,omitempty"` 33 | License *License `json:"license,omitempty"` 34 | } 35 | 36 | func (l RepositoryLicense) String() string { 37 | return Stringify(l) 38 | } 39 | 40 | // License represents an open source license. 41 | type License struct { 42 | Key *string `json:"key,omitempty"` 43 | Name *string `json:"name,omitempty"` 44 | URL *string `json:"url,omitempty"` 45 | 46 | SPDXID *string `json:"spdx_id,omitempty"` 47 | HTMLURL *string `json:"html_url,omitempty"` 48 | Featured *bool `json:"featured,omitempty"` 49 | Description *string `json:"description,omitempty"` 50 | Implementation *string `json:"implementation,omitempty"` 51 | Permissions *[]string `json:"permissions,omitempty"` 52 | Conditions *[]string `json:"conditions,omitempty"` 53 | Limitations *[]string `json:"limitations,omitempty"` 54 | Body *string `json:"body,omitempty"` 55 | } 56 | 57 | func (l License) String() string { 58 | return Stringify(l) 59 | } 60 | 61 | // List popular open source licenses. 62 | // 63 | // GitHub API docs: https://docs.github.com/rest/licenses/licenses#get-all-commonly-used-licenses 64 | // 65 | //meta:operation GET /licenses 66 | func (s *LicensesService) List(ctx context.Context) ([]*License, *Response, error) { 67 | req, err := s.client.NewRequest("GET", "licenses", nil) 68 | if err != nil { 69 | return nil, nil, err 70 | } 71 | 72 | var licenses []*License 73 | resp, err := s.client.Do(ctx, req, &licenses) 74 | if err != nil { 75 | return nil, resp, err 76 | } 77 | 78 | return licenses, resp, nil 79 | } 80 | 81 | // Get extended metadata for one license. 82 | // 83 | // GitHub API docs: https://docs.github.com/rest/licenses/licenses#get-a-license 84 | // 85 | //meta:operation GET /licenses/{license} 86 | func (s *LicensesService) Get(ctx context.Context, licenseName string) (*License, *Response, error) { 87 | u := fmt.Sprintf("licenses/%s", licenseName) 88 | 89 | req, err := s.client.NewRequest("GET", u, nil) 90 | if err != nil { 91 | return nil, nil, err 92 | } 93 | 94 | license := new(License) 95 | resp, err := s.client.Do(ctx, req, license) 96 | if err != nil { 97 | return nil, resp, err 98 | } 99 | 100 | return license, resp, nil 101 | } 102 | -------------------------------------------------------------------------------- /github/markdown.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "bytes" 10 | "context" 11 | ) 12 | 13 | // MarkdownService provides access to markdown-related functions in the GitHub API. 14 | type MarkdownService service 15 | 16 | // MarkdownOptions specifies optional parameters to the Render method. 17 | type MarkdownOptions struct { 18 | // Mode identifies the rendering mode. Possible values are: 19 | // markdown - render a document as plain Render, just like 20 | // README files are rendered. 21 | // 22 | // gfm - to render a document as user-content, e.g. like user 23 | // comments or issues are rendered. In GFM mode, hard line breaks are 24 | // always taken into account, and issue and user mentions are linked 25 | // accordingly. 26 | // 27 | // Default is "markdown". 28 | Mode string 29 | 30 | // Context identifies the repository context. Only taken into account 31 | // when rendering as "gfm". 32 | Context string 33 | } 34 | 35 | type markdownRenderRequest struct { 36 | Text *string `json:"text,omitempty"` 37 | Mode *string `json:"mode,omitempty"` 38 | Context *string `json:"context,omitempty"` 39 | } 40 | 41 | // Render renders an arbitrary Render document. 42 | // 43 | // GitHub API docs: https://docs.github.com/rest/markdown/markdown#render-a-markdown-document 44 | // 45 | //meta:operation POST /markdown 46 | func (s *MarkdownService) Render(ctx context.Context, text string, opts *MarkdownOptions) (string, *Response, error) { 47 | request := &markdownRenderRequest{Text: Ptr(text)} 48 | if opts != nil { 49 | if opts.Mode != "" { 50 | request.Mode = Ptr(opts.Mode) 51 | } 52 | if opts.Context != "" { 53 | request.Context = Ptr(opts.Context) 54 | } 55 | } 56 | 57 | req, err := s.client.NewRequest("POST", "markdown", request) 58 | if err != nil { 59 | return "", nil, err 60 | } 61 | 62 | buf := new(bytes.Buffer) 63 | resp, err := s.client.Do(ctx, req, buf) 64 | if err != nil { 65 | return "", resp, err 66 | } 67 | 68 | return buf.String(), resp, nil 69 | } 70 | -------------------------------------------------------------------------------- /github/markdown_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | "encoding/json" 11 | "fmt" 12 | "net/http" 13 | "testing" 14 | 15 | "github.com/google/go-cmp/cmp" 16 | ) 17 | 18 | func TestMarkdownService_Markdown(t *testing.T) { 19 | t.Parallel() 20 | client, mux, _ := setup(t) 21 | 22 | input := &markdownRenderRequest{ 23 | Text: Ptr("# text #"), 24 | Mode: Ptr("gfm"), 25 | Context: Ptr("google/go-github"), 26 | } 27 | mux.HandleFunc("/markdown", func(w http.ResponseWriter, r *http.Request) { 28 | v := new(markdownRenderRequest) 29 | assertNilError(t, json.NewDecoder(r.Body).Decode(v)) 30 | 31 | testMethod(t, r, "POST") 32 | if !cmp.Equal(v, input) { 33 | t.Errorf("Request body = %+v, want %+v", v, input) 34 | } 35 | fmt.Fprint(w, `

text

`) 36 | }) 37 | 38 | ctx := context.Background() 39 | md, _, err := client.Markdown.Render(ctx, "# text #", &MarkdownOptions{ 40 | Mode: "gfm", 41 | Context: "google/go-github", 42 | }) 43 | if err != nil { 44 | t.Errorf("Render returned error: %v", err) 45 | } 46 | 47 | if want := "

text

"; want != md { 48 | t.Errorf("Render returned %+v, want %+v", md, want) 49 | } 50 | 51 | const methodName = "Render" 52 | testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 53 | got, resp, err := client.Markdown.Render(ctx, "# text #", &MarkdownOptions{ 54 | Mode: "gfm", 55 | Context: "google/go-github", 56 | }) 57 | if got != "" { 58 | t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 59 | } 60 | return resp, err 61 | }) 62 | } 63 | 64 | func TestMarkdownRenderRequest_Marshal(t *testing.T) { 65 | t.Parallel() 66 | testJSONMarshal(t, &markdownRenderRequest{}, "{}") 67 | 68 | a := &markdownRenderRequest{ 69 | Text: Ptr("txt"), 70 | Mode: Ptr("mode"), 71 | Context: Ptr("ctx"), 72 | } 73 | 74 | want := `{ 75 | "text": "txt", 76 | "mode": "mode", 77 | "context": "ctx" 78 | }` 79 | 80 | testJSONMarshal(t, a, want) 81 | } 82 | -------------------------------------------------------------------------------- /github/orgs_actions_allowed.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | ) 11 | 12 | // GetActionsAllowed gets the actions that are allowed in an organization. 13 | // 14 | // Deprecated: please use `client.Actions.GetActionsAllowed` instead. 15 | // 16 | // GitHub API docs: https://docs.github.com/rest/actions/permissions#get-allowed-actions-and-reusable-workflows-for-an-organization 17 | // 18 | //meta:operation GET /orgs/{org}/actions/permissions/selected-actions 19 | func (s *OrganizationsService) GetActionsAllowed(ctx context.Context, org string) (*ActionsAllowed, *Response, error) { 20 | s2 := (*ActionsService)(s) 21 | return s2.GetActionsAllowed(ctx, org) 22 | } 23 | 24 | // EditActionsAllowed sets the actions that are allowed in an organization. 25 | // 26 | // Deprecated: please use `client.Actions.EditActionsAllowed` instead. 27 | // 28 | // GitHub API docs: https://docs.github.com/rest/actions/permissions#set-allowed-actions-and-reusable-workflows-for-an-organization 29 | // 30 | //meta:operation PUT /orgs/{org}/actions/permissions/selected-actions 31 | func (s *OrganizationsService) EditActionsAllowed(ctx context.Context, org string, actionsAllowed ActionsAllowed) (*ActionsAllowed, *Response, error) { 32 | s2 := (*ActionsService)(s) 33 | return s2.EditActionsAllowed(ctx, org, actionsAllowed) 34 | } 35 | -------------------------------------------------------------------------------- /github/orgs_actions_allowed_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | "encoding/json" 11 | "fmt" 12 | "net/http" 13 | "testing" 14 | 15 | "github.com/google/go-cmp/cmp" 16 | ) 17 | 18 | func TestOrganizationsService_GetActionsAllowed(t *testing.T) { 19 | t.Parallel() 20 | client, mux, _ := setup(t) 21 | 22 | mux.HandleFunc("/orgs/o/actions/permissions/selected-actions", func(w http.ResponseWriter, r *http.Request) { 23 | testMethod(t, r, "GET") 24 | fmt.Fprint(w, `{"github_owned_allowed":true, "verified_allowed":false, "patterns_allowed":["a/b"]}`) 25 | }) 26 | 27 | ctx := context.Background() 28 | org, _, err := client.Organizations.GetActionsAllowed(ctx, "o") 29 | if err != nil { 30 | t.Errorf("Organizations.GetActionsAllowed returned error: %v", err) 31 | } 32 | want := &ActionsAllowed{GithubOwnedAllowed: Ptr(true), VerifiedAllowed: Ptr(false), PatternsAllowed: []string{"a/b"}} 33 | if !cmp.Equal(org, want) { 34 | t.Errorf("Organizations.GetActionsAllowed returned %+v, want %+v", org, want) 35 | } 36 | 37 | const methodName = "GetActionsAllowed" 38 | testBadOptions(t, methodName, func() (err error) { 39 | _, _, err = client.Organizations.GetActionsAllowed(ctx, "\n") 40 | return err 41 | }) 42 | 43 | testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 44 | got, resp, err := client.Organizations.GetActionsAllowed(ctx, "o") 45 | if got != nil { 46 | t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 47 | } 48 | return resp, err 49 | }) 50 | } 51 | 52 | func TestOrganizationsService_EditActionsAllowed(t *testing.T) { 53 | t.Parallel() 54 | client, mux, _ := setup(t) 55 | 56 | input := &ActionsAllowed{GithubOwnedAllowed: Ptr(true), VerifiedAllowed: Ptr(false), PatternsAllowed: []string{"a/b"}} 57 | 58 | mux.HandleFunc("/orgs/o/actions/permissions/selected-actions", func(w http.ResponseWriter, r *http.Request) { 59 | v := new(ActionsAllowed) 60 | assertNilError(t, json.NewDecoder(r.Body).Decode(v)) 61 | 62 | testMethod(t, r, "PUT") 63 | if !cmp.Equal(v, input) { 64 | t.Errorf("Request body = %+v, want %+v", v, input) 65 | } 66 | 67 | fmt.Fprint(w, `{"github_owned_allowed":true, "verified_allowed":false, "patterns_allowed":["a/b"]}`) 68 | }) 69 | 70 | ctx := context.Background() 71 | org, _, err := client.Organizations.EditActionsAllowed(ctx, "o", *input) 72 | if err != nil { 73 | t.Errorf("Organizations.EditActionsAllowed returned error: %v", err) 74 | } 75 | 76 | want := &ActionsAllowed{GithubOwnedAllowed: Ptr(true), VerifiedAllowed: Ptr(false), PatternsAllowed: []string{"a/b"}} 77 | if !cmp.Equal(org, want) { 78 | t.Errorf("Organizations.EditActionsAllowed returned %+v, want %+v", org, want) 79 | } 80 | 81 | const methodName = "EditActionsAllowed" 82 | testBadOptions(t, methodName, func() (err error) { 83 | _, _, err = client.Organizations.EditActionsAllowed(ctx, "\n", *input) 84 | return err 85 | }) 86 | 87 | testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 88 | got, resp, err := client.Organizations.EditActionsAllowed(ctx, "o", *input) 89 | if got != nil { 90 | t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 91 | } 92 | return resp, err 93 | }) 94 | } 95 | -------------------------------------------------------------------------------- /github/orgs_actions_permissions.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | ) 11 | 12 | // GetActionsPermissions gets the GitHub Actions permissions policy for repositories and allowed actions in an organization. 13 | // 14 | // Deprecated: please use `client.Actions.GetActionsPermissions` instead. 15 | // 16 | // GitHub API docs: https://docs.github.com/rest/actions/permissions#get-github-actions-permissions-for-an-organization 17 | // 18 | //meta:operation GET /orgs/{org}/actions/permissions 19 | func (s *OrganizationsService) GetActionsPermissions(ctx context.Context, org string) (*ActionsPermissions, *Response, error) { 20 | s2 := (*ActionsService)(s) 21 | return s2.GetActionsPermissions(ctx, org) 22 | } 23 | 24 | // EditActionsPermissions sets the permissions policy for repositories and allowed actions in an organization. 25 | // 26 | // Deprecated: please use `client.Actions.EditActionsPermissions` instead. 27 | // 28 | // GitHub API docs: https://docs.github.com/rest/actions/permissions#set-github-actions-permissions-for-an-organization 29 | // 30 | //meta:operation PUT /orgs/{org}/actions/permissions 31 | func (s *OrganizationsService) EditActionsPermissions(ctx context.Context, org string, actionsPermissions ActionsPermissions) (*ActionsPermissions, *Response, error) { 32 | s2 := (*ActionsService)(s) 33 | return s2.EditActionsPermissions(ctx, org, actionsPermissions) 34 | } 35 | -------------------------------------------------------------------------------- /github/orgs_actions_permissions_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | "encoding/json" 11 | "fmt" 12 | "net/http" 13 | "testing" 14 | 15 | "github.com/google/go-cmp/cmp" 16 | ) 17 | 18 | func TestOrganizationsService_GetActionsPermissions(t *testing.T) { 19 | t.Parallel() 20 | client, mux, _ := setup(t) 21 | 22 | mux.HandleFunc("/orgs/o/actions/permissions", func(w http.ResponseWriter, r *http.Request) { 23 | testMethod(t, r, "GET") 24 | fmt.Fprint(w, `{"enabled_repositories": "all", "allowed_actions": "all"}`) 25 | }) 26 | 27 | ctx := context.Background() 28 | org, _, err := client.Organizations.GetActionsPermissions(ctx, "o") 29 | if err != nil { 30 | t.Errorf("Organizations.GetActionsPermissions returned error: %v", err) 31 | } 32 | want := &ActionsPermissions{EnabledRepositories: Ptr("all"), AllowedActions: Ptr("all")} 33 | if !cmp.Equal(org, want) { 34 | t.Errorf("Organizations.GetActionsPermissions returned %+v, want %+v", org, want) 35 | } 36 | 37 | const methodName = "GetActionsPermissions" 38 | testBadOptions(t, methodName, func() (err error) { 39 | _, _, err = client.Organizations.GetActionsPermissions(ctx, "\n") 40 | return err 41 | }) 42 | 43 | testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 44 | got, resp, err := client.Organizations.GetActionsPermissions(ctx, "o") 45 | if got != nil { 46 | t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 47 | } 48 | return resp, err 49 | }) 50 | } 51 | 52 | func TestOrganizationsService_EditActionsPermissions(t *testing.T) { 53 | t.Parallel() 54 | client, mux, _ := setup(t) 55 | 56 | input := &ActionsPermissions{EnabledRepositories: Ptr("all"), AllowedActions: Ptr("selected")} 57 | 58 | mux.HandleFunc("/orgs/o/actions/permissions", func(w http.ResponseWriter, r *http.Request) { 59 | v := new(ActionsPermissions) 60 | assertNilError(t, json.NewDecoder(r.Body).Decode(v)) 61 | 62 | testMethod(t, r, "PUT") 63 | if !cmp.Equal(v, input) { 64 | t.Errorf("Request body = %+v, want %+v", v, input) 65 | } 66 | 67 | fmt.Fprint(w, `{"enabled_repositories": "all", "allowed_actions": "selected"}`) 68 | }) 69 | 70 | ctx := context.Background() 71 | org, _, err := client.Organizations.EditActionsPermissions(ctx, "o", *input) 72 | if err != nil { 73 | t.Errorf("Organizations.EditActionsPermissions returned error: %v", err) 74 | } 75 | 76 | want := &ActionsPermissions{EnabledRepositories: Ptr("all"), AllowedActions: Ptr("selected")} 77 | if !cmp.Equal(org, want) { 78 | t.Errorf("Organizations.EditActionsPermissions returned %+v, want %+v", org, want) 79 | } 80 | 81 | const methodName = "EditActionsPermissions" 82 | testBadOptions(t, methodName, func() (err error) { 83 | _, _, err = client.Organizations.EditActionsPermissions(ctx, "\n", *input) 84 | return err 85 | }) 86 | 87 | testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 88 | got, resp, err := client.Organizations.EditActionsPermissions(ctx, "o", *input) 89 | if got != nil { 90 | t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 91 | } 92 | return resp, err 93 | }) 94 | } 95 | -------------------------------------------------------------------------------- /github/orgs_attestations.go: -------------------------------------------------------------------------------- 1 | // Copyright 2024 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | "fmt" 11 | ) 12 | 13 | // ListAttestations returns a collection of artifact attestations 14 | // with a given subject digest that are associated with repositories 15 | // owned by an organization. 16 | // 17 | // GitHub API docs: https://docs.github.com/rest/orgs/orgs#list-attestations 18 | // 19 | //meta:operation GET /orgs/{org}/attestations/{subject_digest} 20 | func (s *OrganizationsService) ListAttestations(ctx context.Context, org, subjectDigest string, opts *ListOptions) (*AttestationsResponse, *Response, error) { 21 | var u = fmt.Sprintf("orgs/%v/attestations/%v", org, subjectDigest) 22 | 23 | u, err := addOptions(u, opts) 24 | if err != nil { 25 | return nil, nil, err 26 | } 27 | 28 | req, err := s.client.NewRequest("GET", u, nil) 29 | if err != nil { 30 | return nil, nil, err 31 | } 32 | 33 | var attestations *AttestationsResponse 34 | resp, err := s.client.Do(ctx, req, &attestations) 35 | if err != nil { 36 | return nil, resp, err 37 | } 38 | 39 | return attestations, resp, nil 40 | } 41 | -------------------------------------------------------------------------------- /github/orgs_attestations_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2024 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | "fmt" 11 | "net/http" 12 | "testing" 13 | 14 | "github.com/google/go-cmp/cmp" 15 | ) 16 | 17 | func TestOrganizationsService_ListAttestations(t *testing.T) { 18 | t.Parallel() 19 | client, mux, _ := setup(t) 20 | 21 | mux.HandleFunc("/orgs/o/attestations/digest", func(w http.ResponseWriter, r *http.Request) { 22 | testMethod(t, r, "GET") 23 | fmt.Fprint(w, `{ 24 | "attestations": [ 25 | { 26 | "repository_id": 1, 27 | "bundle": {} 28 | }, 29 | { 30 | "repository_id": 2, 31 | "bundle": {} 32 | } 33 | ] 34 | }`) 35 | }) 36 | ctx := context.Background() 37 | attestations, _, err := client.Organizations.ListAttestations(ctx, "o", "digest", &ListOptions{}) 38 | if err != nil { 39 | t.Errorf("Organizations.ListAttestations returned error: %v", err) 40 | } 41 | 42 | want := &AttestationsResponse{ 43 | Attestations: []*Attestation{ 44 | { 45 | RepositoryID: 1, 46 | Bundle: []byte(`{}`), 47 | }, 48 | { 49 | RepositoryID: 2, 50 | Bundle: []byte(`{}`), 51 | }, 52 | }, 53 | } 54 | 55 | if !cmp.Equal(attestations, want) { 56 | t.Errorf("Organizations.ListAttestations = %+v, want %+v", attestations, want) 57 | } 58 | const methodName = "ListAttestations" 59 | 60 | testBadOptions(t, methodName, func() (err error) { 61 | _, _, err = client.Organizations.ListAttestations(ctx, "\n", "\n", &ListOptions{}) 62 | return err 63 | }) 64 | 65 | testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 66 | got, resp, err := client.Organizations.ListAttestations(ctx, "o", "digest", nil) 67 | if got != nil { 68 | t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 69 | } 70 | return resp, err 71 | }) 72 | } 73 | -------------------------------------------------------------------------------- /github/orgs_credential_authorizations_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | "fmt" 11 | "net/http" 12 | "testing" 13 | "time" 14 | 15 | "github.com/google/go-cmp/cmp" 16 | ) 17 | 18 | func TestOrganizationsService_ListCredentialAuthorizations(t *testing.T) { 19 | t.Parallel() 20 | client, mux, _ := setup(t) 21 | 22 | mux.HandleFunc("/orgs/o/credential-authorizations", func(w http.ResponseWriter, r *http.Request) { 23 | testMethod(t, r, http.MethodGet) 24 | testFormValues(t, r, values{"per_page": "2", "page": "2", "login": "l"}) 25 | fmt.Fprint(w, `[ 26 | { 27 | "login": "l", 28 | "credential_id": 1, 29 | "credential_type": "t", 30 | "credential_authorized_at": "2017-01-21T00:00:00Z", 31 | "credential_accessed_at": "2017-01-21T00:00:00Z", 32 | "authorized_credential_id": 1 33 | } 34 | ]`) 35 | }) 36 | 37 | opts := &CredentialAuthorizationsListOptions{ 38 | ListOptions: ListOptions{Page: 2, PerPage: 2}, 39 | Login: "l", 40 | } 41 | 42 | ctx := context.Background() 43 | creds, _, err := client.Organizations.ListCredentialAuthorizations(ctx, "o", opts) 44 | if err != nil { 45 | t.Errorf("Organizations.ListCredentialAuthorizations returned error: %v", err) 46 | } 47 | 48 | ts := time.Date(2017, time.January, 21, 0, 0, 0, 0, time.UTC) 49 | want := []*CredentialAuthorization{ 50 | { 51 | Login: Ptr("l"), 52 | CredentialID: Ptr(int64(1)), 53 | CredentialType: Ptr("t"), 54 | CredentialAuthorizedAt: &Timestamp{ts}, 55 | CredentialAccessedAt: &Timestamp{ts}, 56 | AuthorizedCredentialID: Ptr(int64(1)), 57 | }, 58 | } 59 | if !cmp.Equal(creds, want) { 60 | t.Errorf("Organizations.ListCredentialAuthorizations returned %+v, want %+v", creds, want) 61 | } 62 | 63 | const methodName = "ListCredentialAuthorizations" 64 | testBadOptions(t, methodName, func() (err error) { 65 | _, _, err = client.Organizations.ListCredentialAuthorizations(ctx, "\n", opts) 66 | return err 67 | }) 68 | 69 | testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 70 | _, resp, err := client.Organizations.ListCredentialAuthorizations(ctx, "o", opts) 71 | return resp, err 72 | }) 73 | } 74 | 75 | func TestOrganizationsService_RemoveCredentialAuthorization(t *testing.T) { 76 | t.Parallel() 77 | client, mux, _ := setup(t) 78 | 79 | mux.HandleFunc("/orgs/o/credential-authorizations/1", func(w http.ResponseWriter, r *http.Request) { 80 | testMethod(t, r, http.MethodDelete) 81 | w.WriteHeader(http.StatusNoContent) 82 | }) 83 | 84 | ctx := context.Background() 85 | resp, err := client.Organizations.RemoveCredentialAuthorization(ctx, "o", 1) 86 | if err != nil { 87 | t.Errorf("Organizations.RemoveCredentialAuthorization returned error: %v", err) 88 | } 89 | 90 | if resp.StatusCode != http.StatusNoContent { 91 | t.Errorf("Organizations.RemoveCredentialAuthorization returned %v, want %v", resp.StatusCode, http.StatusNoContent) 92 | } 93 | 94 | const methodName = "RemoveCredentialAuthorization" 95 | testBadOptions(t, methodName, func() (err error) { 96 | _, err = client.Organizations.RemoveCredentialAuthorization(ctx, "\n", 0) 97 | return err 98 | }) 99 | 100 | testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 101 | return client.Organizations.RemoveCredentialAuthorization(ctx, "o", 1) 102 | }) 103 | } 104 | -------------------------------------------------------------------------------- /github/orgs_hooks_configuration.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | "fmt" 11 | ) 12 | 13 | // GetHookConfiguration returns the configuration for the specified organization webhook. 14 | // 15 | // GitHub API docs: https://docs.github.com/rest/orgs/webhooks#get-a-webhook-configuration-for-an-organization 16 | // 17 | //meta:operation GET /orgs/{org}/hooks/{hook_id}/config 18 | func (s *OrganizationsService) GetHookConfiguration(ctx context.Context, org string, id int64) (*HookConfig, *Response, error) { 19 | u := fmt.Sprintf("orgs/%v/hooks/%v/config", org, id) 20 | req, err := s.client.NewRequest("GET", u, nil) 21 | if err != nil { 22 | return nil, nil, err 23 | } 24 | 25 | config := new(HookConfig) 26 | resp, err := s.client.Do(ctx, req, config) 27 | if err != nil { 28 | return nil, resp, err 29 | } 30 | 31 | return config, resp, nil 32 | } 33 | 34 | // EditHookConfiguration updates the configuration for the specified organization webhook. 35 | // 36 | // GitHub API docs: https://docs.github.com/rest/orgs/webhooks#update-a-webhook-configuration-for-an-organization 37 | // 38 | //meta:operation PATCH /orgs/{org}/hooks/{hook_id}/config 39 | func (s *OrganizationsService) EditHookConfiguration(ctx context.Context, org string, id int64, config *HookConfig) (*HookConfig, *Response, error) { 40 | u := fmt.Sprintf("orgs/%v/hooks/%v/config", org, id) 41 | req, err := s.client.NewRequest("PATCH", u, config) 42 | if err != nil { 43 | return nil, nil, err 44 | } 45 | 46 | c := new(HookConfig) 47 | resp, err := s.client.Do(ctx, req, c) 48 | if err != nil { 49 | return nil, resp, err 50 | } 51 | 52 | return c, resp, nil 53 | } 54 | -------------------------------------------------------------------------------- /github/orgs_hooks_deliveries.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | "fmt" 11 | ) 12 | 13 | // ListHookDeliveries lists webhook deliveries for a webhook configured in an organization. 14 | // 15 | // GitHub API docs: https://docs.github.com/rest/orgs/webhooks#list-deliveries-for-an-organization-webhook 16 | // 17 | //meta:operation GET /orgs/{org}/hooks/{hook_id}/deliveries 18 | func (s *OrganizationsService) ListHookDeliveries(ctx context.Context, org string, id int64, opts *ListCursorOptions) ([]*HookDelivery, *Response, error) { 19 | u := fmt.Sprintf("orgs/%v/hooks/%v/deliveries", org, id) 20 | u, err := addOptions(u, opts) 21 | if err != nil { 22 | return nil, nil, err 23 | } 24 | 25 | req, err := s.client.NewRequest("GET", u, nil) 26 | if err != nil { 27 | return nil, nil, err 28 | } 29 | 30 | deliveries := []*HookDelivery{} 31 | resp, err := s.client.Do(ctx, req, &deliveries) 32 | if err != nil { 33 | return nil, resp, err 34 | } 35 | 36 | return deliveries, resp, nil 37 | } 38 | 39 | // GetHookDelivery returns a delivery for a webhook configured in an organization. 40 | // 41 | // GitHub API docs: https://docs.github.com/rest/orgs/webhooks#get-a-webhook-delivery-for-an-organization-webhook 42 | // 43 | //meta:operation GET /orgs/{org}/hooks/{hook_id}/deliveries/{delivery_id} 44 | func (s *OrganizationsService) GetHookDelivery(ctx context.Context, owner string, hookID, deliveryID int64) (*HookDelivery, *Response, error) { 45 | u := fmt.Sprintf("orgs/%v/hooks/%v/deliveries/%v", owner, hookID, deliveryID) 46 | req, err := s.client.NewRequest("GET", u, nil) 47 | if err != nil { 48 | return nil, nil, err 49 | } 50 | 51 | h := new(HookDelivery) 52 | resp, err := s.client.Do(ctx, req, h) 53 | if err != nil { 54 | return nil, resp, err 55 | } 56 | 57 | return h, resp, nil 58 | } 59 | 60 | // RedeliverHookDelivery redelivers a delivery for a webhook configured in an organization. 61 | // 62 | // GitHub API docs: https://docs.github.com/rest/orgs/webhooks#redeliver-a-delivery-for-an-organization-webhook 63 | // 64 | //meta:operation POST /orgs/{org}/hooks/{hook_id}/deliveries/{delivery_id}/attempts 65 | func (s *OrganizationsService) RedeliverHookDelivery(ctx context.Context, owner string, hookID, deliveryID int64) (*HookDelivery, *Response, error) { 66 | u := fmt.Sprintf("orgs/%v/hooks/%v/deliveries/%v/attempts", owner, hookID, deliveryID) 67 | req, err := s.client.NewRequest("POST", u, nil) 68 | if err != nil { 69 | return nil, nil, err 70 | } 71 | 72 | h := new(HookDelivery) 73 | resp, err := s.client.Do(ctx, req, h) 74 | if err != nil { 75 | return nil, resp, err 76 | } 77 | 78 | return h, resp, nil 79 | } 80 | -------------------------------------------------------------------------------- /github/orgs_outside_collaborators.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | "fmt" 11 | ) 12 | 13 | // ListOutsideCollaboratorsOptions specifies optional parameters to the 14 | // OrganizationsService.ListOutsideCollaborators method. 15 | type ListOutsideCollaboratorsOptions struct { 16 | // Filter outside collaborators returned in the list. Possible values are: 17 | // 2fa_disabled, all. Default is "all". 18 | Filter string `url:"filter,omitempty"` 19 | 20 | ListOptions 21 | } 22 | 23 | // ListOutsideCollaborators lists outside collaborators of organization's repositories. 24 | // This will only work if the authenticated 25 | // user is an owner of the organization. 26 | // 27 | // Warning: The API may change without advance notice during the preview period. 28 | // Preview features are not supported for production use. 29 | // 30 | // GitHub API docs: https://docs.github.com/rest/orgs/outside-collaborators#list-outside-collaborators-for-an-organization 31 | // 32 | //meta:operation GET /orgs/{org}/outside_collaborators 33 | func (s *OrganizationsService) ListOutsideCollaborators(ctx context.Context, org string, opts *ListOutsideCollaboratorsOptions) ([]*User, *Response, error) { 34 | u := fmt.Sprintf("orgs/%v/outside_collaborators", org) 35 | u, err := addOptions(u, opts) 36 | if err != nil { 37 | return nil, nil, err 38 | } 39 | 40 | req, err := s.client.NewRequest("GET", u, nil) 41 | if err != nil { 42 | return nil, nil, err 43 | } 44 | 45 | var members []*User 46 | resp, err := s.client.Do(ctx, req, &members) 47 | if err != nil { 48 | return nil, resp, err 49 | } 50 | 51 | return members, resp, nil 52 | } 53 | 54 | // RemoveOutsideCollaborator removes a user from the list of outside collaborators; 55 | // consequently, removing them from all the organization's repositories. 56 | // 57 | // GitHub API docs: https://docs.github.com/rest/orgs/outside-collaborators#remove-outside-collaborator-from-an-organization 58 | // 59 | //meta:operation DELETE /orgs/{org}/outside_collaborators/{username} 60 | func (s *OrganizationsService) RemoveOutsideCollaborator(ctx context.Context, org string, user string) (*Response, error) { 61 | u := fmt.Sprintf("orgs/%v/outside_collaborators/%v", org, user) 62 | req, err := s.client.NewRequest("DELETE", u, nil) 63 | if err != nil { 64 | return nil, err 65 | } 66 | 67 | return s.client.Do(ctx, req, nil) 68 | } 69 | 70 | // ConvertMemberToOutsideCollaborator reduces the permission level of a member of the 71 | // organization to that of an outside collaborator. Therefore, they will only 72 | // have access to the repositories that their current team membership allows. 73 | // Responses for converting a non-member or the last owner to an outside collaborator 74 | // are listed in GitHub API docs. 75 | // 76 | // GitHub API docs: https://docs.github.com/rest/orgs/outside-collaborators#convert-an-organization-member-to-outside-collaborator 77 | // 78 | //meta:operation PUT /orgs/{org}/outside_collaborators/{username} 79 | func (s *OrganizationsService) ConvertMemberToOutsideCollaborator(ctx context.Context, org string, user string) (*Response, error) { 80 | u := fmt.Sprintf("orgs/%v/outside_collaborators/%v", org, user) 81 | req, err := s.client.NewRequest("PUT", u, nil) 82 | if err != nil { 83 | return nil, err 84 | } 85 | 86 | return s.client.Do(ctx, req, nil) 87 | } 88 | -------------------------------------------------------------------------------- /github/orgs_security_managers.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | "fmt" 11 | ) 12 | 13 | // ListSecurityManagerTeams lists all security manager teams for an organization. 14 | // 15 | // GitHub API docs: https://docs.github.com/rest/orgs/security-managers#list-security-manager-teams 16 | // 17 | //meta:operation GET /orgs/{org}/security-managers 18 | func (s *OrganizationsService) ListSecurityManagerTeams(ctx context.Context, org string) ([]*Team, *Response, error) { 19 | u := fmt.Sprintf("orgs/%v/security-managers", org) 20 | 21 | req, err := s.client.NewRequest("GET", u, nil) 22 | if err != nil { 23 | return nil, nil, err 24 | } 25 | 26 | var teams []*Team 27 | resp, err := s.client.Do(ctx, req, &teams) 28 | if err != nil { 29 | return nil, resp, err 30 | } 31 | 32 | return teams, resp, nil 33 | } 34 | 35 | // AddSecurityManagerTeam adds a team to the list of security managers for an organization. 36 | // 37 | // GitHub API docs: https://docs.github.com/rest/orgs/security-managers#add-a-security-manager-team 38 | // 39 | //meta:operation PUT /orgs/{org}/security-managers/teams/{team_slug} 40 | func (s *OrganizationsService) AddSecurityManagerTeam(ctx context.Context, org, team string) (*Response, error) { 41 | u := fmt.Sprintf("orgs/%v/security-managers/teams/%v", org, team) 42 | req, err := s.client.NewRequest("PUT", u, nil) 43 | if err != nil { 44 | return nil, err 45 | } 46 | 47 | return s.client.Do(ctx, req, nil) 48 | } 49 | 50 | // RemoveSecurityManagerTeam removes a team from the list of security managers for an organization. 51 | // 52 | // GitHub API docs: https://docs.github.com/rest/orgs/security-managers#remove-a-security-manager-team 53 | // 54 | //meta:operation DELETE /orgs/{org}/security-managers/teams/{team_slug} 55 | func (s *OrganizationsService) RemoveSecurityManagerTeam(ctx context.Context, org, team string) (*Response, error) { 56 | u := fmt.Sprintf("orgs/%v/security-managers/teams/%v", org, team) 57 | req, err := s.client.NewRequest("DELETE", u, nil) 58 | if err != nil { 59 | return nil, err 60 | } 61 | 62 | return s.client.Do(ctx, req, nil) 63 | } 64 | -------------------------------------------------------------------------------- /github/orgs_users_blocking.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | "fmt" 11 | ) 12 | 13 | // ListBlockedUsers lists all the users blocked by an organization. 14 | // 15 | // GitHub API docs: https://docs.github.com/rest/orgs/blocking#list-users-blocked-by-an-organization 16 | // 17 | //meta:operation GET /orgs/{org}/blocks 18 | func (s *OrganizationsService) ListBlockedUsers(ctx context.Context, org string, opts *ListOptions) ([]*User, *Response, error) { 19 | u := fmt.Sprintf("orgs/%v/blocks", org) 20 | u, err := addOptions(u, opts) 21 | if err != nil { 22 | return nil, nil, err 23 | } 24 | 25 | req, err := s.client.NewRequest("GET", u, nil) 26 | if err != nil { 27 | return nil, nil, err 28 | } 29 | 30 | // TODO: remove custom Accept header when this API fully launches. 31 | req.Header.Set("Accept", mediaTypeBlockUsersPreview) 32 | 33 | var blockedUsers []*User 34 | resp, err := s.client.Do(ctx, req, &blockedUsers) 35 | if err != nil { 36 | return nil, resp, err 37 | } 38 | 39 | return blockedUsers, resp, nil 40 | } 41 | 42 | // IsBlocked reports whether specified user is blocked from an organization. 43 | // 44 | // GitHub API docs: https://docs.github.com/rest/orgs/blocking#check-if-a-user-is-blocked-by-an-organization 45 | // 46 | //meta:operation GET /orgs/{org}/blocks/{username} 47 | func (s *OrganizationsService) IsBlocked(ctx context.Context, org string, user string) (bool, *Response, error) { 48 | u := fmt.Sprintf("orgs/%v/blocks/%v", org, user) 49 | 50 | req, err := s.client.NewRequest("GET", u, nil) 51 | if err != nil { 52 | return false, nil, err 53 | } 54 | 55 | // TODO: remove custom Accept header when this API fully launches. 56 | req.Header.Set("Accept", mediaTypeBlockUsersPreview) 57 | 58 | resp, err := s.client.Do(ctx, req, nil) 59 | isBlocked, err := parseBoolResponse(err) 60 | return isBlocked, resp, err 61 | } 62 | 63 | // BlockUser blocks specified user from an organization. 64 | // 65 | // GitHub API docs: https://docs.github.com/rest/orgs/blocking#block-a-user-from-an-organization 66 | // 67 | //meta:operation PUT /orgs/{org}/blocks/{username} 68 | func (s *OrganizationsService) BlockUser(ctx context.Context, org string, user string) (*Response, error) { 69 | u := fmt.Sprintf("orgs/%v/blocks/%v", org, user) 70 | 71 | req, err := s.client.NewRequest("PUT", u, nil) 72 | if err != nil { 73 | return nil, err 74 | } 75 | 76 | // TODO: remove custom Accept header when this API fully launches. 77 | req.Header.Set("Accept", mediaTypeBlockUsersPreview) 78 | 79 | return s.client.Do(ctx, req, nil) 80 | } 81 | 82 | // UnblockUser unblocks specified user from an organization. 83 | // 84 | // GitHub API docs: https://docs.github.com/rest/orgs/blocking#unblock-a-user-from-an-organization 85 | // 86 | //meta:operation DELETE /orgs/{org}/blocks/{username} 87 | func (s *OrganizationsService) UnblockUser(ctx context.Context, org string, user string) (*Response, error) { 88 | u := fmt.Sprintf("orgs/%v/blocks/%v", org, user) 89 | 90 | req, err := s.client.NewRequest("DELETE", u, nil) 91 | if err != nil { 92 | return nil, err 93 | } 94 | 95 | // TODO: remove custom Accept header when this API fully launches. 96 | req.Header.Set("Accept", mediaTypeBlockUsersPreview) 97 | 98 | return s.client.Do(ctx, req, nil) 99 | } 100 | -------------------------------------------------------------------------------- /github/pulls_threads.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | // PullRequestThread represents a thread of comments on a pull request. 9 | type PullRequestThread struct { 10 | ID *int64 `json:"id,omitempty"` 11 | NodeID *string `json:"node_id,omitempty"` 12 | Comments []*PullRequestComment `json:"comments,omitempty"` 13 | } 14 | 15 | func (p PullRequestThread) String() string { 16 | return Stringify(p) 17 | } 18 | -------------------------------------------------------------------------------- /github/repos_actions_access.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | "fmt" 11 | ) 12 | 13 | // RepositoryActionsAccessLevel represents the repository actions access level. 14 | // 15 | // GitHub API docs: https://docs.github.com/rest/actions/permissions#set-the-level-of-access-for-workflows-outside-of-the-repository 16 | type RepositoryActionsAccessLevel struct { 17 | // AccessLevel specifies the level of access that workflows outside of the repository have 18 | // to actions and reusable workflows within the repository. 19 | // Possible values are: "none", "organization" "enterprise". 20 | AccessLevel *string `json:"access_level,omitempty"` 21 | } 22 | 23 | // GetActionsAccessLevel gets the level of access that workflows outside of the repository have 24 | // to actions and reusable workflows in the repository. 25 | // 26 | // GitHub API docs: https://docs.github.com/rest/actions/permissions#get-the-level-of-access-for-workflows-outside-of-the-repository 27 | // 28 | //meta:operation GET /repos/{owner}/{repo}/actions/permissions/access 29 | func (s *RepositoriesService) GetActionsAccessLevel(ctx context.Context, owner, repo string) (*RepositoryActionsAccessLevel, *Response, error) { 30 | u := fmt.Sprintf("repos/%v/%v/actions/permissions/access", owner, repo) 31 | req, err := s.client.NewRequest("GET", u, nil) 32 | if err != nil { 33 | return nil, nil, err 34 | } 35 | 36 | raal := new(RepositoryActionsAccessLevel) 37 | resp, err := s.client.Do(ctx, req, raal) 38 | if err != nil { 39 | return nil, resp, err 40 | } 41 | 42 | return raal, resp, nil 43 | } 44 | 45 | // EditActionsAccessLevel sets the level of access that workflows outside of the repository have 46 | // to actions and reusable workflows in the repository. 47 | // 48 | // GitHub API docs: https://docs.github.com/rest/actions/permissions#set-the-level-of-access-for-workflows-outside-of-the-repository 49 | // 50 | //meta:operation PUT /repos/{owner}/{repo}/actions/permissions/access 51 | func (s *RepositoriesService) EditActionsAccessLevel(ctx context.Context, owner, repo string, repositoryActionsAccessLevel RepositoryActionsAccessLevel) (*Response, error) { 52 | u := fmt.Sprintf("repos/%v/%v/actions/permissions/access", owner, repo) 53 | req, err := s.client.NewRequest("PUT", u, repositoryActionsAccessLevel) 54 | if err != nil { 55 | return nil, err 56 | } 57 | 58 | return s.client.Do(ctx, req, nil) 59 | } 60 | -------------------------------------------------------------------------------- /github/repos_actions_access_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | "encoding/json" 11 | "fmt" 12 | "net/http" 13 | "testing" 14 | 15 | "github.com/google/go-cmp/cmp" 16 | ) 17 | 18 | func TestRepositoriesService_GetActionsAccessLevel(t *testing.T) { 19 | t.Parallel() 20 | client, mux, _ := setup(t) 21 | 22 | mux.HandleFunc("/repos/o/r/actions/permissions/access", func(w http.ResponseWriter, r *http.Request) { 23 | testMethod(t, r, "GET") 24 | fmt.Fprintf(w, `{"access_level": "none"}`) 25 | }) 26 | 27 | ctx := context.Background() 28 | org, _, err := client.Repositories.GetActionsAccessLevel(ctx, "o", "r") 29 | if err != nil { 30 | t.Errorf("Repositories.GetActionsAccessLevel returned error: %v", err) 31 | } 32 | want := &RepositoryActionsAccessLevel{AccessLevel: Ptr("none")} 33 | if !cmp.Equal(org, want) { 34 | t.Errorf("Repositories.GetActionsAccessLevel returned %+v, want %+v", org, want) 35 | } 36 | 37 | const methodName = "GetActionsAccessLevel" 38 | testBadOptions(t, methodName, func() (err error) { 39 | _, _, err = client.Repositories.GetActionsAccessLevel(ctx, "\n", "\n") 40 | return err 41 | }) 42 | 43 | testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 44 | got, resp, err := client.Repositories.GetActionsAccessLevel(ctx, "o", "r") 45 | if got != nil { 46 | t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 47 | } 48 | return resp, err 49 | }) 50 | } 51 | 52 | func TestRepositoriesService_EditActionsAccessLevel(t *testing.T) { 53 | t.Parallel() 54 | client, mux, _ := setup(t) 55 | 56 | input := &RepositoryActionsAccessLevel{AccessLevel: Ptr("organization")} 57 | 58 | mux.HandleFunc("/repos/o/r/actions/permissions/access", func(w http.ResponseWriter, r *http.Request) { 59 | v := new(RepositoryActionsAccessLevel) 60 | assertNilError(t, json.NewDecoder(r.Body).Decode(v)) 61 | 62 | testMethod(t, r, "PUT") 63 | if !cmp.Equal(v, input) { 64 | t.Errorf("Request body = %+v, want %+v", v, input) 65 | } 66 | }) 67 | 68 | ctx := context.Background() 69 | _, err := client.Repositories.EditActionsAccessLevel(ctx, "o", "r", *input) 70 | if err != nil { 71 | t.Errorf("Repositories.EditActionsAccessLevel returned error: %v", err) 72 | } 73 | 74 | const methodName = "EditActionsAccessLevel" 75 | testBadOptions(t, methodName, func() (err error) { 76 | _, err = client.Repositories.EditActionsAccessLevel(ctx, "\n", "\n", *input) 77 | return err 78 | }) 79 | 80 | testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 81 | resp, err := client.Repositories.EditActionsAccessLevel(ctx, "o", "r", *input) 82 | return resp, err 83 | }) 84 | } 85 | 86 | func TestRepositoryActionsAccessLevel_Marshal(t *testing.T) { 87 | t.Parallel() 88 | testJSONMarshal(t, &ActionsPermissions{}, "{}") 89 | 90 | u := &RepositoryActionsAccessLevel{ 91 | AccessLevel: Ptr("enterprise"), 92 | } 93 | 94 | want := `{ 95 | "access_level": "enterprise" 96 | }` 97 | 98 | testJSONMarshal(t, u, want) 99 | } 100 | -------------------------------------------------------------------------------- /github/repos_actions_allowed.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | "fmt" 11 | ) 12 | 13 | // GetActionsAllowed gets the allowed actions and reusable workflows for a repository. 14 | // 15 | // GitHub API docs: https://docs.github.com/rest/actions/permissions#get-allowed-actions-and-reusable-workflows-for-a-repository 16 | // 17 | //meta:operation GET /repos/{owner}/{repo}/actions/permissions/selected-actions 18 | func (s *RepositoriesService) GetActionsAllowed(ctx context.Context, org, repo string) (*ActionsAllowed, *Response, error) { 19 | u := fmt.Sprintf("repos/%v/%v/actions/permissions/selected-actions", org, repo) 20 | req, err := s.client.NewRequest("GET", u, nil) 21 | if err != nil { 22 | return nil, nil, err 23 | } 24 | 25 | actionsAllowed := new(ActionsAllowed) 26 | resp, err := s.client.Do(ctx, req, actionsAllowed) 27 | if err != nil { 28 | return nil, resp, err 29 | } 30 | 31 | return actionsAllowed, resp, nil 32 | } 33 | 34 | // EditActionsAllowed sets the allowed actions and reusable workflows for a repository. 35 | // 36 | // GitHub API docs: https://docs.github.com/rest/actions/permissions#set-allowed-actions-and-reusable-workflows-for-a-repository 37 | // 38 | //meta:operation PUT /repos/{owner}/{repo}/actions/permissions/selected-actions 39 | func (s *RepositoriesService) EditActionsAllowed(ctx context.Context, org, repo string, actionsAllowed ActionsAllowed) (*ActionsAllowed, *Response, error) { 40 | u := fmt.Sprintf("repos/%v/%v/actions/permissions/selected-actions", org, repo) 41 | req, err := s.client.NewRequest("PUT", u, actionsAllowed) 42 | if err != nil { 43 | return nil, nil, err 44 | } 45 | 46 | p := new(ActionsAllowed) 47 | resp, err := s.client.Do(ctx, req, p) 48 | if err != nil { 49 | return nil, resp, err 50 | } 51 | 52 | return p, resp, nil 53 | } 54 | -------------------------------------------------------------------------------- /github/repos_actions_allowed_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | "encoding/json" 11 | "fmt" 12 | "net/http" 13 | "testing" 14 | 15 | "github.com/google/go-cmp/cmp" 16 | ) 17 | 18 | func TestRepositoryService_GetActionsAllowed(t *testing.T) { 19 | t.Parallel() 20 | client, mux, _ := setup(t) 21 | 22 | mux.HandleFunc("/repos/o/r/actions/permissions/selected-actions", func(w http.ResponseWriter, r *http.Request) { 23 | testMethod(t, r, "GET") 24 | fmt.Fprint(w, `{"github_owned_allowed":true, "verified_allowed":false, "patterns_allowed":["a/b"]}`) 25 | }) 26 | 27 | ctx := context.Background() 28 | org, _, err := client.Repositories.GetActionsAllowed(ctx, "o", "r") 29 | if err != nil { 30 | t.Errorf("Repositories.GetActionsAllowed returned error: %v", err) 31 | } 32 | want := &ActionsAllowed{GithubOwnedAllowed: Ptr(true), VerifiedAllowed: Ptr(false), PatternsAllowed: []string{"a/b"}} 33 | if !cmp.Equal(org, want) { 34 | t.Errorf("Repositories.GetActionsAllowed returned %+v, want %+v", org, want) 35 | } 36 | 37 | const methodName = "GetActionsAllowed" 38 | testBadOptions(t, methodName, func() (err error) { 39 | _, _, err = client.Repositories.GetActionsAllowed(ctx, "\n", "\n") 40 | return err 41 | }) 42 | 43 | testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 44 | got, resp, err := client.Repositories.GetActionsAllowed(ctx, "o", "r") 45 | if got != nil { 46 | t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 47 | } 48 | return resp, err 49 | }) 50 | } 51 | 52 | func TestRepositoriesService_EditActionsAllowed(t *testing.T) { 53 | t.Parallel() 54 | client, mux, _ := setup(t) 55 | 56 | input := &ActionsAllowed{GithubOwnedAllowed: Ptr(true), VerifiedAllowed: Ptr(false), PatternsAllowed: []string{"a/b"}} 57 | 58 | mux.HandleFunc("/repos/o/r/actions/permissions/selected-actions", func(w http.ResponseWriter, r *http.Request) { 59 | v := new(ActionsAllowed) 60 | assertNilError(t, json.NewDecoder(r.Body).Decode(v)) 61 | 62 | testMethod(t, r, "PUT") 63 | if !cmp.Equal(v, input) { 64 | t.Errorf("Request body = %+v, want %+v", v, input) 65 | } 66 | 67 | fmt.Fprint(w, `{"github_owned_allowed":true, "verified_allowed":false, "patterns_allowed":["a/b"]}`) 68 | }) 69 | 70 | ctx := context.Background() 71 | org, _, err := client.Repositories.EditActionsAllowed(ctx, "o", "r", *input) 72 | if err != nil { 73 | t.Errorf("Repositories.EditActionsAllowed returned error: %v", err) 74 | } 75 | 76 | want := &ActionsAllowed{GithubOwnedAllowed: Ptr(true), VerifiedAllowed: Ptr(false), PatternsAllowed: []string{"a/b"}} 77 | if !cmp.Equal(org, want) { 78 | t.Errorf("Repositories.EditActionsAllowed returned %+v, want %+v", org, want) 79 | } 80 | 81 | const methodName = "EditActionsAllowed" 82 | testBadOptions(t, methodName, func() (err error) { 83 | _, _, err = client.Repositories.EditActionsAllowed(ctx, "\n", "\n", *input) 84 | return err 85 | }) 86 | 87 | testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 88 | got, resp, err := client.Repositories.EditActionsAllowed(ctx, "o", "r", *input) 89 | if got != nil { 90 | t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 91 | } 92 | return resp, err 93 | }) 94 | } 95 | -------------------------------------------------------------------------------- /github/repos_attestations.go: -------------------------------------------------------------------------------- 1 | // Copyright 2024 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | "fmt" 11 | ) 12 | 13 | // ListAttestations returns a collection of artifact attestations 14 | // with a given subject digest that are associated with a repository. 15 | // 16 | // GitHub API docs: https://docs.github.com/rest/repos/repos#list-attestations 17 | // 18 | //meta:operation GET /repos/{owner}/{repo}/attestations/{subject_digest} 19 | func (s *RepositoriesService) ListAttestations(ctx context.Context, owner, repo, subjectDigest string, opts *ListOptions) (*AttestationsResponse, *Response, error) { 20 | var u = fmt.Sprintf("repos/%v/%v/attestations/%v", owner, repo, subjectDigest) 21 | 22 | u, err := addOptions(u, opts) 23 | if err != nil { 24 | return nil, nil, err 25 | } 26 | 27 | req, err := s.client.NewRequest("GET", u, nil) 28 | if err != nil { 29 | return nil, nil, err 30 | } 31 | 32 | var attestations *AttestationsResponse 33 | resp, err := s.client.Do(ctx, req, &attestations) 34 | if err != nil { 35 | return nil, resp, err 36 | } 37 | 38 | return attestations, resp, nil 39 | } 40 | -------------------------------------------------------------------------------- /github/repos_attestations_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2024 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | "fmt" 11 | "net/http" 12 | "testing" 13 | 14 | "github.com/google/go-cmp/cmp" 15 | ) 16 | 17 | func TestRepositoriesService_ListAttestations(t *testing.T) { 18 | t.Parallel() 19 | client, mux, _ := setup(t) 20 | 21 | mux.HandleFunc("/repos/o/r/attestations/digest", func(w http.ResponseWriter, r *http.Request) { 22 | testMethod(t, r, "GET") 23 | fmt.Fprint(w, `{ 24 | "attestations": [ 25 | { 26 | "repository_id": 1, 27 | "bundle": {} 28 | }, 29 | { 30 | "repository_id": 2, 31 | "bundle": {} 32 | } 33 | ] 34 | }`) 35 | }) 36 | ctx := context.Background() 37 | attestations, _, err := client.Repositories.ListAttestations(ctx, "o", "r", "digest", &ListOptions{}) 38 | if err != nil { 39 | t.Errorf("Repositories.ListAttestations returned error: %v", err) 40 | } 41 | 42 | want := &AttestationsResponse{ 43 | Attestations: []*Attestation{ 44 | { 45 | RepositoryID: 1, 46 | Bundle: []byte(`{}`), 47 | }, 48 | { 49 | RepositoryID: 2, 50 | Bundle: []byte(`{}`), 51 | }, 52 | }, 53 | } 54 | 55 | if !cmp.Equal(attestations, want) { 56 | t.Errorf("Repositories.ListAttestations = %+v, want %+v", attestations, want) 57 | } 58 | const methodName = "ListAttestations" 59 | 60 | testBadOptions(t, methodName, func() (err error) { 61 | _, _, err = client.Repositories.ListAttestations(ctx, "\n", "\n", "\n", &ListOptions{}) 62 | return err 63 | }) 64 | 65 | testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 66 | got, resp, err := client.Repositories.ListAttestations(ctx, "o", "r", "digest", nil) 67 | if got != nil { 68 | t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 69 | } 70 | return resp, err 71 | }) 72 | } 73 | -------------------------------------------------------------------------------- /github/repos_codeowners.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | "fmt" 11 | ) 12 | 13 | // GetCodeownersErrorsOptions specifies the optional parameters to the 14 | // RepositoriesService.GetCodeownersErrors method. 15 | type GetCodeownersErrorsOptions struct { 16 | // A branch, tag or commit name used to determine which version of the CODEOWNERS file to use. 17 | // Default: the repository's default branch (e.g. main). 18 | Ref string `url:"ref,omitempty"` 19 | } 20 | 21 | // CodeownersErrors represents a list of syntax errors detected in the CODEOWNERS file. 22 | type CodeownersErrors struct { 23 | Errors []*CodeownersError `json:"errors"` 24 | } 25 | 26 | // CodeownersError represents a syntax error detected in the CODEOWNERS file. 27 | type CodeownersError struct { 28 | Line int `json:"line"` 29 | Column int `json:"column"` 30 | Kind string `json:"kind"` 31 | Source string `json:"source"` 32 | Suggestion *string `json:"suggestion,omitempty"` 33 | Message string `json:"message"` 34 | Path string `json:"path"` 35 | } 36 | 37 | // GetCodeownersErrors lists any syntax errors that are detected in the CODEOWNERS file. 38 | // 39 | // GitHub API docs: https://docs.github.com/rest/repos/repos#list-codeowners-errors 40 | // 41 | //meta:operation GET /repos/{owner}/{repo}/codeowners/errors 42 | func (s *RepositoriesService) GetCodeownersErrors(ctx context.Context, owner, repo string, opts *GetCodeownersErrorsOptions) (*CodeownersErrors, *Response, error) { 43 | u := fmt.Sprintf("repos/%v/%v/codeowners/errors", owner, repo) 44 | u, err := addOptions(u, opts) 45 | if err != nil { 46 | return nil, nil, err 47 | } 48 | 49 | req, err := s.client.NewRequest("GET", u, nil) 50 | if err != nil { 51 | return nil, nil, err 52 | } 53 | 54 | codeownersErrors := &CodeownersErrors{} 55 | resp, err := s.client.Do(ctx, req, codeownersErrors) 56 | if err != nil { 57 | return nil, resp, err 58 | } 59 | 60 | return codeownersErrors, resp, nil 61 | } 62 | -------------------------------------------------------------------------------- /github/repos_community_health.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | "fmt" 11 | ) 12 | 13 | // Metric represents the different fields for one file in community health files. 14 | type Metric struct { 15 | Name *string `json:"name"` 16 | Key *string `json:"key"` 17 | SPDXID *string `json:"spdx_id"` 18 | URL *string `json:"url"` 19 | HTMLURL *string `json:"html_url"` 20 | NodeID *string `json:"node_id"` 21 | } 22 | 23 | // CommunityHealthFiles represents the different files in the community health metrics response. 24 | type CommunityHealthFiles struct { 25 | CodeOfConduct *Metric `json:"code_of_conduct"` 26 | CodeOfConductFile *Metric `json:"code_of_conduct_file"` 27 | Contributing *Metric `json:"contributing"` 28 | IssueTemplate *Metric `json:"issue_template"` 29 | PullRequestTemplate *Metric `json:"pull_request_template"` 30 | License *Metric `json:"license"` 31 | Readme *Metric `json:"readme"` 32 | } 33 | 34 | // CommunityHealthMetrics represents a response containing the community metrics of a repository. 35 | type CommunityHealthMetrics struct { 36 | HealthPercentage *int `json:"health_percentage"` 37 | Description *string `json:"description"` 38 | Documentation *string `json:"documentation"` 39 | Files *CommunityHealthFiles `json:"files"` 40 | UpdatedAt *Timestamp `json:"updated_at"` 41 | ContentReportsEnabled *bool `json:"content_reports_enabled"` 42 | } 43 | 44 | // GetCommunityHealthMetrics retrieves all the community health metrics for a repository. 45 | // 46 | // GitHub API docs: https://docs.github.com/rest/metrics/community#get-community-profile-metrics 47 | // 48 | //meta:operation GET /repos/{owner}/{repo}/community/profile 49 | func (s *RepositoriesService) GetCommunityHealthMetrics(ctx context.Context, owner, repo string) (*CommunityHealthMetrics, *Response, error) { 50 | u := fmt.Sprintf("repos/%v/%v/community/profile", owner, repo) 51 | req, err := s.client.NewRequest("GET", u, nil) 52 | if err != nil { 53 | return nil, nil, err 54 | } 55 | 56 | metrics := &CommunityHealthMetrics{} 57 | resp, err := s.client.Do(ctx, req, metrics) 58 | if err != nil { 59 | return nil, resp, err 60 | } 61 | 62 | return metrics, resp, nil 63 | } 64 | -------------------------------------------------------------------------------- /github/repos_forks.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | "encoding/json" 11 | "fmt" 12 | ) 13 | 14 | // RepositoryListForksOptions specifies the optional parameters to the 15 | // RepositoriesService.ListForks method. 16 | type RepositoryListForksOptions struct { 17 | // How to sort the forks list. Possible values are: newest, oldest, 18 | // watchers. Default is "newest". 19 | Sort string `url:"sort,omitempty"` 20 | 21 | ListOptions 22 | } 23 | 24 | // ListForks lists the forks of the specified repository. 25 | // 26 | // GitHub API docs: https://docs.github.com/rest/repos/forks#list-forks 27 | // 28 | //meta:operation GET /repos/{owner}/{repo}/forks 29 | func (s *RepositoriesService) ListForks(ctx context.Context, owner, repo string, opts *RepositoryListForksOptions) ([]*Repository, *Response, error) { 30 | u := fmt.Sprintf("repos/%v/%v/forks", owner, repo) 31 | u, err := addOptions(u, opts) 32 | if err != nil { 33 | return nil, nil, err 34 | } 35 | 36 | req, err := s.client.NewRequest("GET", u, nil) 37 | if err != nil { 38 | return nil, nil, err 39 | } 40 | 41 | // TODO: remove custom Accept header when topics API fully launches. 42 | req.Header.Set("Accept", mediaTypeTopicsPreview) 43 | 44 | var repos []*Repository 45 | resp, err := s.client.Do(ctx, req, &repos) 46 | if err != nil { 47 | return nil, resp, err 48 | } 49 | 50 | return repos, resp, nil 51 | } 52 | 53 | // RepositoryCreateForkOptions specifies the optional parameters to the 54 | // RepositoriesService.CreateFork method. 55 | type RepositoryCreateForkOptions struct { 56 | // The organization to fork the repository into. 57 | Organization string `json:"organization,omitempty"` 58 | Name string `json:"name,omitempty"` 59 | DefaultBranchOnly bool `json:"default_branch_only,omitempty"` 60 | } 61 | 62 | // CreateFork creates a fork of the specified repository. 63 | // 64 | // This method might return an *AcceptedError and a status code of 65 | // 202. This is because this is the status that GitHub returns to signify that 66 | // it is now computing creating the fork in a background task. In this event, 67 | // the Repository value will be returned, which includes the details about the pending fork. 68 | // A follow up request, after a delay of a second or so, should result 69 | // in a successful request. 70 | // 71 | // GitHub API docs: https://docs.github.com/rest/repos/forks#create-a-fork 72 | // 73 | //meta:operation POST /repos/{owner}/{repo}/forks 74 | func (s *RepositoriesService) CreateFork(ctx context.Context, owner, repo string, opts *RepositoryCreateForkOptions) (*Repository, *Response, error) { 75 | u := fmt.Sprintf("repos/%v/%v/forks", owner, repo) 76 | 77 | req, err := s.client.NewRequest("POST", u, opts) 78 | if err != nil { 79 | return nil, nil, err 80 | } 81 | 82 | fork := new(Repository) 83 | resp, err := s.client.Do(ctx, req, fork) 84 | if err != nil { 85 | // Persist AcceptedError's metadata to the Repository object. 86 | if aerr, ok := err.(*AcceptedError); ok { 87 | if err := json.Unmarshal(aerr.Raw, fork); err != nil { 88 | return fork, resp, err 89 | } 90 | 91 | return fork, resp, err 92 | } 93 | return nil, resp, err 94 | } 95 | 96 | return fork, resp, nil 97 | } 98 | -------------------------------------------------------------------------------- /github/repos_hooks_configuration.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | "fmt" 11 | ) 12 | 13 | // HookConfig describes metadata about a webhook configuration. 14 | type HookConfig struct { 15 | // The media type used to serialize the payloads 16 | // Possible values are `json` and `form`, the field is not specified the default is `form` 17 | ContentType *string `json:"content_type,omitempty"` 18 | // The possible values are 0 and 1. 19 | // Setting it to 1 will allow skip certificate verification for the host, 20 | // potentially exposing to MitM attacks: https://en.wikipedia.org/wiki/Man-in-the-middle_attack 21 | InsecureSSL *string `json:"insecure_ssl,omitempty"` 22 | URL *string `json:"url,omitempty"` 23 | 24 | // Secret is returned obfuscated by GitHub, but it can be set for outgoing requests. 25 | Secret *string `json:"secret,omitempty"` 26 | } 27 | 28 | // GetHookConfiguration returns the configuration for the specified repository webhook. 29 | // 30 | // GitHub API docs: https://docs.github.com/rest/repos/webhooks#get-a-webhook-configuration-for-a-repository 31 | // 32 | //meta:operation GET /repos/{owner}/{repo}/hooks/{hook_id}/config 33 | func (s *RepositoriesService) GetHookConfiguration(ctx context.Context, owner, repo string, id int64) (*HookConfig, *Response, error) { 34 | u := fmt.Sprintf("repos/%v/%v/hooks/%v/config", owner, repo, id) 35 | req, err := s.client.NewRequest("GET", u, nil) 36 | if err != nil { 37 | return nil, nil, err 38 | } 39 | 40 | config := new(HookConfig) 41 | resp, err := s.client.Do(ctx, req, config) 42 | if err != nil { 43 | return nil, resp, err 44 | } 45 | 46 | return config, resp, nil 47 | } 48 | 49 | // EditHookConfiguration updates the configuration for the specified repository webhook. 50 | // 51 | // GitHub API docs: https://docs.github.com/rest/repos/webhooks#update-a-webhook-configuration-for-a-repository 52 | // 53 | //meta:operation PATCH /repos/{owner}/{repo}/hooks/{hook_id}/config 54 | func (s *RepositoriesService) EditHookConfiguration(ctx context.Context, owner, repo string, id int64, config *HookConfig) (*HookConfig, *Response, error) { 55 | u := fmt.Sprintf("repos/%v/%v/hooks/%v/config", owner, repo, id) 56 | req, err := s.client.NewRequest("PATCH", u, config) 57 | if err != nil { 58 | return nil, nil, err 59 | } 60 | 61 | c := new(HookConfig) 62 | resp, err := s.client.Do(ctx, req, c) 63 | if err != nil { 64 | return nil, resp, err 65 | } 66 | 67 | return c, resp, nil 68 | } 69 | -------------------------------------------------------------------------------- /github/repos_keys.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | "fmt" 11 | ) 12 | 13 | // The Key type is defined in users_keys.go 14 | 15 | // ListKeys lists the deploy keys for a repository. 16 | // 17 | // GitHub API docs: https://docs.github.com/rest/deploy-keys/deploy-keys#list-deploy-keys 18 | // 19 | //meta:operation GET /repos/{owner}/{repo}/keys 20 | func (s *RepositoriesService) ListKeys(ctx context.Context, owner string, repo string, opts *ListOptions) ([]*Key, *Response, error) { 21 | u := fmt.Sprintf("repos/%v/%v/keys", owner, repo) 22 | u, err := addOptions(u, opts) 23 | if err != nil { 24 | return nil, nil, err 25 | } 26 | 27 | req, err := s.client.NewRequest("GET", u, nil) 28 | if err != nil { 29 | return nil, nil, err 30 | } 31 | 32 | var keys []*Key 33 | resp, err := s.client.Do(ctx, req, &keys) 34 | if err != nil { 35 | return nil, resp, err 36 | } 37 | 38 | return keys, resp, nil 39 | } 40 | 41 | // GetKey fetches a single deploy key. 42 | // 43 | // GitHub API docs: https://docs.github.com/rest/deploy-keys/deploy-keys#get-a-deploy-key 44 | // 45 | //meta:operation GET /repos/{owner}/{repo}/keys/{key_id} 46 | func (s *RepositoriesService) GetKey(ctx context.Context, owner string, repo string, id int64) (*Key, *Response, error) { 47 | u := fmt.Sprintf("repos/%v/%v/keys/%v", owner, repo, id) 48 | 49 | req, err := s.client.NewRequest("GET", u, nil) 50 | if err != nil { 51 | return nil, nil, err 52 | } 53 | 54 | key := new(Key) 55 | resp, err := s.client.Do(ctx, req, key) 56 | if err != nil { 57 | return nil, resp, err 58 | } 59 | 60 | return key, resp, nil 61 | } 62 | 63 | // CreateKey adds a deploy key for a repository. 64 | // 65 | // GitHub API docs: https://docs.github.com/rest/deploy-keys/deploy-keys#create-a-deploy-key 66 | // 67 | //meta:operation POST /repos/{owner}/{repo}/keys 68 | func (s *RepositoriesService) CreateKey(ctx context.Context, owner string, repo string, key *Key) (*Key, *Response, error) { 69 | u := fmt.Sprintf("repos/%v/%v/keys", owner, repo) 70 | 71 | req, err := s.client.NewRequest("POST", u, key) 72 | if err != nil { 73 | return nil, nil, err 74 | } 75 | 76 | k := new(Key) 77 | resp, err := s.client.Do(ctx, req, k) 78 | if err != nil { 79 | return nil, resp, err 80 | } 81 | 82 | return k, resp, nil 83 | } 84 | 85 | // DeleteKey deletes a deploy key. 86 | // 87 | // GitHub API docs: https://docs.github.com/rest/deploy-keys/deploy-keys#delete-a-deploy-key 88 | // 89 | //meta:operation DELETE /repos/{owner}/{repo}/keys/{key_id} 90 | func (s *RepositoriesService) DeleteKey(ctx context.Context, owner string, repo string, id int64) (*Response, error) { 91 | u := fmt.Sprintf("repos/%v/%v/keys/%v", owner, repo, id) 92 | 93 | req, err := s.client.NewRequest("DELETE", u, nil) 94 | if err != nil { 95 | return nil, err 96 | } 97 | 98 | return s.client.Do(ctx, req, nil) 99 | } 100 | -------------------------------------------------------------------------------- /github/repos_lfs.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | "fmt" 11 | ) 12 | 13 | // EnableLFS turns the LFS (Large File Storage) feature ON for the selected repo. 14 | // 15 | // GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/repos/lfs#enable-git-lfs-for-a-repository 16 | // 17 | //meta:operation PUT /repos/{owner}/{repo}/lfs 18 | func (s *RepositoriesService) EnableLFS(ctx context.Context, owner, repo string) (*Response, error) { 19 | u := fmt.Sprintf("repos/%v/%v/lfs", owner, repo) 20 | 21 | req, err := s.client.NewRequest("PUT", u, nil) 22 | if err != nil { 23 | return nil, err 24 | } 25 | 26 | resp, err := s.client.Do(ctx, req, nil) 27 | if err != nil { 28 | return resp, err 29 | } 30 | 31 | return resp, nil 32 | } 33 | 34 | // DisableLFS turns the LFS (Large File Storage) feature OFF for the selected repo. 35 | // 36 | // GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/repos/lfs#disable-git-lfs-for-a-repository 37 | // 38 | //meta:operation DELETE /repos/{owner}/{repo}/lfs 39 | func (s *RepositoriesService) DisableLFS(ctx context.Context, owner, repo string) (*Response, error) { 40 | u := fmt.Sprintf("repos/%v/%v/lfs", owner, repo) 41 | 42 | req, err := s.client.NewRequest("DELETE", u, nil) 43 | if err != nil { 44 | return nil, err 45 | } 46 | 47 | resp, err := s.client.Do(ctx, req, nil) 48 | if err != nil { 49 | return resp, err 50 | } 51 | 52 | return resp, nil 53 | } 54 | -------------------------------------------------------------------------------- /github/repos_lfs_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | "net/http" 11 | "testing" 12 | ) 13 | 14 | func TestRepositoriesService_EnableLFS(t *testing.T) { 15 | t.Parallel() 16 | client, mux, _ := setup(t) 17 | 18 | mux.HandleFunc("/repos/o/r/lfs", func(w http.ResponseWriter, r *http.Request) { 19 | testMethod(t, r, "PUT") 20 | 21 | w.WriteHeader(http.StatusNoContent) 22 | }) 23 | 24 | ctx := context.Background() 25 | if _, err := client.Repositories.EnableLFS(ctx, "o", "r"); err != nil { 26 | t.Errorf("Repositories.EnableLFS returned error: %v", err) 27 | } 28 | 29 | const methodName = "EnableLFS" 30 | testBadOptions(t, methodName, func() (err error) { 31 | _, err = client.Repositories.EnableLFS(ctx, "\n", "\n") 32 | return err 33 | }) 34 | 35 | testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 36 | return client.Repositories.EnableLFS(ctx, "o", "r") 37 | }) 38 | } 39 | 40 | func TestRepositoriesService_DisableLFS(t *testing.T) { 41 | t.Parallel() 42 | client, mux, _ := setup(t) 43 | 44 | mux.HandleFunc("/repos/o/r/lfs", func(w http.ResponseWriter, r *http.Request) { 45 | testMethod(t, r, "DELETE") 46 | 47 | w.WriteHeader(http.StatusNoContent) 48 | }) 49 | 50 | ctx := context.Background() 51 | if _, err := client.Repositories.DisableLFS(ctx, "o", "r"); err != nil { 52 | t.Errorf("Repositories.DisableLFS returned error: %v", err) 53 | } 54 | 55 | const methodName = "DisableLFS" 56 | testBadOptions(t, methodName, func() (err error) { 57 | _, err = client.Repositories.DisableLFS(ctx, "\n", "\n") 58 | return err 59 | }) 60 | 61 | testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 62 | return client.Repositories.DisableLFS(ctx, "o", "r") 63 | }) 64 | } 65 | -------------------------------------------------------------------------------- /github/repos_merging.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | "fmt" 11 | ) 12 | 13 | // RepositoryMergeRequest represents a request to merge a branch in a 14 | // repository. 15 | type RepositoryMergeRequest struct { 16 | Base *string `json:"base,omitempty"` 17 | Head *string `json:"head,omitempty"` 18 | CommitMessage *string `json:"commit_message,omitempty"` 19 | } 20 | 21 | // RepoMergeUpstreamRequest represents a request to sync a branch of 22 | // a forked repository to keep it up-to-date with the upstream repository. 23 | type RepoMergeUpstreamRequest struct { 24 | Branch *string `json:"branch,omitempty"` 25 | } 26 | 27 | // RepoMergeUpstreamResult represents the result of syncing a branch of 28 | // a forked repository with the upstream repository. 29 | type RepoMergeUpstreamResult struct { 30 | Message *string `json:"message,omitempty"` 31 | MergeType *string `json:"merge_type,omitempty"` 32 | BaseBranch *string `json:"base_branch,omitempty"` 33 | } 34 | 35 | // Merge a branch in the specified repository. 36 | // 37 | // GitHub API docs: https://docs.github.com/rest/branches/branches#merge-a-branch 38 | // 39 | //meta:operation POST /repos/{owner}/{repo}/merges 40 | func (s *RepositoriesService) Merge(ctx context.Context, owner, repo string, request *RepositoryMergeRequest) (*RepositoryCommit, *Response, error) { 41 | u := fmt.Sprintf("repos/%v/%v/merges", owner, repo) 42 | req, err := s.client.NewRequest("POST", u, request) 43 | if err != nil { 44 | return nil, nil, err 45 | } 46 | 47 | commit := new(RepositoryCommit) 48 | resp, err := s.client.Do(ctx, req, commit) 49 | if err != nil { 50 | return nil, resp, err 51 | } 52 | 53 | return commit, resp, nil 54 | } 55 | 56 | // MergeUpstream syncs a branch of a forked repository to keep it up-to-date 57 | // with the upstream repository. 58 | // 59 | // GitHub API docs: https://docs.github.com/rest/branches/branches#sync-a-fork-branch-with-the-upstream-repository 60 | // 61 | //meta:operation POST /repos/{owner}/{repo}/merge-upstream 62 | func (s *RepositoriesService) MergeUpstream(ctx context.Context, owner, repo string, request *RepoMergeUpstreamRequest) (*RepoMergeUpstreamResult, *Response, error) { 63 | u := fmt.Sprintf("repos/%v/%v/merge-upstream", owner, repo) 64 | req, err := s.client.NewRequest("POST", u, request) 65 | if err != nil { 66 | return nil, nil, err 67 | } 68 | 69 | result := new(RepoMergeUpstreamResult) 70 | resp, err := s.client.Do(ctx, req, result) 71 | if err != nil { 72 | return nil, resp, err 73 | } 74 | 75 | return result, resp, nil 76 | } 77 | -------------------------------------------------------------------------------- /github/repos_properties.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | "fmt" 11 | ) 12 | 13 | // GetAllCustomPropertyValues gets all custom property values that are set for a repository. 14 | // 15 | // GitHub API docs: https://docs.github.com/rest/repos/custom-properties#get-all-custom-property-values-for-a-repository 16 | // 17 | //meta:operation GET /repos/{owner}/{repo}/properties/values 18 | func (s *RepositoriesService) GetAllCustomPropertyValues(ctx context.Context, org, repo string) ([]*CustomPropertyValue, *Response, error) { 19 | u := fmt.Sprintf("repos/%v/%v/properties/values", org, repo) 20 | 21 | req, err := s.client.NewRequest("GET", u, nil) 22 | if err != nil { 23 | return nil, nil, err 24 | } 25 | 26 | var customPropertyValues []*CustomPropertyValue 27 | resp, err := s.client.Do(ctx, req, &customPropertyValues) 28 | if err != nil { 29 | return nil, resp, err 30 | } 31 | 32 | return customPropertyValues, resp, nil 33 | } 34 | 35 | // CreateOrUpdateCustomProperties creates new or updates existing custom property values for a repository. 36 | // 37 | // GitHub API docs: https://docs.github.com/rest/repos/custom-properties#create-or-update-custom-property-values-for-a-repository 38 | // 39 | //meta:operation PATCH /repos/{owner}/{repo}/properties/values 40 | func (s *RepositoriesService) CreateOrUpdateCustomProperties(ctx context.Context, org, repo string, customPropertyValues []*CustomPropertyValue) (*Response, error) { 41 | u := fmt.Sprintf("repos/%v/%v/properties/values", org, repo) 42 | 43 | params := struct { 44 | Properties []*CustomPropertyValue `json:"properties"` 45 | }{ 46 | Properties: customPropertyValues, 47 | } 48 | 49 | req, err := s.client.NewRequest("PATCH", u, params) 50 | if err != nil { 51 | return nil, err 52 | } 53 | 54 | resp, err := s.client.Do(ctx, req, nil) 55 | if err != nil { 56 | return resp, err 57 | } 58 | 59 | return resp, nil 60 | } 61 | -------------------------------------------------------------------------------- /github/repos_properties_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | "fmt" 11 | "net/http" 12 | "testing" 13 | 14 | "github.com/google/go-cmp/cmp" 15 | ) 16 | 17 | func TestRepositoriesService_GetAllCustomPropertyValues(t *testing.T) { 18 | t.Parallel() 19 | client, mux, _ := setup(t) 20 | 21 | mux.HandleFunc("/repos/o/r/properties/values", func(w http.ResponseWriter, r *http.Request) { 22 | testMethod(t, r, "GET") 23 | fmt.Fprint(w, `[ 24 | { 25 | "property_name": "environment", 26 | "value": "production" 27 | }, 28 | { 29 | "property_name": "service", 30 | "value": "web" 31 | }, 32 | { 33 | "property_name": "languages", 34 | "value": ["Go", "JavaScript"] 35 | }, 36 | { 37 | "property_name": "null_property", 38 | "value": null 39 | } 40 | ]`) 41 | }) 42 | 43 | ctx := context.Background() 44 | customPropertyValues, _, err := client.Repositories.GetAllCustomPropertyValues(ctx, "o", "r") 45 | if err != nil { 46 | t.Errorf("Repositories.GetAllCustomPropertyValues returned error: %v", err) 47 | } 48 | 49 | want := []*CustomPropertyValue{ 50 | { 51 | PropertyName: "environment", 52 | Value: "production", 53 | }, 54 | { 55 | PropertyName: "service", 56 | Value: "web", 57 | }, 58 | { 59 | PropertyName: "languages", 60 | Value: []string{"Go", "JavaScript"}, 61 | }, 62 | { 63 | PropertyName: "null_property", 64 | Value: nil, 65 | }, 66 | } 67 | 68 | if !cmp.Equal(customPropertyValues, want) { 69 | t.Errorf("Repositories.GetAllCustomPropertyValues returned %+v, want %+v", customPropertyValues, want) 70 | } 71 | 72 | const methodName = "GetAllCustomPropertyValues" 73 | 74 | testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 75 | got, resp, err := client.Repositories.GetAllCustomPropertyValues(ctx, "o", "r") 76 | if got != nil { 77 | t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 78 | } 79 | return resp, err 80 | }) 81 | } 82 | 83 | func TestRepositoriesService_CreateOrUpdateCustomProperties(t *testing.T) { 84 | t.Parallel() 85 | client, mux, _ := setup(t) 86 | 87 | mux.HandleFunc("/repos/usr/r/properties/values", func(w http.ResponseWriter, r *http.Request) { 88 | testMethod(t, r, "PATCH") 89 | w.WriteHeader(http.StatusNoContent) 90 | }) 91 | 92 | ctx := context.Background() 93 | repoCustomProperty := []*CustomPropertyValue{ 94 | { 95 | PropertyName: "environment", 96 | Value: "production", 97 | }, 98 | } 99 | _, err := client.Repositories.CreateOrUpdateCustomProperties(ctx, "usr", "r", repoCustomProperty) 100 | if err != nil { 101 | t.Errorf("Repositories.CreateOrUpdateCustomProperties returned error: %v", err) 102 | } 103 | 104 | const methodName = "CreateOrUpdateCustomProperties" 105 | 106 | testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 107 | return client.Repositories.CreateOrUpdateCustomProperties(ctx, "usr", "r", repoCustomProperty) 108 | }) 109 | } 110 | -------------------------------------------------------------------------------- /github/strings.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "bytes" 10 | "fmt" 11 | "reflect" 12 | ) 13 | 14 | var timestampType = reflect.TypeOf(Timestamp{}) 15 | 16 | // Stringify attempts to create a reasonable string representation of types in 17 | // the GitHub library. It does things like resolve pointers to their values 18 | // and omits struct fields with nil values. 19 | func Stringify(message interface{}) string { 20 | var buf bytes.Buffer 21 | v := reflect.ValueOf(message) 22 | stringifyValue(&buf, v) 23 | return buf.String() 24 | } 25 | 26 | // stringifyValue was heavily inspired by the goprotobuf library. 27 | 28 | func stringifyValue(w *bytes.Buffer, val reflect.Value) { 29 | if val.Kind() == reflect.Ptr && val.IsNil() { 30 | w.WriteString("") 31 | return 32 | } 33 | 34 | v := reflect.Indirect(val) 35 | 36 | switch v.Kind() { 37 | case reflect.String: 38 | fmt.Fprintf(w, `"%s"`, v) 39 | case reflect.Slice: 40 | w.WriteByte('[') 41 | for i := 0; i < v.Len(); i++ { 42 | if i > 0 { 43 | w.WriteByte(' ') 44 | } 45 | 46 | stringifyValue(w, v.Index(i)) 47 | } 48 | 49 | w.WriteByte(']') 50 | return 51 | case reflect.Struct: 52 | if v.Type().Name() != "" { 53 | w.WriteString(v.Type().String()) 54 | } 55 | 56 | // special handling of Timestamp values 57 | if v.Type() == timestampType { 58 | fmt.Fprintf(w, "{%s}", v.Interface()) 59 | return 60 | } 61 | 62 | w.WriteByte('{') 63 | 64 | var sep bool 65 | for i := 0; i < v.NumField(); i++ { 66 | fv := v.Field(i) 67 | if fv.Kind() == reflect.Ptr && fv.IsNil() { 68 | continue 69 | } 70 | if fv.Kind() == reflect.Slice && fv.IsNil() { 71 | continue 72 | } 73 | if fv.Kind() == reflect.Map && fv.IsNil() { 74 | continue 75 | } 76 | 77 | if sep { 78 | w.WriteString(", ") 79 | } else { 80 | sep = true 81 | } 82 | 83 | w.WriteString(v.Type().Field(i).Name) 84 | w.WriteByte(':') 85 | stringifyValue(w, fv) 86 | } 87 | 88 | w.WriteByte('}') 89 | default: 90 | if v.CanInterface() { 91 | fmt.Fprint(w, v.Interface()) 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /github/timestamp.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "strconv" 10 | "time" 11 | ) 12 | 13 | // Timestamp represents a time that can be unmarshalled from a JSON string 14 | // formatted as either an RFC3339 or Unix timestamp. This is necessary for some 15 | // fields since the GitHub API is inconsistent in how it represents times. All 16 | // exported methods of time.Time can be called on Timestamp. 17 | type Timestamp struct { 18 | time.Time 19 | } 20 | 21 | func (t Timestamp) String() string { 22 | return t.Time.String() 23 | } 24 | 25 | // GetTime returns std time.Time. 26 | func (t *Timestamp) GetTime() *time.Time { 27 | if t == nil { 28 | return nil 29 | } 30 | return &t.Time 31 | } 32 | 33 | // UnmarshalJSON implements the json.Unmarshaler interface. 34 | // Time is expected in RFC3339 or Unix format. 35 | func (t *Timestamp) UnmarshalJSON(data []byte) (err error) { 36 | str := string(data) 37 | i, err := strconv.ParseInt(str, 10, 64) 38 | if err == nil { 39 | t.Time = time.Unix(i, 0) 40 | if t.Time.Year() > 3000 { 41 | t.Time = time.Unix(0, i*1e6) 42 | } 43 | } else { 44 | t.Time, err = time.Parse(`"`+time.RFC3339+`"`, str) 45 | } 46 | return 47 | } 48 | 49 | // Equal reports whether t and u are equal based on time.Equal. 50 | func (t Timestamp) Equal(u Timestamp) bool { 51 | return t.Time.Equal(u.Time) 52 | } 53 | -------------------------------------------------------------------------------- /github/users_administration.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | "fmt" 11 | ) 12 | 13 | // PromoteSiteAdmin promotes a user to a site administrator of a GitHub Enterprise instance. 14 | // 15 | // GitHub API docs: https://docs.github.com/enterprise-server@3.15/rest/enterprise-admin/users#promote-a-user-to-be-a-site-administrator 16 | // 17 | //meta:operation PUT /users/{username}/site_admin 18 | func (s *UsersService) PromoteSiteAdmin(ctx context.Context, user string) (*Response, error) { 19 | u := fmt.Sprintf("users/%v/site_admin", user) 20 | 21 | req, err := s.client.NewRequest("PUT", u, nil) 22 | if err != nil { 23 | return nil, err 24 | } 25 | 26 | return s.client.Do(ctx, req, nil) 27 | } 28 | 29 | // DemoteSiteAdmin demotes a user from site administrator of a GitHub Enterprise instance. 30 | // 31 | // GitHub API docs: https://docs.github.com/enterprise-server@3.15/rest/enterprise-admin/users#demote-a-site-administrator 32 | // 33 | //meta:operation DELETE /users/{username}/site_admin 34 | func (s *UsersService) DemoteSiteAdmin(ctx context.Context, user string) (*Response, error) { 35 | u := fmt.Sprintf("users/%v/site_admin", user) 36 | 37 | req, err := s.client.NewRequest("DELETE", u, nil) 38 | if err != nil { 39 | return nil, err 40 | } 41 | 42 | return s.client.Do(ctx, req, nil) 43 | } 44 | 45 | // UserSuspendOptions represents the reason a user is being suspended. 46 | type UserSuspendOptions struct { 47 | Reason *string `json:"reason,omitempty"` 48 | } 49 | 50 | // Suspend a user on a GitHub Enterprise instance. 51 | // 52 | // GitHub API docs: https://docs.github.com/enterprise-server@3.15/rest/enterprise-admin/users#suspend-a-user 53 | // 54 | //meta:operation PUT /users/{username}/suspended 55 | func (s *UsersService) Suspend(ctx context.Context, user string, opts *UserSuspendOptions) (*Response, error) { 56 | u := fmt.Sprintf("users/%v/suspended", user) 57 | 58 | req, err := s.client.NewRequest("PUT", u, opts) 59 | if err != nil { 60 | return nil, err 61 | } 62 | 63 | return s.client.Do(ctx, req, nil) 64 | } 65 | 66 | // Unsuspend a user on a GitHub Enterprise instance. 67 | // 68 | // GitHub API docs: https://docs.github.com/enterprise-server@3.15/rest/enterprise-admin/users#unsuspend-a-user 69 | // 70 | //meta:operation DELETE /users/{username}/suspended 71 | func (s *UsersService) Unsuspend(ctx context.Context, user string) (*Response, error) { 72 | u := fmt.Sprintf("users/%v/suspended", user) 73 | 74 | req, err := s.client.NewRequest("DELETE", u, nil) 75 | if err != nil { 76 | return nil, err 77 | } 78 | 79 | return s.client.Do(ctx, req, nil) 80 | } 81 | -------------------------------------------------------------------------------- /github/users_attestations.go: -------------------------------------------------------------------------------- 1 | // Copyright 2024 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | "fmt" 11 | ) 12 | 13 | // ListAttestations returns a collection of artifact attestations 14 | // with a given subject digest that are associated with repositories 15 | // owned by a user. 16 | // 17 | // GitHub API docs: https://docs.github.com/rest/users/attestations#list-attestations 18 | // 19 | //meta:operation GET /users/{username}/attestations/{subject_digest} 20 | func (s *UsersService) ListAttestations(ctx context.Context, user, subjectDigest string, opts *ListOptions) (*AttestationsResponse, *Response, error) { 21 | var u = fmt.Sprintf("users/%v/attestations/%v", user, subjectDigest) 22 | 23 | u, err := addOptions(u, opts) 24 | if err != nil { 25 | return nil, nil, err 26 | } 27 | 28 | req, err := s.client.NewRequest("GET", u, nil) 29 | if err != nil { 30 | return nil, nil, err 31 | } 32 | 33 | var attestations *AttestationsResponse 34 | res, err := s.client.Do(ctx, req, &attestations) 35 | if err != nil { 36 | return nil, res, err 37 | } 38 | 39 | return attestations, res, nil 40 | } 41 | -------------------------------------------------------------------------------- /github/users_attestations_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2024 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | "fmt" 11 | "net/http" 12 | "testing" 13 | 14 | "github.com/google/go-cmp/cmp" 15 | ) 16 | 17 | func TestUsersService_ListAttestations(t *testing.T) { 18 | t.Parallel() 19 | client, mux, _ := setup(t) 20 | 21 | mux.HandleFunc("/users/u/attestations/digest", func(w http.ResponseWriter, r *http.Request) { 22 | testMethod(t, r, "GET") 23 | fmt.Fprint(w, `{ 24 | "attestations": [ 25 | { 26 | "repository_id": 1, 27 | "bundle": {} 28 | }, 29 | { 30 | "repository_id": 2, 31 | "bundle": {} 32 | } 33 | ] 34 | }`) 35 | }) 36 | ctx := context.Background() 37 | attestations, _, err := client.Users.ListAttestations(ctx, "u", "digest", &ListOptions{}) 38 | if err != nil { 39 | t.Errorf("Users.ListAttestations returned error: %v", err) 40 | } 41 | 42 | want := &AttestationsResponse{ 43 | Attestations: []*Attestation{ 44 | { 45 | RepositoryID: 1, 46 | Bundle: []byte(`{}`), 47 | }, 48 | { 49 | RepositoryID: 2, 50 | Bundle: []byte(`{}`), 51 | }, 52 | }, 53 | } 54 | 55 | if !cmp.Equal(attestations, want) { 56 | t.Errorf("Users.ListAttestations = %+v, want %+v", attestations, want) 57 | } 58 | const methodName = "ListAttestations" 59 | 60 | testBadOptions(t, methodName, func() (err error) { 61 | _, _, err = client.Users.ListAttestations(ctx, "\n", "\n", &ListOptions{}) 62 | return err 63 | }) 64 | 65 | testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 66 | got, resp, err := client.Users.ListAttestations(ctx, "u", "digest", nil) 67 | if got != nil { 68 | t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 69 | } 70 | return resp, err 71 | }) 72 | } 73 | -------------------------------------------------------------------------------- /github/users_blocking.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import ( 9 | "context" 10 | "fmt" 11 | ) 12 | 13 | // ListBlockedUsers lists all the blocked users by the authenticated user. 14 | // 15 | // GitHub API docs: https://docs.github.com/rest/users/blocking#list-users-blocked-by-the-authenticated-user 16 | // 17 | //meta:operation GET /user/blocks 18 | func (s *UsersService) ListBlockedUsers(ctx context.Context, opts *ListOptions) ([]*User, *Response, error) { 19 | u := "user/blocks" 20 | u, err := addOptions(u, opts) 21 | if err != nil { 22 | return nil, nil, err 23 | } 24 | 25 | req, err := s.client.NewRequest("GET", u, nil) 26 | if err != nil { 27 | return nil, nil, err 28 | } 29 | 30 | // TODO: remove custom Accept header when this API fully launches. 31 | req.Header.Set("Accept", mediaTypeBlockUsersPreview) 32 | 33 | var blockedUsers []*User 34 | resp, err := s.client.Do(ctx, req, &blockedUsers) 35 | if err != nil { 36 | return nil, resp, err 37 | } 38 | 39 | return blockedUsers, resp, nil 40 | } 41 | 42 | // IsBlocked reports whether specified user is blocked by the authenticated user. 43 | // 44 | // GitHub API docs: https://docs.github.com/rest/users/blocking#check-if-a-user-is-blocked-by-the-authenticated-user 45 | // 46 | //meta:operation GET /user/blocks/{username} 47 | func (s *UsersService) IsBlocked(ctx context.Context, user string) (bool, *Response, error) { 48 | u := fmt.Sprintf("user/blocks/%v", user) 49 | 50 | req, err := s.client.NewRequest("GET", u, nil) 51 | if err != nil { 52 | return false, nil, err 53 | } 54 | 55 | // TODO: remove custom Accept header when this API fully launches. 56 | req.Header.Set("Accept", mediaTypeBlockUsersPreview) 57 | 58 | resp, err := s.client.Do(ctx, req, nil) 59 | isBlocked, err := parseBoolResponse(err) 60 | return isBlocked, resp, err 61 | } 62 | 63 | // BlockUser blocks specified user for the authenticated user. 64 | // 65 | // GitHub API docs: https://docs.github.com/rest/users/blocking#block-a-user 66 | // 67 | //meta:operation PUT /user/blocks/{username} 68 | func (s *UsersService) BlockUser(ctx context.Context, user string) (*Response, error) { 69 | u := fmt.Sprintf("user/blocks/%v", user) 70 | 71 | req, err := s.client.NewRequest("PUT", u, nil) 72 | if err != nil { 73 | return nil, err 74 | } 75 | 76 | // TODO: remove custom Accept header when this API fully launches. 77 | req.Header.Set("Accept", mediaTypeBlockUsersPreview) 78 | 79 | return s.client.Do(ctx, req, nil) 80 | } 81 | 82 | // UnblockUser unblocks specified user for the authenticated user. 83 | // 84 | // GitHub API docs: https://docs.github.com/rest/users/blocking#unblock-a-user 85 | // 86 | //meta:operation DELETE /user/blocks/{username} 87 | func (s *UsersService) UnblockUser(ctx context.Context, user string) (*Response, error) { 88 | u := fmt.Sprintf("user/blocks/%v", user) 89 | 90 | req, err := s.client.NewRequest("DELETE", u, nil) 91 | if err != nil { 92 | return nil, err 93 | } 94 | 95 | // TODO: remove custom Accept header when this API fully launches. 96 | req.Header.Set("Accept", mediaTypeBlockUsersPreview) 97 | 98 | return s.client.Do(ctx, req, nil) 99 | } 100 | -------------------------------------------------------------------------------- /github/users_emails.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package github 7 | 8 | import "context" 9 | 10 | // UserEmail represents user's email address. 11 | type UserEmail struct { 12 | Email *string `json:"email,omitempty"` 13 | Primary *bool `json:"primary,omitempty"` 14 | Verified *bool `json:"verified,omitempty"` 15 | Visibility *string `json:"visibility,omitempty"` 16 | } 17 | 18 | // ListEmails lists all email addresses for the authenticated user. 19 | // 20 | // GitHub API docs: https://docs.github.com/rest/users/emails#list-email-addresses-for-the-authenticated-user 21 | // 22 | //meta:operation GET /user/emails 23 | func (s *UsersService) ListEmails(ctx context.Context, opts *ListOptions) ([]*UserEmail, *Response, error) { 24 | u := "user/emails" 25 | u, err := addOptions(u, opts) 26 | if err != nil { 27 | return nil, nil, err 28 | } 29 | 30 | req, err := s.client.NewRequest("GET", u, nil) 31 | if err != nil { 32 | return nil, nil, err 33 | } 34 | 35 | var emails []*UserEmail 36 | resp, err := s.client.Do(ctx, req, &emails) 37 | if err != nil { 38 | return nil, resp, err 39 | } 40 | 41 | return emails, resp, nil 42 | } 43 | 44 | // AddEmails adds email addresses of the authenticated user. 45 | // 46 | // GitHub API docs: https://docs.github.com/rest/users/emails#add-an-email-address-for-the-authenticated-user 47 | // 48 | //meta:operation POST /user/emails 49 | func (s *UsersService) AddEmails(ctx context.Context, emails []string) ([]*UserEmail, *Response, error) { 50 | u := "user/emails" 51 | req, err := s.client.NewRequest("POST", u, emails) 52 | if err != nil { 53 | return nil, nil, err 54 | } 55 | 56 | var e []*UserEmail 57 | resp, err := s.client.Do(ctx, req, &e) 58 | if err != nil { 59 | return nil, resp, err 60 | } 61 | 62 | return e, resp, nil 63 | } 64 | 65 | // DeleteEmails deletes email addresses from authenticated user. 66 | // 67 | // GitHub API docs: https://docs.github.com/rest/users/emails#delete-an-email-address-for-the-authenticated-user 68 | // 69 | //meta:operation DELETE /user/emails 70 | func (s *UsersService) DeleteEmails(ctx context.Context, emails []string) (*Response, error) { 71 | u := "user/emails" 72 | req, err := s.client.NewRequest("DELETE", u, emails) 73 | if err != nil { 74 | return nil, err 75 | } 76 | 77 | return s.client.Do(ctx, req, nil) 78 | } 79 | 80 | // SetEmailVisibility sets the visibility for the primary email address of the authenticated user. 81 | // `visibility` can be "private" or "public". 82 | // 83 | // GitHub API docs: https://docs.github.com/rest/users/emails#set-primary-email-visibility-for-the-authenticated-user 84 | // 85 | //meta:operation PATCH /user/email/visibility 86 | func (s *UsersService) SetEmailVisibility(ctx context.Context, visibility string) ([]*UserEmail, *Response, error) { 87 | u := "user/email/visibility" 88 | 89 | updateVisibilityReq := &UserEmail{ 90 | Visibility: &visibility, 91 | } 92 | 93 | req, err := s.client.NewRequest("PATCH", u, updateVisibilityReq) 94 | if err != nil { 95 | return nil, nil, err 96 | } 97 | 98 | var e []*UserEmail 99 | resp, err := s.client.Do(ctx, req, &e) 100 | if err != nil { 101 | return nil, resp, err 102 | } 103 | 104 | return e, resp, nil 105 | } 106 | -------------------------------------------------------------------------------- /github/with_appengine.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | //go:build appengine 7 | 8 | // This file provides glue for making github work on App Engine. 9 | 10 | package github 11 | 12 | import ( 13 | "context" 14 | "net/http" 15 | ) 16 | 17 | func withContext(ctx context.Context, req *http.Request) *http.Request { 18 | // No-op because App Engine adds context to a request differently. 19 | return req 20 | } 21 | -------------------------------------------------------------------------------- /github/without_appengine.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | //go:build !appengine 7 | 8 | // This file provides glue for making github work without App Engine. 9 | 10 | package github 11 | 12 | import ( 13 | "context" 14 | "net/http" 15 | ) 16 | 17 | func withContext(ctx context.Context, req *http.Request) *http.Request { 18 | return req.WithContext(ctx) 19 | } 20 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/google/go-github/v68 2 | 3 | require ( 4 | github.com/google/go-cmp v0.6.0 5 | github.com/google/go-querystring v1.1.0 6 | ) 7 | 8 | go 1.22.10 9 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 2 | github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= 3 | github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 4 | github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= 5 | github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= 6 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 7 | -------------------------------------------------------------------------------- /scrape/README.md: -------------------------------------------------------------------------------- 1 | [![Go Reference](https://pkg.go.dev/badge/github.com/google/go-github/scrape.svg)](https://pkg.go.dev/github.com/google/go-github/scrape) 2 | 3 | The scrape package provides an experimental client for accessing additional 4 | GitHub data via screen scraping. It is designed to be a client of last resort 5 | for data that cannot be retrieved via the REST or GraphQL APIs. 6 | 7 | # What should be added here 8 | 9 | **Add only what you need.** Whereas the main go-github library attempts to 10 | implement the entire GitHub REST API, there is little point in trying to do that 11 | here. Certainly, feel free to contribution patches to get data you actually 12 | need, but I'd rather not try and provide exhaustive coverage of all GitHub data 13 | here. 14 | 15 | **Add only what can't be accessed elsewhere.** If the data can be retrieved 16 | through the REST or GraphQL API, use the appropriate libraries for that. 17 | 18 | **Prefer read-only access.** For now, I'm only focusing on reading data. It 19 | might be that writing works fine as well, but it is of course much riskier. 20 | 21 | # How to add methods 22 | 23 | See [apps.go](apps.go) for examples of methods that access data. Basically, 24 | fetch the contents of the page using `client.get`, and then use goquery to dig 25 | into the markup on the page. Prefer selectors that grab semantic ID or class 26 | names, as they are more likely to be stable. 27 | -------------------------------------------------------------------------------- /scrape/example/scrape/main.go: -------------------------------------------------------------------------------- 1 | // The scrape tool demonstrates use of the github.com/google/go-github/scrape 2 | // package to fetch data from GitHub. The tool lists whether third-party app 3 | // restrictions are enabled for an organization, and lists information about 4 | // OAuth apps requested for the org. 5 | package main 6 | 7 | import ( 8 | "bufio" 9 | "flag" 10 | "fmt" 11 | "log" 12 | "os" 13 | "strings" 14 | 15 | "github.com/google/go-github/scrape" 16 | ) 17 | 18 | var ( 19 | username = flag.String("username", "", "github auth: username") 20 | password = flag.String("password", "", "github auth: password") 21 | otpseed = flag.String("otpseed", "", "github auth: otp seed") 22 | org = flag.String("org", "", "github org to get data for") 23 | ) 24 | 25 | func main() { 26 | flag.Parse() 27 | 28 | // prompt for password and otpseed in case the user didn't want to specify as flags 29 | reader := bufio.NewReader(os.Stdin) 30 | if *password == "" { 31 | fmt.Print("password: ") 32 | *password, _ = reader.ReadString('\n') 33 | *password = strings.TrimSpace(*password) 34 | } 35 | if *otpseed == "" { 36 | fmt.Print("OTP seed: ") 37 | *otpseed, _ = reader.ReadString('\n') 38 | *otpseed = strings.TrimSpace(*otpseed) 39 | } 40 | 41 | client := scrape.NewClient(nil) 42 | 43 | if err := client.Authenticate(*username, *password, *otpseed); err != nil { 44 | log.Fatal(err) 45 | } 46 | 47 | enabled, err := client.AppRestrictionsEnabled(*org) 48 | if err != nil { 49 | log.Fatal(err) 50 | } 51 | fmt.Printf("App restrictions enabled for %q: %t\n", *org, enabled) 52 | 53 | apps, err := client.ListOAuthApps(*org) 54 | if err != nil { 55 | log.Fatal(err) 56 | } 57 | fmt.Printf("OAuth apps for %q: \n", *org) 58 | for _, app := range apps { 59 | fmt.Printf("\t%+v\n", app) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /scrape/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/google/go-github/scrape 2 | 3 | go 1.23.4 4 | 5 | require ( 6 | github.com/PuerkitoBio/goquery v1.10.1 7 | github.com/google/go-cmp v0.6.0 8 | github.com/google/go-github/v68 v68.0.0 9 | github.com/xlzd/gotp v0.1.0 10 | golang.org/x/net v0.33.0 11 | ) 12 | 13 | require ( 14 | github.com/andybalholm/cascadia v1.3.3 // indirect 15 | github.com/google/go-querystring v1.1.0 // indirect 16 | ) 17 | -------------------------------------------------------------------------------- /scrape/payment.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | // apps.go contains functions for accessing data about applications installed 7 | // on a GitHub organization. 8 | 9 | package scrape 10 | 11 | import ( 12 | "strings" 13 | 14 | "github.com/PuerkitoBio/goquery" 15 | ) 16 | 17 | // OrgPaymentInformation returns payment information for the specified org. 18 | func (c *Client) OrgPaymentInformation(org string) (PaymentInformation, error) { 19 | var info PaymentInformation 20 | 21 | doc, err := c.get("/organizations/%s/settings/billing/payment_information", org) 22 | if err != nil { 23 | return info, err 24 | } 25 | 26 | doc.Find("main h4.mb-1").Each(func(i int, s *goquery.Selection) { 27 | name := strings.TrimSpace(strings.ToLower(s.Text())) 28 | value := strings.Join(strings.Fields(strings.TrimSpace(s.NextFiltered("p").Text())), " ") 29 | 30 | switch name { 31 | case "payment method": 32 | info.PaymentMethod = value 33 | case "last payment": 34 | info.LastPayment = value 35 | case "coupon": 36 | info.Coupon = value 37 | case "extra information": 38 | info.ExtraInformation = value 39 | } 40 | }) 41 | 42 | return info, nil 43 | } 44 | 45 | // PaymentInformation for an organization on a paid plan. 46 | type PaymentInformation struct { 47 | PaymentMethod string 48 | LastPayment string 49 | Coupon string 50 | ExtraInformation string 51 | } 52 | -------------------------------------------------------------------------------- /scrape/scrape_test.go: -------------------------------------------------------------------------------- 1 | package scrape 2 | 3 | import ( 4 | "io" 5 | "net/http" 6 | "net/http/httptest" 7 | "net/url" 8 | "os" 9 | "path/filepath" 10 | "testing" 11 | ) 12 | 13 | // setup a test HTTP server along with a scrape.Client that is configured to 14 | // talk to that test server. Tests should register handlers on the mux which 15 | // provide mock responses for the GitHub pages being tested. 16 | func setup(t *testing.T) (client *Client, mux *http.ServeMux) { 17 | t.Helper() 18 | mux = http.NewServeMux() 19 | server := httptest.NewServer(mux) 20 | 21 | client = NewClient(nil) 22 | client.baseURL, _ = url.Parse(server.URL + "/") 23 | 24 | t.Cleanup(server.Close) 25 | 26 | return client, mux 27 | } 28 | 29 | func copyTestFile(t *testing.T, w io.Writer, filename string) { 30 | t.Helper() 31 | f, err := os.Open(filepath.Join("testdata", filename)) 32 | if err != nil { 33 | t.Fatalf("unable to open test file: %v", err) 34 | } 35 | _, err = io.Copy(w, f) 36 | if err != nil { 37 | t.Errorf("failure copying test file: %v", err) 38 | } 39 | err = f.Close() 40 | if err != nil { 41 | t.Errorf("failure closing test file: %v", err) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /scrape/testdata/access-restrictions-disabled.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 |
7 |
8 | 9 |
10 | 11 |
12 | 13 |
14 | 15 |
16 |

Third-party application access policy

17 |
18 |

19 | Policy: No restrictions 20 |

21 |

22 | All applications authorized by organization members have access to google-test’s data. 23 |

24 | Setup application access restrictions 25 |

26 | 27 | When authorized, applications can act on behalf of organization members. Your access policy determines which applications can access data in your organization. Read more about third-party access and organizations. 28 |

29 |
30 |
31 | 32 |
33 |
34 |
35 | 36 |
37 |
38 | 39 | 40 | -------------------------------------------------------------------------------- /script/fmt.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | #/ script/fmt.sh runs go fmt on all go files in the project. 3 | 4 | set -e 5 | 6 | CDPATH="" cd -- "$(dirname -- "$0")/.." 7 | 8 | MOD_DIRS="$(git ls-files '*go.mod' | xargs dirname | sort)" 9 | 10 | for dir in $MOD_DIRS; do 11 | ( 12 | cd "$dir" 13 | go fmt ./... 14 | ) 15 | done 16 | -------------------------------------------------------------------------------- /script/generate.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | #/ script/generate.sh runs go generate on all modules in this repo. 3 | #/ `script/generate.sh --check` checks that the generated files are up to date. 4 | 5 | set -e 6 | 7 | CDPATH="" cd -- "$(dirname -- "$0")/.." 8 | 9 | if [ "$1" = "--check" ]; then 10 | GENTEMP="$(mktemp -d)" 11 | git worktree add -q --detach "$GENTEMP" 12 | trap 'git worktree remove -f "$GENTEMP"; rm -rf "$GENTEMP"' EXIT 13 | for f in $(git ls-files -com --exclude-standard); do 14 | target="$GENTEMP/$f" 15 | mkdir -p "$(dirname -- "$target")" 16 | cp "$f" "$target" 17 | done 18 | if [ -f "$(pwd)"/bin ]; then 19 | ln -s "$(pwd)"/bin "$GENTEMP"/bin 20 | fi 21 | ( 22 | cd "$GENTEMP" 23 | git add . 24 | git -c user.name='bot' -c user.email='bot@localhost' commit -m "generate" -q --allow-empty 25 | script/generate.sh 26 | [ -z "$(git status --porcelain)" ] || { 27 | msg="Generated files are out of date. Please run script/generate.sh and commit the results" 28 | if [ -n "$GITHUB_ACTIONS" ]; then 29 | echo "::error ::$msg" 30 | else 31 | echo "$msg" 1>&2 32 | fi 33 | git diff 34 | exit 1 35 | } 36 | ) 37 | exit 0 38 | fi 39 | 40 | MOD_DIRS="$(git ls-files '*go.mod' | xargs dirname | sort)" 41 | 42 | for dir in $MOD_DIRS; do 43 | ( 44 | cd "$dir" 45 | go generate ./... 46 | go mod tidy -compat '1.21' 47 | ) 48 | done 49 | -------------------------------------------------------------------------------- /script/lint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | #/ [ CHECK_GITHUB_OPENAPI=1 ] script/lint.sh runs linters and validates generated files. 3 | #/ When CHECK_GITHUB is set, it validates that openapi_operations.yaml is consistent with the 4 | #/ descriptions from github.com/github/rest-api-description. 5 | 6 | set -e 7 | 8 | GOLANGCI_LINT_VERSION="1.62.0" 9 | 10 | CDPATH="" cd -- "$(dirname -- "$0")/.." 11 | BIN="$(pwd -P)"/bin 12 | 13 | mkdir -p "$BIN" 14 | 15 | EXIT_CODE=0 16 | 17 | fail() { 18 | echo "$@" 19 | EXIT_CODE=1 20 | } 21 | 22 | # install golangci-lint bin/golangci-lint doesn't exist with the correct version 23 | if ! "$BIN"/golangci-lint --version 2> /dev/null | grep -q "$GOLANGCI_LINT_VERSION"; then 24 | GOBIN="$BIN" go install "github.com/golangci/golangci-lint/cmd/golangci-lint@v$GOLANGCI_LINT_VERSION" 25 | fi 26 | 27 | MOD_DIRS="$(git ls-files '*go.mod' | xargs dirname | sort)" 28 | 29 | for dir in $MOD_DIRS; do 30 | [ "$dir" = "example/newreposecretwithlibsodium" ] && continue 31 | echo linting "$dir" 32 | ( 33 | cd "$dir" 34 | # github actions output when running in an action 35 | if [ -n "$GITHUB_ACTIONS" ]; then 36 | "$BIN"/golangci-lint run --path-prefix "$dir" --out-format colored-line-number 37 | else 38 | "$BIN"/golangci-lint run --path-prefix "$dir" 39 | fi 40 | ) || fail "failed linting $dir" 41 | done 42 | 43 | if [ -n "$CHECK_GITHUB_OPENAPI" ]; then 44 | echo validating openapi_operations.yaml 45 | script/metadata.sh update-openapi --validate || fail "failed validating openapi_operations.yaml" 46 | fi 47 | 48 | echo validating generated files 49 | script/generate.sh --check || fail "failed validating generated files" 50 | 51 | [ -z "$FAILED" ] || exit 1 52 | 53 | exit "$EXIT_CODE" 54 | -------------------------------------------------------------------------------- /script/metadata.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | #/ script/metadata.sh runs ./tools/metadata in the repository root with the given arguments 3 | 4 | set -e 5 | 6 | CDPATH="" cd -- "$(dirname -- "$0")/.." 7 | REPO_DIR="$(pwd)" 8 | 9 | ( 10 | cd tools/metadata 11 | go build -o "$REPO_DIR"/bin/metadata 12 | ) 13 | 14 | exec bin/metadata "$@" 15 | -------------------------------------------------------------------------------- /script/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | #/ script/test.sh runs tests on each go module in go-github. Arguments are passed to each go test invocation. 3 | #/ "-race -covermode atomic ./..." is used when no arguments are given. 4 | #/ 5 | #/ When UPDATE_GOLDEN is set, all directories named "golden" are removed before running tests. 6 | 7 | set -e 8 | 9 | CDPATH="" cd -- "$(dirname -- "$0")/.." 10 | # TODO(gmlewis): Remove this when #3409 is resolved. 11 | export GODEBUG=httpmuxgo121=1 12 | 13 | if [ "$#" = "0" ]; then 14 | set -- -race -covermode atomic ./... 15 | fi 16 | 17 | if [ -n "$UPDATE_GOLDEN" ]; then 18 | find . -name golden -type d -exec rm -rf {} + 19 | fi 20 | 21 | MOD_DIRS="$(git ls-files '*go.mod' | xargs dirname | sort)" 22 | 23 | for dir in $MOD_DIRS; do 24 | [ "$dir" = "example/newreposecretwithlibsodium" ] && continue 25 | echo "testing $dir" 26 | ( 27 | cd "$dir" 28 | go test "$@" 29 | ) || FAILED=1 30 | done 31 | 32 | if [ -n "$FAILED" ]; then 33 | exit 1 34 | fi 35 | -------------------------------------------------------------------------------- /test/README.md: -------------------------------------------------------------------------------- 1 | go-github tests 2 | =============== 3 | 4 | This directory contains additional test suites beyond the unit tests already in 5 | [../github](../github). Whereas the unit tests run very quickly (since they 6 | don't make any network calls) and are run by Travis on every commit, the tests 7 | in this directory are only run manually. 8 | 9 | The test packages are: 10 | 11 | integration 12 | ----------- 13 | 14 | This will exercise the entire go-github library (or at least as much as is 15 | practical) against the live GitHub API. These tests will verify that the 16 | library is properly coded against the actual behavior of the API, and will 17 | (hopefully) fail upon any incompatible change in the API. 18 | 19 | Because these tests are running using live data, there is a much higher 20 | probability of false positives in test failures due to network issues, test 21 | data having been changed, etc. 22 | 23 | These tests send real network traffic to the GitHub API and will exhaust the 24 | default unregistered rate limit (60 requests per hour) very quickly. 25 | Additionally, in order to test the methods that modify data, a real OAuth token 26 | will need to be present. While the tests will try to be well-behaved in terms 27 | of what data they modify, it is **strongly** recommended that these tests only 28 | be run using a dedicated test account. 29 | 30 | Run tests using: 31 | 32 | GITHUB_AUTH_TOKEN=XXX go test -v -tags=integration ./integration 33 | 34 | Some tests create repositories. By default, the new repositories will be owned 35 | by the user identified by the OAuth token. Set the `GITHUB_OWNER=''` 36 | environment variable to specify a different owner, such as an organization. 37 | 38 | Additionally there are a set of integration tests for the Authorizations API. 39 | These tests require a GitHub user (username and password), and also that a 40 | [GitHub Application](https://github.com/settings/applications/new) (with 41 | attendant Client ID and Client Secret) be available. Then, to execute just the 42 | Authorization tests: 43 | 44 | GITHUB_USERNAME='' GITHUB_PASSWORD='' GITHUB_CLIENT_ID='' GITHUB_CLIENT_SECRET='' go test -v -tags=integration -run=Authorizations ./integration 45 | 46 | If some or all of these environment variables are not available, certain of the 47 | Authorization integration tests will be skipped. 48 | 49 | fields 50 | ------ 51 | 52 | This will identify the fields being returned by the live GitHub API that are 53 | not currently being mapped into the relevant Go data type. Sometimes fields 54 | are deliberately not mapped, so the results of this tool should just be taken 55 | as a hint. 56 | 57 | This test sends real network traffic to the GitHub API and will exhaust the 58 | default unregistered rate limit (60 requests per hour) very quickly. 59 | Additionally, some data is only returned for authenticated API calls. Unlike 60 | the integration tests above, these tests only read data, so it's less 61 | imperative that these be run using a dedicated test account (though you still 62 | really should). 63 | 64 | Run the fields tool using: 65 | 66 | GITHUB_AUTH_TOKEN=XXX go run ./fields/fields.go 67 | -------------------------------------------------------------------------------- /test/integration/audit_log_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | //go:build integration 7 | 8 | package integration 9 | 10 | import ( 11 | "context" 12 | "testing" 13 | ) 14 | 15 | // TestOrganizationAuditLog test that the client can read an org's audit log. 16 | // Note: Org must be part of an enterprise. 17 | // Test requires auth - set env var GITHUB_AUTH_TOKEN. 18 | func TestOrganizationAuditLog(t *testing.T) { 19 | org := "example_org" 20 | entries, _, err := client.Organizations.GetAuditLog(context.Background(), org, nil) 21 | if err != nil { 22 | t.Fatalf("Organizations.GetAuditLog returned error: %v", err) 23 | } 24 | 25 | if len(entries) == 0 { 26 | t.Errorf("No AuditLog events returned for org") 27 | } 28 | 29 | for _, e := range entries { 30 | t.Log(e.GetAction(), e.GetActor(), e.GetTimestamp(), e.GetUser()) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /test/integration/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | // Package integration contains integration tests. 7 | // 8 | // These tests call the live GitHub API, and therefore require a little more 9 | // setup to run. See https://github.com/google/go-github/tree/master/test#integration 10 | // for more information. 11 | package integration 12 | -------------------------------------------------------------------------------- /test/integration/github_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | //go:build integration 7 | 8 | package integration 9 | 10 | import ( 11 | "context" 12 | "fmt" 13 | "math/rand" 14 | "net/http" 15 | "os" 16 | 17 | "github.com/google/go-github/v68/github" 18 | ) 19 | 20 | var ( 21 | client *github.Client 22 | 23 | // auth indicates whether tests are being run with an OAuth token. 24 | // Tests can use this flag to skip certain tests when run without auth. 25 | auth bool 26 | ) 27 | 28 | func init() { 29 | token := os.Getenv("GITHUB_AUTH_TOKEN") 30 | if token == "" { 31 | fmt.Print("!!! No OAuth token. Some tests won't run. !!!\n\n") 32 | client = github.NewClient(nil) 33 | } else { 34 | client = github.NewClient(nil).WithAuthToken(token) 35 | auth = true 36 | } 37 | } 38 | 39 | func checkAuth(name string) bool { 40 | if !auth { 41 | fmt.Printf("No auth - skipping portions of %v\n", name) 42 | } 43 | return auth 44 | } 45 | 46 | func createRandomTestRepository(owner string, autoinit bool) (*github.Repository, error) { 47 | // determine the owner to use if one wasn't specified 48 | if owner == "" { 49 | owner = os.Getenv("GITHUB_OWNER") 50 | if owner == "" { 51 | me, _, err := client.Users.Get(context.Background(), "") 52 | if err != nil { 53 | return nil, err 54 | } 55 | owner = *me.Login 56 | } 57 | } 58 | 59 | // create random repo name that does not currently exist 60 | var repoName string 61 | for { 62 | repoName = fmt.Sprintf("test-%d", rand.Int()) 63 | _, resp, err := client.Repositories.Get(context.Background(), owner, repoName) 64 | if err != nil { 65 | if resp.StatusCode == http.StatusNotFound { 66 | // found a non-existent repo, perfect 67 | break 68 | } 69 | 70 | return nil, err 71 | } 72 | } 73 | 74 | // create the repository 75 | repo, _, err := client.Repositories.Create( 76 | context.Background(), 77 | owner, 78 | &github.Repository{ 79 | Name: github.Ptr(repoName), 80 | AutoInit: github.Ptr(autoinit), 81 | }, 82 | ) 83 | if err != nil { 84 | return nil, err 85 | } 86 | 87 | return repo, nil 88 | } 89 | -------------------------------------------------------------------------------- /test/integration/issues_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | //go:build integration 7 | 8 | package integration 9 | 10 | import ( 11 | "context" 12 | "testing" 13 | ) 14 | 15 | func TestIssueEvents(t *testing.T) { 16 | events, _, err := client.Issues.ListRepositoryEvents(context.Background(), "google", "go-github", nil) 17 | if err != nil { 18 | t.Fatalf("Issues.ListRepositoryEvents returned error: %v", err) 19 | } 20 | 21 | if len(events) == 0 { 22 | t.Errorf("ListRepositoryEvents returned no events") 23 | } 24 | 25 | events, _, err = client.Issues.ListIssueEvents(context.Background(), "google", "go-github", 1, nil) 26 | if err != nil { 27 | t.Fatalf("Issues.ListIssueEvents returned error: %v", err) 28 | } 29 | 30 | if len(events) == 0 { 31 | t.Errorf("ListIssueEvents returned no events") 32 | } 33 | 34 | event, _, err := client.Issues.GetEvent(context.Background(), "google", "go-github", *events[0].ID) 35 | if err != nil { 36 | t.Fatalf("Issues.GetEvent returned error: %v", err) 37 | } 38 | 39 | if *event.URL != *events[0].URL { 40 | t.Fatalf("Issues.GetEvent returned event URL: %v, want %v", *event.URL, *events[0].URL) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /test/integration/misc_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | //go:build integration 7 | 8 | package integration 9 | 10 | import ( 11 | "context" 12 | "testing" 13 | "time" 14 | ) 15 | 16 | func TestEmojis(t *testing.T) { 17 | emoji, _, err := client.Emojis.List(context.Background()) 18 | if err != nil { 19 | t.Fatalf("List returned error: %v", err) 20 | } 21 | 22 | if len(emoji) == 0 { 23 | t.Errorf("List returned no emojis") 24 | } 25 | 26 | if _, ok := emoji["+1"]; !ok { 27 | t.Errorf("List missing '+1' emoji") 28 | } 29 | } 30 | 31 | func TestAPIMeta(t *testing.T) { 32 | meta, _, err := client.Meta.Get(context.Background()) 33 | if err != nil { 34 | t.Fatalf("Get returned error: %v", err) 35 | } 36 | 37 | if len(meta.Hooks) == 0 { 38 | t.Errorf("Get returned no hook addresses") 39 | } 40 | 41 | if len(meta.Git) == 0 { 42 | t.Errorf("Get returned no git addresses") 43 | } 44 | 45 | if !*meta.VerifiablePasswordAuthentication { 46 | t.Errorf("APIMeta VerifiablePasswordAuthentication is false") 47 | } 48 | } 49 | 50 | func TestRateLimits(t *testing.T) { 51 | limits, _, err := client.RateLimit.Get(context.Background()) 52 | if err != nil { 53 | t.Fatalf("RateLimits returned error: %v", err) 54 | } 55 | 56 | // do some sanity checks 57 | if limits.Core.Limit == 0 { 58 | t.Errorf("RateLimits returned 0 core limit") 59 | } 60 | 61 | if limits.Core.Limit < limits.Core.Remaining { 62 | t.Errorf("Core.Limits is less than Core.Remaining.") 63 | } 64 | 65 | if limits.Core.Reset.Time.Before(time.Now().Add(-1 * time.Minute)) { 66 | t.Errorf("Core.Reset is more than 1 minute in the past; that doesn't seem right.") 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /test/integration/pulls_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | //go:build integration 7 | 8 | package integration 9 | 10 | import ( 11 | "context" 12 | "testing" 13 | ) 14 | 15 | func TestPullRequests_ListCommits(t *testing.T) { 16 | commits, _, err := client.PullRequests.ListCommits(context.Background(), "google", "go-github", 2, nil) 17 | if err != nil { 18 | t.Fatalf("PullRequests.ListCommits() returned error: %v", err) 19 | } 20 | 21 | if got, want := len(commits), 3; got != want { 22 | t.Fatalf("PullRequests.ListCommits() returned %d commits, want %d", got, want) 23 | } 24 | 25 | if got, want := *commits[0].Author.Login, "sqs"; got != want { 26 | t.Fatalf("PullRequests.ListCommits()[0].Author.Login returned %v, want %v", got, want) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /tools/go.mod: -------------------------------------------------------------------------------- 1 | module tools 2 | 3 | go 1.23.4 4 | 5 | require ( 6 | github.com/alecthomas/kong v1.6.0 7 | github.com/getkin/kin-openapi v0.128.0 8 | github.com/google/go-cmp v0.6.0 9 | github.com/google/go-github/v68 v68.0.0 10 | golang.org/x/sync v0.10.0 11 | gopkg.in/yaml.v3 v3.0.1 12 | ) 13 | 14 | require ( 15 | github.com/go-openapi/jsonpointer v0.21.0 // indirect 16 | github.com/go-openapi/swag v0.23.0 // indirect 17 | github.com/google/go-querystring v1.1.0 // indirect 18 | github.com/invopop/yaml v0.3.1 // indirect 19 | github.com/josharian/intern v1.0.0 // indirect 20 | github.com/mailru/easyjson v0.7.7 // indirect 21 | github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect 22 | github.com/perimeterx/marshmallow v1.1.5 // indirect 23 | ) 24 | 25 | // Use version at HEAD, not the latest published. 26 | replace github.com/google/go-github/v68 => ../ 27 | -------------------------------------------------------------------------------- /tools/metadata/metadata_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023 The go-github AUTHORS. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package main 7 | 8 | import ( 9 | "testing" 10 | ) 11 | 12 | func Test_normalizedOpName(t *testing.T) { 13 | t.Parallel() 14 | for _, td := range []struct { 15 | name string 16 | want string 17 | }{ 18 | {name: "", want: ""}, 19 | {name: "get /foo/{id}", want: "GET /foo/*"}, 20 | {name: "get foo", want: "GET /foo"}, 21 | } { 22 | td := td 23 | t.Run(td.name, func(t *testing.T) { 24 | t.Parallel() 25 | got := normalizedOpName(td.name) 26 | if got != td.want { 27 | t.Errorf("normalizedOpName() = %v, want %v", got, td.want) 28 | } 29 | }) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tools/metadata/testdata/format/openapi_operations.yaml: -------------------------------------------------------------------------------- 1 | 2 | operations: 3 | - name: POST /a/{a_id} 4 | documentation_url: https://docs.github.com/rest/a/a#update-a 5 | openapi_operations: 6 | - name: GET /a/{a_id} 7 | documentation_url: https://docs.github.com/rest/a/a#get-a 8 | - name: GET /undocumented/{undocumented_id} 9 | 10 | operation_overrides: 11 | - name: GET /a/{a_id_noncanonical2} # this comment will disappear 12 | documentation_url: https://docs.github.com/rest/a/a#overridden-get-a 13 | - name: GET /fake/{a_id} 14 | documentation_url: https://docs.github.com/rest/a/a#overridden-get-a 15 | 16 | openapi_commit: b8dafbe912a3be421d21346faa2b29bf15e6f84d 17 | -------------------------------------------------------------------------------- /tools/metadata/testdata/golden/TestFormat/openapi_operations.yaml: -------------------------------------------------------------------------------- 1 | operations: 2 | - name: POST /a/{a_id} 3 | documentation_url: https://docs.github.com/rest/a/a#update-a 4 | operation_overrides: 5 | - name: GET /a/{a_id_noncanonical2} 6 | documentation_url: https://docs.github.com/rest/a/a#overridden-get-a 7 | - name: GET /fake/{a_id} 8 | documentation_url: https://docs.github.com/rest/a/a#overridden-get-a 9 | openapi_commit: b8dafbe912a3be421d21346faa2b29bf15e6f84d 10 | openapi_operations: 11 | - name: GET /a/{a_id} 12 | documentation_url: https://docs.github.com/rest/a/a#get-a 13 | - name: GET /undocumented/{undocumented_id} 14 | -------------------------------------------------------------------------------- /tools/metadata/testdata/golden/TestUpdateGo/valid/github/a.go: -------------------------------------------------------------------------------- 1 | package github 2 | 3 | type AService struct{} 4 | 5 | // Get gets an A 6 | // 7 | // GitHub API docs: https://docs.github.com/rest/a/a#overridden-get-a 8 | // 9 | //meta:operation GET /a/{a_id} 10 | func (s *AService) Get() {} 11 | 12 | // Undocumented uses an undocumented operation 13 | // 14 | // Note: Undocumented uses the undocumented GitHub API endpoint "GET /undocumented/{undocumented_id}". 15 | // 16 | //meta:operation GET /undocumented/{undocumented_id} 17 | func (s *AService) Undocumented() {} 18 | 19 | // OutdatedLinks has links that are outdated or wrong 20 | // 21 | // GitHub API docs: https://docs.github.com/rest/a/a#update-a 22 | // 23 | //meta:operation POST /a/{a_id} 24 | func (s *AService) OutdatedLinks() {} 25 | 26 | // GitHub API docs: https://docs.github.com/rest/a/a#overridden-get-a 27 | // 28 | //meta:operation GET /a/{a_id} 29 | func (s *AService) Uncommented() {} 30 | 31 | func (s *AService) unexported() {} 32 | 33 | func NotAMethod() {} 34 | 35 | type internalService struct{} 36 | 37 | func (i *internalService) Get() {} 38 | -------------------------------------------------------------------------------- /tools/metadata/testdata/golden/TestUpdateOpenAPI/openapi_operations.yaml: -------------------------------------------------------------------------------- 1 | operations: 2 | - name: GET /a/{a_id} 3 | documentation_url: https://docs.github.com/rest/a/a#get-a 4 | openapi_commit: s 5 | openapi_operations: 6 | - name: GET /a/b/{a_id} 7 | documentation_url: https://docs.github.com/rest/reference/a 8 | openapi_files: 9 | - descriptions/ghec/ghec.json 10 | - descriptions/ghes-3.10/ghes-3.10.json 11 | - name: GET /a/{a_id} 12 | documentation_url: https://docs.github.com/rest/reference/a 13 | openapi_files: 14 | - descriptions/api.github.com/api.github.com.json 15 | -------------------------------------------------------------------------------- /tools/metadata/testdata/unused/github/a.go: -------------------------------------------------------------------------------- 1 | package github 2 | 3 | type AService struct{} 4 | 5 | // PostABC 6 | // 7 | //meta:operation POST /a/b/c/{a_id} 8 | func (a *AService) PostABC() {} 9 | -------------------------------------------------------------------------------- /tools/metadata/testdata/unused/openapi_operations.yaml: -------------------------------------------------------------------------------- 1 | openapi_commit: b8dafbe912a3be421d21346faa2b29bf15e6f84d 2 | operations: 3 | - name: POST /a/{a_id} 4 | documentation_url: https://docs.github.com/rest/a/a#update-a 5 | openapi_operations: 6 | - name: POST /a/b/c/{a_id} 7 | documentation_url: https://docs.github.com/rest/a/b/c#update-a 8 | - name: GET /a/{a_id} 9 | documentation_url: https://docs.github.com/rest/a/a#get-a 10 | - name: GET /undocumented/{undocumented_id} 11 | operation_overrides: 12 | - name: GET /a/{a_id} 13 | documentation_url: https://docs.github.com/rest/a/a#overridden-get-a 14 | - name: GET /fake/{a_id} 15 | documentation_url: https://docs.github.com/rest/a/a#overridden-get-a 16 | -------------------------------------------------------------------------------- /tools/metadata/testdata/update-go/invalid/github/a.go: -------------------------------------------------------------------------------- 1 | package github 2 | 3 | type AService struct{} 4 | 5 | // NoOperation has no operation 6 | func (*AService) NoOperation() {} 7 | 8 | func (*AService) NoComment() {} 9 | 10 | // Ambiguous has an operation that could resolve to multiple operations 11 | // 12 | //meta:operation GET /ambiguous/{} 13 | func (*AService) Ambiguous() {} 14 | 15 | // MissingOperation has an operation that is missing from the OpenAPI spec 16 | // 17 | //meta:operation GET /missing/{id} 18 | func (*AService) MissingOperation() {} 19 | 20 | // DuplicateOperations has duplicate operations 21 | // 22 | //meta:operation GET /a/{a_id} 23 | //meta:operation POST /a/{a_id} 24 | //meta:operation GET /a/{a_id} 25 | func (*AService) DuplicateOperations() {} 26 | -------------------------------------------------------------------------------- /tools/metadata/testdata/update-go/invalid/openapi_operations.yaml: -------------------------------------------------------------------------------- 1 | operations: 2 | - name: POST /a/{a_id} 3 | documentation_url: https://docs.github.com/rest/a/a#update-a 4 | openapi_operations: 5 | - name: GET /ambiguous/{id} 6 | documentation_url: https://docs.github.com/rest/ambiguous/ 7 | - name: GET /ambiguous/{name} 8 | documentation_url: https://docs.github.com/rest/ambiguous/ 9 | - name: GET /undocumented/{undocumented_id} 10 | - name: GET /a/{a_id} 11 | documentation_url: https://docs.github.com/rest/a/a#get-a 12 | operation_overrides: 13 | - name: GET /a/{a_id} 14 | documentation_url: https://docs.github.com/rest/a/a#overridden-get-a 15 | - name: GET /fake/{a_id} 16 | documentation_url: https://docs.github.com/rest/a/a#overridden-get-a 17 | -------------------------------------------------------------------------------- /tools/metadata/testdata/update-go/valid/github/a.go: -------------------------------------------------------------------------------- 1 | package github 2 | 3 | type AService struct{} 4 | 5 | // Get gets an A 6 | // 7 | //meta:operation GET /a/{non-canonical-id} 8 | func (s *AService) Get() {} 9 | 10 | // Undocumented uses an undocumented operation 11 | // 12 | //meta:operation GET /undocumented/{undocumented_id} 13 | func (s *AService) Undocumented() {} 14 | 15 | // OutdatedLinks has links that are outdated or wrong 16 | // 17 | // GitHub API docs: https://docs.github.com/rest/a/a#get-a 18 | // GitHub API docs: https://example.com 19 | // Note: Undocumented uses the undocumented GitHub API endpoint "GET /undocumented/{undocumented_id}". 20 | // 21 | //meta:operation post a/{a_id} 22 | func (s *AService) OutdatedLinks() {} 23 | 24 | //meta:operation GET /a/{a_id} 25 | func (s *AService) Uncommented() {} 26 | 27 | func (s *AService) unexported() {} 28 | 29 | func NotAMethod() {} 30 | 31 | type internalService struct{} 32 | 33 | func (i *internalService) Get() {} 34 | -------------------------------------------------------------------------------- /tools/metadata/testdata/update-go/valid/github/ignoreme.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GabrielNat1/go-github/3428a813851d8b860cda96761747a657b3b4a222/tools/metadata/testdata/update-go/valid/github/ignoreme.txt -------------------------------------------------------------------------------- /tools/metadata/testdata/update-go/valid/openapi_operations.yaml: -------------------------------------------------------------------------------- 1 | openapi_commit: b8dafbe912a3be421d21346faa2b29bf15e6f84d 2 | operations: 3 | - name: POST /a/{a_id} 4 | documentation_url: https://docs.github.com/rest/a/a#update-a 5 | openapi_operations: 6 | - name: GET /a/{a_id} 7 | documentation_url: https://docs.github.com/rest/a/a#get-a 8 | - name: GET /undocumented/{undocumented_id} 9 | operation_overrides: 10 | - name: GET /a/{a_id} 11 | documentation_url: https://docs.github.com/rest/a/a#overridden-get-a 12 | - name: GET /fake/{a_id} 13 | documentation_url: https://docs.github.com/rest/a/a#overridden-get-a 14 | -------------------------------------------------------------------------------- /tools/metadata/testdata/update-openapi/openapi_operations.yaml: -------------------------------------------------------------------------------- 1 | operations: 2 | - name: GET /a/{a_id} 3 | documentation_url: https://docs.github.com/rest/a/a#get-a 4 | openapi_commit: s 5 | --------------------------------------------------------------------------------