Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
cc231f6
Add variable restoration step to config-remote-sync
ilyakuz-db Apr 21, 2026
50e90e1
Lint fix
ilyakuz-db Apr 21, 2026
e86c423
Fix
ilyakuz-db Apr 21, 2026
f3004e1
Update tests
ilyakuz-db Apr 22, 2026
5e2405d
Add support for compound interpolation
ilyakuz-db Apr 22, 2026
2cbf71b
Merge branch 'main' of github.com:databricks/cli into config-remote-s…
ilyakuz-db Apr 22, 2026
d61af60
Fix lint
ilyakuz-db Apr 22, 2026
79a8a60
Update tests
ilyakuz-db Apr 22, 2026
f7fdc01
In "Add" case only restore variables that are added as part of sequen…
ilyakuz-db Apr 23, 2026
88785d3
Merge branch 'main' of github.com:databricks/cli into config-remote-s…
ilyakuz-db Apr 24, 2026
8126579
Proper variable handling for resource IDs
ilyakuz-db Apr 24, 2026
b2249f4
Remove logdiag
ilyakuz-db Apr 24, 2026
61dcccb
Merge branch 'main' of github.com:databricks/cli into config-remote-s…
ilyakuz-db Apr 28, 2026
c6809e3
Fix lint
ilyakuz-db Apr 28, 2026
de6527f
Fall back to any variable when ${var.X} replace doesn't match
ilyakuz-db Apr 29, 2026
2d51710
Switch compound interpolation restore to substring substitution
ilyakuz-db Apr 29, 2026
db6c4bc
Apply source-linked transformation to variable values
ilyakuz-db Apr 29, 2026
e4f77fb
Use mode: development in config-remote-sync acceptance tests
ilyakuz-db Apr 29, 2026
bc097c7
Merge branch 'main' of github.com:databricks/cli into config-remote-s…
ilyakuz-db Apr 29, 2026
a1bec86
Drop dead findAnchorOffset helper
ilyakuz-db Apr 29, 2026
e011de4
Merge branch 'main' of github.com:databricks/cli into config-remote-s…
ilyakuz-db Apr 30, 2026
e95f1f6
Lint fix
ilyakuz-db Apr 30, 2026
55d8f0d
Log warnings
ilyakuz-db May 1, 2026
ab9c35c
Regenerate resolve_variables out.test.toml
ilyakuz-db May 1, 2026
8b5155e
Merge branch 'main' of github.com:databricks/cli into config-remote-s…
ilyakuz-db May 1, 2026
1c12e17
Merge branches 'config-remote-sync-resolve-variables' and 'main' of g…
ilyakuz-db May 4, 2026
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
@@ -0,0 +1,3 @@
{
"file_override_var": "from-overrides-file"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
bundle:
name: test-bundle-$UNIQUE_NAME

variables:
my_catalog:
default: main
# Both resolve to same value to test ambiguity (when we have multiple matches → skip)
landing_schema:
default: raw_data
curated_schema:
default: raw_data
# Variable with value set only in target (no default)
target_env:
description: "Environment name"
# Variable set via .databricks/bundle/<target>/variable-overrides.json
file_override_var:
description: "Set from variable-overrides.json"
# Complex variable to verify no panics
cluster_config:
type: complex
default:
node_type_id: Standard_DS3_v2
num_workers: 2

resources:
pipelines:
my_pipeline:
name: test-pipeline-$UNIQUE_NAME
development: false
libraries:
- notebook:
path: /Users/{{workspace_user_name}}/notebook

jobs:
my_job:
parameters:
- name: catalog
default: ${var.my_catalog}
- name: env
default: ${var.target_env}
- name: file_val
default: ${var.file_override_var}
# Bundle reference: ${bundle.target} resolves to "default".
- name: target_name
default: ${bundle.target}
# Both use variables that resolve to the same value ("raw_data").
# Tests disambiguation: original reference is preserved on Replace.
- name: landing
default: ${var.landing_schema}
- name: curated
default: ${var.curated_schema}
tasks:
- task_key: main
notebook_task:
notebook_path: /Users/{{workspace_user_name}}/notebook
base_parameters:
# Compound interpolation: mixes ${var.X} and ${bundle.X} refs.
source_path: /mnt/${var.my_catalog}/${bundle.target}/raw/landing
# Resource reference: ${resources.pipelines.my_pipeline.id} resolves to
# the deployed pipeline's ID. Used to test that resource refs are
# treated the same as other reference kinds by the sync logic.
- task_key: run_pipeline
pipeline_task:
pipeline_id: ${resources.pipelines.my_pipeline.id}
full_refresh: false

targets:
default:
mode: development
variables:
target_env: production

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

93 changes: 93 additions & 0 deletions acceptance/bundle/config-remote-sync/resolve_variables/output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-bundle-[UNIQUE_NAME]/default/files...
Deploying resources...
Updating deployment state...
Deployment complete!

=== Add and replace parameters remotely
=== Detect and save changes
Detected changes in 1 resource(s):

Resource: resources.jobs.my_job
parameters[name='catalog'].default: replace
parameters[name='data_catalog']: add
parameters[name='deploy_env']: add
parameters[name='deploy_target']: add
parameters[name='file_sourced']: add
parameters[name='region']: add
parameters[name='some_schema']: add
tags['deployment']: add
tags['dev']: remove
tasks[task_key='main'].notebook_task.base_parameters['source_path']: replace
tasks[task_key='run_pipeline'].pipeline_task.full_refresh: replace
tasks[task_key='run_pipeline_again']: add
tasks[task_key='secondary']: add



=== Configuration changes

>>> diff.py databricks.yml.backup databricks.yml
--- databricks.yml.backup
+++ databricks.yml
@@ -36,5 +36,5 @@
parameters:
- name: catalog
- default: ${var.my_catalog}
+ default: staging_catalog
- name: env
default: ${var.target_env}
@@ -50,4 +50,16 @@
- name: curated
default: ${var.curated_schema}
+ - default: ${var.my_catalog}
+ name: data_catalog
+ - default: ${var.target_env}
+ name: deploy_env
+ - default: ${bundle.target}
+ name: deploy_target
+ - default: ${var.file_override_var}
+ name: file_sourced
+ - default: us-west-2
+ name: region
+ - default: raw_data
+ name: some_schema
tasks:
- task_key: main
@@ -56,5 +68,5 @@
base_parameters:
# Compound interpolation: mixes ${var.X} and ${bundle.X} refs.
- source_path: /mnt/${var.my_catalog}/${bundle.target}/raw/landing
+ source_path: /mnt/${var.my_catalog}/${bundle.target}/raw/landing_v2
# Resource reference: ${resources.pipelines.my_pipeline.id} resolves to
# the deployed pipeline's ID. Used to test that resource refs are
@@ -63,5 +75,15 @@
pipeline_task:
pipeline_id: ${resources.pipelines.my_pipeline.id}
- full_refresh: false
+ full_refresh: true
+ - pipeline_task:
+ pipeline_id: ${resources.pipelines.my_pipeline.id}
+ task_key: run_pipeline_again
+ - notebook_task:
+ base_parameters:
+ source_path: /mnt/${var.my_catalog}/${bundle.target}/raw/landing_v2
+ notebook_path: /Users/{{workspace_user_name}}/notebook
+ task_key: secondary
+ tags:
+ deployment: main

targets:

>>> [CLI] bundle destroy --auto-approve
The following resources will be deleted:
delete resources.jobs.my_job
delete resources.pipelines.my_pipeline

This action will result in the deletion of the following Lakeflow Spark Declarative Pipelines along with the
Streaming Tables (STs) and Materialized Views (MVs) managed by them:
delete resources.pipelines.my_pipeline

All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/test-bundle-[UNIQUE_NAME]/default

Deleting files...
Destroy complete!
88 changes: 88 additions & 0 deletions acceptance/bundle/config-remote-sync/resolve_variables/script
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#!/bin/bash

envsubst < databricks.yml.tmpl > databricks.yml

cleanup() {
trace $CLI bundle destroy --auto-approve
}
trap cleanup EXIT

$CLI bundle deploy
job_id="$(read_id.py my_job)"

title "Add and replace parameters remotely"
edit_resource.py jobs $job_id <<EOF
# --- Add operations (reverse map) ---
# "main" matches exactly one variable (my_catalog) -> restored to \${var.my_catalog}
r["parameters"].append({"name": "data_catalog", "default": "main"})
# "raw_data" matches two variables (landing_schema, curated_schema) -> ambiguous, stays hardcoded
r["parameters"].append({"name": "some_schema", "default": "raw_data"})
# "us-west-2" matches no variable -> stays hardcoded
r["parameters"].append({"name": "region", "default": "us-west-2"})
# "production" matches target_env (set in target, not default) -> restored to \${var.target_env}
r["parameters"].append({"name": "deploy_env", "default": "production"})
# "from-overrides-file" matches file_override_var (set via variable-overrides.json) -> restored
r["parameters"].append({"name": "file_sourced", "default": "from-overrides-file"})
# "default" matches sibling target_name's \${bundle.target} -> restored
r["parameters"].append({"name": "deploy_target", "default": "default"})

# Add a new task with the same structure as the existing one (different task_key).
# The sibling's source_path uses compound interpolation with \${var.my_catalog} and
# \${bundle.target}; the new task's source_path matches the resolved template, so
# both variables should be restored via compound-sibling alignment.
r["tasks"].append({
"task_key": "secondary",
"notebook_task": {
"notebook_path": r["tasks"][0]["notebook_task"]["notebook_path"],
"base_parameters": {"source_path": "/mnt/main/default/raw/landing"}
}
})

# Change full_refresh on the existing run_pipeline task. The sibling field
# pipeline_id uses \${resources.pipelines.my_pipeline.id} and must stay
# intact in the YAML because the Replace only affects full_refresh.
for t in r["tasks"]:
if t.get("task_key") == "run_pipeline":
t["pipeline_task"]["full_refresh"] = True

# Add a new pipeline task that triggers the same pipeline. The sibling
# run_pipeline has pipeline_id = \${resources.pipelines.my_pipeline.id}; the
# new task uses the same resolved ID, so the sibling rule should restore
# the resource reference.
pipeline_id = next(t for t in r["tasks"] if t["task_key"] == "run_pipeline")["pipeline_task"]["pipeline_id"]
r["tasks"].append({
"task_key": "run_pipeline_again",
"pipeline_task": {
"pipeline_id": pipeline_id,
}
})

# --- Replace operations (original ref) ---
# Change "catalog" param (originally \${var.my_catalog} = "main") to unrelated value -> hardcoded
for p in r["parameters"]:
if p["name"] == "catalog":
p["default"] = "staging_catalog"

# --- Non-sequence Add (false-positive prevention) ---
# Add tags to the job. Tags is a map (not a sequence), so Add restoration is
# skipped entirely: "main" stays hardcoded even though it matches \${var.my_catalog}.
r["tags"] = {"deployment": "main"}

# Compound interpolation: change only the suffix of source_path.
# Both \${var.my_catalog}="main" and \${bundle.target}="default" are unchanged;
# only the literal suffix changes. Expected: both refs preserved, suffix updated.
for t in r["tasks"]:
bp = t.get("notebook_task", {}).get("base_parameters", {})
if "source_path" in bp:
bp["source_path"] = "/mnt/main/default/raw/landing_v2"
EOF

title "Detect and save changes"
echo
cp databricks.yml databricks.yml.backup
$CLI bundle config-remote-sync --save

title "Configuration changes"
echo
trace diff.py databricks.yml.backup databricks.yml
rm databricks.yml.backup
11 changes: 11 additions & 0 deletions acceptance/bundle/config-remote-sync/resolve_variables/test.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
Cloud = true
RequiresUnityCatalog = true

RecordRequests = false
Ignore = [".databricks", "databricks.yml", "databricks.yml.backup"]

[Env]
DATABRICKS_BUNDLE_ENABLE_EXPERIMENTAL_YAML_SYNC = "true"

[EnvMatrix]
DATABRICKS_BUNDLE_ENGINE = ["direct", "terraform"]
Loading
Loading