Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
5590258
bundle: record and read deployment state via DMS with server-generate…
shreyas-goenka Jul 23, 2026
da1ed9d
bundle: read DMS authority from last_successful_version_id
shreyas-goenka Jul 24, 2026
011c092
bundle: fix DMS deployment recording bugs found in review
shreyas-goenka Jul 27, 2026
38dc082
bundle: upload DMS operations asynchronously
shreyas-goenka Jul 27, 2026
19467dc
bundle: gate experimental.record_deployment_history behind an env var
shreyas-goenka Jul 27, 2026
22ec66a
bundle: rename the record_deployment_history escape hatch to force_allow
shreyas-goenka Jul 27, 2026
d7441e4
bundle: only record net-new deployments in DMS
shreyas-goenka Jul 27, 2026
026a521
bundle: fix lint errors in the operation queue test
shreyas-goenka Jul 27, 2026
481259b
bundle: keep the create action when coalescing DMS operations
shreyas-goenka Jul 27, 2026
309a1a4
bundle: drop the dms package comment
shreyas-goenka Jul 27, 2026
211aa94
bundle: resolve the DMS deployment ID from the workspace
shreyas-goenka Jul 27, 2026
4009eb4
bundle: address review of the DMS state PR
shreyas-goenka Jul 28, 2026
70741ae
bundle: record depends_on in the state uploaded to DMS
shreyas-goenka Jul 28, 2026
386a0b6
bundle: drop the DMS state overlay check
shreyas-goenka Jul 28, 2026
efe7320
bundle: gate DMS state on a state feature flag
shreyas-goenka Jul 28, 2026
92eac95
bundle: combine queued operations into a single Create action
shreyas-goenka Jul 29, 2026
96c0826
acceptance: set MSYS_NO_PATHCONV for the DMS tests
shreyas-goenka Jul 29, 2026
b2ef0e8
acceptance: scope MSYS_NO_PATHCONV to the get-status commands
shreyas-goenka Jul 29, 2026
30adb99
bundle: drop the locks in the operation queue's close
shreyas-goenka Jul 29, 2026
8f56ef6
bundle: record operation state without redacting it
shreyas-goenka Jul 29, 2026
329886f
bundle: drop the redaction TODO from the operation recorder
shreyas-goenka Jul 29, 2026
2818d11
bundle: revert the schema annotation and tighten CompleteVersion's guard
shreyas-goenka Jul 29, 2026
b84ae7c
bundle: gate record_deployment_history off again
shreyas-goenka Jul 29, 2026
daa69e2
bundle: stop the deploy when an operation upload fails
shreyas-goenka Jul 29, 2026
2c2e209
bundle: stop applying resources once an operation upload fails
shreyas-goenka Jul 29, 2026
9329441
testserver: create the DMS deployment record on the first version
shreyas-goenka Jul 29, 2026
38b6f54
bundle: simplify the concurrency test comment
shreyas-goenka Jul 29, 2026
4f45539
bundle: trim the operation recorder tests
shreyas-goenka Jul 29, 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
13 changes: 13 additions & 0 deletions acceptance/bundle/dms/depends-on/databricks.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
bundle:
name: dms-depends-on

experimental:
record_deployment_history: true

resources:
jobs:
parent:
name: parent
child:
name: child
description: depends on ${resources.jobs.parent.id}
3 changes: 3 additions & 0 deletions acceptance/bundle/dms/depends-on/out.test.toml

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

87 changes: 87 additions & 0 deletions acceptance/bundle/dms/depends-on/output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@

=== Deploy a job that references another: depends_on is recorded alongside the config, since the reference is resolved to a literal in the config itself
>>> [CLI] bundle deploy
Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/dms-depends-on/default/files...
Deploying resources...
Updating deployment state...
Deployment complete!

