mirror of https://github.com/databricks/cli.git
Added support for bundle.Seq, simplified Mutator.Apply interface (#403)
## Changes Added support for `bundle.Seq`, simplified `Mutator.Apply` interface by removing list of mutators from return values/ ## Tests 1. Ran `cli bundle deploy` and interrupted it with Cmd + C mid execution so lock is not released 2. Ran `cli bundle deploy` top make sure that CLI is not trying to release lock when it fail to acquire it ``` andrew.nester@HFW9Y94129 multiples-tasks % cli bundle deploy Starting upload of bundle files Uploaded bundle files at /Users/andrew.nester@databricks.com/.bundle/simple-task/development/files! ^C andrew.nester@HFW9Y94129 multiples-tasks % cli bundle deploy Error: deploy lock acquired by andrew.nester@databricks.com at 2023-05-24 12:10:23.050343 +0200 CEST. Use --force to override ```
This commit is contained in:
parent
273271bc59
commit
6141476ca2
|
@ -20,7 +20,7 @@ func (m *all) Name() string {
|
|||
return fmt.Sprintf("artifacts.%sAll", m.name)
|
||||
}
|
||||
|
||||
func (m *all) Apply(ctx context.Context, b *bundle.Bundle) ([]bundle.Mutator, error) {
|
||||
func (m *all) Apply(ctx context.Context, b *bundle.Bundle) error {
|
||||
var out []bundle.Mutator
|
||||
|
||||
// Iterate with stable ordering.
|
||||
|
@ -30,12 +30,12 @@ func (m *all) Apply(ctx context.Context, b *bundle.Bundle) ([]bundle.Mutator, er
|
|||
for _, name := range keys {
|
||||
m, err := m.fn(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
if m != nil {
|
||||
out = append(out, m)
|
||||
}
|
||||
}
|
||||
|
||||
return out, nil
|
||||
return bundle.Apply(ctx, b, bundle.Seq(out...))
|
||||
}
|
||||
|
|
|
@ -27,15 +27,15 @@ func (m *build) Name() string {
|
|||
return fmt.Sprintf("artifacts.Build(%s)", m.name)
|
||||
}
|
||||
|
||||
func (m *build) Apply(ctx context.Context, b *bundle.Bundle) ([]bundle.Mutator, error) {
|
||||
func (m *build) Apply(ctx context.Context, b *bundle.Bundle) error {
|
||||
artifact, ok := b.Config.Artifacts[m.name]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("artifact doesn't exist: %s", m.name)
|
||||
return fmt.Errorf("artifact doesn't exist: %s", m.name)
|
||||
}
|
||||
|
||||
if artifact.Notebook != nil {
|
||||
return []bundle.Mutator{notebook.Build(m.name)}, nil
|
||||
return bundle.Apply(ctx, b, notebook.Build(m.name))
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -27,10 +27,10 @@ func (m *build) Name() string {
|
|||
return fmt.Sprintf("notebook.Build(%s)", m.name)
|
||||
}
|
||||
|
||||
func (m *build) Apply(_ context.Context, b *bundle.Bundle) ([]bundle.Mutator, error) {
|
||||
func (m *build) Apply(_ context.Context, b *bundle.Bundle) error {
|
||||
a, ok := b.Config.Artifacts[m.name]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("artifact doesn't exist: %s", m.name)
|
||||
return fmt.Errorf("artifact doesn't exist: %s", m.name)
|
||||
}
|
||||
|
||||
artifact := a.Notebook
|
||||
|
@ -44,35 +44,35 @@ func (m *build) Apply(_ context.Context, b *bundle.Bundle) ([]bundle.Mutator, er
|
|||
case ".sql":
|
||||
artifact.Language = workspace.LanguageSql
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid notebook extension: %s", ext)
|
||||
return fmt.Errorf("invalid notebook extension: %s", ext)
|
||||
}
|
||||
|
||||
// Open underlying file.
|
||||
f, err := os.Open(filepath.Join(b.Config.Path, artifact.Path))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to open artifact file %s: %w", artifact.Path, errors.Unwrap(err))
|
||||
return fmt.Errorf("unable to open artifact file %s: %w", artifact.Path, errors.Unwrap(err))
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
// Check that the file contains the notebook marker on its first line.
|
||||
ok, err = hasMarker(artifact.Language, f)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to read artifact file %s: %s", artifact.Path, errors.Unwrap(err))
|
||||
return fmt.Errorf("unable to read artifact file %s: %s", artifact.Path, errors.Unwrap(err))
|
||||
}
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("notebook marker not found in %s", artifact.Path)
|
||||
return fmt.Errorf("notebook marker not found in %s", artifact.Path)
|
||||
}
|
||||
|
||||
// Check that an artifact path is defined.
|
||||
remotePath := b.Config.Workspace.ArtifactsPath
|
||||
if remotePath == "" {
|
||||
return nil, fmt.Errorf("remote artifact path not configured")
|
||||
return fmt.Errorf("remote artifact path not configured")
|
||||
}
|
||||
|
||||
// Store absolute paths.
|
||||
artifact.LocalPath = filepath.Join(b.Config.Path, artifact.Path)
|
||||
artifact.RemotePath = path.Join(remotePath, stripExtension(artifact.Path))
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func stripExtension(path string) string {
|
||||
|
|
|
@ -26,22 +26,22 @@ func (m *upload) Name() string {
|
|||
return fmt.Sprintf("notebook.Upload(%s)", m.name)
|
||||
}
|
||||
|
||||
func (m *upload) Apply(ctx context.Context, b *bundle.Bundle) ([]bundle.Mutator, error) {
|
||||
func (m *upload) Apply(ctx context.Context, b *bundle.Bundle) error {
|
||||
a, ok := b.Config.Artifacts[m.name]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("artifact doesn't exist: %s", m.name)
|
||||
return fmt.Errorf("artifact doesn't exist: %s", m.name)
|
||||
}
|
||||
|
||||
artifact := a.Notebook
|
||||
raw, err := os.ReadFile(artifact.LocalPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to read %s: %w", m.name, errors.Unwrap(err))
|
||||
return fmt.Errorf("unable to read %s: %w", m.name, errors.Unwrap(err))
|
||||
}
|
||||
|
||||
// Make sure target directory exists.
|
||||
err = b.WorkspaceClient().Workspace.MkdirsByPath(ctx, path.Dir(artifact.RemotePath))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to create directory for %s: %w", m.name, err)
|
||||
return fmt.Errorf("unable to create directory for %s: %w", m.name, err)
|
||||
}
|
||||
|
||||
// Import to workspace.
|
||||
|
@ -53,8 +53,8 @@ func (m *upload) Apply(ctx context.Context, b *bundle.Bundle) ([]bundle.Mutator,
|
|||
Content: base64.StdEncoding.EncodeToString(raw),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to import %s: %w", m.name, err)
|
||||
return fmt.Errorf("unable to import %s: %w", m.name, err)
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -27,15 +27,15 @@ func (m *upload) Name() string {
|
|||
return fmt.Sprintf("artifacts.Upload(%s)", m.name)
|
||||
}
|
||||
|
||||
func (m *upload) Apply(ctx context.Context, b *bundle.Bundle) ([]bundle.Mutator, error) {
|
||||
func (m *upload) Apply(ctx context.Context, b *bundle.Bundle) error {
|
||||
artifact, ok := b.Config.Artifacts[m.name]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("artifact doesn't exist: %s", m.name)
|
||||
return fmt.Errorf("artifact doesn't exist: %s", m.name)
|
||||
}
|
||||
|
||||
if artifact.Notebook != nil {
|
||||
return []bundle.Mutator{notebook.Upload(m.name)}, nil
|
||||
return bundle.Apply(ctx, b, notebook.Upload(m.name))
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -247,6 +247,6 @@ func (m *interpolate) Name() string {
|
|||
return "Interpolate"
|
||||
}
|
||||
|
||||
func (m *interpolate) Apply(_ context.Context, b *bundle.Bundle) ([]bundle.Mutator, error) {
|
||||
return nil, m.expand(&b.Config)
|
||||
func (m *interpolate) Apply(_ context.Context, b *bundle.Bundle) error {
|
||||
return m.expand(&b.Config)
|
||||
}
|
||||
|
|
|
@ -24,14 +24,14 @@ func (m *defineDefaultEnvironment) Name() string {
|
|||
return fmt.Sprintf("DefineDefaultEnvironment(%s)", m.name)
|
||||
}
|
||||
|
||||
func (m *defineDefaultEnvironment) Apply(_ context.Context, b *bundle.Bundle) ([]bundle.Mutator, error) {
|
||||
func (m *defineDefaultEnvironment) Apply(_ context.Context, b *bundle.Bundle) error {
|
||||
// Nothing to do if the configuration has at least 1 environment.
|
||||
if len(b.Config.Environments) > 0 {
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// Define default environment.
|
||||
b.Config.Environments = make(map[string]*config.Environment)
|
||||
b.Config.Environments[m.name] = &config.Environment{}
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ import (
|
|||
|
||||
func TestDefaultEnvironment(t *testing.T) {
|
||||
bundle := &bundle.Bundle{}
|
||||
_, err := mutator.DefineDefaultEnvironment().Apply(context.Background(), bundle)
|
||||
err := mutator.DefineDefaultEnvironment().Apply(context.Background(), bundle)
|
||||
require.NoError(t, err)
|
||||
env, ok := bundle.Config.Environments["default"]
|
||||
assert.True(t, ok)
|
||||
|
@ -28,7 +28,7 @@ func TestDefaultEnvironmentAlreadySpecified(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
_, err := mutator.DefineDefaultEnvironment().Apply(context.Background(), bundle)
|
||||
err := mutator.DefineDefaultEnvironment().Apply(context.Background(), bundle)
|
||||
require.NoError(t, err)
|
||||
_, ok := bundle.Config.Environments["default"]
|
||||
assert.False(t, ok)
|
||||
|
|
|
@ -28,9 +28,9 @@ func (m *defineDefaultInclude) Name() string {
|
|||
return "DefineDefaultInclude"
|
||||
}
|
||||
|
||||
func (m *defineDefaultInclude) Apply(_ context.Context, b *bundle.Bundle) ([]bundle.Mutator, error) {
|
||||
func (m *defineDefaultInclude) Apply(_ context.Context, b *bundle.Bundle) error {
|
||||
if len(b.Config.Include) == 0 {
|
||||
b.Config.Include = slices.Clone(m.include)
|
||||
}
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ import (
|
|||
|
||||
func TestDefaultInclude(t *testing.T) {
|
||||
bundle := &bundle.Bundle{}
|
||||
_, err := mutator.DefineDefaultInclude().Apply(context.Background(), bundle)
|
||||
err := mutator.DefineDefaultInclude().Apply(context.Background(), bundle)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []string{"*.yml", "*/*.yml"}, bundle.Config.Include)
|
||||
}
|
||||
|
|
|
@ -19,10 +19,10 @@ func (m *defineDefaultWorkspacePaths) Name() string {
|
|||
return "DefaultWorkspacePaths"
|
||||
}
|
||||
|
||||
func (m *defineDefaultWorkspacePaths) Apply(ctx context.Context, b *bundle.Bundle) ([]bundle.Mutator, error) {
|
||||
func (m *defineDefaultWorkspacePaths) Apply(ctx context.Context, b *bundle.Bundle) error {
|
||||
root := b.Config.Workspace.RootPath
|
||||
if root == "" {
|
||||
return nil, fmt.Errorf("unable to define default workspace paths: workspace root not defined")
|
||||
return fmt.Errorf("unable to define default workspace paths: workspace root not defined")
|
||||
}
|
||||
|
||||
if b.Config.Workspace.FilesPath == "" {
|
||||
|
@ -37,5 +37,5 @@ func (m *defineDefaultWorkspacePaths) Apply(ctx context.Context, b *bundle.Bundl
|
|||
b.Config.Workspace.StatePath = path.Join(root, "state")
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ func TestDefineDefaultWorkspacePaths(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
_, err := mutator.DefineDefaultWorkspacePaths().Apply(context.Background(), bundle)
|
||||
err := mutator.DefineDefaultWorkspacePaths().Apply(context.Background(), bundle)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "/files", bundle.Config.Workspace.FilesPath)
|
||||
assert.Equal(t, "/artifacts", bundle.Config.Workspace.ArtifactsPath)
|
||||
|
@ -37,7 +37,7 @@ func TestDefineDefaultWorkspacePathsAlreadySet(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
_, err := mutator.DefineDefaultWorkspacePaths().Apply(context.Background(), bundle)
|
||||
err := mutator.DefineDefaultWorkspacePaths().Apply(context.Background(), bundle)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "/foo/bar", bundle.Config.Workspace.FilesPath)
|
||||
assert.Equal(t, "/foo/bar", bundle.Config.Workspace.ArtifactsPath)
|
||||
|
|
|
@ -18,17 +18,17 @@ func (m *defineDefaultWorkspaceRoot) Name() string {
|
|||
return "DefineDefaultWorkspaceRoot"
|
||||
}
|
||||
|
||||
func (m *defineDefaultWorkspaceRoot) Apply(ctx context.Context, b *bundle.Bundle) ([]bundle.Mutator, error) {
|
||||
func (m *defineDefaultWorkspaceRoot) Apply(ctx context.Context, b *bundle.Bundle) error {
|
||||
if b.Config.Workspace.RootPath != "" {
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
if b.Config.Bundle.Name == "" {
|
||||
return nil, fmt.Errorf("unable to define default workspace root: bundle name not defined")
|
||||
return fmt.Errorf("unable to define default workspace root: bundle name not defined")
|
||||
}
|
||||
|
||||
if b.Config.Bundle.Environment == "" {
|
||||
return nil, fmt.Errorf("unable to define default workspace root: bundle environment not selected")
|
||||
return fmt.Errorf("unable to define default workspace root: bundle environment not selected")
|
||||
}
|
||||
|
||||
b.Config.Workspace.RootPath = fmt.Sprintf(
|
||||
|
@ -36,5 +36,5 @@ func (m *defineDefaultWorkspaceRoot) Apply(ctx context.Context, b *bundle.Bundle
|
|||
b.Config.Bundle.Name,
|
||||
b.Config.Bundle.Environment,
|
||||
)
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ func TestDefaultWorkspaceRoot(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
_, err := mutator.DefineDefaultWorkspaceRoot().Apply(context.Background(), bundle)
|
||||
err := mutator.DefineDefaultWorkspaceRoot().Apply(context.Background(), bundle)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "~/.bundle/name/environment", bundle.Config.Workspace.RootPath)
|
||||
}
|
||||
|
|
|
@ -20,15 +20,15 @@ func (m *expandWorkspaceRoot) Name() string {
|
|||
return "ExpandWorkspaceRoot"
|
||||
}
|
||||
|
||||
func (m *expandWorkspaceRoot) Apply(ctx context.Context, b *bundle.Bundle) ([]bundle.Mutator, error) {
|
||||
func (m *expandWorkspaceRoot) Apply(ctx context.Context, b *bundle.Bundle) error {
|
||||
root := b.Config.Workspace.RootPath
|
||||
if root == "" {
|
||||
return nil, fmt.Errorf("unable to expand workspace root: workspace root not defined")
|
||||
return fmt.Errorf("unable to expand workspace root: workspace root not defined")
|
||||
}
|
||||
|
||||
currentUser := b.Config.Workspace.CurrentUser
|
||||
if currentUser == nil || currentUser.UserName == "" {
|
||||
return nil, fmt.Errorf("unable to expand workspace root: current user not set")
|
||||
return fmt.Errorf("unable to expand workspace root: current user not set")
|
||||
}
|
||||
|
||||
if strings.HasPrefix(root, "~/") {
|
||||
|
@ -36,5 +36,5 @@ func (m *expandWorkspaceRoot) Apply(ctx context.Context, b *bundle.Bundle) ([]bu
|
|||
b.Config.Workspace.RootPath = path.Join(home, root[2:])
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ func TestExpandWorkspaceRoot(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
_, err := mutator.ExpandWorkspaceRoot().Apply(context.Background(), bundle)
|
||||
err := mutator.ExpandWorkspaceRoot().Apply(context.Background(), bundle)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "/Users/jane@doe.com/foo", bundle.Config.Workspace.RootPath)
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ func TestExpandWorkspaceRootDoesNothing(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
_, err := mutator.ExpandWorkspaceRoot().Apply(context.Background(), bundle)
|
||||
err := mutator.ExpandWorkspaceRoot().Apply(context.Background(), bundle)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "/Users/charly@doe.com/foo", bundle.Config.Workspace.RootPath)
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ func TestExpandWorkspaceRootWithoutRoot(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
_, err := mutator.ExpandWorkspaceRoot().Apply(context.Background(), bundle)
|
||||
err := mutator.ExpandWorkspaceRoot().Apply(context.Background(), bundle)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
|
@ -66,6 +66,6 @@ func TestExpandWorkspaceRootWithoutCurrentUser(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
_, err := mutator.ExpandWorkspaceRoot().Apply(context.Background(), bundle)
|
||||
err := mutator.ExpandWorkspaceRoot().Apply(context.Background(), bundle)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
|
|
@ -18,11 +18,11 @@ func (m *loadGitDetails) Name() string {
|
|||
return "LoadGitDetails"
|
||||
}
|
||||
|
||||
func (m *loadGitDetails) Apply(ctx context.Context, b *bundle.Bundle) ([]bundle.Mutator, error) {
|
||||
func (m *loadGitDetails) Apply(ctx context.Context, b *bundle.Bundle) error {
|
||||
// Load relevant git repository
|
||||
repo, err := git.NewRepository(b.Config.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
// load branch name if undefined
|
||||
if b.Config.Bundle.Git.Branch == "" {
|
||||
|
@ -47,5 +47,5 @@ func (m *loadGitDetails) Apply(ctx context.Context, b *bundle.Bundle) ([]bundle.
|
|||
remoteUrl := repo.OriginUrl()
|
||||
b.Config.Bundle.Git.OriginURL = remoteUrl
|
||||
}
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -17,13 +17,13 @@ func (m *populateCurrentUser) Name() string {
|
|||
return "PopulateCurrentUser"
|
||||
}
|
||||
|
||||
func (m *populateCurrentUser) Apply(ctx context.Context, b *bundle.Bundle) ([]bundle.Mutator, error) {
|
||||
func (m *populateCurrentUser) Apply(ctx context.Context, b *bundle.Bundle) error {
|
||||
w := b.WorkspaceClient()
|
||||
me, err := w.CurrentUser.Me(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
b.Config.Workspace.CurrentUser = me
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -25,10 +25,10 @@ func (m *processInclude) Name() string {
|
|||
return fmt.Sprintf("ProcessInclude(%s)", m.relPath)
|
||||
}
|
||||
|
||||
func (m *processInclude) Apply(_ context.Context, b *bundle.Bundle) ([]bundle.Mutator, error) {
|
||||
func (m *processInclude) Apply(_ context.Context, b *bundle.Bundle) error {
|
||||
this, err := config.Load(m.fullPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
return nil, b.Config.Merge(this)
|
||||
return b.Config.Merge(this)
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ func TestProcessInclude(t *testing.T) {
|
|||
f.Close()
|
||||
|
||||
assert.Equal(t, "foo", bundle.Config.Workspace.Host)
|
||||
_, err = mutator.ProcessInclude(fullPath, relPath).Apply(context.Background(), bundle)
|
||||
err = mutator.ProcessInclude(fullPath, relPath).Apply(context.Background(), bundle)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "bar", bundle.Config.Workspace.Host)
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ func (m *processRootIncludes) Name() string {
|
|||
return "ProcessRootIncludes"
|
||||
}
|
||||
|
||||
func (m *processRootIncludes) Apply(_ context.Context, b *bundle.Bundle) ([]bundle.Mutator, error) {
|
||||
func (m *processRootIncludes) Apply(ctx context.Context, b *bundle.Bundle) error {
|
||||
var out []bundle.Mutator
|
||||
|
||||
// Map with files we've already seen to avoid loading them twice.
|
||||
|
@ -40,13 +40,13 @@ func (m *processRootIncludes) Apply(_ context.Context, b *bundle.Bundle) ([]bund
|
|||
for _, entry := range b.Config.Include {
|
||||
// Include paths must be relative.
|
||||
if filepath.IsAbs(entry) {
|
||||
return nil, fmt.Errorf("%s: includes must be relative paths", entry)
|
||||
return fmt.Errorf("%s: includes must be relative paths", entry)
|
||||
}
|
||||
|
||||
// Anchor includes to the bundle root path.
|
||||
matches, err := filepath.Glob(filepath.Join(b.Config.Path, entry))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
// Filter matches to ones we haven't seen yet.
|
||||
|
@ -54,7 +54,7 @@ func (m *processRootIncludes) Apply(_ context.Context, b *bundle.Bundle) ([]bund
|
|||
for _, match := range matches {
|
||||
rel, err := filepath.Rel(b.Config.Path, match)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
if _, ok := seen[rel]; ok {
|
||||
continue
|
||||
|
@ -74,5 +74,5 @@ func (m *processRootIncludes) Apply(_ context.Context, b *bundle.Bundle) ([]bund
|
|||
// Swap out the original includes list with the expanded globs.
|
||||
b.Config.Include = files
|
||||
|
||||
return out, nil
|
||||
return bundle.Apply(ctx, b, bundle.Seq(out...))
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ func TestProcessRootIncludesEmpty(t *testing.T) {
|
|||
Path: ".",
|
||||
},
|
||||
}
|
||||
_, err := mutator.ProcessRootIncludes().Apply(context.Background(), bundle)
|
||||
err := mutator.ProcessRootIncludes().Apply(context.Background(), bundle)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
|
@ -46,7 +46,7 @@ func TestProcessRootIncludesAbs(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
_, err := mutator.ProcessRootIncludes().Apply(context.Background(), bundle)
|
||||
err := mutator.ProcessRootIncludes().Apply(context.Background(), bundle)
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "must be relative paths")
|
||||
}
|
||||
|
@ -65,17 +65,9 @@ func TestProcessRootIncludesSingleGlob(t *testing.T) {
|
|||
touch(t, bundle.Config.Path, "a.yml")
|
||||
touch(t, bundle.Config.Path, "b.yml")
|
||||
|
||||
ms, err := mutator.ProcessRootIncludes().Apply(context.Background(), bundle)
|
||||
err := mutator.ProcessRootIncludes().Apply(context.Background(), bundle)
|
||||
require.NoError(t, err)
|
||||
|
||||
var names []string
|
||||
for _, m := range ms {
|
||||
names = append(names, m.Name())
|
||||
}
|
||||
|
||||
assert.NotContains(t, names, "ProcessInclude(bundle.yml)")
|
||||
assert.Contains(t, names, "ProcessInclude(a.yml)")
|
||||
assert.Contains(t, names, "ProcessInclude(b.yml)")
|
||||
assert.Equal(t, []string{"a.yml", "b.yml"}, bundle.Config.Include)
|
||||
}
|
||||
|
||||
|
@ -93,16 +85,9 @@ func TestProcessRootIncludesMultiGlob(t *testing.T) {
|
|||
touch(t, bundle.Config.Path, "a1.yml")
|
||||
touch(t, bundle.Config.Path, "b1.yml")
|
||||
|
||||
ms, err := mutator.ProcessRootIncludes().Apply(context.Background(), bundle)
|
||||
err := mutator.ProcessRootIncludes().Apply(context.Background(), bundle)
|
||||
require.NoError(t, err)
|
||||
|
||||
var names []string
|
||||
for _, m := range ms {
|
||||
names = append(names, m.Name())
|
||||
}
|
||||
|
||||
assert.Contains(t, names, "ProcessInclude(a1.yml)")
|
||||
assert.Contains(t, names, "ProcessInclude(b1.yml)")
|
||||
assert.Equal(t, []string{"a1.yml", "b1.yml"}, bundle.Config.Include)
|
||||
}
|
||||
|
||||
|
@ -119,9 +104,7 @@ func TestProcessRootIncludesRemoveDups(t *testing.T) {
|
|||
|
||||
touch(t, bundle.Config.Path, "a.yml")
|
||||
|
||||
ms, err := mutator.ProcessRootIncludes().Apply(context.Background(), bundle)
|
||||
err := mutator.ProcessRootIncludes().Apply(context.Background(), bundle)
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, ms, 1)
|
||||
assert.Equal(t, "ProcessInclude(a.yml)", ms[0].Name())
|
||||
assert.Equal(t, []string{"a.yml"}, bundle.Config.Include)
|
||||
}
|
||||
|
|
|
@ -20,15 +20,15 @@ func (m *selectDefaultEnvironment) Name() string {
|
|||
return "SelectDefaultEnvironment"
|
||||
}
|
||||
|
||||
func (m *selectDefaultEnvironment) Apply(_ context.Context, b *bundle.Bundle) ([]bundle.Mutator, error) {
|
||||
func (m *selectDefaultEnvironment) Apply(ctx context.Context, b *bundle.Bundle) error {
|
||||
if len(b.Config.Environments) == 0 {
|
||||
return nil, fmt.Errorf("no environments defined")
|
||||
return fmt.Errorf("no environments defined")
|
||||
}
|
||||
|
||||
// One environment means there's only one default.
|
||||
names := maps.Keys(b.Config.Environments)
|
||||
if len(names) == 1 {
|
||||
return []bundle.Mutator{SelectEnvironment(names[0])}, nil
|
||||
return SelectEnvironment(names[0]).Apply(ctx, b)
|
||||
}
|
||||
|
||||
// Multiple environments means we look for the `default` flag.
|
||||
|
@ -41,14 +41,14 @@ func (m *selectDefaultEnvironment) Apply(_ context.Context, b *bundle.Bundle) ([
|
|||
|
||||
// It is invalid to have multiple environments with the `default` flag set.
|
||||
if len(defaults) > 1 {
|
||||
return nil, fmt.Errorf("multiple environments are marked as default (%s)", strings.Join(defaults, ", "))
|
||||
return fmt.Errorf("multiple environments are marked as default (%s)", strings.Join(defaults, ", "))
|
||||
}
|
||||
|
||||
// If no environment has the `default` flag set, ask the user to specify one.
|
||||
if len(defaults) == 0 {
|
||||
return nil, fmt.Errorf("please specify environment")
|
||||
return fmt.Errorf("please specify environment")
|
||||
}
|
||||
|
||||
// One default remaining.
|
||||
return []bundle.Mutator{SelectEnvironment(defaults[0])}, nil
|
||||
return SelectEnvironment(defaults[0]).Apply(ctx, b)
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ func TestSelectDefaultEnvironmentNoEnvironments(t *testing.T) {
|
|||
Environments: map[string]*config.Environment{},
|
||||
},
|
||||
}
|
||||
_, err := mutator.SelectDefaultEnvironment().Apply(context.Background(), bundle)
|
||||
err := mutator.SelectDefaultEnvironment().Apply(context.Background(), bundle)
|
||||
assert.ErrorContains(t, err, "no environments defined")
|
||||
}
|
||||
|
||||
|
@ -28,10 +28,9 @@ func TestSelectDefaultEnvironmentSingleEnvironments(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
ms, err := mutator.SelectDefaultEnvironment().Apply(context.Background(), bundle)
|
||||
err := mutator.SelectDefaultEnvironment().Apply(context.Background(), bundle)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, ms, 1)
|
||||
assert.Equal(t, "SelectEnvironment(foo)", ms[0].Name())
|
||||
assert.Equal(t, "foo", bundle.Config.Bundle.Environment)
|
||||
}
|
||||
|
||||
func TestSelectDefaultEnvironmentNoDefaults(t *testing.T) {
|
||||
|
@ -44,7 +43,7 @@ func TestSelectDefaultEnvironmentNoDefaults(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
_, err := mutator.SelectDefaultEnvironment().Apply(context.Background(), bundle)
|
||||
err := mutator.SelectDefaultEnvironment().Apply(context.Background(), bundle)
|
||||
assert.ErrorContains(t, err, "please specify environment")
|
||||
}
|
||||
|
||||
|
@ -57,7 +56,7 @@ func TestSelectDefaultEnvironmentNoDefaultsWithNil(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
_, err := mutator.SelectDefaultEnvironment().Apply(context.Background(), bundle)
|
||||
err := mutator.SelectDefaultEnvironment().Apply(context.Background(), bundle)
|
||||
assert.ErrorContains(t, err, "please specify environment")
|
||||
}
|
||||
|
||||
|
@ -71,7 +70,7 @@ func TestSelectDefaultEnvironmentMultipleDefaults(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
_, err := mutator.SelectDefaultEnvironment().Apply(context.Background(), bundle)
|
||||
err := mutator.SelectDefaultEnvironment().Apply(context.Background(), bundle)
|
||||
assert.ErrorContains(t, err, "multiple environments are marked as default")
|
||||
}
|
||||
|
||||
|
@ -85,8 +84,7 @@ func TestSelectDefaultEnvironmentSingleDefault(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
ms, err := mutator.SelectDefaultEnvironment().Apply(context.Background(), bundle)
|
||||
err := mutator.SelectDefaultEnvironment().Apply(context.Background(), bundle)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, ms, 1)
|
||||
assert.Equal(t, "SelectEnvironment(bar)", ms[0].Name())
|
||||
assert.Equal(t, "bar", bundle.Config.Bundle.Environment)
|
||||
}
|
||||
|
|
|
@ -22,21 +22,21 @@ func (m *selectEnvironment) Name() string {
|
|||
return fmt.Sprintf("SelectEnvironment(%s)", m.name)
|
||||
}
|
||||
|
||||
func (m *selectEnvironment) Apply(_ context.Context, b *bundle.Bundle) ([]bundle.Mutator, error) {
|
||||
func (m *selectEnvironment) Apply(_ context.Context, b *bundle.Bundle) error {
|
||||
if b.Config.Environments == nil {
|
||||
return nil, fmt.Errorf("no environments defined")
|
||||
return fmt.Errorf("no environments defined")
|
||||
}
|
||||
|
||||
// Get specified environment
|
||||
env, ok := b.Config.Environments[m.name]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("%s: no such environment", m.name)
|
||||
return fmt.Errorf("%s: no such environment", m.name)
|
||||
}
|
||||
|
||||
// Merge specified environment into root configuration structure.
|
||||
err := b.Config.MergeEnvironment(env)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
// Store specified environment in configuration for reference.
|
||||
|
@ -44,5 +44,5 @@ func (m *selectEnvironment) Apply(_ context.Context, b *bundle.Bundle) ([]bundle
|
|||
|
||||
// Clear environments after loading.
|
||||
b.Config.Environments = nil
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ func TestSelectEnvironment(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
_, err := mutator.SelectEnvironment("default").Apply(context.Background(), bundle)
|
||||
err := mutator.SelectEnvironment("default").Apply(context.Background(), bundle)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "bar", bundle.Config.Workspace.Host)
|
||||
}
|
||||
|
@ -39,6 +39,6 @@ func TestSelectEnvironmentNotFound(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
_, err := mutator.SelectEnvironment("doesnt-exist").Apply(context.Background(), bundle)
|
||||
err := mutator.SelectEnvironment("doesnt-exist").Apply(context.Background(), bundle)
|
||||
require.Error(t, err, "no environments defined")
|
||||
}
|
||||
|
|
|
@ -52,12 +52,12 @@ func setVariable(v *variable.Variable, name string) error {
|
|||
return fmt.Errorf(`no value assigned to required variable %s. Assignment can be done through the "--var" flag or by setting the %s environment variable`, name, bundleVarPrefix+name)
|
||||
}
|
||||
|
||||
func (m *setVariables) Apply(ctx context.Context, b *bundle.Bundle) ([]bundle.Mutator, error) {
|
||||
func (m *setVariables) Apply(ctx context.Context, b *bundle.Bundle) error {
|
||||
for name, variable := range b.Config.Variables {
|
||||
err := setVariable(variable, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -108,7 +108,7 @@ func TestSetVariablesMutator(t *testing.T) {
|
|||
|
||||
t.Setenv("BUNDLE_VAR_b", "env-var-b")
|
||||
|
||||
_, err := SetVariables().Apply(context.Background(), bundle)
|
||||
err := SetVariables().Apply(context.Background(), bundle)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "default-a", *bundle.Config.Variables["a"].Value)
|
||||
assert.Equal(t, "env-var-b", *bundle.Config.Variables["b"].Value)
|
||||
|
|
|
@ -145,19 +145,19 @@ func (m *translatePaths) translatePipelineLibrary(dir string, b *bundle.Bundle,
|
|||
return nil
|
||||
}
|
||||
|
||||
func (m *translatePaths) Apply(_ context.Context, b *bundle.Bundle) ([]bundle.Mutator, error) {
|
||||
func (m *translatePaths) Apply(_ context.Context, b *bundle.Bundle) error {
|
||||
m.seen = make(map[string]string)
|
||||
|
||||
for key, job := range b.Config.Resources.Jobs {
|
||||
dir, err := job.ConfigFileDirectory()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to determine directory for job %s: %w", key, err)
|
||||
return fmt.Errorf("unable to determine directory for job %s: %w", key, err)
|
||||
}
|
||||
|
||||
for i := 0; i < len(job.Tasks); i++ {
|
||||
err := m.translateJobTask(dir, b, &job.Tasks[i])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -165,16 +165,16 @@ func (m *translatePaths) Apply(_ context.Context, b *bundle.Bundle) ([]bundle.Mu
|
|||
for key, pipeline := range b.Config.Resources.Pipelines {
|
||||
dir, err := pipeline.ConfigFileDirectory()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to determine directory for pipeline %s: %w", key, err)
|
||||
return fmt.Errorf("unable to determine directory for pipeline %s: %w", key, err)
|
||||
}
|
||||
|
||||
for i := 0; i < len(pipeline.Libraries); i++ {
|
||||
err := m.translatePipelineLibrary(dir, b, &pipeline.Libraries[i])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -118,7 +118,7 @@ func TestTranslatePaths(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
_, err := mutator.TranslatePaths().Apply(context.Background(), bundle)
|
||||
err := mutator.TranslatePaths().Apply(context.Background(), bundle)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Assert that the path in the tasks now refer to the artifact.
|
||||
|
@ -215,7 +215,7 @@ func TestTranslatePathsInSubdirectories(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
_, err := mutator.TranslatePaths().Apply(context.Background(), bundle)
|
||||
err := mutator.TranslatePaths().Apply(context.Background(), bundle)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(
|
||||
|
@ -261,7 +261,7 @@ func TestTranslatePathsOutsideBundleRoot(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
_, err := mutator.TranslatePaths().Apply(context.Background(), bundle)
|
||||
err := mutator.TranslatePaths().Apply(context.Background(), bundle)
|
||||
assert.ErrorContains(t, err, "is not contained in bundle root")
|
||||
}
|
||||
|
||||
|
@ -292,7 +292,7 @@ func TestJobNotebookDoesNotExistError(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
_, err := mutator.TranslatePaths().Apply(context.Background(), bundle)
|
||||
err := mutator.TranslatePaths().Apply(context.Background(), bundle)
|
||||
assert.EqualError(t, err, "notebook ./doesnt_exist.py not found")
|
||||
}
|
||||
|
||||
|
@ -323,7 +323,7 @@ func TestJobFileDoesNotExistError(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
_, err := mutator.TranslatePaths().Apply(context.Background(), bundle)
|
||||
err := mutator.TranslatePaths().Apply(context.Background(), bundle)
|
||||
assert.EqualError(t, err, "file ./doesnt_exist.py not found")
|
||||
}
|
||||
|
||||
|
@ -354,7 +354,7 @@ func TestPipelineNotebookDoesNotExistError(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
_, err := mutator.TranslatePaths().Apply(context.Background(), bundle)
|
||||
err := mutator.TranslatePaths().Apply(context.Background(), bundle)
|
||||
assert.EqualError(t, err, "notebook ./doesnt_exist.py not found")
|
||||
}
|
||||
|
||||
|
@ -385,6 +385,6 @@ func TestPipelineFileDoesNotExistError(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
_, err := mutator.TranslatePaths().Apply(context.Background(), bundle)
|
||||
err := mutator.TranslatePaths().Apply(context.Background(), bundle)
|
||||
assert.EqualError(t, err, "file ./doesnt_exist.py not found")
|
||||
}
|
||||
|
|
|
@ -7,29 +7,27 @@ import (
|
|||
)
|
||||
|
||||
type DeferredMutator struct {
|
||||
mutators []Mutator
|
||||
finally []Mutator
|
||||
mutator Mutator
|
||||
finally Mutator
|
||||
}
|
||||
|
||||
func (d *DeferredMutator) Name() string {
|
||||
return "deferred"
|
||||
}
|
||||
|
||||
func Defer(mutators []Mutator, finally []Mutator) []Mutator {
|
||||
return []Mutator{
|
||||
&DeferredMutator{
|
||||
mutators: mutators,
|
||||
finally: finally,
|
||||
},
|
||||
func Defer(mutator Mutator, finally Mutator) Mutator {
|
||||
return &DeferredMutator{
|
||||
mutator: mutator,
|
||||
finally: finally,
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DeferredMutator) Apply(ctx context.Context, b *Bundle) ([]Mutator, error) {
|
||||
mainErr := Apply(ctx, b, d.mutators)
|
||||
func (d *DeferredMutator) Apply(ctx context.Context, b *Bundle) error {
|
||||
mainErr := Apply(ctx, b, d.mutator)
|
||||
errOnFinish := Apply(ctx, b, d.finally)
|
||||
if mainErr != nil || errOnFinish != nil {
|
||||
return nil, errs.FromMany(mainErr, errOnFinish)
|
||||
return errs.FromMany(mainErr, errOnFinish)
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -17,9 +17,9 @@ func (t *mutatorWithError) Name() string {
|
|||
return "mutatorWithError"
|
||||
}
|
||||
|
||||
func (t *mutatorWithError) Apply(_ context.Context, b *Bundle) ([]Mutator, error) {
|
||||
func (t *mutatorWithError) Apply(_ context.Context, b *Bundle) error {
|
||||
t.applyCalled++
|
||||
return nil, fmt.Errorf(t.errorMsg)
|
||||
return fmt.Errorf(t.errorMsg)
|
||||
}
|
||||
|
||||
func TestDeferredMutatorWhenAllMutatorsSucceed(t *testing.T) {
|
||||
|
@ -27,7 +27,7 @@ func TestDeferredMutatorWhenAllMutatorsSucceed(t *testing.T) {
|
|||
m2 := &testMutator{}
|
||||
m3 := &testMutator{}
|
||||
cleanup := &testMutator{}
|
||||
deferredMutator := Defer([]Mutator{m1, m2, m3}, []Mutator{cleanup})
|
||||
deferredMutator := Defer(Seq(m1, m2, m3), cleanup)
|
||||
|
||||
bundle := &Bundle{}
|
||||
err := Apply(context.Background(), bundle, deferredMutator)
|
||||
|
@ -44,7 +44,7 @@ func TestDeferredMutatorWhenFirstFails(t *testing.T) {
|
|||
m2 := &testMutator{}
|
||||
mErr := &mutatorWithError{errorMsg: "mutator error occurred"}
|
||||
cleanup := &testMutator{}
|
||||
deferredMutator := Defer([]Mutator{mErr, m1, m2}, []Mutator{cleanup})
|
||||
deferredMutator := Defer(Seq(mErr, m1, m2), cleanup)
|
||||
|
||||
bundle := &Bundle{}
|
||||
err := Apply(context.Background(), bundle, deferredMutator)
|
||||
|
@ -61,7 +61,7 @@ func TestDeferredMutatorWhenMiddleOneFails(t *testing.T) {
|
|||
m2 := &testMutator{}
|
||||
mErr := &mutatorWithError{errorMsg: "mutator error occurred"}
|
||||
cleanup := &testMutator{}
|
||||
deferredMutator := Defer([]Mutator{m1, mErr, m2}, []Mutator{cleanup})
|
||||
deferredMutator := Defer(Seq(m1, mErr, m2), cleanup)
|
||||
|
||||
bundle := &Bundle{}
|
||||
err := Apply(context.Background(), bundle, deferredMutator)
|
||||
|
@ -78,7 +78,7 @@ func TestDeferredMutatorWhenLastOneFails(t *testing.T) {
|
|||
m2 := &testMutator{}
|
||||
mErr := &mutatorWithError{errorMsg: "mutator error occurred"}
|
||||
cleanup := &testMutator{}
|
||||
deferredMutator := Defer([]Mutator{m1, m2, mErr}, []Mutator{cleanup})
|
||||
deferredMutator := Defer(Seq(m1, m2, mErr), cleanup)
|
||||
|
||||
bundle := &Bundle{}
|
||||
err := Apply(context.Background(), bundle, deferredMutator)
|
||||
|
@ -95,7 +95,7 @@ func TestDeferredMutatorCombinesErrorMessages(t *testing.T) {
|
|||
m2 := &testMutator{}
|
||||
mErr := &mutatorWithError{errorMsg: "mutator error occurred"}
|
||||
cleanupErr := &mutatorWithError{errorMsg: "cleanup error occurred"}
|
||||
deferredMutator := Defer([]Mutator{m1, m2, mErr}, []Mutator{cleanupErr})
|
||||
deferredMutator := Defer(Seq(m1, m2, mErr), cleanupErr)
|
||||
|
||||
bundle := &Bundle{}
|
||||
err := Apply(context.Background(), bundle, deferredMutator)
|
||||
|
|
|
@ -16,10 +16,10 @@ func (m *delete) Name() string {
|
|||
return "files.Delete"
|
||||
}
|
||||
|
||||
func (m *delete) Apply(ctx context.Context, b *bundle.Bundle) ([]bundle.Mutator, error) {
|
||||
func (m *delete) Apply(ctx context.Context, b *bundle.Bundle) error {
|
||||
// Do not delete files if terraform destroy was not consented
|
||||
if !b.Plan.IsEmpty && !b.Plan.ConfirmApply {
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
cmdio.LogString(ctx, "Starting deletion of remote bundle files")
|
||||
|
@ -29,10 +29,10 @@ func (m *delete) Apply(ctx context.Context, b *bundle.Bundle) ([]bundle.Mutator,
|
|||
if !b.AutoApprove {
|
||||
proceed, err := cmdio.Ask(ctx, fmt.Sprintf("\n%s and all files in it will be %s Proceed?: ", b.Config.Workspace.RootPath, red("deleted permanently!")))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
if !proceed {
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,22 +41,22 @@ func (m *delete) Apply(ctx context.Context, b *bundle.Bundle) ([]bundle.Mutator,
|
|||
Recursive: true,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
// Clean up sync snapshot file
|
||||
sync, err := getSync(ctx, b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
err = sync.DestroySnapshot(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
cmdio.LogString(ctx, fmt.Sprintf("Deleted snapshot file at %s", sync.SnapshotPath()))
|
||||
cmdio.LogString(ctx, "Successfully deleted files!")
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func Delete() bundle.Mutator {
|
||||
|
|
|
@ -14,20 +14,20 @@ func (m *upload) Name() string {
|
|||
return "files.Upload"
|
||||
}
|
||||
|
||||
func (m *upload) Apply(ctx context.Context, b *bundle.Bundle) ([]bundle.Mutator, error) {
|
||||
func (m *upload) Apply(ctx context.Context, b *bundle.Bundle) error {
|
||||
cmdio.LogString(ctx, "Starting upload of bundle files")
|
||||
sync, err := getSync(ctx, b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
err = sync.RunOnce(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
cmdio.LogString(ctx, fmt.Sprintf("Uploaded bundle files at %s!\n", b.Config.Workspace.FilesPath))
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func Upload() bundle.Mutator {
|
||||
|
|
|
@ -30,16 +30,16 @@ func (m *acquire) init(b *bundle.Bundle) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (m *acquire) Apply(ctx context.Context, b *bundle.Bundle) ([]bundle.Mutator, error) {
|
||||
func (m *acquire) Apply(ctx context.Context, b *bundle.Bundle) error {
|
||||
// Return early if locking is disabled.
|
||||
if !b.Config.Bundle.Lock.IsEnabled() {
|
||||
log.Infof(ctx, "Skipping; locking is disabled")
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
err := m.init(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
force := b.Config.Bundle.Lock.Force
|
||||
|
@ -47,8 +47,8 @@ func (m *acquire) Apply(ctx context.Context, b *bundle.Bundle) ([]bundle.Mutator
|
|||
err = b.Locker.Lock(ctx, force)
|
||||
if err != nil {
|
||||
log.Errorf(ctx, "Failed to acquire deployment lock: %v", err)
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -17,26 +17,26 @@ func (m *release) Name() string {
|
|||
return "lock:release"
|
||||
}
|
||||
|
||||
func (m *release) Apply(ctx context.Context, b *bundle.Bundle) ([]bundle.Mutator, error) {
|
||||
func (m *release) Apply(ctx context.Context, b *bundle.Bundle) error {
|
||||
// Return early if locking is disabled.
|
||||
if !b.Config.Bundle.Lock.IsEnabled() {
|
||||
log.Infof(ctx, "Skipping; locking is disabled")
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// Return early if the locker is not set.
|
||||
// It is likely an error occurred prior to initialization of the locker instance.
|
||||
if b.Locker == nil {
|
||||
log.Warnf(ctx, "Unable to release lock if locker is not configured")
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Infof(ctx, "Releasing deployment lock")
|
||||
err := b.Locker.Unlock(ctx)
|
||||
if err != nil {
|
||||
log.Errorf(ctx, "Failed to release deployment lock: %v", err)
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -15,26 +15,26 @@ func (w *apply) Name() string {
|
|||
return "terraform.Apply"
|
||||
}
|
||||
|
||||
func (w *apply) Apply(ctx context.Context, b *bundle.Bundle) ([]bundle.Mutator, error) {
|
||||
func (w *apply) Apply(ctx context.Context, b *bundle.Bundle) error {
|
||||
tf := b.Terraform
|
||||
if tf == nil {
|
||||
return nil, fmt.Errorf("terraform not initialized")
|
||||
return fmt.Errorf("terraform not initialized")
|
||||
}
|
||||
|
||||
cmdio.LogString(ctx, "Starting resource deployment")
|
||||
|
||||
err := tf.Init(ctx, tfexec.Upgrade(true))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("terraform init: %w", err)
|
||||
return fmt.Errorf("terraform init: %w", err)
|
||||
}
|
||||
|
||||
err = tf.Apply(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("terraform apply: %w", err)
|
||||
return fmt.Errorf("terraform apply: %w", err)
|
||||
}
|
||||
|
||||
cmdio.LogString(ctx, "Resource deployment completed!")
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// Apply returns a [bundle.Mutator] that runs the equivalent of `terraform apply`
|
||||
|
|
|
@ -62,28 +62,28 @@ func (w *destroy) Name() string {
|
|||
return "terraform.Destroy"
|
||||
}
|
||||
|
||||
func (w *destroy) Apply(ctx context.Context, b *bundle.Bundle) ([]bundle.Mutator, error) {
|
||||
func (w *destroy) Apply(ctx context.Context, b *bundle.Bundle) error {
|
||||
// return early if plan is empty
|
||||
if b.Plan.IsEmpty {
|
||||
cmdio.LogString(ctx, "No resources to destroy in plan. Skipping destroy!")
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
tf := b.Terraform
|
||||
if tf == nil {
|
||||
return nil, fmt.Errorf("terraform not initialized")
|
||||
return fmt.Errorf("terraform not initialized")
|
||||
}
|
||||
|
||||
// read plan file
|
||||
plan, err := tf.ShowPlanFile(ctx, b.Plan.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
// print the resources that will be destroyed
|
||||
err = logDestroyPlan(ctx, plan.ResourceChanges)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
// Ask for confirmation, if needed
|
||||
|
@ -91,17 +91,17 @@ func (w *destroy) Apply(ctx context.Context, b *bundle.Bundle) ([]bundle.Mutator
|
|||
red := color.New(color.FgRed).SprintFunc()
|
||||
b.Plan.ConfirmApply, err = cmdio.Ask(ctx, fmt.Sprintf("\nThis will permanently %s resources! Proceed? [y/n]: ", red("destroy")))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// return if confirmation was not provided
|
||||
if !b.Plan.ConfirmApply {
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
if b.Plan.Path == "" {
|
||||
return nil, fmt.Errorf("no plan found")
|
||||
return fmt.Errorf("no plan found")
|
||||
}
|
||||
|
||||
cmdio.LogString(ctx, "Starting to destroy resources")
|
||||
|
@ -109,11 +109,11 @@ func (w *destroy) Apply(ctx context.Context, b *bundle.Bundle) ([]bundle.Mutator
|
|||
// Apply terraform according to the computed destroy plan
|
||||
err = tf.Apply(ctx, tfexec.DirOrPlan(b.Plan.Path))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("terraform destroy: %w", err)
|
||||
return fmt.Errorf("terraform destroy: %w", err)
|
||||
}
|
||||
|
||||
cmdio.LogString(ctx, "Successfully destroyed resources!")
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// Destroy returns a [bundle.Mutator] that runs the conceptual equivalent of
|
||||
|
|
|
@ -108,7 +108,7 @@ func setTempDirEnvVars(env map[string]string, b *bundle.Bundle) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (m *initialize) Apply(ctx context.Context, b *bundle.Bundle) ([]bundle.Mutator, error) {
|
||||
func (m *initialize) Apply(ctx context.Context, b *bundle.Bundle) error {
|
||||
tfConfig := b.Config.Bundle.Terraform
|
||||
if tfConfig == nil {
|
||||
tfConfig = &config.Terraform{}
|
||||
|
@ -117,22 +117,22 @@ func (m *initialize) Apply(ctx context.Context, b *bundle.Bundle) ([]bundle.Muta
|
|||
|
||||
execPath, err := m.findExecPath(ctx, b, tfConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
workingDir, err := Dir(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
tf, err := tfexec.NewTerraform(workingDir, execPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
env, err := b.AuthEnv()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
// Include $HOME in set of environment variables to pass along.
|
||||
|
@ -144,18 +144,18 @@ func (m *initialize) Apply(ctx context.Context, b *bundle.Bundle) ([]bundle.Muta
|
|||
// Set the temporary directory environment variables
|
||||
err = setTempDirEnvVars(env, b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
// Configure environment variables for auth for Terraform to use.
|
||||
log.Debugf(ctx, "Environment variables for Terraform: %s", strings.Join(maps.Keys(env), ", "))
|
||||
err = tf.SetEnv(env)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
b.Terraform = tf
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func Initialize() bundle.Mutator {
|
||||
|
|
|
@ -43,7 +43,7 @@ func TestInitEnvironmentVariables(t *testing.T) {
|
|||
t.Setenv("DATABRICKS_TOKEN", "foobar")
|
||||
bundle.WorkspaceClient()
|
||||
|
||||
_, err = Initialize().Apply(context.Background(), bundle)
|
||||
err = Initialize().Apply(context.Background(), bundle)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
|
|
|
@ -15,34 +15,34 @@ func (l *load) Name() string {
|
|||
return "terraform.Load"
|
||||
}
|
||||
|
||||
func (l *load) Apply(ctx context.Context, b *bundle.Bundle) ([]bundle.Mutator, error) {
|
||||
func (l *load) Apply(ctx context.Context, b *bundle.Bundle) error {
|
||||
tf := b.Terraform
|
||||
if tf == nil {
|
||||
return nil, fmt.Errorf("terraform not initialized")
|
||||
return fmt.Errorf("terraform not initialized")
|
||||
}
|
||||
|
||||
err := tf.Init(ctx, tfexec.Upgrade(true))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("terraform init: %w", err)
|
||||
return fmt.Errorf("terraform init: %w", err)
|
||||
}
|
||||
|
||||
state, err := b.Terraform.Show(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
err = ValidateState(state)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
// Merge state into configuration.
|
||||
err = TerraformToBundle(state, &b.Config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func ValidateState(state *tfjson.State) error {
|
||||
|
|
|
@ -32,10 +32,10 @@ func TestLoadWithNoState(t *testing.T) {
|
|||
t.Setenv("DATABRICKS_TOKEN", "foobar")
|
||||
b.WorkspaceClient()
|
||||
|
||||
err = bundle.Apply(context.Background(), b, []bundle.Mutator{
|
||||
err = bundle.Apply(context.Background(), b, bundle.Seq(
|
||||
Initialize(),
|
||||
Load(),
|
||||
})
|
||||
))
|
||||
|
||||
require.ErrorContains(t, err, "Did you forget to run 'databricks bundle deploy'")
|
||||
}
|
||||
|
|
|
@ -26,30 +26,30 @@ func (p *plan) Name() string {
|
|||
return "terraform.Plan"
|
||||
}
|
||||
|
||||
func (p *plan) Apply(ctx context.Context, b *bundle.Bundle) ([]bundle.Mutator, error) {
|
||||
func (p *plan) Apply(ctx context.Context, b *bundle.Bundle) error {
|
||||
tf := b.Terraform
|
||||
if tf == nil {
|
||||
return nil, fmt.Errorf("terraform not initialized")
|
||||
return fmt.Errorf("terraform not initialized")
|
||||
}
|
||||
|
||||
cmdio.LogString(ctx, "Starting plan computation")
|
||||
|
||||
err := tf.Init(ctx, tfexec.Upgrade(true))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("terraform init: %w", err)
|
||||
return fmt.Errorf("terraform init: %w", err)
|
||||
}
|
||||
|
||||
// Persist computed plan
|
||||
tfDir, err := Dir(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
planPath := filepath.Join(tfDir, "plan")
|
||||
destroy := p.goal == PlanDestroy
|
||||
|
||||
notEmpty, err := tf.Plan(ctx, tfexec.Destroy(destroy), tfexec.Out(planPath))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
// Set plan in main bundle struct for downstream mutators
|
||||
|
@ -60,7 +60,7 @@ func (p *plan) Apply(ctx context.Context, b *bundle.Bundle) ([]bundle.Mutator, e
|
|||
}
|
||||
|
||||
cmdio.LogString(ctx, fmt.Sprintf("Planning complete and persisted at %s\n", planPath))
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// Plan returns a [bundle.Mutator] that runs the equivalent of `terraform plan -out ./plan`
|
||||
|
|
|
@ -18,15 +18,15 @@ func (l *statePull) Name() string {
|
|||
return "terraform:state-pull"
|
||||
}
|
||||
|
||||
func (l *statePull) Apply(ctx context.Context, b *bundle.Bundle) ([]bundle.Mutator, error) {
|
||||
func (l *statePull) Apply(ctx context.Context, b *bundle.Bundle) error {
|
||||
f, err := filer.NewWorkspaceFilesClient(b.WorkspaceClient(), b.Config.Workspace.StatePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
dir, err := Dir(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
// Download state file from filer to local cache directory.
|
||||
|
@ -36,21 +36,21 @@ func (l *statePull) Apply(ctx context.Context, b *bundle.Bundle) ([]bundle.Mutat
|
|||
// On first deploy this state file doesn't yet exist.
|
||||
if apierr.IsMissing(err) {
|
||||
log.Infof(ctx, "Remote state file does not exist")
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
// Expect the state file to live under dir.
|
||||
local, err := os.OpenFile(filepath.Join(dir, TerraformStateFileName), os.O_CREATE|os.O_RDWR, 0600)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
defer local.Close()
|
||||
|
||||
if !IsLocalStateStale(local, remote) {
|
||||
log.Infof(ctx, "Local state is the same or newer, ignoring remote state")
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// Truncating the file before writing
|
||||
|
@ -61,10 +61,10 @@ func (l *statePull) Apply(ctx context.Context, b *bundle.Bundle) ([]bundle.Mutat
|
|||
log.Infof(ctx, "Writing remote state file to local cache directory")
|
||||
_, err = io.Copy(local, remote)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func StatePull() bundle.Mutator {
|
||||
|
|
|
@ -16,31 +16,31 @@ func (l *statePush) Name() string {
|
|||
return "terraform:state-push"
|
||||
}
|
||||
|
||||
func (l *statePush) Apply(ctx context.Context, b *bundle.Bundle) ([]bundle.Mutator, error) {
|
||||
func (l *statePush) Apply(ctx context.Context, b *bundle.Bundle) error {
|
||||
f, err := filer.NewWorkspaceFilesClient(b.WorkspaceClient(), b.Config.Workspace.StatePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
dir, err := Dir(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
// Expect the state file to live under dir.
|
||||
local, err := os.Open(filepath.Join(dir, TerraformStateFileName))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
// Upload state file from local cache directory to filer.
|
||||
log.Infof(ctx, "Writing local state file to remote state directory")
|
||||
err = f.Write(ctx, TerraformStateFileName, local, filer.CreateParentDirectories, filer.OverwriteIfExists)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func StatePush() bundle.Mutator {
|
||||
|
|
|
@ -15,16 +15,16 @@ func (w *write) Name() string {
|
|||
return "terraform.Write"
|
||||
}
|
||||
|
||||
func (w *write) Apply(ctx context.Context, b *bundle.Bundle) ([]bundle.Mutator, error) {
|
||||
func (w *write) Apply(ctx context.Context, b *bundle.Bundle) error {
|
||||
dir, err := Dir(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
root := BundleToTerraform(&b.Config)
|
||||
f, err := os.Create(filepath.Join(dir, "bundle.tf.json"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
defer f.Close()
|
||||
|
@ -33,10 +33,10 @@ func (w *write) Apply(ctx context.Context, b *bundle.Bundle) ([]bundle.Mutator,
|
|||
enc.SetIndent("", " ")
|
||||
err = enc.Encode(root)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// Write returns a [bundle.Mutator] that converts resources in a bundle configuration
|
||||
|
|
|
@ -13,42 +13,18 @@ type Mutator interface {
|
|||
Name() string
|
||||
|
||||
// Apply mutates the specified bundle object.
|
||||
// It may return a list of mutators to apply immediately after this mutator.
|
||||
// For example: when processing all configuration files in the tree; each file gets
|
||||
// its own mutator instance.
|
||||
Apply(context.Context, *Bundle) ([]Mutator, error)
|
||||
Apply(context.Context, *Bundle) error
|
||||
}
|
||||
|
||||
// applyMutator calls apply on the specified mutator given a bundle.
|
||||
// Any mutators this call returns are applied recursively.
|
||||
func applyMutator(ctx context.Context, b *Bundle, m Mutator) error {
|
||||
func Apply(ctx context.Context, b *Bundle, m Mutator) error {
|
||||
ctx = log.NewContext(ctx, log.GetLogger(ctx).With("mutator", m.Name()))
|
||||
|
||||
log.Debugf(ctx, "Apply")
|
||||
ms, err := m.Apply(ctx, b)
|
||||
err := m.Apply(ctx, b)
|
||||
if err != nil {
|
||||
log.Errorf(ctx, "Error: %s", err)
|
||||
return err
|
||||
}
|
||||
|
||||
// Apply recursively.
|
||||
err = Apply(ctx, b, ms)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func Apply(ctx context.Context, b *Bundle, ms []Mutator) error {
|
||||
if len(ms) == 0 {
|
||||
return nil
|
||||
}
|
||||
for _, m := range ms {
|
||||
err := applyMutator(ctx, b, m)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -16,9 +16,9 @@ func (t *testMutator) Name() string {
|
|||
return "test"
|
||||
}
|
||||
|
||||
func (t *testMutator) Apply(_ context.Context, b *Bundle) ([]Mutator, error) {
|
||||
func (t *testMutator) Apply(ctx context.Context, b *Bundle) error {
|
||||
t.applyCalled++
|
||||
return t.nestedMutators, nil
|
||||
return Apply(ctx, b, Seq(t.nestedMutators...))
|
||||
}
|
||||
|
||||
func TestMutator(t *testing.T) {
|
||||
|
@ -35,7 +35,7 @@ func TestMutator(t *testing.T) {
|
|||
}
|
||||
|
||||
bundle := &Bundle{}
|
||||
err := Apply(context.Background(), bundle, []Mutator{m})
|
||||
err := Apply(context.Background(), bundle, m)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, 1, m.applyCalled)
|
||||
|
|
|
@ -10,21 +10,24 @@ import (
|
|||
|
||||
// The deploy phase deploys artifacts and resources.
|
||||
func Deploy() bundle.Mutator {
|
||||
deployPhase := bundle.Defer([]bundle.Mutator{
|
||||
deployMutator := bundle.Seq(
|
||||
lock.Acquire(),
|
||||
files.Upload(),
|
||||
artifacts.UploadAll(),
|
||||
terraform.Interpolate(),
|
||||
terraform.Write(),
|
||||
terraform.StatePull(),
|
||||
terraform.Apply(),
|
||||
terraform.StatePush(),
|
||||
}, []bundle.Mutator{
|
||||
lock.Release(),
|
||||
})
|
||||
bundle.Defer(
|
||||
bundle.Seq(
|
||||
files.Upload(),
|
||||
artifacts.UploadAll(),
|
||||
terraform.Interpolate(),
|
||||
terraform.Write(),
|
||||
terraform.StatePull(),
|
||||
terraform.Apply(),
|
||||
terraform.StatePush(),
|
||||
),
|
||||
lock.Release(),
|
||||
),
|
||||
)
|
||||
|
||||
return newPhase(
|
||||
"deploy",
|
||||
deployPhase,
|
||||
[]bundle.Mutator{deployMutator},
|
||||
)
|
||||
}
|
||||
|
|
|
@ -9,19 +9,23 @@ import (
|
|||
|
||||
// The destroy phase deletes artifacts and resources.
|
||||
func Destroy() bundle.Mutator {
|
||||
destroyPhase := bundle.Defer([]bundle.Mutator{
|
||||
|
||||
destroyMutator := bundle.Seq(
|
||||
lock.Acquire(),
|
||||
terraform.StatePull(),
|
||||
terraform.Plan(terraform.PlanGoal("destroy")),
|
||||
terraform.Destroy(),
|
||||
terraform.StatePush(),
|
||||
files.Delete(),
|
||||
}, []bundle.Mutator{
|
||||
lock.Release(),
|
||||
})
|
||||
bundle.Defer(
|
||||
bundle.Seq(
|
||||
terraform.StatePull(),
|
||||
terraform.Plan(terraform.PlanGoal("destroy")),
|
||||
terraform.Destroy(),
|
||||
terraform.StatePush(),
|
||||
files.Delete(),
|
||||
),
|
||||
lock.Release(),
|
||||
),
|
||||
)
|
||||
|
||||
return newPhase(
|
||||
"destroy",
|
||||
destroyPhase,
|
||||
[]bundle.Mutator{destroyMutator},
|
||||
)
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ func (p *phase) Name() string {
|
|||
return p.name
|
||||
}
|
||||
|
||||
func (p *phase) Apply(ctx context.Context, b *bundle.Bundle) ([]bundle.Mutator, error) {
|
||||
func (p *phase) Apply(ctx context.Context, b *bundle.Bundle) error {
|
||||
log.Infof(ctx, "Phase: %s", p.Name())
|
||||
return p.mutators, nil
|
||||
return bundle.Apply(ctx, b, bundle.Seq(p.mutators...))
|
||||
}
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
package bundle
|
||||
|
||||
import "context"
|
||||
|
||||
type seqMutator struct {
|
||||
mutators []Mutator
|
||||
}
|
||||
|
||||
func (s *seqMutator) Name() string {
|
||||
return "seq"
|
||||
}
|
||||
|
||||
func (s *seqMutator) Apply(ctx context.Context, b *Bundle) error {
|
||||
for _, m := range s.mutators {
|
||||
err := Apply(ctx, b, m)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Seq(ms ...Mutator) Mutator {
|
||||
return &seqMutator{mutators: ms}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
package bundle
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestSeqMutator(t *testing.T) {
|
||||
m1 := &testMutator{}
|
||||
m2 := &testMutator{}
|
||||
m3 := &testMutator{}
|
||||
seqMutator := Seq(m1, m2, m3)
|
||||
|
||||
bundle := &Bundle{}
|
||||
err := Apply(context.Background(), bundle, seqMutator)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, 1, m1.applyCalled)
|
||||
assert.Equal(t, 1, m2.applyCalled)
|
||||
assert.Equal(t, 1, m3.applyCalled)
|
||||
}
|
||||
|
||||
func TestSeqWithDeferredMutator(t *testing.T) {
|
||||
m1 := &testMutator{}
|
||||
m2 := &testMutator{}
|
||||
m3 := &testMutator{}
|
||||
m4 := &testMutator{}
|
||||
seqMutator := Seq(m1, Defer(m2, m3), m4)
|
||||
|
||||
bundle := &Bundle{}
|
||||
err := Apply(context.Background(), bundle, seqMutator)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, 1, m1.applyCalled)
|
||||
assert.Equal(t, 1, m2.applyCalled)
|
||||
assert.Equal(t, 1, m3.applyCalled)
|
||||
assert.Equal(t, 1, m4.applyCalled)
|
||||
}
|
||||
|
||||
func TestSeqWithErrorAndDeferredMutator(t *testing.T) {
|
||||
errorMut := &mutatorWithError{errorMsg: "error msg"}
|
||||
m1 := &testMutator{}
|
||||
m2 := &testMutator{}
|
||||
m3 := &testMutator{}
|
||||
seqMutator := Seq(errorMut, Defer(m1, m2), m3)
|
||||
|
||||
bundle := &Bundle{}
|
||||
err := Apply(context.Background(), bundle, seqMutator)
|
||||
assert.Error(t, err)
|
||||
|
||||
assert.Equal(t, 1, errorMut.applyCalled)
|
||||
assert.Equal(t, 0, m1.applyCalled)
|
||||
assert.Equal(t, 0, m2.applyCalled)
|
||||
assert.Equal(t, 0, m3.applyCalled)
|
||||
}
|
||||
|
||||
func TestSeqWithErrorInsideDeferredMutator(t *testing.T) {
|
||||
errorMut := &mutatorWithError{errorMsg: "error msg"}
|
||||
m1 := &testMutator{}
|
||||
m2 := &testMutator{}
|
||||
m3 := &testMutator{}
|
||||
seqMutator := Seq(m1, Defer(errorMut, m2), m3)
|
||||
|
||||
bundle := &Bundle{}
|
||||
err := Apply(context.Background(), bundle, seqMutator)
|
||||
assert.Error(t, err)
|
||||
|
||||
assert.Equal(t, 1, m1.applyCalled)
|
||||
assert.Equal(t, 1, errorMut.applyCalled)
|
||||
assert.Equal(t, 1, m2.applyCalled)
|
||||
assert.Equal(t, 0, m3.applyCalled)
|
||||
}
|
||||
|
||||
func TestSeqWithErrorInsideFinallyStage(t *testing.T) {
|
||||
errorMut := &mutatorWithError{errorMsg: "error msg"}
|
||||
m1 := &testMutator{}
|
||||
m2 := &testMutator{}
|
||||
m3 := &testMutator{}
|
||||
seqMutator := Seq(m1, Defer(m2, errorMut), m3)
|
||||
|
||||
bundle := &Bundle{}
|
||||
err := Apply(context.Background(), bundle, seqMutator)
|
||||
assert.Error(t, err)
|
||||
|
||||
assert.Equal(t, 1, m1.applyCalled)
|
||||
assert.Equal(t, 1, m2.applyCalled)
|
||||
assert.Equal(t, 1, errorMut.applyCalled)
|
||||
assert.Equal(t, 0, m3.applyCalled)
|
||||
}
|
|
@ -21,7 +21,7 @@ func TestConflictingResourceIdsNoSubconfig(t *testing.T) {
|
|||
func TestConflictingResourceIdsOneSubconfig(t *testing.T) {
|
||||
b, err := bundle.Load("./conflicting_resource_ids/one_subconfiguration")
|
||||
require.NoError(t, err)
|
||||
err = bundle.Apply(context.Background(), b, mutator.DefaultMutators())
|
||||
err = bundle.Apply(context.Background(), b, bundle.Seq(mutator.DefaultMutators()...))
|
||||
bundleConfigPath := filepath.FromSlash("conflicting_resource_ids/one_subconfiguration/bundle.yml")
|
||||
resourcesConfigPath := filepath.FromSlash("conflicting_resource_ids/one_subconfiguration/resources.yml")
|
||||
assert.ErrorContains(t, err, fmt.Sprintf("multiple resources named foo (job at %s, pipeline at %s)", bundleConfigPath, resourcesConfigPath))
|
||||
|
@ -30,7 +30,7 @@ func TestConflictingResourceIdsOneSubconfig(t *testing.T) {
|
|||
func TestConflictingResourceIdsTwoSubconfigs(t *testing.T) {
|
||||
b, err := bundle.Load("./conflicting_resource_ids/two_subconfigurations")
|
||||
require.NoError(t, err)
|
||||
err = bundle.Apply(context.Background(), b, mutator.DefaultMutators())
|
||||
err = bundle.Apply(context.Background(), b, bundle.Seq(mutator.DefaultMutators()...))
|
||||
resources1ConfigPath := filepath.FromSlash("conflicting_resource_ids/two_subconfigurations/resources1.yml")
|
||||
resources2ConfigPath := filepath.FromSlash("conflicting_resource_ids/two_subconfigurations/resources2.yml")
|
||||
assert.ErrorContains(t, err, fmt.Sprintf("multiple resources named foo (job at %s, pipeline at %s)", resources1ConfigPath, resources2ConfigPath))
|
||||
|
|
|
@ -12,11 +12,10 @@ import (
|
|||
|
||||
func TestInterpolation(t *testing.T) {
|
||||
b := load(t, "./interpolation")
|
||||
err := bundle.Apply(context.Background(), b, []bundle.Mutator{
|
||||
interpolation.Interpolate(
|
||||
interpolation.IncludeLookupsInPath("bundle"),
|
||||
interpolation.IncludeLookupsInPath("workspace"),
|
||||
)})
|
||||
err := bundle.Apply(context.Background(), b, interpolation.Interpolate(
|
||||
interpolation.IncludeLookupsInPath("bundle"),
|
||||
interpolation.IncludeLookupsInPath("workspace"),
|
||||
))
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "foo bar", b.Config.Bundle.Name)
|
||||
assert.Equal(t, "foo bar | bar", b.Config.Resources.Jobs["my_job"].Name)
|
||||
|
|
|
@ -12,14 +12,14 @@ import (
|
|||
func load(t *testing.T, path string) *bundle.Bundle {
|
||||
b, err := bundle.Load(path)
|
||||
require.NoError(t, err)
|
||||
err = bundle.Apply(context.Background(), b, mutator.DefaultMutators())
|
||||
err = bundle.Apply(context.Background(), b, bundle.Seq(mutator.DefaultMutators()...))
|
||||
require.NoError(t, err)
|
||||
return b
|
||||
}
|
||||
|
||||
func loadEnvironment(t *testing.T, path, env string) *bundle.Bundle {
|
||||
b := load(t, path)
|
||||
err := bundle.Apply(context.Background(), b, []bundle.Mutator{mutator.SelectEnvironment(env)})
|
||||
err := bundle.Apply(context.Background(), b, mutator.SelectEnvironment(env))
|
||||
require.NoError(t, err)
|
||||
return b
|
||||
}
|
||||
|
|
|
@ -15,45 +15,45 @@ import (
|
|||
func TestVariables(t *testing.T) {
|
||||
t.Setenv("BUNDLE_VAR_b", "def")
|
||||
b := load(t, "./variables/vanilla")
|
||||
err := bundle.Apply(context.Background(), b, []bundle.Mutator{
|
||||
err := bundle.Apply(context.Background(), b, bundle.Seq(
|
||||
mutator.SetVariables(),
|
||||
interpolation.Interpolate(
|
||||
interpolation.IncludeLookupsInPath(variable.VariableReferencePrefix),
|
||||
)})
|
||||
)))
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "abc def", b.Config.Bundle.Name)
|
||||
}
|
||||
|
||||
func TestVariablesLoadingFailsWhenRequiredVariableIsNotSpecified(t *testing.T) {
|
||||
b := load(t, "./variables/vanilla")
|
||||
err := bundle.Apply(context.Background(), b, []bundle.Mutator{
|
||||
err := bundle.Apply(context.Background(), b, bundle.Seq(
|
||||
mutator.SetVariables(),
|
||||
interpolation.Interpolate(
|
||||
interpolation.IncludeLookupsInPath(variable.VariableReferencePrefix),
|
||||
)})
|
||||
)))
|
||||
assert.ErrorContains(t, err, "no value assigned to required variable b. Assignment can be done through the \"--var\" flag or by setting the BUNDLE_VAR_b environment variable")
|
||||
}
|
||||
|
||||
func TestVariablesEnvironmentsBlockOverride(t *testing.T) {
|
||||
b := load(t, "./variables/env_overrides")
|
||||
err := bundle.Apply(context.Background(), b, []bundle.Mutator{
|
||||
err := bundle.Apply(context.Background(), b, bundle.Seq(
|
||||
mutator.SelectEnvironment("env-with-single-variable-override"),
|
||||
mutator.SetVariables(),
|
||||
interpolation.Interpolate(
|
||||
interpolation.IncludeLookupsInPath(variable.VariableReferencePrefix),
|
||||
)})
|
||||
)))
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "default-a dev-b", b.Config.Workspace.Profile)
|
||||
}
|
||||
|
||||
func TestVariablesEnvironmentsBlockOverrideForMultipleVariables(t *testing.T) {
|
||||
b := load(t, "./variables/env_overrides")
|
||||
err := bundle.Apply(context.Background(), b, []bundle.Mutator{
|
||||
err := bundle.Apply(context.Background(), b, bundle.Seq(
|
||||
mutator.SelectEnvironment("env-with-two-variable-overrides"),
|
||||
mutator.SetVariables(),
|
||||
interpolation.Interpolate(
|
||||
interpolation.IncludeLookupsInPath(variable.VariableReferencePrefix),
|
||||
)})
|
||||
)))
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "prod-a prod-b", b.Config.Workspace.Profile)
|
||||
}
|
||||
|
@ -61,34 +61,34 @@ func TestVariablesEnvironmentsBlockOverrideForMultipleVariables(t *testing.T) {
|
|||
func TestVariablesEnvironmentsBlockOverrideWithProcessEnvVars(t *testing.T) {
|
||||
t.Setenv("BUNDLE_VAR_b", "env-var-b")
|
||||
b := load(t, "./variables/env_overrides")
|
||||
err := bundle.Apply(context.Background(), b, []bundle.Mutator{
|
||||
err := bundle.Apply(context.Background(), b, bundle.Seq(
|
||||
mutator.SelectEnvironment("env-with-two-variable-overrides"),
|
||||
mutator.SetVariables(),
|
||||
interpolation.Interpolate(
|
||||
interpolation.IncludeLookupsInPath(variable.VariableReferencePrefix),
|
||||
)})
|
||||
)))
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "prod-a env-var-b", b.Config.Workspace.Profile)
|
||||
}
|
||||
|
||||
func TestVariablesEnvironmentsBlockOverrideWithMissingVariables(t *testing.T) {
|
||||
b := load(t, "./variables/env_overrides")
|
||||
err := bundle.Apply(context.Background(), b, []bundle.Mutator{
|
||||
err := bundle.Apply(context.Background(), b, bundle.Seq(
|
||||
mutator.SelectEnvironment("env-missing-a-required-variable-assignment"),
|
||||
mutator.SetVariables(),
|
||||
interpolation.Interpolate(
|
||||
interpolation.IncludeLookupsInPath(variable.VariableReferencePrefix),
|
||||
)})
|
||||
)))
|
||||
assert.ErrorContains(t, err, "no value assigned to required variable b. Assignment can be done through the \"--var\" flag or by setting the BUNDLE_VAR_b environment variable")
|
||||
}
|
||||
|
||||
func TestVariablesEnvironmentsBlockOverrideWithUndefinedVariables(t *testing.T) {
|
||||
b := load(t, "./variables/env_overrides")
|
||||
err := bundle.Apply(context.Background(), b, []bundle.Mutator{
|
||||
err := bundle.Apply(context.Background(), b, bundle.Seq(
|
||||
mutator.SelectEnvironment("env-using-an-undefined-variable"),
|
||||
mutator.SetVariables(),
|
||||
interpolation.Interpolate(
|
||||
interpolation.IncludeLookupsInPath(variable.VariableReferencePrefix),
|
||||
)})
|
||||
)))
|
||||
assert.ErrorContains(t, err, "variable c is not defined but is assigned a value")
|
||||
}
|
||||
|
|
|
@ -17,11 +17,11 @@ var deployCmd = &cobra.Command{
|
|||
// If `--force` is specified, force acquisition of the deployment lock.
|
||||
b.Config.Bundle.Lock.Force = force
|
||||
|
||||
return bundle.Apply(cmd.Context(), b, []bundle.Mutator{
|
||||
return bundle.Apply(cmd.Context(), b, bundle.Seq(
|
||||
phases.Initialize(),
|
||||
phases.Build(),
|
||||
phases.Deploy(),
|
||||
})
|
||||
))
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -42,11 +42,11 @@ var destroyCmd = &cobra.Command{
|
|||
return fmt.Errorf("please specify --auto-approve since selected logging format is json")
|
||||
}
|
||||
|
||||
return bundle.Apply(ctx, b, []bundle.Mutator{
|
||||
return bundle.Apply(ctx, b, bundle.Seq(
|
||||
phases.Initialize(),
|
||||
phases.Build(),
|
||||
phases.Destroy(),
|
||||
})
|
||||
))
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -23,13 +23,13 @@ var runCmd = &cobra.Command{
|
|||
PreRunE: ConfigureBundleWithVariables,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
b := bundle.Get(cmd.Context())
|
||||
err := bundle.Apply(cmd.Context(), b, []bundle.Mutator{
|
||||
err := bundle.Apply(cmd.Context(), b, bundle.Seq(
|
||||
phases.Initialize(),
|
||||
terraform.Interpolate(),
|
||||
terraform.Write(),
|
||||
terraform.StatePull(),
|
||||
terraform.Load(),
|
||||
})
|
||||
))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -39,9 +39,7 @@ var syncCmd = &cobra.Command{
|
|||
b := bundle.Get(cmd.Context())
|
||||
|
||||
// Run initialize phase to make sure paths are set.
|
||||
err := bundle.Apply(cmd.Context(), b, []bundle.Mutator{
|
||||
phases.Initialize(),
|
||||
})
|
||||
err := bundle.Apply(cmd.Context(), b, phases.Initialize())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -16,9 +16,7 @@ var validateCmd = &cobra.Command{
|
|||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
b := bundle.Get(cmd.Context())
|
||||
|
||||
err := bundle.Apply(cmd.Context(), b, []bundle.Mutator{
|
||||
phases.Initialize(),
|
||||
})
|
||||
err := bundle.Apply(cmd.Context(), b, phases.Initialize())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ func loadBundle(cmd *cobra.Command, args []string, load func() (*bundle.Bundle,
|
|||
}
|
||||
|
||||
ctx := cmd.Context()
|
||||
err = bundle.Apply(ctx, b, mutator.DefaultMutators())
|
||||
err = bundle.Apply(ctx, b, bundle.Seq(mutator.DefaultMutators()...))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ func configureBundle(cmd *cobra.Command, args []string, load func() (*bundle.Bun
|
|||
}
|
||||
|
||||
ctx := cmd.Context()
|
||||
err = bundle.Apply(ctx, b, []bundle.Mutator{m})
|
||||
err = bundle.Apply(ctx, b, m)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -78,9 +78,7 @@ var syncCmd = &cobra.Command{
|
|||
// b := bundle.GetOrNil(cmd.Context())
|
||||
// if b != nil {
|
||||
// // Run initialize phase to make sure paths are set.
|
||||
// err = bundle.Apply(cmd.Context(), b, []bundle.Mutator{
|
||||
// phases.Initialize(),
|
||||
// })
|
||||
// err = bundle.Apply(cmd.Context(), b, phases.Initialize())
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
|
|
Loading…
Reference in New Issue