From 524611cf00ea9cc86e2e548244937ec9b7141b24 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 31 May 2023 18:30:41 +0200 Subject: [PATCH] Add Forge Metadata (#1789) close #1787 --- docs/docs/20-usage/50-environment.md | 3 ++ pipeline/frontend/metadata.go | 10 +++++ pipeline/stepBuilder.go | 10 +++++ pipeline/stepBuilder_test.go | 29 ++++++++++++ server/forge/bitbucket/bitbucket.go | 13 ++++-- server/forge/bitbucket/bitbucket_test.go | 4 +- .../forge/bitbucketserver/bitbucketserver.go | 27 ++++++----- server/forge/forge.go | 3 ++ server/forge/gitea/gitea.go | 21 +++++---- server/forge/gitea/gitea_test.go | 2 +- server/forge/github/github.go | 17 ++++--- server/forge/github/github_test.go | 2 +- server/forge/gitlab/convert.go | 2 +- server/forge/gitlab/gitlab.go | 45 ++++++++++--------- server/forge/gitlab/gitlab_test.go | 2 +- server/forge/mocks/forge.go | 14 ++++++ 16 files changed, 149 insertions(+), 55 deletions(-) diff --git a/docs/docs/20-usage/50-environment.md b/docs/docs/20-usage/50-environment.md index ea013a250..bb7160dec 100644 --- a/docs/docs/20-usage/50-environment.md +++ b/docs/docs/20-usage/50-environment.md @@ -120,6 +120,9 @@ This is the reference list of all environment variables available to your pipeli | `CI_SYSTEM_URL` | link to CI system | | `CI_SYSTEM_HOST` | hostname of CI server | | `CI_SYSTEM_VERSION` | version of the server | +| | **Forge** | +| `CI_FORGE_TYPE` | name of forge (gitea, github, ...) | +| `CI_FORGE_URL` | root URL of configured forge | | | **Internal** - Please don't use! | | `CI_SCRIPT` | Internal script path. Used to call pipeline step commands. | | `CI_NETRC_USERNAME` | Credentials for private repos to be able to clone data. (Only available for specific images) | diff --git a/pipeline/frontend/metadata.go b/pipeline/frontend/metadata.go index b33b958fb..1a77227cb 100644 --- a/pipeline/frontend/metadata.go +++ b/pipeline/frontend/metadata.go @@ -49,6 +49,7 @@ type ( Workflow Workflow `json:"workflow,omitempty"` Step Step `json:"step,omitempty"` Sys System `json:"sys,omitempty"` + Forge Forge `json:"forge,omitempty"` } // Repo defines runtime metadata for a repository. @@ -126,6 +127,12 @@ type ( Platform string `json:"arch,omitempty"` Version string `json:"version,omitempty"` } + + // Forge defines runtime metadata about the forge that host the repo + Forge struct { + Type string `json:"type,omitempty"` + URL string `json:"url,omitempty"` + } ) // Environ returns the metadata as a map of environment variables. @@ -223,6 +230,9 @@ func (m *Metadata) Environ() map[string]string { "CI_SYSTEM_PLATFORM": m.Sys.Platform, // will be set by pipeline platform option or by agent "CI_SYSTEM_VERSION": version.Version, + "CI_FORGE_TYPE": m.Forge.Type, + "CI_FORGE_URL": m.Forge.URL, + // DEPRECATED "CI_SYSTEM_ARCH": m.Sys.Platform, // TODO: remove after v1.0.x version // use CI_PIPELINE_* diff --git a/pipeline/stepBuilder.go b/pipeline/stepBuilder.go index 08e45f799..4a55d5a96 100644 --- a/pipeline/stepBuilder.go +++ b/pipeline/stepBuilder.go @@ -335,6 +335,15 @@ func metadataFromStruct(repo *model.Repo, pipeline, last *model.Pipeline, workfl if err == nil { host = uri.Host } + + forge := frontend.Forge{} + if server.Config.Services.Forge != nil { + forge = frontend.Forge{ + Type: server.Config.Services.Forge.Name(), + URL: server.Config.Services.Forge.URL(), + } + } + return frontend.Metadata{ Repo: frontend.Repo{ Name: repo.FullName, @@ -357,6 +366,7 @@ func metadataFromStruct(repo *model.Repo, pipeline, last *model.Pipeline, workfl Host: host, Platform: "", // will be set by pipeline platform option or by agent }, + Forge: forge, } } diff --git a/pipeline/stepBuilder_test.go b/pipeline/stepBuilder_test.go index db8075554..789464d42 100644 --- a/pipeline/stepBuilder_test.go +++ b/pipeline/stepBuilder_test.go @@ -17,14 +17,18 @@ package pipeline import ( "fmt" + "sync" "testing" + "github.com/woodpecker-ci/woodpecker/server" + "github.com/woodpecker-ci/woodpecker/server/forge/mocks" forge_types "github.com/woodpecker-ci/woodpecker/server/forge/types" "github.com/woodpecker-ci/woodpecker/server/model" ) func TestGlobalEnvsubst(t *testing.T) { t.Parallel() + setupMockForge(t) b := StepBuilder{ Envs: map[string]string{ @@ -59,6 +63,7 @@ pipeline: func TestMissingGlobalEnvsubst(t *testing.T) { t.Parallel() + setupMockForge(t) b := StepBuilder{ Envs: map[string]string{ @@ -93,6 +98,7 @@ pipeline: func TestMultilineEnvsubst(t *testing.T) { t.Parallel() + setupMockForge(t) b := StepBuilder{ Repo: &model.Repo{}, @@ -130,6 +136,7 @@ pipeline: func TestMultiPipeline(t *testing.T) { t.Parallel() + setupMockForge(t) b := StepBuilder{ Repo: &model.Repo{}, @@ -164,6 +171,7 @@ pipeline: func TestDependsOn(t *testing.T) { t.Parallel() + setupMockForge(t) b := StepBuilder{ Repo: &model.Repo{}, @@ -210,6 +218,7 @@ depends_on: func TestRunsOn(t *testing.T) { t.Parallel() + setupMockForge(t) b := StepBuilder{ Repo: &model.Repo{}, @@ -246,6 +255,7 @@ runs_on: func TestPipelineName(t *testing.T) { t.Parallel() + setupMockForge(t) b := StepBuilder{ Repo: &model.Repo{Config: ".woodpecker"}, @@ -281,6 +291,7 @@ pipeline: func TestBranchFilter(t *testing.T) { t.Parallel() + setupMockForge(t) b := StepBuilder{ Repo: &model.Repo{}, @@ -327,6 +338,7 @@ pipeline: func TestRootWhenFilter(t *testing.T) { t.Parallel() + setupMockForge(t) b := StepBuilder{ Repo: &model.Repo{}, @@ -373,6 +385,7 @@ pipeline: func TestZeroSteps(t *testing.T) { t.Parallel() + setupMockForge(t) pipeline := &model.Pipeline{Branch: "dev"} @@ -407,6 +420,7 @@ pipeline: func TestZeroStepsAsMultiPipelineDeps(t *testing.T) { t.Parallel() + setupMockForge(t) pipeline := &model.Pipeline{Branch: "dev"} @@ -455,6 +469,7 @@ depends_on: [ zerostep ] func TestZeroStepsAsMultiPipelineTransitiveDeps(t *testing.T) { t.Parallel() + setupMockForge(t) pipeline := &model.Pipeline{Branch: "dev"} @@ -509,6 +524,7 @@ depends_on: [ shouldbefiltered ] func TestTree(t *testing.T) { t.Parallel() + setupMockForge(t) pipeline := &model.Pipeline{ Event: model.EventPush, @@ -549,6 +565,7 @@ pipeline: func TestSanitizePath(t *testing.T) { t.Parallel() + setupMockForge(t) testTable := []struct { path string @@ -586,3 +603,15 @@ func TestSanitizePath(t *testing.T) { } } } + +var setupMockForgeLock = sync.Once{} + +func setupMockForge(t *testing.T) { + setupMockForgeLock.Do(func() { + forge := mocks.NewForge(t) + forge.On("Name").Return("mock") + forge.On("URL").Return("https://codeberg.org") + + server.Config.Services.Forge = forge + }) +} diff --git a/server/forge/bitbucket/bitbucket.go b/server/forge/bitbucket/bitbucket.go index 18b2b3059..d824b1bfe 100644 --- a/server/forge/bitbucket/bitbucket.go +++ b/server/forge/bitbucket/bitbucket.go @@ -46,7 +46,7 @@ type Opts struct { type config struct { API string - URL string + url string Client string Secret string } @@ -56,7 +56,7 @@ type config struct { func New(opts *Opts) (forge.Forge, error) { return &config{ API: DefaultAPI, - URL: DefaultURL, + url: DefaultURL, Client: opts.Client, Secret: opts.Secret, }, nil @@ -68,6 +68,11 @@ func (c *config) Name() string { return "bitbucket" } +// URL returns the root url of a configured forge +func (c *config) URL() string { + return c.url +} + // Login authenticates an account with Bitbucket using the oauth2 protocol. The // Bitbucket account details are returned when the user is successfully authenticated. func (c *config) Login(ctx context.Context, w http.ResponseWriter, req *http.Request) (*model.User, error) { @@ -332,8 +337,8 @@ func (c *config) newConfig(redirect string) *oauth2.Config { ClientID: c.Client, ClientSecret: c.Secret, Endpoint: oauth2.Endpoint{ - AuthURL: fmt.Sprintf("%s/site/oauth2/authorize", c.URL), - TokenURL: fmt.Sprintf("%s/site/oauth2/access_token", c.URL), + AuthURL: fmt.Sprintf("%s/site/oauth2/authorize", c.url), + TokenURL: fmt.Sprintf("%s/site/oauth2/access_token", c.url), }, RedirectURL: fmt.Sprintf("%s/authorize", redirect), } diff --git a/server/forge/bitbucket/bitbucket_test.go b/server/forge/bitbucket/bitbucket_test.go index 031fc441d..ad90acc7a 100644 --- a/server/forge/bitbucket/bitbucket_test.go +++ b/server/forge/bitbucket/bitbucket_test.go @@ -34,7 +34,7 @@ func Test_bitbucket(t *testing.T) { gin.SetMode(gin.TestMode) s := httptest.NewServer(fixtures.Handler()) - c := &config{URL: s.URL, API: s.URL} + c := &config{url: s.URL, API: s.URL} g := goblin.Goblin(t) ctx := context.Background() @@ -45,7 +45,7 @@ func Test_bitbucket(t *testing.T) { g.It("Should return client with default endpoint", func() { forge, _ := New(&Opts{Client: "4vyW6b49Z", Secret: "a5012f6c6"}) - g.Assert(forge.(*config).URL).Equal(DefaultURL) + g.Assert(forge.(*config).url).Equal(DefaultURL) g.Assert(forge.(*config).API).Equal(DefaultAPI) g.Assert(forge.(*config).Client).Equal("4vyW6b49Z") g.Assert(forge.(*config).Secret).Equal("a5012f6c6") diff --git a/server/forge/bitbucketserver/bitbucketserver.go b/server/forge/bitbucketserver/bitbucketserver.go index 84949f239..24c526fd7 100644 --- a/server/forge/bitbucketserver/bitbucketserver.go +++ b/server/forge/bitbucketserver/bitbucketserver.go @@ -55,7 +55,7 @@ type Opts struct { } type Config struct { - URL string + url string Username string Password string SkipVerify bool @@ -66,7 +66,7 @@ type Config struct { // the on-premise edition of Bitbucket Cloud, formerly known as Stash. func New(opts Opts) (forge.Forge, error) { config := &Config{ - URL: opts.URL, + url: opts.URL, Username: opts.Username, Password: opts.Password, SkipVerify: opts.SkipVerify, @@ -111,6 +111,11 @@ func (c *Config) Name() string { return "stash" } +// URL returns the root url of a configured forge +func (c *Config) URL() string { + return c.url +} + func (c *Config) Login(ctx context.Context, res http.ResponseWriter, req *http.Request) (*model.User, error) { requestToken, u, err := c.Consumer.GetRequestTokenAndUrl("oob") if err != nil { @@ -127,7 +132,7 @@ func (c *Config) Login(ctx context.Context, res http.ResponseWriter, req *http.R return nil, err } - client := internal.NewClientWithToken(ctx, c.URL, c.Consumer, accessToken.Token) + client := internal.NewClientWithToken(ctx, c.url, c.Consumer, accessToken.Token) user, err := client.FindCurrentUser() if err != nil { @@ -154,7 +159,7 @@ func (*Config) TeamPerm(_ *model.User, _ string) (*model.Perm, error) { } func (c *Config) Repo(ctx context.Context, u *model.User, _ model.ForgeRemoteID, owner, name string) (*model.Repo, error) { - client := internal.NewClientWithToken(ctx, c.URL, c.Consumer, u.Token) + client := internal.NewClientWithToken(ctx, c.url, c.Consumer, u.Token) repo, err := client.FindRepo(owner, name) if err != nil { return nil, err @@ -167,7 +172,7 @@ func (c *Config) Repo(ctx context.Context, u *model.User, _ model.ForgeRemoteID, } func (c *Config) Repos(ctx context.Context, u *model.User) ([]*model.Repo, error) { - client := internal.NewClientWithToken(ctx, c.URL, c.Consumer, u.Token) + client := internal.NewClientWithToken(ctx, c.url, c.Consumer, u.Token) repos, err := client.FindRepos() if err != nil { return nil, err @@ -185,7 +190,7 @@ func (c *Config) Repos(ctx context.Context, u *model.User) ([]*model.Repo, error } func (c *Config) File(ctx context.Context, u *model.User, r *model.Repo, p *model.Pipeline, f string) ([]byte, error) { - client := internal.NewClientWithToken(ctx, c.URL, c.Consumer, u.Token) + client := internal.NewClientWithToken(ctx, c.url, c.Consumer, u.Token) return client.FindFileForRepo(r.Owner, r.Name, f, p.Ref) } @@ -204,7 +209,7 @@ func (c *Config) Status(ctx context.Context, user *model.User, repo *model.Repo, URL: common.GetPipelineStatusLink(repo, pipeline, nil), } - client := internal.NewClientWithToken(ctx, c.URL, c.Consumer, user.Token) + client := internal.NewClientWithToken(ctx, c.url, c.Consumer, user.Token) return client.CreateStatus(pipeline.Commit, &status) } @@ -223,14 +228,14 @@ func (c *Config) Netrc(_ *model.User, r *model.Repo) (*model.Netrc, error) { } func (c *Config) Activate(ctx context.Context, u *model.User, r *model.Repo, link string) error { - client := internal.NewClientWithToken(ctx, c.URL, c.Consumer, u.Token) + client := internal.NewClientWithToken(ctx, c.url, c.Consumer, u.Token) return client.CreateHook(r.Owner, r.Name, link) } // Branches returns the names of all branches for the named repository. func (c *Config) Branches(ctx context.Context, u *model.User, r *model.Repo, p *model.ListOptions) ([]string, error) { - bitbucketBranches, err := internal.NewClientWithToken(ctx, c.URL, c.Consumer, u.Token).ListBranches(r.Owner, r.Name, p.Page, p.PerPage) + bitbucketBranches, err := internal.NewClientWithToken(ctx, c.url, c.Consumer, u.Token).ListBranches(r.Owner, r.Name, p.Page, p.PerPage) if err != nil { return nil, err } @@ -253,12 +258,12 @@ func (c *Config) PullRequests(_ context.Context, _ *model.User, _ *model.Repo, _ } func (c *Config) Deactivate(ctx context.Context, u *model.User, r *model.Repo, link string) error { - client := internal.NewClientWithToken(ctx, c.URL, c.Consumer, u.Token) + client := internal.NewClientWithToken(ctx, c.url, c.Consumer, u.Token) return client.DeleteHook(r.Owner, r.Name, link) } func (c *Config) Hook(_ context.Context, r *http.Request) (*model.Repo, *model.Pipeline, error) { - return parseHook(r, c.URL) + return parseHook(r, c.url) } // OrgMembership returns if user is member of organization and if user diff --git a/server/forge/forge.go b/server/forge/forge.go index 2bbaaddb7..70d262d33 100644 --- a/server/forge/forge.go +++ b/server/forge/forge.go @@ -32,6 +32,9 @@ type Forge interface { // Name returns the string name of this driver Name() string + // URL returns the root url of a configured forge + URL() string + // Login authenticates the session and returns the // forge user details. Login(ctx context.Context, w http.ResponseWriter, r *http.Request) (*model.User, error) diff --git a/server/forge/gitea/gitea.go b/server/forge/gitea/gitea.go index a74b86528..ff97519ad 100644 --- a/server/forge/gitea/gitea.go +++ b/server/forge/gitea/gitea.go @@ -52,7 +52,7 @@ const ( ) type Gitea struct { - URL string + url string ClientID string ClientSecret string SkipVerify bool @@ -78,7 +78,7 @@ func New(opts Opts) (forge.Forge, error) { u.Host = host } return &Gitea{ - URL: opts.URL, + url: opts.URL, ClientID: opts.Client, ClientSecret: opts.Secret, SkipVerify: opts.SkipVerify, @@ -90,13 +90,18 @@ func (c *Gitea) Name() string { return "gitea" } +// URL returns the root url of a configured forge +func (c *Gitea) URL() string { + return c.url +} + func (c *Gitea) oauth2Config(ctx context.Context) (*oauth2.Config, context.Context) { return &oauth2.Config{ ClientID: c.ClientID, ClientSecret: c.ClientSecret, Endpoint: oauth2.Endpoint{ - AuthURL: fmt.Sprintf(authorizeTokenURL, c.URL), - TokenURL: fmt.Sprintf(accessTokenURL, c.URL), + AuthURL: fmt.Sprintf(authorizeTokenURL, c.url), + TokenURL: fmt.Sprintf(accessTokenURL, c.url), }, RedirectURL: fmt.Sprintf("%s/authorize", server.Config.Server.OAuthHost), }, @@ -149,7 +154,7 @@ func (c *Gitea) Login(ctx context.Context, w http.ResponseWriter, req *http.Requ Login: account.UserName, Email: account.Email, ForgeRemoteID: model.ForgeRemoteID(fmt.Sprint(account.ID)), - Avatar: expandAvatar(c.URL, account.AvatarURL), + Avatar: expandAvatar(c.url, account.AvatarURL), }, nil } @@ -208,7 +213,7 @@ func (c *Gitea) Teams(ctx context.Context, u *model.User) ([]*model.Team, error) ) teams := make([]*model.Team, 0, len(orgs)) for _, org := range orgs { - teams = append(teams, toTeam(org, c.URL)) + teams = append(teams, toTeam(org, c.url)) } return teams, err }) @@ -546,11 +551,11 @@ func (c *Gitea) newClientToken(ctx context.Context, token string) (*gitea.Client TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, } } - client, err := gitea.NewClient(c.URL, gitea.SetToken(token), gitea.SetHTTPClient(httpClient), gitea.SetContext(ctx)) + client, err := gitea.NewClient(c.url, gitea.SetToken(token), gitea.SetHTTPClient(httpClient), gitea.SetContext(ctx)) if err != nil && strings.Contains(err.Error(), "Malformed version") { // we guess it's a dev gitea version log.Error().Err(err).Msgf("could not detect gitea version, assume dev version %s", giteaDevVersion) - client, err = gitea.NewClient(c.URL, gitea.SetGiteaVersion(giteaDevVersion), gitea.SetToken(token), gitea.SetHTTPClient(httpClient), gitea.SetContext(ctx)) + client, err = gitea.NewClient(c.url, gitea.SetGiteaVersion(giteaDevVersion), gitea.SetToken(token), gitea.SetHTTPClient(httpClient), gitea.SetContext(ctx)) } return client, err } diff --git a/server/forge/gitea/gitea_test.go b/server/forge/gitea/gitea_test.go index eb9b6d57f..e2e104220 100644 --- a/server/forge/gitea/gitea_test.go +++ b/server/forge/gitea/gitea_test.go @@ -57,7 +57,7 @@ func Test_gitea(t *testing.T) { URL: "http://localhost:8080", SkipVerify: true, }) - g.Assert(forge.(*Gitea).URL).Equal("http://localhost:8080") + g.Assert(forge.(*Gitea).url).Equal("http://localhost:8080") g.Assert(forge.(*Gitea).SkipVerify).Equal(true) }) g.It("Should handle malformed url", func() { diff --git a/server/forge/github/github.go b/server/forge/github/github.go index f73570b94..40342e349 100644 --- a/server/forge/github/github.go +++ b/server/forge/github/github.go @@ -57,22 +57,22 @@ type Opts struct { func New(opts Opts) (forge.Forge, error) { r := &client{ API: defaultAPI, - URL: defaultURL, + url: defaultURL, Client: opts.Client, Secret: opts.Secret, SkipVerify: opts.SkipVerify, MergeRef: opts.MergeRef, } if opts.URL != defaultURL { - r.URL = strings.TrimSuffix(opts.URL, "/") - r.API = r.URL + "/api/v3/" + r.url = strings.TrimSuffix(opts.URL, "/") + r.API = r.url + "/api/v3/" } return r, nil } type client struct { - URL string + url string API string Client string Secret string @@ -85,6 +85,11 @@ func (c *client) Name() string { return "github" } +// URL returns the root url of a configured forge +func (c *client) URL() string { + return c.url +} + // Login authenticates the session and returns the forge user details. func (c *client) Login(ctx context.Context, res http.ResponseWriter, req *http.Request) (*model.User, error) { config := c.newConfig(req) @@ -380,8 +385,8 @@ func (c *client) newConfig(req *http.Request) *oauth2.Config { ClientSecret: c.Secret, Scopes: []string{"repo", "repo:status", "user:email", "read:org"}, Endpoint: oauth2.Endpoint{ - AuthURL: fmt.Sprintf("%s/login/oauth/authorize", c.URL), - TokenURL: fmt.Sprintf("%s/login/oauth/access_token", c.URL), + AuthURL: fmt.Sprintf("%s/login/oauth/authorize", c.url), + TokenURL: fmt.Sprintf("%s/login/oauth/access_token", c.url), }, RedirectURL: redirect, } diff --git a/server/forge/github/github_test.go b/server/forge/github/github_test.go index b5a952ad9..f13eb21c9 100644 --- a/server/forge/github/github_test.go +++ b/server/forge/github/github_test.go @@ -51,7 +51,7 @@ func Test_github(t *testing.T) { Secret: "I1NiIsInR5", SkipVerify: true, }) - g.Assert(forge.(*client).URL).Equal("http://localhost:8080") + g.Assert(forge.(*client).url).Equal("http://localhost:8080") g.Assert(forge.(*client).API).Equal("http://localhost:8080/api/v3/") g.Assert(forge.(*client).Client).Equal("0ZXh0IjoiI") g.Assert(forge.(*client).Secret).Equal("I1NiIsInR5") diff --git a/server/forge/gitlab/convert.go b/server/forge/gitlab/convert.go index b863f218c..c68b84ba5 100644 --- a/server/forge/gitlab/convert.go +++ b/server/forge/gitlab/convert.go @@ -58,7 +58,7 @@ func (g *GitLab) convertGitLabRepo(_repo *gitlab.Project) (*model.Repo, error) { } if len(repo.Avatar) != 0 && !strings.HasPrefix(repo.Avatar, "http") { - repo.Avatar = fmt.Sprintf("%s/%s", g.URL, repo.Avatar) + repo.Avatar = fmt.Sprintf("%s/%s", g.url, repo.Avatar) } return repo, nil diff --git a/server/forge/gitlab/gitlab.go b/server/forge/gitlab/gitlab.go index f98daaf96..db4ab20e2 100644 --- a/server/forge/gitlab/gitlab.go +++ b/server/forge/gitlab/gitlab.go @@ -54,7 +54,7 @@ type Opts struct { // Gitlab implements "Forge" interface type GitLab struct { - URL string + url string ClientID string ClientSecret string SkipVerify bool @@ -66,7 +66,7 @@ type GitLab struct { // source Git service. See https://gitlab.com func New(opts Opts) (forge.Forge, error) { return &GitLab{ - URL: opts.URL, + url: opts.URL, ClientID: opts.ClientID, ClientSecret: opts.ClientSecret, SkipVerify: opts.SkipVerify, @@ -78,13 +78,18 @@ func (g *GitLab) Name() string { return "gitlab" } +// URL returns the root url of a configured forge +func (g *GitLab) URL() string { + return g.url +} + func (g *GitLab) oauth2Config(ctx context.Context) (*oauth2.Config, context.Context) { return &oauth2.Config{ ClientID: g.ClientID, ClientSecret: g.ClientSecret, Endpoint: oauth2.Endpoint{ - AuthURL: fmt.Sprintf("%s/oauth/authorize", g.URL), - TokenURL: fmt.Sprintf("%s/oauth/token", g.URL), + AuthURL: fmt.Sprintf("%s/oauth/authorize", g.url), + TokenURL: fmt.Sprintf("%s/oauth/token", g.url), }, Scopes: []string{defaultScope}, RedirectURL: fmt.Sprintf("%s/authorize", server.Config.Server.OAuthHost), @@ -122,7 +127,7 @@ func (g *GitLab) Login(ctx context.Context, res http.ResponseWriter, req *http.R return nil, fmt.Errorf("Error exchanging token. %w", err) } - client, err := newClient(g.URL, token.AccessToken, g.SkipVerify) + client, err := newClient(g.url, token.AccessToken, g.SkipVerify) if err != nil { return nil, err } @@ -141,7 +146,7 @@ func (g *GitLab) Login(ctx context.Context, res http.ResponseWriter, req *http.R Secret: token.RefreshToken, } if !strings.HasPrefix(user.Avatar, "http") { - user.Avatar = g.URL + "/" + login.AvatarURL + user.Avatar = g.url + "/" + login.AvatarURL } return user, nil @@ -172,7 +177,7 @@ func (g *GitLab) Refresh(ctx context.Context, user *model.User) (bool, error) { // Auth authenticates the session and returns the forge user login for the given token func (g *GitLab) Auth(ctx context.Context, token, _ string) (string, error) { - client, err := newClient(g.URL, token, g.SkipVerify) + client, err := newClient(g.url, token, g.SkipVerify) if err != nil { return "", err } @@ -186,7 +191,7 @@ func (g *GitLab) Auth(ctx context.Context, token, _ string) (string, error) { // Teams fetches a list of team memberships from the forge. func (g *GitLab) Teams(ctx context.Context, user *model.User) ([]*model.Team, error) { - client, err := newClient(g.URL, user.Token, g.SkipVerify) + client, err := newClient(g.url, user.Token, g.SkipVerify) if err != nil { return nil, err } @@ -231,7 +236,7 @@ func (g *GitLab) getProject(ctx context.Context, client *gitlab.Client, owner, n // Repo fetches the repository from the forge. func (g *GitLab) Repo(ctx context.Context, user *model.User, remoteID model.ForgeRemoteID, owner, name string) (*model.Repo, error) { - client, err := newClient(g.URL, user.Token, g.SkipVerify) + client, err := newClient(g.url, user.Token, g.SkipVerify) if err != nil { return nil, err } @@ -258,7 +263,7 @@ func (g *GitLab) Repo(ctx context.Context, user *model.User, remoteID model.Forg // Repos fetches a list of repos from the forge. func (g *GitLab) Repos(ctx context.Context, user *model.User) ([]*model.Repo, error) { - client, err := newClient(g.URL, user.Token, g.SkipVerify) + client, err := newClient(g.url, user.Token, g.SkipVerify) if err != nil { return nil, err } @@ -307,7 +312,7 @@ func (g *GitLab) PullRequests(ctx context.Context, u *model.User, r *model.Repo, if u != nil { token = u.Token } - client, err := newClient(g.URL, token, g.SkipVerify) + client, err := newClient(g.url, token, g.SkipVerify) if err != nil { return nil, err } @@ -338,7 +343,7 @@ func (g *GitLab) PullRequests(ctx context.Context, u *model.User, r *model.Repo, // File fetches a file from the forge repository and returns in string format. func (g *GitLab) File(ctx context.Context, user *model.User, repo *model.Repo, pipeline *model.Pipeline, fileName string) ([]byte, error) { - client, err := newClient(g.URL, user.Token, g.SkipVerify) + client, err := newClient(g.url, user.Token, g.SkipVerify) if err != nil { return nil, err } @@ -352,7 +357,7 @@ func (g *GitLab) File(ctx context.Context, user *model.User, repo *model.Repo, p // Dir fetches a folder from the forge repository func (g *GitLab) Dir(ctx context.Context, user *model.User, repo *model.Repo, pipeline *model.Pipeline, path string) ([]*forge_types.FileMeta, error) { - client, err := newClient(g.URL, user.Token, g.SkipVerify) + client, err := newClient(g.url, user.Token, g.SkipVerify) if err != nil { return nil, err } @@ -400,7 +405,7 @@ func (g *GitLab) Dir(ctx context.Context, user *model.User, repo *model.Repo, pi // Status sends the commit status back to gitlab. func (g *GitLab) Status(ctx context.Context, user *model.User, repo *model.Repo, pipeline *model.Pipeline, step *model.Step) error { - client, err := newClient(g.URL, user.Token, g.SkipVerify) + client, err := newClient(g.url, user.Token, g.SkipVerify) if err != nil { return err } @@ -457,7 +462,7 @@ func (g *GitLab) getTokenAndWebURL(link string) (token, webURL string, err error // Activate activates a repository by adding a Post-commit hook and // a Public Deploy key, if applicable. func (g *GitLab) Activate(ctx context.Context, user *model.User, repo *model.Repo, link string) error { - client, err := newClient(g.URL, user.Token, g.SkipVerify) + client, err := newClient(g.url, user.Token, g.SkipVerify) if err != nil { return err } @@ -492,7 +497,7 @@ func (g *GitLab) Activate(ctx context.Context, user *model.User, repo *model.Rep // Deactivate removes a repository by removing all the post-commit hooks // which are equal to link and removing the SSH deploy key. func (g *GitLab) Deactivate(ctx context.Context, user *model.User, repo *model.Repo, link string) error { - client, err := newClient(g.URL, user.Token, g.SkipVerify) + client, err := newClient(g.url, user.Token, g.SkipVerify) if err != nil { return err } @@ -549,7 +554,7 @@ func (g *GitLab) Branches(ctx context.Context, user *model.User, repo *model.Rep if user != nil { token = user.Token } - client, err := newClient(g.URL, token, g.SkipVerify) + client, err := newClient(g.url, token, g.SkipVerify) if err != nil { return nil, err } @@ -579,7 +584,7 @@ func (g *GitLab) BranchHead(ctx context.Context, u *model.User, r *model.Repo, b if u != nil { token = u.Token } - client, err := newClient(g.URL, token, g.SkipVerify) + client, err := newClient(g.url, token, g.SkipVerify) if err != nil { return "", err } @@ -635,7 +640,7 @@ func (g *GitLab) Hook(ctx context.Context, req *http.Request) (*model.Repo, *mod // OrgMembership returns if user is member of organization and if user // is admin/owner in this organization. func (g *GitLab) OrgMembership(ctx context.Context, u *model.User, owner string) (*model.OrgPerm, error) { - client, err := newClient(g.URL, u.Token, g.SkipVerify) + client, err := newClient(g.url, u.Token, g.SkipVerify) if err != nil { return nil, err } @@ -705,7 +710,7 @@ func (g *GitLab) loadChangedFilesFromMergeRequest(ctx context.Context, tmpRepo * return nil, err } - client, err := newClient(g.URL, user.Token, g.SkipVerify) + client, err := newClient(g.url, user.Token, g.SkipVerify) if err != nil { return nil, err } diff --git a/server/forge/gitlab/gitlab_test.go b/server/forge/gitlab/gitlab_test.go index 28666884f..927c7fd91 100644 --- a/server/forge/gitlab/gitlab_test.go +++ b/server/forge/gitlab/gitlab_test.go @@ -39,7 +39,7 @@ func load(t *testing.T, config string) *GitLab { _url.RawQuery = "" gitlab := GitLab{} - gitlab.URL = _url.String() + gitlab.url = _url.String() gitlab.ClientID = params.Get("client_id") gitlab.ClientSecret = params.Get("client_secret") gitlab.SkipVerify, _ = strconv.ParseBool(params.Get("skip_verify")) diff --git a/server/forge/mocks/forge.go b/server/forge/mocks/forge.go index 6b0268fc4..0acae699d 100644 --- a/server/forge/mocks/forge.go +++ b/server/forge/mocks/forge.go @@ -418,6 +418,20 @@ func (_m *Forge) Teams(ctx context.Context, u *model.User) ([]*model.Team, error return r0, r1 } +// URL provides a mock function with given fields: +func (_m *Forge) URL() string { + ret := _m.Called() + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + type mockConstructorTestingTNewForge interface { mock.TestingT Cleanup(func())