Skip to content

direct: ignore remote-only changes on name-based ID fields#5599

Open
denik wants to merge 11 commits into
mainfrom
denik/named-id-fields
Open

direct: ignore remote-only changes on name-based ID fields#5599
denik wants to merge 11 commits into
mainfrom
denik/named-id-fields

Conversation

@denik

@denik denik commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

In #5531 we fixed spurious recreation of schemas/volumes due to backend lowercasing fields that are part of the id/name. This was fixed by making comparison for those fields case-insensitive.

This is more general fix for all resources that have ID fields configured in bundle config based on the following: if we can fetch the resource by ID, then even if fields come back changed, we should not recreate, because change can only be attributed to normalization, not replacement.

@github-actions

github-actions Bot commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

Approval status: pending

/acceptance/bundle/ - needs approval

5 files changed
Suggested: @pietern
Also eligible: @janniklasrose, @andrewnester, @shreyas-goenka, @anton-107, @lennartkats-db

/bundle/ - needs approval

9 files changed
Suggested: @pietern
Also eligible: @janniklasrose, @andrewnester, @shreyas-goenka, @anton-107, @lennartkats-db

General files (require maintainer)

Files: NEXT_CHANGELOG.md
Based on git history:

  • @pietern -- recent work in bundle/direct/dresources/, bundle/direct/, ./

Any maintainer (@andrewnester, @anton-107, @pietern, @shreyas-goenka, @simonfaltum, @renaudhartert-db) can approve all areas.
See OWNERS for ownership rules.

@denik denik force-pushed the denik/named-id-fields branch from de92903 to 380841e Compare June 14, 2026 22:26
@denik denik temporarily deployed to test-trigger-is June 14, 2026 22:26 — with GitHub Actions Inactive
@denik denik temporarily deployed to test-trigger-is June 14, 2026 22:26 — with GitHub Actions Inactive
@denik denik temporarily deployed to test-trigger-is June 14, 2026 22:50 — with GitHub Actions Inactive
@denik denik temporarily deployed to test-trigger-is June 14, 2026 22:50 — with GitHub Actions Inactive
@eng-dev-ecosystem-bot

eng-dev-ecosystem-bot commented Jun 14, 2026

Copy link
Copy Markdown
Collaborator

Integration test report

Commit: 66684c6

Run: 27567841723

Env 🟨​KNOWN 💚​RECOVERED 🙈​SKIP ✅​pass 🙈​skip Time
🟨​ aws linux 7 15 264 981 6:37
🟨​ aws windows 7 15 266 979 11:34
💚​ aws-ucws linux 7 15 360 895 6:36
💚​ aws-ucws windows 7 15 362 893 8:12
💚​ azure linux 1 17 267 979 6:06
💚​ azure windows 1 17 269 977 8:46
💚​ azure-ucws linux 1 17 365 891 6:52
💚​ azure-ucws windows 1 17 367 889 9:24
💚​ gcp linux 1 17 263 982 7:55
💚​ gcp windows 1 17 265 980 7:46
22 interesting tests: 15 SKIP, 7 KNOWN
Test Name aws linux aws windows aws-ucws linux aws-ucws windows azure linux azure windows azure-ucws linux azure-ucws windows gcp linux gcp windows
🟨​ TestAccept 🟨​K 🟨​K 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R
🙈​ TestAccept/bundle/invariant/no_drift 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/permissions 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🟨​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/with_permissions 🟨​K 🟨​K 💚​R 💚​R 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🟨​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/with_permissions/DATABRICKS_BUNDLE_ENGINE=direct 🟨​K 🟨​K 💚​R 💚​R
🟨​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/with_permissions/DATABRICKS_BUNDLE_ENGINE=terraform 🟨​K 🟨​K 💚​R 💚​R
🟨​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/without_permissions 🟨​K 🟨​K 💚​R 💚​R 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🟨​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/without_permissions/DATABRICKS_BUNDLE_ENGINE=direct 🟨​K 🟨​K 💚​R 💚​R
🟨​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/without_permissions/DATABRICKS_BUNDLE_ENGINE=terraform 🟨​K 🟨​K 💚​R 💚​R
🙈​ TestAccept/bundle/resources/postgres_branches/basic 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/postgres_branches/recreate 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/postgres_branches/replace_existing 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/postgres_branches/update_protected 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/postgres_branches/without_branch_id 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/postgres_endpoints/basic 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/postgres_endpoints/recreate 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/postgres_projects/update_display_name 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/synced_database_tables/basic 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/vector_search_endpoints/drift/recreated_same_name 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/vector_search_indexes/basic 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/vector_search_indexes/grants/select 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/ssh/connection 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
Top 24 slowest tests (at least 2 minutes):
duration env testname
6:29 gcp linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
4:49 gcp linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
4:21 gcp windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
4:14 gcp windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
3:27 azure windows TestAccept
3:16 azure linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
3:13 azure-ucws windows TestAccept
3:10 azure windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
3:09 azure-ucws linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
3:09 gcp windows TestAccept
3:06 azure windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
3:04 aws windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
3:02 aws-ucws windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
2:56 azure-ucws windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
2:53 azure-ucws windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
2:50 aws linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
2:49 azure-ucws linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
2:49 aws-ucws windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
2:37 aws windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
2:35 azure linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
2:34 aws-ucws linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
2:33 aws-ucws windows TestAccept
2:31 aws linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
2:27 aws-ucws linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform

