diff --git a/README.md b/README.md index df23d586f3..fd0bd8752d 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ Set up a development environment on any infrastructure, with a single command. * __Configuration File Support__: Initially support for [dev container](https://containers.dev/), ability to expand to DevFile, Nix & Flox (Contributions welcome here!). * __Prebuilds System__: Drastically improve environment setup times (Contributions welcome here!). * __IDE Support__ : Seamlessly supports [VS Code](https://github.com/microsoft/vscode) & [JetBrains](https://www.jetbrains.com/remote-development/gateway/) locally, ready to use without configuration. Includes a built-in Web IDE for added convenience. -* __Git Provider Integration__: GitHub, GitLab, Bitbucket, Bitbucket Server, Gitea, Gitness, Azure DevOps, AWS CodeCommit & Gogs can be connected, allowing easy repo branch or PR pull and commit back from the workspaces. +* __Git Provider Integration__: GitHub, GitLab, Bitbucket, Bitbucket Server, Gitea, Gitness, Azure DevOps, AWS CodeCommit, Gogs & Gitee can be connected, allowing easy repo branch or PR pull and commit back from the workspaces. * __Multiple Project Workspace__: Support for multiple project repositories in the same workspace, making it easy to develop using a micro-service architecture. * __Reverse Proxy Integration__: Enable collaboration and streamline feedback loops by leveraging reverse proxy functionality. Access preview ports and the Web IDE seamlessly, even behind firewalls. * __Extensibility__: Enable extensibility with plugin or provider development. Moreover, in any dynamic language, not just Go(Contributions welcome here!). diff --git a/cmd/daytona/config/const.go b/cmd/daytona/config/const.go index 294471ef44..cbd4116e23 100644 --- a/cmd/daytona/config/const.go +++ b/cmd/daytona/config/const.go @@ -59,6 +59,7 @@ func GetSupportedGitProviders() []GitProvider { {"azure-devops", "Azure DevOps"}, {"aws-codecommit", "AWS CodeCommit"}, {"gogs", "Gogs"}, + {"gitee", "Gitee"}, } } @@ -88,6 +89,8 @@ func GetDocsLinkFromGitProvider(providerId string) string { return "https://docs.aws.amazon.com/codecommit/latest/userguide/setting-up-gc.html and to configure AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY & AWS_DEFAULT_REGION read https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html" case "gogs": return "https://www.daytona.io/docs/configuration/git-providers/#gogs" + case "gitee": + return "https://www.daytona.io/docs/configuration/git-providers/#gitee" default: return "" } @@ -134,6 +137,8 @@ func GetRequiredScopesFromGitProviderId(providerId string) string { return "Code (Status, Read & Write); User Profile (Read); Project and Team (Read)" case "aws-codecommit": return "/" + case "gitee": + return "user_info, pull_requests, groups, projects, emails" case "gogs": fallthrough default: diff --git a/go.mod b/go.mod index 394d7907ef..218be924b9 100644 --- a/go.mod +++ b/go.mod @@ -10,6 +10,8 @@ replace github.com/samber/lo => github.com/samber/lo v1.39.0 require ( code.gitea.io/sdk/gitea v0.17.1 + gitee.com/openeuler/go-gitee v0.0.0-20220530104019-3af895bc380c + github.com/antihax/optional v1.0.0 github.com/aws/aws-sdk-go-v2/config v1.27.26 github.com/aws/aws-sdk-go-v2/service/iam v1.34.3 github.com/charmbracelet/bubbles v0.20.0 diff --git a/go.sum b/go.sum index 0823972806..5cab9092ed 100644 --- a/go.sum +++ b/go.sum @@ -605,6 +605,8 @@ filippo.io/mkcert v1.4.4 h1:8eVbbwfVlaqUM7OwuftKc2nuYOoTDQWqsoXmzoXZdbc= filippo.io/mkcert v1.4.4/go.mod h1:VyvOchVuAye3BoUsPUOOofKygVwLV2KQMVFJNRq+1dA= gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc= +gitee.com/openeuler/go-gitee v0.0.0-20220530104019-3af895bc380c h1:miClKCIA2Zyqif+Mf0GOdd/1u2q2wW7/vVuHpQprwDw= +gitee.com/openeuler/go-gitee v0.0.0-20220530104019-3af895bc380c/go.mod h1:qGJhn1KxC5UE4BUmxCE/hTpFfuKbd3U3V9fNROrspfE= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= @@ -635,6 +637,7 @@ github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1L github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= +github.com/antihax/optional v1.0.0 h1:xK2lYat7ZLaVVcIuj82J8kIro4V6kDe0AUDFboUCwcg= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/apache/arrow/go/v10 v10.0.1/go.mod h1:YvhnlEePVnBS4+0z3fhPfUy7W1Ikj0Ih0vcRo/gZ1M0= github.com/apache/arrow/go/v11 v11.0.0/go.mod h1:Eg5OsL5H+e299f7u5ssuXsuHQVEGC4xei5aX110hRiI= diff --git a/pkg/cmd/workspace/util/repository_wizard.go b/pkg/cmd/workspace/util/repository_wizard.go index 32f74ca6d0..d957a88b68 100644 --- a/pkg/cmd/workspace/util/repository_wizard.go +++ b/pkg/cmd/workspace/util/repository_wizard.go @@ -22,7 +22,7 @@ import ( func isGitProviderWithUnsupportedPagination(providerId string) bool { switch providerId { - case "azure-devops", "bitbucket", "gitness", "aws-codecommit", "gogs": + case "azure-devops", "bitbucket", "gitness", "aws-codecommit", "gogs", "gitee": return true default: return false diff --git a/pkg/gitprovider/gitee.go b/pkg/gitprovider/gitee.go new file mode 100644 index 0000000000..ebe40d6a0b --- /dev/null +++ b/pkg/gitprovider/gitee.go @@ -0,0 +1,380 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package gitprovider + +import ( + "context" + "fmt" + "io" + "strings" + + "net/http" + "net/url" + "strconv" + + "encoding/json" + + "gitee.com/openeuler/go-gitee/gitee" + "github.com/antihax/optional" + "golang.org/x/oauth2" +) + +type Project struct { + Id int32 `json:"id,omitempty"` + FullName string `json:"full_name,omitempty"` + HumanName string `json:"human_name,omitempty"` + Url string `json:"url,omitempty"` + Namespace *gitee.Namespace `json:"namespace,omitempty"` + Path string `json:"path,omitempty"` + Name string `json:"name,omitempty"` + Owner *gitee.UserBasic `json:"owner,omitempty"` + Description string `json:"description,omitempty"` + Private bool `json:"private,omitempty"` + Public bool `json:"public,omitempty"` + Internal bool `json:"internal,omitempty"` + HtmlUrl string `json:"html_url,omitempty"` + Homepage string `json:"homepage,omitempty"` + DefaultBranch string `json:"default_branch,omitempty"` + Parent *Project `json:"parent,omitempty"` +} + +type GiteeGitProvider struct { + *AbstractGitProvider + + token string +} + +func NewGiteeGitProvider(token string) *GiteeGitProvider { + gitProvider := &GiteeGitProvider{ + token: token, + AbstractGitProvider: &AbstractGitProvider{}, + } + gitProvider.AbstractGitProvider.GitProvider = gitProvider + + return gitProvider +} + +func (g *GiteeGitProvider) CanHandle(repoUrl string) (bool, error) { + staticContext, err := g.ParseStaticGitContext(repoUrl) + if err != nil { + return false, err + } + + return strings.Contains("https://gitee.com", staticContext.Source), nil +} + +func (g *GiteeGitProvider) getApiClient() *gitee.APIClient { + tokenSource := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: g.token}) + conf := gitee.NewConfiguration() + conf.HTTPClient = oauth2.NewClient(context.Background(), tokenSource) + return gitee.NewAPIClient(conf) +} + +func (g *GiteeGitProvider) GetUser() (*GitUser, error) { + client := g.getApiClient() + ctx := context.Background() + user, _, err := client.UsersApi.GetV5User(ctx, nil) + if err != nil { + return nil, fmt.Errorf("failed to fetch User : %w", err) + } + + gitUser := &GitUser{ + Id: strconv.FormatInt(int64(user.Id), 10), + Username: user.Login, + Name: user.Name, + } + + // gitee email will be empty if not set to public + if user.Email != "" { + gitUser.Email = user.Email + } + + return gitUser, nil +} + +func (g *GiteeGitProvider) GetNamespaces(options ListOptions) ([]*GitNamespace, error) { + client := g.getApiClient() + ctx := context.Background() + userNamespaces, _, err := client.UsersApi.GetV5UserNamespaces(ctx, nil) + if err != nil { + return nil, fmt.Errorf("failed to fetch Namespaces : %w", err) + } + + var namespaces []*GitNamespace + for _, namespace := range userNamespaces { + namespaces = append(namespaces, &GitNamespace{ + Id: namespace.Name, + Name: namespace.Name, + }) + } + + return namespaces, nil +} + +func (g *GiteeGitProvider) GetRepositories(namespace string, options ListOptions) ([]*GitRepository, error) { + reposApiURL := fmt.Sprintf("https://gitee.com/api/v5/user/repos?access_token=%s", g.token) + body, err := g.performRequest("GET", reposApiURL) + if err != nil { + return nil, fmt.Errorf("failed to fetch Repositories : %w", err) + } + + var repos []Project + err = json.Unmarshal(body, &repos) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal GetRepositories response : %w", err) + } + + response := []*GitRepository{} + for _, repo := range repos { + u, err := url.Parse(repo.HtmlUrl) + if err != nil { + return nil, err + } + response = append(response, &GitRepository{ + Id: repo.Name, + Name: repo.Name, + Url: repo.HtmlUrl, + Branch: repo.DefaultBranch, + Owner: repo.Owner.Login, + Source: u.Host, + }) + } + return response, nil +} + +func (g *GiteeGitProvider) GetRepoBranches(repositoryId string, namespaceId string, options ListOptions) ([]*GitBranch, error) { + client := g.getApiClient() + ctx := context.Background() + branches, _, err := client.RepositoriesApi.GetV5ReposOwnerRepoBranches(ctx, namespaceId, repositoryId, nil) + if err != nil { + return nil, err + } + + var response []*GitBranch + for _, branch := range branches { + response = append(response, &GitBranch{ + Name: branch.Name, + Sha: branch.Commit.Sha, + }) + } + return response, nil +} + +func (g *GiteeGitProvider) GetRepoPRs(repositoryId string, namespaceId string, options ListOptions) ([]*GitPullRequest, error) { + client := g.getApiClient() + ctx := context.Background() + prs, _, err := client.PullRequestsApi.GetV5ReposOwnerRepoPulls(ctx, namespaceId, repositoryId, nil) + if err != nil { + return nil, err + } + + var response []*GitPullRequest + for _, pr := range prs { + response = append(response, &GitPullRequest{ + Name: pr.Title, + Branch: pr.Head.Label, + Sha: pr.Head.Sha, + SourceRepoId: pr.Head.Repo.Name, + SourceRepoName: pr.Head.Repo.Name, + SourceRepoUrl: pr.Head.Repo.HtmlUrl, + SourceRepoOwner: pr.Head.Repo.Owner.Name, + }) + } + return response, nil +} + +func (g *GiteeGitProvider) GetBranchByCommit(staticContext *StaticGitContext) (string, error) { + client := g.getApiClient() + ctx := context.Background() + branches, _, err := client.RepositoriesApi.GetV5ReposOwnerRepoBranches(ctx, staticContext.Owner, staticContext.Name, nil) + if err != nil { + return "", fmt.Errorf("failed to get branch by commit: %w", err) + } + + var branchName string + for _, branch := range branches { + commitId := branch.Commit.Sha + if *staticContext.Sha == commitId { + branchName = branch.Name + break + } + + commits, _, err := client.RepositoriesApi.GetV5ReposOwnerRepoCommits(ctx, staticContext.Owner, staticContext.Name, &gitee.GetV5ReposOwnerRepoCommitsOpts{ + Sha: optional.NewString(branchName), + }) + if err != nil { + continue + } + + if len(commits) == 0 { + continue + } + + for _, commit := range commits { + if commit.Sha == *staticContext.Sha { + branchName = branch.Name + break + } + } + if branchName != "" { + break + } + } + + if branchName == "" { + return "", fmt.Errorf("status code: %d branch not found for SHA: %s", http.StatusNotFound, *staticContext.Sha) + } + return branchName, nil +} + +func (g *GiteeGitProvider) GetLastCommitSha(staticContext *StaticGitContext) (string, error) { + client := g.getApiClient() + ctx := context.Background() + + var sha *string + + if staticContext.Branch != nil { + sha = staticContext.Branch + } + + if staticContext.Sha != nil { + sha = staticContext.Sha + } + commits, _, err := client.RepositoriesApi.GetV5ReposOwnerRepoCommits(ctx, staticContext.Owner, staticContext.Name, &gitee.GetV5ReposOwnerRepoCommitsOpts{ + Sha: optional.NewString(*sha), + }) + if err != nil { + return "", err + } + if len(commits) == 0 { + return "", nil + } + return commits[0].Sha, nil +} + +func (g *GiteeGitProvider) GetDefaultBranch(staticContext *StaticGitContext) (*string, error) { + client := g.getApiClient() + ctx := context.Background() + repo, _, err := client.RepositoriesApi.GetV5ReposOwnerRepo(ctx, staticContext.Owner, staticContext.Name, nil) + if err != nil { + return nil, err + } + + return &repo.DefaultBranch, nil +} + +func (g *GiteeGitProvider) GetUrlFromContext(repoContext *GetRepositoryContext) string { + url := strings.TrimSuffix(repoContext.Url, ".git") + + if repoContext.Branch != nil && *repoContext.Branch != "" { + if repoContext.Sha != nil && *repoContext.Sha == *repoContext.Branch { + //https://gitee.com///commit/ + if repoContext.Path != nil { + url += "/blob/" + *repoContext.Sha + "/" + *repoContext.Path + } else { + url += "/commit/" + *repoContext.Branch + } + } else { + if repoContext.Path != nil { + url += "/blob/" + *repoContext.Branch + "/" + *repoContext.Path + } else { + url += "/tree/" + *repoContext.Branch + } + } + } else if repoContext.Path != nil { + url += "/blob/master/" + *repoContext.Path + } + + return url +} + +func (g *GiteeGitProvider) ParseStaticGitContext(repoUrl string) (*StaticGitContext, error) { + staticContext, err := g.AbstractGitProvider.ParseStaticGitContext(repoUrl) + if err != nil { + return nil, err + } + + if staticContext.Path == nil { + return staticContext, nil + } + + parts := strings.Split(*staticContext.Path, "/") + + switch { + case len(parts) >= 2 && parts[0] == "pulls": + prNumber, err := strconv.Atoi(parts[1]) + if err != nil { + return nil, err + } + prUint := uint32(prNumber) + staticContext.PrNumber = &prUint + staticContext.Path = nil + + case len(parts) >= 2 && parts[0] == "commit": + staticContext.Sha = &parts[1] + staticContext.Branch = staticContext.Sha + staticContext.Path = nil + + case len(parts) >= 2 && (parts[0] == "commits" || parts[0] == "tree"): + staticContext.Branch = &parts[1] + staticContext.Path = nil + + case len(parts) >= 2 && parts[0] == "blob": + staticContext.Sha = &parts[1] + staticContext.Branch = staticContext.Sha + path := strings.Join(parts[2:], "/") + staticContext.Path = &path + + } + + return staticContext, nil +} + +func (g *GiteeGitProvider) GetPrContext(staticContext *StaticGitContext) (*StaticGitContext, error) { + if staticContext.PrNumber == nil { + return staticContext, nil + } + client := g.getApiClient() + ctx := context.Background() + pr, _, err := client.PullRequestsApi.GetV5ReposOwnerRepoPullsNumber(ctx, staticContext.Owner, staticContext.Name, int32(*staticContext.PrNumber), nil) + if err != nil { + return nil, fmt.Errorf("failed to get PR context: %w", err) + } + + repo := *staticContext + repo.Branch = &pr.Head.Ref + repo.Url = pr.Head.Repo.HtmlUrl + repo.Name = pr.Head.Repo.Name + repo.Id = pr.Head.Repo.Name + repo.Owner = pr.Head.Repo.Owner.Login + return &repo, nil +} + +func (g *GiteeGitProvider) performRequest(method, requestURL string) ([]byte, error) { + req, err := http.NewRequestWithContext(context.Background(), method, requestURL, nil) + if err != nil { + return nil, err + } + + req.Header.Set("Accept", "application/json") + req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", g.token)) + + client := &http.Client{} + res, err := client.Do(req) + if err != nil { + return nil, err + } + defer res.Body.Close() + + body, err := io.ReadAll(res.Body) + if err != nil { + return nil, err + } + + if res.StatusCode >= 400 { + return nil, fmt.Errorf("status code: %d err: %s", res.StatusCode, string(body)) + } + + return body, nil +} diff --git a/pkg/gitprovider/gitee_test.go b/pkg/gitprovider/gitee_test.go new file mode 100644 index 0000000000..15fd3cb20a --- /dev/null +++ b/pkg/gitprovider/gitee_test.go @@ -0,0 +1,183 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package gitprovider + +import ( + "testing" + + "github.com/daytonaio/daytona/internal/util" + "github.com/stretchr/testify/suite" +) + +type GiteeGitProviderTestSuite struct { + gitProvider *GiteeGitProvider + suite.Suite +} + +func NewGiteeGitProviderTestSuite() *GiteeGitProviderTestSuite { + return &GiteeGitProviderTestSuite{ + gitProvider: NewGiteeGitProvider(""), + } +} + +func (g *GiteeGitProviderTestSuite) TestCanHandle() { + repoUrl := "https://gitee.com/daytonaio/daytona" + require := g.Require() + canHandle, _ := g.gitProvider.CanHandle(repoUrl) + require.True(canHandle) +} + +func (g *GiteeGitProviderTestSuite) TestCanHandle_False() { + repoUrl := "https://github.com/daytonaio/daytona" + require := g.Require() + canHandle, _ := g.gitProvider.CanHandle(repoUrl) + require.False(canHandle) +} + +func (g *GiteeGitProviderTestSuite) TestParseStaticGitContext_PR() { + prUrl := "https://gitee.com/daytonaio/daytona/pulls/1" + prContext := &StaticGitContext{ + Id: "daytona", + Name: "daytona", + Owner: "daytonaio", + Url: "https://gitee.com/daytonaio/daytona.git", + Source: "gitee.com", + Branch: nil, + Sha: nil, + PrNumber: util.Pointer(uint32(1)), + Path: nil, + } + + require := g.Require() + + httpContext, err := g.gitProvider.ParseStaticGitContext(prUrl) + + require.Nil(err) + require.Equal(httpContext, prContext) +} + +func (g *GiteeGitProviderTestSuite) TestParseStaticGitContext_Blob() { + blobUrl := "https://gitee.com/daytonaio/daytona/blob/fff62f9717b0e4d2f9262d159b90f24efc626021/README.en.md" + blobContext := &StaticGitContext{ + Id: "daytona", + Name: "daytona", + Owner: "daytonaio", + Url: "https://gitee.com/daytonaio/daytona.git", + Source: "gitee.com", + Branch: util.Pointer("fff62f9717b0e4d2f9262d159b90f24efc626021"), + Sha: util.Pointer("fff62f9717b0e4d2f9262d159b90f24efc626021"), + PrNumber: nil, + Path: util.Pointer("README.en.md"), + } + + require := g.Require() + + httpContext, err := g.gitProvider.ParseStaticGitContext(blobUrl) + + require.Nil(err) + require.Equal(httpContext, blobContext) +} + +func (g *GiteeGitProviderTestSuite) TestParseStaticGitContext_Branch() { + branchUrl := "https://gitee.com/daytonaio/daytona/tree/test" + branchContext := &StaticGitContext{ + Id: "daytona", + Name: "daytona", + Owner: "daytonaio", + Url: "https://gitee.com/daytonaio/daytona.git", + Source: "gitee.com", + Branch: util.Pointer("test"), + Sha: nil, + PrNumber: nil, + Path: nil, + } + + require := g.Require() + + httpContext, err := g.gitProvider.ParseStaticGitContext(branchUrl) + + require.Nil(err) + require.Equal(httpContext, branchContext) +} + +func (g *GiteeGitProviderTestSuite) TestParseStaticGitContext_Commits() { + commitsUrl := "https://gitee.com/daytonaio/daytona/commits/master" + commitsContext := &StaticGitContext{ + Id: "daytona", + Name: "daytona", + Owner: "daytonaio", + Url: "https://gitee.com/daytonaio/daytona.git", + Source: "gitee.com", + Branch: util.Pointer("master"), + Sha: nil, + PrNumber: nil, + Path: nil, + } + + require := g.Require() + + httpContext, err := g.gitProvider.ParseStaticGitContext(commitsUrl) + + require.Nil(err) + require.Equal(httpContext, commitsContext) +} + +func (g *GiteeGitProviderTestSuite) TestParseStaticGitContext_Commit() { + commitUrl := "https://gitee.com/daytonaio/daytona/commit/fff62f9717b0e4d2f9262d159b90f24efc626021" + commitContext := &StaticGitContext{ + Id: "daytona", + Name: "daytona", + Owner: "daytonaio", + Url: "https://gitee.com/daytonaio/daytona.git", + Source: "gitee.com", + Branch: util.Pointer("fff62f9717b0e4d2f9262d159b90f24efc626021"), + Sha: util.Pointer("fff62f9717b0e4d2f9262d159b90f24efc626021"), + PrNumber: nil, + Path: nil, + } + + require := g.Require() + + httpContext, err := g.gitProvider.ParseStaticGitContext(commitUrl) + + require.Nil(err) + require.Equal(httpContext, commitContext) +} + +func (g *GiteeGitProviderTestSuite) TestGetUrlFromRepo_Bare() { + repo := &GetRepositoryContext{ + Id: util.Pointer("daytona"), + Name: util.Pointer("daytona"), + Owner: util.Pointer("daytonaio"), + Source: util.Pointer("gitee.com"), + Url: "https://gitee.com/daytonaio/daytona.git", + } + + require := g.Require() + + url := g.gitProvider.GetUrlFromContext(repo) + + require.Equal("https://gitee.com/daytonaio/daytona", url) +} + +func (g *GiteeGitProviderTestSuite) TestGetUrlFromRepo_Branch() { + repo := &GetRepositoryContext{ + Id: util.Pointer("daytona"), + Name: util.Pointer("daytona"), + Owner: util.Pointer("daytonaio"), + Source: util.Pointer("gitee.com"), + Url: "https://gitee.com/daytonaio/daytona.git", + Branch: util.Pointer("test"), + } + + require := g.Require() + + url := g.gitProvider.GetUrlFromContext(repo) + + require.Equal("https://gitee.com/daytonaio/daytona/tree/test", url) +} + +func TestGiteeGitProvider(t *testing.T) { + suite.Run(t, NewGiteeGitProviderTestSuite()) +} diff --git a/pkg/server/gitproviders/service.go b/pkg/server/gitproviders/service.go index 98d038c407..8a48c13c0b 100644 --- a/pkg/server/gitproviders/service.go +++ b/pkg/server/gitproviders/service.go @@ -184,6 +184,8 @@ func (s *GitProviderService) newGitProvider(config *gitprovider.GitProviderConfi return gitprovider.NewAwsCodeCommitGitProvider(baseApiUrl), nil case "gogs": return gitprovider.NewGogsGitProvider(config.Token, baseApiUrl), nil + case "gitee": + return gitprovider.NewGiteeGitProvider(config.Token), nil default: return nil, errors.New("git provider not found") }