From 176c5f9df74d46fb4ad077641e8d4c2ba6d0c816 Mon Sep 17 00:00:00 2001 From: Charlie Moog Date: Sat, 24 Oct 2020 18:27:11 -0500 Subject: [PATCH 1/2] Show warning on coder-cli / Coder API error mismatch --- ci/steps/build.sh | 2 +- cmd/coder/main.go | 6 ++---- coder-sdk/request.go | 2 +- coder-sdk/version.go | 22 ++++++++++++++++++++++ internal/cmd/auth.go | 16 +++++++++++++--- internal/version/version.go | 18 ++++++++++++++++++ internal/version/version_test.go | 29 +++++++++++++++++++++++++++++ 7 files changed, 86 insertions(+), 9 deletions(-) create mode 100644 coder-sdk/version.go create mode 100644 internal/version/version.go create mode 100644 internal/version/version_test.go diff --git a/ci/steps/build.sh b/ci/steps/build.sh index 6307c0d7..64ef65b2 100755 --- a/ci/steps/build.sh +++ b/ci/steps/build.sh @@ -13,7 +13,7 @@ build() { echo "Building coder-cli for $GOOS-$GOARCH..." tmpdir=$(mktemp -d) - go build -ldflags "-X main.version=${tag}" -o "$tmpdir/coder" ../../cmd/coder + go build -ldflags "-X cdr.dev/coder-cli/internal/version.Version=${tag}" -o "$tmpdir/coder" ../../cmd/coder pushd "$tmpdir" if [[ "$GOOS" == "windows" ]]; then diff --git a/cmd/coder/main.go b/cmd/coder/main.go index 8ba4ab19..d59a1abe 100644 --- a/cmd/coder/main.go +++ b/cmd/coder/main.go @@ -11,12 +11,10 @@ import ( "cdr.dev/coder-cli/internal/clog" "cdr.dev/coder-cli/internal/cmd" + "cdr.dev/coder-cli/internal/version" "cdr.dev/coder-cli/internal/x/xterminal" ) -// Using a global for the version so it can be set at build time using ldflags. -var version = "unknown" - func main() { ctx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -39,7 +37,7 @@ func main() { }() app := cmd.Make() - app.Version = fmt.Sprintf("%s %s %s/%s", version, runtime.Version(), runtime.GOOS, runtime.GOARCH) + app.Version = fmt.Sprintf("%s %s %s/%s", version.Version, runtime.Version(), runtime.GOOS, runtime.GOARCH) if err := app.ExecuteContext(ctx); err != nil { clog.Log(err) diff --git a/coder-sdk/request.go b/coder-sdk/request.go index 4ae2bdf2..1be30882 100644 --- a/coder-sdk/request.go +++ b/coder-sdk/request.go @@ -61,4 +61,4 @@ func (c Client) requestBody(ctx context.Context, method, path string, in, out in } } return nil -} +} \ No newline at end of file diff --git a/coder-sdk/version.go b/coder-sdk/version.go new file mode 100644 index 00000000..a2211afe --- /dev/null +++ b/coder-sdk/version.go @@ -0,0 +1,22 @@ +package coder + +import ( + "context" + "net/http" +) + +// APIVersion parses the coder-version http header from an authenticated request. +func (c Client) APIVersion(ctx context.Context) (string, error) { + const coderVersionHeaderKey = "coder-version" + resp, err := c.request(ctx, http.MethodGet, "/api/users/"+Me, nil) + if err != nil { + return "", err + } + + version := resp.Header.Get(coderVersionHeaderKey) + if version == "" { + version = "unknown" + } + + return version, nil +} diff --git a/internal/cmd/auth.go b/internal/cmd/auth.go index b0105ac4..b048593c 100644 --- a/internal/cmd/auth.go +++ b/internal/cmd/auth.go @@ -2,6 +2,7 @@ package cmd import ( "context" + "fmt" "net/http" "net/url" @@ -10,6 +11,7 @@ import ( "cdr.dev/coder-cli/coder-sdk" "cdr.dev/coder-cli/internal/clog" "cdr.dev/coder-cli/internal/config" + "cdr.dev/coder-cli/internal/version" ) var errNeedLogin = clog.Fatal( @@ -18,6 +20,7 @@ var errNeedLogin = clog.Fatal( ) func newClient() (*coder.Client, error) { + ctx := context.Background() sessionToken, err := config.Session.Read() if err != nil { return nil, errNeedLogin @@ -38,9 +41,7 @@ func newClient() (*coder.Client, error) { Token: sessionToken, } - // Make sure we can make a request so the final - // error is more clean. - _, err = c.Me(context.Background()) + apiVersion, err := c.APIVersion(ctx) if err != nil { var he *coder.HTTPError if xerrors.As(err, &he) { @@ -52,5 +53,14 @@ func newClient() (*coder.Client, error) { return nil, err } + if !version.VersionsMatch(apiVersion) { + clog.Log(clog.Warn( + "version mismatch detected", + fmt.Sprintf("coder-cli version: %s", version.Version), + fmt.Sprintf("Coder API version: %s", apiVersion), clog.BlankLine, + clog.Tipf("download the appropriate version here: https://github.com/cdr/coder-cli/releases"), + )) + } + return c, nil } diff --git a/internal/version/version.go b/internal/version/version.go new file mode 100644 index 00000000..00effefa --- /dev/null +++ b/internal/version/version.go @@ -0,0 +1,18 @@ +package version + +import ( + "strings" +) + +// Version is populated at compile-time with the current coder-cli version. +var Version string = "unknown" + +// VersionMatch compares the given APIVersion to the compile-time injected coder-cli version. +func VersionsMatch(apiVersion string) bool { + withoutPatchRelease := strings.Split(Version, ".") + if len(withoutPatchRelease) < 3 { + return false + } + majorMinor := strings.Join(withoutPatchRelease[:len(withoutPatchRelease)-1], ".") + return strings.HasPrefix(strings.TrimPrefix(apiVersion, "v"), strings.TrimPrefix(majorMinor, "v")) +} diff --git a/internal/version/version_test.go b/internal/version/version_test.go new file mode 100644 index 00000000..83aeb0b1 --- /dev/null +++ b/internal/version/version_test.go @@ -0,0 +1,29 @@ +package version + +import ( + "testing" + + "cdr.dev/slog/sloggers/slogtest/assert" +) + +func TestVersion(t *testing.T) { + Version = "1.12.1" + match := VersionsMatch("1.12.2") + assert.True(t, "versions match", match) + + Version = "v1.14.1" + match = VersionsMatch("1.15.2") + assert.True(t, "versions do not match", !match) + + Version = "v1.15.4" + match = VersionsMatch("1.15.2") + assert.True(t, "versions do match", match) + + Version = "1.15.4" + match = VersionsMatch("v1.15.2") + assert.True(t, "versions do match", match) + + Version = "1.15.4" + match = VersionsMatch("v2.15.2") + assert.True(t, "versions do not match", !match) +} \ No newline at end of file From 729bb0609f22bb8b3a10d56d512781154f5b3278 Mon Sep 17 00:00:00 2001 From: Charlie Moog Date: Sat, 24 Oct 2020 18:30:55 -0500 Subject: [PATCH 2/2] fixup! Show warning on coder-cli / Coder API error mismatch --- coder-sdk/request.go | 2 +- internal/version/version_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/coder-sdk/request.go b/coder-sdk/request.go index 1be30882..4ae2bdf2 100644 --- a/coder-sdk/request.go +++ b/coder-sdk/request.go @@ -61,4 +61,4 @@ func (c Client) requestBody(ctx context.Context, method, path string, in, out in } } return nil -} \ No newline at end of file +} diff --git a/internal/version/version_test.go b/internal/version/version_test.go index 83aeb0b1..9791717e 100644 --- a/internal/version/version_test.go +++ b/internal/version/version_test.go @@ -26,4 +26,4 @@ func TestVersion(t *testing.T) { Version = "1.15.4" match = VersionsMatch("v2.15.2") assert.True(t, "versions do not match", !match) -} \ No newline at end of file +}