Skip to content

Commit 9eb7725

Browse files
authored
Add databricks version --check to check for available CLI updates (#5469)
## Why `databricks version` (and `databricks --version`) only prints the version you're on. There's no way to tell whether you're behind, and even once you know, the command to upgrade depends on how you installed the CLI (Homebrew, WinGet, Chocolatey, or the install script). A version check also shouldn't be fragile: if GitHub is slow or unreachable it must not hang or fail the command. ## Changes Before: `databricks version` prints the current version and nothing else. Now: `databricks version --check` fetches the latest release from GitHub, compares it with the running build, and prints the upgrade command for your install method: ``` Databricks CLI v0.240.0 A new version is available: 0.245.0 To upgrade, run: brew upgrade databricks ``` Per review feedback this is the only way to run the check (the `version check` subcommand from an earlier revision is gone). Bare `databricks version` and `databricks --version` stay lightweight and identical to today: no network call, no output change. Details: - New `libs/versioncheck` package fetches `api.github.com/repos/databricks/cli/releases/latest`, semver-compares, and infers the install method from the executable path (resolving symlinks so a Homebrew shim classifies as Homebrew, not the install script). - The lookup is capped at 2s. If GitHub is unreachable, times out, or rate-limits, the check fails gently: it prints that it couldn't reach GitHub and links to the releases page, and still exits 0 instead of erroring. - Development and snapshot builds short-circuit without a network call. - `databricks version --check --output json` returns the structured result (including `check_failed`) for scripting. First PR in a two-PR stack; the follow-up (#5470) adds a passive once-per-day notice. ## Test plan - [x] Unit tests: install-method detection across OSes, semver comparison, and the full check against a mock server (update available, up to date, dev build, server error fails gently, unreachable fails gently). - [x] White-box render tests asserting exact output for all states, including the "couldn't reach GitHub" message. - [x] Acceptance test (`acceptance/cmd/version`) covering lightweight `version`, `version --check`, and `version --check --output json`. - [x] Full local acceptance suite (`go test ./acceptance`), including the `help` output test. - [x] `./task fmt`, lint on changed packages, and `./task checks` clean. This pull request and its description were written by Isaac.
1 parent 97eef66 commit 9eb7725

9 files changed

Lines changed: 502 additions & 1 deletion

File tree

NEXT_CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@
77

88
### CLI
99
* Added the `databricks quickstart` command, a short introduction to the CLI that prints a human-friendly guide interactively and an agent-oriented version when run non-interactively ([#5464](https://github.com/databricks/cli/pull/5464)).
10+
* Add `databricks version --check` to report whether a newer CLI version is available and print the upgrade command for the detected install method ([#5469](https://github.com/databricks/cli/pull/5469)).
1011
* `databricks auth describe` now verifies credentials against both the workspace and account endpoints before reporting a failure, fixing false "Unable to authenticate" errors for account console profiles ([#5479](https://github.com/databricks/cli/issues/5479)).
1112
* `databricks auth login` no longer prompts for workspace selection when logging in to an account console host (`https://accounts.*`). Pass `--workspace-id` explicitly to store a workspace ID on such a profile ([#5504](https://github.com/databricks/cli/pull/5504)).
1213
* `databricks auth profiles --skip-validate` no longer makes any network calls; the host metadata fetch is skipped along with validation ([#5530](https://github.com/databricks/cli/pull/5530)).
1314

1415

16+
1517
### Bundles
1618
* Set the default `data_security_mode` to `DATA_SECURITY_MODE_AUTO` in bundle templates ([#5452](https://github.com/databricks/cli/pull/5452)).
1719
* Mark vector search index index_subtype as backend_default to prevent drift after deployment ([#5454](https://github.com/databricks/cli/pull/5454)).

acceptance/cmd/version/out.test.toml

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

acceptance/cmd/version/output.txt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
2+
=== version stays lightweight
3+
4+
>>> [CLI] version
5+
Databricks CLI v[DEV_VERSION]
6+
7+
=== version --check
8+
9+
>>> [CLI] version --check
10+
Databricks CLI v[DEV_VERSION]
11+
This is a development build; skipping the update check.
12+
13+
=== version --check --output json
14+
15+
>>> [CLI] version --check --output json
16+
{
17+
"current_version": "[DEV_VERSION]",
18+
"update_available": false,
19+
"development_build": true
20+
}

acceptance/cmd/version/script

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
title "version stays lightweight\n"
2+
trace $CLI version
3+
4+
# The acceptance binary is a development build, so the check short-circuits
5+
# without contacting GitHub. This exercises command wiring and output rendering.
6+
title "version --check\n"
7+
trace $CLI version --check
8+
9+
title "version --check --output json\n"
10+
trace $CLI version --check --output json

acceptance/cmd/version/test.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# The update check is not bundle-aware; run it once instead of per-engine.
2+
[EnvMatrix]
3+
DATABRICKS_BUNDLE_ENGINE = []

cmd/version/version.go

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,30 @@ import (
66
"github.com/databricks/cli/cmd/root"
77
"github.com/databricks/cli/internal/build"
88
"github.com/databricks/cli/libs/cmdio"
9+
"github.com/databricks/cli/libs/versioncheck"
910
"github.com/spf13/cobra"
1011
)
1112

13+
// updateCheckTemplate renders an update check in text mode. JSON output is
14+
// rendered directly from the versioncheck.Result struct by cmdio.
15+
const updateCheckTemplate = `Databricks CLI v{{.CurrentVersion}}
16+
{{if .DevelopmentBuild -}}
17+
This is a development build; skipping the update check.
18+
{{- else if .CheckFailed -}}
19+
Could not reach GitHub to check for a newer version. See https://github.com/databricks/cli/releases for the latest release.
20+
{{- else if .UpdateAvailable -}}
21+
{{yellow "A new version is available"}}: {{.LatestVersion}}
22+
{{if .UpgradeCommand -}}
23+
To upgrade, run:
24+
{{.UpgradeCommand}}
25+
{{- else -}}
26+
Download the latest release: https://github.com/databricks/cli/releases
27+
{{- end}}
28+
{{- else -}}
29+
{{green "You're on the latest version."}}
30+
{{- end}}
31+
`
32+
1233
func New() *cobra.Command {
1334
cmd := &cobra.Command{
1435
Use: "version",
@@ -19,8 +40,15 @@ func New() *cobra.Command {
1940
},
2041
}
2142

43+
var check bool
44+
cmd.Flags().BoolVar(&check, "check", false, "Check whether a newer version of the CLI is available")
45+
2246
cmd.RunE = func(cmd *cobra.Command, args []string) error {
23-
return cmdio.Render(cmd.Context(), build.GetInfo())
47+
ctx := cmd.Context()
48+
if check {
49+
return cmdio.RenderWithTemplate(ctx, versioncheck.Check(ctx), "", updateCheckTemplate)
50+
}
51+
return cmdio.Render(ctx, build.GetInfo())
2452
}
2553

2654
return cmd

cmd/version/version_test.go

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package version
2+
3+
import (
4+
"testing"
5+
6+
"github.com/databricks/cli/libs/cmdio"
7+
"github.com/databricks/cli/libs/versioncheck"
8+
"github.com/stretchr/testify/assert"
9+
"github.com/stretchr/testify/require"
10+
)
11+
12+
func TestUpdateCheckTemplate(t *testing.T) {
13+
tests := []struct {
14+
name string
15+
result versioncheck.Result
16+
want string
17+
}{
18+
{
19+
name: "update available with upgrade command",
20+
result: versioncheck.Result{
21+
CurrentVersion: "0.240.0",
22+
LatestVersion: "0.245.0",
23+
UpdateAvailable: true,
24+
InstallMethod: versioncheck.InstallHomebrew,
25+
UpgradeCommand: "brew upgrade databricks",
26+
},
27+
want: `Databricks CLI v0.240.0
28+
A new version is available: 0.245.0
29+
To upgrade, run:
30+
brew upgrade databricks
31+
`,
32+
},
33+
{
34+
name: "update available without known install method",
35+
result: versioncheck.Result{
36+
CurrentVersion: "0.240.0",
37+
LatestVersion: "0.245.0",
38+
UpdateAvailable: true,
39+
InstallMethod: versioncheck.InstallUnknown,
40+
},
41+
want: `Databricks CLI v0.240.0
42+
A new version is available: 0.245.0
43+
Download the latest release: https://github.com/databricks/cli/releases
44+
`,
45+
},
46+
{
47+
name: "up to date",
48+
result: versioncheck.Result{
49+
CurrentVersion: "0.245.0",
50+
LatestVersion: "0.245.0",
51+
UpdateAvailable: false,
52+
},
53+
want: `Databricks CLI v0.245.0
54+
You're on the latest version.
55+
`,
56+
},
57+
{
58+
name: "development build",
59+
result: versioncheck.Result{
60+
CurrentVersion: "0.0.0-dev+abc123",
61+
DevelopmentBuild: true,
62+
},
63+
want: `Databricks CLI v0.0.0-dev+abc123
64+
This is a development build; skipping the update check.
65+
`,
66+
},
67+
{
68+
name: "check failed",
69+
result: versioncheck.Result{
70+
CurrentVersion: "0.240.0",
71+
CheckFailed: true,
72+
},
73+
want: `Databricks CLI v0.240.0
74+
Could not reach GitHub to check for a newer version. See https://github.com/databricks/cli/releases for the latest release.
75+
`,
76+
},
77+
}
78+
79+
for _, tt := range tests {
80+
t.Run(tt.name, func(t *testing.T) {
81+
ctx, out := cmdio.NewTestContextWithStdout(t.Context())
82+
err := cmdio.RenderWithTemplate(ctx, tt.result, "", updateCheckTemplate)
83+
require.NoError(t, err)
84+
assert.Equal(t, tt.want, out.String())
85+
})
86+
}
87+
}

0 commit comments

Comments
 (0)