GitHub
- provider
- createProvider("github")
- auth header
- Authorization: token
- env vars
- GH_TOKEN, GITHUB_TOKEN
- anonymous reads
- 60 requests an hour per address
Address it
import { createProvider } from "@agntn/forges";
const github = createProvider("github"); // GH_TOKEN, GITHUB_TOKEN, then gh auth token
const enterprise = createProvider("github", { baseURL: "https://github.example.com/api/v3" });
baseURL is taken as given, so spell out /api/v3 for Enterprise. The token chain asks gh for the host in baseURL, not for github.com.
What it reads
| Resource | Endpoint |
|---|---|
| repos | GET /repos/:owner/:repo, GET /users/:owner/repos |
| issues | GET /repos/:owner/:repo/issues, GET /search/issues, POST /repos/:owner/:repo/issues |
| pull requests | GET /repos/:owner/:repo/pulls, …/pulls/:number/files, …/commits/:sha/check-runs |
| commits | GET /repos/:owner/:repo/commits, …/commits/:sha |
| CI runs | GET /repos/:owner/:repo/actions/runs |
| threads | GraphQL reviewThreads, REST POST …/pulls/:number/comments/:id/replies |
| templates | GET /repos/:owner/:repo/contents/.github/…, then :owner/.github |
| code | GET /search/code |
Pagination reads the Link header. nextPage is the page of its rel="next".
What comes back
Repository.parent from parent, viewerPermission from permissions when the token has any. Issue from /issues with pull requests filtered out by the missing pull_request key. PullRequest.mergeable is null while GitHub is still computing it, which it does lazily, so the first read after a push often says null. Commit.filesComplete is true when GitHub confirms a complete file list, collected up to its cap of 3 000 files.
Templates: repository files first, then the owner's .github repository with scope: "owner" and inherited: true. Issue and pull request overrides resolve on their own. A host without the x-github-enterprise-version header that is not github.com is treated as repository scope only.
Gotchas
- Review threads need a token. GraphQL has no anonymous access and REST has no resolved flag, so there is no anonymous thread list to be had.
- Anonymous reads share sixty requests an hour per address. A 403 with a rate limit header is a
RateLimitErrorwithretryAfter, not aPermissionError. /issuesreturns pull requests too. Filtered out here. Search returns both, andpullRequests.searchkeeps the ones withpull_request.- Code search:
incompletegoes true on a search timeout, when scope enforcement drops a stray row, or past the cap of 1 000 results. - Issue search keeps GitHub's qualifier syntax.
label:bug is:openworks here and is plain text on GitLab and Gitea.
Where it lives
src/providers/github.ts. Also the template for a new provider. Copy it, do not start from scratch.