Skip to content

Fix bundle.deployment.lock.force being ignored - #6188

Merged
janniklasrose merged 2 commits into
mainfrom
janniklasrose/force-lock
Aug 6, 2026
Merged

Fix bundle.deployment.lock.force being ignored#6188
janniklasrose merged 2 commits into
mainfrom
janniklasrose/force-lock

Conversation

@janniklasrose

Copy link
Copy Markdown
Contributor

Changes

bundle.deployment.lock.force had no effect. Setting it in databricks.yml did not let a deploy break through a stale deployment lock — only the --force-lock flag worked.

The flag was assigned unconditionally inside InitFunc, which runs after the bundle configuration is loaded (cmd/bundle/utils/process.go:138). With the flag absent, its zero value false overwrote a force: true from config:

b.Config.Bundle.Force = force
b.Config.Bundle.Deployment.Lock.Force = forceLock   // always overwrites config

Both halves of the lock override are then lost: libs/locker/locker.go only adds filer.OverwriteIfExists when forced, and assertLockHeld checks the IsForced field. Neither gets set, so the write fails against the existing lock exactly as if nothing had been passed.

The neighbouring flags in the very same closure were already guarded (--cluster-id, --fail-on-active-runs); --force-lock was the one that wasn't. In cmd/apps/deploy_bundle.go the enclosing function's own doc comment already stated the intended contract — "Flags that override bundle YAML are only applied when explicitly set by the user" — which forceLock did not honor.

This is a user-visible silent-ignore: the field is documented in annotations.yml, appears in the public reference docs, and passes schema validation, so users get no warning that it does nothing.

Fix: route all six sites through a new utils.SetForceLock, which applies the flag only when explicitly passed. It uses Flags().Lookup rather than cmd.Flag(...).Changed because BindResource is also reached from bundle generate, which never registers the flag and would panic on a nil return.

cmd/apps/import.go is intentionally unchanged: it forces false on a synthetic command with no flags.

Scope note on bundle.force

b.Config.Bundle.Force is clobbered the same way but is not a bug, so it is deliberately left alone. It is tagged bundle:"readonly" and libs/jsonschema/from_type.go strips readonly fields from the generated schema. Confirmed against the generated schema:

Bundle: ['cluster_id', 'compute_id', 'databricks_cli_version', 'deployment', 'engine', 'git', 'name', 'uuid']
Lock:   ['enabled', 'force']

bundle.force is not a settable field, so a flag default cannot overwrite anything a user could have set. The public reference docs likewise document deployment.lock.force but have no entry for bundle.force. Every other b.Config.* assignment in the flag paths (cluster_id, fail_on_active_runs) is already .Changed-guarded; AutoApprove, Select, and SkipLocalFileValidation live on the Bundle struct rather than Config and are not YAML-settable. lock.force was the only field affected.

Out of scope but worth noting: readonly only strips a field from the schema, so bundle.force: true in YAML is still accepted by the loader and shows up in bundle validate -o json with no warning. That gap affects every readonly field and predates this change.

Tests

New acceptance test acceptance/bundle/deploy/force-lock-config/ seeds a real stale lock held by another user, then deploys with only force: true in databricks.yml — following the existing acceptance/pipelines/deploy/force-lock/ pattern rather than asserting on request shape.

Verified it fails before the fix and passes after. Against the unfixed code it reproduces the reported error:

Error: Failed to acquire deployment lock: deploy lock acquired by user-with-lock@databricks.com at [TIMESTAMP] +0000 UTC.
Another deployment may be in progress. Use --force-lock to override, but this may
conflict with the other deployment if it is still active

With the fix the lock is overridden and the deploy completes.

cmd/apps/deploy_bundle_test.go had an assertion pinning the old behavior ("force, forceLock, autoApprove always apply"), now split into unset-flag and explicit-flag cases. The unset case pre-seeds lock.force = true via a new configure hook, since a zero-value bundle cannot detect a clobber. Also added a table-driven unit test for the helper in cmd/bundle/utils/utils_test.go.

./cmd/... 2379 passed; bundle deploy/destroy, deployment, help, pipelines and apps acceptance suites 450 passed; ./task fmt, ./task lint-q, ./task checks clean.

This pull request and its description were written by Isaac, an AI coding agent.

The --force-lock flag was assigned unconditionally in InitFunc, which runs
after the bundle configuration is loaded. When the flag was absent its zero
value overwrote `force: true` from databricks.yml, so the config field had no
effect and a stale deployment lock could only be overridden with the flag.

Route the flag through utils.SetForceLock, which only applies it when the user
passed it explicitly. Neighbouring flags in the same closures (--cluster-id,
--fail-on-active-runs) were already guarded this way.

The helper looks the flag up rather than calling cmd.Flag(...).Changed
directly because BindResource is also reached from `bundle generate`, which
never registers the flag.

cmd/apps/import.go is left as-is: it forces false deliberately on a synthetic
command that has no flags.

