Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
c80d23b
Add design spec for databricks dbconnect init/sync
rugpanov Jun 19, 2026
59ca8c4
Add implementation plan for databricks dbconnect init/sync
rugpanov Jun 19, 2026
a0efbc1
Add dbconnect command namespace scaffold
rugpanov Jun 19, 2026
050bf98
Fix dbconnect help acceptance golden
rugpanov Jun 22, 2026
ee4da53
Add dbconnect result types and error codes
rugpanov Jun 22, 2026
d7ad457
Address review: remove noise comments and Mode.String default
rugpanov Jun 22, 2026
99f5c15
Add dbconnect envKey mapping and python-version parsing
rugpanov Jun 22, 2026
28f06c8
Address review: simplify envKey normalization, hoist regex
rugpanov Jun 22, 2026
563f415
Add dbconnect constraint fetch with offline cache
rugpanov Jun 22, 2026
f76db1f
Add surgical formatting-preserving pyproject.toml merge
rugpanov Jun 22, 2026
8a0fa12
Fix tool.uv merge to preserve user-authored keys
rugpanov Jun 22, 2026
ffe111a
Detect multi-line owned-only [tool.uv] to avoid stray empty table
rugpanov Jun 22, 2026
801b6c1
Add dbconnect target resolution with three-state messaging
rugpanov Jun 22, 2026
98a1aff
gofmt dbconnect target.go field alignment
rugpanov Jun 22, 2026
a72fb41
gofmt dbconnect result.go field alignment
rugpanov Jun 22, 2026
5f5461f
Add PackageManager interface and uv implementation
rugpanov Jun 22, 2026
6d88a13
Make uv venv python path cross-platform; explain --no-project
rugpanov Jun 22, 2026
37e3c87
Add dbconnect pipeline orchestrating all phases
rugpanov Jun 22, 2026
33162f1
Fix: use correct error code for python version parse failure in pipeline
rugpanov Jun 22, 2026
29662f6
Fix: append PhaseResult on python-version parse failure in pipeline f…
rugpanov Jun 22, 2026
668211a
Fix: add success PhaseResult for parse-python-version in fetch phase
rugpanov Jun 22, 2026
8f4631c
Fail validation when databricks-connect major version is unparseable
rugpanov Jun 22, 2026
0ffdabf
Wire dbconnect Cobra layer: flags, compute adapter, rendering
rugpanov Jun 22, 2026
03fa3ee
gofmt dbconnect output.go
rugpanov Jun 22, 2026
04aedef
Fix dbconnect JSON error schema, uv version probe, nil-result rendering
rugpanov Jun 22, 2026
fceace2
Add dbconnect acceptance tests
rugpanov Jun 22, 2026
8f9a134
Fix acceptance tests to use musterr for required-failure commands
rugpanov Jun 22, 2026
7cf72cd
Fix lint findings in dbconnect packages
rugpanov Jun 22, 2026
1ac61fe
Add dbconnect changelog entry; fix constraint repo URL comment
rugpanov Jun 22, 2026
995b6a4
Fix dbconnect JSON-mode exit code; populate spark_version; drop unuse…
rugpanov Jun 22, 2026
bccdae8
Bridge pip.conf index-url to UV_INDEX_URL and surface uv stderr in er…
rugpanov Jun 22, 2026
1eb07e2
Add diagnostic logging and a failure hint for remote troubleshooting
rugpanov Jun 22, 2026
8f656d9
Remove superpowers design/plan docs from PR
rugpanov Jun 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions NEXT_CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
### Notable Changes

### CLI
* Add `databricks dbconnect init` and `databricks dbconnect sync` to provision a local Python environment (Python version, `databricks-connect` pin, and dependency constraints) matched to the selected Databricks compute target.

### Bundles
* `bundle run` now prints the modern job run URL (`/jobs/<id>/runs/<id>`) so that non-admin users permitted to view the run are taken to the run instead of the workspace homepage.
Expand Down
3 changes: 3 additions & 0 deletions acceptance/dbconnect/cluster-unsupported/out.test.toml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions acceptance/dbconnect/cluster-unsupported/output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
=== Phase 1: preflight ===
status=ok uv [UV_VERSION]
=== Phase 2: resolve ===
status=ok kind=cluster envKey=dbr/15.4.x-scala2.12
=== Phase 3: fetch ===
status=failed fetch constraints for dbr/15.4.x-scala2.12: GET [DATABRICKS_URL]/dbr/15.4.x-scala2.12/pyproject.toml: unexpected status 404 Not Found
For more detail, re-run with --debug, or --output json to share a structured report.
Error: fetch constraints for dbr/15.4.x-scala2.12: GET [DATABRICKS_URL]/dbr/15.4.x-scala2.12/pyproject.toml: unexpected status 404 Not Found
1 change: 1 addition & 0 deletions acceptance/dbconnect/cluster-unsupported/script
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
musterr $CLI dbconnect init --cluster test-cluster-id --check
22 changes: 22 additions & 0 deletions acceptance/dbconnect/cluster-unsupported/test.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
EnvMatrix.DATABRICKS_BUNDLE_ENGINE = []

