diff --git a/cmd/workspace/repos/overrides.go b/cmd/workspace/repos/overrides.go index 9f131c03..44d9dca4 100644 --- a/cmd/workspace/repos/overrides.go +++ b/cmd/workspace/repos/overrides.go @@ -17,6 +17,42 @@ func init() { {{range .}}{{green "%d" .Id}} {{.Path}} {{.Branch|blue}} {{.Url|cyan}} {{end}}`) + createCmd.Use = "create URL [PROVIDER]" + createCmd.Args = func(cmd *cobra.Command, args []string) error { + // If the provider argument is not specified, we try to detect it from the URL. + check := cobra.RangeArgs(1, 2) + if cmd.Flags().Changed("json") { + check = cobra.ExactArgs(0) + } + return check(cmd, args) + } + createCmd.RunE = func(cmd *cobra.Command, args []string) (err error) { + ctx := cmd.Context() + w := root.WorkspaceClient(ctx) + if cmd.Flags().Changed("json") { + err = createJson.Unmarshal(&createReq) + if err != nil { + return err + } + } else { + createReq.Url = args[0] + if len(args) > 1 { + createReq.Provider = args[1] + } else { + createReq.Provider = DetectProvider(createReq.Url) + if createReq.Provider == "" { + return fmt.Errorf( + "could not detect provider from URL %q; please specify", createReq.Url) + } + } + } + response, err := w.Repos.Create(ctx, createReq) + if err != nil { + return err + } + return cmdio.Render(ctx, response) + } + deleteCmd.Use = "delete REPO_ID_OR_PATH" deleteCmd.RunE = func(cmd *cobra.Command, args []string) (err error) { ctx := cmd.Context() diff --git a/cmd/workspace/repos/provider.go b/cmd/workspace/repos/provider.go new file mode 100644 index 00000000..9e407e2b --- /dev/null +++ b/cmd/workspace/repos/provider.go @@ -0,0 +1,30 @@ +package repos + +import ( + "net/url" + "regexp" + "strings" +) + +var gitProviders = map[string]string{ + "github.com": "gitHub", + "dev.azure.com": "azureDevOpsServices", + "gitlab.com": "gitLab", + "bitbucket.org": "bitbucketCloud", +} + +var awsCodeCommitRegexp = regexp.MustCompile(`^git-codecommit\.[^.]+\.amazonaws.com$`) + +func DetectProvider(rawURL string) string { + provider := "" + u, err := url.Parse(rawURL) + if err != nil { + return provider + } + if v, ok := gitProviders[strings.ToLower(u.Host)]; ok { + provider = v + } else if awsCodeCommitRegexp.MatchString(u.Host) { + provider = "awsCodeCommit" + } + return provider +} diff --git a/cmd/workspace/repos/provider_test.go b/cmd/workspace/repos/provider_test.go new file mode 100644 index 00000000..e719be2b --- /dev/null +++ b/cmd/workspace/repos/provider_test.go @@ -0,0 +1,21 @@ +package repos + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestDetectProvider(t *testing.T) { + for url, provider := range map[string]string{ + "https://user@bitbucket.org/user/repo.git": "bitbucketCloud", + "https://github.com//user/repo.git": "gitHub", + "https://user@dev.azure.com/user/project/_git/repo": "azureDevOpsServices", + "https://abc/user/repo.git": "", + "ewfgwergfwe": "", + "https://foo@@bar": "", + "https://git-codecommit.us-east-2.amazonaws.com/v1/repos/MyDemoRepo": "awsCodeCommit", + } { + assert.Equal(t, provider, DetectProvider(url)) + } +} diff --git a/internal/repos_test.go b/internal/repos_test.go index 957952ca..340de334 100644 --- a/internal/repos_test.go +++ b/internal/repos_test.go @@ -13,28 +13,70 @@ import ( "github.com/stretchr/testify/require" ) -func createTemporaryRepo(t *testing.T, w *databricks.WorkspaceClient, ctx context.Context) (int64, string) { +func synthesizeTemporaryRepoPath(t *testing.T, w *databricks.WorkspaceClient, ctx context.Context) string { me, err := w.CurrentUser.Me(ctx) require.NoError(t, err) - repoPath := fmt.Sprintf("/Repos/%s/%s", me.UserName, RandomName("empty-repo-integration-")) + + // Cleanup if repo was created at specified path. + t.Cleanup(func() { + oi, err := w.Workspace.GetStatusByPath(ctx, repoPath) + if apierr.IsMissing(err) { + return + } + require.NoError(t, err) + err = w.Repos.DeleteByRepoId(ctx, oi.ObjectId) + require.NoError(t, err) + }) + + return repoPath +} + +func createTemporaryRepo(t *testing.T, w *databricks.WorkspaceClient, ctx context.Context) (int64, string) { + repoPath := synthesizeTemporaryRepoPath(t, w, ctx) repoInfo, err := w.Repos.Create(ctx, workspace.CreateRepo{ Path: repoPath, Url: repoUrl, Provider: "gitHub", }) require.NoError(t, err) - - t.Cleanup(func() { - err := w.Repos.DeleteByRepoId(ctx, repoInfo.Id) - if !apierr.IsMissing(err) { - assert.NoError(t, err) - } - }) - return repoInfo.Id, repoPath } +func TestReposCreateWithProvider(t *testing.T) { + t.Log(GetEnvOrSkipTest(t, "CLOUD_ENV")) + + ctx := context.Background() + w, err := databricks.NewWorkspaceClient() + require.NoError(t, err) + repoPath := synthesizeTemporaryRepoPath(t, w, ctx) + + _, stderr := RequireSuccessfulRun(t, "repos", "create", repoUrl, "gitHub", "--path", repoPath) + assert.Equal(t, "", stderr.String()) + + // Confirm the repo was created. + oi, err := w.Workspace.GetStatusByPath(ctx, repoPath) + assert.NoError(t, err) + assert.Equal(t, workspace.ObjectTypeRepo, oi.ObjectType) +} + +func TestReposCreateWithoutProvider(t *testing.T) { + t.Log(GetEnvOrSkipTest(t, "CLOUD_ENV")) + + ctx := context.Background() + w, err := databricks.NewWorkspaceClient() + require.NoError(t, err) + repoPath := synthesizeTemporaryRepoPath(t, w, ctx) + + _, stderr := RequireSuccessfulRun(t, "repos", "create", repoUrl, "--path", repoPath) + assert.Equal(t, "", stderr.String()) + + // Confirm the repo was created. + oi, err := w.Workspace.GetStatusByPath(ctx, repoPath) + assert.NoError(t, err) + assert.Equal(t, workspace.ObjectTypeRepo, oi.ObjectType) +} + func TestReposGet(t *testing.T) { t.Log(GetEnvOrSkipTest(t, "CLOUD_ENV"))