The acceptance test seeds a real stale lock held by another user and deploys
with only `force: true` in databricks.yml. Against the unfixed code it
reproduces the reported "Use --force-lock to override" failure.

Note that `bundle.force` is deliberately not covered: it is tagged
bundle:"readonly" and stripped from the generated JSON schema, so a flag
default cannot clobber a value users can set.

Co-authored-by: Isaac
@eng-dev-ecosystem-bot

eng-dev-ecosystem-bot commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

Integration test report

Commit: 0e99688

Run: 31099632327

Env 💚​RECOVERED 🙈​SKIP ✅​pass 🙈​skip Time
💚​ aws linux 4 4 291 1111 5:14
💚​ aws windows 4 4 293 1109 4:39
💚​ azure linux 4 4 290 1111 5:59
💚​ azure windows 4 4 292 1109 5:50
💚​ gcp linux 1 5 291 1111 5:33
💚​ gcp windows 1 5 293 1109 5:53
8 interesting tests: 4 RECOVERED, 4 SKIP
Test Name aws linux aws windows azure linux azure windows gcp linux gcp windows
💚​ TestAccept 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R
🙈​ TestAccept/bundle/invariant/no_drift 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/vector_search_endpoints/drift/recreated_same_name 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/vector_search_indexes/recreate/embedding_dimension 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/ssh/connection 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
💚​ TestFetchRepositoryInfoAPI_FromRepo 💚​R 💚​R 💚​R 💚​R 🙈​S 🙈​S
💚​ TestFetchRepositoryInfoAPI_FromRepo/root 💚​R 💚​R 💚​R 💚​R
💚​ TestFetchRepositoryInfoAPI_FromRepo/subdir 💚​R 💚​R 💚​R 💚​R
Top 3 slowest tests (at least 2 minutes):
duration env testname
5:11 gcp windows TestAccept
3:50 azure windows TestAccept
3:18 aws windows TestAccept

@janniklasrose
janniklasrose enabled auto-merge August 6, 2026 12:00
@janniklasrose
janniklasrose added this pull request to the merge queue Aug 6, 2026
Merged via the queue into main with commit 3773988 Aug 6, 2026
26 checks passed
@janniklasrose
janniklasrose deleted the janniklasrose/force-lock branch August 6, 2026 12:38
deco-sdk-tagging Bot added a commit that referenced this pull request Aug 12, 2026
## Release v1.12.0

### CLI

 * `databricks aitools install` now supports Gemini CLI, installing Databricks agent skills into its skills directory.
 * `databricks aitools install` now supports Pi, installing Databricks agent skills into its skills directory.
 * A locally built CLI (`go build`, without release flags) now reports the next release version with a `-dev` prerelease, e.g. `1.12.0-dev+abcdef123456`, instead of `0.0.0-dev+abcdef123456`. The old string sorted below every published release even though a local build is newer than the latest release; the new one sorts above the latest release and below the release it will become, matching what goreleaser already produces for snapshot builds.
 * Added the `databricks environments setup-local` command, which provisions (or updates) a local Python environment matched to a Databricks compute target. It resolves the target to an environment key, fetches the pinned Python version, databricks-connect version, and dependency constraints published for that key, then provisions a matched `.venv` with uv.

### Bundles

 * Added a `cascade_on_destroy` field to the pipeline resource to control whether destroying a pipeline also deletes its datasets (MVs, STs, Views). When unset, the server default applies; set `cascade_on_destroy: false` to retain the datasets on destroy. Supported with the direct deployment engine ([#5846](#5846)).
 * Fix `bundle.deployment.lock.force` being ignored. The `--force-lock` flag's default value overwrote the value configured in `databricks.yml`, so setting the field had no effect and a stale deployment lock could only be overridden with the flag. ([#6188](#6188))
 * direct: experimental `job_runs` now sends a CLI-managed idempotency token on every run-now, so an SDK retry after a lost response returns the same run. Configured `idempotency_token` values are rejected.
 * direct: the experimental `job_runs` resource now waits for the triggered run to finish, so other resources can reference its outcome (e.g. `${resources.job_runs.nightly.state.result_state}`). A run that does not succeed fails the deploy, naming the failed task, and is run again on the next deploy. If a deploy is interrupted while waiting, the next one resumes waiting on the same run.
 * direct: Fixed model serving `telemetry_config` drift and applied planned telemetry updates. Unsupported endpoint types now fail when telemetry is applied; create may still succeed because it drops the field ([#6106](#6106)).
 * The `cli_version` field in the direct engine's deployment state (`resources.json`) now records the CLI version that last wrote the state. Previously it kept the version of the CLI that first created the state.
 * Add support for UC secrets resource ([#5861](#5861))

### Dependency Updates

 * Bump `github.com/databricks/databricks-sdk-go` from v0.166.0 to v0.169.0.
 * Bump Terraform provider from v1.124.0 to v1.126.0 ([#6250](#6250)).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants