Skip to content
This repository was archived by the owner on Aug 30, 2024. It is now read-only.

Commit 7a4312f

Browse files
authored
Show warning on coder-cli / Coder API version mismatch (#158)
1 parent e9b4f97 commit 7a4312f

File tree

6 files changed

+85
-8
lines changed

6 files changed

+85
-8
lines changed

ci/steps/build.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ build() {
1313
echo "Building coder-cli for $GOOS-$GOARCH..."
1414

1515
tmpdir=$(mktemp -d)
16-
go build -ldflags "-X main.version=${tag}" -o "$tmpdir/coder" ../../cmd/coder
16+
go build -ldflags "-X cdr.dev/coder-cli/internal/version.Version=${tag}" -o "$tmpdir/coder" ../../cmd/coder
1717

1818
pushd "$tmpdir"
1919
if [[ "$GOOS" == "windows" ]]; then

cmd/coder/main.go

+2-4
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,10 @@ import (
1111

1212
"cdr.dev/coder-cli/internal/clog"
1313
"cdr.dev/coder-cli/internal/cmd"
14+
"cdr.dev/coder-cli/internal/version"
1415
"cdr.dev/coder-cli/internal/x/xterminal"
1516
)
1617

17-
// Using a global for the version so it can be set at build time using ldflags.
18-
var version = "unknown"
19-
2018
func main() {
2119
ctx, cancel := context.WithCancel(context.Background())
2220
defer cancel()
@@ -39,7 +37,7 @@ func main() {
3937
}()
4038

4139
app := cmd.Make()
42-
app.Version = fmt.Sprintf("%s %s %s/%s", version, runtime.Version(), runtime.GOOS, runtime.GOARCH)
40+
app.Version = fmt.Sprintf("%s %s %s/%s", version.Version, runtime.Version(), runtime.GOOS, runtime.GOARCH)
4341

4442
if err := app.ExecuteContext(ctx); err != nil {
4543
clog.Log(err)

coder-sdk/version.go

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package coder
2+
3+
import (
4+
"context"
5+
"net/http"
6+
)
7+
8+
// APIVersion parses the coder-version http header from an authenticated request.
9+
func (c Client) APIVersion(ctx context.Context) (string, error) {
10+
const coderVersionHeaderKey = "coder-version"
11+
resp, err := c.request(ctx, http.MethodGet, "/api/users/"+Me, nil)
12+
if err != nil {
13+
return "", err
14+
}
15+
16+
version := resp.Header.Get(coderVersionHeaderKey)
17+
if version == "" {
18+
version = "unknown"
19+
}
20+
21+
return version, nil
22+
}

internal/cmd/auth.go

+13-3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package cmd
22

33
import (
44
"context"
5+
"fmt"
56
"net/http"
67
"net/url"
78

@@ -10,6 +11,7 @@ import (
1011
"cdr.dev/coder-cli/coder-sdk"
1112
"cdr.dev/coder-cli/internal/clog"
1213
"cdr.dev/coder-cli/internal/config"
14+
"cdr.dev/coder-cli/internal/version"
1315
)
1416

1517
var errNeedLogin = clog.Fatal(
@@ -18,6 +20,7 @@ var errNeedLogin = clog.Fatal(
1820
)
1921

2022
func newClient() (*coder.Client, error) {
23+
ctx := context.Background()
2124
sessionToken, err := config.Session.Read()
2225
if err != nil {
2326
return nil, errNeedLogin
@@ -38,9 +41,7 @@ func newClient() (*coder.Client, error) {
3841
Token: sessionToken,
3942
}
4043

41-
// Make sure we can make a request so the final
42-
// error is more clean.
43-
_, err = c.Me(context.Background())
44+
apiVersion, err := c.APIVersion(ctx)
4445
if err != nil {
4546
var he *coder.HTTPError
4647
if xerrors.As(err, &he) {
@@ -52,5 +53,14 @@ func newClient() (*coder.Client, error) {
5253
return nil, err
5354
}
5455

56+
if !version.VersionsMatch(apiVersion) {
57+
clog.Log(clog.Warn(
58+
"version mismatch detected",
59+
fmt.Sprintf("coder-cli version: %s", version.Version),
60+
fmt.Sprintf("Coder API version: %s", apiVersion), clog.BlankLine,
61+
clog.Tipf("download the appropriate version here: https://github.com/cdr/coder-cli/releases"),
62+
))
63+
}
64+
5565
return c, nil
5666
}

internal/version/version.go

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package version
2+
3+
import (
4+
"strings"
5+
)
6+
7+
// Version is populated at compile-time with the current coder-cli version.
8+
var Version string = "unknown"
9+
10+
// VersionMatch compares the given APIVersion to the compile-time injected coder-cli version.
11+
func VersionsMatch(apiVersion string) bool {
12+
withoutPatchRelease := strings.Split(Version, ".")
13+
if len(withoutPatchRelease) < 3 {
14+
return false
15+
}
16+
majorMinor := strings.Join(withoutPatchRelease[:len(withoutPatchRelease)-1], ".")
17+
return strings.HasPrefix(strings.TrimPrefix(apiVersion, "v"), strings.TrimPrefix(majorMinor, "v"))
18+
}

internal/version/version_test.go

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package version
2+
3+
import (
4+
"testing"
5+
6+
"cdr.dev/slog/sloggers/slogtest/assert"
7+
)
8+
9+
func TestVersion(t *testing.T) {
10+
Version = "1.12.1"
11+
match := VersionsMatch("1.12.2")
12+
assert.True(t, "versions match", match)
13+
14+
Version = "v1.14.1"
15+
match = VersionsMatch("1.15.2")
16+
assert.True(t, "versions do not match", !match)
17+
18+
Version = "v1.15.4"
19+
match = VersionsMatch("1.15.2")
20+
assert.True(t, "versions do match", match)
21+
22+
Version = "1.15.4"
23+
match = VersionsMatch("v1.15.2")
24+
assert.True(t, "versions do match", match)
25+
26+
Version = "1.15.4"
27+
match = VersionsMatch("v2.15.2")
28+
assert.True(t, "versions do not match", !match)
29+
}

0 commit comments

Comments
 (0)