GitHub¶
Package: pkg/vcs/github
Provides the GitHub Enterprise API client (GHClient) and a release.Provider implementation backed by the GitHub Releases API.
Constructor¶
cfg should be a props.Config.Sub("github") subtree. Reads url.api, url.upload, and authentication via vcs.ResolveToken.
Token is optional โ public repositories work without one. Private repositories will receive a 401 from the API if no token is set.
Configuration keys (under the github subtree):
| Key | Default | Description |
|---|---|---|
url.api |
"" |
GitHub Enterprise API base URL. Empty string uses https://api.github.com. |
url.upload |
"" |
GitHub Enterprise upload URL. |
auth.env |
โ | Name of the environment variable holding the token |
auth.value |
โ | Literal token value (use auth.env in preference) |
If neither auth.env nor auth.value is present, NewGitHubClient falls back to the GITHUB_TOKEN environment variable.
Token Helper¶
Returns the resolved token or an error if none is found. Use this where a token is strictly required (e.g. authenticated git operations). For release/update operations on public repos, vcs.ResolveToken directly is sufficient.
GitHubClient Interface¶
All operations are available through the GitHubClient interface. Use the interface type in function signatures for testability:
type GitHubClient interface {
GetClient() *github.Client
// Pull requests
CreatePullRequest(ctx context.Context, owner, repo string, pull *github.NewPullRequest) (*github.PullRequest, error)
GetPullRequestByBranch(ctx context.Context, owner, repo, branch, state string) (*github.PullRequest, error)
AddLabelsToPullRequest(ctx context.Context, owner, repo string, number int, labels []string) error
UpdatePullRequest(ctx context.Context, owner, repo string, number int, pull *github.PullRequest) (*github.PullRequest, *github.Response, error)
// Repository management
CreateRepo(ctx context.Context, owner, slug string) (*github.Repository, error)
UploadKey(ctx context.Context, name string, key []byte) error
GetFileContents(ctx context.Context, owner, repo, path, ref string) (string, error)
// Releases (lower-level โ prefer NewReleaseProvider for release workflows)
ListReleases(ctx context.Context, owner, repo string) ([]string, error)
GetReleaseAssets(ctx context.Context, owner, repo, tag string) ([]*github.ReleaseAsset, error)
GetReleaseAssetID(ctx context.Context, owner, repo, tag, assetName string) (int64, error)
DownloadAsset(ctx context.Context, owner, repo string, assetID int64) (io.ReadCloser, error)
DownloadAssetTo(ctx context.Context, fs afero.Fs, owner, repo string, assetID int64, filePath string) error
}
Sentinel errors:
| Error | Condition |
|---|---|
ErrNoPullRequestFound |
GetPullRequestByBranch finds no matching PR |
ErrRepoExists |
CreateRepo target already exists |
Usage Examples¶
Pull Request Workflow¶
client, err := github.NewGitHubClient(props.Config.Sub("github"))
if err != nil {
return err
}
pr, err := client.CreatePullRequest(ctx, "my-org", "my-repo", &gogithub.NewPullRequest{
Title: gogithub.Ptr("feat: add new command"),
Head: gogithub.Ptr("feature/my-branch"),
Base: gogithub.Ptr("main"),
Body: gogithub.Ptr("Automated PR from my-tool"),
})
if err != nil {
return err
}
_ = client.AddLabelsToPullRequest(ctx, "my-org", "my-repo", pr.GetNumber(), []string{"automated"})
File Contents¶
Asset Download (low-level)¶
assetID, err := client.GetReleaseAssetID(ctx, "my-org", "my-repo", "v1.2.0", "mytool_linux_amd64.tar.gz")
if err != nil {
return err
}
err = client.DownloadAssetTo(ctx, props.FS, "my-org", "my-repo", assetID, "/tmp/mytool.tar.gz")
For release workflows (auto-update, version checking), prefer the higher-level release.Provider โ see below.
Release Provider¶
Wraps a GitHubClient and returns a release.Provider. This is the preferred way to work with releases โ it keeps consuming code (e.g. the auto-update command) decoupled from GitHub specifics.
client, err := github.NewGitHubClient(props.Config.Sub("github"))
if err != nil {
return err
}
provider := github.NewReleaseProvider(client)
latest, err := provider.GetLatestRelease(ctx, "my-org", "my-repo")
fmt.Println(latest.GetTagName())
rc, _, err := provider.DownloadReleaseAsset(ctx, "my-org", "my-repo", latest.GetAssets()[0])
See Release Provider for the full interface reference.
Testing¶
The GitHubClient mock is generated by mockery:
import mock_github "gitlab.com/phpboyscout/go-tool-base/mocks/pkg/vcs/github"
mockClient := mock_github.NewMockGitHubClient(t)
mockClient.EXPECT().
ListReleases(mock.Anything, "my-org", "my-repo").
Return([]string{"v2.0.0", "v1.0.0"}, nil)
For HTTP-level tests, use net/http/httptest to stand up a mock server and pass its URL as url.api in the test config. See pkg/vcs/github/client_coverage_test.go for the established pattern.
Related Documentation¶
- GitLab โ GitLab release provider (same
release.Providerinterface) - Release Provider โ interface reference for
Provider,Release,ReleaseAsset - VCS index โ
ResolveTokenand package overview