[Env]
DATABRICKS_DBCONNECT_CONSTRAINT_SOURCE = "$DATABRICKS_HOST"

[[Server]]
Pattern = "GET /api/2.1/clusters/get"
Response.Body = '''
{
"cluster_id": "test-cluster-id",
"spark_version": "15.4.x-scala2.12"
}
'''

[[Server]]
Pattern = "GET /dbr/15.4.x-scala2.12/pyproject.toml"
Response.StatusCode = 404
Response.Body = '{"message": "Not found"}'

[[Repls]]
Old = 'uv uv \S+(?: \([^)]+\))?'
New = 'uv [UV_VERSION]'
3 changes: 3 additions & 0 deletions acceptance/dbconnect/flag-conflict/out.test.toml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions acceptance/dbconnect/flag-conflict/output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Error: if any flags in the group [cluster serverless job] are set none of the others can be; [cluster serverless] were all set
1 change: 1 addition & 0 deletions acceptance/dbconnect/flag-conflict/script
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
musterr $CLI dbconnect init --cluster abc --serverless v4
1 change: 1 addition & 0 deletions acceptance/dbconnect/flag-conflict/test.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
EnvMatrix.DATABRICKS_BUNDLE_ENGINE = []
3 changes: 3 additions & 0 deletions acceptance/dbconnect/help/out.test.toml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

40 changes: 40 additions & 0 deletions acceptance/dbconnect/help/output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
Set up a local Python environment matched to your Databricks compute target.

Derives the Python version, databricks-connect version, and dependency
constraints from the selected compute (cluster, serverless, or job) so that
local resolution matches the Databricks runtime.

Usage:
databricks dbconnect [command]

Available Commands:
init Create a fresh pyproject.toml and provision a matched .venv
sync Merge managed dependencies into an existing pyproject.toml and re-provision

Flags:
-h, --help help for dbconnect

Global Flags:
--debug enable debug logging
-o, --output type output type: text or json (default text)
-p, --profile string ~/.databrickscfg profile
-t, --target string bundle target to use (if applicable)

Use "databricks dbconnect [command] --help" for more information about a command.
Create a fresh pyproject.toml and provision a matched .venv

Usage:
databricks dbconnect init [flags]

Flags:
--check compute the plan without writing files or provisioning
--cluster string cluster ID to use as the compute target
-h, --help help for init
--job string job ID to use as the compute target
--serverless string serverless version to use as the compute target (e.g. v4)

Global Flags:
--debug enable debug logging
-o, --output type output type: text or json (default text)
-p, --profile string ~/.databrickscfg profile
-t, --target string bundle target to use (if applicable)
2 changes: 2 additions & 0 deletions acceptance/dbconnect/help/script
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
$CLI dbconnect --help
$CLI dbconnect init --help
1 change: 1 addition & 0 deletions acceptance/dbconnect/help/test.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
EnvMatrix.DATABRICKS_BUNDLE_ENGINE = []
3 changes: 3 additions & 0 deletions acceptance/dbconnect/json-error/out.test.toml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 20 additions & 0 deletions acceptance/dbconnect/json-error/output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"mode": "init",
"check": false,
"phases": [
{
"name": "preflight",
"status": "ok",
"detail": "uv [UV_VERSION]"
},
{
"name": "resolve",
"status": "failed",
"detail": "No compute target is selected. Select a cluster or serverless target, or pass --cluster/--serverless/--job"
}
],
"error": {
"code": "no_target_selected",
"message": "No compute target is selected. Select a cluster or serverless target, or pass --cluster/--serverless/--job"
}
}
1 change: 1 addition & 0 deletions acceptance/dbconnect/json-error/script
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
musterr $CLI dbconnect init --output json
5 changes: 5 additions & 0 deletions acceptance/dbconnect/json-error/test.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
EnvMatrix.DATABRICKS_BUNDLE_ENGINE = []

