Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
75ace5a
direct: replace WaitAfterCreate/WaitAfterUpdate with Engine callback …
denik May 28, 2026
709e90e
direct/testserver: improve app test realism
denik May 29, 2026
53c27d0
testserver: remove unused GetWorkspace method
denik Jun 1, 2026
532c076
direct: simplify Engine API: SaveState(id, state) replaces SetID+Save…
denik Jun 1, 2026
290095b
direct: Engine.SaveState takes ctx, returns void; logs I/O failures i…
denik Jun 1, 2026
f45ffe0
direct: save state before wait in postgres and dashboard resources
denik Jun 1, 2026
6aacc6d
direct: save state before publishing dashboard; add acceptance tests
denik Jun 2, 2026
8a934e9
acceptance/dashboards: normalize ?o=/?w= workspace param in URL repla…
denik Jun 2, 2026
01b577e
acceptance/dashboards: fix ?o=/?w= workspace param normalization
denik Jun 2, 2026
087e744
acceptance/dashboards: fix &>> redirect for bash 3.2 compatibility
denik Jun 2, 2026
3f19239
acceptance/dashboards: unset MSYS_NO_PATHCONV before fault.py on Windows
denik Jun 3, 2026
b8f56a4
direct: Engine dedup+logging; dashboard saves draft state as Publishe…
denik Jun 3, 2026
d135237
direct: inline WaitAfterCreate/WaitAfterUpdate into sql_warehouse DoC…
denik Jun 3, 2026
e60f663
acceptance/dashboards: use replace_ids.py and inline plan output in p…
denik Jun 4, 2026
37ba9de
direct: save state before wait/publish in sql_warehouse DoCreate and …
denik Jun 5, 2026
106e36b
direct: save state before wait in model_serving_endpoint DoUpdate
denik Jun 5, 2026
3deeb64
direct: revert postgres SaveState (waiter.Name() is the LRO operation…
denik Jun 5, 2026
3574599
direct: route final Create/Update state saves through Engine
denik Jun 5, 2026
250161d
direct: rename Engine -> StateSaver
denik Jun 5, 2026
3bcb95e
direct: add SaveStateWith helper; avoid double JSON marshal in StateS…
denik Jun 5, 2026
3e5fc24
direct: fix SaveStateWith parameter order (ctx first)
denik Jun 5, 2026
ed4de44
direct: use SaveStateWith in app DoCreate to prevent un-deployed app
denik Jun 7, 2026
51d0012
acceptance: move ETAG replacement from parent dashboard test.toml to …
denik Jun 9, 2026
9260b0e
direct: add StateSaver parameter to genie_space DoCreate and DoUpdate
denik Jun 14, 2026
5c982db
direct: revert SaveStateWith from dashboard DoUpdate; add stale-conte…
denik Jun 14, 2026
dabe0cd
direct: add StateSaver parameter to postgres_database and postgres_ro…
denik Jun 25, 2026
3ba6c4f
direct: adapt instance_pool/job_run DoCreate/DoUpdate to StateSaver s…
denik Jul 29, 2026
fb2cbd5
direct: fix README reference to renamed StateSaver type
denik Jul 29, 2026
4c2736d
direct: drop RedactSensitiveFields from state save paths
denik Jul 29, 2026
51cee66
acceptance/dashboards: drop wide etag regexes, rely on precise ACC_REPLS
denik Jul 29, 2026
8c1c43a
direct: save dashboard state before publishing in DoUpdate
denik Aug 5, 2026
060ad91
acceptance/postgres: update goldens for uncorrupted duration state
denik Aug 5, 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,46 @@
{
"method": "POST",
"path": "/api/2.0/workspace/mkdirs",
"body": {
"path": "/Workspace/Users/[USERNAME]/.bundle/publish-failure-cleans-up-dashboard/default/state"
}
}
{
"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,55 @@

>>> [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
{
"action": "update",
"old": false,
"new": true,
"remote": false
}

>>> [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,20 @@
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"]

[Env]
# This test drives an explicit publish-failure/retry sequence and reads the
# dashboard back with `bundle plan`. The inherited eventual-consistency simulation
# would make that read observe a stale 404 and mask the behavior under test, so
# opt out of it here (same reason as detect-change).
INJECT_STALE_ON_DIRECT = "0"

# 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
Cloud = false
Local = true
RecordRequests = true

# Only run with the direct engine: the test verifies direct engine's SaveState
# behavior (draft persists on publish failure and is re-published on retry).
[EnvMatrix]
DATABRICKS_BUNDLE_ENGINE = ["direct"]

[Env]
# This test drives an explicit publish-failure/retry sequence and reads the
# dashboard back with `bundle plan`. The inherited eventual-consistency simulation
# would make that read observe a stale 404 and mask the behavior under test, so
# opt out of it here (same reason as detect-change).
INJECT_STALE_ON_DIRECT = "0"

# Dashboard published URLs use ?o= (local testserver) or ?w= (cloud) for the workspace/org ID.
[[Repls]]
Old = '\?[ow]=\d+'
New = "?[WSPARAM]=[NUMID]"
Loading
Loading