Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
bc86051
Support DMS migration during bundle deploy
shreyas-goenka Oct 19, 2026
1604111
Explain remote-state authority during DMS migration
shreyas-goenka Oct 19, 2026
74f87db
Verify DMS migration invalidates newer local state
shreyas-goenka Oct 19, 2026
e9ca163
Assert the exact diff between migration backups
shreyas-goenka Oct 19, 2026
b5a31b8
Use default state selection for DMS migration
shreyas-goenka Oct 19, 2026
3d4929a
Clarify migration and deployment version offsets
shreyas-goenka Oct 19, 2026
4871cbf
Prepare deployment history migration before planning
shreyas-goenka Oct 19, 2026
c345710
Commit DMS migration separately before deployment
shreyas-goenka Oct 19, 2026
6ee4adb
Close migration state explicitly before normal DMS reads
shreyas-goenka Oct 19, 2026
207e2f0
Clarify deployment annotation cases next to mutators
shreyas-goenka Oct 19, 2026
f35c8d9
Reuse loaded state for migration and skip locking recorded state
shreyas-goenka Oct 19, 2026
3ddeba6
Require direct state before enabling deployment history
shreyas-goenka Oct 19, 2026
b540bdf
Clarify skipped deployment ID annotation for new deployments
shreyas-goenka Oct 20, 2026
6c5f9a8
Inline DMS registration in the migration phase
shreyas-goenka Oct 20, 2026
51a97d6
Clarify version annotation runs for new deployments
shreyas-goenka Oct 20, 2026
ee3746f
Rename deployment history marker method
shreyas-goenka Oct 20, 2026
bd53e85
Remove obsolete Terraform migration flag reset from DMS
shreyas-goenka Oct 20, 2026
aebedd5
Remove marker persistence unit test covered by acceptance
shreyas-goenka Oct 20, 2026
f6a63c2
Only refresh migration descriptor fields used downstream
shreyas-goenka Oct 20, 2026
accee18
Explain close-state tests with numbered expectations
shreyas-goenka Oct 20, 2026
e6f058f
Simplify migration unit tests around uncovered cases
shreyas-goenka Oct 20, 2026
f1fa38b
Explain migration state update in plain language
shreyas-goenka Oct 20, 2026
d97a698
Simplify migration acceptance scenarios and visible explanations
shreyas-goenka Oct 20, 2026
3d85450
Separate migration acceptance from existing-state lifecycle checks
shreyas-goenka Oct 21, 2026
836970b
Restore fresh DMS deployment assertion after destroy
shreyas-goenka Oct 21, 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
42 changes: 22 additions & 20 deletions acceptance/bundle/dms/existing-state/output.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

=== Deploy without recording: ordinary direct-engine state tracking one job, unknown to DMS
=== 1. Deploy without history: existing state tracks one job
>>> [CLI] bundle deploy
Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/dms-existing-state-[UNIQUE_NAME]/default/files...
Created jobs.one
Expand All @@ -25,36 +25,38 @@ Plan: 0 to add, 0 to change, 0 to delete, 1 unchanged
"features": null
}

=== Enabling recording is refused because the existing deployment is not recorded
=== 2. Enable history on the existing deployment
Expect: migration succeeds without recreating the job.
>>> DATABRICKS_BUNDLE_DEPLOYMENT_HISTORY=true [CLI] bundle deploy
Error: deployment history setting (true) does not match the existing state (false)

Update experimental.deployment_history to match the existing deployment, or run "databricks bundle destroy" to start over


>>> print_requests.py --dms //api/2.0/bundle --oneline
Enabling deployment history...
Deployment history enabled: [DATABRICKS_URL]/deployments/[DEPLOYMENT_ID]?version=2
Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/dms-existing-state-[UNIQUE_NAME]/default/files...
Updated jobs.one
Files: 0 uploaded, 0 deleted
Resources: 0 created, 1 changed, 0 deleted, 0 unchanged

=== Wiping the local cache still refuses after pulling the non-DMS state from the workspace
=== 3. Remove local state and deploy again
Expect: remote DMS state is loaded; no migration or resource creation.
>>> DATABRICKS_BUNDLE_DEPLOYMENT_HISTORY=true [CLI] bundle deploy
Error: deployment history setting (true) does not match the existing state (false)