>>> print_requests.py //versions/1/operations --sort
{
"method": "POST",
"path": "/api/2.0/bundle/deployments/[NUMID]/versions/1/operations",
"q": {
"resource_key": "jobs.child"
},
"body": {
"action_type": "OPERATION_ACTION_TYPE_CREATE",
"resource_id": "[NUMID]",
"resource_key": "jobs.child",
"state": {
"state": {
"deployment": {
"kind": "BUNDLE",
"metadata_file_path": "/Workspace/Users/[USERNAME]/.bundle/dms-depends-on/default/state/metadata.json"
},
"description": "depends on [NUMID]",
"edit_mode": "UI_LOCKED",
"format": "MULTI_TASK",
"max_concurrent_runs": 1,
"name": "child",
"queue": {
"enabled": true
}
},
"depends_on": [
{
"node": "resources.jobs.parent",
"label": "${resources.jobs.parent.id}"
}
]
},
"status": "OPERATION_STATUS_SUCCEEDED"
}
}
{
"method": "POST",
"path": "/api/2.0/bundle/deployments/[NUMID]/versions/1/operations",
"q": {
"resource_key": "jobs.parent"
},
"body": {
"action_type": "OPERATION_ACTION_TYPE_CREATE",
"resource_id": "[NUMID]",
"resource_key": "jobs.parent",
"state": {
"state": {
"deployment": {
"kind": "BUNDLE",
"metadata_file_path": "/Workspace/Users/[USERNAME]/.bundle/dms-depends-on/default/state/metadata.json"
},
"edit_mode": "UI_LOCKED",
"format": "MULTI_TASK",
"max_concurrent_runs": 1,
"name": "parent",
"queue": {
"enabled": true
}
}
},
"status": "OPERATION_STATUS_SUCCEEDED"
}
}

=== Wipe the local state, then destroy: depends_on comes back from DMS, so the child is still deleted before the parent it references
>>> [CLI] bundle destroy --auto-approve
The following resources will be deleted:
delete resources.jobs.child
delete resources.jobs.parent

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

Deleting files...
Destroy complete!

>>> print_requests.py //jobs --oneline
{"method": "POST", "path": "/api/2.2/jobs/delete", "body": {"job_id": [NUMID]}}
{"method": "POST", "path": "/api/2.2/jobs/delete", "body": {"job_id": [NUMID]}}
8 changes: 8 additions & 0 deletions acceptance/bundle/dms/depends-on/script
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
title "Deploy a job that references another: depends_on is recorded alongside the config, since the reference is resolved to a literal in the config itself"
trace $CLI bundle deploy
trace print_requests.py //versions/1/operations --sort

title "Wipe the local state, then destroy: depends_on comes back from DMS, so the child is still deleted before the parent it references"
rm -rf .databricks
trace $CLI bundle destroy --auto-approve
trace print_requests.py //jobs --oneline
10 changes: 10 additions & 0 deletions acceptance/bundle/dms/existing-state/databricks.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
bundle:
name: dms-existing-state

experimental:
record_deployment_history: false

resources:
jobs:
one:
name: one
3 changes: 3 additions & 0 deletions acceptance/bundle/dms/existing-state/out.test.toml

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

52 changes: 52 additions & 0 deletions acceptance/bundle/dms/existing-state/output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@

=== Deploy without recording: the bundle gets ordinary direct-engine state, unknown to DMS
>>> [CLI] bundle deploy
Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/dms-existing-state/default/files...
Deploying resources...
Updating deployment state...
Deployment complete!

>>> print_requests.py //api/2.0/bundle --oneline

=== Turning recording on afterwards is an error: those resources were never recorded, so treating DMS as authoritative would deploy them a second time
>>> update_file.py databricks.yml record_deployment_history: false record_deployment_history: true

>>> musterr [CLI] bundle deploy
Error: cannot record deployment history for a bundle that already has deployed resources tracked in [TEST_TMP_DIR]/.databricks/bundle/default/resources.json: only new deployments can be recorded. Remove experimental.record_deployment_history, or destroy the bundle and deploy it again


=== No deployment was created in DMS
>>> print_requests.py //api/2.0/bundle --oneline

