Skip to content

Conversation

@ilyakuz-db
Copy link
Contributor

@ilyakuz-db ilyakuz-db commented Jan 15, 2026

Changes

New experimental command databricks bundle config-remote-sync. The command fetches the latest remote changes of resources and compares them to the deployed state. With the --save flag, it also writes changes back to YAML files.

The command leverages the diffing algorithm of the bundle plan command. Also note that new dependency is added to do yaml patching that preserves comments

This is a first PR, I will continue fixing all limitations in the next PRs

Current limitations:

  • The command only works in direct mode, for TF engine the plan is to prepare a deploy-time conversion of Terraform state to direct engine state (behind the env-flag DATABRICKS_BUNDLE_ENABLE_EXPERIMENTAL_YAML_SYNC)
  • Server-side defaults are hardcoded for now until it is better supported in the bundle plan
  • Selectors like tasks[task_key='my_task'] need to be tested for cases when the object or parent doesn't exist
  • CLI transformations (dev prefixes, path translations, resource mutators etc) and variables are not properly handled, so there are some bugs possible when it affects these fields
  • Tested only for jobs

No changelog entries are needed as the command is intended to be private for now, and we don't want to encourage users to use it due to the unstable API

Why

This command serves as the backend for the new visual authoring feature in DABs in the Workspace.

User edits job or pipeline in the Workspace UI, then clicks the "Sync" button, and then the new command applies the diff to the source configuration files. Then the user may accept or reject these changes in the editor

Tests

Currently, only unit tests to speed up devloop, but once I have full functionality, I'll add proper acceptance test coverage

Acceptance tests are failing because of the change in formatting (even though the command is hidden)

@eng-dev-ecosystem-bot
Copy link
Collaborator

eng-dev-ecosystem-bot commented Jan 15, 2026

Commit: cf60183

Run: 21249477366

Env 🟨​KNOWN 💚​RECOVERED 🙈​SKIP ✅​pass 🙈​skip Time
🟨​ aws linux 7 1 6 411 710 20:56
🟨​ aws windows 7 1 6 413 708 21:53
💚​ azure linux 2 8 411 709 21:52
💚​ azure windows 2 8 413 707 20:48
💚​ gcp linux 2 8 400 715 21:59
💚​ gcp windows 2 8 402 713 19:43
14 interesting tests: 7 KNOWN, 6 SKIP, 1 RECOVERED
Test Name aws linux aws windows azure linux azure windows gcp linux gcp windows
🟨​ TestAccept 🟨​K 🟨​K 💚​R 💚​R 💚​R 💚​R
🙈​ TestAccept/bundle/deployment/bind/alert 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/generate/alert 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/alerts/basic 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/alerts/with_file 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/permissions 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🟨​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/with_permissions 🟨​K 🟨​K 🙈​S 🙈​S 🙈​S 🙈​S
🟨​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/with_permissions/DATABRICKS_BUNDLE_ENGINE=direct 🟨​K 🟨​K
🟨​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/with_permissions/DATABRICKS_BUNDLE_ENGINE=terraform 🟨​K 🟨​K
🟨​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/without_permissions 🟨​K 🟨​K 🙈​S 🙈​S 🙈​S 🙈​S
🟨​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/without_permissions/DATABRICKS_BUNDLE_ENGINE=direct 🟨​K 🟨​K
🟨​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/without_permissions/DATABRICKS_BUNDLE_ENGINE=terraform 🟨​K 🟨​K
🙈​ TestAccept/bundle/resources/synced_database_tables/basic 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
💚​ TestAccept/ssh/connection 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R
Top 21 slowest tests (at least 2 minutes):
duration env testname
5:50 azure linux TestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=direct
5:49 gcp windows TestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=terraform
5:31 aws windows TestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=direct
5:23 gcp linux TestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=direct
5:17 gcp windows TestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=direct
5:08 gcp linux TestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=terraform
3:46 gcp linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
3:27 gcp windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
3:13 gcp linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
3:10 gcp windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
3:03 aws windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
2:50 azure linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
2:47 aws windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
2:18 aws linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
2:12 aws linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
2:12 azure windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
2:12 azure linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
2:10 aws linux TestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=terraform
2:09 aws linux TestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=direct
2:09 aws windows TestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=terraform
2:09 azure windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct

