github.com/google/go-github/v66@v66.0.0/README.md (about) 1 # go-github # 2 3 [](https://github.com/google/go-github/releases) 4 [](https://pkg.go.dev/github.com/google/go-github/v66/github) 5 [](https://github.com/google/go-github/actions?query=workflow%3Atests) 6 [](https://codecov.io/gh/google/go-github) 7 [](https://groups.google.com/group/go-github) 8 [](https://bestpractices.coreinfrastructure.org/projects/796) 9 10 go-github is a Go client library for accessing the [GitHub API v3][]. 11 12 Currently, **go-github tests against Go version 1.22 and greater**. go-github tracks 13 [Go's version support policy][support-policy]. We do our best not to break 14 older versions of Go if we don't have to, but due to tooling constraints, we 15 don't always test older versions. 16 17 [support-policy]: https://golang.org/doc/devel/release.html#policy 18 19 If you're interested in using the [GraphQL API v4][], the recommended library is 20 [shurcooL/githubv4][]. 21 22 ## Installation ## 23 24 go-github is compatible with modern Go releases in module mode, with Go installed: 25 26 ```bash 27 go get github.com/google/go-github/v66 28 ``` 29 30 will resolve and add the package to the current development module, along with its dependencies. 31 32 Alternatively the same can be achieved if you use import in a package: 33 34 ```go 35 import "github.com/google/go-github/v66/github" 36 ``` 37 38 and run `go get` without parameters. 39 40 Finally, to use the top-of-trunk version of this repo, use the following command: 41 42 ```bash 43 go get github.com/google/go-github/v66@master 44 ``` 45 46 ## Usage ## 47 48 ```go 49 import "github.com/google/go-github/v66/github" // with go modules enabled (GO111MODULE=on or outside GOPATH) 50 import "github.com/google/go-github/github" // with go modules disabled 51 ``` 52 53 Construct a new GitHub client, then use the various services on the client to 54 access different parts of the GitHub API. For example: 55 56 ```go 57 client := github.NewClient(nil) 58 59 // list all organizations for user "willnorris" 60 orgs, _, err := client.Organizations.List(context.Background(), "willnorris", nil) 61 ``` 62 63 Some API methods have optional parameters that can be passed. For example: 64 65 ```go 66 client := github.NewClient(nil) 67 68 // list public repositories for org "github" 69 opt := &github.RepositoryListByOrgOptions{Type: "public"} 70 repos, _, err := client.Repositories.ListByOrg(context.Background(), "github", opt) 71 ``` 72 73 The services of a client divide the API into logical chunks and correspond to 74 the structure of the [GitHub API documentation](https://docs.github.com/en/rest). 75 76 NOTE: Using the [context](https://pkg.go.dev/context) package, one can easily 77 pass cancelation signals and deadlines to various services of the client for 78 handling a request. In case there is no context available, then `context.Background()` 79 can be used as a starting point. 80 81 For more sample code snippets, head over to the 82 [example](https://github.com/google/go-github/tree/master/example) directory. 83 84 ### Authentication ### 85 86 Use the `WithAuthToken` method to configure your client to authenticate using an 87 OAuth token (for example, a [personal access token][]). This is what is needed 88 for a majority of use cases aside from GitHub Apps. 89 90 ```go 91 client := github.NewClient(nil).WithAuthToken("... your access token ...") 92 ``` 93 94 Note that when using an authenticated Client, all calls made by the client will 95 include the specified OAuth token. Therefore, authenticated clients should 96 almost never be shared between different users. 97 98 For API methods that require HTTP Basic Authentication, use the 99 [`BasicAuthTransport`](https://pkg.go.dev/github.com/google/go-github/github#BasicAuthTransport). 100 101 #### As a GitHub App #### 102 103 GitHub Apps authentication can be provided by different pkgs like [bradleyfalzon/ghinstallation](https://github.com/bradleyfalzon/ghinstallation) 104 or [jferrl/go-githubauth](https://github.com/jferrl/go-githubauth). 105 106 > **Note**: Most endpoints (ex. [`GET /rate_limit`]) require access token authentication 107 > while a few others (ex. [`GET /app/hook/deliveries`]) require [JWT] authentication. 108 109 [`GET /rate_limit`]: https://docs.github.com/en/rest/rate-limit#get-rate-limit-status-for-the-authenticated-user 110 [`GET /app/hook/deliveries`]: https://docs.github.com/en/rest/apps/webhooks#list-deliveries-for-an-app-webhook 111 [JWT]: https://docs.github.com/en/developers/apps/building-github-apps/authenticating-with-github-apps#authenticating-as-a-github-app 112 113 `ghinstallation` provides `Transport`, which implements `http.RoundTripper` to provide authentication as an installation for GitHub Apps. 114 115 Here is an example of how to authenticate as a GitHub App using the `ghinstallation` package: 116 117 ```go 118 import ( 119 "net/http" 120 121 "github.com/bradleyfalzon/ghinstallation/v2" 122 "github.com/google/go-github/v66/github" 123 ) 124 125 func main() { 126 // Wrap the shared transport for use with the integration ID 1 authenticating with installation ID 99. 127 itr, err := ghinstallation.NewKeyFromFile(http.DefaultTransport, 1, 99, "2016-10-19.private-key.pem") 128 129 // Or for endpoints that require JWT authentication 130 // itr, err := ghinstallation.NewAppsTransportKeyFromFile(http.DefaultTransport, 1, "2016-10-19.private-key.pem") 131 132 if err != nil { 133 // Handle error. 134 } 135 136 // Use installation transport with client. 137 client := github.NewClient(&http.Client{Transport: itr}) 138 139 // Use client... 140 } 141 ``` 142 143 `go-githubauth` implements a set of `oauth2.TokenSource` to be used with `oauth2.Client`. An `oauth2.Client` can be injected into the `github.Client` to authenticate requests. 144 145 Other example using `go-githubauth`: 146 147 ```go 148 package main 149 150 import ( 151 "context" 152 "fmt" 153 "os" 154 "strconv" 155 156 "github.com/google/go-github/v66/github" 157 "github.com/jferrl/go-githubauth" 158 "golang.org/x/oauth2" 159 ) 160 161 func main() { 162 privateKey := []byte(os.Getenv("GITHUB_APP_PRIVATE_KEY")) 163 164 appTokenSource, err := githubauth.NewApplicationTokenSource(1112, privateKey) 165 if err != nil { 166 fmt.Println("Error creating application token source:", err) 167 return 168 } 169 170 installationTokenSource := githubauth.NewInstallationTokenSource(1113, appTokenSource) 171 172 // oauth2.NewClient uses oauth2.ReuseTokenSource to reuse the token until it expires. 173 // The token will be automatically refreshed when it expires. 174 // InstallationTokenSource has the mechanism to refresh the token when it expires. 175 httpClient := oauth2.NewClient(context.Background(), installationTokenSource) 176 177 client := github.NewClient(httpClient) 178 } 179 ``` 180 181 *Note*: In order to interact with certain APIs, for example writing a file to a repo, one must generate an installation token 182 using the installation ID of the GitHub app and authenticate with the OAuth method mentioned above. See the examples. 183 184 ### Rate Limiting ### 185 186 GitHub imposes a rate limit on all API clients. Unauthenticated clients are 187 limited to 60 requests per hour, while authenticated clients can make up to 188 5,000 requests per hour. The Search API has a custom rate limit. Unauthenticated 189 clients are limited to 10 requests per minute, while authenticated clients 190 can make up to 30 requests per minute. To receive the higher rate limit when 191 making calls that are not issued on behalf of a user, 192 use `UnauthenticatedRateLimitedTransport`. 193 194 The returned `Response.Rate` value contains the rate limit information 195 from the most recent API call. If a recent enough response isn't 196 available, you can use `RateLimits` to fetch the most up-to-date rate 197 limit data for the client. 198 199 To detect an API rate limit error, you can check if its type is `*github.RateLimitError`: 200 201 ```go 202 repos, _, err := client.Repositories.List(ctx, "", nil) 203 if _, ok := err.(*github.RateLimitError); ok { 204 log.Println("hit rate limit") 205 } 206 ``` 207 208 Learn more about GitHub rate limiting in 209 ["REST API endpoints for rate limits"](https://docs.github.com/en/rest/rate-limit). 210 211 In addition to these rate limits, GitHub imposes a secondary rate limit on all API clients. 212 This rate limit prevents clients from making too many concurrent requests. 213 214 To detect an API secondary rate limit error, you can check if its type is `*github.AbuseRateLimitError`: 215 216 ```go 217 repos, _, err := client.Repositories.List(ctx, "", nil) 218 if _, ok := err.(*github.AbuseRateLimitError); ok { 219 log.Println("hit secondary rate limit") 220 } 221 ``` 222 223 Alternatively, you can block until the rate limit is reset by using the `context.WithValue` method: 224 225 ```go 226 repos, _, err := client.Repositories.List(context.WithValue(ctx, github.SleepUntilPrimaryRateLimitResetWhenRateLimited, true), "", nil) 227 ``` 228 229 You can use [gofri/go-github-ratelimit](https://github.com/gofri/go-github-ratelimit) to handle 230 secondary rate limit sleep-and-retry for you. 231 232 Learn more about GitHub secondary rate limiting in 233 ["About secondary rate limits"](https://docs.github.com/en/rest/using-the-rest-api/rate-limits-for-the-rest-api?apiVersion=2022-11-28#about-secondary-rate-limits). 234 235 ### Accepted Status ### 236 237 Some endpoints may return a 202 Accepted status code, meaning that the 238 information required is not yet ready and was scheduled to be gathered on 239 the GitHub side. Methods known to behave like this are documented specifying 240 this behavior. 241 242 To detect this condition of error, you can check if its type is 243 `*github.AcceptedError`: 244 245 ```go 246 stats, _, err := client.Repositories.ListContributorsStats(ctx, org, repo) 247 if _, ok := err.(*github.AcceptedError); ok { 248 log.Println("scheduled on GitHub side") 249 } 250 ``` 251 252 ### Conditional Requests ### 253 254 The GitHub API has good support for conditional requests which will help 255 prevent you from burning through your rate limit, as well as help speed up your 256 application. `go-github` does not handle conditional requests directly, but is 257 instead designed to work with a caching `http.Transport`. We recommend using 258 [gregjones/httpcache](https://github.com/gregjones/httpcache) for that. For example: 259 260 ```go 261 import "github.com/gregjones/httpcache" 262 263 client := github.NewClient( 264 httpcache.NewMemoryCacheTransport().Client() 265 ).WithAuthToken(os.Getenv("GITHUB_TOKEN")) 266 ``` 267 268 Learn more about GitHub conditional requests in 269 ["Use conditional requests if appropriate"](https://docs.github.com/en/rest/using-the-rest-api/best-practices-for-using-the-rest-api?apiVersion=2022-11-28#use-conditional-requests-if-appropriate). 270 271 ### Creating and Updating Resources ### 272 273 All structs for GitHub resources use pointer values for all non-repeated fields. 274 This allows distinguishing between unset fields and those set to a zero-value. 275 Helper functions have been provided to easily create these pointers for string, 276 bool, and int values. For example: 277 278 ```go 279 // create a new private repository named "foo" 280 repo := &github.Repository{ 281 Name: github.String("foo"), 282 Private: github.Bool(true), 283 } 284 client.Repositories.Create(ctx, "", repo) 285 ``` 286 287 Users who have worked with protocol buffers should find this pattern familiar. 288 289 ### Pagination ### 290 291 All requests for resource collections (repos, pull requests, issues, etc.) 292 support pagination. Pagination options are described in the 293 `github.ListOptions` struct and passed to the list methods directly or as an 294 embedded type of a more specific list options struct (for example 295 `github.PullRequestListOptions`). Pages information is available via the 296 `github.Response` struct. 297 298 ```go 299 client := github.NewClient(nil) 300 301 opt := &github.RepositoryListByOrgOptions{ 302 ListOptions: github.ListOptions{PerPage: 10}, 303 } 304 // get all pages of results 305 var allRepos []*github.Repository 306 for { 307 repos, resp, err := client.Repositories.ListByOrg(ctx, "github", opt) 308 if err != nil { 309 return err 310 } 311 allRepos = append(allRepos, repos...) 312 if resp.NextPage == 0 { 313 break 314 } 315 opt.Page = resp.NextPage 316 } 317 ``` 318 319 #### Iterators (**experimental**) #### 320 321 Go v1.23 introduces the new `iter` package. 322 323 With the `enrichman/gh-iter` package, it is possible to create iterators for `go-github`. The iterator will handle pagination for you, looping through all the available results. 324 325 ```go 326 client := github.NewClient(nil) 327 var allRepos []*github.Repository 328 329 // create an iterator and start looping through all the results 330 repos := ghiter.NewFromFn1(client.Repositories.ListByOrg, "github") 331 for repo := range repos.All() { 332 allRepos = append(allRepos, repo) 333 } 334 ``` 335 336 For complete usage of `enrichman/gh-iter`, see the full [package docs](https://github.com/enrichman/gh-iter). 337 338 ### Webhooks ### 339 340 `go-github` provides structs for almost all [GitHub webhook events][] as well as functions to validate them and unmarshal JSON payloads from `http.Request` structs. 341 342 ```go 343 func (s *GitHubEventMonitor) ServeHTTP(w http.ResponseWriter, r *http.Request) { 344 payload, err := github.ValidatePayload(r, s.webhookSecretKey) 345 if err != nil { ... } 346 event, err := github.ParseWebHook(github.WebHookType(r), payload) 347 if err != nil { ... } 348 switch event := event.(type) { 349 case *github.CommitCommentEvent: 350 processCommitCommentEvent(event) 351 case *github.CreateEvent: 352 processCreateEvent(event) 353 ... 354 } 355 } 356 ``` 357 358 Furthermore, there are libraries like [cbrgm/githubevents][] that build upon the example above and provide functions to subscribe callbacks to specific events. 359 360 For complete usage of go-github, see the full [package docs][]. 361 362 [GitHub API v3]: https://docs.github.com/en/rest 363 [personal access token]: https://github.com/blog/1509-personal-api-tokens 364 [package docs]: https://pkg.go.dev/github.com/google/go-github/v66/github 365 [GraphQL API v4]: https://developer.github.com/v4/ 366 [shurcooL/githubv4]: https://github.com/shurcooL/githubv4 367 [GitHub webhook events]: https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads 368 [cbrgm/githubevents]: https://github.com/cbrgm/githubevents 369 370 ### Testing code that uses `go-github` ### 371 372 The repo [migueleliasweb/go-github-mock](https://github.com/migueleliasweb/go-github-mock) provides a way to mock responses. Check the repo for more details. 373 374 ### Integration Tests ### 375 376 You can run integration tests from the `test` directory. See the integration tests [README](test/README.md). 377 378 ## Contributing ## 379 380 I would like to cover the entire GitHub API and contributions are of course always welcome. The 381 calling pattern is pretty well established, so adding new methods is relatively 382 straightforward. See [`CONTRIBUTING.md`](CONTRIBUTING.md) for details. 383 384 ## Versioning ## 385 386 In general, go-github follows [semver](https://semver.org/) as closely as we 387 can for tagging releases of the package. For self-contained libraries, the 388 application of semantic versioning is relatively straightforward and generally 389 understood. But because go-github is a client library for the GitHub API, which 390 itself changes behavior, and because we are typically pretty aggressive about 391 implementing preview features of the GitHub API, we've adopted the following 392 versioning policy: 393 394 * We increment the **major version** with any incompatible change to 395 non-preview functionality, including changes to the exported Go API surface 396 or behavior of the API. 397 * We increment the **minor version** with any backwards-compatible changes to 398 functionality, as well as any changes to preview functionality in the GitHub 399 API. GitHub makes no guarantee about the stability of preview functionality, 400 so neither do we consider it a stable part of the go-github API. 401 * We increment the **patch version** with any backwards-compatible bug fixes. 402 403 Preview functionality may take the form of entire methods or simply additional 404 data returned from an otherwise non-preview method. Refer to the GitHub API 405 documentation for details on preview functionality. 406 407 ### Calendar Versioning ### 408 409 As of 2022-11-28, GitHub [has announced](https://github.blog/2022-11-28-to-infinity-and-beyond-enabling-the-future-of-githubs-rest-api-with-api-versioning/) 410 that they are starting to version their v3 API based on "calendar-versioning". 411 412 In practice, our goal is to make per-method version overrides (at 413 least in the core library) rare and temporary. 414 415 Our understanding of the GitHub docs is that they will be revving the 416 entire API to each new date-based version, even if only a few methods 417 have breaking changes. Other methods will accept the new version with 418 their existing functionality. So when a new date-based version of the 419 GitHub API is released, we (the repo maintainers) plan to: 420 421 * update each method that had breaking changes, overriding their 422 per-method API version header. This may happen in one or multiple 423 commits and PRs, and is all done in the main branch. 424 425 * once all of the methods with breaking changes have been updated, 426 have a final commit that bumps the default API version, and remove 427 all of the per-method overrides. That would now get a major version 428 bump when the next go-github release is made. 429 430 ### Version Compatibility Table ### 431 432 The following table identifies which version of the GitHub API is 433 supported by this (and past) versions of this repo (go-github). 434 Versions prior to 48.2.0 are not listed. 435 436 | go-github Version | GitHub v3 API Version | 437 | ----------------- | --------------------- | 438 | 66.0.0 | 2022-11-28 | 439 | 65.0.0 | 2022-11-28 | 440 | 64.0.0 | 2022-11-28 | 441 | 63.0.0 | 2022-11-28 | 442 | 62.0.0 | 2022-11-28 | 443 | 61.0.0 | 2022-11-28 | 444 | 60.0.0 | 2022-11-28 | 445 | 59.0.0 | 2022-11-28 | 446 | 58.0.0 | 2022-11-28 | 447 | 57.0.0 | 2022-11-28 | 448 | 56.0.0 | 2022-11-28 | 449 | 55.0.0 | 2022-11-28 | 450 | 54.0.0 | 2022-11-28 | 451 | 53.2.0 | 2022-11-28 | 452 | 53.1.0 | 2022-11-28 | 453 | 53.0.0 | 2022-11-28 | 454 | 52.0.0 | 2022-11-28 | 455 | 51.0.0 | 2022-11-28 | 456 | 50.2.0 | 2022-11-28 | 457 | 50.1.0 | 2022-11-28 | 458 | 50.0.0 | 2022-11-28 | 459 | 49.1.0 | 2022-11-28 | 460 | 49.0.0 | 2022-11-28 | 461 | 48.2.0 | 2022-11-28 | 462 463 ## License ## 464 465 This library is distributed under the BSD-style license found in the [LICENSE](./LICENSE) 466 file.