=== Still an error after wiping the local cache: deploy pulls the state file back from the workspace, so the resources are still tracked
>>> musterr [CLI] bundle deploy
Error: cannot record deployment history for a bundle that already has deployed resources tracked in [TEST_TMP_DIR]/.databricks/bundle/default/resources.json: only new deployments can be recorded. Remove experimental.record_deployment_history, or destroy the bundle and deploy it again


>>> print_requests.py //api/2.0/bundle --oneline

=== Destroy clears the tracked resources, so recording can be enabled afterwards
>>> update_file.py databricks.yml record_deployment_history: true record_deployment_history: false

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

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

Deleting files...
Destroy complete!

>>> update_file.py databricks.yml record_deployment_history: false record_deployment_history: true

>>> [CLI] bundle deploy
Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/dms-existing-state/default/files...
Deploying resources...
Updating deployment state...
Deployment complete!

>>> print_requests.py //api/2.0/bundle --oneline
{"method": "POST", "path": "/api/2.0/bundle/deployments", "body": {"initial_parent_path": "/Workspace/Users/[USERNAME]/.bundle/dms-existing-state/default/state", "target_name": "default"}}
{"method": "POST", "path": "/api/2.0/bundle/deployments/[NUMID]/versions", "q": {"version_id": "1"}, "body": {"cli_version": "[CLI_VERSION]", "target_name": "default", "version_type": "VERSION_TYPE_DEPLOY"}}
{"method": "POST", "path": "/api/2.0/bundle/deployments/[NUMID]/versions/1/operations", "q": {"resource_key": "jobs.one"}, "body": {"action_type": "OPERATION_ACTION_TYPE_CREATE", "resource_id": "[NUMID]", "resource_key": "jobs.one", "state": {"state": {"deployment": {"kind": "BUNDLE", "metadata_file_path": "/Workspace/Users/[USERNAME]/.bundle/dms-existing-state/default/state/metadata.json"}, "edit_mode": "UI_LOCKED", "format": "MULTI_TASK", "max_concurrent_runs": 1, "name": "one", "queue": {"enabled": true}}}, "status": "OPERATION_STATUS_SUCCEEDED"}}
{"method": "POST", "path": "/api/2.0/bundle/deployments/[NUMID]/versions/1/complete", "body": {"completion_reason": "VERSION_COMPLETE_SUCCESS"}}
22 changes: 22 additions & 0 deletions acceptance/bundle/dms/existing-state/script
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
title "Deploy without recording: the bundle gets ordinary direct-engine state, unknown to DMS"
trace $CLI bundle deploy
trace print_requests.py //api/2.0/bundle --oneline

title "Turning recording on afterwards is an error: those resources were never recorded, so treating DMS as authoritative would deploy them a second time"
trace update_file.py databricks.yml "record_deployment_history: false" "record_deployment_history: true"
trace musterr $CLI bundle deploy

title "No deployment was created in DMS"
trace print_requests.py //api/2.0/bundle --oneline

title "Still an error after wiping the local cache: deploy pulls the state file back from the workspace, so the resources are still tracked"
rm -rf .databricks
trace musterr $CLI bundle deploy
trace print_requests.py //api/2.0/bundle --oneline

title "Destroy clears the tracked resources, so recording can be enabled afterwards"
trace update_file.py databricks.yml "record_deployment_history: true" "record_deployment_history: false"
trace $CLI bundle destroy --auto-approve
trace update_file.py databricks.yml "record_deployment_history: false" "record_deployment_history: true"
trace $CLI bundle deploy
trace print_requests.py //api/2.0/bundle --oneline
18 changes: 18 additions & 0 deletions acceptance/bundle/dms/multiple-resources/databricks.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
bundle:
name: dms-multiple-resources

experimental:
record_deployment_history: true

resources:
jobs:
one:
name: one
two:
name: two
three:
name: three
four:
name: four
five:
name: five
3 changes: 3 additions & 0 deletions acceptance/bundle/dms/multiple-resources/out.test.toml

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

25 changes: 25 additions & 0 deletions acceptance/bundle/dms/multiple-resources/output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

