Skip to content

Commit f92dc1a

Browse files
authored
Merge branch 'main' into ssh-connect-budget-policy
2 parents 4f79291 + cb73bba commit f92dc1a

321 files changed

Lines changed: 7819 additions & 1128 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/check.yml

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,17 +40,14 @@ jobs:
4040
with:
4141
version: "0.8.9"
4242

43-
- name: Run Go lint checks (does not include formatting checks)
43+
- name: Run Go and Python lint checks (does not include formatting checks)
44+
# `task lint` runs golangci-lint and `ruff check` (lint-python). ruff is
45+
# provided by uvx, installed above; formatting is checked by `task fmt` below.
4446
run: go tool -modfile=tools/task/go.mod task lint
4547

46-
- name: Run ruff (Python linter and formatter)
47-
uses: astral-sh/ruff-action@0ce1b0bf8b818ef400413f810f8a11cdbda0034b # v4.0.0
48-
with:
49-
version: "0.9.1"
50-
args: "format --check"
51-
52-
- name: "task fmt: Python and Go formatting"
53-
# Python formatting is already checked above, but this also checks Go and YAML formatting
48+
- name: "task fmt: Python, Go and YAML formatting"
49+
# `task fmt` runs ruff format (Python) plus Go and YAML formatters; the diff
50+
# check fails the build if anything was left unformatted.
5451
run: |
5552
go tool -modfile=tools/task/go.mod task fmt
5653
git diff --exit-code

