Skip to content

Commit

Permalink
feat: Add baseline support for bitbucket cloud (#134)
Browse files Browse the repository at this point in the history
Signed-off-by: Sergiy Kulanov <sergiy_kulanov@epam.com>

Extend Codebase Operator for Bitbucket Cloud Support
  • Loading branch information
SergK authored and NikolayMarusenko committed Sep 30, 2024
1 parent 65ead20 commit 13f9044
Show file tree
Hide file tree
Showing 16 changed files with 103 additions and 43 deletions.
11 changes: 6 additions & 5 deletions api/v1/git_server_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ import (
)

const (
GitProviderGerrit = "gerrit"
GitProviderGithub = "github"
GitProviderGitlab = "gitlab"
GitProviderGerrit = "gerrit"
GitProviderGithub = "github"
GitProviderGitlab = "gitlab"
GitProviderBitbucket = "bitbucket"
)

// GitServerSpec defines the desired state of GitServer.
Expand All @@ -26,8 +27,8 @@ type GitServerSpec struct {
NameSshKeySecret string `json:"nameSshKeySecret"`

// GitProvider is a git provider type. It can be gerrit, github or gitlab. Default value is gerrit.
// +kubebuilder:validation:Enum=gerrit;gitlab;github
// +kubebuilder:default:=gerrit
// +kubebuilder:validation:Enum=gerrit;gitlab;github;bitbucket
// +kubebuilder:default:=github
// +optional
GitProvider string `json:"gitProvider,omitempty"`

Expand Down
3 changes: 2 additions & 1 deletion config/crd/bases/v2.edp.epam.com_gitservers.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,14 @@ spec:
gitHost:
type: string
gitProvider:
default: gerrit
default: github
description: GitProvider is a git provider type. It can be gerrit,
github or gitlab. Default value is gerrit.
enum:
- gerrit
- gitlab
- github
- bitbucket
type: string
gitUser:
default: git
Expand Down
2 changes: 1 addition & 1 deletion controllers/codebase/service/chain/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func MakeChain(ctx context.Context, c client.Client) handler.CodebaseHandler {

ch.Use(
NewPutGitWebRepoUrl(c),
NewPutProject(c, gp, &gerrit.SSHGerritClient{}, gitprovider.NewMockGitProjectProvider),
NewPutProject(c, gp, &gerrit.SSHGerritClient{}, gitprovider.NewGitProjectProvider),
NewPutWebHook(c, resty.New()),
NewPutDeployConfigs(c, gp),
NewPutDefaultCodeBaseBranch(c),
Expand Down
2 changes: 1 addition & 1 deletion controllers/codebase/service/chain/put_gitwebrepourl.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func (s *PutGitWebRepoUrl) ServeRequest(ctx context.Context, codebase *codebaseA
// For Gerrit we return link to the repository in format: https://<gerrit_host>/gitweb?p=<codebase>.git
func (s *PutGitWebRepoUrl) getGitWebURL(ctx context.Context, gitServer *codebaseApi.GitServer, codebase *codebaseApi.Codebase) (string, error) {
switch gitServer.Spec.GitProvider {
case codebaseApi.GitProviderGitlab, codebaseApi.GitProviderGithub:
case codebaseApi.GitProviderGitlab, codebaseApi.GitProviderGithub, codebaseApi.GitProviderBitbucket:
urlLink := util.GetHostWithProtocol(gitServer.Spec.GitHost)
urlLink = strings.TrimSuffix(urlLink, "/")
// For GitHub and GitLab we return link to the repository in format: https://<git_host>/<git_org>/<git_repo>
Expand Down
8 changes: 4 additions & 4 deletions controllers/codebase/service/chain/put_gitwebrepourl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ func TestPutGitWebRepoUrl_ServeRequest(t *testing.T) {
k8sObjects: []client.Object{
&codebaseApi.GitServer{
ObjectMeta: metaV1.ObjectMeta{Name: "git-server", Namespace: namespace},
Spec: codebaseApi.GitServerSpec{GitProvider: "bitbucket"},
Spec: codebaseApi.GitServerSpec{GitProvider: "test-provider"},
},
&codebaseApi.Codebase{
ObjectMeta: metaV1.ObjectMeta{Name: "test", Namespace: namespace},
Expand All @@ -92,7 +92,7 @@ func TestPutGitWebRepoUrl_ServeRequest(t *testing.T) {
wantErr: func(t require.TestingT, err error, _ ...any) {
require.Error(t, err)

require.Contains(t, err.Error(), "unsupported Git provider bitbucket")
require.Contains(t, err.Error(), "unsupported Git provider test-provider")
},
},
}
Expand Down Expand Up @@ -223,12 +223,12 @@ func TestPutGitWebRepoUrl_getGitWebURL(t *testing.T) {
},
gitServer: &codebaseApi.GitServer{
ObjectMeta: metaV1.ObjectMeta{Name: "git-server", Namespace: namespace},
Spec: codebaseApi.GitServerSpec{GitProvider: "bitbucket", GitHost: "bitbucket"},
Spec: codebaseApi.GitServerSpec{GitProvider: "test-provider", GitHost: "test-host"},
},
k8sObjects: []client.Object{
&codebaseApi.GitServer{
ObjectMeta: metaV1.ObjectMeta{Name: "git-server", Namespace: namespace},
Spec: codebaseApi.GitServerSpec{GitProvider: "bitbucket", GitHost: "bitbucket"},
Spec: codebaseApi.GitServerSpec{GitProvider: "test-provider", GitHost: "test-host"},
},
&codebaseApi.Codebase{
ObjectMeta: metaV1.ObjectMeta{Name: "test", Namespace: namespace},
Expand Down
3 changes: 2 additions & 1 deletion controllers/codebase/service/chain/put_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ func (s *PutWebHook) ServeRequest(ctx context.Context, codebase *codebaseApi.Cod
}

if gitServer.Spec.GitProvider != codebaseApi.GitProviderGitlab &&
gitServer.Spec.GitProvider != codebaseApi.GitProviderGithub {
gitServer.Spec.GitProvider != codebaseApi.GitProviderGithub &&
gitServer.Spec.GitProvider != codebaseApi.GitProviderBitbucket {
log.Info(fmt.Sprintf("Unsupported Git provider %s. Skip putting webhook", gitServer.Spec.GitProvider))
return nil
}
Expand Down
3 changes: 2 additions & 1 deletion deploy-templates/crds/v2.edp.epam.com_gitservers.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,14 @@ spec:
gitHost:
type: string
gitProvider:
default: gerrit
default: github
description: GitProvider is a git provider type. It can be gerrit,
github or gitlab. Default value is gerrit.
enum:
- gerrit
- gitlab
- github
- bitbucket
type: string
gitUser:
default: git
Expand Down
4 changes: 2 additions & 2 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -1139,8 +1139,8 @@ GitServerSpec defines the desired state of GitServer.
<td>
GitProvider is a git provider type. It can be gerrit, github or gitlab. Default value is gerrit.<br/>
<br/>
<i>Enum</i>: gerrit, gitlab, github<br/>
<i>Default</i>: gerrit<br/>
<i>Enum</i>: gerrit, gitlab, github, bitbucket<br/>
<i>Default</i>: github<br/>
</td>
<td>false</td>
</tr><tr>
Expand Down
46 changes: 46 additions & 0 deletions pkg/gitprovider/bitbucket.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// nolint // TODO: add linters after bitbucket implementation
package gitprovider

import (
"context"
"errors"
)

type BitbucketClient struct {
}

func NewBitbucketClient() *BitbucketClient {
return &BitbucketClient{}
}

func (b BitbucketClient) CreateWebHook(ctx context.Context, gitProviderURL, token, projectID, webHookSecret, webHookURL string, skipTLS bool) (*WebHook, error) {
return nil, errors.New("not implemented")
}

func (b BitbucketClient) CreateWebHookIfNotExists(ctx context.Context, githubURL, token, projectID, webHookSecret, webHookURL string, skipTLS bool) (*WebHook, error) {
return nil, errors.New("not implemented")
}

func (b BitbucketClient) GetWebHook(ctx context.Context, gitProviderURL, token, projectID string, webHookID int) (*WebHook, error) {
return nil, errors.New("not implemented")
}

func (b BitbucketClient) GetWebHooks(ctx context.Context, githubURL, token, projectID string) ([]*WebHook, error) {
return nil, errors.New("not implemented")
}

func (b BitbucketClient) DeleteWebHook(ctx context.Context, gitProviderURL, token, projectID string, webHookID int) error {
return errors.New("not implemented")
}

func (b BitbucketClient) CreateProject(ctx context.Context, gitlabURL, token, fullPath string) error {
return errors.New("not implemented")
}

func (b BitbucketClient) ProjectExists(ctx context.Context, gitlabURL, token, projectID string) (bool, error) {
return false, errors.New("not implemented")
}

func (b BitbucketClient) SetDefaultBranch(ctx context.Context, githubURL, token, projectID, branch string) error {
return errors.New("not implemented")
}
4 changes: 2 additions & 2 deletions pkg/gitprovider/github.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ const (
ownerPathParam = "owner"
)

// NewMockGitHubClient creates a new GitHub client.
func NewMockGitHubClient(restyClient *resty.Client) *GitHubClient {
// NewGitHubClient creates a new GitHub client.
func NewGitHubClient(restyClient *resty.Client) *GitHubClient {
restyClient.SetRetryCount(retryCount)
restyClient.AddRetryCondition(
func(response *resty.Response, err error) bool {
Expand Down
16 changes: 8 additions & 8 deletions pkg/gitprovider/github_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ func TestGitHubClient_CreateWebHook(t *testing.T) {
require.NoError(t, err)
httpmock.RegisterRegexpResponder(http.MethodPost, fakeUrlRegexp, responder)

c := NewMockGitHubClient(restyClient)
c := NewGitHubClient(restyClient)

got, err := c.CreateWebHook(context.Background(), "url", "token", tt.projectID, "secret", "webHookURL", false)

Expand Down Expand Up @@ -137,7 +137,7 @@ func TestGitHubClient_GetWebHook(t *testing.T) {
require.NoError(t, err)
httpmock.RegisterRegexpResponder(http.MethodGet, fakeUrlRegexp, responder)

c := NewMockGitHubClient(restyClient)
c := NewGitHubClient(restyClient)

got, err := c.GetWebHook(context.Background(), "url", "token", tt.projectID, 999)

Expand Down Expand Up @@ -205,7 +205,7 @@ func TestGitHubClient_DeleteWebHook(t *testing.T) {
responder := httpmock.NewStringResponder(tt.respStatus, "")
httpmock.RegisterRegexpResponder(http.MethodDelete, fakeUrlRegexp, responder)

c := NewMockGitHubClient(restyClient)
c := NewGitHubClient(restyClient)

err := c.DeleteWebHook(context.Background(), "url", "token", tt.projectID, 999)

Expand Down Expand Up @@ -280,7 +280,7 @@ func TestGitHubClient_GetWebHooks(t *testing.T) {
require.NoError(t, err)
httpmock.RegisterRegexpResponder(http.MethodGet, fakeUrlRegexp, responder)

c := NewMockGitHubClient(restyClient)
c := NewGitHubClient(restyClient)

got, err := c.GetWebHooks(context.Background(), "url", "token", tt.projectID)

Expand Down Expand Up @@ -384,7 +384,7 @@ func TestGitHubClient_CreateWebHookIfNotExists(t *testing.T) {
require.NoError(t, err)
httpmock.RegisterRegexpResponder(http.MethodPost, fakeUrlRegexp, POSTResponder)

c := NewMockGitHubClient(restyClient)
c := NewGitHubClient(restyClient)

got, err := c.CreateWebHookIfNotExists(context.Background(), "url", "token", tt.projectID, "secret", tt.webHookURL, false)

Expand Down Expand Up @@ -482,7 +482,7 @@ func TestGitHubClient_CreateProject(t *testing.T) {
require.NoError(t, err)
httpmock.RegisterRegexpResponder(http.MethodGet, fakeUrlRegexp, GetOrgResponder)

c := NewMockGitHubClient(restyClient)
c := NewGitHubClient(restyClient)
err = c.CreateProject(context.Background(), "url", "token", tt.projectID)
tt.wantErr(t, err)
})
Expand Down Expand Up @@ -543,7 +543,7 @@ func TestGitHubClient_ProjectExists(t *testing.T) {
require.NoError(t, err)
httpmock.RegisterRegexpResponder(http.MethodGet, fakeUrlRegexp, GETResponder)

c := NewMockGitHubClient(restyClient)
c := NewGitHubClient(restyClient)
got, err := c.ProjectExists(context.Background(), "url", "token", tt.projectID)
tt.wantErr(t, err)
assert.Equal(t, tt.want, got)
Expand Down Expand Up @@ -598,7 +598,7 @@ func TestGitHubClient_SetDefaultBranch(t *testing.T) {
require.NoError(t, err)
httpmock.RegisterRegexpResponder(http.MethodPatch, fakeUrlRegexp, GETResponder)

c := NewMockGitHubClient(restyClient)
c := NewGitHubClient(restyClient)
err = c.SetDefaultBranch(context.Background(), "url", "token", tt.projectID, "main")
tt.wantErr(t, err)
})
Expand Down
4 changes: 2 additions & 2 deletions pkg/gitprovider/gitlab.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ const (
projectIDPathParam = "project-id"
)

// NewMockGitLabClient creates a new GitLab client.
func NewMockGitLabClient(restyClient *resty.Client) *GitLabClient {
// NewGitLabClient creates a new GitLab client.
func NewGitLabClient(restyClient *resty.Client) *GitLabClient {
restyClient.SetRetryCount(retryCount)
restyClient.AddRetryCondition(
func(response *resty.Response, err error) bool {
Expand Down
16 changes: 8 additions & 8 deletions pkg/gitprovider/gitlab_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func TestGitLabClient_CreateWebHook(t *testing.T) {
require.NoError(t, err)
httpmock.RegisterRegexpResponder(http.MethodPost, fakeUrlRegexp, responder)

c := NewMockGitLabClient(restyClient)
c := NewGitLabClient(restyClient)

got, err := c.CreateWebHook(context.Background(), "url", "token", "project", "secret", "webHookURL", false)
if !tt.wantErr(t, err) {
Expand Down Expand Up @@ -106,7 +106,7 @@ func TestGitLabClient_GetWebHook(t *testing.T) {
require.NoError(t, err)
httpmock.RegisterRegexpResponder(http.MethodGet, fakeUrlRegexp, responder)

c := NewMockGitLabClient(restyClient)
c := NewGitLabClient(restyClient)

got, err := c.GetWebHook(context.Background(), "url", "token", "project", 999)
if !tt.wantErr(t, err) {
Expand Down Expand Up @@ -158,7 +158,7 @@ func TestGitLabClient_DeleteWebHook(t *testing.T) {
responder := httpmock.NewStringResponder(tt.respStatus, "")
httpmock.RegisterRegexpResponder(http.MethodDelete, fakeUrlRegexp, responder)

c := NewMockGitLabClient(restyClient)
c := NewGitLabClient(restyClient)

err := c.DeleteWebHook(context.Background(), "url", "token", "project", 999)
if !tt.wantErr(t, err) {
Expand Down Expand Up @@ -223,7 +223,7 @@ func TestGitLabClient_GetWebHooks(t *testing.T) {
require.NoError(t, err)
httpmock.RegisterRegexpResponder(http.MethodGet, fakeUrlRegexp, responder)

c := NewMockGitLabClient(restyClient)
c := NewGitLabClient(restyClient)

got, err := c.GetWebHooks(context.Background(), "url", "token", tt.projectID)

Expand Down Expand Up @@ -321,7 +321,7 @@ func TestGitLabClient_CreateWebHookIfNotExists(t *testing.T) {
require.NoError(t, err)
httpmock.RegisterRegexpResponder(http.MethodPost, fakeUrlRegexp, POSTResponder)

c := NewMockGitLabClient(restyClient)
c := NewGitLabClient(restyClient)

got, err := c.CreateWebHookIfNotExists(context.Background(), "url", "token", tt.projectID, "secret", tt.webHookURL, false)

Expand Down Expand Up @@ -404,7 +404,7 @@ func TestGitLabClient_CreateProject(t *testing.T) {
require.NoError(t, err)
httpmock.RegisterRegexpResponder(http.MethodPost, fakeUrlRegexp, POSTResponder)

c := NewMockGitLabClient(restyClient)
c := NewGitLabClient(restyClient)

err = c.CreateProject(context.Background(), "url", "token", tt.projectID)
tt.wantErr(t, err)
Expand Down Expand Up @@ -463,7 +463,7 @@ func TestGitLabClient_ProjectExists(t *testing.T) {
require.NoError(t, err)
httpmock.RegisterRegexpResponder(http.MethodGet, fakeUrlRegexp, GETResponder)

c := NewMockGitLabClient(restyClient)
c := NewGitLabClient(restyClient)

got, err := c.ProjectExists(context.Background(), "url", "token", tt.projectID)
tt.wantErr(t, err)
Expand Down Expand Up @@ -510,7 +510,7 @@ func TestGitLabClient_SetDefaultBranch(t *testing.T) {
require.NoError(t, err)
httpmock.RegisterRegexpResponder(http.MethodPut, fakeUrlRegexp, GETResponder)

c := NewMockGitLabClient(restyClient)
c := NewGitLabClient(restyClient)

err = c.SetDefaultBranch(context.Background(), "url", "token", tt.projectID, "main")
tt.wantErr(t, err)
Expand Down
18 changes: 14 additions & 4 deletions pkg/gitprovider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,16 +84,18 @@ type GitProvider interface {
func NewProvider(gitServer *codebaseApi.GitServer, restyClient *resty.Client) (GitProvider, error) {
switch gitServer.Spec.GitProvider {
case codebaseApi.GitProviderGithub:
return NewMockGitHubClient(restyClient), nil
return NewGitHubClient(restyClient), nil
case codebaseApi.GitProviderGitlab:
return NewMockGitLabClient(restyClient), nil
return NewGitLabClient(restyClient), nil
case codebaseApi.GitProviderBitbucket:
return NewBitbucketClient(), nil
default:
return nil, fmt.Errorf("unsupported git provider %s", gitServer.Spec.GitProvider)
}
}

// NewMockGitProjectProvider creates a new Git project provider based on gitServer.
func NewMockGitProjectProvider(gitServer *codebaseApi.GitServer) (GitProjectProvider, error) {
// NewGitProjectProvider creates a new Git project provider based on gitServer.
func NewGitProjectProvider(gitServer *codebaseApi.GitServer) (GitProjectProvider, error) {
return NewProvider(gitServer, resty.New())
}

Expand All @@ -111,6 +113,14 @@ func GetGitProviderAPIURL(gitServer *codebaseApi.GitServer) string {
url = fmt.Sprintf("%s/api/v3", url)
}

if gitServer.Spec.GitProvider == codebaseApi.GitProviderBitbucket {
if url == "https://bitbucket.org" {
return "https://api.bitbucket.org/2.0"
}

url = fmt.Sprintf("%s/rest/api/1.0", url)
}

if gitServer.Spec.HttpsPort != 0 {
url = fmt.Sprintf("%s:%d", url, gitServer.Spec.HttpsPort)
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/gitprovider/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func TestNewProvider(t *testing.T) {
GitProvider: codebaseApi.GitProviderGithub,
},
},
want: NewMockGitHubClient(restyClient),
want: NewGitHubClient(restyClient),
wantErr: require.NoError,
},
{
Expand All @@ -37,7 +37,7 @@ func TestNewProvider(t *testing.T) {
GitProvider: codebaseApi.GitProviderGitlab,
},
},
want: NewMockGitLabClient(restyClient),
want: NewGitLabClient(restyClient),
wantErr: require.NoError,
},
{
Expand Down
Loading

0 comments on commit 13f9044

Please sign in to comment.