From 384e2d1401ed1df7fa7b8b036ef410667e59d4c4 Mon Sep 17 00:00:00 2001 From: Sankalp-Mittal Date: Tue, 1 Sep 2026 14:01:14 +0000 Subject: [PATCH 01/15] Add acceptance test for inline serialized_dashboard Prove that a dashboard whose serialized_dashboard is an inline YAML map (not a string) plans and deploys correctly, and record that the map is sent to the API as a JSON string. Both engines produce identical output. Co-authored-by: Isaac --- .../serialized-inline/databricks.yml.tmpl | 12 ++++++ .../serialized-inline/out.test.toml | 3 ++ .../dashboards/serialized-inline/output.txt | 39 +++++++++++++++++++ .../dashboards/serialized-inline/script | 19 +++++++++ .../dashboards/serialized-inline/test.toml | 8 ++++ 5 files changed, 81 insertions(+) create mode 100644 acceptance/bundle/resources/dashboards/serialized-inline/databricks.yml.tmpl create mode 100644 acceptance/bundle/resources/dashboards/serialized-inline/out.test.toml create mode 100644 acceptance/bundle/resources/dashboards/serialized-inline/output.txt create mode 100644 acceptance/bundle/resources/dashboards/serialized-inline/script create mode 100644 acceptance/bundle/resources/dashboards/serialized-inline/test.toml diff --git a/acceptance/bundle/resources/dashboards/serialized-inline/databricks.yml.tmpl b/acceptance/bundle/resources/dashboards/serialized-inline/databricks.yml.tmpl new file mode 100644 index 00000000000..ca96f9fcf14 --- /dev/null +++ b/acceptance/bundle/resources/dashboards/serialized-inline/databricks.yml.tmpl @@ -0,0 +1,12 @@ +bundle: + name: dashboard-serialized-inline-$UNIQUE_NAME + +resources: + dashboards: + inline_dash: + display_name: Inline Dash + warehouse_id: $TEST_DEFAULT_WAREHOUSE_ID + serialized_dashboard: # inline YAML MAP = the non-string case + pages: + - name: page1 + displayName: Page 1 diff --git a/acceptance/bundle/resources/dashboards/serialized-inline/out.test.toml b/acceptance/bundle/resources/dashboards/serialized-inline/out.test.toml new file mode 100644 index 00000000000..cef45fe553a --- /dev/null +++ b/acceptance/bundle/resources/dashboards/serialized-inline/out.test.toml @@ -0,0 +1,3 @@ +Cloud = true +EnvMatrix.DATABRICKS_BUNDLE_ENGINE = ["terraform", "direct"] +EnvMatrix.DMS = ["", "true"] diff --git a/acceptance/bundle/resources/dashboards/serialized-inline/output.txt b/acceptance/bundle/resources/dashboards/serialized-inline/output.txt new file mode 100644 index 00000000000..389e62fcdeb --- /dev/null +++ b/acceptance/bundle/resources/dashboards/serialized-inline/output.txt @@ -0,0 +1,39 @@ + +>>> [CLI] bundle plan +create dashboards.inline_dash + +Plan: 1 to add, 0 to change, 0 to delete, 0 unchanged + +>>> [CLI] bundle deploy +Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/dashboard-serialized-inline-[UNIQUE_NAME]/default/files... +Created dashboards.inline_dash +Files: 6 uploaded, 0 deleted +Resources: 1 created, 0 changed, 0 deleted, 0 unchanged + +>>> print_requests.py //api/2.0/lakeview/dashboards +{ + "method": "POST", + "path": "/api/2.0/lakeview/dashboards", + "body": { + "display_name": "Inline Dash", + "parent_path": "/Workspace/Users/[USERNAME]/.bundle/dashboard-serialized-inline-[UNIQUE_NAME]/default/resources", + "serialized_dashboard": "{\"pages\":[{\"displayName\":\"Page 1\",\"name\":\"page1\"}]}", + "warehouse_id": "[TEST_DEFAULT_WAREHOUSE_ID]" + } +} +{ + "method": "POST", + "path": "/api/2.0/lakeview/dashboards/[DASHBOARD_ID]/published", + "body": { + "embed_credentials": false, + "warehouse_id": "[TEST_DEFAULT_WAREHOUSE_ID]" + } +} + +>>> [CLI] bundle destroy --auto-approve +The following resources will be deleted: + delete resources.dashboards.inline_dash + +All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/dashboard-serialized-inline-[UNIQUE_NAME]/default + +Destroy: 1 deleted diff --git a/acceptance/bundle/resources/dashboards/serialized-inline/script b/acceptance/bundle/resources/dashboards/serialized-inline/script new file mode 100644 index 00000000000..04ca23512e0 --- /dev/null +++ b/acceptance/bundle/resources/dashboards/serialized-inline/script @@ -0,0 +1,19 @@ +envsubst < databricks.yml.tmpl > databricks.yml + +cleanup() { + trace $CLI bundle destroy --auto-approve + rm out.requests.txt +} +trap cleanup EXIT + +trace $CLI bundle plan +trace $CLI bundle deploy + +# Normalize the non-deterministic dashboard ID so the published-dashboard request +# path is stable across engines and runs. +dashboard_id=$($CLI bundle summary --output json | jq -r '.resources.dashboards.inline_dash.id') +add_repl "$dashboard_id" DASHBOARD_ID + +# serialized_dashboard is authored as an inline YAML map but must reach the API as a +# JSON *string*, not a nested object. Record the create request to prove that. +trace print_requests.py //api/2.0/lakeview/dashboards diff --git a/acceptance/bundle/resources/dashboards/serialized-inline/test.toml b/acceptance/bundle/resources/dashboards/serialized-inline/test.toml new file mode 100644 index 00000000000..a5edf8715ad --- /dev/null +++ b/acceptance/bundle/resources/dashboards/serialized-inline/test.toml @@ -0,0 +1,8 @@ +Ignore = [ + "databricks.yml", +] + +# This test does no read-after-deploy, so the inherited eventual-consistency stale GET +# is unnecessary. With it enabled, the direct-engine destroy's first GET 404s and reports +# "0 deleted", diverging from terraform. Disable it so both engines destroy identically. +Env.INJECT_STALE_ON_DIRECT = "0" From b806ba114728daf8454c296c31e6ee3ddbe14639 Mon Sep 17 00:00:00 2001 From: Sankalp-Mittal Date: Tue, 1 Sep 2026 14:10:42 +0000 Subject: [PATCH 02/15] Add acceptance test for changing an inline serialized_dashboard Deploy a dashboard whose serialized_dashboard is an inline YAML map, then change a value inside the map and show the plan: the change is detected as an update (not a recreate). Capture the update request the direct engine sends, which serializes the inline map to a JSON string. Co-authored-by: Isaac --- .../databricks.yml.tmpl | 12 ++++++ .../out.requests.direct.txt | 18 +++++++++ .../change-serialized-inline/out.test.toml | 3 ++ .../change-serialized-inline/output.txt | 25 ++++++++++++ .../change-serialized-inline/script | 38 +++++++++++++++++++ .../change-serialized-inline/test.toml | 3 ++ 6 files changed, 99 insertions(+) create mode 100644 acceptance/bundle/resources/dashboards/change-serialized-inline/databricks.yml.tmpl create mode 100644 acceptance/bundle/resources/dashboards/change-serialized-inline/out.requests.direct.txt create mode 100644 acceptance/bundle/resources/dashboards/change-serialized-inline/out.test.toml create mode 100644 acceptance/bundle/resources/dashboards/change-serialized-inline/output.txt create mode 100644 acceptance/bundle/resources/dashboards/change-serialized-inline/script create mode 100644 acceptance/bundle/resources/dashboards/change-serialized-inline/test.toml diff --git a/acceptance/bundle/resources/dashboards/change-serialized-inline/databricks.yml.tmpl b/acceptance/bundle/resources/dashboards/change-serialized-inline/databricks.yml.tmpl new file mode 100644 index 00000000000..c5f5494f367 --- /dev/null +++ b/acceptance/bundle/resources/dashboards/change-serialized-inline/databricks.yml.tmpl @@ -0,0 +1,12 @@ +bundle: + name: change-serialized-inline-$UNIQUE_NAME + +resources: + dashboards: + inline_dash: + display_name: Inline Dash + warehouse_id: $TEST_DEFAULT_WAREHOUSE_ID + serialized_dashboard: # inline YAML MAP = the non-string case + pages: + - name: page1 + displayName: $PAGE_DISPLAY_NAME diff --git a/acceptance/bundle/resources/dashboards/change-serialized-inline/out.requests.direct.txt b/acceptance/bundle/resources/dashboards/change-serialized-inline/out.requests.direct.txt new file mode 100644 index 00000000000..763f6fc22c7 --- /dev/null +++ b/acceptance/bundle/resources/dashboards/change-serialized-inline/out.requests.direct.txt @@ -0,0 +1,18 @@ +{ + "method": "PATCH", + "path": "/api/2.0/lakeview/dashboards/[DASHBOARD_ID]", + "body": { + "display_name": "Inline Dash", + "parent_path": "/Workspace/Users/[USERNAME]/.bundle/change-serialized-inline-[UNIQUE_NAME]/default/resources", + "serialized_dashboard": "{\"pages\":[{\"displayName\":\"Page One\",\"name\":\"page1\"}]}", + "warehouse_id": "[TEST_DEFAULT_WAREHOUSE_ID]" + } +} +{ + "method": "POST", + "path": "/api/2.0/lakeview/dashboards/[DASHBOARD_ID]/published", + "body": { + "embed_credentials": false, + "warehouse_id": "[TEST_DEFAULT_WAREHOUSE_ID]" + } +} diff --git a/acceptance/bundle/resources/dashboards/change-serialized-inline/out.test.toml b/acceptance/bundle/resources/dashboards/change-serialized-inline/out.test.toml new file mode 100644 index 00000000000..cef45fe553a --- /dev/null +++ b/acceptance/bundle/resources/dashboards/change-serialized-inline/out.test.toml @@ -0,0 +1,3 @@ +Cloud = true +EnvMatrix.DATABRICKS_BUNDLE_ENGINE = ["terraform", "direct"] +EnvMatrix.DMS = ["", "true"] diff --git a/acceptance/bundle/resources/dashboards/change-serialized-inline/output.txt b/acceptance/bundle/resources/dashboards/change-serialized-inline/output.txt new file mode 100644 index 00000000000..e41d7092757 --- /dev/null +++ b/acceptance/bundle/resources/dashboards/change-serialized-inline/output.txt @@ -0,0 +1,25 @@ + +>>> [CLI] bundle deploy +Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/change-serialized-inline-[UNIQUE_NAME]/default/files... +Created dashboards.inline_dash +Files: 6 uploaded, 0 deleted +Resources: 1 created, 0 changed, 0 deleted, 0 unchanged + +>>> [CLI] bundle plan +update dashboards.inline_dash + +Plan: 0 to add, 1 to change, 0 to delete, 0 unchanged + +>>> [CLI] bundle deploy +Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/change-serialized-inline-[UNIQUE_NAME]/default/files... +Updated dashboards.inline_dash +Files: 3 uploaded, 0 deleted +Resources: 0 created, 1 changed, 0 deleted, 0 unchanged + +>>> [CLI] bundle destroy --auto-approve +The following resources will be deleted: + delete resources.dashboards.inline_dash + +All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/change-serialized-inline-[UNIQUE_NAME]/default + +Destroy: 1 deleted diff --git a/acceptance/bundle/resources/dashboards/change-serialized-inline/script b/acceptance/bundle/resources/dashboards/change-serialized-inline/script new file mode 100644 index 00000000000..8f10ff62903 --- /dev/null +++ b/acceptance/bundle/resources/dashboards/change-serialized-inline/script @@ -0,0 +1,38 @@ +cleanup() { + trace $CLI bundle destroy --auto-approve + rm -f out.requests.txt +} +trap cleanup EXIT + +# Deploy a dashboard whose serialized_dashboard is an inline YAML map. +export PAGE_DISPLAY_NAME="Page 1" +envsubst < databricks.yml.tmpl > databricks.yml +trace $CLI bundle deploy + +dashboard_id=$($CLI bundle summary --output json | jq -r '.resources.dashboards.inline_dash.id') +add_repl "$dashboard_id" DASHBOARD_ID + +# Wait out eventual consistency so the change below is planned against the deployed +# state (the first read of a freshly created dashboard 404s on the direct engine). +retry --until "Page 1" $CLI lakeview get "$dashboard_id" > /dev/null + +# Change a value *inside* the inline serialized_dashboard, then show the plan. The +# change must be detected as an update to the existing dashboard, not a recreate. +export PAGE_DISPLAY_NAME="Page One" +envsubst < databricks.yml.tmpl > databricks.yml +trace $CLI bundle plan + +# Discard the requests from the initial deploy so the recording below shows only what +# deploying the change sends. Direct only: terraform echoes OUTPUT_ONLY fields in the +# request body, and the direct engine is the default we care about here. +if [ "$DATABRICKS_BUNDLE_ENGINE" = "direct" ]; then + print_requests.py //api/2.0/lakeview/dashboards > /dev/null +fi + +# Deploy the change. The update serializes the inline YAML map to a JSON string, same +# as create. +trace $CLI bundle deploy + +if [ "$DATABRICKS_BUNDLE_ENGINE" = "direct" ]; then + print_requests.py //api/2.0/lakeview/dashboards > out.requests.direct.txt +fi diff --git a/acceptance/bundle/resources/dashboards/change-serialized-inline/test.toml b/acceptance/bundle/resources/dashboards/change-serialized-inline/test.toml new file mode 100644 index 00000000000..17383eac468 --- /dev/null +++ b/acceptance/bundle/resources/dashboards/change-serialized-inline/test.toml @@ -0,0 +1,3 @@ +Ignore = [ + "databricks.yml", +] From aba995ffcadf41ffd559fff2814ab144263965b4 Mon Sep 17 00:00:00 2001 From: Sankalp-Mittal Date: Tue, 1 Sep 2026 14:17:11 +0000 Subject: [PATCH 03/15] Output the JSON plan and drop request capture in change test Show the machine-readable plan (per engine) for the serialized_dashboard change instead of recording the update request. Co-authored-by: Isaac --- .../out.plan.direct.json | 95 +++++++++++++++++++ .../out.plan.terraform.json | 8 ++ .../out.requests.direct.txt | 18 ---- .../change-serialized-inline/output.txt | 8 +- .../change-serialized-inline/script | 18 +--- .../change-serialized-inline/test.toml | 1 + 6 files changed, 109 insertions(+), 39 deletions(-) create mode 100644 acceptance/bundle/resources/dashboards/change-serialized-inline/out.plan.direct.json create mode 100644 acceptance/bundle/resources/dashboards/change-serialized-inline/out.plan.terraform.json delete mode 100644 acceptance/bundle/resources/dashboards/change-serialized-inline/out.requests.direct.txt diff --git a/acceptance/bundle/resources/dashboards/change-serialized-inline/out.plan.direct.json b/acceptance/bundle/resources/dashboards/change-serialized-inline/out.plan.direct.json new file mode 100644 index 00000000000..b9244b3ab9d --- /dev/null +++ b/acceptance/bundle/resources/dashboards/change-serialized-inline/out.plan.direct.json @@ -0,0 +1,95 @@ +{ + "plan_version": 2, + "cli_version": "[CLI_VERSION]", + "lineage": "[UUID]", + "serial": 1, + "plan": { + "resources.dashboards.inline_dash": { + "action": "update", + "new_state": { + "value": { + "display_name": "Inline Dash", + "embed_credentials": false, + "parent_path": "/Workspace/Users/[USERNAME]/.bundle/change-serialized-inline-[UNIQUE_NAME]/default/resources", + "published": true, + "serialized_dashboard": { + "pages": [ + { + "displayName": "Page One", + "name": "page1" + } + ] + }, + "warehouse_id": "[TEST_DEFAULT_WAREHOUSE_ID]" + } + }, + "remote_state": { + "create_time": "[TIMESTAMP]", + "dashboard_id": "[DASHBOARD_ID]", + "display_name": "Inline Dash", + "embed_credentials": false, + "etag": "[NUMID]", + "lifecycle_state": "ACTIVE", + "parent_path": "/Workspace/Users/[USERNAME]/.bundle/change-serialized-inline-[UNIQUE_NAME]/default/resources", + "path": "/Users/[USERNAME]/.bundle/change-serialized-inline-[UNIQUE_NAME]/default/resources/Inline Dash.lvdash.json", + "published": true, + "serialized_dashboard": "{\"pages\":[{\"displayName\":\"Page 1\",\"name\":\"page1\",\"pageType\":\"PAGE_TYPE_CANVAS\"}]}\n", + "update_time": "[TIMESTAMP]", + "warehouse_id": "[TEST_DEFAULT_WAREHOUSE_ID]" + }, + "changes": { + "create_time": { + "action": "skip", + "reason": "spec:output_only", + "remote": "[TIMESTAMP]" + }, + "dashboard_id": { + "action": "skip", + "reason": "spec:output_only", + "remote": "[DASHBOARD_ID]" + }, + "etag": { + "action": "skip", + "reason": "custom", + "old": "[NUMID]", + "remote": "[NUMID]" + }, + "lifecycle_state": { + "action": "skip", + "reason": "spec:output_only", + "remote": "ACTIVE" + }, + "path": { + "action": "skip", + "reason": "spec:output_only", + "remote": "/Users/[USERNAME]/.bundle/change-serialized-inline-[UNIQUE_NAME]/default/resources/Inline Dash.lvdash.json" + }, + "serialized_dashboard": { + "action": "update", + "old": { + "pages": [ + { + "displayName": "Page 1", + "name": "page1" + } + ] + }, + "new": { + "pages": [ + { + "displayName": "Page One", + "name": "page1" + } + ] + }, + "remote": "{\"pages\":[{\"displayName\":\"Page 1\",\"name\":\"page1\",\"pageType\":\"PAGE_TYPE_CANVAS\"}]}\n" + }, + "update_time": { + "action": "skip", + "reason": "spec:output_only", + "remote": "[TIMESTAMP]" + } + } + } + } +} diff --git a/acceptance/bundle/resources/dashboards/change-serialized-inline/out.plan.terraform.json b/acceptance/bundle/resources/dashboards/change-serialized-inline/out.plan.terraform.json new file mode 100644 index 00000000000..7795272689a --- /dev/null +++ b/acceptance/bundle/resources/dashboards/change-serialized-inline/out.plan.terraform.json @@ -0,0 +1,8 @@ +{ + "cli_version": "[CLI_VERSION]", + "plan": { + "resources.dashboards.inline_dash": { + "action": "update" + } + } +} diff --git a/acceptance/bundle/resources/dashboards/change-serialized-inline/out.requests.direct.txt b/acceptance/bundle/resources/dashboards/change-serialized-inline/out.requests.direct.txt deleted file mode 100644 index 763f6fc22c7..00000000000 --- a/acceptance/bundle/resources/dashboards/change-serialized-inline/out.requests.direct.txt +++ /dev/null @@ -1,18 +0,0 @@ -{ - "method": "PATCH", - "path": "/api/2.0/lakeview/dashboards/[DASHBOARD_ID]", - "body": { - "display_name": "Inline Dash", - "parent_path": "/Workspace/Users/[USERNAME]/.bundle/change-serialized-inline-[UNIQUE_NAME]/default/resources", - "serialized_dashboard": "{\"pages\":[{\"displayName\":\"Page One\",\"name\":\"page1\"}]}", - "warehouse_id": "[TEST_DEFAULT_WAREHOUSE_ID]" - } -} -{ - "method": "POST", - "path": "/api/2.0/lakeview/dashboards/[DASHBOARD_ID]/published", - "body": { - "embed_credentials": false, - "warehouse_id": "[TEST_DEFAULT_WAREHOUSE_ID]" - } -} diff --git a/acceptance/bundle/resources/dashboards/change-serialized-inline/output.txt b/acceptance/bundle/resources/dashboards/change-serialized-inline/output.txt index e41d7092757..c675206603d 100644 --- a/acceptance/bundle/resources/dashboards/change-serialized-inline/output.txt +++ b/acceptance/bundle/resources/dashboards/change-serialized-inline/output.txt @@ -2,7 +2,7 @@ >>> [CLI] bundle deploy Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/change-serialized-inline-[UNIQUE_NAME]/default/files... Created dashboards.inline_dash -Files: 6 uploaded, 0 deleted +Files: 5 uploaded, 0 deleted Resources: 1 created, 0 changed, 0 deleted, 0 unchanged >>> [CLI] bundle plan @@ -10,11 +10,7 @@ update dashboards.inline_dash Plan: 0 to add, 1 to change, 0 to delete, 0 unchanged ->>> [CLI] bundle deploy -Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/change-serialized-inline-[UNIQUE_NAME]/default/files... -Updated dashboards.inline_dash -Files: 3 uploaded, 0 deleted -Resources: 0 created, 1 changed, 0 deleted, 0 unchanged +>>> [CLI] bundle plan -o json >>> [CLI] bundle destroy --auto-approve The following resources will be deleted: diff --git a/acceptance/bundle/resources/dashboards/change-serialized-inline/script b/acceptance/bundle/resources/dashboards/change-serialized-inline/script index 8f10ff62903..eb5592ec881 100644 --- a/acceptance/bundle/resources/dashboards/change-serialized-inline/script +++ b/acceptance/bundle/resources/dashboards/change-serialized-inline/script @@ -1,6 +1,5 @@ cleanup() { trace $CLI bundle destroy --auto-approve - rm -f out.requests.txt } trap cleanup EXIT @@ -22,17 +21,6 @@ export PAGE_DISPLAY_NAME="Page One" envsubst < databricks.yml.tmpl > databricks.yml trace $CLI bundle plan -# Discard the requests from the initial deploy so the recording below shows only what -# deploying the change sends. Direct only: terraform echoes OUTPUT_ONLY fields in the -# request body, and the direct engine is the default we care about here. -if [ "$DATABRICKS_BUNDLE_ENGINE" = "direct" ]; then - print_requests.py //api/2.0/lakeview/dashboards > /dev/null -fi - -# Deploy the change. The update serializes the inline YAML map to a JSON string, same -# as create. -trace $CLI bundle deploy - -if [ "$DATABRICKS_BUNDLE_ENGINE" = "direct" ]; then - print_requests.py //api/2.0/lakeview/dashboards > out.requests.direct.txt -fi +# Capture the machine-readable plan too. The plan structure differs between engines, +# so each engine writes its own file. +trace $CLI bundle plan -o json > out.plan.$DATABRICKS_BUNDLE_ENGINE.json diff --git a/acceptance/bundle/resources/dashboards/change-serialized-inline/test.toml b/acceptance/bundle/resources/dashboards/change-serialized-inline/test.toml index 17383eac468..3c873441e45 100644 --- a/acceptance/bundle/resources/dashboards/change-serialized-inline/test.toml +++ b/acceptance/bundle/resources/dashboards/change-serialized-inline/test.toml @@ -1,3 +1,4 @@ Ignore = [ "databricks.yml", ] +RecordRequests = false From 0e491079a6e3236d32906d1419d7acc015444843 Mon Sep 17 00:00:00 2001 From: Sankalp-Mittal Date: Tue, 1 Sep 2026 18:34:02 +0000 Subject: [PATCH 04/15] Stop overriding INJECT_STALE_ON_DIRECT in serialized-inline test The direct-engine destroy 404s on the injected stale GET and reports "0 deleted" while terraform reports "1 deleted". That divergence is only in the cleanup step, so route destroy output to a LOG file instead of disabling the inherited stale-GET simulation. Co-authored-by: Isaac --- .../resources/dashboards/serialized-inline/output.txt | 8 -------- .../bundle/resources/dashboards/serialized-inline/script | 7 +++++-- .../resources/dashboards/serialized-inline/test.toml | 5 ----- 3 files changed, 5 insertions(+), 15 deletions(-) diff --git a/acceptance/bundle/resources/dashboards/serialized-inline/output.txt b/acceptance/bundle/resources/dashboards/serialized-inline/output.txt index 389e62fcdeb..5fbda9f2d9e 100644 --- a/acceptance/bundle/resources/dashboards/serialized-inline/output.txt +++ b/acceptance/bundle/resources/dashboards/serialized-inline/output.txt @@ -29,11 +29,3 @@ Resources: 1 created, 0 changed, 0 deleted, 0 unchanged "warehouse_id": "[TEST_DEFAULT_WAREHOUSE_ID]" } } - ->>> [CLI] bundle destroy --auto-approve -The following resources will be deleted: - delete resources.dashboards.inline_dash - -All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/dashboard-serialized-inline-[UNIQUE_NAME]/default - -Destroy: 1 deleted diff --git a/acceptance/bundle/resources/dashboards/serialized-inline/script b/acceptance/bundle/resources/dashboards/serialized-inline/script index 04ca23512e0..befe8c09248 100644 --- a/acceptance/bundle/resources/dashboards/serialized-inline/script +++ b/acceptance/bundle/resources/dashboards/serialized-inline/script @@ -1,8 +1,11 @@ envsubst < databricks.yml.tmpl > databricks.yml cleanup() { - trace $CLI bundle destroy --auto-approve - rm out.requests.txt + # Cleanup only. The direct engine's destroy 404s on the injected stale GET and + # reports "0 deleted" while terraform reports "1 deleted", so keep it out of the + # compared output. + $CLI bundle destroy --auto-approve &> LOG.destroy + rm -f out.requests.txt } trap cleanup EXIT diff --git a/acceptance/bundle/resources/dashboards/serialized-inline/test.toml b/acceptance/bundle/resources/dashboards/serialized-inline/test.toml index a5edf8715ad..17383eac468 100644 --- a/acceptance/bundle/resources/dashboards/serialized-inline/test.toml +++ b/acceptance/bundle/resources/dashboards/serialized-inline/test.toml @@ -1,8 +1,3 @@ Ignore = [ "databricks.yml", ] - -# This test does no read-after-deploy, so the inherited eventual-consistency stale GET -# is unnecessary. With it enabled, the direct-engine destroy's first GET 404s and reports -# "0 deleted", diverging from terraform. Disable it so both engines destroy identically. -Env.INJECT_STALE_ON_DIRECT = "0" From 25cd3863626a5c05830aaf69e4ccb5069e8f3c92 Mon Sep 17 00:00:00 2001 From: Sankalp-Mittal Date: Tue, 1 Sep 2026 18:46:36 +0000 Subject: [PATCH 05/15] Address review: update_file.py, READPLAN, and capture the update request - Change the inline serialized_dashboard value with update_file.py, which asserts if the target text is missing instead of silently no-op-ing. - Deploy the change and test the READPLAN matrix (in-memory vs saved plan); both send the same update request. - Capture the direct-engine update request alongside the per-engine JSON plans. Co-authored-by: Isaac --- .../databricks.yml.tmpl | 2 +- .../out.requests.direct.txt | 18 ++++++++++++ .../change-serialized-inline/out.test.toml | 1 + .../change-serialized-inline/output.txt | 8 ++++- .../change-serialized-inline/script | 29 ++++++++++++++----- .../change-serialized-inline/test.toml | 3 +- 6 files changed, 51 insertions(+), 10 deletions(-) create mode 100644 acceptance/bundle/resources/dashboards/change-serialized-inline/out.requests.direct.txt diff --git a/acceptance/bundle/resources/dashboards/change-serialized-inline/databricks.yml.tmpl b/acceptance/bundle/resources/dashboards/change-serialized-inline/databricks.yml.tmpl index c5f5494f367..0942aa4f690 100644 --- a/acceptance/bundle/resources/dashboards/change-serialized-inline/databricks.yml.tmpl +++ b/acceptance/bundle/resources/dashboards/change-serialized-inline/databricks.yml.tmpl @@ -9,4 +9,4 @@ resources: serialized_dashboard: # inline YAML MAP = the non-string case pages: - name: page1 - displayName: $PAGE_DISPLAY_NAME + displayName: Page 1 diff --git a/acceptance/bundle/resources/dashboards/change-serialized-inline/out.requests.direct.txt b/acceptance/bundle/resources/dashboards/change-serialized-inline/out.requests.direct.txt new file mode 100644 index 00000000000..763f6fc22c7 --- /dev/null +++ b/acceptance/bundle/resources/dashboards/change-serialized-inline/out.requests.direct.txt @@ -0,0 +1,18 @@ +{ + "method": "PATCH", + "path": "/api/2.0/lakeview/dashboards/[DASHBOARD_ID]", + "body": { + "display_name": "Inline Dash", + "parent_path": "/Workspace/Users/[USERNAME]/.bundle/change-serialized-inline-[UNIQUE_NAME]/default/resources", + "serialized_dashboard": "{\"pages\":[{\"displayName\":\"Page One\",\"name\":\"page1\"}]}", + "warehouse_id": "[TEST_DEFAULT_WAREHOUSE_ID]" + } +} +{ + "method": "POST", + "path": "/api/2.0/lakeview/dashboards/[DASHBOARD_ID]/published", + "body": { + "embed_credentials": false, + "warehouse_id": "[TEST_DEFAULT_WAREHOUSE_ID]" + } +} diff --git a/acceptance/bundle/resources/dashboards/change-serialized-inline/out.test.toml b/acceptance/bundle/resources/dashboards/change-serialized-inline/out.test.toml index cef45fe553a..b1bef937a27 100644 --- a/acceptance/bundle/resources/dashboards/change-serialized-inline/out.test.toml +++ b/acceptance/bundle/resources/dashboards/change-serialized-inline/out.test.toml @@ -1,3 +1,4 @@ Cloud = true EnvMatrix.DATABRICKS_BUNDLE_ENGINE = ["terraform", "direct"] EnvMatrix.DMS = ["", "true"] +EnvMatrix.READPLAN = ["", "1"] diff --git a/acceptance/bundle/resources/dashboards/change-serialized-inline/output.txt b/acceptance/bundle/resources/dashboards/change-serialized-inline/output.txt index c675206603d..ca5a2744eaf 100644 --- a/acceptance/bundle/resources/dashboards/change-serialized-inline/output.txt +++ b/acceptance/bundle/resources/dashboards/change-serialized-inline/output.txt @@ -2,7 +2,7 @@ >>> [CLI] bundle deploy Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/change-serialized-inline-[UNIQUE_NAME]/default/files... Created dashboards.inline_dash -Files: 5 uploaded, 0 deleted +Files: 6 uploaded, 0 deleted Resources: 1 created, 0 changed, 0 deleted, 0 unchanged >>> [CLI] bundle plan @@ -12,6 +12,12 @@ Plan: 0 to add, 1 to change, 0 to delete, 0 unchanged >>> [CLI] bundle plan -o json +=== deploy the change +Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/change-serialized-inline-[UNIQUE_NAME]/default/files... +Updated dashboards.inline_dash +Files: 4 uploaded, 0 deleted +Resources: 0 created, 1 changed, 0 deleted, 0 unchanged + >>> [CLI] bundle destroy --auto-approve The following resources will be deleted: delete resources.dashboards.inline_dash diff --git a/acceptance/bundle/resources/dashboards/change-serialized-inline/script b/acceptance/bundle/resources/dashboards/change-serialized-inline/script index eb5592ec881..b6d5bff961b 100644 --- a/acceptance/bundle/resources/dashboards/change-serialized-inline/script +++ b/acceptance/bundle/resources/dashboards/change-serialized-inline/script @@ -1,10 +1,10 @@ cleanup() { trace $CLI bundle destroy --auto-approve + rm -f out.requests.txt } trap cleanup EXIT # Deploy a dashboard whose serialized_dashboard is an inline YAML map. -export PAGE_DISPLAY_NAME="Page 1" envsubst < databricks.yml.tmpl > databricks.yml trace $CLI bundle deploy @@ -15,12 +15,27 @@ add_repl "$dashboard_id" DASHBOARD_ID # state (the first read of a freshly created dashboard 404s on the direct engine). retry --until "Page 1" $CLI lakeview get "$dashboard_id" > /dev/null -# Change a value *inside* the inline serialized_dashboard, then show the plan. The -# change must be detected as an update to the existing dashboard, not a recreate. -export PAGE_DISPLAY_NAME="Page One" -envsubst < databricks.yml.tmpl > databricks.yml +# Change a value *inside* the inline serialized_dashboard. update_file.py asserts if the +# text is missing, so a broken test fails loudly instead of silently doing nothing. +update_file.py databricks.yml "Page 1" "Page One" + +# The change must be detected as an update to the existing dashboard, not a recreate. trace $CLI bundle plan -# Capture the machine-readable plan too. The plan structure differs between engines, -# so each engine writes its own file. +# Machine-readable plan (per engine); also fed to the READPLAN=1 deploy below. trace $CLI bundle plan -o json > out.plan.$DATABRICKS_BUNDLE_ENGINE.json + +# Discard the requests from the initial deploy so the capture below shows only what +# deploying the change sends (direct only; terraform echoes OUTPUT_ONLY fields). +if [ "$DATABRICKS_BUNDLE_ENGINE" = "direct" ]; then + print_requests.py //api/2.0/lakeview/dashboards > /dev/null +fi + +# Deploy the change, in-memory (READPLAN="") or from the saved plan (READPLAN="1"). A +# saved-plan deploy must send the same request as an in-memory one. +title "deploy the change\n" +$CLI bundle deploy $(readplanarg out.plan.$DATABRICKS_BUNDLE_ENGINE.json) + +if [ "$DATABRICKS_BUNDLE_ENGINE" = "direct" ]; then + print_requests.py //api/2.0/lakeview/dashboards > out.requests.direct.txt +fi diff --git a/acceptance/bundle/resources/dashboards/change-serialized-inline/test.toml b/acceptance/bundle/resources/dashboards/change-serialized-inline/test.toml index 3c873441e45..eb67230b265 100644 --- a/acceptance/bundle/resources/dashboards/change-serialized-inline/test.toml +++ b/acceptance/bundle/resources/dashboards/change-serialized-inline/test.toml @@ -1,4 +1,5 @@ Ignore = [ "databricks.yml", ] -RecordRequests = false + +EnvMatrix.READPLAN = ["", "1"] From 2cd393434417e00afa0bc372f3ac3a9950af0bcd Mon Sep 17 00:00:00 2001 From: Sankalp-Mittal Date: Tue, 1 Sep 2026 18:48:19 +0000 Subject: [PATCH 06/15] Trim verbose comments in the serialized-inline test scripts Co-authored-by: Isaac --- .../dashboards/change-serialized-inline/script | 18 +++++++----------- .../dashboards/serialized-inline/script | 10 +++------- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/acceptance/bundle/resources/dashboards/change-serialized-inline/script b/acceptance/bundle/resources/dashboards/change-serialized-inline/script index b6d5bff961b..2ad282edd7c 100644 --- a/acceptance/bundle/resources/dashboards/change-serialized-inline/script +++ b/acceptance/bundle/resources/dashboards/change-serialized-inline/script @@ -4,35 +4,31 @@ cleanup() { } trap cleanup EXIT -# Deploy a dashboard whose serialized_dashboard is an inline YAML map. +# Deploy an inline-YAML-map dashboard. envsubst < databricks.yml.tmpl > databricks.yml trace $CLI bundle deploy dashboard_id=$($CLI bundle summary --output json | jq -r '.resources.dashboards.inline_dash.id') add_repl "$dashboard_id" DASHBOARD_ID -# Wait out eventual consistency so the change below is planned against the deployed -# state (the first read of a freshly created dashboard 404s on the direct engine). +# Wait out eventual consistency (direct's first read 404s) before changing. retry --until "Page 1" $CLI lakeview get "$dashboard_id" > /dev/null -# Change a value *inside* the inline serialized_dashboard. update_file.py asserts if the -# text is missing, so a broken test fails loudly instead of silently doing nothing. +# Change a value inside the map; update_file.py asserts if the text is missing. update_file.py databricks.yml "Page 1" "Page One" -# The change must be detected as an update to the existing dashboard, not a recreate. +# Should be detected as an update, not a recreate. trace $CLI bundle plan -# Machine-readable plan (per engine); also fed to the READPLAN=1 deploy below. +# Per-engine JSON plan; also the saved plan for READPLAN=1. trace $CLI bundle plan -o json > out.plan.$DATABRICKS_BUNDLE_ENGINE.json -# Discard the requests from the initial deploy so the capture below shows only what -# deploying the change sends (direct only; terraform echoes OUTPUT_ONLY fields). +# Drop initial-deploy requests so we capture only the change (direct only). if [ "$DATABRICKS_BUNDLE_ENGINE" = "direct" ]; then print_requests.py //api/2.0/lakeview/dashboards > /dev/null fi -# Deploy the change, in-memory (READPLAN="") or from the saved plan (READPLAN="1"). A -# saved-plan deploy must send the same request as an in-memory one. +# Deploy the change: in-memory (READPLAN="") or from the saved plan (READPLAN="1"). title "deploy the change\n" $CLI bundle deploy $(readplanarg out.plan.$DATABRICKS_BUNDLE_ENGINE.json) diff --git a/acceptance/bundle/resources/dashboards/serialized-inline/script b/acceptance/bundle/resources/dashboards/serialized-inline/script index befe8c09248..1cbe3b8b0df 100644 --- a/acceptance/bundle/resources/dashboards/serialized-inline/script +++ b/acceptance/bundle/resources/dashboards/serialized-inline/script @@ -1,9 +1,7 @@ envsubst < databricks.yml.tmpl > databricks.yml cleanup() { - # Cleanup only. The direct engine's destroy 404s on the injected stale GET and - # reports "0 deleted" while terraform reports "1 deleted", so keep it out of the - # compared output. + # Cleanup; direct's destroy 404s on the stale GET and diverges, so keep it out of the diff. $CLI bundle destroy --auto-approve &> LOG.destroy rm -f out.requests.txt } @@ -12,11 +10,9 @@ trap cleanup EXIT trace $CLI bundle plan trace $CLI bundle deploy -# Normalize the non-deterministic dashboard ID so the published-dashboard request -# path is stable across engines and runs. +# Stabilize the non-deterministic dashboard ID in recorded requests. dashboard_id=$($CLI bundle summary --output json | jq -r '.resources.dashboards.inline_dash.id') add_repl "$dashboard_id" DASHBOARD_ID -# serialized_dashboard is authored as an inline YAML map but must reach the API as a -# JSON *string*, not a nested object. Record the create request to prove that. +# Prove the inline YAML map reaches the API as a JSON string. trace print_requests.py //api/2.0/lakeview/dashboards From 9aea1255db848f549fdc1e82b2dda6d5115db4cf Mon Sep 17 00:00:00 2001 From: Sankalp-Mittal Date: Tue, 1 Sep 2026 19:56:53 +0000 Subject: [PATCH 07/15] Address review on serialized-inline: replace_ids.py and READPLAN - Use replace_ids.py instead of bundle summary + add_repl for the dashboard ID. - Add the READPLAN matrix; the create request is identical in-memory and from a saved plan. Co-authored-by: Isaac --- .../resources/dashboards/serialized-inline/out.test.toml | 1 + .../resources/dashboards/serialized-inline/output.txt | 6 ++---- .../bundle/resources/dashboards/serialized-inline/script | 8 +++----- .../resources/dashboards/serialized-inline/test.toml | 3 +++ 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/acceptance/bundle/resources/dashboards/serialized-inline/out.test.toml b/acceptance/bundle/resources/dashboards/serialized-inline/out.test.toml index cef45fe553a..b1bef937a27 100644 --- a/acceptance/bundle/resources/dashboards/serialized-inline/out.test.toml +++ b/acceptance/bundle/resources/dashboards/serialized-inline/out.test.toml @@ -1,3 +1,4 @@ Cloud = true EnvMatrix.DATABRICKS_BUNDLE_ENGINE = ["terraform", "direct"] EnvMatrix.DMS = ["", "true"] +EnvMatrix.READPLAN = ["", "1"] diff --git a/acceptance/bundle/resources/dashboards/serialized-inline/output.txt b/acceptance/bundle/resources/dashboards/serialized-inline/output.txt index 5fbda9f2d9e..f469ff494a4 100644 --- a/acceptance/bundle/resources/dashboards/serialized-inline/output.txt +++ b/acceptance/bundle/resources/dashboards/serialized-inline/output.txt @@ -3,11 +3,9 @@ create dashboards.inline_dash Plan: 1 to add, 0 to change, 0 to delete, 0 unchanged - ->>> [CLI] bundle deploy Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/dashboard-serialized-inline-[UNIQUE_NAME]/default/files... Created dashboards.inline_dash -Files: 6 uploaded, 0 deleted +Files: 7 uploaded, 0 deleted Resources: 1 created, 0 changed, 0 deleted, 0 unchanged >>> print_requests.py //api/2.0/lakeview/dashboards @@ -23,7 +21,7 @@ Resources: 1 created, 0 changed, 0 deleted, 0 unchanged } { "method": "POST", - "path": "/api/2.0/lakeview/dashboards/[DASHBOARD_ID]/published", + "path": "/api/2.0/lakeview/dashboards/[INLINE_DASH_ID]/published", "body": { "embed_credentials": false, "warehouse_id": "[TEST_DEFAULT_WAREHOUSE_ID]" diff --git a/acceptance/bundle/resources/dashboards/serialized-inline/script b/acceptance/bundle/resources/dashboards/serialized-inline/script index 1cbe3b8b0df..dc1b6d7a15b 100644 --- a/acceptance/bundle/resources/dashboards/serialized-inline/script +++ b/acceptance/bundle/resources/dashboards/serialized-inline/script @@ -8,11 +8,9 @@ cleanup() { trap cleanup EXIT trace $CLI bundle plan -trace $CLI bundle deploy - -# Stabilize the non-deterministic dashboard ID in recorded requests. -dashboard_id=$($CLI bundle summary --output json | jq -r '.resources.dashboards.inline_dash.id') -add_repl "$dashboard_id" DASHBOARD_ID +$CLI bundle plan -o json > tmp.plan.json +$CLI bundle deploy $(readplanarg tmp.plan.json) +replace_ids.py # Prove the inline YAML map reaches the API as a JSON string. trace print_requests.py //api/2.0/lakeview/dashboards diff --git a/acceptance/bundle/resources/dashboards/serialized-inline/test.toml b/acceptance/bundle/resources/dashboards/serialized-inline/test.toml index 17383eac468..6f91063a6ee 100644 --- a/acceptance/bundle/resources/dashboards/serialized-inline/test.toml +++ b/acceptance/bundle/resources/dashboards/serialized-inline/test.toml @@ -1,3 +1,6 @@ Ignore = [ "databricks.yml", + "tmp.plan.json", ] + +EnvMatrix.READPLAN = ["", "1"] From 2d72fb21b4d1b6b4be779f2ea4adbf862be26428 Mon Sep 17 00:00:00 2001 From: Sankalp-Mittal Date: Tue, 1 Sep 2026 20:01:08 +0000 Subject: [PATCH 08/15] remove comment --- .../bundle/resources/dashboards/change-serialized-inline/script | 1 - 1 file changed, 1 deletion(-) diff --git a/acceptance/bundle/resources/dashboards/change-serialized-inline/script b/acceptance/bundle/resources/dashboards/change-serialized-inline/script index 2ad282edd7c..89e5c8689e5 100644 --- a/acceptance/bundle/resources/dashboards/change-serialized-inline/script +++ b/acceptance/bundle/resources/dashboards/change-serialized-inline/script @@ -14,7 +14,6 @@ add_repl "$dashboard_id" DASHBOARD_ID # Wait out eventual consistency (direct's first read 404s) before changing. retry --until "Page 1" $CLI lakeview get "$dashboard_id" > /dev/null -# Change a value inside the map; update_file.py asserts if the text is missing. update_file.py databricks.yml "Page 1" "Page One" # Should be detected as an update, not a recreate. From 722f8ebf1b331aaaef55f6ce18aa3b5c992af91a Mon Sep 17 00:00:00 2001 From: Sankalp-Mittal Date: Tue, 1 Sep 2026 20:04:36 +0000 Subject: [PATCH 09/15] Assert the change plan with contains.py Encode "update, not recreate" as an executable check instead of a prose comment. Co-authored-by: Isaac --- .../resources/dashboards/change-serialized-inline/script | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/acceptance/bundle/resources/dashboards/change-serialized-inline/script b/acceptance/bundle/resources/dashboards/change-serialized-inline/script index 89e5c8689e5..cc8d4af20c4 100644 --- a/acceptance/bundle/resources/dashboards/change-serialized-inline/script +++ b/acceptance/bundle/resources/dashboards/change-serialized-inline/script @@ -16,8 +16,7 @@ retry --until "Page 1" $CLI lakeview get "$dashboard_id" > /dev/null update_file.py databricks.yml "Page 1" "Page One" -# Should be detected as an update, not a recreate. -trace $CLI bundle plan +trace $CLI bundle plan | contains.py "update" "!recreate" # Per-engine JSON plan; also the saved plan for READPLAN=1. trace $CLI bundle plan -o json > out.plan.$DATABRICKS_BUNDLE_ENGINE.json From b591e5a182d9417da6241c76676f9b18dd3a4e73 Mon Sep 17 00:00:00 2001 From: Sankalp-Mittal Date: Tue, 1 Sep 2026 20:11:30 +0000 Subject: [PATCH 10/15] Capture the update request per engine, not direct-only Drop the direct-only guard and record out.requests.$DATABRICKS_BUNDLE_ENGINE.txt for both engines. This documents terraform's OUTPUT_ONLY-field echoing instead of hiding it, following the repo's per-engine-file convention for divergent output. Co-authored-by: Isaac --- .../out.requests.terraform.txt | 23 +++++++++++++++++++ .../change-serialized-inline/script | 11 ++++----- 2 files changed, 27 insertions(+), 7 deletions(-) create mode 100644 acceptance/bundle/resources/dashboards/change-serialized-inline/out.requests.terraform.txt diff --git a/acceptance/bundle/resources/dashboards/change-serialized-inline/out.requests.terraform.txt b/acceptance/bundle/resources/dashboards/change-serialized-inline/out.requests.terraform.txt new file mode 100644 index 00000000000..641cd24882e --- /dev/null +++ b/acceptance/bundle/resources/dashboards/change-serialized-inline/out.requests.terraform.txt @@ -0,0 +1,23 @@ +{ + "method": "PATCH", + "path": "/api/2.0/lakeview/dashboards/[DASHBOARD_ID]", + "body": { + "create_time": "[TIMESTAMP]", + "dashboard_id": "[DASHBOARD_ID]", + "display_name": "Inline Dash", + "lifecycle_state": "ACTIVE", + "parent_path": "/Users/[USERNAME]/.bundle/change-serialized-inline-[UNIQUE_NAME]/default/resources", + "path": "/Users/[USERNAME]/.bundle/change-serialized-inline-[UNIQUE_NAME]/default/resources/Inline Dash.lvdash.json", + "serialized_dashboard": "{\"pages\":[{\"displayName\":\"Page One\",\"name\":\"page1\"}]}", + "update_time": "[TIMESTAMP]", + "warehouse_id": "[TEST_DEFAULT_WAREHOUSE_ID]" + } +} +{ + "method": "POST", + "path": "/api/2.0/lakeview/dashboards/[DASHBOARD_ID]/published", + "body": { + "embed_credentials": false, + "warehouse_id": "[TEST_DEFAULT_WAREHOUSE_ID]" + } +} diff --git a/acceptance/bundle/resources/dashboards/change-serialized-inline/script b/acceptance/bundle/resources/dashboards/change-serialized-inline/script index cc8d4af20c4..c58380f7a21 100644 --- a/acceptance/bundle/resources/dashboards/change-serialized-inline/script +++ b/acceptance/bundle/resources/dashboards/change-serialized-inline/script @@ -21,15 +21,12 @@ trace $CLI bundle plan | contains.py "update" "!recreate" # Per-engine JSON plan; also the saved plan for READPLAN=1. trace $CLI bundle plan -o json > out.plan.$DATABRICKS_BUNDLE_ENGINE.json -# Drop initial-deploy requests so we capture only the change (direct only). -if [ "$DATABRICKS_BUNDLE_ENGINE" = "direct" ]; then - print_requests.py //api/2.0/lakeview/dashboards > /dev/null -fi +# Drop the initial-deploy requests so the capture below shows only the change. +print_requests.py //api/2.0/lakeview/dashboards > /dev/null # Deploy the change: in-memory (READPLAN="") or from the saved plan (READPLAN="1"). title "deploy the change\n" $CLI bundle deploy $(readplanarg out.plan.$DATABRICKS_BUNDLE_ENGINE.json) -if [ "$DATABRICKS_BUNDLE_ENGINE" = "direct" ]; then - print_requests.py //api/2.0/lakeview/dashboards > out.requests.direct.txt -fi +# Capture the update request per engine (terraform echoes OUTPUT_ONLY fields). +print_requests.py //api/2.0/lakeview/dashboards > out.requests.$DATABRICKS_BUNDLE_ENGINE.txt From 2806b22594b2d8e24b6c8b332f8a2d435b5f0e6e Mon Sep 17 00:00:00 2001 From: Sankalp-Mittal Date: Tue, 1 Sep 2026 20:21:51 +0000 Subject: [PATCH 11/15] Project change-serialized-inline plan golden to the asserted change The direct plan dumped remote_state (etag, timestamps, and the API's pretty-printed serialized_dashboard string), which a real workspace formats differently than the local fake, breaking the cloud run. Project the golden to just the resource action and the serialized_dashboard old/new diff; keep the full plan in a tmp file for the READPLAN=1 deploy. Co-authored-by: Isaac --- .../out.plan.direct.json | 69 +------------------ .../out.plan.terraform.json | 1 - .../change-serialized-inline/output.txt | 2 +- .../change-serialized-inline/script | 9 ++- .../change-serialized-inline/test.toml | 1 + 5 files changed, 9 insertions(+), 73 deletions(-) diff --git a/acceptance/bundle/resources/dashboards/change-serialized-inline/out.plan.direct.json b/acceptance/bundle/resources/dashboards/change-serialized-inline/out.plan.direct.json index b9244b3ab9d..8228bcdebe1 100644 --- a/acceptance/bundle/resources/dashboards/change-serialized-inline/out.plan.direct.json +++ b/acceptance/bundle/resources/dashboards/change-serialized-inline/out.plan.direct.json @@ -1,69 +1,8 @@ { - "plan_version": 2, - "cli_version": "[CLI_VERSION]", - "lineage": "[UUID]", - "serial": 1, "plan": { "resources.dashboards.inline_dash": { "action": "update", - "new_state": { - "value": { - "display_name": "Inline Dash", - "embed_credentials": false, - "parent_path": "/Workspace/Users/[USERNAME]/.bundle/change-serialized-inline-[UNIQUE_NAME]/default/resources", - "published": true, - "serialized_dashboard": { - "pages": [ - { - "displayName": "Page One", - "name": "page1" - } - ] - }, - "warehouse_id": "[TEST_DEFAULT_WAREHOUSE_ID]" - } - }, - "remote_state": { - "create_time": "[TIMESTAMP]", - "dashboard_id": "[DASHBOARD_ID]", - "display_name": "Inline Dash", - "embed_credentials": false, - "etag": "[NUMID]", - "lifecycle_state": "ACTIVE", - "parent_path": "/Workspace/Users/[USERNAME]/.bundle/change-serialized-inline-[UNIQUE_NAME]/default/resources", - "path": "/Users/[USERNAME]/.bundle/change-serialized-inline-[UNIQUE_NAME]/default/resources/Inline Dash.lvdash.json", - "published": true, - "serialized_dashboard": "{\"pages\":[{\"displayName\":\"Page 1\",\"name\":\"page1\",\"pageType\":\"PAGE_TYPE_CANVAS\"}]}\n", - "update_time": "[TIMESTAMP]", - "warehouse_id": "[TEST_DEFAULT_WAREHOUSE_ID]" - }, "changes": { - "create_time": { - "action": "skip", - "reason": "spec:output_only", - "remote": "[TIMESTAMP]" - }, - "dashboard_id": { - "action": "skip", - "reason": "spec:output_only", - "remote": "[DASHBOARD_ID]" - }, - "etag": { - "action": "skip", - "reason": "custom", - "old": "[NUMID]", - "remote": "[NUMID]" - }, - "lifecycle_state": { - "action": "skip", - "reason": "spec:output_only", - "remote": "ACTIVE" - }, - "path": { - "action": "skip", - "reason": "spec:output_only", - "remote": "/Users/[USERNAME]/.bundle/change-serialized-inline-[UNIQUE_NAME]/default/resources/Inline Dash.lvdash.json" - }, "serialized_dashboard": { "action": "update", "old": { @@ -81,13 +20,7 @@ "name": "page1" } ] - }, - "remote": "{\"pages\":[{\"displayName\":\"Page 1\",\"name\":\"page1\",\"pageType\":\"PAGE_TYPE_CANVAS\"}]}\n" - }, - "update_time": { - "action": "skip", - "reason": "spec:output_only", - "remote": "[TIMESTAMP]" + } } } } diff --git a/acceptance/bundle/resources/dashboards/change-serialized-inline/out.plan.terraform.json b/acceptance/bundle/resources/dashboards/change-serialized-inline/out.plan.terraform.json index 7795272689a..8fc18e647ba 100644 --- a/acceptance/bundle/resources/dashboards/change-serialized-inline/out.plan.terraform.json +++ b/acceptance/bundle/resources/dashboards/change-serialized-inline/out.plan.terraform.json @@ -1,5 +1,4 @@ { - "cli_version": "[CLI_VERSION]", "plan": { "resources.dashboards.inline_dash": { "action": "update" diff --git a/acceptance/bundle/resources/dashboards/change-serialized-inline/output.txt b/acceptance/bundle/resources/dashboards/change-serialized-inline/output.txt index ca5a2744eaf..d8537af591b 100644 --- a/acceptance/bundle/resources/dashboards/change-serialized-inline/output.txt +++ b/acceptance/bundle/resources/dashboards/change-serialized-inline/output.txt @@ -15,7 +15,7 @@ Plan: 0 to add, 1 to change, 0 to delete, 0 unchanged === deploy the change Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/change-serialized-inline-[UNIQUE_NAME]/default/files... Updated dashboards.inline_dash -Files: 4 uploaded, 0 deleted +Files: 5 uploaded, 0 deleted Resources: 0 created, 1 changed, 0 deleted, 0 unchanged >>> [CLI] bundle destroy --auto-approve diff --git a/acceptance/bundle/resources/dashboards/change-serialized-inline/script b/acceptance/bundle/resources/dashboards/change-serialized-inline/script index c58380f7a21..37a92247b4f 100644 --- a/acceptance/bundle/resources/dashboards/change-serialized-inline/script +++ b/acceptance/bundle/resources/dashboards/change-serialized-inline/script @@ -18,15 +18,18 @@ update_file.py databricks.yml "Page 1" "Page One" trace $CLI bundle plan | contains.py "update" "!recreate" -# Per-engine JSON plan; also the saved plan for READPLAN=1. -trace $CLI bundle plan -o json > out.plan.$DATABRICKS_BUNDLE_ENGINE.json +# Full plan drives the READPLAN=1 deploy below. +trace $CLI bundle plan -o json > tmp.plan.json +# Golden keeps only the asserted change; a real workspace formats the dropped +# remote_state/etag/serialized_dashboard fields differently than the local fake. +jq '{plan: (.plan | map_values({action} + (if .changes then {changes: {serialized_dashboard: (.changes.serialized_dashboard | {action, old, new})}} else {} end)))}' tmp.plan.json > out.plan.$DATABRICKS_BUNDLE_ENGINE.json # Drop the initial-deploy requests so the capture below shows only the change. print_requests.py //api/2.0/lakeview/dashboards > /dev/null # Deploy the change: in-memory (READPLAN="") or from the saved plan (READPLAN="1"). title "deploy the change\n" -$CLI bundle deploy $(readplanarg out.plan.$DATABRICKS_BUNDLE_ENGINE.json) +$CLI bundle deploy $(readplanarg tmp.plan.json) # Capture the update request per engine (terraform echoes OUTPUT_ONLY fields). print_requests.py //api/2.0/lakeview/dashboards > out.requests.$DATABRICKS_BUNDLE_ENGINE.txt diff --git a/acceptance/bundle/resources/dashboards/change-serialized-inline/test.toml b/acceptance/bundle/resources/dashboards/change-serialized-inline/test.toml index eb67230b265..6f91063a6ee 100644 --- a/acceptance/bundle/resources/dashboards/change-serialized-inline/test.toml +++ b/acceptance/bundle/resources/dashboards/change-serialized-inline/test.toml @@ -1,5 +1,6 @@ Ignore = [ "databricks.yml", + "tmp.plan.json", ] EnvMatrix.READPLAN = ["", "1"] From da5627c16dbea3f040fa656fdc8216ef24cfee6b Mon Sep 17 00:00:00 2001 From: Sankalp-Mittal Date: Tue, 1 Sep 2026 20:33:13 +0000 Subject: [PATCH 12/15] Make change-serialized-inline local-only, revert plan projection The real Lakeview API pretty-prints serialized_dashboard and returns a differently-shaped etag, which the recorded plan golden can't match on a real workspace. Mark the test Cloud=false and drop the jq projection, dumping the full plan again (stable against the local fake). Co-authored-by: Isaac --- .../out.plan.direct.json | 69 ++++++++++++++++++- .../out.plan.terraform.json | 1 + .../change-serialized-inline/out.test.toml | 2 +- .../change-serialized-inline/output.txt | 2 +- .../change-serialized-inline/script | 9 +-- .../change-serialized-inline/test.toml | 5 +- 6 files changed, 78 insertions(+), 10 deletions(-) diff --git a/acceptance/bundle/resources/dashboards/change-serialized-inline/out.plan.direct.json b/acceptance/bundle/resources/dashboards/change-serialized-inline/out.plan.direct.json index 8228bcdebe1..b9244b3ab9d 100644 --- a/acceptance/bundle/resources/dashboards/change-serialized-inline/out.plan.direct.json +++ b/acceptance/bundle/resources/dashboards/change-serialized-inline/out.plan.direct.json @@ -1,8 +1,69 @@ { + "plan_version": 2, + "cli_version": "[CLI_VERSION]", + "lineage": "[UUID]", + "serial": 1, "plan": { "resources.dashboards.inline_dash": { "action": "update", + "new_state": { + "value": { + "display_name": "Inline Dash", + "embed_credentials": false, + "parent_path": "/Workspace/Users/[USERNAME]/.bundle/change-serialized-inline-[UNIQUE_NAME]/default/resources", + "published": true, + "serialized_dashboard": { + "pages": [ + { + "displayName": "Page One", + "name": "page1" + } + ] + }, + "warehouse_id": "[TEST_DEFAULT_WAREHOUSE_ID]" + } + }, + "remote_state": { + "create_time": "[TIMESTAMP]", + "dashboard_id": "[DASHBOARD_ID]", + "display_name": "Inline Dash", + "embed_credentials": false, + "etag": "[NUMID]", + "lifecycle_state": "ACTIVE", + "parent_path": "/Workspace/Users/[USERNAME]/.bundle/change-serialized-inline-[UNIQUE_NAME]/default/resources", + "path": "/Users/[USERNAME]/.bundle/change-serialized-inline-[UNIQUE_NAME]/default/resources/Inline Dash.lvdash.json", + "published": true, + "serialized_dashboard": "{\"pages\":[{\"displayName\":\"Page 1\",\"name\":\"page1\",\"pageType\":\"PAGE_TYPE_CANVAS\"}]}\n", + "update_time": "[TIMESTAMP]", + "warehouse_id": "[TEST_DEFAULT_WAREHOUSE_ID]" + }, "changes": { + "create_time": { + "action": "skip", + "reason": "spec:output_only", + "remote": "[TIMESTAMP]" + }, + "dashboard_id": { + "action": "skip", + "reason": "spec:output_only", + "remote": "[DASHBOARD_ID]" + }, + "etag": { + "action": "skip", + "reason": "custom", + "old": "[NUMID]", + "remote": "[NUMID]" + }, + "lifecycle_state": { + "action": "skip", + "reason": "spec:output_only", + "remote": "ACTIVE" + }, + "path": { + "action": "skip", + "reason": "spec:output_only", + "remote": "/Users/[USERNAME]/.bundle/change-serialized-inline-[UNIQUE_NAME]/default/resources/Inline Dash.lvdash.json" + }, "serialized_dashboard": { "action": "update", "old": { @@ -20,7 +81,13 @@ "name": "page1" } ] - } + }, + "remote": "{\"pages\":[{\"displayName\":\"Page 1\",\"name\":\"page1\",\"pageType\":\"PAGE_TYPE_CANVAS\"}]}\n" + }, + "update_time": { + "action": "skip", + "reason": "spec:output_only", + "remote": "[TIMESTAMP]" } } } diff --git a/acceptance/bundle/resources/dashboards/change-serialized-inline/out.plan.terraform.json b/acceptance/bundle/resources/dashboards/change-serialized-inline/out.plan.terraform.json index 8fc18e647ba..7795272689a 100644 --- a/acceptance/bundle/resources/dashboards/change-serialized-inline/out.plan.terraform.json +++ b/acceptance/bundle/resources/dashboards/change-serialized-inline/out.plan.terraform.json @@ -1,4 +1,5 @@ { + "cli_version": "[CLI_VERSION]", "plan": { "resources.dashboards.inline_dash": { "action": "update" diff --git a/acceptance/bundle/resources/dashboards/change-serialized-inline/out.test.toml b/acceptance/bundle/resources/dashboards/change-serialized-inline/out.test.toml index b1bef937a27..bf4f0e7d3c6 100644 --- a/acceptance/bundle/resources/dashboards/change-serialized-inline/out.test.toml +++ b/acceptance/bundle/resources/dashboards/change-serialized-inline/out.test.toml @@ -1,4 +1,4 @@ -Cloud = true +Cloud = false EnvMatrix.DATABRICKS_BUNDLE_ENGINE = ["terraform", "direct"] EnvMatrix.DMS = ["", "true"] EnvMatrix.READPLAN = ["", "1"] diff --git a/acceptance/bundle/resources/dashboards/change-serialized-inline/output.txt b/acceptance/bundle/resources/dashboards/change-serialized-inline/output.txt index d8537af591b..ca5a2744eaf 100644 --- a/acceptance/bundle/resources/dashboards/change-serialized-inline/output.txt +++ b/acceptance/bundle/resources/dashboards/change-serialized-inline/output.txt @@ -15,7 +15,7 @@ Plan: 0 to add, 1 to change, 0 to delete, 0 unchanged === deploy the change Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/change-serialized-inline-[UNIQUE_NAME]/default/files... Updated dashboards.inline_dash -Files: 5 uploaded, 0 deleted +Files: 4 uploaded, 0 deleted Resources: 0 created, 1 changed, 0 deleted, 0 unchanged >>> [CLI] bundle destroy --auto-approve diff --git a/acceptance/bundle/resources/dashboards/change-serialized-inline/script b/acceptance/bundle/resources/dashboards/change-serialized-inline/script index 37a92247b4f..c58380f7a21 100644 --- a/acceptance/bundle/resources/dashboards/change-serialized-inline/script +++ b/acceptance/bundle/resources/dashboards/change-serialized-inline/script @@ -18,18 +18,15 @@ update_file.py databricks.yml "Page 1" "Page One" trace $CLI bundle plan | contains.py "update" "!recreate" -# Full plan drives the READPLAN=1 deploy below. -trace $CLI bundle plan -o json > tmp.plan.json -# Golden keeps only the asserted change; a real workspace formats the dropped -# remote_state/etag/serialized_dashboard fields differently than the local fake. -jq '{plan: (.plan | map_values({action} + (if .changes then {changes: {serialized_dashboard: (.changes.serialized_dashboard | {action, old, new})}} else {} end)))}' tmp.plan.json > out.plan.$DATABRICKS_BUNDLE_ENGINE.json +# Per-engine JSON plan; also the saved plan for READPLAN=1. +trace $CLI bundle plan -o json > out.plan.$DATABRICKS_BUNDLE_ENGINE.json # Drop the initial-deploy requests so the capture below shows only the change. print_requests.py //api/2.0/lakeview/dashboards > /dev/null # Deploy the change: in-memory (READPLAN="") or from the saved plan (READPLAN="1"). title "deploy the change\n" -$CLI bundle deploy $(readplanarg tmp.plan.json) +$CLI bundle deploy $(readplanarg out.plan.$DATABRICKS_BUNDLE_ENGINE.json) # Capture the update request per engine (terraform echoes OUTPUT_ONLY fields). print_requests.py //api/2.0/lakeview/dashboards > out.requests.$DATABRICKS_BUNDLE_ENGINE.txt diff --git a/acceptance/bundle/resources/dashboards/change-serialized-inline/test.toml b/acceptance/bundle/resources/dashboards/change-serialized-inline/test.toml index 6f91063a6ee..5bb2a87bbbc 100644 --- a/acceptance/bundle/resources/dashboards/change-serialized-inline/test.toml +++ b/acceptance/bundle/resources/dashboards/change-serialized-inline/test.toml @@ -1,6 +1,9 @@ +# Local only: the real Lakeview API pretty-prints serialized_dashboard and returns a +# differently-shaped etag, which the recorded plan golden can't match. +Cloud = false + Ignore = [ "databricks.yml", - "tmp.plan.json", ] EnvMatrix.READPLAN = ["", "1"] From 94fc3938cd24dda3df2b78150520256cb691fe59 Mon Sep 17 00:00:00 2001 From: Sankalp-Mittal Date: Tue, 1 Sep 2026 20:34:48 +0000 Subject: [PATCH 13/15] humanize comment --- .../resources/dashboards/change-serialized-inline/test.toml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/acceptance/bundle/resources/dashboards/change-serialized-inline/test.toml b/acceptance/bundle/resources/dashboards/change-serialized-inline/test.toml index 5bb2a87bbbc..5cab5faff69 100644 --- a/acceptance/bundle/resources/dashboards/change-serialized-inline/test.toml +++ b/acceptance/bundle/resources/dashboards/change-serialized-inline/test.toml @@ -1,5 +1,6 @@ -# Local only: the real Lakeview API pretty-prints serialized_dashboard and returns a -# differently-shaped etag, which the recorded plan golden can't match. +# the real API returns a pretty printed JSON output which causes +# the test to fail, since we are testing CLI only feature, we can set to +# Cloud = true Cloud = false Ignore = [ From 88bd16918cc2daac84b2576fbdda3879d6aef988 Mon Sep 17 00:00:00 2001 From: Sankalp-Mittal Date: Tue, 1 Sep 2026 21:04:01 +0000 Subject: [PATCH 14/15] Fix Windows: unset MSYS_NO_PATHCONV so bare python helpers resolve The inherited MSYS_NO_PATHCONV=1 stops Git-Bash from converting a helper script's own /c/... path when handing it to python3.exe, so replace_ids.py / update_file.py / print_requests.py fail to open on Windows. These tests pass no absolute paths to the CLI (print_requests.py uses the // form), so unset it. Co-authored-by: Isaac --- .../resources/dashboards/change-serialized-inline/script | 3 +++ .../bundle/resources/dashboards/serialized-inline/script | 3 +++ 2 files changed, 6 insertions(+) diff --git a/acceptance/bundle/resources/dashboards/change-serialized-inline/script b/acceptance/bundle/resources/dashboards/change-serialized-inline/script index c58380f7a21..cc0783834fb 100644 --- a/acceptance/bundle/resources/dashboards/change-serialized-inline/script +++ b/acceptance/bundle/resources/dashboards/change-serialized-inline/script @@ -1,3 +1,6 @@ +# Inherited MSYS_NO_PATHCONV breaks bare python helpers on Windows; this test doesn't need it. +unset MSYS_NO_PATHCONV + cleanup() { trace $CLI bundle destroy --auto-approve rm -f out.requests.txt diff --git a/acceptance/bundle/resources/dashboards/serialized-inline/script b/acceptance/bundle/resources/dashboards/serialized-inline/script index dc1b6d7a15b..78c6503704b 100644 --- a/acceptance/bundle/resources/dashboards/serialized-inline/script +++ b/acceptance/bundle/resources/dashboards/serialized-inline/script @@ -1,3 +1,6 @@ +# Inherited MSYS_NO_PATHCONV breaks bare python helpers on Windows; this test doesn't need it. +unset MSYS_NO_PATHCONV + envsubst < databricks.yml.tmpl > databricks.yml cleanup() { From 8766edc3aa11c861835edd46d33ce68b444d5519 Mon Sep 17 00:00:00 2001 From: Sankalp-Mittal Date: Wed, 2 Sep 2026 08:01:03 +0000 Subject: [PATCH 15/15] address comments --- .../dashboards/change-serialized-inline/script | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/acceptance/bundle/resources/dashboards/change-serialized-inline/script b/acceptance/bundle/resources/dashboards/change-serialized-inline/script index cc0783834fb..03b8c2ac46b 100644 --- a/acceptance/bundle/resources/dashboards/change-serialized-inline/script +++ b/acceptance/bundle/resources/dashboards/change-serialized-inline/script @@ -11,25 +11,21 @@ trap cleanup EXIT envsubst < databricks.yml.tmpl > databricks.yml trace $CLI bundle deploy +rm out.requests.txt + dashboard_id=$($CLI bundle summary --output json | jq -r '.resources.dashboards.inline_dash.id') add_repl "$dashboard_id" DASHBOARD_ID -# Wait out eventual consistency (direct's first read 404s) before changing. +# Wait out eventual consistency before changing. retry --until "Page 1" $CLI lakeview get "$dashboard_id" > /dev/null update_file.py databricks.yml "Page 1" "Page One" trace $CLI bundle plan | contains.py "update" "!recreate" -# Per-engine JSON plan; also the saved plan for READPLAN=1. trace $CLI bundle plan -o json > out.plan.$DATABRICKS_BUNDLE_ENGINE.json -# Drop the initial-deploy requests so the capture below shows only the change. -print_requests.py //api/2.0/lakeview/dashboards > /dev/null - -# Deploy the change: in-memory (READPLAN="") or from the saved plan (READPLAN="1"). title "deploy the change\n" $CLI bundle deploy $(readplanarg out.plan.$DATABRICKS_BUNDLE_ENGINE.json) -# Capture the update request per engine (terraform echoes OUTPUT_ONLY fields). print_requests.py //api/2.0/lakeview/dashboards > out.requests.$DATABRICKS_BUNDLE_ENGINE.txt