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