-
Notifications
You must be signed in to change notification settings - Fork 71
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
Handle ${workspace.file_path}
references in source-linked deployments
#2046
Changes from all commits
d7fbf8a
35b3921
31ff82f
74f51d6
85959ac
cf19166
a65dc98
42cad14
53c1e18
fcdc3ea
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
package mutator | ||
|
||
import ( | ||
"context" | ||
"strings" | ||
|
||
"github.com/databricks/cli/bundle" | ||
"github.com/databricks/cli/bundle/config" | ||
"github.com/databricks/cli/libs/dbr" | ||
"github.com/databricks/cli/libs/diag" | ||
"github.com/databricks/cli/libs/dyn" | ||
) | ||
|
||
type applySourceLinkedDeploymentPreset struct{} | ||
|
||
// Apply source-linked deployment preset | ||
func ApplySourceLinkedDeploymentPreset() *applySourceLinkedDeploymentPreset { | ||
return &applySourceLinkedDeploymentPreset{} | ||
} | ||
|
||
func (m *applySourceLinkedDeploymentPreset) Name() string { | ||
return "ApplySourceLinkedDeploymentPreset" | ||
} | ||
|
||
func (m *applySourceLinkedDeploymentPreset) Apply(ctx context.Context, b *bundle.Bundle) diag.Diagnostics { | ||
if config.IsExplicitlyDisabled(b.Config.Presets.SourceLinkedDeployment) { | ||
return nil | ||
} | ||
|
||
var diags diag.Diagnostics | ||
isDatabricksWorkspace := dbr.RunsOnRuntime(ctx) && strings.HasPrefix(b.SyncRootPath, "/Workspace/") | ||
target := b.Config.Bundle.Target | ||
|
||
if config.IsExplicitlyEnabled((b.Config.Presets.SourceLinkedDeployment)) { | ||
if !isDatabricksWorkspace { | ||
path := dyn.NewPath(dyn.Key("targets"), dyn.Key(target), dyn.Key("presets"), dyn.Key("source_linked_deployment")) | ||
diags = diags.Append( | ||
diag.Diagnostic{ | ||
Severity: diag.Warning, | ||
Summary: "source-linked deployment is available only in the Databricks Workspace", | ||
Paths: []dyn.Path{ | ||
path, | ||
}, | ||
Locations: b.Config.GetLocations(path[2:].String()), | ||
}, | ||
) | ||
|
||
disabled := false | ||
b.Config.Presets.SourceLinkedDeployment = &disabled | ||
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. SInce you're mutating the config here, you'd have to call 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. Thanks, I will update it! Could you elaborate what is the difference between this mutation and normal assignment to struct. Seems that it works good in both cases but I may miss some context 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. Discussed with Pieter that it's better to skip dynamic assignment here in favor of simplicity, but I can update it in another PR if it doesn't feel right |
||
return diags | ||
} | ||
} | ||
|
||
if isDatabricksWorkspace && b.Config.Bundle.Mode == config.Development { | ||
enabled := true | ||
b.Config.Presets.SourceLinkedDeployment = &enabled | ||
} | ||
|
||
if b.Config.Workspace.FilePath != "" && config.IsExplicitlyEnabled(b.Config.Presets.SourceLinkedDeployment) { | ||
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. Added warning for cases when 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. Please include a comment saying that this mutator runs before these fields are defaulted. I was puzzled by this but then found it is run before the mutators that populate its default value. |
||
path := dyn.NewPath(dyn.Key("targets"), dyn.Key(target), dyn.Key("workspace"), dyn.Key("file_path")) | ||
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. Same issue as above w.r.t. the path not existing. 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. 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. Ah, I was confused by the path including This call site and the one above index it with It looks like it is not used in full, so the first two elements can be removed from the assignment. |
||
|
||
diags = diags.Append( | ||
diag.Diagnostic{ | ||
Severity: diag.Warning, | ||
Summary: "workspace.file_path setting will be ignored in source-linked deployment mode", | ||
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. This warning should have a |
||
Paths: []dyn.Path{ | ||
path[2:], | ||
}, | ||
Locations: b.Config.GetLocations(path[2:].String()), | ||
}, | ||
) | ||
} | ||
|
||
return diags | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
package mutator_test | ||
|
||
import ( | ||
"context" | ||
"runtime" | ||
"testing" | ||
|
||
"github.com/databricks/cli/bundle" | ||
"github.com/databricks/cli/bundle/config" | ||
"github.com/databricks/cli/bundle/config/mutator" | ||
"github.com/databricks/cli/bundle/internal/bundletest" | ||
"github.com/databricks/cli/libs/dbr" | ||
"github.com/databricks/cli/libs/dyn" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestApplyPresetsSourceLinkedDeployment(t *testing.T) { | ||
if runtime.GOOS == "windows" { | ||
t.Skip("this test is not applicable on Windows because source-linked mode works only in the Databricks Workspace") | ||
} | ||
|
||
testContext := context.Background() | ||
enabled := true | ||
disabled := false | ||
workspacePath := "/Workspace/user.name@company.com" | ||
|
||
tests := []struct { | ||
name string | ||
ctx context.Context | ||
mutateBundle func(b *bundle.Bundle) | ||
initialValue *bool | ||
expectedValue *bool | ||
expectedWarning string | ||
}{ | ||
{ | ||
name: "preset enabled, bundle in Workspace, databricks runtime", | ||
ctx: dbr.MockRuntime(testContext, true), | ||
initialValue: &enabled, | ||
expectedValue: &enabled, | ||
}, | ||
{ | ||
name: "preset enabled, bundle not in Workspace, databricks runtime", | ||
ctx: dbr.MockRuntime(testContext, true), | ||
mutateBundle: func(b *bundle.Bundle) { | ||
b.SyncRootPath = "/Users/user.name@company.com" | ||
}, | ||
initialValue: &enabled, | ||
expectedValue: &disabled, | ||
expectedWarning: "source-linked deployment is available only in the Databricks Workspace", | ||
}, | ||
{ | ||
name: "preset enabled, bundle in Workspace, not databricks runtime", | ||
ctx: dbr.MockRuntime(testContext, false), | ||
initialValue: &enabled, | ||
expectedValue: &disabled, | ||
expectedWarning: "source-linked deployment is available only in the Databricks Workspace", | ||
}, | ||
{ | ||
name: "preset disabled, bundle in Workspace, databricks runtime", | ||
ctx: dbr.MockRuntime(testContext, true), | ||
initialValue: &disabled, | ||
expectedValue: &disabled, | ||
}, | ||
{ | ||
name: "preset nil, bundle in Workspace, databricks runtime", | ||
ctx: dbr.MockRuntime(testContext, true), | ||
initialValue: nil, | ||
expectedValue: nil, | ||
}, | ||
{ | ||
name: "preset nil, dev mode true, bundle in Workspace, databricks runtime", | ||
ctx: dbr.MockRuntime(testContext, true), | ||
mutateBundle: func(b *bundle.Bundle) { | ||
b.Config.Bundle.Mode = config.Development | ||
}, | ||
initialValue: nil, | ||
expectedValue: &enabled, | ||
}, | ||
{ | ||
name: "preset enabled, workspace.file_path is defined by user", | ||
ctx: dbr.MockRuntime(testContext, true), | ||
mutateBundle: func(b *bundle.Bundle) { | ||
b.Config.Workspace.FilePath = "file_path" | ||
}, | ||
initialValue: &enabled, | ||
expectedValue: &enabled, | ||
expectedWarning: "workspace.file_path setting will be ignored in source-linked deployment mode", | ||
}, | ||
} | ||
|
||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
b := &bundle.Bundle{ | ||
SyncRootPath: workspacePath, | ||
Config: config.Root{ | ||
Presets: config.Presets{ | ||
SourceLinkedDeployment: tt.initialValue, | ||
}, | ||
}, | ||
} | ||
|
||
if tt.mutateBundle != nil { | ||
tt.mutateBundle(b) | ||
} | ||
|
||
bundletest.SetLocation(b, "presets.source_linked_deployment", []dyn.Location{{File: "databricks.yml"}}) | ||
bundletest.SetLocation(b, "workspace.file_path", []dyn.Location{{File: "databricks.yml"}}) | ||
|
||
diags := bundle.Apply(tt.ctx, b, mutator.ApplySourceLinkedDeploymentPreset()) | ||
if diags.HasError() { | ||
t.Fatalf("unexpected error: %v", diags) | ||
} | ||
|
||
if tt.expectedWarning != "" { | ||
require.Equal(t, tt.expectedWarning, diags[0].Summary) | ||
require.NotEmpty(t, diags[0].Locations) | ||
} | ||
|
||
require.Equal(t, tt.expectedValue, b.Config.Presets.SourceLinkedDeployment) | ||
}) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This won't work -- the
targets
field is cleared after selecting it.But because the target is merged into the main configuration, you can use
presets.source_linked_deployment
directly and it will return the original location.