Update experimental.deployment_history to match the existing deployment, or run "databricks bundle destroy" to start over

Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/dms-existing-state-[UNIQUE_NAME]/default/files...
Files: 2 uploaded, 0 deleted
Resources: 0 created, 0 changed, 0 deleted, 1 unchanged

=== A leftover local WAL with the wrong lineage is still refused
=== 4. A leftover local WAL is refused: DMS deployments do not use WALs
>>> DATABRICKS_BUNDLE_DEPLOYMENT_HISTORY=true [CLI] bundle deploy
Error: reading state from [TEST_TMP_DIR]/.databricks/bundle/default/resources.json: WAL recovery failed: WAL lineage ("stale") does not match state lineage ("[UUID]")
Error: unexpected WAL file found at [TEST_TMP_DIR]/.databricks/bundle/default/resources.json.wal: this deployment records deployment history, which does not write one


=== Destroy clears the deployment. With nothing recorded remotely the bundle is treated as new, so recording can be enabled once the stale WAL is gone
>>> DATABRICKS_BUNDLE_DEPLOYMENT_HISTORY=true [CLI] bundle destroy --auto-approve
=== 5. Destroy follows recorded state; redeploy starts a new history
>>> DATABRICKS_BUNDLE_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-[UNIQUE_NAME]/default

Destroy: 1 deleted

=== Fresh history: version 1 creates the job without migration
>>> DATABRICKS_BUNDLE_DEPLOYMENT_HISTORY=true [CLI] bundle deploy
Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/dms-existing-state-[UNIQUE_NAME]/default/files...
Created jobs.one
Expand All @@ -63,9 +65,9 @@ Resources: 1 created, 0 changed, 0 deleted, 0 unchanged