@denik denik force-pushed the denik/named-id-fields branch from 4f7b7ab to b99237b Compare June 15, 2026 13:43
@denik denik temporarily deployed to test-trigger-is June 15, 2026 13:43 — with GitHub Actions Inactive
@denik denik temporarily deployed to test-trigger-is June 15, 2026 13:43 — with GitHub Actions Inactive
denik added 6 commits June 15, 2026 09:34
Resources fetched by a name-based ID (schemas, volumes, registered models,
apps, secret scopes, postgres resources, etc.) cannot exhibit real remote
drift on the fields composing that ID: a successful get-by-ID means a
differing remote value can only be backend normalization (e.g. UC
lowercasing), since an out-of-band rename would 404 and is already handled
as resource-gone. Reacting with recreate or rename is therefore never
correct for remote-only diffs on these fields.

Encode this declaratively:
- named_id_fields: ID components; local changes recreate, remote-only
  diffs are skipped. Replaces their recreate_on_changes entries.
- update_id_on_local_changes (renamed from update_id_on_changes): same
  skip for remote-only diffs; local changes still rename via DoUpdateWithID.

normalize_case is unchanged: it covers local case-only edits, which the
get-by-ID argument does not, and which would otherwise recreate a resource
UC considers unchanged.

Co-authored-by: Isaac
Revert the cosmetic update_id_on_changes -> update_id_on_local_changes rename
to minimize the diff (catalogs, external_locations, volumes,
secret_scopes.permissions keep their existing key). The semantics shift is
explained in comments instead: update_id_on_changes now only governs local
changes, since remote-only diffs on these ID fields are skipped by
shouldSkipIDField.

Co-authored-by: Isaac
The fields hold a user-provided name that forms the resource ID (as opposed to
a server-generated id); "provided" makes clear why a remote-only difference can
only be backend normalization. Source-only rename; reason strings (id_field)
are unchanged.

Also regenerate volumes/uppercase-name/out.deploy.direct.txt, whose id_field
reasons were reverted to the stale uc_case by the rebase auto-merge.

Co-authored-by: Isaac
provided_id_fields already skips the remote-only diffs that normalize_case was
added for (the no-op-redeploy bug), so normalize_case only guarded a local
case-only edit — an untested corner, gated by the destructive-action prompt for
schemas/volumes, and inconsistent with the other provided_id_fields resources
that never had it. Remove the field, its shouldSkipNormalized branch, and the
schemas/volumes yaml blocks. normalize_slash is unaffected.

Also regenerate model_serving_endpoints/basic/out.second-plan.direct.json
(immutable -> id_field), a cloud-only golden carrying the reason change from
moving name to provided_id_fields; local task test skips it, so CI integration
caught it.

Co-authored-by: Isaac
The method now also covers provided_id_fields (both categories recreate on a
local change), so the recreate_on_changes-specific name was inaccurate.

Co-authored-by: Isaac
The provided_id_fields / update_id_on_changes logic was split across
shouldSkipIDField (remote-only -> skip) and shouldUpdateOrRecreate (local ->
recreate/rename), so correctness depended on the first running before the second
in the ladder. Fold both into classifyIDField, which decides skip vs
recreate/UpdateWithID in one place from Old==New. The leftover
shouldUpdateOrRecreate then only matched recreate_on_changes, so inline it as a
direct findMatchingRule call (cfg is never nil here). Pure refactor; no behavior
or golden changes.

Co-authored-by: Isaac
@denik denik force-pushed the denik/named-id-fields branch from f99e1b4 to 042a58e Compare June 15, 2026 16:38
@denik denik temporarily deployed to test-trigger-is June 15, 2026 16:38 — with GitHub Actions Inactive
@denik denik temporarily deployed to test-trigger-is June 15, 2026 16:38 — with GitHub Actions Inactive
@denik denik temporarily deployed to test-trigger-is June 15, 2026 16:46 — with GitHub Actions Inactive
@denik denik temporarily deployed to test-trigger-is June 15, 2026 16:46 — with GitHub Actions Inactive
recreate_on_changes, provided_id_fields, and update_id_on_changes each decide a
field's action, and classifyIDField runs before recreate_on_changes in the
ladder, so a field in more than one would have dead entries and the categories
disagree on remote-only diffs. Add a test that a field appears in at most one.

Co-authored-by: Isaac
@denik denik temporarily deployed to test-trigger-is June 15, 2026 16:52 — with GitHub Actions Inactive
@denik denik temporarily deployed to test-trigger-is June 15, 2026 16:52 — with GitHub Actions Inactive
Pairs with provided_id_fields: both compose the resource's user-provided ID and
are handled by classifyIDField (remote-only diffs skipped), differing only in the
local-change action — provided_id_fields recreates, updatable_id_fields renames
via UpdateWithID. The *_id_fields naming makes the family explicit and is more
accurate than "update_id_on_changes", which post-refactor also governs the
remote-only skip. Source-only; the per-field reason (id_changes) is unchanged so
no golden churn.

Co-authored-by: Isaac
@denik denik temporarily deployed to test-trigger-is June 15, 2026 16:55 — with GitHub Actions Inactive
@denik denik temporarily deployed to test-trigger-is June 15, 2026 16:55 — with GitHub Actions Inactive
@denik denik requested review from janniklasrose and pietern June 15, 2026 17:44
Co-authored-by: Isaac
@denik denik temporarily deployed to test-trigger-is June 15, 2026 18:10 — with GitHub Actions Inactive
@denik denik temporarily deployed to test-trigger-is June 15, 2026 18:10 — with GitHub Actions Inactive
Co-authored-by: Isaac
@denik denik temporarily deployed to test-trigger-is June 15, 2026 18:33 — with GitHub Actions Inactive
@denik denik temporarily deployed to test-trigger-is June 15, 2026 18:33 — with GitHub Actions Inactive
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.

2 participants