NEXT_CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,17 @@
77
### CLI
88
* `ssh connect` now supports specifying a serverless usage policy with `--usage-policy-id` ([#5781](https://github.com/databricks/cli/pull/5781)).
99

10+
* `ssh connect` now accepts a `--base-environment` flag to run a serverless session on a custom base environment. It takes an `env.yaml` path, a `workspace-base-environments/...` resource ID, or a base environment display name, and is rejected together with `--environment-version` or `--cluster` ([#5706](https://github.com/databricks/cli/pull/5706)).
11+
* `databricks aitools install` is now plugin-first: it installs the Databricks plugin through each agent's own CLI (Claude Code, Codex, GitHub Copilot) instead of copying raw skill files. Agents without a plugin (OpenCode, Antigravity) still get skill files, and Cursor prints the `/add-plugin databricks` step. Use `--skills-only` to force raw skill files for every agent, or `--path <dir>` to write skills to a directory ([#5738](https://github.com/databricks/cli/pull/5738)).
12+
* `databricks labs list` now only shows projects that can be installed ([#5560](https://github.com/databricks/cli/pull/5560)).
13+
1014
### Bundles
1115

16+
* direct: Fixed persistent drift on `model_serving_endpoints` caused by the `traffic_config` field ([#5708](https://github.com/databricks/cli/pull/5708)).
17+
* direct: Fix spurious update when `apply_policy_default_values: true` is set on job task, for-each-task, or job cluster new_cluster ([#5731](https://github.com/databricks/cli/pull/5731)). Also fix spurious updates for for-each-task clusters due to missing backend defaults for `data_security_mode`, `node_type_id`, `driver_node_type_id`, `driver_instance_pool_id`, `enable_elastic_disk`, and `enable_local_disk_encryption`.
18+
* direct: Cluster resize now falls back to regular update if resize fails due to `INVALID_STATE` ([#5716](https://github.com/databricks/cli/pull/5716)).
19+
* Fixed `bundle deployment migrate` failing on `model_serving_endpoints`/`database_instances` with permissions (regression since v1.5.0) ([#5775](https://github.com/databricks/cli/pull/5775)).
20+
1221
### Dependency updates
1322

1423
### API Changes

Taskfile.yml

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ vars:
44
# Absolute path so tasks with `dir:` (lint-go-tools, lint-go-codegen) can use it.
55
GO_TOOL: go tool -modfile={{.ROOT_DIR}}/tools/go.mod
66
EXE_EXT: '{{if eq OS "windows"}}.exe{{end}}'
7+
# Pinned ruff (linter + formatter). Keep in sync with the version in
8+
# .github/workflows/check.yml and python/Taskfile.yml.
9+
RUFF: uvx ruff@0.15.17
710
TEST_PACKAGES: ./acceptance/internal ./libs/... ./internal/... ./cmd/... ./bundle/... ./experimental/ssh/... .
811
ACCEPTANCE_TEST_FILTER: ""
912
# Single brace-expansion glob covering every //go:embed target in the repo,
@@ -75,14 +78,29 @@ tasks:
7578
# speed; `./task all` uses the full variants.
7679

7780
lint:
78-
desc: Lint all Go files (root + tools + codegen modules)
81+
desc: Lint all Go files (root + tools + codegen modules) and Python scripts
7982
cmds:
8083
- task: lint-go
84+
- task: lint-python
8185

8286
lint-q:
83-
desc: Lint changed Go files in root module (diff vs main, with --fix)
87+
desc: Lint changed Go files in root module (diff vs main, with --fix) and Python scripts
8488
cmds:
8589
- task: lint-q-go-root
90+
- task: lint-python
91+
92+
lint-python:
93+
desc: Lint first-party Python scripts with ruff
94+
sources:
95+
- "**/*.py"
96+
- ruff.toml
97+
cmds:
98+
# Lints the whole repo; fixtures and generated outputs are skipped via
99+
# `lint.exclude` / `extend-exclude` in ruff.toml. --no-cache: some excluded
100+
# acceptance fixtures carry their own pyproject.toml/ruff.toml (config
101+
# roots), so without it ruff writes a .ruff_cache into those checked-in
102+
# dirs, polluting the goldens and breaking the acceptance tests.
103+
- "{{.RUFF}} check --no-cache ."
86104

87105
# `golangci-lint run` typechecks, so it stops at go.mod boundaries. We have
88106
# one task per Go module; `lint-go` composes them to cover the whole repo.
@@ -166,14 +184,19 @@ tasks:
166184
deps: ['fmt-python', 'fmt-q-go', 'fmt-yaml']
167185

168186
fmt-python:
169-
desc: Format Python files
187+
desc: Lint-fix and format Python files
170188
sources:
171189
- "**/*.py"
190+
- ruff.toml
172191
cmds:
173-
# Pinned to match the version used by the `ruff format --check` step in
192+
# Auto-fix the lint issues that ruff can fix (whole repo, minus lint.exclude);
193+
# `|| true` so unfixable findings don't abort fmt (lint-python reports them).
194+
# --no-cache: see lint-python (avoids polluting acceptance fixture goldens).
195+
- "{{.RUFF}} check --no-cache --fix . || true"
196+
# Pinned (via the RUFF var) to match the `ruff format --check` step in
174197
# .github/workflows/check.yml — newer ruff versions reformat files that
175198
# CI considers already formatted.
176-
- "uvx ruff@0.9.1 format -n"
199+
- "{{.RUFF}} format -n"
177200

178201
# `golangci-lint fmt` walks the filesystem and doesn't typecheck, so it
179202
# formats files across all nested modules (tools/, bundle/internal/tf/codegen/)
@@ -694,11 +717,11 @@ tasks:
694717
-- -parallel 4 -timeout=12h
695718
696719
integration-short:
697-
desc: Run short integration tests
720+
desc: Run integration tests except the slow ones (skips CloudSlow via -short)
698721
deps: [install-pythons]
699722
cmds:
700723
- |
701-
DATABRICKS_TEST_SKIPLOCAL=1 VERBOSE_TEST=1 \
724+
VERBOSE_TEST=1 \
702725
go run -modfile=tools/go.mod ./tools/testrunner/main.go \
703726
{{.GO_TOOL}} gotestsum \
704727
--format github-actions \
@@ -707,6 +730,20 @@ tasks:
707730
--packages "./acceptance ./integration/..." \
708731
-- -parallel 4 -timeout=12h -short
709732
733+
integration-short-skiplocal:
734+
desc: Run integration tests for PRs (skips CloudSlow and tests with testserver coverage)
735+
deps: [install-pythons]
736+
cmds:
737+
- |
738+
DATABRICKS_TEST_SKIPLOCAL=1 VERBOSE_TEST=1 \
739+
go run -modfile=tools/go.mod ./tools/testrunner/main.go \
740+
{{.GO_TOOL}} gotestsum \
741+
--format github-actions \
742+
--rerun-fails \
743+
--jsonfile output.json \
744+
--packages "./acceptance ./integration/..." \
745+
-- -parallel 4 -timeout=2h -short
746+
710747
dbr-integration:
711748
desc: Run DBR acceptance tests on Databricks Runtime
712749
deps: [install-pythons]

acceptance/acceptance_test.go

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ var (
4545
LogRequests bool
4646
LogConfig bool
4747
UseVersion string
48+
CLIPath string
4849
WorkspaceTmpDir bool
4950
OnlyOutTestToml bool
5051
Subset bool
@@ -75,6 +76,7 @@ func init() {
7576
flag.BoolVar(&LogRequests, "logrequests", false, "Log request and responses from testserver")
7677
flag.BoolVar(&LogConfig, "logconfig", false, "Log merged for each test case")
7778
flag.StringVar(&UseVersion, "useversion", "", "Download previously released version of CLI and use it to run the tests")
79+
flag.StringVar(&CLIPath, "clipath", "", "Use the CLI binary at this path instead of building from source (e.g. a CLI built from main for regression comparison)")
7880

7981
// DABs in the workspace runs on the workspace file system. This flags does the same for acceptance tests
8082
// to simulate an identical environment.
@@ -191,17 +193,27 @@ func hasRunFilter() bool {
191193
// requirePrerequisites verifies external tool prerequisites before doing any
192194
// work, so a stale toolchain fails fast with an actionable message instead of
193195
// producing confusing diffs deep into the run.
194-
func requirePrerequisites(t *testing.T) {
195-
// Scripts use jq 1.7 features (the pick/1 builtin and the `.foo.[]` iteration syntax).
196-
internal.RequireJQ(t, "1.7")
197-
// uv builds the databricks-bundles wheel and provides the test interpreter
198-
// via `uv python find`, which landed in the 0.3 line.
199-
internal.RequireUV(t, "0.4")
200-
// ruff 0.9.1 is pinned across the repo (python/pyproject.toml, Taskfile.yml);
201-
// the check-formatting test's golden output assumes its formatter behavior.
202-
internal.RequireRuff(t, "0.9.1")
203-
// Acceptance scripts import the stdlib tomllib module, added in Python 3.11.
204-
internal.EnsurePython(t, "3.11")
196+
//
197+
// It reports whether all checks passed; a failure surfaces as
198+
// TestAccept/prerequisites rather than a bare TestAccept.
199+
//
200+
// On DBR the serverless image only provides what the test archive ships, so
201+
// every tool required here must also be bundled in internal/testarchive. When
202+
// adding a new RequireX prerequisite, add a matching downloader there too, or
203+
// DBR runs will fail this check before any test runs.
204+
func requirePrerequisites(t *testing.T) bool {
205+
return t.Run("prerequisites", func(t *testing.T) {
206+
// Scripts use jq 1.7 features (the pick/1 builtin and the `.foo.[]` iteration syntax).
207+
internal.RequireJQ(t, "1.7")
208+
// uv builds the databricks-bundles wheel and provides the test interpreter
209+
// via `uv python find`, which landed in the 0.3 line.
210+
internal.RequireUV(t, "0.4")
211+
// ruff 0.9.1 is pinned across the repo (python/pyproject.toml, Taskfile.yml);
212+
// the check-formatting test's golden output assumes its formatter behavior.
213+
internal.RequireRuff(t, "0.9.1")
214+
// Acceptance scripts import the stdlib tomllib module, added in Python 3.11.
215+
internal.RequirePython(t, "3.11")
216+
})
205217
}
206218

207219
func testAccept(t *testing.T, inprocessMode bool, singleTest string) int {
@@ -245,7 +257,14 @@ func testAccept(t *testing.T, inprocessMode bool, singleTest string) int {
245257
os.Unsetenv(v) //nolint:usetesting // t.Setenv cannot unset
246258
}
247259

248-
requirePrerequisites(t)
260+
if !requirePrerequisites(t) {
261+
// Don't run the suite against a stale toolchain; the failed subtest
262+
// has already marked the parent test as failed.
263+
return 0
264+
}
265+
// Run after the version check passed; must use the top-level t so the PATH
266+
// change survives for the rest of the run.
267+
internal.ConfigurePython(t, "3.11")
249268

250269
buildDir := getBuildDir(t, cwd, runtime.GOOS, runtime.GOARCH)
251270

@@ -285,7 +304,11 @@ func testAccept(t *testing.T, inprocessMode bool, singleTest string) int {
285304
t.Setenv("CMD_SERVER_URL", cmdServer.URL)
286305
execPath = filepath.Join(cwd, "bin", "callserver.py")
287306
} else {
288-
if UseVersion != "" {
307+
if CLIPath != "" {
308+
// Use a prebuilt binary (e.g. a CLI built from main) instead of building
309+
// from the current source, so the test infra and tests stay on this branch.
310+
execPath = CLIPath
311+
} else if UseVersion != "" {
289312
version := UseVersion
290313
if version == "latest" {
291314
version = resolveLatestVersion(t, buildDir)

acceptance/bin/add_repl.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
If entry already exists, it'll add suffix in _<number> format.
66
"""
77

8-
import os
98
import argparse
9+
import os
1010
from pathlib import Path
1111

1212
ACC_REPLS = Path(os.environ["TEST_TMP_DIR"]) / "ACC_REPLS"

acceptance/bin/assert_exists.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#!/usr/bin/env python3
2-
import os, sys
2+
import os
3+
import sys
34

45
errors = 0
56

acceptance/bin/assert_not_exists.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#!/usr/bin/env python3
2-
import os, sys
2+
import os
3+
import sys
34

45
errors = 0
56

acceptance/bin/benchmark.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
#!/usr/bin/env python3
22
import argparse
3-
import subprocess
4-
import time
3+
import json
4+
import os
55
import statistics
6+
import subprocess
67
import sys
7-
import os
8-
import json
8+
import time
99

1010
try:
1111
import resource
@@ -19,7 +19,7 @@ def run_benchmark(command, warmup, runs):
1919

2020
for i in range(runs):
2121
# double fork to reset max statistics like ru_maxrss
22-
cp = subprocess.run([sys.executable, sys.argv[0], "--once"] + command, stdout=subprocess.PIPE)
22+
cp = subprocess.run([sys.executable, sys.argv[0], "--once", *command], stdout=subprocess.PIPE)
2323
if cp.returncode != 0:
2424
sys.exit(cp.returncode)
2525

@@ -54,7 +54,7 @@ def run_benchmark(command, warmup, runs):
5454

5555

5656
def run_once(command):
57-
if len(command) == 1 and " " in command[0] or ">" in command[0]:
57+
if (len(command) == 1 and " " in command[0]) or ">" in command[0]:
5858
shell = True
5959
command = command[0]
6060
else:

acceptance/bin/browser.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
Usage: browser.py <url>
77
"""
88

9-
import urllib.request
109
import sys
10+
import urllib.request
1111

1212
if len(sys.argv) < 2:
1313
sys.stderr.write("Usage: browser.py <url>\n")

acceptance/bin/callserver.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/usr/bin/env python3
2-
import sys
3-
import os
42
import json
3+
import os
4+
import sys
55
import urllib.request
66
from urllib.parse import urlencode
77

0 commit comments

Comments
 (0)