Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
cb9f61b
direct: replace WaitAfterCreate/WaitAfterUpdate with Engine callback …
denik May 28, 2026
2d5f565
direct/testserver: improve app test realism
denik May 29, 2026
1e5729b
testserver: remove unused GetWorkspace method
denik Jun 1, 2026
06a470f
direct: simplify Engine API: SaveState(id, state) replaces SetID+Save…
denik Jun 1, 2026
9b3ee59
direct: Engine.SaveState takes ctx, returns void; logs I/O failures i…
denik Jun 1, 2026
d362f10
direct: save state before wait in postgres and dashboard resources
denik Jun 1, 2026
1d54250
direct: save state before publishing dashboard; add acceptance tests
denik Jun 2, 2026
6f1d6e0
acceptance/dashboards: normalize ?o=/?w= workspace param in URL repla…
denik Jun 2, 2026
a88f6b7
acceptance/dashboards: fix ?o=/?w= workspace param normalization
denik Jun 2, 2026
49a7521
acceptance/dashboards: fix &>> redirect for bash 3.2 compatibility
denik Jun 2, 2026
48d6a45
acceptance/dashboards: unset MSYS_NO_PATHCONV before fault.py on Windows
denik Jun 3, 2026
1681535
direct: Engine dedup+logging; dashboard saves draft state as Publishe…
denik Jun 3, 2026
6445fa9
direct: inline WaitAfterCreate/WaitAfterUpdate into sql_warehouse DoC…
denik Jun 3, 2026
f3f6c7e
acceptance/dashboards: use replace_ids.py and inline plan output in p…
denik Jun 4, 2026
09378f0
direct: save state before wait/publish in sql_warehouse DoCreate and …
denik Jun 5, 2026
0025f4a
direct: save state before wait in model_serving_endpoint DoUpdate
denik Jun 5, 2026
18a8fe2
direct: revert postgres SaveState (waiter.Name() is the LRO operation…
denik Jun 5, 2026
1634ac8
direct: route final Create/Update state saves through Engine
denik Jun 5, 2026
ce332b9
direct: rename Engine -> StateSaver
denik Jun 5, 2026
6306ca9
direct: add SaveStateWith helper; avoid double JSON marshal in StateS…
denik Jun 5, 2026
2aff514
direct: fix SaveStateWith parameter order (ctx first)
denik Jun 5, 2026
1476840
direct: use SaveStateWith in app DoCreate to prevent un-deployed app
denik Jun 7, 2026
218a062
acceptance: move ETAG replacement from parent dashboard test.toml to …
denik Jun 9, 2026
24072ef
direct: add StateSaver parameter to genie_space DoCreate and DoUpdate
denik Jun 14, 2026
166b51d
direct: revert SaveStateWith from dashboard DoUpdate; add stale-conte…
denik Jun 14, 2026
0168a96
direct: add StateSaver parameter to postgres_database and postgres_ro…
denik Jun 25, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Etag is a long integer in the Terraform PATCH body; can be negative on cloud.
[[Repls]]
Old = "\"[-0-9]{8,}\""
New = "[ETAG]"

[[Repls]]
Old = "\"[0-9]{8,}\""
New = "[ETAG]"
8 changes: 8 additions & 0 deletions acceptance/bundle/resources/dashboards/change-name/test.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Etag is a long integer in the Terraform PATCH body; can be negative on cloud.
[[Repls]]
Old = "\"[-0-9]{8,}\""
New = "[ETAG]"

[[Repls]]
Old = "\"[0-9]{8,}\""
New = "[ETAG]"
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@ Ignore = [
# Setting this environment variable prevents that conversion on windows.
MSYS_NO_PATHCONV = "1"

# Etag is a long integer; can be negative on cloud. Replace for cloud compatibility.
[[Repls]]
Old = "\"[-0-9]{8,}\""
New = "[ETAG]"

[[Repls]]
Old = "\"[0-9]{8,}\""
New = "[ETAG]"

[[Repls]]
Old = "[0-9a-z]{16,}"
New = "[ALPHANUMID]"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"method": "POST",
"path": "/api/2.0/workspace/mkdirs",
"body": {
"path": "/Workspace/Users/[USERNAME]/.bundle/publish-failure-cleans-up-dashboard/default/artifacts/.internal"
}
}
{
"method": "POST",
"path": "/api/2.0/workspace/mkdirs",
"body": {
"path": "/Workspace/Users/[USERNAME]/.bundle/publish-failure-cleans-up-dashboard/default/files"
}
}
{
"method": "POST",
"path": "/api/2.0/workspace/mkdirs",
"body": {
"path": "/Workspace/Users/[USERNAME]/.bundle/publish-failure-cleans-up-dashboard/default/resources"
}
}
{
"method": "POST",
"path": "/api/2.0/lakeview/dashboards",
"body": {
"display_name": "my dashboard",
"parent_path": "/Workspace/Users/[USERNAME]/.bundle/publish-failure-cleans-up-dashboard/default/resources",
"serialized_dashboard": "{\"pages\":[{\"name\":\"test-page\",\"displayName\":\"Test Dashboard\"}]}\n",
"warehouse_id": "doesnotexist"
}
}
{
"method": "POST",
"path": "/api/2.0/lakeview/dashboards/[DASHBOARD_ID]/published",
"body": {
"embed_credentials": false,
"warehouse_id": "doesnotexist"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ HTTP Status: 400 Bad Request
API error_code: RESOURCE_DOES_NOT_EXIST
API message: Warehouse doesnotexist does not exist

Updating deployment state...

Exit code: 1
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

>>> [CLI] bundle summary
Name: publish-failure-cleans-up-dashboard
Target: default
Workspace:
User: [USERNAME]
Path: /Workspace/Users/[USERNAME]/.bundle/publish-failure-cleans-up-dashboard/default
Resources:
Dashboards:
dashboard1:
Name: my dashboard
URL: [DATABRICKS_URL]/dashboardsv3/[DASHBOARD_ID]/published?[WSPARAM]=[NUMID]
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

>>> [CLI] bundle summary
Name: publish-failure-cleans-up-dashboard
Target: default
Workspace:
User: [USERNAME]
Path: /Workspace/Users/[USERNAME]/.bundle/publish-failure-cleans-up-dashboard/default
Resources:
Dashboards:
dashboard1:
Name: my dashboard
URL: (not deployed)
Original file line number Diff line number Diff line change
@@ -1,12 +0,0 @@

>>> [CLI] bundle summary
Name: publish-failure-cleans-up-dashboard
Target: default
Workspace:
User: [USERNAME]
Path: /Workspace/Users/[USERNAME]/.bundle/publish-failure-cleans-up-dashboard/default
Resources:
Dashboards:
dashboard1:
Name: my dashboard
URL: (not deployed)
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ envsubst < databricks.yml.tmpl > databricks.yml
# Deploy the dashboard. The dashboard will be created but publish will fail because the warehouse does not exist.
errcode trace $CLI bundle deploy &> out.deploy.$DATABRICKS_BUNDLE_ENGINE.txt

trace $CLI bundle summary
# After publish failure the dashboard draft should be in state (direct) or cleaned up (terraform).
trace $CLI bundle summary >> out.summary.$DATABRICKS_BUNDLE_ENGINE.txt 2>&1

# API should record a DELETE call to clean up the draft dashboard that was not published.
# Request sequence is identical across terraform and direct modes.
# API request sequence differs between engines (direct: no DELETE; terraform: DELETE to clean up).
unset MSYS_NO_PATHCONV
print_requests.py //lakeview/dashboards //workspace/mkdirs > out.dashboardrequests.txt
print_requests.py //lakeview/dashboards //workspace/mkdirs > out.dashboardrequests.$DATABRICKS_BUNDLE_ENGINE.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,8 @@ Response.Body = '{"error_code": "RESOURCE_DOES_NOT_EXIST", "message": "Warehouse
[[Repls]]
Old = "[0-9a-f]{32}"
New = "[DASHBOARD_ID]"

# Dashboard published URLs use ?o= (local testserver) or ?w= (cloud) for the workspace/org ID.
[[Repls]]
Old = '\?[ow]=\d+'
New = "?[WSPARAM]=[NUMID]"
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"pages":[{"name":"test-page","displayName":"Test Dashboard"}]}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
bundle:
name: publish-failure-retry-on-update

resources:
dashboards:
dashboard1:
display_name: my dashboard
warehouse_id: someid
file_path: ./dashboard.lvdash.json

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@

>>> [CLI] bundle deploy
Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/publish-failure-retry-on-update/default/files...
Deploying resources...
Updating deployment state...
Deployment complete!

>>> [CLI] bundle deploy
Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/publish-failure-retry-on-update/default/files...
Deploying resources...
Error: cannot update resources.dashboards.dashboard1: updating id=[DASHBOARD1_ID]: Fault injected by test. (400 INJECTED)

Endpoint: POST [DATABRICKS_URL]/api/2.0/lakeview/dashboards/[DASHBOARD1_ID]/published
HTTP Status: 400 Bad Request
API error_code: INJECTED
API message: Fault injected by test.

Updating deployment state...

Exit code: 1
{
"method": "PATCH",
"path": "/api/2.0/lakeview/dashboards/[DASHBOARD1_ID]",
"body": {
"display_name": "my dashboard renamed",
"parent_path": "/Workspace/Users/[USERNAME]/.bundle/publish-failure-retry-on-update/default/resources",
"serialized_dashboard": "{\"pages\":[{\"name\":\"test-page\",\"displayName\":\"Test Dashboard\"}]}\n",
"warehouse_id": "someid"
}
}
{
"method": "POST",
"path": "/api/2.0/lakeview/dashboards/[DASHBOARD1_ID]/published",
"body": {
"embed_credentials": false,
"warehouse_id": "someid"
}
}

>>> [CLI] bundle plan -o json
Warning: dashboard "dashboard1" has been modified remotely
at resources.dashboards.dashboard1
in databricks.yml:7:7

This dashboard has been modified remotely since the last bundle deployment.
These modifications are untracked and will be overwritten on deploy.

Make sure that the local dashboard definition matches what you intend to deploy
before proceeding with the deployment.

To overwrite the remote changes with your local version, use --force.
The remote modifications will be lost.

null

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

All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/publish-failure-retry-on-update/default

Deleting files...
Destroy complete!
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
envsubst < databricks.yml.tmpl > databricks.yml

cleanup() {
trace $CLI bundle destroy --auto-approve
rm -f out.requests.txt
}
trap cleanup EXIT

# unset MSYS_NO_PATHCONV so MSYS2 converts the script path to a Windows path
# when invoking the Python interpreter (required for fault.py to be found on Windows).
unset MSYS_NO_PATHCONV

# First deploy succeeds fully: the dashboard is created and published.
trace $CLI bundle deploy
replace_ids.py
rm out.requests.txt

# Inject a single publish failure for the update below.
fault.py "POST /api/2.0/lakeview/dashboards/*" 400 0 1

# Change the dashboard to trigger an Update, which bumps the server-side etag.
update_file.py databricks.yml "my dashboard" "my dashboard renamed"

# Deploy: Update (PATCH) succeeds and bumps the etag, but the publish (POST) fails.
errcode trace $CLI bundle deploy

# The failed deploy issued a PATCH (update) and a POST (publish), but no CREATE
# (POST /api/2.0/lakeview/dashboards): the existing dashboard was updated in place.
print_requests.py //lakeview/dashboards

# Plan shows "modified remotely": state still holds the pre-PATCH etag; the PATCH bumped
# the remote etag, so the next plan sees an etag mismatch and blocks with a warning.
# The published field is not shown as a pending change (null) because the "modified
# remotely" guard takes precedence.
trace $CLI bundle plan -o json | jq '.plan["resources.dashboards.dashboard1"].changes.published'
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Cloud = false
Local = true
RecordRequests = true

# Only run with the direct engine: the test verifies direct engine's SaveState
# behavior during DoUpdate (new etag + published=false persisted before a failed publish).
[EnvMatrix]
DATABRICKS_BUNDLE_ENGINE = ["direct"]

# Dashboard published URLs use ?o= (local testserver) or ?w= (cloud) for the workspace/org ID.
[[Repls]]
Old = '\?[ow]=\d+'
New = "?[WSPARAM]=[NUMID]"
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"pages":[{"name":"test-page","displayName":"Test Dashboard"}]}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
bundle:
name: publish-failure-retry

resources:
dashboards:
dashboard1:
display_name: my dashboard
warehouse_id: someid
file_path: ./dashboard.lvdash.json

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@

>>> [CLI] bundle deploy
Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/publish-failure-retry/default/files...
Deploying resources...
Error: cannot create resources.dashboards.dashboard1: Fault injected by test. (400 INJECTED)

Endpoint: POST [DATABRICKS_URL]/api/2.0/lakeview/dashboards/[DASHBOARD1_ID]/published
HTTP Status: 400 Bad Request
API error_code: INJECTED
API message: Fault injected by test.

Updating deployment state...

Exit code: 1

>>> [CLI] bundle summary
Name: publish-failure-retry
Target: default
Workspace:
User: [USERNAME]
Path: /Workspace/Users/[USERNAME]/.bundle/publish-failure-retry/default
Resources:
Dashboards:
dashboard1:
Name: my dashboard
URL: [DATABRICKS_URL]/dashboardsv3/[DASHBOARD1_ID]/published?[WSPARAM]=[NUMID]

>>> [CLI] bundle plan -o json
{
"action": "update",
"old": false,
"new": true,
"remote": false
}

>>> [CLI] bundle deploy
Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/publish-failure-retry/default/files...
Deploying resources...
Updating deployment state...
Deployment complete!
{
"method": "PATCH",
"path": "/api/2.0/lakeview/dashboards/[DASHBOARD1_ID]",
"body": {
"display_name": "my dashboard",
"parent_path": "/Workspace/Users/[USERNAME]/.bundle/publish-failure-retry/default/resources",
"serialized_dashboard": "{\"pages\":[{\"name\":\"test-page\",\"displayName\":\"Test Dashboard\"}]}\n",
"warehouse_id": "someid"
}
}
{
"method": "POST",
"path": "/api/2.0/lakeview/dashboards/[DASHBOARD1_ID]/published",
"body": {
"embed_credentials": false,
"warehouse_id": "someid"
}
}

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

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

Deleting files...
Destroy complete!
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
envsubst < databricks.yml.tmpl > databricks.yml

cleanup() {
trace $CLI bundle destroy --auto-approve
rm -f out.requests.txt
}
trap cleanup EXIT

# unset MSYS_NO_PATHCONV so MSYS2 converts the script path to a Windows path
# when invoking the Python interpreter (required for fault.py to be found on Windows).
unset MSYS_NO_PATHCONV

# Inject a single publish failure so the first deploy creates the dashboard
# draft but fails to publish it.
fault.py "POST /api/2.0/lakeview/dashboards/*" 400 0 1

# First deploy: dashboard is created and saved to state, but publish fails.
errcode trace $CLI bundle deploy

# Capture the dashboard ID from state so subsequent output is normalized.
replace_ids.py

# Dashboard should be in state (tracked) despite the publish failure.
trace $CLI bundle summary

# Plan should show published: false (saved state) -> true (desired).
trace $CLI bundle plan -o json | jq '.plan["resources.dashboards.dashboard1"].changes.published'

# Discard first-deploy requests so the output only contains second-deploy
# calls, making it easy to confirm no CREATE was issued.
rm out.requests.txt

# Second deploy: fault is gone; must publish the existing draft, not create a new one.
trace $CLI bundle deploy

# Confirm: second deploy issued an UPDATE and a PUBLISH call but no CREATE.
print_requests.py //lakeview/dashboards
Loading
Loading