[[Repls]]
Old = 'uv uv \S+(?: \([^)]+\))?'
New = 'uv [UV_VERSION]'
3 changes: 3 additions & 0 deletions acceptance/dbconnect/no-target/out.test.toml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions acceptance/dbconnect/no-target/output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
=== Phase 1: preflight ===
status=ok uv [UV_VERSION]
=== Phase 2: resolve ===
status=failed No compute target is selected. Select a cluster or serverless target, or pass --cluster/--serverless/--job
For more detail, re-run with --debug, or --output json to share a structured report.
Error: No compute target is selected. Select a cluster or serverless target, or pass --cluster/--serverless/--job
1 change: 1 addition & 0 deletions acceptance/dbconnect/no-target/script
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
musterr $CLI dbconnect init
5 changes: 5 additions & 0 deletions acceptance/dbconnect/no-target/test.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
EnvMatrix.DATABRICKS_BUNDLE_ENGINE = []

[[Repls]]
Old = 'uv uv \S+(?: \([^)]+\))?'
New = 'uv [UV_VERSION]'
3 changes: 3 additions & 0 deletions acceptance/dbconnect/serverless-check/out.test.toml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions acceptance/dbconnect/serverless-check/output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@

>>> [CLI] dbconnect init --serverless v4 --check
=== Phase 1: preflight ===
status=ok uv [UV_VERSION]
=== Phase 2: resolve ===
status=ok kind=serverless envKey=serverless/serverless-v4
=== Phase 3: fetch ===
status=ok source=[DATABRICKS_URL]/serverless/serverless-v4/pyproject.toml fromCache=false
=== Phase 4: parse-python-version ===
status=ok 3.12
=== Phase 5: plan ===
status=ok changed=requires-python,databricks-connect,tool.uv.constraint-dependencies
Plan: [TEST_TMP_DIR]/pyproject.toml
changed region: requires-python
changed region: databricks-connect
changed region: tool.uv.constraint-dependencies
Check complete. No files were modified.
1 change: 1 addition & 0 deletions acceptance/dbconnect/serverless-check/script
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
trace $CLI dbconnect init --serverless v4 --check
21 changes: 21 additions & 0 deletions acceptance/dbconnect/serverless-check/test.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
EnvMatrix.DATABRICKS_BUNDLE_ENGINE = []

[Env]
DATABRICKS_DBCONNECT_CONSTRAINT_SOURCE = "$DATABRICKS_HOST"

[[Server]]
Pattern = "GET /serverless/serverless-v4/pyproject.toml"
Response.Body = '''
[project]
requires-python = ">=3.12"

[dependency-groups]
dev = ["databricks-connect~=17.2.0"]

[tool.uv]
constraint-dependencies = ["pyarrow<19", "pandas<3"]
'''

[[Repls]]
Old = 'uv uv \S+(?: \([^)]+\))?'
New = 'uv [UV_VERSION]'
3 changes: 3 additions & 0 deletions acceptance/dbconnect/serverless-json/out.test.toml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

57 changes: 57 additions & 0 deletions acceptance/dbconnect/serverless-json/output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@

>>> [CLI] dbconnect init --serverless v4 --check --output json
{
"mode": "init",
"check": true,
"target": {
"kind": "serverless",
"cluster_id": "",
"spark_version": "",
"env_key": "serverless/serverless-v4",
"python_version": "3.12"
},
"constraints": {
"source_url": "[DATABRICKS_URL]/serverless/serverless-v4/pyproject.toml",
"from_cache": false,
"requires_python": "\u003e=3.12",
"databricks_connect": "databricks-connect~=17.2.0",
"constraint_count": 2
},
"plan": {
"pyproject_path": "[TEST_TMP_DIR]/pyproject.toml",
"backup_path": "[TEST_TMP_DIR]/pyproject.toml.bak",
"diff": "--- pyproject.toml\n+++ pyproject.toml\n@@ -1 +1,16 @@\n+[project]\n+name = \"001\"\n+requires-python = \"\u003e=3.12\"\n+\n+[dependency-groups]\n+dev = [\n+ \"databricks-connect~=17.2.0\",\n+]\n+\n+# managed by databricks dbconnect — do not edit\n+[tool.uv]\n+constraint-dependencies = [\n+ \"pyarrow\u003c19\",\n+ \"pandas\u003c3\",\n+]\n+# end managed by databricks dbconnect\n",
"changed_regions": [
"requires-python",
"databricks-connect",
"tool.uv.constraint-dependencies"
]
},
"phases": [
{
"name": "preflight",
"status": "ok",
"detail": "uv [UV_VERSION]"
},
{
"name": "resolve",
"status": "ok",
"detail": "kind=serverless envKey=serverless/serverless-v4"
},
{
"name": "fetch",
"status": "ok",
"detail": "source=[DATABRICKS_URL]/serverless/serverless-v4/pyproject.toml fromCache=false"
},
{
"name": "parse-python-version",
"status": "ok",
"detail": "3.12"
},
{
"name": "plan",
"status": "ok",
"detail": "changed=requires-python,databricks-connect,tool.uv.constraint-dependencies"
}
]
}
1 change: 1 addition & 0 deletions acceptance/dbconnect/serverless-json/script
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
trace $CLI dbconnect init --serverless v4 --check --output json
21 changes: 21 additions & 0 deletions acceptance/dbconnect/serverless-json/test.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
EnvMatrix.DATABRICKS_BUNDLE_ENGINE = []

