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