Distinguish "not supported" from "not deployed" in bundle summary - #6583
Conversation
## Changes Bump `github.com/databricks/databricks-sdk-go` from v0.175.0 to v0.177.0 and the pinned OpenAPI spec SHA to `0f2c9a3d`. Regenerated all downstream artifacts from the new spec: CLI command stubs, bundle JSON schema, validation, direct-engine resources, pydabs models, and the DABs<->TF field map. User-visible additions include the jobs continuous `maintenance_window` field and the pipelines RabbitMQ connector options; the postgres branch `source_snapshot` field is now handled as immutable/input-only by the direct engine. The v0.177.0 `ml.*` field removals (feature-engineering) are not referenced by hand-written CLI code, so they required no source changes. The SDK now marks the pipelines `continuous` field deprecated; it remains a supported bundle config field, so its four usages carry `//nolint:staticcheck` (SA1019). ## Why Keep the CLI current with the latest SDK and provide a clean base for upcoming feature work. ## Tests Acceptance goldens regenerated via `-update` (help text + refschema). The non-update verify pass is green apart from load-induced terraform-engine timeout flakes, each confirmed passing in isolation. Root-module unit suite passes (9532 tests). `./task fmt`, `./task lint`, and `./task checks` clean. Co-authored-by: Isaac <no-reply@databricks.com>
## Changes
Add the `postgres_snapshot_schedules` bundle resource, which manages the
automatic-snapshot schedule of a Lakebase Postgres branch.
The snapshot schedule is a per-branch singleton with no create or delete API —
only `GetSnapshotSchedule` and `UpdateSnapshotSchedule`. The resource maps the
lifecycle onto that single write call:
- create/update set the branch's schedule via `UpdateSnapshotSchedule`
(update_mask `schedule`, awaiting the long-running operation);
- delete disables automatic snapshots by setting an empty cadence set, since
DoDelete also fires when the resource is removed from config, not only on
`bundle destroy`;
- `branch` composes the schedule's hierarchical name and is a provided id field
(a change recreates).
Modeled on the existing `postgres_*` resources. Direct engine only: the schedule
was added in databricks-sdk-go v0.177.0 and the pinned Terraform provider has no
equivalent resource yet, so the acceptance and bind tests are pinned to the
direct engine.
## Tests
- direct-engine unit CRUD (`bundle/direct/dresources`);
- acceptance (direct engine), four end-to-end scenarios, each reading the
schedule back with `postgres get-snapshot-schedule`:
- `basic`: create with a cadence, in-place cadence update, then remove the
resource from config, which disables the schedule (reads back
`schedule: null`);
- `update`: add the schedule to an already-deployed branch, then remove it;
- `out-of-band`: an out-of-band `update-snapshot-schedule` is detected as
drift by `bundle plan` (`update postgres_snapshot_schedules.main_schedule`)
and reconciled back by deploy;
- `orphaned`: removing the branch from config while keeping the schedule that
references it — the reference still resolves from the deployed state, so
validate passes and plan sequences a branch delete alongside a schedule
recreate (documented, not a validation error);
- the invariant and bind/unbind suites;
- resource-enumeration unit tests (bind support, run_as, permissions,
target-mode) extended for the new type.
Acceptance goldens regenerated via `-update`; the verify pass is green apart
from pre-existing load-induced terraform-engine timeout flakes, each confirmed
passing in isolation.
Co-authored-by: Isaac <no-reply@databricks.com>
Drop the `update` subtest (create/update/remove is already covered by `basic`) and the `orphaned` subtest (deleting a branch while keeping a schedule that references it is user error — it plans but fails at apply, which we don't need to pin in a golden). Co-authored-by: Isaac <no-reply@databricks.com>
DoCreate built the schedule resource name as `config.Branch + "/snapshot-schedule"`, which doubles the separator if a user writes `branch:` with a trailing slash. Route it through snapshotScheduleName, which trims trailing slashes first, and cover it with a unit test. Co-authored-by: Isaac <no-reply@databricks.com>
Add a `bundle plan` after the removal step in the basic acceptance test; it reports "0 to add, 0 to change, 0 to delete" (project and branch unchanged), confirming the disable settled cleanly and leaves no lingering drift. Co-authored-by: Isaac <no-reply@databricks.com>
…s-snapshot-schedules # Conflicts: # .nextchanges/dependency-updates/bump-sdk-0.177.0.md # bundle/terraform_dabs_map/generated.go # go.mod
Completes wiring for the postgres_snapshot_schedules resource so it satisfies the repo-wide "for all resources" guard tests: - Add MarshalJSON/UnmarshalJSON to resources.PostgresSnapshotSchedule so the outer wrapper's id/url/lifecycle/modified_status survive a JSON round-trip instead of being dropped by the embedded config marshaler (mirrors resources.PostgresBranch). - Pin the resource to Beta via launchStageOverrides and cover it in the launch-stage override test. - Populate PostgresSnapshotSchedules in the StateToBundle fixtures. - Mark it direct-engine only in the Terraform lifecycle test; the pinned provider has no resource that maps to a snapshot schedule. Regenerate the resource's out.test.toml snapshots to pick up the DMS EnvMatrix inherited from a parent test.toml. Co-authored-by: Isaac <no-reply@databricks.com>
Add the required bullet marker and trailing PR link so the fragment passes check-changelog. Co-authored-by: Isaac <no-reply@databricks.com>
The snapshot schedule has no web UI page of its own. Per agreement with
the Postgres team, point its URL at the parent branch's restore view:
lakebase/projects/{project_id}/branches/{branch_id}/restore, resolved
from the resource's branch. Covered in TestInitializeURLs and reflected
in the bind acceptance golden.
Co-authored-by: Isaac <no-reply@databricks.com>
Register a postgres_snapshot_schedules pattern (lakebase/%s/restore, %s = parent branch) and use workspaceurls.ResourceURL in InitializeURL instead of hand-assembling the path, matching every other resource. Co-authored-by: Isaac <no-reply@databricks.com>
Adding postgres_snapshot_schedules to workspaceurls broke tests that
assert the exact ResourceTypes() list (cmd/experimental open command and
its acceptance golden); update them.
Also derive the branch from the schedule's resolved ID rather than the
Branch field, which may hold an unresolved "${...}" reference at summary
time. This matches the other parent-referencing postgres resources and
correctly shows "(not deployed)" until the schedule has an ID.
Co-authored-by: Isaac <no-reply@databricks.com>
It now has a workspace URL, so TestBundleResourcePluralNamesResolveInWorkspaceURLs requires it to resolve rather than be empty. Co-authored-by: Isaac <no-reply@databricks.com>
…s-snapshot-schedules
Main's new TestMarshalerValueReceiver requires marshalling by value and by pointer to agree; match the sibling postgres configs. Co-authored-by: Isaac <no-reply@databricks.com>
The Lakebase web UI addresses resources by uid, not by the resource name in bundle state, so the name-based URL was wrong. Revert to no URL (back in the noURL allowlist) until a uid-based scheme is designed. Co-authored-by: Isaac <no-reply@databricks.com>
The backend rejects a snapshot schedule on any non-root branch ("not
allowed to snapshot non-root branch"), which surfaced only on cloud. Teach
the testserver the same rule, and point the acceptance and CRUD fixtures at
the project's implicit root "production" branch instead of a child branch.
Co-authored-by: Isaac <no-reply@databricks.com>
The schedule's resource name is its ID ("{branch}/snapshot-schedule");
return it from GetName so bundle summary shows it instead of a blank,
matching the SecretScope precedent (per review feedback).
Co-authored-by: Isaac <no-reply@databricks.com>
…s-snapshot-schedules # Conflicts: # bundle/config/resources.go # bundle/config/resources_test.go # bundle/direct/dresources/all_test.go
The Python codegen had no mapping for duration.Duration (the schedule's retention type), failing pydabs-codegen with a KeyError. Treat it as a str-serialized primitive, matching time.Time (PRIMITIVES + RENAMES + the test-case synthesizer), and regenerate the PyDABs module. Add the required acceptance/bundle/python support fixture and refresh the core public-API snapshot. Co-authored-by: Isaac <no-reply@databricks.com>
Resource types that never expose a workspace URL (the postgres_* resources, secret scopes, external locations, snapshots) rendered "URL: (not deployed)" in `bundle summary` even after a successful deploy, which was misleading. Add a type-level SupportsURL() to the ConfigResource interface (default true on BaseResource, overridden to false on the no-URL types) and render "(not supported)" for those, while keeping "(not deployed)" for URL-capable resources that are not deployed yet. Co-authored-by: Isaac <no-reply@databricks.com>
Co-authored-by: Isaac <no-reply@databricks.com>
…-url-not-supported # Conflicts: # acceptance/bundle/deployment/bind/postgres_snapshot_schedule/output.txt # bundle/config/resources/postgres_snapshot_schedule.go
Integration test reportCommit: 47c0de4
Top 6 slowest tests (at least 2 minutes):
|
bundle open and pipelines open told the user a no-URL resource might just need deploying ("has it been deployed?"), and pipelines deploy printed "View your <resource> here:" with a blank URL for such resources. Guard all three on SupportsURL() so the message is honest and the blank line is skipped.
Co-authored-by: Isaac <no-reply@databricks.com>
| // SupportsURL reports whether this resource type can have a workspace URL. | ||
| // It distinguishes an empty GetURL() that means "not deployed yet" from one | ||
| // that means the type never has a URL. | ||
| SupportsURL() bool |
There was a problem hiding this comment.
alternative: GetURL() (string, bool)
There was a problem hiding this comment.
slight preference for this, no chance of two methods going out of sync.
There was a problem hiding this comment.
yep, already refactored :-) also makes it clear for the caller of GetURL
| database1: | ||
| Name: | ||
| URL: (not deployed) | ||
| URL: (not supported) |
There was a problem hiding this comment.
This could be read a bit like resource is not supported (e.g. engine limitation), not that URL is not supported.
Maybe it should be "(unknown)" or "(not available)".
Actually, why show "URL:" row at all for such cases? Cannot we just omit it?
There was a problem hiding this comment.
I think any string has the potential to be misunderstood. +1 to skip the line for resources that don't support it
| return "" | ||
| } | ||
|
|
||
| func (b *PostgresSnapshotSchedule) SupportsURL() bool { |
There was a problem hiding this comment.
Is GetURL() returning "" not enough?
There was a problem hiding this comment.
GetURL() == "" currently means either not supported (InitializeURL is no-op) or not deployed yet (InitializeURL guarded on e.g. r.ID being empty)
Address review: rather than a separate SupportsURL() method, GetURL now returns (url, supported), following the (value, ok) idiom (cf. context.Context.Deadline). The default lives on BaseResource like GetLifecycle, so the 27 trivial 'return X.URL' overrides are dropped and only the 9 no-URL types override to return ("", false).
Also consolidate the changelog into a single generic entry covering all affected commands.
Co-authored-by: Isaac <no-reply@databricks.com>
Per review: instead of printing a placeholder like "(not supported)" (which reads ambiguously), the summary template now skips the URL line entirely when GetURL reports the type has no URL. URL-capable resources are unchanged, including the "(not deployed)" case. Co-authored-by: Isaac <no-reply@databricks.com>
| @@ -18,15 +18,12 @@ Resources: | |||
| Postgres branches: | |||
| main: | |||
| Name: | |||
There was a problem hiding this comment.
out of scope for this PR, but related theme: why do we show Name: without a value there? Is it because there is no Name or it not known yet?
There was a problem hiding this comment.
Taking a look as follow-up
|
description is out of date and overly verbose |
Integration test reportCommit: 162cc17
12 interesting tests: 6 flaky, 4 FAIL, 1 KNOWN, 1 SKIP
Top 50 slowest tests (at least 2 minutes):
|
) `resource.GetURL() == ""` did not distinguish between "not deployed yet" and "resource does not support URLs". Add a boolean return value to the method to allow callers (`bundle summary`, `bundle open`, `pipelines open` `pipelines deploy`) to adjust the messaging. --------- Co-authored-by: Isaac <no-reply@databricks.com>
## Release v1.17.0 ### Notable Changes * Bump the direct deployment state version to 3. Clients older than v1.8.0 will reject bundles deployed with this release. ([#6713](#6713)) ### CLI * Add an `INVALID_REFRESH_TOKEN` error code to `databricks auth token --output json` failures. ([#6684](#6684)) * Add experimental `databricks auth docker configure` to configure Docker credential helper access for Databricks Artifact Registry. ([#6700](#6700)) * Add experimental `databricks auth docker token` to generate Docker credentials for Databricks Artifact Registry. ([#6699](#6699)) * `databricks environments setup-local` now reports the `E_PROVISION_CONFLICT` error code instead of the generic `E_PROVISION` when `uv sync` fails to resolve a dependency conflict. ([#6666](#6666)) * Preserve SSH sessions across temporary tunnel disconnects, with bounded replay and backpressure for large transfers. ([#6650](#6650)) * Allow OAuth U2M logins to override the CLI client ID with `--client-id`, profile `client_id`, or `DATABRICKS_CLIENT_ID`. ([#6594](#6594)) ### Bundles * direct: Store a dashboard's `serialized_dashboard` in state as a content hash instead of its full contents. ([#6105](#6105)) * direct: Fix pipelines recreation when the whole `ingestion_definition` block is added or removed. ([#6589](#6589)) * `bundle plan`, `deploy`, and `destroy` no longer report removing `permissions`, `grants`, or secret scope ACLs from a bundle as a deletion, since it leaves the resource untouched. ([#6647](#6647)) * `bundle plan` and `deploy` no longer list or count a resource that was already deleted remotely as a deletion, matching `bundle destroy`; applying still cleans up its stale state entry. ([#6675](#6675)) * Fix `bundle run` failing with `expected an int, found a string` when an unrelated resource references another resource that is not deployed. `bundle run` now resolves `${resources.*}` references only within the resource being run. ([#6690](#6690)) * Add grants support for the AI Gateway `model_service`, `mcp_service`, and `model_provider_service` resources (direct engine). ([#6635](#6635)) * Add bundle support for the AI Gateway `mcp_service` resource (direct engine). ([#6633](#6633)) * Add bundle support for the AI Gateway `model_provider_service` resource (direct engine). ([#6634](#6634)) * Add bundle support for the AI Gateway `model_service` resource (direct engine). ([#6525](#6525)) * Prevent resource drift on catalogs if `storage_root` contained a trailing slash in the URL. ([#6622](#6622)) * Fixed a "lineage mismatch in state files" error that could occur after destroying a bundle and redeploying it from another machine. `bundle destroy` now removes the local state file so no stale lineage is left behind, and prunes the state directories it leaves empty (such as `.internal/` and `sync-snapshots/`). ([#6210](#6210), [#6685](#6685)) * direct: `bundle plan` no longer reports a permanent update on a cluster that uses a cluster policy: when the cluster spec sets `policy_id`, a field present in the remote but absent from the bundle config is not treated as drift. ([#6531](#6531)) * `bundle deploy` on the direct engine now reports each resource as soon as it is deployed, instead of listing them all after the deployment finishes. A deploy that fails part way through now reports the resources it did apply. ([#6361](#6361)) * Direct-engine bundles no longer flag phantom drift on server-populated nested fields under reused config types (e.g. `external_locations` file-event-queue resource IDs, `database_instances` parent-instance refs, `apps` git credential ID). ([#6618](#6618)) * `databricks bundle generate app` now reproduces a git-backed app's `git_repository` and `git_source` configuration instead of emitting a workspace `source_code_path`, so generating from a Git-deployed app no longer silently converts it to workspace source. ([#6656](#6656)) * Improved configuration load time for bundles with many included files. ([#6195](#6195)) * `bundle destroy` no longer deletes triggered job runs, leaving them untouched on the backend. ([#6672](#6672)) * direct: resources.job\_runs: new lifecycle.triggers.on\_file\_change setting to restart the run when monitored files change. Can be set to a series of paths or globs. ([#6309](#6309)) * Bundle summary now shows a name for Postgres branches, endpoints, databases, and roles instead of a blank Name field. ([#6663](#6663)) * Added PyDABs (Python) support for cluster policies, dashboards, and Genie spaces. ([#6585](#6585)) * CLI commands no longer imply that a resource whose type has no workspace URL is merely not deployed yet. ([#6583](#6583)) * Capture the implicit dependency a vector search index has on a catalog or schema defined in the same bundle, so the catalog and schema are deployed first. ([#6655](#6655)) ### Dependency Updates * Bump dependencies with known vulnerabilities. ([#6695](#6695)) * Bump `github.com/databricks/databricks-sdk-go` from v0.177.0 to v0.178.0. ([#6673](#6673)) * Bump Terraform provider from v1.131.0 to v1.132.0. ([#6671](#6671))
resource.GetURL() == ""did not distinguish between "not deployed yet" and "resource does not support URLs".Add a boolean return value to the method to allow callers (
bundle summary,bundle open,pipelines openpipelines deploy) to adjust the messaging.