[Env]
DATABRICKS_DBCONNECT_CONSTRAINT_SOURCE = "$DATABRICKS_HOST"

[[Server]]
Pattern = "GET /serverless/serverless-v4/pyproject.toml"
Response.Body = '''
[project]
requires-python = ">=3.12"

[dependency-groups]
dev = ["databricks-connect~=17.2.0"]

[tool.uv]
constraint-dependencies = ["pyarrow<19", "pandas<3"]
'''

[[Repls]]
Old = 'uv uv \S+(?: \([^)]+\))?'
New = 'uv [UV_VERSION]'
2 changes: 2 additions & 0 deletions cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/databricks/cli/cmd/cache"
"github.com/databricks/cli/cmd/completion"
"github.com/databricks/cli/cmd/configure"
"github.com/databricks/cli/cmd/dbconnect"
"github.com/databricks/cli/cmd/experimental"
"github.com/databricks/cli/cmd/fs"
"github.com/databricks/cli/cmd/labs"
Expand Down Expand Up @@ -120,6 +121,7 @@ func New(ctx context.Context) *cobra.Command {
cli.AddCommand(cache.New())
cli.AddCommand(experimental.New())
cli.AddCommand(psql.New())
cli.AddCommand(dbconnect.New())
cli.AddCommand(configure.New())
cli.AddCommand(fs.New())
cli.AddCommand(labs.New(ctx))
Expand Down
60 changes: 60 additions & 0 deletions cmd/dbconnect/compute.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package dbconnect

import (
"context"
"fmt"
"strconv"

databricks "github.com/databricks/databricks-sdk-go"
)

// sdkCompute adapts the Databricks SDK to the dbconnect.ComputeClient interface.
type sdkCompute struct {
w *databricks.WorkspaceClient
}

// GetClusterSparkVersion returns the Spark version string for a running cluster.
func (c sdkCompute) GetClusterSparkVersion(ctx context.Context, clusterID string) (string, error) {
d, err := c.w.Clusters.GetByClusterId(ctx, clusterID)
if err != nil {
return "", fmt.Errorf("get cluster %s: %w", clusterID, err)
}
return d.SparkVersion, nil
}

// GetJobSparkVersion inspects the job's configuration to determine compute type.
//
// A job is considered serverless when it has non-empty Environments (JobEnvironment
// entries), which signals the Databricks serverless runtime. A job with classic compute
// uses JobClusters; we read SparkVersion from the first job cluster's NewCluster spec.
// If neither indicator is present the job's compute cannot be determined.
func (c sdkCompute) GetJobSparkVersion(ctx context.Context, jobID string) (sparkVersion string, isServerless bool, version string, err error) {
id, err := strconv.ParseInt(jobID, 10, 64)
if err != nil {
return "", false, "", fmt.Errorf("invalid job ID %q: must be an integer: %w", jobID, err)
}

job, err := c.w.Jobs.GetByJobId(ctx, id)
if err != nil {
return "", false, "", fmt.Errorf("get job %d: %w", id, err)
}

if job.Settings == nil {
return "", false, "", fmt.Errorf("job %d has no settings", id)
}

// Serverless jobs have Environments populated; classic compute uses JobClusters.
if len(job.Settings.Environments) > 0 {
return "", true, "", nil
}

if len(job.Settings.JobClusters) > 0 {
sv := job.Settings.JobClusters[0].NewCluster.SparkVersion
if sv == "" {
return "", false, "", fmt.Errorf("could not determine compute for job %d: first job cluster has no spark_version", id)
}
return sv, false, sv, nil
}

return "", false, "", fmt.Errorf("could not determine compute for job %d: no environments or job clusters found", id)
}
20 changes: 20 additions & 0 deletions cmd/dbconnect/dbconnect.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package dbconnect

import "github.com/spf13/cobra"

// New returns the `dbconnect` command group.
func New() *cobra.Command {
cmd := &cobra.Command{
Use: "dbconnect",
Short: "Set up a local Python environment matched to your Databricks compute",
GroupID: "development",
Long: `Set up a local Python environment matched to your Databricks compute target.

Derives the Python version, databricks-connect version, and dependency
constraints from the selected compute (cluster, serverless, or job) so that
local resolution matches the Databricks runtime.`,
}
cmd.AddCommand(newInitCommand())
cmd.AddCommand(newSyncCommand())
return cmd
}
Loading
Loading