github.com/google/go-github/v74@v74.0.0/README.md (about)

     1  # go-github #
     2  
     3  [![go-github release (latest SemVer)](https://img.shields.io/github/v/release/google/go-github?sort=semver)](https://github.com/google/go-github/releases)
     4  [![Go Reference](https://img.shields.io/static/v1?label=godoc&message=reference&color=blue)](https://pkg.go.dev/github.com/google/go-github/v74/github)
     5  [![Test Status](https://github.com/google/go-github/actions/workflows/tests.yml/badge.svg?branch=master)](https://github.com/google/go-github/actions/workflows/tests.yml)
     6  [![Test Coverage](https://codecov.io/gh/google/go-github/branch/master/graph/badge.svg)](https://codecov.io/gh/google/go-github)
     7  [![Discuss at go-github@googlegroups.com](https://img.shields.io/badge/discuss-go--github%40googlegroups.com-blue.svg)](https://groups.google.com/group/go-github)
     8  [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/796/badge)](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.23 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/v74
    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/v74/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/v74@master
    50  ```
    51  
    52  ## Usage ##
    53  
    54  ```go
    55  import "github.com/google/go-github/v74/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 cancellation 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/v74/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/v74/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 rate limits on all API clients. The [primary rate limit](https://docs.github.com/en/rest/using-the-rest-api/rate-limits-for-the-rest-api#about-primary-rate-limits)
   193  is the limit to the number of REST API requests that a client can make within a
   194  specific amount of time. This limit helps prevent abuse and denial-of-service
   195  attacks, and ensures that the API remains available for all users. Some
   196  endpoints, like the search endpoints, have more restrictive limits.
   197  Unauthenticated clients may request public data but have a low rate limit,
   198  while authenticated clients have rate limits based on the client
   199  identity.
   200  
   201  In addition to primary rate limits, GitHub enforces [secondary rate limits](https://docs.github.com/en/rest/using-the-rest-api/rate-limits-for-the-rest-api#about-secondary-rate-limits)
   202  in order to prevent abuse and keep the API available for all users.
   203  Secondary rate limits generally limit the number of concurrent requests that a
   204  client can make.
   205  
   206  The client returned `Response.Rate` value contains the rate limit information
   207  from the most recent API call. If a recent enough response isn't
   208  available, you can use the client `RateLimits` service to fetch the most
   209  up-to-date rate limit data for the client.
   210  
   211  To detect a primary API rate limit error, you can check if the error is a
   212  `RateLimitError`.
   213  
   214  ```go
   215  repos, _, err := client.Repositories.List(ctx, "", nil)
   216  var rateErr *github.RateLimitError
   217  if errors.As(err, &rateError) {
   218  	log.Printf("hit primary rate limit, used %d of %d\n", rateErr.Rate.Used, rateErr.rate.Limit)
   219  }
   220  ```
   221  
   222  To detect an API secondary rate limit error, you can check if the error is an
   223  `AbuseRateLimitError`.
   224  
   225  ```go
   226  repos, _, err := client.Repositories.List(ctx, "", nil)
   227  var rateErr *github.AbuseRateLimitError
   228  if errors.As(err, &rateErr) {
   229  	log.Printf("hit secondary rate limit, retry after %v\n", rateErr.RetryAfter)
   230  }
   231  ```
   232  
   233  If you hit the primary rate limit, you can use the `SleepUntilPrimaryRateLimitResetWhenRateLimited`
   234  method to block until the rate limit is reset.
   235  
   236  ```go
   237  repos, _, err := client.Repositories.List(context.WithValue(ctx, github.SleepUntilPrimaryRateLimitResetWhenRateLimited, true), "", nil)
   238  ```
   239  
   240  If you need to make a request even if the rate limit has been hit you can use
   241  the `BypassRateLimitCheck` method to bypass the rate limit check and make the
   242  request anyway.
   243  
   244  ```go
   245  repos, _, err := client.Repositories.List(context.WithValue(ctx, github.BypassRateLimitCheck, true), "", nil)
   246  ```
   247  
   248  For more advanced use cases, you can use [gofri/go-github-ratelimit](https://github.com/gofri/go-github-ratelimit)
   249  which provides a middleware (`http.RoundTripper`) that handles both the primary
   250  rate limit and secondary rate limit for the GitHub API. In this case you can
   251  set the client `DisableRateLimitCheck` to `true` so the client doesn't track the rate limit usage.
   252  
   253  If the client is an [OAuth app](https://docs.github.com/en/rest/using-the-rest-api/rate-limits-for-the-rest-api#primary-rate-limit-for-oauth-apps)
   254  you can use the apps higher rate limit to request public data by using the
   255  `UnauthenticatedRateLimitedTransport` to make calls as the app instead of as
   256  the user.
   257  
   258  ### Accepted Status ###
   259  
   260  Some endpoints may return a 202 Accepted status code, meaning that the
   261  information required is not yet ready and was scheduled to be gathered on
   262  the GitHub side. Methods known to behave like this are documented specifying
   263  this behavior.
   264  
   265  To detect this condition of error, you can check if its type is
   266  `*github.AcceptedError`:
   267  
   268  ```go
   269  stats, _, err := client.Repositories.ListContributorsStats(ctx, org, repo)
   270  if _, ok := err.(*github.AcceptedError); ok {
   271  	log.Println("scheduled on GitHub side")
   272  }
   273  ```
   274  
   275  ### Conditional Requests ###
   276  
   277  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)
   278  via the `ETag` header which will help prevent you from burning through your
   279  rate limit, as well as help speed up your application. `go-github` does not
   280  handle conditional requests directly, but is instead designed to work with a
   281  caching `http.Transport`.
   282  
   283  Typically, an [RFC 9111](https://datatracker.ietf.org/doc/html/rfc9111)
   284  compliant HTTP cache such as [bartventer/httpcache](https://github.com/bartventer/httpcache)
   285  is recommended, ex:
   286  
   287  ```go
   288  import (
   289  	"github.com/bartventer/httpcache"
   290  	_ "github.com/bartventer/httpcache/store/memcache" //  Register the in-memory backend
   291  )
   292  
   293  client := github.NewClient(
   294  	httpcache.NewClient("memcache://"),
   295  ).WithAuthToken(os.Getenv("GITHUB_TOKEN"))
   296  ```
   297  
   298  Alternatively, the [bored-engineer/github-conditional-http-transport](https://github.com/bored-engineer/github-conditional-http-transport)
   299  package relies on (undocumented) GitHub specific cache logic and is
   300  recommended when making requests using short-lived credentials such as a 
   301  [GitHub App installation token](https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/authenticating-as-a-github-app-installation).
   302  
   303  ### Creating and Updating Resources ###
   304  
   305  All structs for GitHub resources use pointer values for all non-repeated fields.
   306  This allows distinguishing between unset fields and those set to a zero-value.
   307  Helper functions have been provided to easily create these pointers for string,
   308  bool, and int values. For example:
   309  
   310  ```go
   311  // create a new private repository named "foo"
   312  repo := &github.Repository{
   313  	Name:    github.Ptr("foo"),
   314  	Private: github.Ptr(true),
   315  }
   316  client.Repositories.Create(ctx, "", repo)
   317  ```
   318  
   319  Users who have worked with protocol buffers should find this pattern familiar.
   320  
   321  ### Pagination ###
   322  
   323  All requests for resource collections (repos, pull requests, issues, etc.)
   324  support pagination. Pagination options are described in the
   325  `github.ListOptions` struct and passed to the list methods directly or as an
   326  embedded type of a more specific list options struct (for example
   327  `github.PullRequestListOptions`). Pages information is available via the
   328  `github.Response` struct.
   329  
   330  ```go
   331  client := github.NewClient(nil)
   332  
   333  opt := &github.RepositoryListByOrgOptions{
   334  	ListOptions: github.ListOptions{PerPage: 10},
   335  }
   336  // get all pages of results
   337  var allRepos []*github.Repository
   338  for {
   339  	repos, resp, err := client.Repositories.ListByOrg(ctx, "github", opt)
   340  	if err != nil {
   341  		return err
   342  	}
   343  	allRepos = append(allRepos, repos...)
   344  	if resp.NextPage == 0 {
   345  		break
   346  	}
   347  	opt.Page = resp.NextPage
   348  }
   349  ```
   350  
   351  #### Iterators (**experimental**) ####
   352  
   353  Go v1.23 introduces the new `iter` package.  
   354  
   355  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.
   356  
   357  ```go
   358  client := github.NewClient(nil)
   359  var allRepos []*github.Repository
   360  
   361  // create an iterator and start looping through all the results
   362  repos := ghiter.NewFromFn1(client.Repositories.ListByOrg, "github")
   363  for repo := range repos.All() {
   364  	allRepos = append(allRepos, repo)
   365  }
   366  ```
   367  
   368  For complete usage of `enrichman/gh-iter`, see the full [package docs](https://github.com/enrichman/gh-iter).
   369  
   370  #### Middleware ####
   371  
   372  You can use [gofri/go-github-pagination](https://github.com/gofri/go-github-pagination) to handle
   373  pagination for you. It supports both sync and async modes, as well as customizations.  
   374  By default, the middleware automatically paginates through all pages, aggregates results, and returns them as an array.  
   375  See `example/ratelimit/main.go` for usage.
   376  
   377  ### Webhooks ###
   378  
   379  `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.
   380  
   381  ```go
   382  func (s *GitHubEventMonitor) ServeHTTP(w http.ResponseWriter, r *http.Request) {
   383  	payload, err := github.ValidatePayload(r, s.webhookSecretKey)
   384  	if err != nil { ... }
   385  	event, err := github.ParseWebHook(github.WebHookType(r), payload)
   386  	if err != nil { ... }
   387  	switch event := event.(type) {
   388  	case *github.CommitCommentEvent:
   389  		processCommitCommentEvent(event)
   390  	case *github.CreateEvent:
   391  		processCreateEvent(event)
   392  	...
   393  	}
   394  }
   395  ```
   396  
   397  Furthermore, there are libraries like [cbrgm/githubevents][] that build upon the example above and provide functions to subscribe callbacks to specific events.
   398  
   399  For complete usage of go-github, see the full [package docs][].
   400  
   401  [GitHub API v3]: https://docs.github.com/en/rest
   402  [personal access token]: https://github.com/blog/1509-personal-api-tokens
   403  [package docs]: https://pkg.go.dev/github.com/google/go-github/v74/github
   404  [GraphQL API v4]: https://developer.github.com/v4/
   405  [shurcooL/githubv4]: https://github.com/shurcooL/githubv4
   406  [GitHub webhook events]: https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads
   407  [cbrgm/githubevents]: https://github.com/cbrgm/githubevents
   408  
   409  ### Testing code that uses `go-github` ###
   410  
   411  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.
   412  
   413  ### Integration Tests ###
   414  
   415  You can run integration tests from the `test` directory. See the integration tests [README](test/README.md).
   416  
   417  ## Contributing ##
   418  
   419  I would like to cover the entire GitHub API and contributions are of course always welcome. The
   420  calling pattern is pretty well established, so adding new methods is relatively
   421  straightforward. See [`CONTRIBUTING.md`](CONTRIBUTING.md) for details.
   422  
   423  ## Versioning ##
   424  
   425  In general, go-github follows [semver](https://semver.org/) as closely as we
   426  can for tagging releases of the package. For self-contained libraries, the
   427  application of semantic versioning is relatively straightforward and generally
   428  understood. But because go-github is a client library for the GitHub API, which
   429  itself changes behavior, and because we are typically pretty aggressive about
   430  implementing preview features of the GitHub API, we've adopted the following
   431  versioning policy:
   432  
   433  * We increment the **major version** with any incompatible change to
   434  	non-preview functionality, including changes to the exported Go API surface
   435  	or behavior of the API.
   436  * We increment the **minor version** with any backwards-compatible changes to
   437  	functionality, as well as any changes to preview functionality in the GitHub
   438  	API. GitHub makes no guarantee about the stability of preview functionality,
   439  	so neither do we consider it a stable part of the go-github API.
   440  * We increment the **patch version** with any backwards-compatible bug fixes.
   441  
   442  Preview functionality may take the form of entire methods or simply additional
   443  data returned from an otherwise non-preview method. Refer to the GitHub API
   444  documentation for details on preview functionality.
   445  
   446  ### Calendar Versioning ###
   447  
   448  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/)
   449  that they are starting to version their v3 API based on "calendar-versioning".
   450  
   451  In practice, our goal is to make per-method version overrides (at
   452  least in the core library) rare and temporary.
   453  
   454  Our understanding of the GitHub docs is that they will be revving the
   455  entire API to each new date-based version, even if only a few methods
   456  have breaking changes. Other methods will accept the new version with
   457  their existing functionality. So when a new date-based version of the
   458  GitHub API is released, we (the repo maintainers) plan to:
   459  
   460  * update each method that had breaking changes, overriding their
   461    per-method API version header. This may happen in one or multiple
   462    commits and PRs, and is all done in the main branch.
   463  
   464  * once all of the methods with breaking changes have been updated,
   465    have a final commit that bumps the default API version, and remove
   466    all of the per-method overrides. That would now get a major version
   467    bump when the next go-github release is made.
   468  
   469  ### Version Compatibility Table ###
   470  
   471  The following table identifies which version of the GitHub API is
   472  supported by this (and past) versions of this repo (go-github).
   473  Versions prior to 48.2.0 are not listed.
   474  
   475  | go-github Version | GitHub v3 API Version |
   476  | ----------------- | --------------------- |
   477  | 74.0.0            | 2022-11-28            |
   478  | ...               | 2022-11-28            |
   479  | 48.2.0            | 2022-11-28            |
   480  
   481  ## License ##
   482  
   483  This library is distributed under the BSD-style license found in the [LICENSE](./LICENSE)
   484  file.