Copy link
Contributor

@denik denik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add some acceptance tests?

You can see examples here that modify remote resource:

% git ls-files | find . -type d | grep remote
./bundle/resources/permissions/jobs/deleted_remotely
./bundle/resources/permissions/jobs/added_remotely
./bundle/resources/permissions/jobs/reorder_remotely
./bundle/resources/volumes/remote-delete
./bundle/resources/volumes/remote-change-name
./bundle/resources/jobs/remote_add_tag
./bundle/resources/jobs/remote_matches_config
./bundle/resources/jobs/remote_delete
./bundle/resources/jobs/remote_delete/destroy
./bundle/resources/jobs/remote_delete/deploy
./bundle/resource_deps/remote_field_storage_location
./bundle/resource_deps/remote_app_url
./bundle/resource_deps/remote_app_url/app
./bundle/resource_deps/jobs_update_remote
./bundle/resource_deps/remote_pipeline

schema Generate JSON Schema for bundle configuration
summary Summarize resources deployed by this bundle
sync Synchronize bundle tree to the workspace
validate Validate configuration
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The output seems to be the same except for whitespace?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, probably a bug in help/Cobra? New command is hidden, but help reserves space for it.

isDefault: isEmptyStruct,
},
{
pattern: regexp.MustCompile(`^webhook_notifications$`),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can probably drop these, they now using different reason: #4338

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep that works good now, thanks!

currentValue := b.Config.Value()

for i, n := range nodes {
if key, ok := n.StringKey(); ok {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

StringKey might be rendered with a dot or with [""] or with [''] depending on string contents.

I suggest to output PathNode and then convert it to string rather than recreate the string directly.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, updated to use path nodes

@ilyakuz-db ilyakuz-db requested a review from denik January 22, 2026 11:39
@ilyakuz-db
Copy link
Contributor Author

@denik I added acceptance tests and addressed all comments

Copy link
Contributor

@denik denik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestions: add permissions to some of the test configs.

}

if save {
if err := configsync.SaveFiles(ctx, b, files); err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like --save will write the updated files and will also print a diff. Is that intentional? I'd expect that you either need a diff or in-place updates but not both.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is pretty useful, I can avoid reading the affected files in the UI when I need to pass this diff to the accept/reject UI

Also quite useful for debugging

cmd.Flags().BoolVar(&save, "save", false, "Write updated config files to disk")

cmd.RunE = func(cmd *cobra.Command, args []string) error {
b, _, err := utils.ProcessBundleRet(cmd, utils.ProcessOptions{})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see that plan command does this:

        cmd.RunE = func(cmd *cobra.Command, args []string) error {
                opts := utils.ProcessOptions{
                        AlwaysPull:      true,
                        FastValidate:    true,
                        Build:           true,
                        PreDeployChecks: true,
                }

You need Build because it updates the configuration and hence the plan. You probably also want AlwaysPull as well.


title "Updated configuration"
echo
cat databricks.yml
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we record diff old_databricks.yml new_databricks.yml here instead of full config? It's hard to see if there are any subtle changes there.

my_job:
email_notifications:
on_success:
- success@example.com
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO a few of these tests can be combined into one, e.g. formatting_preserved, job_email_notifications

@@ -0,0 +1,8 @@
Local = true
Cloud = false
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Running some of these tests on Cloud would actually be useful here since extra fields backends adds can play a role.

for task in r["tasks"]:
if task["task_key"] == "process":
task["new_cluster"]["num_workers"] = 5
task["timeout_seconds"] = 3600
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: also delete a task in the middle to see how it copes.

jsonPointers = append(jsonPointers, targetPrefix+jsonPointer)
}

hasConfigValue := changeDesc.Old != nil || changeDesc.New != nil
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have a test where a field is removed in remote and in config (New)?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants