go-github

repository·master·Indexed 11 days ago

https://github.com/google/go-github

A type-safe Go client library for interacting with the GitHub REST API v3. It provides tools for managing repositories, issues, and users, with support for OAuth and GitHub App authentication, rate limit handling, and OpenTelemetry instrumentation. Includes the v90 module and an experimental scrape package for accessing data not available via standard APIs.

Tokens
4.1K
Snippets
14
Records
20
Agent score
95%

What's inside go-github

  1. Use the scrape package for experimental GitHub data access

    master

    The scrape package provides an experimental client for accessing GitHub data via screen scraping. It is intended as a 'client of last resort' for data that is not available through the standard GitHub REST or GraphQL APIs.

    Usage Guidelines:

    • Use only for unavailable data: If the data can be retrieved via the REST or GraphQL APIs, use those instead.
    • Prefer read-only access: The package currently focuses on reading data; writing via scraping is considered high-risk.
    • Minimalist approach: The package does not aim for exhaustive coverage of GitHub; it only implements what is necessary for specific use cases.
  2. Understand go-github versioning policy

    master

    go-github follows semantic versioning (semver) with specific rules regarding GitHub API preview features:

    • Major version: Incremented for incompatible changes to non-preview functionality, including changes to the exported Go API surface or changes in the behavior of the underlying GitHub API.
    • Minor version: Incremented for backwards-compatible changes and any changes to GitHub API preview functionality. Note that preview functionality is not considered a stable part of the go-github API.
    • Patch version: Incremented for backwards-compatible bug fixes.

    Preview functionality may appear as entirely new methods or as additional data returned from existing methods.

  3. Create and Update Resources using Pointers

    master

    All structs for GitHub resources use pointer values for non-repeated fields. This allows the API to distinguish between a field being unset and a field being set to its zero-value. Use the provided helper functions (e.g., github.Ptr) to create these pointers.

    // create a new private repository named "foo"
    repo := &github.Repository{
    	Name:    github.Ptr("foo"),
    	Private: github.Ptr(true),
    }
    client.Repositories.Create(ctx, "", repo)
  4. Handle Rate Limiting

    master

    GitHub enforces primary and secondary rate limits. go-github provides several ways to manage these:

    • Detect Primary Rate Limit: Check if the error is of type *github.RateLimitError using errors.As.
    • Detect Secondary Rate Limit: Check if the error is of type *github.AbuseRateLimitError.
    • Wait for Reset: Use context.WithValue(ctx, github.SleepUntilPrimaryRateLimitResetWhenRateLimited, true) to make a request block until the primary rate limit resets.
    • Bypass Check: Use context.WithValue(ctx, github.BypassRateLimitCheck, true) to attempt a request even if the client thinks the rate limit has been hit.

    For advanced management, the gofri/go-github-ratelimit middleware is recommended.

    // Detect primary rate limit
    var rateErr *github.RateLimitError
    if errors.As(err, &rateErr) {
    	log.Printf("hit primary rate limit, used %v of %v\n", rateErr.Rate.Used, rateErr.Rate.Limit)
    }
    
    // Detect secondary rate limit
    var abuseErr *github.AbuseRateLimitError
    if errors.As(err, &abuseErr) {
    	log.Printf("hit secondary rate limit, retry after %v\n", abuseErr.RetryAfter)
    }
    
    // Block until primary rate limit reset
    ctxWithSleep := context.WithValue(ctx, github.SleepUntilPrimaryRateLimitResetWhenRateLimited, true)
    repos, _, err := client.Repositories.List(ctxWithSleep, "", nil)
  5. Understand GitHub API calendar-versioning support

    master

    GitHub's v3 API uses calendar-versioning. The go-github library manages this by:

    1. Updating specific methods that have breaking changes by overriding their per-method API version header.
    2. Once all breaking changes are addressed, the library bumps the default API version and removes per-method overrides (which triggers a major version bump of go-github).

    Always check the Version Compatibility Table in the documentation to ensure your version of go-github supports the required GitHub v3 API version.

  6. Paginate through resource collections

    master

    Resource collections (repos, PRs, etc.) support pagination via github.ListOptions (for page numbers) or github.ListCursorOptions (for string cursors).

    Manual Pagination

    Use the NextPage field in the github.Response struct to iterate through pages.

    Using Iterators (Go 1.23+)

    If using Go 1.23 or later, you can use the auto-generated *Iter methods (e.g., ListIter) to range over results using the new iter package functionality.

    // Manual pagination
    opt := &github.RepositoryListByOrgOptions{
    	ListOptions: github.ListOptions{PerPage: 10},
    }
    for {
    	repos, resp, err := client.Repositories.ListByOrg(ctx, "github", opt)
    	if err != nil {
    		return err
    	}
    	allRepos = append(allRepos, repos...)
    	if resp.NextPage == 0 {
    		break
    	}
    	opt.Page = resp.NextPage
    }
    
    // Go 1.23+ Iterator
    iter := client.Repositories.ListIter(ctx, "github", nil)
    for repo, err := range iter {
    	if err != nil {
    		log.Fatal(err)
    	}
    	allRepos = append(allRepos, repo)
    }
  7. Import go-github in your Go project

    master

    When using the library, import the github subpackage from the v90 module. After adding the import statement, run go get to resolve the dependency and its requirements.

    import "github.com/google/go-github/v90/github"
  8. Basic usage of go-github

    master

    To use go-github, import the package and construct a new client using github.NewClient(). You can then access various GitHub API services through the client. Most methods require a context.Context to handle cancellation and deadlines; if no context is available, use context.Background().

    import "github.com/google/go-github/v90/github"
    
    client, err := github.NewClient()
    if err != nil {
    	// Handle error.
    }
    
    // list all organizations for user "willnorris"
    orgs, _, err := client.Organizations.List(context.Background(), "willnorris", nil)
  9. How to add methods to the scrape package

    master

    To implement new data access methods in the scrape package, follow these steps:

    1. Fetch the page: Use client.get to retrieve the HTML contents of the target page.
    2. Parse the markup: Use the goquery library to traverse and extract data from the HTML.
    3. Select stable elements: When using goquery selectors, prefer semantic ID or class names, as these are more stable than other HTML attributes and less likely to break during GitHub UI updates.

    Refer to apps.go within the package for existing implementation examples.

  10. Install go-github

    master

    To use go-github in your project, install the v90 module using Go's module mode. You can do this by running the go get command or by importing the package in your code and running go get without parameters.

    To use the latest development version (top-of-trunk), use the @master suffix.

    # Install the latest stable v90 release
    go get github.com/google/go-github/v90
    
    # Install the top-of-trunk (master) version
    go get github.com/google/go-github/v90@master
  11. Authenticate as a GitHub App

    master

    GitHub App authentication can be handled in two primary ways:

    1. Using ghinstallation: This package provides a Transport (implementing http.RoundTripper) to authenticate as an installation. Use github.WithTransport(itr) to inject it into the client.
    2. Using go-githubauth: This package provides oauth2.TokenSource implementations. You can create an oauth2.Client and inject it into the github.Client using github.WithHTTPClient(httpClient).

    Note that some endpoints require access token authentication while others require JWT authentication.

    // Example using ghinstallation
    import (
    	"net/http"
    	"github.com/bradleyfalzon/ghinstallation/v2"
    	"github.com/google/go-github/v90/github"
    )
    
    // ...
    // Wrap the shared transport for use with the integration ID 1 authenticating with installation ID 99.
    itr, err := ghinstallation.NewKeyFromFile(http.DefaultTransport, 1, 99, "2016-10-19.private-key.pem")
    if err != nil {
    	// Handle error
    }
    
    client, err := github.NewClient(github.WithTransport(itr))