Replace all instances of errors.Wrap() with fmt.Errorf. Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
607 lines
19 KiB
Go
607 lines
19 KiB
Go
// Copyright 2024 Cloudbase Solutions SRL
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
// not use this file except in compliance with the License. You may obtain
|
|
// a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
// License for the specific language governing permissions and limitations
|
|
// under the License.
|
|
|
|
package github
|
|
|
|
import (
|
|
"context"
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"log/slog"
|
|
"net/http"
|
|
"net/url"
|
|
"strings"
|
|
|
|
"github.com/google/go-github/v72/github"
|
|
|
|
runnerErrors "github.com/cloudbase/garm-provider-common/errors"
|
|
"github.com/cloudbase/garm/metrics"
|
|
"github.com/cloudbase/garm/params"
|
|
"github.com/cloudbase/garm/runner/common"
|
|
)
|
|
|
|
type githubClient struct {
|
|
*github.ActionsService
|
|
org *github.OrganizationsService
|
|
repo *github.RepositoriesService
|
|
enterprise *github.EnterpriseService
|
|
rateLimit *github.RateLimitService
|
|
|
|
entity params.ForgeEntity
|
|
cli *github.Client
|
|
}
|
|
|
|
func (g *githubClient) ListEntityHooks(ctx context.Context, opts *github.ListOptions) (ret []*github.Hook, response *github.Response, err error) {
|
|
metrics.GithubOperationCount.WithLabelValues(
|
|
"ListHooks", // label: operation
|
|
g.entity.LabelScope(), // label: scope
|
|
).Inc()
|
|
defer func() {
|
|
if err != nil {
|
|
metrics.GithubOperationFailedCount.WithLabelValues(
|
|
"ListHooks", // label: operation
|
|
g.entity.LabelScope(), // label: scope
|
|
).Inc()
|
|
}
|
|
}()
|
|
switch g.entity.EntityType {
|
|
case params.ForgeEntityTypeRepository:
|
|
ret, response, err = g.repo.ListHooks(ctx, g.entity.Owner, g.entity.Name, opts)
|
|
case params.ForgeEntityTypeOrganization:
|
|
ret, response, err = g.org.ListHooks(ctx, g.entity.Owner, opts)
|
|
default:
|
|
return nil, nil, fmt.Errorf("invalid entity type: %s", g.entity.EntityType)
|
|
}
|
|
return ret, response, err
|
|
}
|
|
|
|
func (g *githubClient) GetEntityHook(ctx context.Context, id int64) (ret *github.Hook, err error) {
|
|
metrics.GithubOperationCount.WithLabelValues(
|
|
"GetHook", // label: operation
|
|
g.entity.LabelScope(), // label: scope
|
|
).Inc()
|
|
defer func() {
|
|
if err != nil {
|
|
metrics.GithubOperationFailedCount.WithLabelValues(
|
|
"GetHook", // label: operation
|
|
g.entity.LabelScope(), // label: scope
|
|
).Inc()
|
|
}
|
|
}()
|
|
switch g.entity.EntityType {
|
|
case params.ForgeEntityTypeRepository:
|
|
ret, _, err = g.repo.GetHook(ctx, g.entity.Owner, g.entity.Name, id)
|
|
case params.ForgeEntityTypeOrganization:
|
|
ret, _, err = g.org.GetHook(ctx, g.entity.Owner, id)
|
|
default:
|
|
return nil, errors.New("invalid entity type")
|
|
}
|
|
return ret, err
|
|
}
|
|
|
|
func (g *githubClient) createGithubEntityHook(ctx context.Context, hook *github.Hook) (ret *github.Hook, err error) {
|
|
metrics.GithubOperationCount.WithLabelValues(
|
|
"CreateHook", // label: operation
|
|
g.entity.LabelScope(), // label: scope
|
|
).Inc()
|
|
defer func() {
|
|
if err != nil {
|
|
metrics.GithubOperationFailedCount.WithLabelValues(
|
|
"CreateHook", // label: operation
|
|
g.entity.LabelScope(), // label: scope
|
|
).Inc()
|
|
}
|
|
}()
|
|
switch g.entity.EntityType {
|
|
case params.ForgeEntityTypeRepository:
|
|
ret, _, err = g.repo.CreateHook(ctx, g.entity.Owner, g.entity.Name, hook)
|
|
case params.ForgeEntityTypeOrganization:
|
|
ret, _, err = g.org.CreateHook(ctx, g.entity.Owner, hook)
|
|
default:
|
|
return nil, errors.New("invalid entity type")
|
|
}
|
|
return ret, err
|
|
}
|
|
|
|
func (g *githubClient) CreateEntityHook(ctx context.Context, hook *github.Hook) (ret *github.Hook, err error) {
|
|
switch g.entity.Credentials.ForgeType {
|
|
case params.GithubEndpointType:
|
|
return g.createGithubEntityHook(ctx, hook)
|
|
case params.GiteaEndpointType:
|
|
return g.createGiteaEntityHook(ctx, hook)
|
|
default:
|
|
return nil, errors.New("invalid entity type")
|
|
}
|
|
}
|
|
|
|
func (g *githubClient) DeleteEntityHook(ctx context.Context, id int64) (ret *github.Response, err error) {
|
|
metrics.GithubOperationCount.WithLabelValues(
|
|
"DeleteHook", // label: operation
|
|
g.entity.LabelScope(), // label: scope
|
|
).Inc()
|
|
defer func() {
|
|
if err != nil {
|
|
metrics.GithubOperationFailedCount.WithLabelValues(
|
|
"DeleteHook", // label: operation
|
|
g.entity.LabelScope(), // label: scope
|
|
).Inc()
|
|
}
|
|
}()
|
|
switch g.entity.EntityType {
|
|
case params.ForgeEntityTypeRepository:
|
|
ret, err = g.repo.DeleteHook(ctx, g.entity.Owner, g.entity.Name, id)
|
|
case params.ForgeEntityTypeOrganization:
|
|
ret, err = g.org.DeleteHook(ctx, g.entity.Owner, id)
|
|
default:
|
|
return nil, errors.New("invalid entity type")
|
|
}
|
|
return ret, err
|
|
}
|
|
|
|
func (g *githubClient) PingEntityHook(ctx context.Context, id int64) (ret *github.Response, err error) {
|
|
metrics.GithubOperationCount.WithLabelValues(
|
|
"PingHook", // label: operation
|
|
g.entity.LabelScope(), // label: scope
|
|
).Inc()
|
|
defer func() {
|
|
if err != nil {
|
|
metrics.GithubOperationFailedCount.WithLabelValues(
|
|
"PingHook", // label: operation
|
|
g.entity.LabelScope(), // label: scope
|
|
).Inc()
|
|
}
|
|
}()
|
|
switch g.entity.EntityType {
|
|
case params.ForgeEntityTypeRepository:
|
|
ret, err = g.repo.PingHook(ctx, g.entity.Owner, g.entity.Name, id)
|
|
case params.ForgeEntityTypeOrganization:
|
|
ret, err = g.org.PingHook(ctx, g.entity.Owner, id)
|
|
default:
|
|
return nil, errors.New("invalid entity type")
|
|
}
|
|
return ret, err
|
|
}
|
|
|
|
func (g *githubClient) ListEntityRunners(ctx context.Context, opts *github.ListRunnersOptions) (*github.Runners, *github.Response, error) {
|
|
var ret *github.Runners
|
|
var response *github.Response
|
|
var err error
|
|
|
|
metrics.GithubOperationCount.WithLabelValues(
|
|
"ListEntityRunners", // label: operation
|
|
g.entity.LabelScope(), // label: scope
|
|
).Inc()
|
|
defer func() {
|
|
if err != nil {
|
|
metrics.GithubOperationFailedCount.WithLabelValues(
|
|
"ListEntityRunners", // label: operation
|
|
g.entity.LabelScope(), // label: scope
|
|
).Inc()
|
|
}
|
|
}()
|
|
|
|
switch g.entity.EntityType {
|
|
case params.ForgeEntityTypeRepository:
|
|
ret, response, err = g.ListRunners(ctx, g.entity.Owner, g.entity.Name, opts)
|
|
case params.ForgeEntityTypeOrganization:
|
|
ret, response, err = g.ListOrganizationRunners(ctx, g.entity.Owner, opts)
|
|
case params.ForgeEntityTypeEnterprise:
|
|
ret, response, err = g.enterprise.ListRunners(ctx, g.entity.Owner, opts)
|
|
default:
|
|
return nil, nil, errors.New("invalid entity type")
|
|
}
|
|
|
|
return ret, response, err
|
|
}
|
|
|
|
func (g *githubClient) ListEntityRunnerApplicationDownloads(ctx context.Context) ([]*github.RunnerApplicationDownload, *github.Response, error) {
|
|
var ret []*github.RunnerApplicationDownload
|
|
var response *github.Response
|
|
var err error
|
|
|
|
metrics.GithubOperationCount.WithLabelValues(
|
|
"ListEntityRunnerApplicationDownloads", // label: operation
|
|
g.entity.LabelScope(), // label: scope
|
|
).Inc()
|
|
defer func() {
|
|
if err != nil {
|
|
metrics.GithubOperationFailedCount.WithLabelValues(
|
|
"ListEntityRunnerApplicationDownloads", // label: operation
|
|
g.entity.LabelScope(), // label: scope
|
|
).Inc()
|
|
}
|
|
}()
|
|
|
|
switch g.entity.EntityType {
|
|
case params.ForgeEntityTypeRepository:
|
|
ret, response, err = g.ListRunnerApplicationDownloads(ctx, g.entity.Owner, g.entity.Name)
|
|
case params.ForgeEntityTypeOrganization:
|
|
ret, response, err = g.ListOrganizationRunnerApplicationDownloads(ctx, g.entity.Owner)
|
|
case params.ForgeEntityTypeEnterprise:
|
|
ret, response, err = g.enterprise.ListRunnerApplicationDownloads(ctx, g.entity.Owner)
|
|
default:
|
|
return nil, nil, errors.New("invalid entity type")
|
|
}
|
|
|
|
return ret, response, err
|
|
}
|
|
|
|
func parseError(response *github.Response, err error) error {
|
|
var statusCode int
|
|
if response != nil {
|
|
statusCode = response.StatusCode
|
|
}
|
|
|
|
switch statusCode {
|
|
case http.StatusNotFound:
|
|
return runnerErrors.ErrNotFound
|
|
case http.StatusUnauthorized:
|
|
return runnerErrors.ErrUnauthorized
|
|
case http.StatusUnprocessableEntity:
|
|
return runnerErrors.ErrBadRequest
|
|
default:
|
|
if statusCode >= 100 && statusCode < 300 {
|
|
return nil
|
|
}
|
|
if err != nil {
|
|
errResp := &github.ErrorResponse{}
|
|
if errors.As(err, &errResp) && errResp.Response != nil {
|
|
switch errResp.Response.StatusCode {
|
|
case http.StatusNotFound:
|
|
return runnerErrors.ErrNotFound
|
|
case http.StatusUnauthorized:
|
|
return runnerErrors.ErrUnauthorized
|
|
case http.StatusUnprocessableEntity:
|
|
return runnerErrors.ErrBadRequest
|
|
default:
|
|
// ugly hack. Gitea returns 500 if we try to remove a runner that does not exist.
|
|
if strings.Contains(err.Error(), "does not exist") {
|
|
return runnerErrors.ErrNotFound
|
|
}
|
|
return err
|
|
}
|
|
}
|
|
return err
|
|
}
|
|
return errors.New("unknown error")
|
|
}
|
|
}
|
|
|
|
func (g *githubClient) RemoveEntityRunner(ctx context.Context, runnerID int64) error {
|
|
var response *github.Response
|
|
var err error
|
|
|
|
metrics.GithubOperationCount.WithLabelValues(
|
|
"RemoveEntityRunner", // label: operation
|
|
g.entity.LabelScope(), // label: scope
|
|
).Inc()
|
|
defer func() {
|
|
if err != nil {
|
|
metrics.GithubOperationFailedCount.WithLabelValues(
|
|
"RemoveEntityRunner", // label: operation
|
|
g.entity.LabelScope(), // label: scope
|
|
).Inc()
|
|
}
|
|
}()
|
|
|
|
switch g.entity.EntityType {
|
|
case params.ForgeEntityTypeRepository:
|
|
response, err = g.RemoveRunner(ctx, g.entity.Owner, g.entity.Name, runnerID)
|
|
case params.ForgeEntityTypeOrganization:
|
|
response, err = g.RemoveOrganizationRunner(ctx, g.entity.Owner, runnerID)
|
|
case params.ForgeEntityTypeEnterprise:
|
|
response, err = g.enterprise.RemoveRunner(ctx, g.entity.Owner, runnerID)
|
|
default:
|
|
return errors.New("invalid entity type")
|
|
}
|
|
|
|
if err := parseError(response, err); err != nil {
|
|
return fmt.Errorf("error removing runner %d: %w", runnerID, err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (g *githubClient) CreateEntityRegistrationToken(ctx context.Context) (*github.RegistrationToken, *github.Response, error) {
|
|
var ret *github.RegistrationToken
|
|
var response *github.Response
|
|
var err error
|
|
|
|
metrics.GithubOperationCount.WithLabelValues(
|
|
"CreateEntityRegistrationToken", // label: operation
|
|
g.entity.LabelScope(), // label: scope
|
|
).Inc()
|
|
defer func() {
|
|
if err != nil {
|
|
metrics.GithubOperationFailedCount.WithLabelValues(
|
|
"CreateEntityRegistrationToken", // label: operation
|
|
g.entity.LabelScope(), // label: scope
|
|
).Inc()
|
|
}
|
|
}()
|
|
|
|
switch g.entity.EntityType {
|
|
case params.ForgeEntityTypeRepository:
|
|
ret, response, err = g.CreateRegistrationToken(ctx, g.entity.Owner, g.entity.Name)
|
|
case params.ForgeEntityTypeOrganization:
|
|
ret, response, err = g.CreateOrganizationRegistrationToken(ctx, g.entity.Owner)
|
|
case params.ForgeEntityTypeEnterprise:
|
|
ret, response, err = g.enterprise.CreateRegistrationToken(ctx, g.entity.Owner)
|
|
default:
|
|
return nil, nil, errors.New("invalid entity type")
|
|
}
|
|
|
|
return ret, response, err
|
|
}
|
|
|
|
func (g *githubClient) getOrganizationRunnerGroupIDByName(ctx context.Context, entity params.ForgeEntity, rgName string) (int64, error) {
|
|
opts := github.ListOrgRunnerGroupOptions{
|
|
ListOptions: github.ListOptions{
|
|
PerPage: 100,
|
|
},
|
|
}
|
|
|
|
for {
|
|
metrics.GithubOperationCount.WithLabelValues(
|
|
"ListOrganizationRunnerGroups", // label: operation
|
|
entity.LabelScope(), // label: scope
|
|
).Inc()
|
|
runnerGroups, ghResp, err := g.ListOrganizationRunnerGroups(ctx, entity.Owner, &opts)
|
|
if err != nil {
|
|
metrics.GithubOperationFailedCount.WithLabelValues(
|
|
"ListOrganizationRunnerGroups", // label: operation
|
|
entity.LabelScope(), // label: scope
|
|
).Inc()
|
|
if ghResp != nil && ghResp.StatusCode == http.StatusUnauthorized {
|
|
return 0, fmt.Errorf("error fetching runners: %w", runnerErrors.ErrUnauthorized)
|
|
}
|
|
return 0, fmt.Errorf("error fetching runners: %w", err)
|
|
}
|
|
for _, runnerGroup := range runnerGroups.RunnerGroups {
|
|
if runnerGroup.Name != nil && *runnerGroup.Name == rgName {
|
|
return *runnerGroup.ID, nil
|
|
}
|
|
}
|
|
if ghResp.NextPage == 0 {
|
|
break
|
|
}
|
|
opts.Page = ghResp.NextPage
|
|
}
|
|
return 0, runnerErrors.NewNotFoundError("runner group %s not found", rgName)
|
|
}
|
|
|
|
func (g *githubClient) getEnterpriseRunnerGroupIDByName(ctx context.Context, entity params.ForgeEntity, rgName string) (int64, error) {
|
|
opts := github.ListEnterpriseRunnerGroupOptions{
|
|
ListOptions: github.ListOptions{
|
|
PerPage: 100,
|
|
},
|
|
}
|
|
|
|
for {
|
|
metrics.GithubOperationCount.WithLabelValues(
|
|
"ListRunnerGroups", // label: operation
|
|
entity.LabelScope(), // label: scope
|
|
).Inc()
|
|
runnerGroups, ghResp, err := g.enterprise.ListRunnerGroups(ctx, entity.Owner, &opts)
|
|
if err != nil {
|
|
metrics.GithubOperationFailedCount.WithLabelValues(
|
|
"ListRunnerGroups", // label: operation
|
|
entity.LabelScope(), // label: scope
|
|
).Inc()
|
|
if ghResp != nil && ghResp.StatusCode == http.StatusUnauthorized {
|
|
return 0, fmt.Errorf("error fetching runners: %w", runnerErrors.ErrUnauthorized)
|
|
}
|
|
return 0, fmt.Errorf("error fetching runners: %w", err)
|
|
}
|
|
for _, runnerGroup := range runnerGroups.RunnerGroups {
|
|
if runnerGroup.Name != nil && *runnerGroup.Name == rgName {
|
|
return *runnerGroup.ID, nil
|
|
}
|
|
}
|
|
if ghResp.NextPage == 0 {
|
|
break
|
|
}
|
|
opts.Page = ghResp.NextPage
|
|
}
|
|
return 0, runnerErrors.NewNotFoundError("runner group not found")
|
|
}
|
|
|
|
func (g *githubClient) GetEntityJITConfig(ctx context.Context, instance string, pool params.Pool, labels []string) (jitConfigMap map[string]string, runner *github.Runner, err error) {
|
|
// If no runner group is set, use the default runner group ID. This is also the default for
|
|
// repository level runners.
|
|
var rgID int64 = 1
|
|
|
|
if pool.GitHubRunnerGroup != "" {
|
|
switch g.entity.EntityType {
|
|
case params.ForgeEntityTypeOrganization:
|
|
rgID, err = g.getOrganizationRunnerGroupIDByName(ctx, g.entity, pool.GitHubRunnerGroup)
|
|
case params.ForgeEntityTypeEnterprise:
|
|
rgID, err = g.getEnterpriseRunnerGroupIDByName(ctx, g.entity, pool.GitHubRunnerGroup)
|
|
}
|
|
|
|
if err != nil {
|
|
return nil, nil, fmt.Errorf("getting runner group ID: %w", err)
|
|
}
|
|
}
|
|
|
|
req := github.GenerateJITConfigRequest{
|
|
Name: instance,
|
|
RunnerGroupID: rgID,
|
|
Labels: labels,
|
|
// nolint:golangci-lint,godox
|
|
// TODO(gabriel-samfira): Should we make this configurable?
|
|
WorkFolder: github.Ptr("_work"),
|
|
}
|
|
|
|
metrics.GithubOperationCount.WithLabelValues(
|
|
"GetEntityJITConfig", // label: operation
|
|
g.entity.LabelScope(), // label: scope
|
|
).Inc()
|
|
|
|
var ret *github.JITRunnerConfig
|
|
var response *github.Response
|
|
|
|
switch g.entity.EntityType {
|
|
case params.ForgeEntityTypeRepository:
|
|
ret, response, err = g.GenerateRepoJITConfig(ctx, g.entity.Owner, g.entity.Name, &req)
|
|
case params.ForgeEntityTypeOrganization:
|
|
ret, response, err = g.GenerateOrgJITConfig(ctx, g.entity.Owner, &req)
|
|
case params.ForgeEntityTypeEnterprise:
|
|
ret, response, err = g.enterprise.GenerateEnterpriseJITConfig(ctx, g.entity.Owner, &req)
|
|
}
|
|
if err != nil {
|
|
metrics.GithubOperationFailedCount.WithLabelValues(
|
|
"GetEntityJITConfig", // label: operation
|
|
g.entity.LabelScope(), // label: scope
|
|
).Inc()
|
|
if response != nil && response.StatusCode == http.StatusUnauthorized {
|
|
return nil, nil, fmt.Errorf("failed to get JIT config: %w", err)
|
|
}
|
|
return nil, nil, fmt.Errorf("failed to get JIT config: %w", err)
|
|
}
|
|
|
|
defer func(run *github.Runner) {
|
|
if err != nil && run != nil {
|
|
innerErr := g.RemoveEntityRunner(ctx, run.GetID())
|
|
slog.With(slog.Any("error", innerErr)).ErrorContext(
|
|
ctx, "failed to remove runner",
|
|
"runner_id", run.GetID(), string(g.entity.EntityType), g.entity.String())
|
|
}
|
|
}(ret.Runner)
|
|
|
|
decoded, err := base64.StdEncoding.DecodeString(*ret.EncodedJITConfig)
|
|
if err != nil {
|
|
return nil, nil, fmt.Errorf("failed to decode JIT config: %w", err)
|
|
}
|
|
|
|
var jitConfig map[string]string
|
|
if err := json.Unmarshal(decoded, &jitConfig); err != nil {
|
|
return nil, nil, fmt.Errorf("failed to unmarshal JIT config: %w", err)
|
|
}
|
|
|
|
return jitConfig, ret.Runner, nil
|
|
}
|
|
|
|
func (g *githubClient) RateLimit(ctx context.Context) (*github.RateLimits, error) {
|
|
limits, resp, err := g.rateLimit.Get(ctx)
|
|
if err != nil {
|
|
metrics.GithubOperationFailedCount.WithLabelValues(
|
|
"GetRateLimit", // label: operation
|
|
g.entity.LabelScope(), // label: scope
|
|
).Inc()
|
|
}
|
|
if err := parseError(resp, err); err != nil {
|
|
return nil, fmt.Errorf("getting rate limit: %w", err)
|
|
}
|
|
return limits, nil
|
|
}
|
|
|
|
func (g *githubClient) GetEntity() params.ForgeEntity {
|
|
return g.entity
|
|
}
|
|
|
|
func (g *githubClient) GithubBaseURL() *url.URL {
|
|
return g.cli.BaseURL
|
|
}
|
|
|
|
func NewRateLimitClient(ctx context.Context, credentials params.ForgeCredentials) (common.RateLimitClient, error) {
|
|
httpClient, err := credentials.GetHTTPClient(ctx)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error fetching http client: %w", err)
|
|
}
|
|
|
|
slog.DebugContext(
|
|
ctx, "creating rate limit client",
|
|
"base_url", credentials.APIBaseURL,
|
|
"upload_url", credentials.UploadBaseURL)
|
|
|
|
ghClient, err := github.NewClient(httpClient).WithEnterpriseURLs(
|
|
credentials.APIBaseURL, credentials.UploadBaseURL)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error fetching github client: %w", err)
|
|
}
|
|
cli := &githubClient{
|
|
rateLimit: ghClient.RateLimit,
|
|
cli: ghClient,
|
|
}
|
|
|
|
return cli, nil
|
|
}
|
|
|
|
func withGiteaURLs(client *github.Client, apiBaseURL string) (*github.Client, error) {
|
|
if client == nil {
|
|
return nil, errors.New("client is nil")
|
|
}
|
|
|
|
if apiBaseURL == "" {
|
|
return nil, errors.New("invalid gitea URLs")
|
|
}
|
|
|
|
parsedBaseURL, err := url.ParseRequestURI(apiBaseURL)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error parsing gitea base URL: %w", err)
|
|
}
|
|
|
|
if !strings.HasSuffix(parsedBaseURL.Path, "/") {
|
|
parsedBaseURL.Path += "/"
|
|
}
|
|
|
|
if !strings.HasSuffix(parsedBaseURL.Path, "/api/v1/") {
|
|
parsedBaseURL.Path += "api/v1/"
|
|
}
|
|
|
|
client.BaseURL = parsedBaseURL
|
|
client.UploadURL = parsedBaseURL
|
|
|
|
return client, nil
|
|
}
|
|
|
|
func Client(ctx context.Context, entity params.ForgeEntity) (common.GithubClient, error) {
|
|
// func GithubClient(ctx context.Context, entity params.ForgeEntity) (common.GithubClient, error) {
|
|
httpClient, err := entity.Credentials.GetHTTPClient(ctx)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error fetching http client: %w", err)
|
|
}
|
|
|
|
slog.DebugContext(
|
|
ctx, "creating client for entity",
|
|
"entity", entity.String(), "base_url", entity.Credentials.APIBaseURL,
|
|
"upload_url", entity.Credentials.UploadBaseURL)
|
|
|
|
ghClient := github.NewClient(httpClient)
|
|
switch entity.Credentials.ForgeType {
|
|
case params.GithubEndpointType:
|
|
ghClient, err = ghClient.WithEnterpriseURLs(entity.Credentials.APIBaseURL, entity.Credentials.UploadBaseURL)
|
|
case params.GiteaEndpointType:
|
|
ghClient, err = withGiteaURLs(ghClient, entity.Credentials.APIBaseURL)
|
|
}
|
|
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error fetching github client: %w", err)
|
|
}
|
|
|
|
cli := &githubClient{
|
|
ActionsService: ghClient.Actions,
|
|
org: ghClient.Organizations,
|
|
repo: ghClient.Repositories,
|
|
enterprise: ghClient.Enterprise,
|
|
rateLimit: ghClient.RateLimit,
|
|
cli: ghClient,
|
|
entity: entity,
|
|
}
|
|
|
|
return cli, nil
|
|
}
|