mirror of https://github.com/databricks/cli.git
Added CloneOptions and passing context object around
This commit is contained in:
parent
5f9ec5dd29
commit
ac6cf0fec4
|
@ -1,6 +1,8 @@
|
||||||
package internal
|
package internal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -8,14 +10,51 @@ import (
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestAccGitClonePrivateRepository(t *testing.T) {
|
// TODO: add assertion that the git tool is not called, maybe by voiding PATH
|
||||||
|
// TODO: add assertion for error if git CLI is not found
|
||||||
|
func TestGitClonePublicRepository(t *testing.T) {
|
||||||
|
// t.Log(GetEnvOrSkipTest(t, "CLOUD_ENV"))
|
||||||
|
|
||||||
tmpDir := t.TempDir()
|
tmpDir := t.TempDir()
|
||||||
|
ctx := context.Background()
|
||||||
|
var err error
|
||||||
|
|
||||||
|
// We unset PATH to ensure that git.Clone cannot rely on the git CLI
|
||||||
|
t.Setenv("PATH", "")
|
||||||
|
|
||||||
|
err = git.Clone(ctx, git.CloneOptions{
|
||||||
|
Provider: "github",
|
||||||
|
Organization: "databricks",
|
||||||
|
RepositoryName: "cli",
|
||||||
|
Reference: "main",
|
||||||
|
TargetDir: tmpDir,
|
||||||
|
})
|
||||||
|
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.DirExists(t, filepath.Join(tmpDir, "cli-main"))
|
||||||
|
|
||||||
|
b, err := os.ReadFile(filepath.Join(tmpDir, "cli-main/NOTICE"))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Contains(t, string(b), "Copyright (2023) Databricks, Inc.")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAccGitClonePrivateRepository(t *testing.T) {
|
||||||
|
// t.Log(GetEnvOrSkipTest(t, "CLOUD_ENV"))
|
||||||
|
|
||||||
|
tmpDir := t.TempDir()
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
// This is a private repository only accessible to databricks employees
|
// This is a private repository only accessible to databricks employees
|
||||||
err := git.Clone("databricks", "bundle-samples-internal", tmpDir)
|
err := git.Clone(ctx, git.CloneOptions{
|
||||||
|
Provider: "github",
|
||||||
|
Organization: "databricks",
|
||||||
|
RepositoryName: "bundle-samples-internal",
|
||||||
|
Reference: "main",
|
||||||
|
TargetDir: tmpDir,
|
||||||
|
})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// assert examples from the private repository
|
// assert examples from the private repository
|
||||||
assert.DirExists(t, filepath.Join(tmpDir, "shark_sightings"))
|
assert.DirExists(t, filepath.Join(tmpDir, "bundle-samples-internal-main", "shark_sightings"))
|
||||||
assert.DirExists(t, filepath.Join(tmpDir, "wikipedia_clickstream"))
|
assert.DirExists(t, filepath.Join(tmpDir, "bundle-samples-internal-main", "wikipedia_clickstream"))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package git
|
package git
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
@ -14,14 +15,6 @@ import (
|
||||||
|
|
||||||
var errNotFound = errors.New("not found")
|
var errNotFound = errors.New("not found")
|
||||||
|
|
||||||
func githubZipUrl(org string, name string, ref string) string {
|
|
||||||
return fmt.Sprintf(`%s/archive/%s.zip`, githubUrl(org, name), ref)
|
|
||||||
}
|
|
||||||
|
|
||||||
func githubUrl(org string, name string) string {
|
|
||||||
return fmt.Sprintf(`https://github.com/%s/%s`, org, name)
|
|
||||||
}
|
|
||||||
|
|
||||||
type RepositoryNotFoundError struct {
|
type RepositoryNotFoundError struct {
|
||||||
url string
|
url string
|
||||||
}
|
}
|
||||||
|
@ -34,9 +27,42 @@ func (err RepositoryNotFoundError) Is(other error) bool {
|
||||||
return other == errNotFound
|
return other == errNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: pass context to these the get requests
|
type CloneOptions struct {
|
||||||
func download(url string, dest string) error {
|
// Name of the organization or profile with the repository
|
||||||
resp, err := http.Get(url)
|
Organization string
|
||||||
|
RepositoryName string
|
||||||
|
|
||||||
|
// Git service provider. Eg: github, gitlab
|
||||||
|
Provider string
|
||||||
|
|
||||||
|
// Branch or tag name to clone
|
||||||
|
Reference string
|
||||||
|
|
||||||
|
// Path to clone into. The repository is cloned as ${RepositoryName}-${Reference}
|
||||||
|
// in this target directory.
|
||||||
|
TargetDir string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (opts CloneOptions) repoUrl() string {
|
||||||
|
return fmt.Sprintf(`https://github.com/%s/%s`, opts.Organization, opts.RepositoryName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (opts CloneOptions) zipUrl() string {
|
||||||
|
return fmt.Sprintf(`%s/archive/%s.zip`, opts.repoUrl(), opts.Reference)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: test this holds true for alternate branches and tags
|
||||||
|
func (opts CloneOptions) destination() string {
|
||||||
|
return filepath.Join(opts.TargetDir, opts.RepositoryName+"-"+opts.Reference)
|
||||||
|
}
|
||||||
|
|
||||||
|
func download(ctx context.Context, url string, dest string) error {
|
||||||
|
// Get request to download the ZIP archive
|
||||||
|
request, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
resp, err := http.DefaultClient.Do(request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -59,45 +85,45 @@ func download(url string, dest string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func clonePrivate(org string, repoName string, targetDir string) error {
|
// TODO: check stdin / stdout works properly with git clone and requesting an ID/password
|
||||||
zipUrl := githubUrl(org, repoName)
|
func clonePrivate(ctx context.Context, opts CloneOptions) error {
|
||||||
|
// TODO: test that the branch --branch flag works with tags
|
||||||
// We append repoName-main to targetDir to be symmetric to clonePublic
|
cmd := exec.CommandContext(ctx, "git", "clone", opts.repoUrl(), opts.destination(), "--branch", opts.Reference)
|
||||||
targetDir = filepath.Join(targetDir, repoName+"-main")
|
|
||||||
|
|
||||||
// TODO: pass context to the command execution
|
|
||||||
cmd := exec.Command("git", "clone", zipUrl, targetDir, "--branch", "main")
|
|
||||||
return cmd.Run()
|
return cmd.Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
func clonePublic(org string, repoName string, targetDir string) error {
|
func clonePublic(ctx context.Context, opts CloneOptions) error {
|
||||||
zipDst := filepath.Join(targetDir, repoName+".zip")
|
zipDst := filepath.Join(opts.TargetDir, opts.RepositoryName+".zip")
|
||||||
zipUrl := githubZipUrl(org, repoName, "main")
|
|
||||||
|
|
||||||
// Download public repository from github as a ZIP file
|
// Download public repository from github as a ZIP file
|
||||||
err := download(zipUrl, zipDst)
|
err := download(ctx, opts.zipUrl(), zipDst)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decompress the ZIP file
|
// Decompress the ZIP file
|
||||||
err = zip.Extract(zipDst, targetDir)
|
err = zip.Extract(zipDst, opts.TargetDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove the ZIP file
|
// Remove the ZIP file post extraction
|
||||||
return os.Remove(zipDst)
|
return os.Remove(zipDst)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Clone(org, repoName string, targetDir string) error {
|
func Clone(ctx context.Context, opts CloneOptions) error {
|
||||||
// First we try to clone the repository as a public URL, as that does not
|
if opts.Provider != "github" {
|
||||||
// require the git CLI
|
return fmt.Errorf("git provider not supported: %s", opts.Provider)
|
||||||
err := clonePublic(org, repoName, targetDir)
|
|
||||||
if err != nil && !errors.Is(err, errNotFound) {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Since a public repository was not found, we defer to the git CLI
|
// First we try to clone the repository as a public URL, as that does not
|
||||||
return clonePrivate(org, repoName, targetDir)
|
// require the git CLI
|
||||||
|
err := clonePublic(ctx, opts)
|
||||||
|
|
||||||
|
// If a public repository was not found, we defer to the git CLI
|
||||||
|
if errors.Is(err, errNotFound) {
|
||||||
|
|
||||||
|
return clonePrivate(ctx, opts)
|
||||||
|
}
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
package git
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestGitClonePublicRepository(t *testing.T) {
|
|
||||||
tmpDir := t.TempDir()
|
|
||||||
var err error
|
|
||||||
|
|
||||||
err = clonePublic("databricks", "cli", tmpDir)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.DirExists(t, filepath.Join(tmpDir, "cli-main"))
|
|
||||||
|
|
||||||
b, err := os.ReadFile(filepath.Join(tmpDir, "cli-main/NOTICE"))
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Contains(t, string(b), "Copyright (2023) Databricks, Inc.")
|
|
||||||
}
|
|
Loading…
Reference in New Issue