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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 2 additions & 4 deletions
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

Lines changed: 22 additions & 0 deletions
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

Lines changed: 13 additions & 3 deletions
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

Lines changed: 18 additions & 0 deletions
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

Lines changed: 29 additions & 0 deletions
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy