Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 213
Add support for cloning repositories#544
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
d55cba253bf15fcf592104957cdaad37e1832b1eec5552c7d38b3de5fdf30e7a3357e2cf71e652142030feb065a77da327d76519828b30790fceb224f9d16238ee5b0ca1cf7e2e2b705c547425File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| package internal | ||
| import ( | ||
| "context" | ||
| "os" | ||
| "path/filepath" | ||
| "testing" | ||
| "github.com/databricks/cli/libs/git" | ||
| "github.com/stretchr/testify/assert" | ||
| ) | ||
| func TestAccGitClone(t *testing.T) { | ||
| t.Log(GetEnvOrSkipTest(t, "CLOUD_ENV")) | ||
| tmpDir := t.TempDir() | ||
| ctx := context.Background() | ||
| var err error | ||
| err = git.Clone(ctx, "https://github.com/databricks/databricks-empty-ide-project.git", "", tmpDir) | ||
| assert.NoError(t, err) | ||
| // assert repo content | ||
| assert.NoError(t, err) | ||
| b, err := os.ReadFile(filepath.Join(tmpDir, "README-IDE.md")) | ||
| assert.NoError(t, err) | ||
| assert.Contains(t, string(b), "This folder contains a project that was synchronized from an IDE.") | ||
| // assert current branch is ide, ie default for the repo | ||
| b, err = os.ReadFile(filepath.Join(tmpDir, ".git/HEAD")) | ||
| assert.NoError(t, err) | ||
| assert.Contains(t, string(b), "ide") | ||
| } | ||
| func TestAccGitCloneWithOnlyRepoNameOnAlternateBranch(t *testing.T) { | ||
| t.Log(GetEnvOrSkipTest(t, "CLOUD_ENV")) | ||
| tmpDir := t.TempDir() | ||
| ctx := context.Background() | ||
| var err error | ||
| err = git.Clone(ctx, "notebook-best-practices", "dais-2022", tmpDir) | ||
| // assert on repo content | ||
| assert.NoError(t, err) | ||
| b, err := os.ReadFile(filepath.Join(tmpDir, "README.md")) | ||
| assert.NoError(t, err) | ||
| assert.Contains(t, string(b), "Software engineering best practices for Databricks notebooks") | ||
| // assert current branch is main, ie default for the repo | ||
| b, err = os.ReadFile(filepath.Join(tmpDir, ".git/HEAD")) | ||
| assert.NoError(t, err) | ||
| assert.Contains(t, string(b), "dais-2022") | ||
| } | ||
| func TestAccGitCloneRepositoryDoesNotExist(t *testing.T) { | ||
| t.Log(GetEnvOrSkipTest(t, "CLOUD_ENV")) | ||
| tmpDir := t.TempDir() | ||
| err := git.Clone(context.Background(), "doesnot-exist", "", tmpDir) | ||
| assert.Contains(t, err.Error(), `repository 'https://github.com/databricks/doesnot-exist/' not found`) | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| package git | ||
| import ( | ||
| "bytes" | ||
| "context" | ||
| "errors" | ||
| "fmt" | ||
| "os/exec" | ||
| "regexp" | ||
| "strings" | ||
| ) | ||
| // source: https://stackoverflow.com/questions/59081778/rules-for-special-characters-in-github-repository-name | ||
| var githubRepoRegex = regexp.MustCompile(`^[\w-\.]+$`) | ||
| const githubUrl = "https://github.com" | ||
| const databricksOrg = "databricks" | ||
| type cloneOptions struct { | ||
| // Branch or tag to clone | ||
| Reference string | ||
| // URL for the repository | ||
| RepositoryUrl string | ||
| // Local path to clone repository at | ||
| TargetPath string | ||
| } | ||
| func (opts cloneOptions) args() []string { | ||
| args := []string{"clone", opts.RepositoryUrl, opts.TargetPath, "--depth=1", "--no-tags"} | ||
| if opts.Reference != "" { | ||
| args = append(args, "--branch", opts.Reference) | ||
| } | ||
| return args | ||
| } | ||
| func Clone(ctx context.Context, url, reference, targetPath string) error { | ||
Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The argument suggests Which one applies?
| ||
| // We assume only the repository name has been if input does not contain any | ||
| // `/` characters and the url is only made up of alphanumeric characters and | ||
| // ".", "_" and "-". This repository is resolved again databricks github account. | ||
| fullUrl := url | ||
| if githubRepoRegex.MatchString(url) { | ||
| fullUrl = strings.Join([]string{githubUrl, databricksOrg, url}, "/") | ||
| } | ||
| opts := cloneOptions{ | ||
| Reference: reference, | ||
| RepositoryUrl: fullUrl, | ||
| TargetPath: targetPath, | ||
| } | ||
| cmd := exec.CommandContext(ctx, "git", opts.args()...) | ||
| var cmdErr bytes.Buffer | ||
| cmd.Stderr = &cmdErr | ||
| // start git clone | ||
| err := cmd.Start() | ||
shreyas-goenka marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| if errors.Is(err, exec.ErrNotFound) { | ||
| return fmt.Errorf("please install git CLI to clone a repository: %w", err) | ||
| } | ||
| if err != nil { | ||
| return err | ||
| } | ||
| // wait for git clone to complete | ||
| err = cmd.Wait() | ||
| if err != nil { | ||
| return fmt.Errorf("git clone failed: %w. %s", err, cmdErr.String()) | ||
| } | ||
| return nil | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| package git | ||
| import ( | ||
| "context" | ||
| "os/exec" | ||
| "testing" | ||
| "github.com/stretchr/testify/assert" | ||
| ) | ||
| func TestGitCloneArgs(t *testing.T) { | ||
| // case: No branch / tag specified. In this case git clones the default branch | ||
| assert.Equal(t, []string{"clone", "abc", "/def", "--depth=1", "--no-tags"}, cloneOptions{ | ||
| Reference: "", | ||
| RepositoryUrl: "abc", | ||
| TargetPath: "/def", | ||
| }.args()) | ||
| // case: A branch is specified. | ||
| assert.Equal(t, []string{"clone", "abc", "/def", "--depth=1", "--no-tags", "--branch", "my-branch"}, cloneOptions{ | ||
| Reference: "my-branch", | ||
| RepositoryUrl: "abc", | ||
| TargetPath: "/def", | ||
| }.args()) | ||
| } | ||
| func TestGitCloneWithGitNotFound(t *testing.T) { | ||
| // We set $PATH here so the git CLI cannot be found by the clone function | ||
| t.Setenv("PATH", "") | ||
| tmpDir := t.TempDir() | ||
| err := Clone(context.Background(), "abc", "", tmpDir) | ||
| assert.ErrorIs(t, err, exec.ErrNotFound) | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.