=== Deploy several resources: operations are uploaded from background workers, so exactly one is recorded per resource no matter what order the uploads finish in. The serialized state is dropped from the output here; bundle/dms/record covers it.
>>> [CLI] bundle deploy
Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/dms-multiple-resources/default/files...
Deploying resources...
Updating deployment state...
Deployment complete!

>>> print_requests.py //versions/1/operations --sort --del-body state --oneline
{"method": "POST", "path": "/api/2.0/bundle/deployments/[NUMID]/versions/1/operations", "q": {"resource_key": "jobs.five"}, "body": {"action_type": "OPERATION_ACTION_TYPE_CREATE", "resource_id": "[NUMID]", "resource_key": "jobs.five", "status": "OPERATION_STATUS_SUCCEEDED"}}
{"method": "POST", "path": "/api/2.0/bundle/deployments/[NUMID]/versions/1/operations", "q": {"resource_key": "jobs.four"}, "body": {"action_type": "OPERATION_ACTION_TYPE_CREATE", "resource_id": "[NUMID]", "resource_key": "jobs.four", "status": "OPERATION_STATUS_SUCCEEDED"}}
{"method": "POST", "path": "/api/2.0/bundle/deployments/[NUMID]/versions/1/operations", "q": {"resource_key": "jobs.one"}, "body": {"action_type": "OPERATION_ACTION_TYPE_CREATE", "resource_id": "[NUMID]", "resource_key": "jobs.one", "status": "OPERATION_STATUS_SUCCEEDED"}}
{"method": "POST", "path": "/api/2.0/bundle/deployments/[NUMID]/versions/1/operations", "q": {"resource_key": "jobs.three"}, "body": {"action_type": "OPERATION_ACTION_TYPE_CREATE", "resource_id": "[NUMID]", "resource_key": "jobs.three", "status": "OPERATION_STATUS_SUCCEEDED"}}
{"method": "POST", "path": "/api/2.0/bundle/deployments/[NUMID]/versions/1/operations", "q": {"resource_key": "jobs.two"}, "body": {"action_type": "OPERATION_ACTION_TYPE_CREATE", "resource_id": "[NUMID]", "resource_key": "jobs.two", "status": "OPERATION_STATUS_SUCCEEDED"}}

=== Redeploy with no changes: nothing is applied, so no operations are recorded and only the version is opened and completed
>>> [CLI] bundle deploy
Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/dms-multiple-resources/default/files...
Deploying resources...
Updating deployment state...
Deployment complete!

>>> print_requests.py //api/2.0/bundle --sort --oneline
{"method": "POST", "path": "/api/2.0/bundle/deployments/[NUMID]/versions", "q": {"version_id": "2"}, "body": {"cli_version": "[CLI_VERSION]", "target_name": "default", "version_type": "VERSION_TYPE_DEPLOY"}}
{"method": "POST", "path": "/api/2.0/bundle/deployments/[NUMID]/versions/2/complete", "body": {"completion_reason": "VERSION_COMPLETE_SUCCESS"}}
7 changes: 7 additions & 0 deletions acceptance/bundle/dms/multiple-resources/script
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
title "Deploy several resources: operations are uploaded from background workers, so exactly one is recorded per resource no matter what order the uploads finish in. The serialized state is dropped from the output here; bundle/dms/record covers it."
trace $CLI bundle deploy
trace print_requests.py //versions/1/operations --sort --del-body state --oneline

title "Redeploy with no changes: nothing is applied, so no operations are recorded and only the version is opened and completed"
trace $CLI bundle deploy
trace print_requests.py //api/2.0/bundle --sort --oneline
5 changes: 5 additions & 0 deletions acceptance/bundle/dms/no-resources/databricks.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
bundle:
name: dms-no-resources

experimental:
record_deployment_history: true
3 changes: 3 additions & 0 deletions acceptance/bundle/dms/no-resources/out.test.toml

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

76 changes: 76 additions & 0 deletions acceptance/bundle/dms/no-resources/output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@

=== First deploy of a bundle with no resources: the deployment is created, and its workspace node identifies it even though no resource state was written
>>> [CLI] bundle deploy
Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/dms-no-resources/default/files...
Deploying resources...
Deployment complete!

