diff --git a/acceptance/localenv/constraints-only/out.test.toml b/acceptance/localenv/constraints-only/out.test.toml new file mode 100644 index 0000000000..d6187dcb04 --- /dev/null +++ b/acceptance/localenv/constraints-only/out.test.toml @@ -0,0 +1,3 @@ +Local = true +Cloud = false +EnvMatrix.DATABRICKS_BUNDLE_ENGINE = [] diff --git a/acceptance/localenv/constraints-only/output.txt b/acceptance/localenv/constraints-only/output.txt new file mode 100644 index 0000000000..d2f12be5db --- /dev/null +++ b/acceptance/localenv/constraints-only/output.txt @@ -0,0 +1,53 @@ + +>>> [CLI] local-env python sync --serverless v4 --constraints-only --check --output json +{ + "schemaVersion": 1, + "command": "local-env python sync", + "ok": true, + "mode": "constraints-only", + "dryRun": true, + "target": { + "source": "serverless", + "serverlessVersion": "v4", + "envKey": "serverless/serverless-v4" + }, + "resolved": { + "pythonVersion": "3.12", + "artifactSource": "network" + }, + "greenfield": true, + "plan": { + "wouldWrite": "[TEST_TMP_DIR]/pyproject.toml", + "wouldInstallPython": "3.12", + "diff": "--- pyproject.toml\n+++ pyproject.toml\n@@ -1 +1,15 @@\n+[project]\n+name = \"001\"\n+version = \"0.0.0\"\n+requires-python = \"\u003e=3.12\"\n+\n+[dependency-groups]\n+dev = []\n+\n+# managed by databricks local-env python sync — do not edit\n+[tool.uv]\n+constraint-dependencies = [\n+ \"pyarrow\u003c19\",\n+ \"pandas\u003c3\",\n+]\n+# end managed by databricks local-env python sync\n" + }, + "phases": [ + { + "phase": "preflight", + "status": "ok" + }, + { + "phase": "resolve", + "status": "ok" + }, + { + "phase": "fetch", + "status": "ok" + }, + { + "phase": "merge", + "status": "ok" + }, + { + "phase": "provision", + "status": "ok" + }, + { + "phase": "validate", + "status": "ok" + } + ], + "warnings": [], + "error": null, + "durationMs": 0 +} diff --git a/acceptance/localenv/constraints-only/script b/acceptance/localenv/constraints-only/script new file mode 100644 index 0000000000..354eac4996 --- /dev/null +++ b/acceptance/localenv/constraints-only/script @@ -0,0 +1 @@ +trace $CLI local-env python sync --serverless v4 --constraints-only --check --output json diff --git a/acceptance/localenv/constraints-only/test.toml b/acceptance/localenv/constraints-only/test.toml new file mode 100644 index 0000000000..e2b12fc95b --- /dev/null +++ b/acceptance/localenv/constraints-only/test.toml @@ -0,0 +1,21 @@ +EnvMatrix.DATABRICKS_BUNDLE_ENGINE = [] + +[Env] +DATABRICKS_LOCALENV_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]' diff --git a/acceptance/localenv/env-unsupported/out.test.toml b/acceptance/localenv/env-unsupported/out.test.toml new file mode 100644 index 0000000000..d6187dcb04 --- /dev/null +++ b/acceptance/localenv/env-unsupported/out.test.toml @@ -0,0 +1,3 @@ +Local = true +Cloud = false +EnvMatrix.DATABRICKS_BUNDLE_ENGINE = [] diff --git a/acceptance/localenv/env-unsupported/output.txt b/acceptance/localenv/env-unsupported/output.txt new file mode 100644 index 0000000000..39e540600d --- /dev/null +++ b/acceptance/localenv/env-unsupported/output.txt @@ -0,0 +1,8 @@ +preflight ok check +resolve ok source=cluster envKey=dbr/15.4.x-scala2.12 +fetch error no published environment for "dbr/15.4.x-scala2.12". If this is a new runtime, try the latest LTS target (e.g. --serverless v4 or a supported --cluster DBR): GET [DATABRICKS_URL]/dbr/15.4.x-scala2.12/pyproject.toml: environment key not found +merge pending +provision pending +validate pending +For more detail, re-run with --debug, or --output json to share a structured report. +Error: no published environment for "dbr/15.4.x-scala2.12". If this is a new runtime, try the latest LTS target (e.g. --serverless v4 or a supported --cluster DBR): GET [DATABRICKS_URL]/dbr/15.4.x-scala2.12/pyproject.toml: environment key not found diff --git a/acceptance/localenv/env-unsupported/script b/acceptance/localenv/env-unsupported/script new file mode 100644 index 0000000000..924f04b9d9 --- /dev/null +++ b/acceptance/localenv/env-unsupported/script @@ -0,0 +1 @@ +musterr $CLI local-env python sync --cluster test-cluster-id --check diff --git a/acceptance/localenv/env-unsupported/test.toml b/acceptance/localenv/env-unsupported/test.toml new file mode 100644 index 0000000000..7823db924d --- /dev/null +++ b/acceptance/localenv/env-unsupported/test.toml @@ -0,0 +1,22 @@ +EnvMatrix.DATABRICKS_BUNDLE_ENGINE = [] + +[Env] +DATABRICKS_LOCALENV_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]' diff --git a/acceptance/localenv/flag-conflict/out.test.toml b/acceptance/localenv/flag-conflict/out.test.toml new file mode 100644 index 0000000000..d6187dcb04 --- /dev/null +++ b/acceptance/localenv/flag-conflict/out.test.toml @@ -0,0 +1,3 @@ +Local = true +Cloud = false +EnvMatrix.DATABRICKS_BUNDLE_ENGINE = [] diff --git a/acceptance/localenv/flag-conflict/output.txt b/acceptance/localenv/flag-conflict/output.txt new file mode 100644 index 0000000000..141152ae1c --- /dev/null +++ b/acceptance/localenv/flag-conflict/output.txt @@ -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 diff --git a/acceptance/localenv/flag-conflict/script b/acceptance/localenv/flag-conflict/script new file mode 100644 index 0000000000..3309cd5220 --- /dev/null +++ b/acceptance/localenv/flag-conflict/script @@ -0,0 +1 @@ +musterr $CLI local-env python sync --cluster abc --serverless v4 diff --git a/acceptance/localenv/flag-conflict/test.toml b/acceptance/localenv/flag-conflict/test.toml new file mode 100644 index 0000000000..c63fe3fe10 --- /dev/null +++ b/acceptance/localenv/flag-conflict/test.toml @@ -0,0 +1 @@ +EnvMatrix.DATABRICKS_BUNDLE_ENGINE = [] diff --git a/acceptance/localenv/help/out.test.toml b/acceptance/localenv/help/out.test.toml new file mode 100644 index 0000000000..d6187dcb04 --- /dev/null +++ b/acceptance/localenv/help/out.test.toml @@ -0,0 +1,3 @@ +Local = true +Cloud = false +EnvMatrix.DATABRICKS_BUNDLE_ENGINE = [] diff --git a/acceptance/localenv/help/output.txt b/acceptance/localenv/help/output.txt new file mode 100644 index 0000000000..03fffb2be7 --- /dev/null +++ b/acceptance/localenv/help/output.txt @@ -0,0 +1,43 @@ +Manage the local Python environment matched to a Databricks compute target. + +Usage: + databricks local-env python [flags] + databricks local-env python [command] + +Available Commands: + sync Provision a local Python environment matched to a Databricks compute target + +Flags: + -h, --help help for python + +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 local-env python [command] --help" for more information about a command. +Provision (or update) a local Python environment matched to a Databricks compute target. + +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. A project with no pyproject.toml is +initialized from scratch; an existing pyproject.toml is merged in place (its +env-owned sections are refreshed, user-owned content is preserved). + +Usage: + databricks local-env python sync [flags] + +Flags: + --check compute the plan without writing files or provisioning + --cluster string cluster ID to use as the compute target + --constraints-only apply the Python version and constraints without adding the databricks-connect dependency + -h, --help help for sync + --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) diff --git a/acceptance/localenv/help/script b/acceptance/localenv/help/script new file mode 100644 index 0000000000..cca1e85aad --- /dev/null +++ b/acceptance/localenv/help/script @@ -0,0 +1,2 @@ +$CLI local-env python --help +$CLI local-env python sync --help diff --git a/acceptance/localenv/help/test.toml b/acceptance/localenv/help/test.toml new file mode 100644 index 0000000000..c63fe3fe10 --- /dev/null +++ b/acceptance/localenv/help/test.toml @@ -0,0 +1 @@ +EnvMatrix.DATABRICKS_BUNDLE_ENGINE = [] diff --git a/acceptance/localenv/json-error/out.test.toml b/acceptance/localenv/json-error/out.test.toml new file mode 100644 index 0000000000..d6187dcb04 --- /dev/null +++ b/acceptance/localenv/json-error/out.test.toml @@ -0,0 +1,3 @@ +Local = true +Cloud = false +EnvMatrix.DATABRICKS_BUNDLE_ENGINE = [] diff --git a/acceptance/localenv/json-error/output.txt b/acceptance/localenv/json-error/output.txt new file mode 100644 index 0000000000..e76a8f7479 --- /dev/null +++ b/acceptance/localenv/json-error/output.txt @@ -0,0 +1,42 @@ +{ + "schemaVersion": 1, + "command": "local-env python sync", + "ok": false, + "mode": "default", + "dryRun": false, + "greenfield": false, + "phases": [ + { + "phase": "preflight", + "status": "ok" + }, + { + "phase": "resolve", + "status": "error" + }, + { + "phase": "fetch", + "status": "pending" + }, + { + "phase": "merge", + "status": "pending" + }, + { + "phase": "provision", + "status": "pending" + }, + { + "phase": "validate", + "status": "pending" + } + ], + "warnings": [], + "error": { + "code": "E_NO_TARGET", + "failurePhase": "resolve", + "message": "No compute target is selected. Select a cluster or serverless target, or pass --cluster / --serverless / --job", + "diskMutated": false + }, + "durationMs": 0 +} diff --git a/acceptance/localenv/json-error/script b/acceptance/localenv/json-error/script new file mode 100644 index 0000000000..bffcc264af --- /dev/null +++ b/acceptance/localenv/json-error/script @@ -0,0 +1 @@ +musterr $CLI local-env python sync --output json diff --git a/acceptance/localenv/json-error/test.toml b/acceptance/localenv/json-error/test.toml new file mode 100644 index 0000000000..0d0481fb83 --- /dev/null +++ b/acceptance/localenv/json-error/test.toml @@ -0,0 +1,5 @@ +EnvMatrix.DATABRICKS_BUNDLE_ENGINE = [] + +[[Repls]] +Old = 'uv uv \S+(?: \([^)]+\))?' +New = 'uv [UV_VERSION]' diff --git a/acceptance/localenv/manager-unsupported/environment.yml b/acceptance/localenv/manager-unsupported/environment.yml new file mode 100644 index 0000000000..d5364e4706 --- /dev/null +++ b/acceptance/localenv/manager-unsupported/environment.yml @@ -0,0 +1,3 @@ +name: demo +dependencies: + - python=3.10 diff --git a/acceptance/localenv/manager-unsupported/out.test.toml b/acceptance/localenv/manager-unsupported/out.test.toml new file mode 100644 index 0000000000..d6187dcb04 --- /dev/null +++ b/acceptance/localenv/manager-unsupported/out.test.toml @@ -0,0 +1,3 @@ +Local = true +Cloud = false +EnvMatrix.DATABRICKS_BUNDLE_ENGINE = [] diff --git a/acceptance/localenv/manager-unsupported/output.txt b/acceptance/localenv/manager-unsupported/output.txt new file mode 100644 index 0000000000..4a5b3b2c08 --- /dev/null +++ b/acceptance/localenv/manager-unsupported/output.txt @@ -0,0 +1,8 @@ +preflight error detected a conda project; automated setup for conda is not yet available (P1). Use a uv project (add a pyproject.toml with a [tool.uv] table, or run `uv init`) to provision automatically +resolve pending +fetch pending +merge pending +provision pending +validate pending +For more detail, re-run with --debug, or --output json to share a structured report. +Error: detected a conda project; automated setup for conda is not yet available (P1). Use a uv project (add a pyproject.toml with a [tool.uv] table, or run `uv init`) to provision automatically diff --git a/acceptance/localenv/manager-unsupported/script b/acceptance/localenv/manager-unsupported/script new file mode 100644 index 0000000000..aae187d00c --- /dev/null +++ b/acceptance/localenv/manager-unsupported/script @@ -0,0 +1 @@ +musterr $CLI local-env python sync --serverless v4 --check diff --git a/acceptance/localenv/manager-unsupported/test.toml b/acceptance/localenv/manager-unsupported/test.toml new file mode 100644 index 0000000000..0d0481fb83 --- /dev/null +++ b/acceptance/localenv/manager-unsupported/test.toml @@ -0,0 +1,5 @@ +EnvMatrix.DATABRICKS_BUNDLE_ENGINE = [] + +[[Repls]] +Old = 'uv uv \S+(?: \([^)]+\))?' +New = 'uv [UV_VERSION]' diff --git a/acceptance/localenv/no-target/out.test.toml b/acceptance/localenv/no-target/out.test.toml new file mode 100644 index 0000000000..d6187dcb04 --- /dev/null +++ b/acceptance/localenv/no-target/out.test.toml @@ -0,0 +1,3 @@ +Local = true +Cloud = false +EnvMatrix.DATABRICKS_BUNDLE_ENGINE = [] diff --git a/acceptance/localenv/no-target/output.txt b/acceptance/localenv/no-target/output.txt new file mode 100644 index 0000000000..f17c350c8f --- /dev/null +++ b/acceptance/localenv/no-target/output.txt @@ -0,0 +1,8 @@ +preflight ok uv [UV_VERSION] +resolve error No compute target is selected. Select a cluster or serverless target, or pass --cluster / --serverless / --job +fetch pending +merge pending +provision pending +validate pending +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 diff --git a/acceptance/localenv/no-target/script b/acceptance/localenv/no-target/script new file mode 100644 index 0000000000..3460d1b8cf --- /dev/null +++ b/acceptance/localenv/no-target/script @@ -0,0 +1 @@ +musterr $CLI local-env python sync diff --git a/acceptance/localenv/no-target/test.toml b/acceptance/localenv/no-target/test.toml new file mode 100644 index 0000000000..0d0481fb83 --- /dev/null +++ b/acceptance/localenv/no-target/test.toml @@ -0,0 +1,5 @@ +EnvMatrix.DATABRICKS_BUNDLE_ENGINE = [] + +[[Repls]] +Old = 'uv uv \S+(?: \([^)]+\))?' +New = 'uv [UV_VERSION]' diff --git a/acceptance/localenv/serverless-check/out.test.toml b/acceptance/localenv/serverless-check/out.test.toml new file mode 100644 index 0000000000..d6187dcb04 --- /dev/null +++ b/acceptance/localenv/serverless-check/out.test.toml @@ -0,0 +1,3 @@ +Local = true +Cloud = false +EnvMatrix.DATABRICKS_BUNDLE_ENGINE = [] diff --git a/acceptance/localenv/serverless-check/output.txt b/acceptance/localenv/serverless-check/output.txt new file mode 100644 index 0000000000..927da068d4 --- /dev/null +++ b/acceptance/localenv/serverless-check/output.txt @@ -0,0 +1,13 @@ + +>>> [CLI] local-env python sync --serverless v4 --check +preflight ok check +resolve ok source=serverless envKey=serverless/serverless-v4 +fetch ok source=[DATABRICKS_URL]/serverless/serverless-v4/pyproject.toml fromCache=false +merge ok +provision ok +validate ok +Plan: [TEST_TMP_DIR]/pyproject.toml + changed region: requires-python + changed region: tool.uv.constraint-dependencies + changed region: databricks-connect +Check complete. No files were modified. diff --git a/acceptance/localenv/serverless-check/script b/acceptance/localenv/serverless-check/script new file mode 100644 index 0000000000..8c202ab129 --- /dev/null +++ b/acceptance/localenv/serverless-check/script @@ -0,0 +1 @@ +trace $CLI local-env python sync --serverless v4 --check diff --git a/acceptance/localenv/serverless-check/test.toml b/acceptance/localenv/serverless-check/test.toml new file mode 100644 index 0000000000..e2b12fc95b --- /dev/null +++ b/acceptance/localenv/serverless-check/test.toml @@ -0,0 +1,21 @@ +EnvMatrix.DATABRICKS_BUNDLE_ENGINE = [] + +[Env] +DATABRICKS_LOCALENV_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]' diff --git a/acceptance/localenv/serverless-json/out.test.toml b/acceptance/localenv/serverless-json/out.test.toml new file mode 100644 index 0000000000..d6187dcb04 --- /dev/null +++ b/acceptance/localenv/serverless-json/out.test.toml @@ -0,0 +1,3 @@ +Local = true +Cloud = false +EnvMatrix.DATABRICKS_BUNDLE_ENGINE = [] diff --git a/acceptance/localenv/serverless-json/output.txt b/acceptance/localenv/serverless-json/output.txt new file mode 100644 index 0000000000..c53fa61031 --- /dev/null +++ b/acceptance/localenv/serverless-json/output.txt @@ -0,0 +1,54 @@ + +>>> [CLI] local-env python sync --serverless v4 --check --output json +{ + "schemaVersion": 1, + "command": "local-env python sync", + "ok": true, + "mode": "default", + "dryRun": true, + "target": { + "source": "serverless", + "serverlessVersion": "v4", + "envKey": "serverless/serverless-v4" + }, + "resolved": { + "pythonVersion": "3.12", + "dbconnectVersion": "17.2.0", + "artifactSource": "network" + }, + "greenfield": true, + "plan": { + "wouldWrite": "[TEST_TMP_DIR]/pyproject.toml", + "wouldInstallPython": "3.12", + "diff": "--- pyproject.toml\n+++ pyproject.toml\n@@ -1 +1,17 @@\n+[project]\n+name = \"001\"\n+version = \"0.0.0\"\n+requires-python = \"\u003e=3.12\"\n+\n+[dependency-groups]\n+dev = [\n+ \"databricks-connect~=17.2.0\",\n+]\n+\n+# managed by databricks local-env python sync — do not edit\n+[tool.uv]\n+constraint-dependencies = [\n+ \"pyarrow\u003c19\",\n+ \"pandas\u003c3\",\n+]\n+# end managed by databricks local-env python sync\n" + }, + "phases": [ + { + "phase": "preflight", + "status": "ok" + }, + { + "phase": "resolve", + "status": "ok" + }, + { + "phase": "fetch", + "status": "ok" + }, + { + "phase": "merge", + "status": "ok" + }, + { + "phase": "provision", + "status": "ok" + }, + { + "phase": "validate", + "status": "ok" + } + ], + "warnings": [], + "error": null, + "durationMs": 0 +} diff --git a/acceptance/localenv/serverless-json/script b/acceptance/localenv/serverless-json/script new file mode 100644 index 0000000000..84ff562045 --- /dev/null +++ b/acceptance/localenv/serverless-json/script @@ -0,0 +1 @@ +trace $CLI local-env python sync --serverless v4 --check --output json diff --git a/acceptance/localenv/serverless-json/test.toml b/acceptance/localenv/serverless-json/test.toml new file mode 100644 index 0000000000..e2b12fc95b --- /dev/null +++ b/acceptance/localenv/serverless-json/test.toml @@ -0,0 +1,21 @@ +EnvMatrix.DATABRICKS_BUNDLE_ENGINE = [] + +[Env] +DATABRICKS_LOCALENV_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]'