Documentation
¶
Overview ¶
Package github provides an HTTP client for the GitHub API.
Overview ¶
This package fetches repository metrics from GitHub (https://api.github.com) for metadata enrichment. It provides data used by Nebraska ranking and brittle detection features.
Usage ¶
client, err := github.NewClient(token, 24 * time.Hour)
if err != nil {
log.Fatal(err)
}
metrics, err := client.Fetch(ctx, "pallets", "flask", false)
if err != nil {
log.Fatal(err)
}
fmt.Println("Stars:", metrics.Stars)
fmt.Println("Contributors:", metrics.Contributors)
Authentication ¶
A GitHub personal access token is optional but recommended to avoid rate limits. Without a token, the client is limited to 60 requests/hour. With a token, the limit is 5000 requests/hour.
RepoMetrics ¶
[Fetch] returns an integrations.RepoMetrics containing:
- Stars: Stargazer count
- Owner: Repository owner login
- Contributors: Top 5 contributors with commit counts
- LastCommitAt: Most recent push date
- LastReleaseAt: Most recent release date
- Archived: Whether the repository is archived
- License, Language, Topics: Additional metadata
Caching ¶
Responses are cached to reduce API calls. The cache TTL is set when creating the client. Pass refresh=true to bypass the cache.
URL Extraction ¶
ExtractURL parses GitHub repository URLs from package metadata, handling various URL formats (with/without .git, trailing slashes, etc.).
Package Search ¶
[SearchPackageRepo] searches GitHub code for manifest files containing a package name, useful for finding repository URLs when not provided by the package registry.
Index ¶
- Constants
- func DetectLanguageFromManifest(path string) string
- func ExtractURL(urls map[string]string, homepage string) (owner, repo string, ok bool)
- func ParseRepoRef(ref string) (owner, repo string, err error)
- func ValidateOwner(owner string) error
- func ValidateRepo(repo string) error
- func ValidateRepoRef(owner, repo string) error
- type Client
- type CodeSearchResult
- type ContentClient
- func (c *ContentClient) DetectManifests(ctx context.Context, owner, repo string, patterns map[string]string) ([]ManifestFile, error)
- func (c *ContentClient) FetchFile(ctx context.Context, owner, repo, path string) (*FileContent, error)
- func (c *ContentClient) FetchFileRaw(ctx context.Context, owner, repo, path string) (string, error)
- func (c *ContentClient) FetchUser(ctx context.Context) (*User, error)
- func (c *ContentClient) FetchUserRepos(ctx context.Context) ([]Repo, error)
- func (c *ContentClient) GetRepoInfo(ctx context.Context, owner, repo string) (*RepoInfo, error)
- func (c *ContentClient) GetTree(ctx context.Context, owner, repo, branch string) ([]TreeEntry, error)
- func (c *ContentClient) ListContents(ctx context.Context, owner, repo, path string) ([]ContentItem, error)
- func (c *ContentClient) ScanReposForManifests(ctx context.Context, manifestPatterns map[string]string, publicOnly bool) ([]RepoWithManifests, error)
- func (c *ContentClient) SearchCode(ctx context.Context, owner, repo, query string) ([]CodeSearchResult, error)
- type ContentItem
- type DeviceCodeResponse
- type FileContent
- type ManifestFile
- type OAuthClient
- func (c *OAuthClient) AuthorizationURL(state string) string
- func (c *OAuthClient) ExchangeCode(code string) (*OAuthToken, error)
- func (c *OAuthClient) PollForToken(ctx context.Context, deviceCode string, interval int) (*OAuthToken, error)
- func (c *OAuthClient) RequestDeviceCode(ctx context.Context) (*DeviceCodeResponse, error)
- type OAuthConfig
- type OAuthToken
- type Repo
- type RepoInfo
- type RepoWithManifests
- type TreeEntry
- type User
Constants ¶
const DefaultClientID = "Ov23liyPM58WU6hMeP7E"
DefaultClientID is the OAuth App Client ID for Stacktower. This is public and safe to commit - only the Client Secret must be kept private. The Device Flow doesn't require a secret, only the Client ID.
To use your own OAuth App, set GITHUB_CLIENT_ID env var.
Variables ¶
This section is empty.
Functions ¶
func DetectLanguageFromManifest ¶ added in v1.0.0
DetectLanguageFromManifest determines the language from a manifest filename.
func ExtractURL ¶
ExtractURL extracts GitHub repository owner and name from package URLs.
This function searches through urls map and homepage for GitHub URLs. It looks for patterns like "https://github.com/owner/repo".
Parameters:
- urls: Map of URL keys to URL values from package metadata (may be nil)
- homepage: Fallback homepage URL (may be empty)
Returns:
- owner: Repository owner username (empty if not found)
- repo: Repository name (empty if not found)
- ok: true if a GitHub URL was found, false otherwise
This function is safe for concurrent use.
func ParseRepoRef ¶ added in v1.0.0
ParseRepoRef parses an "owner/repo" string and validates both parts. Returns owner, repo, and any validation error.
func ValidateOwner ¶ added in v1.0.0
ValidateOwner validates a GitHub username or organization name.
func ValidateRepo ¶ added in v1.0.0
ValidateRepo validates a GitHub repository name.
func ValidateRepoRef ¶ added in v1.0.0
ValidateRepoRef validates both owner and repo parameters.
Types ¶
type Client ¶
type Client struct {
*integrations.Client
// contains filtered or unexported fields
}
Client provides access to the GitHub API for repository metadata enrichment. It handles HTTP requests with caching, automatic retries, and optional authentication.
All methods are safe for concurrent use by multiple goroutines.
func NewClient ¶
NewClient creates a GitHub API client with optional authentication.
Parameters:
- backend: Cache backend for HTTP response caching (use storage.NullBackend{} for no caching)
- token: GitHub personal access token (empty string for unauthenticated)
- cacheTTL: How long responses are cached (typical: 1-24 hours)
Rate limits:
- Unauthenticated: 60 requests/hour per IP
- Authenticated: 5,000 requests/hour per token
Authentication is strongly recommended for production use to avoid rate limiting. The returned Client is safe for concurrent use.
func (*Client) Fetch ¶
func (c *Client) Fetch(ctx context.Context, owner, repo string, refresh bool) (*integrations.RepoMetrics, error)
Fetch retrieves repository metrics (stars, maintainers, activity) from GitHub.
Parameters:
- owner: Repository owner username (e.g., "pallets")
- repo: Repository name (e.g., "flask")
- refresh: If true, bypass cache and fetch fresh data
The method performs up to 3 API calls:
- Repository metadata (required)
- Latest release data (optional, silently ignored if no releases)
- Contributors list (optional, top 5, silently ignored on failure)
If refresh is true, the cache is bypassed and a fresh API call is made. If refresh is false, cached data is returned if available and not expired.
Returns:
- RepoMetrics populated with repository data on success
- integrations.ErrNotFound if the repository doesn't exist
- integrations.ErrNetwork for HTTP failures (timeout, 5xx, rate limits, etc.)
- Other errors for JSON decoding failures
The returned RepoMetrics pointer is never nil if err is nil. This method is safe for concurrent use.
func (*Client) SearchPackageRepo ¶
func (c *Client) SearchPackageRepo(ctx context.Context, pkgName, manifestFile string) (owner, repo string, ok bool)
SearchPackageRepo searches GitHub code for a manifest file containing a package name.
This is useful for finding repository URLs when package metadata doesn't include them.
Parameters:
- pkgName: Package name to search for (exact match in manifest file)
- manifestFile: Manifest filename to search in (e.g., "package.json", "Gemfile")
Example:
owner, repo, ok := client.SearchPackageRepo(ctx, "fastapi", "pyproject.toml")
Returns:
- owner: Repository owner username (empty if not found)
- repo: Repository name (empty if not found)
- ok: true if a match was found, false otherwise
Search results are always cached (refresh=false) to conserve GitHub API quota. This method is safe for concurrent use.
type CodeSearchResult ¶ added in v1.0.0
type CodeSearchResult struct {
Name string `json:"name"`
Path string `json:"path"`
Matches []string `json:"matches,omitempty"`
}
CodeSearchResult represents a code search match.
type ContentClient ¶ added in v1.0.0
type ContentClient struct {
// contains filtered or unexported fields
}
ContentClient provides access to GitHub repository content. Use this for fetching files, listing directories, and user operations.
func NewContentClient ¶ added in v1.0.0
func NewContentClient(token string) *ContentClient
NewContentClient creates a new content client with the given access token.
func (*ContentClient) DetectManifests ¶ added in v1.0.0
func (c *ContentClient) DetectManifests(ctx context.Context, owner, repo string, patterns map[string]string) ([]ManifestFile, error)
DetectManifests finds manifest files in a repository's root directory. The patterns map filename -> language name (e.g., "go.mod" -> "go"). Use deps.SupportedManifests(languages) to get patterns from the deps package.
func (*ContentClient) FetchFile ¶ added in v1.0.0
func (c *ContentClient) FetchFile(ctx context.Context, owner, repo, path string) (*FileContent, error)
FetchFile retrieves the content of a file from a repository. The content is returned as a string (decoded from base64).
func (*ContentClient) FetchFileRaw ¶ added in v1.0.0
FetchFileRaw retrieves the raw content of a file from a repository. This is more efficient for large files as it doesn't use base64 encoding.
func (*ContentClient) FetchUser ¶ added in v1.0.0
func (c *ContentClient) FetchUser(ctx context.Context) (*User, error)
FetchUser retrieves the authenticated user's info.
func (*ContentClient) FetchUserRepos ¶ added in v1.0.0
func (c *ContentClient) FetchUserRepos(ctx context.Context) ([]Repo, error)
FetchUserRepos retrieves all of the authenticated user's repositories. This includes private repos if the OAuth token has the 'repo' scope. Results are paginated automatically to retrieve all repos.
func (*ContentClient) GetRepoInfo ¶ added in v1.0.0
GetRepoInfo retrieves repository metadata.
func (*ContentClient) GetTree ¶ added in v1.0.0
func (c *ContentClient) GetTree(ctx context.Context, owner, repo, branch string) ([]TreeEntry, error)
GetTree retrieves the full file tree of a repository.
func (*ContentClient) ListContents ¶ added in v1.0.0
func (c *ContentClient) ListContents(ctx context.Context, owner, repo, path string) ([]ContentItem, error)
ListContents lists files and directories in a repository path.
func (*ContentClient) ScanReposForManifests ¶ added in v1.0.0
func (c *ContentClient) ScanReposForManifests(ctx context.Context, manifestPatterns map[string]string, publicOnly bool) ([]RepoWithManifests, error)
ScanReposForManifests fetches repos and detects manifests in parallel. It returns repos sorted by UpdatedAt (most recent first). The manifestPatterns map should be filename -> language (use deps.SupportedManifests). Set publicOnly=true to filter out private repos.
func (*ContentClient) SearchCode ¶ added in v1.0.0
func (c *ContentClient) SearchCode(ctx context.Context, owner, repo, query string) ([]CodeSearchResult, error)
SearchCode searches for code in a repository. Query follows GitHub code search syntax: https://docs.github.com/en/search-github/searching-on-github/searching-code
type ContentItem ¶ added in v1.0.0
type ContentItem struct {
Name string `json:"name"`
Path string `json:"path"`
Type string `json:"type"` // "file" or "dir"
Size int `json:"size"`
}
ContentItem represents an item in a repository directory listing.
type DeviceCodeResponse ¶ added in v1.0.0
type DeviceCodeResponse struct {
DeviceCode string `json:"device_code"`
UserCode string `json:"user_code"`
VerificationURI string `json:"verification_uri"`
ExpiresIn int `json:"expires_in"`
Interval int `json:"interval"`
}
DeviceCodeResponse contains the response from requesting a device code.
type FileContent ¶ added in v1.0.0
type FileContent struct {
Path string `json:"path"`
Size int `json:"size"`
Content string `json:"content"`
}
FileContent represents the content of a file.
type ManifestFile ¶ added in v1.0.0
type ManifestFile struct {
Path string `json:"path"`
Language string `json:"language"`
Name string `json:"name"`
}
ManifestFile represents a detected manifest file.
type OAuthClient ¶ added in v1.0.0
type OAuthClient struct {
// contains filtered or unexported fields
}
OAuthClient handles GitHub OAuth operations.
func NewOAuthClient ¶ added in v1.0.0
func NewOAuthClient(config OAuthConfig) *OAuthClient
NewOAuthClient creates a new OAuth client.
func (*OAuthClient) AuthorizationURL ¶ added in v1.0.0
func (c *OAuthClient) AuthorizationURL(state string) string
AuthorizationURL returns the GitHub OAuth authorization URL.
func (*OAuthClient) ExchangeCode ¶ added in v1.0.0
func (c *OAuthClient) ExchangeCode(code string) (*OAuthToken, error)
ExchangeCode exchanges an authorization code for an access token.
func (*OAuthClient) PollForToken ¶ added in v1.0.0
func (c *OAuthClient) PollForToken(ctx context.Context, deviceCode string, interval int) (*OAuthToken, error)
PollForToken polls GitHub for the access token after user authorization. It respects the interval from the device code response. Returns the token when authorized, or an error if expired/denied.
func (*OAuthClient) RequestDeviceCode ¶ added in v1.0.0
func (c *OAuthClient) RequestDeviceCode(ctx context.Context) (*DeviceCodeResponse, error)
RequestDeviceCode initiates the device authorization flow. The user must visit the VerificationURI and enter the UserCode.
type OAuthConfig ¶ added in v1.0.0
OAuthConfig holds OAuth configuration.
type OAuthToken ¶ added in v1.0.0
type OAuthToken struct {
AccessToken string `json:"access_token"`
TokenType string `json:"token_type"`
Scope string `json:"scope"`
}
OAuthToken represents an OAuth access token response.
type Repo ¶ added in v1.0.0
type Repo struct {
ID int64 `json:"id"`
Name string `json:"name"`
FullName string `json:"full_name"`
Description string `json:"description"`
Private bool `json:"private"`
DefaultBranch string `json:"default_branch"`
Language string `json:"language"`
UpdatedAt string `json:"updated_at"`
}
Repo represents a GitHub repository.
type RepoInfo ¶ added in v1.0.0
type RepoInfo struct {
Name string `json:"name"`
FullName string `json:"full_name"`
Description string `json:"description"`
Language string `json:"language"`
DefaultBranch string `json:"default_branch"`
Stars int `json:"stars"`
Forks int `json:"forks"`
OpenIssues int `json:"open_issues"`
License string `json:"license"`
Topics []string `json:"topics"`
Archived bool `json:"archived"`
}
RepoInfo contains repository metadata.
type RepoWithManifests ¶ added in v1.0.0
type RepoWithManifests struct {
Repo Repo `json:"repo"`
Manifests []ManifestFile `json:"manifests,omitempty"`
}
RepoWithManifests holds a repo and its detected manifest files.