Provisioning: Implement connection repositories endpoint for GitHub
This change implements the `/repositories` subresource endpoint for Connection resources, enabling listing of repositories accessible through a GitHub App connection. Changes: - Add ListRepositories method to Connection interface - Add ListInstallationRepositories to GitHub Client interface - Implement GitHub client method to list installation repositories - Creates installation access token from JWT - Handles pagination up to 1000 repos - Implement ListRepositories in GitHub Connection - Update connectionRepositoriesConnector to use Connection.ListRepositories - Add ConnectionGetter interface and GetConnection method to APIBuilder - Add comprehensive tests for the new functionality
This commit is contained in:
@@ -22,6 +22,19 @@ type Client interface {
|
||||
// Apps and installations
|
||||
GetApp(ctx context.Context) (App, error)
|
||||
GetAppInstallation(ctx context.Context, installationID string) (AppInstallation, error)
|
||||
|
||||
// Repositories
|
||||
ListInstallationRepositories(ctx context.Context, installationID string) ([]Repository, error)
|
||||
}
|
||||
|
||||
// Repository represents a GitHub repository accessible through an installation.
|
||||
type Repository struct {
|
||||
// Name of the repository
|
||||
Name string
|
||||
// Owner is the user or organization that owns the repository
|
||||
Owner string
|
||||
// URL of the repository (HTML URL)
|
||||
URL string
|
||||
}
|
||||
|
||||
// App represents a Github App.
|
||||
@@ -91,3 +104,68 @@ func (r *githubClient) GetAppInstallation(ctx context.Context, installationID st
|
||||
Enabled: installation.GetSuspendedAt().IsZero(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
const (
|
||||
maxRepositories = 1000 // Maximum number of repositories to fetch
|
||||
)
|
||||
|
||||
// ListInstallationRepositories lists all repositories accessible by the specified GitHub App installation.
|
||||
// It first creates an installation access token using the JWT, then uses that token to list repositories.
|
||||
func (r *githubClient) ListInstallationRepositories(ctx context.Context, installationID string) ([]Repository, error) {
|
||||
id, err := strconv.ParseInt(installationID, 10, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid installation ID: %s", installationID)
|
||||
}
|
||||
|
||||
// Create an installation access token
|
||||
installationToken, _, err := r.gh.Apps.CreateInstallationToken(ctx, id, nil)
|
||||
if err != nil {
|
||||
var ghErr *github.ErrorResponse
|
||||
if errors.As(err, &ghErr) && ghErr.Response.StatusCode == http.StatusServiceUnavailable {
|
||||
return nil, ErrServiceUnavailable
|
||||
}
|
||||
return nil, fmt.Errorf("create installation token: %w", err)
|
||||
}
|
||||
|
||||
// Create a new client with the installation token
|
||||
tokenClient := github.NewClient(nil).WithAuthToken(installationToken.GetToken())
|
||||
|
||||
var allRepos []Repository
|
||||
opts := &github.ListOptions{
|
||||
Page: 1,
|
||||
PerPage: 100,
|
||||
}
|
||||
|
||||
for {
|
||||
result, resp, err := tokenClient.Apps.ListRepos(ctx, opts)
|
||||
if err != nil {
|
||||
var ghErr *github.ErrorResponse
|
||||
if errors.As(err, &ghErr) && ghErr.Response.StatusCode == http.StatusServiceUnavailable {
|
||||
return nil, ErrServiceUnavailable
|
||||
}
|
||||
return nil, fmt.Errorf("list repositories: %w", err)
|
||||
}
|
||||
|
||||
for _, repo := range result.Repositories {
|
||||
allRepos = append(allRepos, Repository{
|
||||
Name: repo.GetName(),
|
||||
Owner: repo.GetOwner().GetLogin(),
|
||||
URL: repo.GetHTMLURL(),
|
||||
})
|
||||
}
|
||||
|
||||
// Check if we've exceeded the maximum allowed repositories
|
||||
if len(allRepos) > maxRepositories {
|
||||
return nil, fmt.Errorf("too many repositories to fetch (more than %d)", maxRepositories)
|
||||
}
|
||||
|
||||
// If there are no more pages, break
|
||||
if resp.NextPage == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
opts.Page = resp.NextPage
|
||||
}
|
||||
|
||||
return allRepos, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user