>>> print_requests.py --dms //api/2.0/bundle --oneline
{"method": "POST", "path": "/api/2.0/bundle/deployments", "body": {"display_name": "dms-existing-state-[UNIQUE_NAME]", "initial_parent_path": "/Workspace/Users/[USERNAME]/.bundle/dms-existing-state-[UNIQUE_NAME]/default/state", "target_name": "default", "workspace_info": {"file_path": "/Workspace/Users/[USERNAME]/.bundle/dms-existing-state-[UNIQUE_NAME]/default/files", "root_path": "/Workspace/Users/[USERNAME]/.bundle/dms-existing-state-[UNIQUE_NAME]/default"}}}
{"method": "POST", "path": "/api/2.0/bundle/deployments/[DEPLOYMENT_ID]/versions", "q": {"version_id": "1"}, "body": {"cli_version": "[CLI_VERSION]", "operations": [{"action_type": "OPERATION_ACTION_TYPE_CREATE", "resource_key": "jobs.one"}], "version_type": "VERSION_TYPE_DEPLOY"}}
{"method": "PATCH", "path": "/api/2.0/bundle/deployments/[DEPLOYMENT_ID]/versions/1/operations/jobs.one", "q": {"update_mask": "state,error_message,resource_id,status"}, "body": {"error_message": "", "resource_id": "[ONE_ID]", "sequence_id": 0, "state": "{\"state\":{\"deployment\":{\"deployment_id\":\"[DEPLOYMENT_ID]\",\"kind\":\"BUNDLE\",\"metadata_file_path\":\"/Workspace/Users/[USERNAME]/.bundle/dms-existing-state-[UNIQUE_NAME]/default/state/metadata.json\",\"version_id\":\"1\"},\"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/[DEPLOYMENT_ID]/versions/1/complete", "body": {"completion_reason": "VERSION_COMPLETE_SUCCESS"}}
{"method": "POST", "path": "/api/2.0/bundle/deployments/[DEPLOYMENT_ID_2]/versions", "q": {"version_id": "1"}, "body": {"cli_version": "[CLI_VERSION]", "operations": [{"action_type": "OPERATION_ACTION_TYPE_CREATE", "resource_key": "jobs.one"}], "version_type": "VERSION_TYPE_DEPLOY"}}
{"method": "PATCH", "path": "/api/2.0/bundle/deployments/[DEPLOYMENT_ID_2]/versions/1/operations/jobs.one", "q": {"update_mask": "state,error_message,resource_id,status"}, "body": {"error_message": "", "resource_id": "[ONE_ID]", "sequence_id": 0, "state": "{\"state\":{\"deployment\":{\"deployment_id\":\"[DEPLOYMENT_ID_2]\",\"kind\":\"BUNDLE\",\"metadata_file_path\":\"/Workspace/Users/[USERNAME]/.bundle/dms-existing-state-[UNIQUE_NAME]/default/state/metadata.json\",\"version_id\":\"1\"},\"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/[DEPLOYMENT_ID_2]/versions/1/complete", "body": {"completion_reason": "VERSION_COMPLETE_SUCCESS"}}

>>> find.py resources[.]json[.]wal --expect 0

Expand Down
31 changes: 16 additions & 15 deletions acceptance/bundle/dms/existing-state/script
Original file line number Diff line number Diff line change
@@ -1,38 +1,39 @@
envsubst < databricks.yml.tmpl > databricks.yml

title "Deploy without recording: ordinary direct-engine state tracking one job, unknown to DMS"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

general observation, this test is rewritten so much it is practically a different test. Maybe worth adding this new test separately and record output changes for the original test (with minimal script changes).

title "1. Deploy without history: existing state tracks one job"
trace $CLI bundle deploy
dms_plan
trace print_requests.py --dms //api/2.0/bundle --oneline
trace jq '{state_version, features}' .databricks/bundle/default/resources.json

title "Enabling recording is refused because the existing deployment is not recorded"
musterr trace DATABRICKS_BUNDLE_DEPLOYMENT_HISTORY=true $CLI bundle deploy
trace print_requests.py --dms //api/2.0/bundle --oneline
title "2. Enable history on the existing deployment\nExpect: migration succeeds without recreating the job."
trace DATABRICKS_BUNDLE_DEPLOYMENT_HISTORY=true $CLI bundle deploy
deployment_id=$(MSYS_NO_PATHCONV=1 $CLI workspace get-status "/Workspace/Users/${CURRENT_USER_NAME}/.bundle/dms-existing-state-${UNIQUE_NAME}/default/state/resources.deployment.json" -o json | python3 -c 'import sys, json; print(json.load(sys.stdin)["object_id"])')
add_repl "$deployment_id" DEPLOYMENT_ID

title "Wiping the local cache still refuses after pulling the non-DMS state from the workspace"
title "3. Remove local state and deploy again\nExpect: remote DMS state is loaded; no migration or resource creation."
rm -rf .databricks
musterr trace DATABRICKS_BUNDLE_DEPLOYMENT_HISTORY=true $CLI bundle deploy
trace DATABRICKS_BUNDLE_DEPLOYMENT_HISTORY=true $CLI bundle deploy

title "A leftover local WAL with the wrong lineage is still refused"
title "4. A leftover local WAL is refused: DMS deployments do not use WALs"
mkdir -p .databricks/bundle/default
printf '{"lineage":"stale","serial":99,"state_version":2,"features":{"deployment_history":{}}}\n' > .databricks/bundle/default/resources.json.wal
musterr trace DATABRICKS_BUNDLE_DEPLOYMENT_HISTORY=true $CLI bundle deploy

title "Destroy clears the deployment. With nothing recorded remotely the bundle is treated as new, so recording can be enabled once the stale WAL is gone"
# Clear the stale WAL first: it was refused, not deleted, and destroy runs without recording, so it
# would otherwise try to replay it and fail on the lineage mismatch.
title "5. Destroy follows recorded state; redeploy starts a new history"
# The rejected WAL remains on disk. Remove it before destroying the recorded deployment.
rm -f .databricks/bundle/default/resources.json.wal
# Keep the mismatched setting here to verify that destroy ignores configuration and follows state.
trace DATABRICKS_BUNDLE_DEPLOYMENT_HISTORY=true $CLI bundle destroy --auto-approve
# Turn history off to check that destroy still follows the recorded backend.
trace DATABRICKS_BUNDLE_DEPLOYMENT_HISTORY=false $CLI bundle destroy --auto-approve
title "Fresh history: version 1 creates the job without migration"
rm -f "$OUT_REQUESTS"
trace DATABRICKS_BUNDLE_DEPLOYMENT_HISTORY=true $CLI bundle deploy
trace print_requests.py --dms //api/2.0/bundle --oneline
trace find.py 'resources[.]json[.]wal' --expect 0
trace jq '{state_version, features}' .databricks/bundle/default/resources.json
DATABRICKS_BUNDLE_DEPLOYMENT_HISTORY=true replace_ids.py
deployment_id=$(MSYS_NO_PATHCONV=1 $CLI workspace get-status "/Workspace/Users/${CURRENT_USER_NAME}/.bundle/dms-existing-state-${UNIQUE_NAME}/default/state/resources.deployment.json" | python3 -c 'import sys, json; print(json.load(sys.stdin)["object_id"])')
deployment_id=$(MSYS_NO_PATHCONV=1 $CLI workspace get-status "/Workspace/Users/${CURRENT_USER_NAME}/.bundle/dms-existing-state-${UNIQUE_NAME}/default/state/resources.deployment.json" -o json | python3 -c 'import sys, json; print(json.load(sys.stdin)["object_id"])')
add_repl "$deployment_id" DEPLOYMENT_ID

# The recorded requests are asserted above via print_requests.py; drop whatever the run added after
# that (telemetry, and the state probes of the non-recording variant) so nothing is left to compare.
# Drop telemetry and state probes recorded after the fresh-deployment assertion above.
rm -f "$OUT_REQUESTS"
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
bundle:
name: dms-migration-before-deploy-$UNIQUE_NAME

experimental:
deployment_history: false

sync:
exclude:
- LOG.*

resources:
jobs:
job:
name: migration-before-deploy
schemas:
schema:
name: dms_migration_before_deploy_$UNIQUE_NAME
catalog_name: main
2 changes: 2 additions & 0 deletions acceptance/bundle/dms/migration-before-deploy/out.test.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Cloud = false
EnvMatrix.DMS = ["true"]
80 changes: 80 additions & 0 deletions acceptance/bundle/dms/migration-before-deploy/output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@

=== Setup (LOG.setup): create a job and schema without history
Next deploy enables history and recreates the schema in another catalog, requiring approval.
=== 1. Fail deployment planning
Expect: migration version 2 stays complete; no deployment version is created.
>>> fault.py GET /api/2.2/jobs/get* 403 0 1

>>> musterr [CLI] bundle deploy -qq
Enabling deployment history...
Deployment history enabled: [DATABRICKS_URL]/deployments/[DEPLOYMENT_ID]?version=2
Error: cannot plan resources.jobs.job: reading id="[JOB_ID]": Fault injected by test. (403 INJECTED)

Endpoint: GET [DATABRICKS_URL]/api/2.2/jobs/get?job_id=[JOB_ID]
HTTP Status: 403 Forbidden
API error_code: INJECTED
API message: Fault injected by test.

Error: planning failed


=== Request order: complete migration -> upload marker -> read DMS -> plan jobs
>>> print_requests.py --dms --get //api/2.0/bundle //jobs/get //workspace/import //workspace-files/import-file --oneline
{"method":"POST","path":"/api/2.0/bundle/deployments/[DEPLOYMENT_ID]/versions/2/complete"}
{"method":"POST","path":"/Workspace/Users/[USERNAME]/.bundle/dms-migration-before-deploy-[UNIQUE_NAME]/default/state/resources.json"}
{"method":"GET","path":"/api/2.0/bundle/deployments/[DEPLOYMENT_ID]/resources"}
{"method":"GET","path":"/api/2.2/jobs/get"}

=== Remote state: version 2 marker; original resources preserved in the backup
>>> MSYS_NO_PATHCONV=1 [CLI] workspace export /Workspace/Users/[USERNAME]/.bundle/dms-migration-before-deploy-[UNIQUE_NAME]/default/state/resources.json --format AUTO --file .databricks/resources.marker.json

>>> jq -c {serial, features, state} .databricks/resources.marker.json
{"serial":2,"features":{"deployment_history":{}},"state":{}}

>>> MSYS_NO_PATHCONV=1 [CLI] workspace export /Workspace/Users/[USERNAME]/.bundle/dms-migration-before-deploy-[UNIQUE_NAME]/default/state/resources.json.backup --format AUTO --file .databricks/resources.backup.json

>>> cmp .databricks/resources.before-migration.json .databricks/resources.backup.json

=== Migration result: only completed version 2, with INITIAL_REGISTER operations
>>> MSYS_NO_PATHCONV=1 [CLI] bundle-deployments list-versions deployments/[DEPLOYMENT_ID] -o json
[{"version_id":"2","status":"VERSION_STATUS_COMPLETED","completion_reason":"VERSION_COMPLETE_SUCCESS"}]

>>> MSYS_NO_PATHCONV=1 [CLI] bundle-deployments list-operations deployments/[DEPLOYMENT_ID]/versions/2 -o json
[{"resource_key":"jobs.job","action_type":"OPERATION_ACTION_TYPE_INITIAL_REGISTER","status":"OPERATION_STATUS_SUCCEEDED"},{"resource_key":"schemas.schema","action_type":"OPERATION_ACTION_TYPE_INITIAL_REGISTER","status":"OPERATION_STATUS_SUCCEEDED"}]

=== 2. Retry without approval
Expect: deployment declined; migration stays at version 2 and is not repeated.
>>> musterr [CLI] bundle deploy -qq

This action will result in the deletion or recreation of the following UC schemas. Any underlying data may be lost:
recreate resources.schemas.schema
Error: the deployment requires destructive actions, but the current console does not support prompting.
Deleting data assets such as schemas, pipelines, or volumes may cause permanent data loss and should be carefully reviewed.
To proceed, use --auto-approve after reviewing the plan above.


=== Local and remote markers must stay byte-for-byte unchanged
>>> cmp .databricks/resources.marker.json .databricks/bundle/default/resources.json

>>> MSYS_NO_PATHCONV=1 [CLI] workspace export /Workspace/Users/[USERNAME]/.bundle/dms-migration-before-deploy-[UNIQUE_NAME]/default/state/resources.json --format AUTO --file .databricks/resources.after-decline.json

>>> cmp .databricks/resources.marker.json .databricks/resources.after-decline.json

=== No DMS writes and no extra version on the declined retry
>>> print_requests.py --dms //api/2.0/bundle

>>> MSYS_NO_PATHCONV=1 [CLI] bundle-deployments list-versions deployments/[DEPLOYMENT_ID] -o json
[{"version_id":"2","status":"VERSION_STATUS_COMPLETED","completion_reason":"VERSION_COMPLETE_SUCCESS"}]

=== 3. Approve deployment
Expect: ordinary deployment version 3; version 2 remains the only migration.
>>> [CLI] bundle deploy --auto-approve -qq

This action will result in the deletion or recreation of the following UC schemas. Any underlying data may be lost:
recreate resources.schemas.schema

>>> [CLI] bundle summary -o json
{"latest_version_id":3}

>>> MSYS_NO_PATHCONV=1 [CLI] bundle-deployments list-versions deployments/[DEPLOYMENT_ID] -o json
[{"version_id":"2","status":"VERSION_STATUS_COMPLETED","completion_reason":"VERSION_COMPLETE_SUCCESS"},{"version_id":"3","status":"VERSION_STATUS_COMPLETED","completion_reason":"VERSION_COMPLETE_SUCCESS"}]
50 changes: 50 additions & 0 deletions acceptance/bundle/dms/migration-before-deploy/script
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
envsubst < databricks.yml.tmpl > databricks.yml
state_path="/Workspace/Users/${CURRENT_USER_NAME}/.bundle/dms-migration-before-deploy-${UNIQUE_NAME}/default/state"
other_catalog="dms_other_${UNIQUE_NAME}"

title "Setup (LOG.setup): create a job and schema without history\nNext deploy enables history and recreates the schema in another catalog, requiring approval."
{

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why do we need to group it? cannot we record the command + output with trace? This makes output easier to read. As far as I can see the commands below have no or very little output.

$CLI bundle deploy -qq
DATABRICKS_BUNDLE_DEPLOYMENT_HISTORY=false replace_ids.py

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is it significant to have env var here that matches config?

cp .databricks/bundle/default/resources.json .databricks/resources.before-migration.json
$CLI catalogs create "$other_catalog"
update_file.py databricks.yml 'deployment_history: false' 'deployment_history: true'
update_file.py databricks.yml 'catalog_name: main' "catalog_name: ${other_catalog}"
} &> LOG.setup
trap '$CLI bundle destroy --auto-approve >> LOG.cleanup 2>&1; $CLI catalogs delete "$other_catalog" --force >> LOG.cleanup 2>&1; rm -f "$OUT_REQUESTS"' EXIT
rm -f "$OUT_REQUESTS"

title "1. Fail deployment planning\nExpect: migration version 2 stays complete; no deployment version is created."
trace fault.py 'GET /api/2.2/jobs/get*' 403 0 1
trace musterr $CLI bundle deploy -qq
deployment_id=$(MSYS_NO_PATHCONV=1 $CLI workspace get-status "$state_path/resources.deployment.json" -o json | jq -r '.object_id')
add_repl "$deployment_id" DEPLOYMENT_ID
title "Request order: complete migration -> upload marker -> read DMS -> plan jobs"
trace print_requests.py --dms --get //api/2.0/bundle //jobs/get //workspace/import //workspace-files/import-file --oneline |
MSYS_NO_PATHCONV=1 jq -c --arg marker "$state_path/resources.json" '
(.body.multipart_form.path // .body.path // (.path | ltrimstr("/api/2.0/workspace-files/import-file"))) as $destination |
select((.path | endswith("/complete")) or (.path | endswith("/resources")) or .path == "/api/2.2/jobs/get" or $destination == $marker) |
{method, path: (if $destination == $marker then $destination else .path end)}'
title "Remote state: version 2 marker; original resources preserved in the backup"
trace MSYS_NO_PATHCONV=1 $CLI workspace export "$state_path/resources.json" --format AUTO --file .databricks/resources.marker.json
trace jq -c '{serial, features, state}' .databricks/resources.marker.json
trace MSYS_NO_PATHCONV=1 $CLI workspace export "$state_path/resources.json.backup" --format AUTO --file .databricks/resources.backup.json
trace cmp .databricks/resources.before-migration.json .databricks/resources.backup.json
title "Migration result: only completed version 2, with INITIAL_REGISTER operations"
trace MSYS_NO_PATHCONV=1 $CLI bundle-deployments list-versions "deployments/${deployment_id}" -o json | jq -c 'map({version_id, status, completion_reason})'
trace MSYS_NO_PATHCONV=1 $CLI bundle-deployments list-operations "deployments/${deployment_id}/versions/2" -o json | jq -c 'sort_by(.resource_key) | map({resource_key, action_type, status})'

title "2. Retry without approval\nExpect: deployment declined; migration stays at version 2 and is not repeated."
trace musterr $CLI bundle deploy -qq
title "Local and remote markers must stay byte-for-byte unchanged"
trace cmp .databricks/resources.marker.json .databricks/bundle/default/resources.json
trace MSYS_NO_PATHCONV=1 $CLI workspace export "$state_path/resources.json" --format AUTO --file .databricks/resources.after-decline.json
trace cmp .databricks/resources.marker.json .databricks/resources.after-decline.json
title "No DMS writes and no extra version on the declined retry"
trace print_requests.py --dms //api/2.0/bundle
trace MSYS_NO_PATHCONV=1 $CLI bundle-deployments list-versions "deployments/${deployment_id}" -o json | jq -c 'map({version_id, status, completion_reason})'

title "3. Approve deployment\nExpect: ordinary deployment version 3; version 2 remains the only migration."
trace $CLI bundle deploy --auto-approve -qq
trace $CLI bundle summary -o json | jq -c '.bundle.deployment | {latest_version_id}'
trace MSYS_NO_PATHCONV=1 $CLI bundle-deployments list-versions "deployments/${deployment_id}" -o json | jq -c 'sort_by(.version_id | tonumber) | map({version_id, status, completion_reason})'
2 changes: 2 additions & 0 deletions acceptance/bundle/dms/migration-before-deploy/test.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Fault injection exercises a real planner failure against the local testserver.
Cloud = false
16 changes: 16 additions & 0 deletions acceptance/bundle/dms/migration/databricks.yml.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
bundle:
name: dms-migration-$UNIQUE_NAME

experimental:
deployment_history: false

resources:
jobs:
one:
name: one
two:
name: two
tasks:
- task_key: run_one
run_job_task:
job_id: ${resources.jobs.one.id}
2 changes: 2 additions & 0 deletions acceptance/bundle/dms/migration/out.test.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Cloud = true
EnvMatrix.DMS = [""]
Loading