Fix bundle.deployment.lock.force being ignored - #6188
Merged
Conversation
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
andrewnester
approved these changes
Aug 6, 2026
Collaborator
Integration test reportCommit: 0e99688
8 interesting tests: 4 RECOVERED, 4 SKIP
Top 3 slowest tests (at least 2 minutes):
|
janniklasrose
enabled auto-merge
August 6, 2026 12:00
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)).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Changes
bundle.deployment.lock.forcehad no effect. Setting it indatabricks.ymldid not let a deploy break through a stale deployment lock — only the--force-lockflag 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 valuefalseoverwrote aforce: truefrom config:Both halves of the lock override are then lost:
libs/locker/locker.goonly addsfiler.OverwriteIfExistswhen forced, andassertLockHeldchecks theIsForcedfield. 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-lockwas the one that wasn't. Incmd/apps/deploy_bundle.gothe 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" — whichforceLockdid 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 usesFlags().Lookuprather thancmd.Flag(...).ChangedbecauseBindResourceis also reached frombundle generate, which never registers the flag and would panic on a nil return.cmd/apps/import.gois intentionally unchanged: it forcesfalseon a synthetic command with no flags.Scope note on
bundle.forceb.Config.Bundle.Forceis clobbered the same way but is not a bug, so it is deliberately left alone. It is taggedbundle:"readonly"andlibs/jsonschema/from_type.gostrips readonly fields from the generated schema. Confirmed against the generated schema:bundle.forceis not a settable field, so a flag default cannot overwrite anything a user could have set. The public reference docs likewise documentdeployment.lock.forcebut have no entry forbundle.force. Every otherb.Config.*assignment in the flag paths (cluster_id,fail_on_active_runs) is already.Changed-guarded;AutoApprove,Select, andSkipLocalFileValidationlive on theBundlestruct rather thanConfigand are not YAML-settable.lock.forcewas the only field affected.Out of scope but worth noting:
readonlyonly strips a field from the schema, sobundle.force: truein YAML is still accepted by the loader and shows up inbundle validate -o jsonwith 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 onlyforce: trueindatabricks.yml— following the existingacceptance/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:
With the fix the lock is overridden and the deploy completes.
cmd/apps/deploy_bundle_test.gohad an assertion pinning the old behavior ("force, forceLock, autoApprove always apply"), now split into unset-flag and explicit-flag cases. The unset case pre-seedslock.force = truevia a newconfigurehook, since a zero-value bundle cannot detect a clobber. Also added a table-driven unit test for the helper incmd/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 checksclean.This pull request and its description were written by Isaac, an AI coding agent.