From 7066821c3c15c759fb265271c76e1724b5aea70d Mon Sep 17 00:00:00 2001 From: Shreyas Goenka Date: Thu, 12 Mar 2026 00:03:13 +0100 Subject: [PATCH] Translate alert file_path to workspace path in TranslatePaths The alert resource's `file_path` field was not being translated to a workspace file path by the `TranslatePaths` mutator. This adds support for translating it, similar to how other path-based resources (notebooks, SQL files, etc.) are handled. Co-Authored-By: Claude Opus 4.6 --- .../paths/alerts_file_path/databricks.yml | 13 +++++ .../paths/alerts_file_path/out.test.toml | 5 ++ .../paths/alerts_file_path/output.alert.txt | 1 + .../bundle/paths/alerts_file_path/output.txt | 9 ++++ .../bundle/paths/alerts_file_path/script | 6 +++ .../src/my_alert.dbalert.json | 12 +++++ .../mutator/paths/alert_paths_visitor.go | 2 +- .../mutator/paths/alert_paths_visitor_test.go | 29 +++++++++++ bundle/config/mutator/translate_paths.go | 1 + .../config/mutator/translate_paths_alerts.go | 22 ++++++++ .../mutator/translate_paths_alerts_test.go | 52 +++++++++++++++++++ 11 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 acceptance/bundle/paths/alerts_file_path/databricks.yml create mode 100644 acceptance/bundle/paths/alerts_file_path/out.test.toml create mode 100644 acceptance/bundle/paths/alerts_file_path/output.alert.txt create mode 100644 acceptance/bundle/paths/alerts_file_path/output.txt create mode 100644 acceptance/bundle/paths/alerts_file_path/script create mode 100644 acceptance/bundle/paths/alerts_file_path/src/my_alert.dbalert.json create mode 100644 bundle/config/mutator/paths/alert_paths_visitor_test.go create mode 100644 bundle/config/mutator/translate_paths_alerts.go create mode 100644 bundle/config/mutator/translate_paths_alerts_test.go diff --git a/acceptance/bundle/paths/alerts_file_path/databricks.yml b/acceptance/bundle/paths/alerts_file_path/databricks.yml new file mode 100644 index 0000000000..bd1f590adc --- /dev/null +++ b/acceptance/bundle/paths/alerts_file_path/databricks.yml @@ -0,0 +1,13 @@ +bundle: + name: alerts_file_path + +resources: + alerts: + my_alert: + display_name: "My Alert" + file_path: ./src/my_alert.dbalert.json + warehouse_id: cafef00d + +targets: + development: + default: true diff --git a/acceptance/bundle/paths/alerts_file_path/out.test.toml b/acceptance/bundle/paths/alerts_file_path/out.test.toml new file mode 100644 index 0000000000..d560f1de04 --- /dev/null +++ b/acceptance/bundle/paths/alerts_file_path/out.test.toml @@ -0,0 +1,5 @@ +Local = true +Cloud = false + +[EnvMatrix] + DATABRICKS_BUNDLE_ENGINE = ["terraform", "direct"] diff --git a/acceptance/bundle/paths/alerts_file_path/output.alert.txt b/acceptance/bundle/paths/alerts_file_path/output.alert.txt new file mode 100644 index 0000000000..5d40c1f11b --- /dev/null +++ b/acceptance/bundle/paths/alerts_file_path/output.alert.txt @@ -0,0 +1 @@ +"/Workspace/Users/[USERNAME]/.bundle/alerts_file_path/development/files/src/my_alert.dbalert.json" diff --git a/acceptance/bundle/paths/alerts_file_path/output.txt b/acceptance/bundle/paths/alerts_file_path/output.txt new file mode 100644 index 0000000000..7688674a70 --- /dev/null +++ b/acceptance/bundle/paths/alerts_file_path/output.txt @@ -0,0 +1,9 @@ + +>>> [CLI] bundle validate -t development -o json +Warning: required field "schedule" is not set + at resources.alerts.my_alert + in databricks.yml:7:7 + +Warning: required field "source" is not set + at resources.alerts.my_alert.evaluation + diff --git a/acceptance/bundle/paths/alerts_file_path/script b/acceptance/bundle/paths/alerts_file_path/script new file mode 100644 index 0000000000..658a08551d --- /dev/null +++ b/acceptance/bundle/paths/alerts_file_path/script @@ -0,0 +1,6 @@ +errcode trace $CLI bundle validate -t development -o json > tmp.json + +# Capture the file_path for the alert after translation +jq '.resources.alerts.my_alert.file_path' tmp.json > output.alert.txt + +rm -f tmp.json diff --git a/acceptance/bundle/paths/alerts_file_path/src/my_alert.dbalert.json b/acceptance/bundle/paths/alerts_file_path/src/my_alert.dbalert.json new file mode 100644 index 0000000000..1106f0ab16 --- /dev/null +++ b/acceptance/bundle/paths/alerts_file_path/src/my_alert.dbalert.json @@ -0,0 +1,12 @@ +{ + "query_text": "SELECT 1", + "evaluation": { + "empty_result_state": "UNKNOWN", + "comparison_operator": "GREATER_THAN", + "threshold": { + "value": { + "double_value": 0 + } + } + } +} diff --git a/bundle/config/mutator/paths/alert_paths_visitor.go b/bundle/config/mutator/paths/alert_paths_visitor.go index 1f1a010c79..addc3f3b14 100644 --- a/bundle/config/mutator/paths/alert_paths_visitor.go +++ b/bundle/config/mutator/paths/alert_paths_visitor.go @@ -13,6 +13,6 @@ func VisitAlertPaths(value dyn.Value, fn VisitFunc) (dyn.Value, error) { ) return dyn.MapByPattern(value, pattern, func(path dyn.Path, value dyn.Value) (dyn.Value, error) { - return fn(path, TranslateModeLocalRelative, value) + return fn(path, TranslateModeFile, value) }) } diff --git a/bundle/config/mutator/paths/alert_paths_visitor_test.go b/bundle/config/mutator/paths/alert_paths_visitor_test.go new file mode 100644 index 0000000000..f8332620b3 --- /dev/null +++ b/bundle/config/mutator/paths/alert_paths_visitor_test.go @@ -0,0 +1,29 @@ +package paths + +import ( + "testing" + + "github.com/databricks/cli/bundle/config" + "github.com/databricks/cli/bundle/config/resources" + "github.com/databricks/cli/libs/dyn" + "github.com/stretchr/testify/assert" +) + +func TestVisitAlertPaths(t *testing.T) { + root := config.Root{ + Resources: config.Resources{ + Alerts: map[string]*resources.Alert{ + "alert0": { + FilePath: "foo.dbalert.json", + }, + }, + }, + } + + actual := collectVisitedPaths(t, root, VisitAlertPaths) + expected := []dyn.Path{ + dyn.MustPathFromString("resources.alerts.alert0.file_path"), + } + + assert.ElementsMatch(t, expected, actual) +} diff --git a/bundle/config/mutator/translate_paths.go b/bundle/config/mutator/translate_paths.go index cd35dfa042..7a1eec5c3e 100644 --- a/bundle/config/mutator/translate_paths.go +++ b/bundle/config/mutator/translate_paths.go @@ -348,6 +348,7 @@ func (m *translatePaths) Apply(ctx context.Context, b *bundle.Bundle) diag.Diagn t.applyPipelineTranslations(paths.VisitPipelineLibrariesPaths, true), t.applyArtifactTranslations, t.applyAppsTranslations, + t.applyAlertTranslations, }) } diff --git a/bundle/config/mutator/translate_paths_alerts.go b/bundle/config/mutator/translate_paths_alerts.go new file mode 100644 index 0000000000..6ba69ea981 --- /dev/null +++ b/bundle/config/mutator/translate_paths_alerts.go @@ -0,0 +1,22 @@ +package mutator + +import ( + "context" + + "github.com/databricks/cli/bundle/config/mutator/paths" + + "github.com/databricks/cli/libs/dyn" +) + +func (t *translateContext) applyAlertTranslations(ctx context.Context, v dyn.Value) (dyn.Value, error) { + // Convert the `file_path` field to a remote absolute path. + // We use this path to point to the alert definition file in the workspace. + + return paths.VisitAlertPaths(v, func(p dyn.Path, mode paths.TranslateMode, v dyn.Value) (dyn.Value, error) { + opts := translateOptions{ + Mode: mode, + } + + return t.rewriteValue(ctx, p, v, t.b.BundleRootPath, opts) + }) +} diff --git a/bundle/config/mutator/translate_paths_alerts_test.go b/bundle/config/mutator/translate_paths_alerts_test.go new file mode 100644 index 0000000000..e02e1958f1 --- /dev/null +++ b/bundle/config/mutator/translate_paths_alerts_test.go @@ -0,0 +1,52 @@ +package mutator_test + +import ( + "path/filepath" + "testing" + + "github.com/databricks/cli/bundle" + "github.com/databricks/cli/bundle/config" + "github.com/databricks/cli/bundle/config/mutator" + "github.com/databricks/cli/bundle/config/resources" + "github.com/databricks/cli/bundle/internal/bundletest" + "github.com/databricks/cli/libs/dyn" + "github.com/databricks/cli/libs/vfs" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestTranslatePathsAlerts_FilePathRelativeSubDirectory(t *testing.T) { + dir := t.TempDir() + touchEmptyFile(t, filepath.Join(dir, "src", "my_alert.dbalert.json")) + + b := &bundle.Bundle{ + SyncRootPath: dir, + BundleRootPath: dir, + SyncRoot: vfs.MustNew(dir), + Config: config.Root{ + Workspace: config.Workspace{ + FilePath: "/bundle", + }, + Resources: config.Resources{ + Alerts: map[string]*resources.Alert{ + "alert": { + FilePath: "../src/my_alert.dbalert.json", + }, + }, + }, + }, + } + + bundletest.SetLocation(b, "resources.alerts", []dyn.Location{{ + File: filepath.Join(dir, "resources/alert.yml"), + }}) + + diags := bundle.ApplySeq(t.Context(), b, mutator.NormalizePaths(), mutator.TranslatePaths()) + require.NoError(t, diags.Error()) + + assert.Equal( + t, + "/bundle/src/my_alert.dbalert.json", + b.Config.Resources.Alerts["alert"].FilePath, + ) +}