Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ bundle:
resources:
jobs:
my_job:
name: test-job-$UNIQUE_NAME
email_notifications:
on_success:
- success@example.com
Expand Down
14 changes: 10 additions & 4 deletions acceptance/bundle/config-remote-sync/job_fields/output.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Resource: resources.jobs.my_job
email_notifications.no_alert_for_skipped_runs: add
email_notifications.on_failure: add
job_clusters[0].job_cluster_key: replace
name: replace
parameters: replace
tags['team']: add
tasks[task_key='inline_cluster_task'].new_cluster.num_workers: replace
Expand All @@ -28,7 +29,12 @@ Resource: resources.jobs.my_job
>>> diff.py databricks.yml.backup databricks.yml
--- databricks.yml.backup
+++ databricks.yml
@@ -8,13 +8,19 @@
@@ -5,20 +5,26 @@
jobs:
my_job:
- name: test-job-[UNIQUE_NAME]
+ name: renamed-job-[UNIQUE_NAME]
email_notifications:
on_success:
- success@example.com
+ no_alert_for_skipped_runs: true
Expand All @@ -55,21 +61,21 @@ Resource: resources.jobs.my_job
+ - samples.nyctaxi.trips
environments:
- environment_key: default
@@ -24,5 +30,5 @@
@@ -27,5 +33,5 @@
- ./*.whl
job_clusters:
- - job_cluster_key: test_cluster
+ - job_cluster_key: test_cluster_renamed
new_cluster:
spark_version: [[DEFAULT_SPARK_VERSION]]
@@ -33,5 +39,5 @@
@@ -36,5 +42,5 @@
notebook_task:
notebook_path: /Users/{{workspace_user_name}}/notebook
- job_cluster_key: test_cluster
+ job_cluster_key: test_cluster_renamed
- task_key: inline_cluster_task
notebook_task:
@@ -40,5 +46,7 @@
@@ -43,5 +49,7 @@
spark_version: [[DEFAULT_SPARK_VERSION]]
node_type_id: [NODE_TYPE_ID]
- num_workers: 1
Expand Down
2 changes: 2 additions & 0 deletions acceptance/bundle/config-remote-sync/job_fields/script
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ job_id="$(read_id.py my_job)"
title "Modify job fields remotely"
echo
edit_resource.py jobs $job_id <<EOF
# Rename the job remotely; config-remote-sync should strip the dev prefix
r["name"] = r["name"].replace("test-job-$UNIQUE_NAME", "renamed-job-$UNIQUE_NAME")
r["email_notifications"]["on_failure"] = ["failure@example.com"]
r["email_notifications"]["no_alert_for_skipped_runs"] = True
r["parameters"].append({"name": "region", "default": "us-east-1"})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Detected changes in 1 resource(s):
Resource: resources.pipelines.my_pipeline
configuration['key2']: add
environment.dependencies: replace
name: replace
notifications[0].alerts: replace
notifications[0].email_recipients: replace
root_path: add
Expand All @@ -24,7 +25,8 @@ Resource: resources.pipelines.my_pipeline
--- databricks.yml.backup
+++ databricks.yml
@@ -7,18 +7,25 @@
name: test-pipeline-[UNIQUE_NAME]
- name: test-pipeline-[UNIQUE_NAME]
+ name: renamed-pipeline-[UNIQUE_NAME]
catalog: main
- schema: default
+ schema: prod
Expand Down
2 changes: 2 additions & 0 deletions acceptance/bundle/config-remote-sync/pipeline_fields/script
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ pipeline_id="$(read_id.py my_pipeline)"

title "Modify pipeline fields remotely"
edit_resource.py pipelines $pipeline_id <<EOF
# Rename the pipeline remotely; config-remote-sync should strip the dev prefix
r["name"] = r["name"].replace("test-pipeline-$UNIQUE_NAME", "renamed-pipeline-$UNIQUE_NAME")
r["configuration"]["key2"] = "value2"
r["notifications"][0]["email_recipients"].append("admin@example.com")
r["notifications"][0]["alerts"].append("on-update-failure")
Expand Down
30 changes: 30 additions & 0 deletions bundle/configsync/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,3 +176,33 @@ func resetValueIfNeeded(path string, value any) any {
}
return value
}

// prefixedNameFields lists resource name field patterns where the name prefix
// (e.g. "[dev user] ") is applied during deployment and should be stripped
// when syncing remote changes back to config.
var prefixedNameFields = []string{
"resources.jobs.*.name",
"resources.pipelines.*.name",
"resources.dashboards.*.display_name",
}

// stripNamePrefix strips the configured name prefix from name field values
// so that the raw (unprefixed) name is written back to the config YAML.
func stripNamePrefix(path string, value any, prefix string) any {
if prefix == "" {
return value
}

s, ok := value.(string)
if !ok {
return value
}

for _, pattern := range prefixedNameFields {
if matchPattern(pattern, path) {
return strings.TrimPrefix(s, prefix)
}
}

return value
}
4 changes: 3 additions & 1 deletion bundle/configsync/diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,13 +149,15 @@ func DetectChanges(ctx context.Context, b *bundle.Bundle, engine engine.EngineTy
continue
}

change, err := convertChangeDesc(resourceKey+"."+path, changeDesc)
fullPath := resourceKey + "." + path
change, err := convertChangeDesc(fullPath, changeDesc)
if err != nil {
return nil, fmt.Errorf("failed to compute config change for path %s: %w", path, err)
}
if change.Operation == OperationSkip {
continue
}
change.Value = stripNamePrefix(fullPath, change.Value, b.Config.Presets.NamePrefix)
resourceChanges[path] = change
}
}
Expand Down
74 changes: 74 additions & 0 deletions bundle/configsync/diff_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,80 @@ import (
"github.com/stretchr/testify/assert"
)

func TestStripNamePrefix(t *testing.T) {
tests := []struct {
name string
path string
value any
prefix string
want any
}{
{
name: "job name with normal prefix",
path: "resources.jobs.my_job.name",
value: "[dev user] my_job",
prefix: "[dev user] ",
want: "my_job",
},
{
name: "pipeline name with normal prefix",
path: "resources.pipelines.my_pipeline.name",
value: "[dev user] my_pipeline",
prefix: "[dev user] ",
want: "my_pipeline",
},
{
name: "dashboard display_name with prefix",
path: "resources.dashboards.my_dash.display_name",
value: "[dev user] my_dash",
prefix: "[dev user] ",
want: "my_dash",
},
{
name: "name does not start with prefix",
path: "resources.jobs.my_job.name",
value: "my_job",
prefix: "[dev user] ",
want: "my_job",
},
{
name: "empty prefix is noop",
path: "resources.jobs.my_job.name",
value: "[dev user] my_job",
prefix: "",
want: "[dev user] my_job",
},
{
name: "non-name field is not stripped",
path: "resources.jobs.my_job.description",
value: "[dev user] some description",
prefix: "[dev user] ",
want: "[dev user] some description",
},
{
name: "non-string value is unchanged",
path: "resources.jobs.my_job.name",
value: 42,
prefix: "[dev user] ",
want: 42,
},
{
name: "nil value is unchanged",
path: "resources.jobs.my_job.name",
value: nil,
prefix: "[dev user] ",
want: nil,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := stripNamePrefix(tt.path, tt.value, tt.prefix)
assert.Equal(t, tt.want, got)
})
}
}

func TestMatchPattern(t *testing.T) {
tests := []struct {
name string
Expand Down
Loading