Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
7e53b8d
structpath: add NewPattern with AnyKey/AnyIndex wildcards
denik Oct 15, 2026
8c3ec07
bundle: delete libs/dyn; configuration is typed structs with structva…
denik Oct 7, 2026
0ceef3e
structvar: map YAML locations in the YAML source; drop mappedSource
denik Oct 7, 2026
12fd6c3
Use NewStringKeysSlice for single key paths
denik Oct 7, 2026
676ff58
Build literal diagnostic paths with NewStringKeysSlice
denik Oct 7, 2026
a5f49f9
Restack fixes: structvar grammar for structpath's PureReferenceToPath…
denik Oct 7, 2026
e686b7c
Restore import block after restack
denik Oct 7, 2026
9267b74
Use structpath.NewPath for key/index paths
denik Oct 7, 2026
94db6d7
Build the target preset path in one NewPath call
denik Oct 8, 2026
21711ed
GetLocationsOf on the location tree
denik Oct 8, 2026
eea756f
Minimal import edits; drop unused diag import
denik Oct 8, 2026
ee4c21e
structvar: test the YAML decoder with the yamlloader fixtures
denik Oct 9, 2026
e0714e8
structvar: add the YAML test helpers
denik Oct 9, 2026
a10f6e5
Port the job environment_variables files pattern (#6985) to structpath
denik Oct 9, 2026
209b765
Fix codex review findings
denik Oct 9, 2026
1cc9581
Port the job environments project_environment pattern (#6983) to stru…
denik Oct 12, 2026
aefc7a0
Fix regressions recorded by the config edge-case tests
denik Oct 14, 2026
50ad6ef
Drop the embedded JobSettings literal flagged by embedlit
denik Oct 15, 2026
4cb25fc
Keep main's path-node location lookups; build app permission paths fr…
denik Oct 15, 2026
5a9acb9
config: Nearest/Exact location lookups by path node; build paths from…
denik Oct 15, 2026
22d765b
structvar: don't allocate per struct field when traversing views
denik Oct 16, 2026
877f35d
structvar: traverse views without closures, map lookups or rebuilding…
denik Oct 16, 2026
f544948
bundletest: per-component benchmarks that also run on the dyn impleme…
denik Oct 17, 2026
7f613d2
validate: generated typed walkers for required and enum fields
denik Oct 17, 2026
99a1a58
validate: required fields written in the source are set, even if zero
denik Oct 18, 2026
b955c4d
structvar: compare io.EOF with errors.Is
denik Oct 18, 2026
1e6bf34
walk: shared node type for generated configuration walkers
denik Oct 18, 2026
48bd848
Changelog fragment for #7098
denik Oct 18, 2026
f631626
paths: typed visitors instead of pattern traversal
denik Oct 18, 2026
4fc5b71
walk: generated string walker for references
denik Oct 18, 2026
94a20cd
paths: visit explicitly written empty path values
denik Oct 18, 2026
f712bc7
ApplyBundlePermissions: typed access to resource permissions
denik Oct 18, 2026
cbdc041
Fix review findings: presence rules of the typed walkers
denik Oct 18, 2026
c2f1b45
config: generated iterators over all resources, permissions and grants
denik Oct 18, 2026
5b1223b
config: keep main's GetLocationOf names; GetLocationOfExact for exact…
denik Oct 18, 2026
bf89fd1
Iterate resources, permissions, grants and states with the generated …
denik Oct 18, 2026
bdf63f6
Typed access in single-type and fixed-field mutators
denik Oct 18, 2026
31ccd74
Typed library iterators for library expansion, upload and duplicate c…
denik Oct 18, 2026
f74c6e8
Typed defaults and single node cluster validation; walk helpers shared
denik Oct 18, 2026
3d45513
PopulateLocations reads the locations tree and the typed resources
denik Oct 18, 2026
40099e5
python: resource keys and the experimental.python copy from typed config
denik Oct 18, 2026
c98f1bd
Fix lint: unused required helpers, perfsprint, gofmt, dupword
denik Oct 18, 2026
3394ba0
ResolveVariableReferences collects references with the generated stri…
denik Oct 18, 2026
5f6dbd8
ConfigureClusterPolicyDefinition: one helper called per field
denik Oct 18, 2026
543d363
Typed access for the remaining reads of known fields
denik Oct 18, 2026
bdc2693
Fix review findings: python copy refs, grants iterator, built paths
denik Oct 18, 2026
771fb4d
Presence comes from ForceSendFields only, never from locations
denik Oct 18, 2026
6f6b02f
Presence follow-ups: FSF for strings, refs below structs, review fixes
denik Oct 18, 2026
4b55f13
structvar: decode YAML mappings without an index map and key location…
denik Oct 18, 2026
f53e1d4
References under removed values are not returned; libraries: null errors
denik Oct 18, 2026
575fea0
References: reachability by the view's presence rules
denik Oct 18, 2026
b82cc14
References need the view to show them; Set adds no location marker
denik Oct 18, 2026
d8e06ce
Strings walk stops at pure references; clean the default file path
denik Oct 18, 2026
e83880d
Strings walk: stop at a referenced struct node; scoped reference trees
denik Oct 19, 2026
1e26d24
paths: visit takes named arguments
denik Oct 19, 2026
d6035e3
Restore GetLocation/GetLocations (path string) and their callers
denik Oct 19, 2026
e37954d
Merge remote-tracking branch 'origin/main' into denik/typed-config-wa…
denik Oct 19, 2026
891dcf7
paths: pass the path as a value, not a closure
denik Oct 19, 2026
ab16324
Update the validate edge-case tests for the typed configuration
denik Oct 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
10 changes: 8 additions & 2 deletions .agents/rules/auto-generated-files.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ globs:
- "internal/genkit/tagging.py"
- "internal/mocks/**/*.go"
- "bundle/direct/dresources/configs/*.generated.yml"
- "bundle/internal/validation/generated/*.go"
- "bundle/config/validate/*_walk.go"
- "bundle/config/walk/*_walk.go"
- "bundle/config/mutator/resourcemutator/defaults_walk.go"
- "bundle/config/resources_iterate.go"
- "bundle/schema/jsonschema.json"
- "python/databricks/bundles/version.py"
- "python/databricks/bundles/*/__init__.py"
Expand All @@ -33,7 +36,10 @@ paths:
- "internal/genkit/tagging.py"
- "internal/mocks/**/*.go"
- "bundle/direct/dresources/configs/*.generated.yml"
- "bundle/internal/validation/generated/*.go"
- "bundle/config/validate/*_walk.go"
- "bundle/config/walk/*_walk.go"
- "bundle/config/mutator/resourcemutator/defaults_walk.go"
- "bundle/config/resources_iterate.go"
- "bundle/schema/jsonschema.json"
- "python/databricks/bundles/version.py"
- "python/databricks/bundles/*/__init__.py"
Expand Down
4 changes: 2 additions & 2 deletions .agents/rules/style-guide-go.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ return fieldPaths

### Encoding

**RULE: When mutating an API response by round-tripping JSON, decode with `json.Decoder` + `UseNumber()`.** The naive `json.Marshal` → `map[string]any` → `Marshal` path corrupts any int64 larger than 2^53 (it degrades to a float64 mantissa — e.g. a real `spark_context_id`) and alphabetizes object keys. `libs/dyn/jsonloader` preserves key order but also lacks `UseNumber`, so it shares the int64 hazard.
**RULE: When mutating an API response by round-tripping JSON, decode with `json.Decoder` + `UseNumber()`.** The naive `json.Marshal` → `map[string]any` → `Marshal` path corrupts any int64 larger than 2^53 (it degrades to a float64 mantissa — e.g. a real `spark_context_id`) and alphabetizes object keys.

**RULE: Be careful with `encoding/csv` `Writer.UseCRLF = true`.** It rewrites both record terminators AND embedded newlines inside quoted fields to `\r\n`, so tests for quoted multiline fields must expect `\r\n`, not just the line endings between rows.

Expand Down Expand Up @@ -191,7 +191,7 @@ func NewService(deps ServiceDeps) *Service { ... }

### Configuration patterns

- Bundle config uses `dyn.Value` for dynamic typing
- Bundle config is typed structs; `libs/structs/structvar` carries `${...}` references and source locations
- Config loading supports includes, variable interpolation, and target overrides
- Schema generation is automated from Go struct tags

Expand Down
2 changes: 1 addition & 1 deletion .agents/skills/bump-sdk/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ allowed-tools: Read, Edit, Write, Bash, Glob, Grep, WebFetch, AskUserQuestion

The SDK version lives in `go.mod` (`github.com/databricks/databricks-sdk-go`) and the pinned spec SHA lives in `.codegen/_openapi_sha`.
These two move as a pair; everything else in this skill is regenerated from them or is fallout you fix by hand.
Do not hand-edit generated files (`.codegen/cli.json`, `cmd/workspace/*`, `cmd/account/*`, `bundle/schema/jsonschema.json`, `bundle/internal/validation/generated/*`, `bundle/direct/dresources/configs/*.generated.yml`, `python/databricks/bundles/**`); regenerate them.
Do not hand-edit generated files (`.codegen/cli.json`, `cmd/workspace/*`, `cmd/account/*`, `bundle/schema/jsonschema.json`, `bundle/config/validate/*_walk.go`, `bundle/config/walk/*_walk.go`, `bundle/direct/dresources/configs/*.generated.yml`, `python/databricks/bundles/**`); regenerate them.

The Python tasks (`pydabs-*`, and the `pydabs-codegen` step inside `generate-check`) all run through `uv`. If one fails because `uv` is missing or because the host's `python3` is too old (e.g. 3.9), install `uv` (`curl -LsSf https://astral.sh/uv/install.sh | sh`) rather than touching the system Python: `uv run` provisions the interpreter each package pins (`>=3.10`, and `==3.13.*` under `python/codegen/`) and downloads it if needed. Do not chase the system Python version.

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/python_push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ jobs:
acceptance/bundle/python/ \
go.mod \
go.sum \
libs/dyn/dynvar/testdata/reference_vectors.json \
libs/structs/structvar/testdata/reference_vectors.json \
python/ \
tools/task/ \
)
Expand Down
1 change: 1 addition & 0 deletions .nextchanges/bundles/7098-presence.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* `bundle validate` no longer treats a written zero value in a field that cannot record it (no `ForceSendFields`, e.g. `job_id: 0` in `run_job_task`) or an empty mapping (e.g. `presets: {}`) as set, and does not show the pipeline `development` deprecation warning for `development: true` under `mode: development`. ([#7098](https://github.com/databricks/cli/pull/7098))
1 change: 1 addition & 0 deletions .nextchanges/bundles/7098.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* Speed up bundle commands on large bundles: configuration is kept as typed structs instead of being converted to and from a dynamic tree (`bundle validate` and `bundle plan` with 1000 jobs are about 10x faster and use about 3.5x less memory). ([#7098](https://github.com/databricks/cli/pull/7098))
4 changes: 2 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ This is the Databricks CLI, a command-line interface for interacting with Databr

**RULE: Keep each PR focused on one change.** If you notice an unrelated cleanup, bug fix, or refactor while making your primary change, leave it alone or put it in a separate PR. Reviewers consistently ask to split mixed PRs, especially when a dependency bump or schema diff rides along with a feature change.

**RULE: Before adding a new helper, search the codebase for an existing one.** Common homes: `libs/` (shared utilities), `libs/databrickscfg/` (config), `libs/git/`, `libs/filer/`, `libs/cmdio/` (CLI I/O, spinners, prompts), `libs/env/` (env vars), `libs/testserver/`, `libs/structpath/` and `libs/dyn/` (path / dynamic values), `acceptance/bin/` (acceptance test helpers), `internal/mocks/` (generated mocks). A function that duplicates an existing name and signature in the same package is a compile error waiting to happen; grep before you name.
**RULE: Before adding a new helper, search the codebase for an existing one.** Common homes: `libs/` (shared utilities), `libs/databrickscfg/` (config), `libs/git/`, `libs/filer/`, `libs/cmdio/` (CLI I/O, spinners, prompts), `libs/env/` (env vars), `libs/testserver/`, `libs/structs/structpath/` and `libs/structs/structvar/` (paths / typed config values), `acceptance/bin/` (acceptance test helpers), `internal/mocks/` (generated mocks). A function that duplicates an existing name and signature in the same package is a compile error waiting to happen; grep before you name.

# Development Commands

Expand Down Expand Up @@ -73,7 +73,7 @@ GIT_EDITOR=true GIT_SEQUENCE_EDITOR=true VISUAL=true GIT_PAGER=cat git rebase or
- `bundle/phases/` - High-level deployment phases

**libs/** - Shared libraries and utilities
- `libs/dyn/` - Dynamic configuration value manipulation
- `libs/structs/structvar/` - Typed configuration values with references and locations
- `libs/filer/` - File system abstraction (local, DBFS, workspace)
- `libs/auth/` - Databricks authentication handling
- `libs/sync/` - File synchronization between local and remote
Expand Down
9 changes: 6 additions & 3 deletions Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -973,17 +973,20 @@ tasks:
- "go run ./bundle/internal/schema ./bundle/internal/schema ./bundle/schema/jsonschema.json .codegen/cli.json"

generate-validation:
desc: Generate enum and required field validation code
desc: Generate the walkers of the enum and required field validators
sources:
- "**/*.go"
- exclude: "**/*_test.go"
- go.mod
- go.sum
- "{{.EMBED_SOURCES}}"
generates:
- bundle/internal/validation/generated/**/*.go
- bundle/config/validate/*_walk.go
- bundle/config/walk/*_walk.go
- bundle/config/mutator/resourcemutator/defaults_walk.go
- bundle/config/resources_iterate.go
cmds:
- "sh -c 'go run ./bundle/internal/validation/. && gofmt -w -s ./bundle/internal/validation/generated'"
- "go run ./bundle/internal/validation/."

generate-direct:
desc: Generate direct engine config (apitypes + resources)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
bundle:
name: test-bundle
cluster_id: existing-cluster

variables:
cluster:
type: complex
default:
spark_version: 15.4.x-scala2.12
node_type_id: i3.xlarge
num_workers: 1

resources:
clusters:
source:
cluster_name: source
spark_version: 15.4.x-scala2.12
node_type_id: i3.xlarge
num_workers: 2
jobs:
job:
name: job
tasks:
- task_key: task
notebook_task:
notebook_path: /Workspace/notebook
# Replaced by bundle.cluster_id: the reference below new_cluster must go too.
new_cluster:
spark_version: 15.4.x-scala2.12
node_type_id: i3.xlarge
num_workers: ${resources.clusters.source.num_workers}
- task_key: task_var
notebook_task:
notebook_path: /Workspace/notebook
# A reference at new_cluster must not bring it back either.
new_cluster: ${var.cluster}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Cloud = false
EnvMatrix.DMS = ["", "true"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@

>>> [CLI] bundle validate -o json
[
{
"task_key": "task",
"existing_cluster_id": "existing-cluster",
"new_cluster": null
},
{
"task_key": "task_var",
"existing_cluster_id": "existing-cluster",
"new_cluster": null
}
]

>>> [CLI] bundle deploy
Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-bundle/default/files...
Created clusters.source
Created jobs.job
Files: 1 uploaded, 0 deleted
Resources: 2 created, 0 changed, 0 deleted, 0 unchanged
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
trace $CLI bundle validate -o json | jq '[.resources.jobs.job.tasks[] | {task_key, existing_cluster_id, new_cluster}]'
trace $CLI bundle deploy
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
bundle:
name: test-bundle

resources:
quality_monitors:
src:
table_name: main.default.src
assets_dir: /Workspace/monitors/src
output_schema_name: main.default
inference_log:
granularities: [1 day]
model_id_col: model_id
prediction_col: prediction
problem_type: PROBLEM_TYPE_CLASSIFICATION
timestamp_col: timestamp
schedule:
quartz_cron_expression: "0 0 12 * * ?"
timezone_id: UTC
dst:
table_name: main.default.dst
assets_dir: /Workspace/monitors/dst
output_schema_name: main.default
inference_log:
granularities: [1 day]
model_id_col: model_id
prediction_col: prediction
problem_type: PROBLEM_TYPE_CLASSIFICATION
timestamp_col: timestamp
# Forced null: the target override replaces it with a reference.
schedule: null

targets:
dev:
presets:
trigger_pause_status: PAUSED
resources:
quality_monitors:
dst:
schedule: ${resources.quality_monitors.src.schedule}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Cloud = false
EnvMatrix.DMS = ["", "true"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@

>>> [CLI] bundle deploy
Warning: required field "quartz_cron_expression" is not set
at resources.quality_monitors.dst.schedule
in databricks.yml:39:21
databricks.yml:30:17

Warning: required field "timezone_id" is not set
at resources.quality_monitors.dst.schedule
in databricks.yml:39:21
databricks.yml:30:17

Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-bundle/dev/files...
Created quality_monitors.dst
Created quality_monitors.src
Files: 1 uploaded, 0 deleted
Resources: 2 created, 0 changed, 0 deleted, 0 unchanged

>>> print_requests.py //tables/main.default.dst/monitor
{
"schedule": null
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
trace $CLI bundle deploy
trace print_requests.py //tables/main.default.dst/monitor | jq '{schedule: .body.schedule}'
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
RecordRequests = true
Original file line number Diff line number Diff line change
@@ -1,22 +1,14 @@

>>> uv run [UV_ARGS] -q [CLI] bundle validate
Warning: The "development" property of pipelines is deprecated. Use "mode: development" in your databricks.yml instead. See https://docs.databricks.com/dev-tools/bundles/deployment-modes.
at resources.pipelines.with_development.development
in resources.py:7:1

Name: my_project
Target: dev
Workspace:
User: [USERNAME]
Path: /Workspace/Users/[USERNAME]/.bundle/my_project/dev

Found 1 warning
Validation OK!

>>> uv run [UV_ARGS] -q [CLI] bundle validate --output json
Warning: The "development" property of pipelines is deprecated. Use "mode: development" in your databricks.yml instead. See https://docs.databricks.com/dev-tools/bundles/deployment-modes.
at resources.pipelines.with_development.development
in resources.py:7:1

{
"with_development": true,
"without_development": true
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
bundle:
name: test-bundle

presets:
tags:
owner: ${resources.jobs.j.id}

resources:
schemas:
s:
name: s
catalog_name: main
properties: {owner: fixed}
jobs:
j:
name: j
# A whole-map reference: the preset's tags added to the typed map stay hidden.
tags: ${resources.schemas.s.properties}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Cloud = false
EnvMatrix.DMS = ["", "true"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

>>> [CLI] bundle plan
create jobs.j
create schemas.s

Plan: 2 to add, 0 to change, 0 to delete, 0 unchanged
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
trace $CLI bundle plan
2 changes: 1 addition & 1 deletion acceptance/bundle/summary/modified_status/output.txt
Original file line number Diff line number Diff line change
Expand Up @@ -200,4 +200,4 @@ All files and directories at the following location will be deleted: /Workspace/
Destroy: 4 deleted

>>> [CLI] bundle summary -o json
{}
null
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
>>> [CLI] bundle validate
Warning: invalid value "INVALID" for enum field. Valid values are [CAN_MANAGE CAN_MANAGE_RUN CAN_VIEW IS_OWNER]
at resources.apps.app.resources[0].job.permission
in databricks.yml:13:25
in databricks.yml:17:25

Name: test-bundle
Target: default
Expand All @@ -15,7 +15,7 @@ Found 1 warning
>>> [CLI] bundle validate -o json
Warning: invalid value "INVALID" for enum field. Valid values are [CAN_MANAGE CAN_MANAGE_RUN CAN_VIEW IS_OWNER]
at resources.apps.app.resources[0].job.permission
in databricks.yml:13:25
in databricks.yml:17:25

[
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# A diagnostic on a field of a duplicated app resource entry points at the first entry when the duplicate's value is the same.
# A diagnostic on a field of a duplicated app resource entry points at the entry that is kept (the later one).
errcode trace $CLI bundle validate

# The entries are merged by name, the later one wins.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@

>>> [CLI] bundle validate -o json
{
"presets": {},
"presets": {
"artifacts_dynamic_version": true,
"jobs_max_concurrent_runs": 7,
"name_prefix": "base-"
},
"job": {
"name": "job",
"max_concurrent_runs": 1
"name": "base-job",
"max_concurrent_runs": 7
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Badness = "An include cannot clear a preset with \"\", 0 or false: the base value stays (a written zero is not recorded without ForceSendFields)."
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@

>>> [CLI] bundle validate
Warning: unknown field: unexpected_after_failure
at bundle
in b.yml:2:3

Error: cannot merge map with string

Name: test-bundle

Found 1 error
Found 1 error and 1 warning

Exit code: 1
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# Includes after one that fails to merge do not report their diagnostics.
# Includes after one that fails to merge still report their diagnostics.
errcode trace $CLI bundle validate
Original file line number Diff line number Diff line change
@@ -1 +1 @@
Badness = "The merge error has no location or path, and diagnostics of includes loaded after the failed merge (the unknown field in b.yml) are not reported, although they do not depend on the merge."
Badness = "The merge error has no location or path."
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@

>>> [CLI] bundle validate
Error: expected a map at "resources", found nil

Name: test-bundle
Target: default
Workspace:
User: [USERNAME]
Path: /Workspace/Users/[USERNAME]/.bundle/test-bundle/default

Found 1 error

Exit code: 1
Validation OK!
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# resources: null is rejected.
# resources: null is accepted.
errcode trace $CLI bundle validate

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ Warning: expected string, found map
in databricks.yml:15:23

{
"bad.key[0]": "",
"good": "ok"
}
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# A map value whose reference resolves to the wrong type is dropped, with a warning at its path.
# A map value whose reference resolves to the wrong type becomes an empty string, with a warning at its path.
trace $CLI bundle validate -o json | jq .resources.jobs.j.tags
Loading
Loading