>>> print_requests.py //api/2.0/bundle --get
{
"method": "POST",
"path": "/api/2.0/bundle/deployments",
"body": {
"initial_parent_path": "/Workspace/Users/[USERNAME]/.bundle/dms-no-resources/default/state",
"target_name": "default"
}
}
{
"method": "POST",
"path": "/api/2.0/bundle/deployments/[NUMID]/versions",
"q": {
"version_id": "1"
},
"body": {
"cli_version": "[CLI_VERSION]",
"target_name": "default",
"version_type": "VERSION_TYPE_DEPLOY"
}
}
{
"method": "POST",
"path": "/api/2.0/bundle/deployments/[NUMID]/versions/1/complete",
"body": {
"completion_reason": "VERSION_COMPLETE_SUCCESS"
}
}

>>> MSYS_NO_PATHCONV=1 [CLI] workspace get-status /Workspace/Users/[USERNAME]/.bundle/dms-no-resources/default/state/resources.deployment.json
{
"object_type": "FILE",
"path": "/Workspace/Users/[USERNAME]/.bundle/dms-no-resources/default/state/resources.deployment.json"
}

=== Redeploy: the deployment is resolved from that node, so no second deployment is created
>>> [CLI] bundle deploy
Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/dms-no-resources/default/files...
Deploying resources...
Deployment complete!

>>> print_requests.py //api/2.0/bundle --get
{
"method": "GET",
"path": "/api/2.0/bundle/deployments/[NUMID]/resources"
}
{
"method": "GET",
"path": "/api/2.0/bundle/deployments/[NUMID]"
}
{
"method": "POST",
"path": "/api/2.0/bundle/deployments/[NUMID]/versions",
"q": {
"version_id": "2"
},
"body": {
"cli_version": "[CLI_VERSION]",
"target_name": "default",
"version_type": "VERSION_TYPE_DEPLOY"
}
}
{
"method": "POST",
"path": "/api/2.0/bundle/deployments/[NUMID]/versions/2/complete",
"body": {
"completion_reason": "VERSION_COMPLETE_SUCCESS"
}
}
8 changes: 8 additions & 0 deletions acceptance/bundle/dms/no-resources/script
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
title "First deploy of a bundle with no resources: the deployment is created, and its workspace node identifies it even though no resource state was written"
trace $CLI bundle deploy
trace print_requests.py //api/2.0/bundle --get
trace MSYS_NO_PATHCONV=1 $CLI workspace get-status "/Workspace/Users/${CURRENT_USER_NAME}/.bundle/dms-no-resources/default/state/resources.deployment.json" | jq '{object_type,path}'

title "Redeploy: the deployment is resolved from that node, so no second deployment is created"
trace $CLI bundle deploy
trace print_requests.py //api/2.0/bundle --get
10 changes: 10 additions & 0 deletions acceptance/bundle/dms/not-supported/databricks.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
bundle:
name: dms-not-supported

experimental:
record_deployment_history: true

resources:
jobs:
one:
name: one
3 changes: 3 additions & 0 deletions acceptance/bundle/dms/not-supported/out.test.toml

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

24 changes: 24 additions & 0 deletions acceptance/bundle/dms/not-supported/output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@

=== record_deployment_history is rejected: the service side is not ready for users yet
>>> musterr [CLI] bundle validate
Error: experimental.record_deployment_history is not supported yet
at experimental.record_deployment_history
in databricks.yml:5:30

Name: dms-not-supported
Target: default
Workspace:
User: [USERNAME]
Path: /Workspace/Users/[USERNAME]/.bundle/dms-not-supported/default

Found 1 error

=== The hidden force-allow variable permits it
>>> DATABRICKS_BUNDLE_FORCE_ALLOW_RECORD_DEPLOYMENT_HISTORY=1 [CLI] bundle validate
Name: dms-not-supported
Target: default
Workspace:
User: [USERNAME]
Path: /Workspace/Users/[USERNAME]/.bundle/dms-not-supported/default

Validation OK!
Loading
Loading