Add function to opportunistically load a bundle (#180)

It is not an error if a bundle cannot be found for this category.
This sets the stage for using bundle configuration in non-bundle
commands.
This commit is contained in:
Pieter Noordhuis 2023-01-27 16:57:39 +01:00 committed by GitHub
parent 035fb6514d
commit 9a1d908f79
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 110 additions and 25 deletions

View File

@ -41,8 +41,10 @@ func Load(path string) (*Bundle, error) {
return bundle, nil return bundle, nil
} }
func LoadFromRoot() (*Bundle, error) { // MustLoad returns a bundle configuration.
root, err := getRoot() // It returns an error if a bundle was not found or could not be loaded.
func MustLoad() (*Bundle, error) {
root, err := mustGetRoot()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -50,6 +52,23 @@ func LoadFromRoot() (*Bundle, error) {
return Load(root) return Load(root)
} }
// TryLoad returns a bundle configuration if there is one, but doesn't fail if there isn't one.
// It returns an error if a bundle was found but could not be loaded.
// It returns a `nil` bundle if a bundle was not found.
func TryLoad() (*Bundle, error) {
root, err := tryGetRoot()
if err != nil {
return nil, err
}
// No root is fine in this function.
if root == "" {
return nil, nil
}
return Load(root)
}
func (b *Bundle) WorkspaceClient() *databricks.WorkspaceClient { func (b *Bundle) WorkspaceClient() *databricks.WorkspaceClient {
b.clientOnce.Do(func() { b.clientOnce.Do(func() {
var err error var err error

View File

@ -39,3 +39,42 @@ func TestBundleCacheDir(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
assert.True(t, strings.HasPrefix(cacheDir, projectDir)) assert.True(t, strings.HasPrefix(cacheDir, projectDir))
} }
func TestBundleMustLoadSuccess(t *testing.T) {
t.Setenv(envBundleRoot, "./tests/basic")
b, err := MustLoad()
require.NoError(t, err)
assert.Equal(t, "./tests/basic", b.Config.Path)
}
func TestBundleMustLoadFailureWithEnv(t *testing.T) {
t.Setenv(envBundleRoot, "./tests/doesntexist")
_, err := MustLoad()
require.Error(t, err, "not a directory")
}
func TestBundleMustLoadFailureIfNotFound(t *testing.T) {
chdir(t, t.TempDir())
_, err := MustLoad()
require.Error(t, err, "unable to find bundle root")
}
func TestBundleTryLoadSuccess(t *testing.T) {
t.Setenv(envBundleRoot, "./tests/basic")
b, err := TryLoad()
require.NoError(t, err)
assert.Equal(t, "./tests/basic", b.Config.Path)
}
func TestBundleTryLoadFailureWithEnv(t *testing.T) {
t.Setenv(envBundleRoot, "./tests/doesntexist")
_, err := TryLoad()
require.Error(t, err, "not a directory")
}
func TestBundleTryLoadOkIfNotFound(t *testing.T) {
chdir(t, t.TempDir())
b, err := TryLoad()
assert.NoError(t, err)
assert.Nil(t, b)
}

View File

@ -10,13 +10,15 @@ import (
const envBundleRoot = "BUNDLE_ROOT" const envBundleRoot = "BUNDLE_ROOT"
// getRoot returns the bundle root. // getRootEnv returns the value of the `BUNDLE_ROOT` environment variable
// If the `BUNDLE_ROOT` environment variable is set, we assume its value // if it set and is a directory. If the environment variable is set but
// to be a valid bundle root. Otherwise we try to find it by traversing // is not a directory, it returns an error. If the environment variable is
// the path and looking for a project configuration file. // not set, it returns an empty string.
func getRoot() (string, error) { func getRootEnv() (string, error) {
path, ok := os.LookupEnv(envBundleRoot) path, ok := os.LookupEnv(envBundleRoot)
if ok { if !ok {
return "", nil
}
stat, err := os.Stat(path) stat, err := os.Stat(path)
if err == nil && !stat.IsDir() { if err == nil && !stat.IsDir() {
err = fmt.Errorf("not a directory") err = fmt.Errorf("not a directory")
@ -26,13 +28,38 @@ func getRoot() (string, error) {
} }
return path, nil return path, nil
} }
// getRootWithTraversal returns the bundle root by traversing the filesystem
// from the working directory to the root looking for a configuration file.
func getRootWithTraversal() (string, error) {
wd, err := os.Getwd() wd, err := os.Getwd()
if err != nil { if err != nil {
return "", err return "", err
} }
path, err = folders.FindDirWithLeaf(wd, config.FileName) path, err := folders.FindDirWithLeaf(wd, config.FileName)
if err != nil { if err != nil {
return "", fmt.Errorf(`unable to locate bundle root`) return "", fmt.Errorf(`unable to locate bundle root: %s not found`, config.FileName)
} }
return path, nil return path, nil
} }
// mustGetRoot returns a bundle root or an error if one cannot be found.
func mustGetRoot() (string, error) {
path, err := getRootEnv()
if path != "" || err != nil {
return path, err
}
return getRootWithTraversal()
}
// tryGetRoot returns a bundle root or an empty string if one cannot be found.
func tryGetRoot() (string, error) {
// Note: an invalid value in the environment variable is still an error.
path, err := getRootEnv()
if path != "" || err != nil {
return path, err
}
// Note: traversal failing means the bundle root cannot be found.
path, _ = getRootWithTraversal()
return path, nil
}

View File

@ -34,7 +34,7 @@ func TestRootFromEnv(t *testing.T) {
t.Setenv(envBundleRoot, dir) t.Setenv(envBundleRoot, dir)
// It should pull the root from the environment variable. // It should pull the root from the environment variable.
root, err := getRoot() root, err := mustGetRoot()
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, root, dir) require.Equal(t, root, dir)
} }
@ -44,7 +44,7 @@ func TestRootFromEnvDoesntExist(t *testing.T) {
t.Setenv(envBundleRoot, filepath.Join(dir, "doesntexist")) t.Setenv(envBundleRoot, filepath.Join(dir, "doesntexist"))
// It should pull the root from the environment variable. // It should pull the root from the environment variable.
_, err := getRoot() _, err := mustGetRoot()
require.Errorf(t, err, "invalid bundle root") require.Errorf(t, err, "invalid bundle root")
} }
@ -56,7 +56,7 @@ func TestRootFromEnvIsFile(t *testing.T) {
t.Setenv(envBundleRoot, f.Name()) t.Setenv(envBundleRoot, f.Name())
// It should pull the root from the environment variable. // It should pull the root from the environment variable.
_, err = getRoot() _, err = mustGetRoot()
require.Errorf(t, err, "invalid bundle root") require.Errorf(t, err, "invalid bundle root")
} }
@ -65,7 +65,7 @@ func TestRootIfEnvIsEmpty(t *testing.T) {
t.Setenv(envBundleRoot, dir) t.Setenv(envBundleRoot, dir)
// It should pull the root from the environment variable. // It should pull the root from the environment variable.
_, err := getRoot() _, err := mustGetRoot()
require.Errorf(t, err, "invalid bundle root") require.Errorf(t, err, "invalid bundle root")
} }
@ -87,7 +87,7 @@ func TestRootLookup(t *testing.T) {
// It should find the project root from $PWD. // It should find the project root from $PWD.
wd := chdir(t, "./a/b/c") wd := chdir(t, "./a/b/c")
root, err := getRoot() root, err := mustGetRoot()
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, wd, root) require.Equal(t, wd, root)
} }
@ -99,6 +99,6 @@ func TestRootLookupError(t *testing.T) {
// It can't find a project root from a temporary directory. // It can't find a project root from a temporary directory.
_ = chdir(t, t.TempDir()) _ = chdir(t, t.TempDir())
_, err := getRoot() _, err := mustGetRoot()
require.ErrorContains(t, err, "unable to locate bundle root") require.ErrorContains(t, err, "unable to locate bundle root")
} }

View File

@ -17,7 +17,7 @@ var rootCmd = &cobra.Command{
// and configures it on the command's context. // and configures it on the command's context.
func ConfigureBundle(cmd *cobra.Command, args []string) error { func ConfigureBundle(cmd *cobra.Command, args []string) error {
ctx := cmd.Context() ctx := cmd.Context()
b, err := bundle.LoadFromRoot() b, err := bundle.MustLoad()
if err != nil { if err != nil {
return err return err
} }