From 054f1fb8833589f755557bf2abb59c25ef66ca7c Mon Sep 17 00:00:00 2001 From: Cian Johnston Date: Fri, 8 Oct 2021 10:39:32 +0000 Subject: [PATCH 1/7] refactor: stop hard-coding tgz bytes in unit test --- internal/cmd/update_test.go | 75 ++++++++++++++++++++++++++++++------- 1 file changed, 61 insertions(+), 14 deletions(-) diff --git a/internal/cmd/update_test.go b/internal/cmd/update_test.go index 6f0a63c1..e6d67a88 100644 --- a/internal/cmd/update_test.go +++ b/internal/cmd/update_test.go @@ -1,10 +1,13 @@ package cmd import ( + "archive/tar" "bytes" + "compress/gzip" "context" "encoding/base64" "fmt" + "io" "io/fs" "io/ioutil" "net/http" @@ -39,6 +42,7 @@ var ( fakeError = xerrors.New("fake error for testing") fakeNewVersionJSON = fmt.Sprintf(`{"version":%q}`, fakeNewVersion) fakeOldVersionJSON = fmt.Sprintf(`{"version":%q}`, fakeOldVersion) + fakeNewVersionTgz = mustValidTgz("coder", []byte(fakeNewVersion), 0751) fakeAssetURLLinux = "https://github.com/cdr/coder-cli/releases/download/v1.23.4-rc.5/" + filenameLinux fakeAssetURLWindows = "https://github.com/cdr/coder-cli/releases/download/v1.23.4-rc.5/" + filenameWindows fakeGithubReleaseJSON = fmt.Sprintf(`{"assets":[{"name":%q,"browser_download_url":%q},{"name":%q,"browser_download_url":%q}]}`, filenameLinux, fakeAssetURLLinux, filenameWindows, fakeAssetURLWindows) @@ -133,7 +137,7 @@ func Test_updater_run(t *testing.T) { fakeFile(t, p.Fakefs, fakeExePathLinux, 0755, fakeOldVersion) p.HTTPClient.M[apiPrivateVersionURL] = newFakeGetterResponse([]byte(fakeOldVersionJSON), 200, variadicS(), nil) p.HTTPClient.M[fakeGithubReleaseURL] = newFakeGetterResponse([]byte(fakeGithubReleaseJSON), 200, variadicS(), nil) - p.HTTPClient.M[fakeAssetURLLinux] = newFakeGetterResponse(fakeValidTgzBytes, 200, variadicS(), nil) + p.HTTPClient.M[fakeAssetURLLinux] = newFakeGetterResponse(fakeNewVersionTgz, 200, variadicS(), nil) p.VersionF = func() string { return fakeOldVersion } p.ConfirmF = fakeConfirmYes p.Execer.M[p.ExecutablePath+".new --version"] = fakeExecerResult{[]byte(fakeNewVersion), nil} @@ -150,7 +154,7 @@ func Test_updater_run(t *testing.T) { fakeFile(t, p.Fakefs, fakeExePathLinux, 0755, fakeOldVersion) p.HTTPClient.M[apiPrivateVersionURL] = newFakeGetterResponse([]byte(fakeOldVersionJSON), 200, variadicS(), nil) p.HTTPClient.M[fakeGithubReleaseURL] = newFakeGetterResponse([]byte(fakeGithubReleaseJSON), 200, variadicS(), nil) - p.HTTPClient.M[fakeAssetURLLinux] = newFakeGetterResponse(fakeValidTgzBytes, 200, variadicS(), nil) + p.HTTPClient.M[fakeAssetURLLinux] = newFakeGetterResponse(fakeNewVersionTgz, 200, variadicS(), nil) p.VersionF = func() string { return fakeOldVersion } p.ConfirmF = fakeConfirmYes p.Execer.M[p.ExecutablePath+".new --version"] = fakeExecerResult{[]byte(fakeNewVersion), nil} @@ -165,7 +169,7 @@ func Test_updater_run(t *testing.T) { fakeFile(t, p.Fakefs, fakeExePathLinux, 0755, fakeOldVersion) p.HTTPClient.M[apiPrivateVersionURL] = newFakeGetterResponse([]byte(fakeNewVersionJSON), 200, variadicS(), nil) p.HTTPClient.M[fakeGithubReleaseURL] = newFakeGetterResponse([]byte(fakeGithubReleaseJSON), 200, variadicS(), nil) - p.HTTPClient.M[fakeAssetURLLinux] = newFakeGetterResponse(fakeValidTgzBytes, 200, variadicS(), nil) + p.HTTPClient.M[fakeAssetURLLinux] = newFakeGetterResponse(fakeNewVersionTgz, 200, variadicS(), nil) p.VersionF = func() string { return fakeOldVersion } p.ConfirmF = fakeConfirmYes p.Execer.M[p.ExecutablePath+".new --version"] = fakeExecerResult{[]byte(fakeNewVersion), nil} @@ -182,7 +186,7 @@ func Test_updater_run(t *testing.T) { fakeFile(t, p.Fakefs, fakeExePathLinux, 0755, fakeOldVersion) p.HTTPClient.M[apiPrivateVersionURL] = newFakeGetterResponse([]byte(fakeNewVersionJSON), 200, variadicS(), nil) p.HTTPClient.M[fakeGithubReleaseURL] = newFakeGetterResponse([]byte(fakeGithubReleaseJSON), 200, variadicS(), nil) - p.HTTPClient.M[fakeAssetURLLinux] = newFakeGetterResponse(fakeValidTgzBytes, 200, variadicS(), nil) + p.HTTPClient.M[fakeAssetURLLinux] = newFakeGetterResponse(fakeNewVersionTgz, 200, variadicS(), nil) p.VersionF = func() string { return fakeOldVersion } p.ConfirmF = fakeConfirmYes p.Execer.M[p.ExecutablePath+".new --version"] = fakeExecerResult{[]byte(fakeNewVersion), nil} @@ -198,7 +202,7 @@ func Test_updater_run(t *testing.T) { fakeFile(t, p.Fakefs, p.ExecutablePath, 0755, fakeOldVersion) p.HTTPClient.M[apiPrivateVersionURL] = newFakeGetterResponse([]byte(fakeNewVersionJSON), 200, variadicS(), nil) p.HTTPClient.M[fakeGithubReleaseURL] = newFakeGetterResponse([]byte(fakeGithubReleaseJSON), 200, variadicS(), nil) - p.HTTPClient.M[fakeAssetURLLinux] = newFakeGetterResponse(fakeValidTgzBytes, 200, variadicS(), nil) + p.HTTPClient.M[fakeAssetURLLinux] = newFakeGetterResponse(fakeNewVersionTgz, 200, variadicS(), nil) p.VersionF = func() string { return fakeOldVersion } p.ConfirmF = fakeConfirmYes p.Execer.M[p.ExecutablePath+".new --version"] = fakeExecerResult{[]byte(fakeNewVersion), nil} @@ -230,7 +234,7 @@ func Test_updater_run(t *testing.T) { fakeFile(t, p.Fakefs, fakeExePathLinux, 0755, fakeOldVersion) p.HTTPClient.M[apiPrivateVersionURL] = newFakeGetterResponse([]byte(fakeNewVersionJSON), 200, variadicS(), nil) p.HTTPClient.M[fakeGithubReleaseURL] = newFakeGetterResponse([]byte(fakeGithubReleaseJSON), 200, variadicS(), nil) - p.HTTPClient.M[fakeAssetURLLinux] = newFakeGetterResponse(fakeValidTgzBytes, 200, variadicS(), nil) + p.HTTPClient.M[fakeAssetURLLinux] = newFakeGetterResponse(fakeNewVersionTgz, 200, variadicS(), nil) p.VersionF = func() string { return fakeOldVersion } p.Execer.M[p.ExecutablePath+".new --version"] = fakeExecerResult{[]byte(fakeNewVersion), nil} u := fromParams(p) @@ -375,7 +379,7 @@ func Test_updater_run(t *testing.T) { fakeFile(t, rwfs, fakeExePathLinux, 0755, fakeOldVersion) p.HTTPClient.M[apiPrivateVersionURL] = newFakeGetterResponse([]byte(fakeNewVersionJSON), 200, variadicS(), nil) p.HTTPClient.M[fakeGithubReleaseURL] = newFakeGetterResponse([]byte(fakeGithubReleaseJSON), 200, variadicS(), nil) - p.HTTPClient.M[fakeAssetURLLinux] = newFakeGetterResponse(fakeValidTgzBytes, 200, variadicS(), nil) + p.HTTPClient.M[fakeAssetURLLinux] = newFakeGetterResponse(fakeNewVersionTgz, 200, variadicS(), nil) p.VersionF = func() string { return fakeOldVersion } p.ConfirmF = fakeConfirmYes u := fromParams(p) @@ -389,7 +393,7 @@ func Test_updater_run(t *testing.T) { fakeFile(t, p.Fakefs, fakeExePathLinux, 0755, fakeOldVersion) p.HTTPClient.M[apiPrivateVersionURL] = newFakeGetterResponse([]byte(fakeNewVersionJSON), 200, variadicS(), nil) p.HTTPClient.M[fakeGithubReleaseURL] = newFakeGetterResponse([]byte(fakeGithubReleaseJSON), 200, variadicS(), nil) - p.HTTPClient.M[fakeAssetURLLinux] = newFakeGetterResponse(fakeValidTgzBytes, 200, variadicS(), nil) + p.HTTPClient.M[fakeAssetURLLinux] = newFakeGetterResponse(fakeNewVersionTgz, 200, variadicS(), nil) p.VersionF = func() string { return fakeOldVersion } p.ConfirmF = fakeConfirmYes p.Execer.M[p.ExecutablePath+".new --version"] = fakeExecerResult{nil, fakeError} @@ -574,12 +578,6 @@ func assertCLIError(t *testing.T, name string, err error, expectedHeader, expect } } -// this is a valid tgz archive containing a single file named 'coder' with permissions 0751 -// containing the string "1.23.4-rc.5+678-gabcdef-12345678". -var fakeValidTgzBytes, _ = base64.StdEncoding.DecodeString(`H4sIAAAAAAAAA+3QsQ4CIRCEYR6F3oC7wIqvc3KnpQnq+3tGCwsTK3LN/zWTTDWZuG/XeeluJFlV -s1dqNfnOtyJOi4qllHOuTlSTqPMydNXH43afuvfu3w3jb9qExpRjCb1F2x3qMVymU5uXc9CUi63F -1vsAAAAAAAAAAAAAAAAAAL89AYuL424AKAAA`) - // this is a valid zip archive containing a single file named 'coder.exe' with permissions 0751 // containing the string "1.23.4-rc.5+678-gabcdef-12345678". var fakeValidZipBytes, _ = base64.StdEncoding.DecodeString(`UEsDBAoAAAAAAAtfDVNCHNDCIAAAACAAAAAJABwAY29kZXIuZXhlVVQJAAPmXRZh/10WYXV4CwAB @@ -587,6 +585,55 @@ BOgDAAAE6AMAADEuMjMuNC1yYy41KzY3OC1nYWJjZGVmLTEyMzQ1Njc4UEsBAh4DCgAAAAAAC18N U0Ic0MIgAAAAIAAAAAkAGAAAAAAAAQAAAO2BAAAAAGNvZGVyLmV4ZVVUBQAD5l0WYXV4CwABBOgD AAAE6AMAAFBLBQYAAAAAAQABAE8AAABjAAAAAAA=`) +// mustValidTgz creates a valid tgz file and panics if any error is encountered. +// only for use in unit tests. +func mustValidTgz(filename string, data []byte, perms os.FileMode) []byte { + must := func(err error, msg string) { + if err != nil { + panic(xerrors.Errorf("%s: %w", msg, err)) + } + } + fs := afero.NewMemMapFs() + // populate memfs with file + f, err := fs.Create(filename) + must(err, "create file") + _, err = f.Write(data) + must(err, "write data") + err = f.Close() + must(err, "close file") + err = fs.Chmod(filename, perms) + must(err, "set perms") + + // create archive from fs + + f, err = fs.Open(filename) + must(err, "open file") + fsinfo, err := f.Stat() + must(err, "stat file") + header, err := tar.FileInfoHeader(fsinfo, fsinfo.Name()) + must(err, "create tar header") + header.Name = filename + + var buf bytes.Buffer + gw := gzip.NewWriter(&buf) + tw := tar.NewWriter(gw) + + err = tw.WriteHeader(header) + must(err, "write header") + _, err = io.Copy(tw, f) + must(err, "write file") + err = f.Close() + must(err, "close file") + err = tw.Close() + must(err, "close tar writer") + err = gw.Close() + must(err, "close gzip writer") + + return buf.Bytes() +} + +var _ = mustValidTgz("testing", []byte("testing"), 0777) + type fakeExecer struct { M map[string]fakeExecerResult T *testing.T From 66d7fb9367969dda46faf6c0f1a4868b9a7a5f87 Mon Sep 17 00:00:00 2001 From: Cian Johnston Date: Fri, 8 Oct 2021 10:48:48 +0000 Subject: [PATCH 2/7] refactor: stop hard-coding zip data in unit tests --- internal/cmd/update_test.go | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/internal/cmd/update_test.go b/internal/cmd/update_test.go index e6d67a88..87b1bda2 100644 --- a/internal/cmd/update_test.go +++ b/internal/cmd/update_test.go @@ -2,10 +2,10 @@ package cmd import ( "archive/tar" + "archive/zip" "bytes" "compress/gzip" "context" - "encoding/base64" "fmt" "io" "io/fs" @@ -43,6 +43,7 @@ var ( fakeNewVersionJSON = fmt.Sprintf(`{"version":%q}`, fakeNewVersion) fakeOldVersionJSON = fmt.Sprintf(`{"version":%q}`, fakeOldVersion) fakeNewVersionTgz = mustValidTgz("coder", []byte(fakeNewVersion), 0751) + fakeNewVersionZip = mustValidZip("coder.exe", []byte(fakeNewVersion)) fakeAssetURLLinux = "https://github.com/cdr/coder-cli/releases/download/v1.23.4-rc.5/" + filenameLinux fakeAssetURLWindows = "https://github.com/cdr/coder-cli/releases/download/v1.23.4-rc.5/" + filenameWindows fakeGithubReleaseJSON = fmt.Sprintf(`{"assets":[{"name":%q,"browser_download_url":%q},{"name":%q,"browser_download_url":%q}]}`, filenameLinux, fakeAssetURLLinux, filenameWindows, fakeAssetURLWindows) @@ -219,7 +220,7 @@ func Test_updater_run(t *testing.T) { fakeFile(t, p.Fakefs, fakeExePathWindows, 0755, fakeOldVersion) p.HTTPClient.M[apiPrivateVersionURL] = newFakeGetterResponse([]byte(fakeNewVersionJSON), 200, variadicS(), nil) p.HTTPClient.M[fakeGithubReleaseURL] = newFakeGetterResponse([]byte(fakeGithubReleaseJSON), 200, variadicS(), nil) - p.HTTPClient.M[fakeAssetURLWindows] = newFakeGetterResponse(fakeValidZipBytes, 200, variadicS(), nil) + p.HTTPClient.M[fakeAssetURLWindows] = newFakeGetterResponse(fakeNewVersionZip, 200, variadicS(), nil) p.VersionF = func() string { return fakeOldVersion } p.ConfirmF = fakeConfirmYes p.Execer.M[p.ExecutablePath+".new --version"] = fakeExecerResult{[]byte(fakeNewVersion), nil} @@ -578,13 +579,6 @@ func assertCLIError(t *testing.T, name string, err error, expectedHeader, expect } } -// this is a valid zip archive containing a single file named 'coder.exe' with permissions 0751 -// containing the string "1.23.4-rc.5+678-gabcdef-12345678". -var fakeValidZipBytes, _ = base64.StdEncoding.DecodeString(`UEsDBAoAAAAAAAtfDVNCHNDCIAAAACAAAAAJABwAY29kZXIuZXhlVVQJAAPmXRZh/10WYXV4CwAB -BOgDAAAE6AMAADEuMjMuNC1yYy41KzY3OC1nYWJjZGVmLTEyMzQ1Njc4UEsBAh4DCgAAAAAAC18N -U0Ic0MIgAAAAIAAAAAkAGAAAAAAAAQAAAO2BAAAAAGNvZGVyLmV4ZVVUBQAD5l0WYXV4CwABBOgD -AAAE6AMAAFBLBQYAAAAAAQABAE8AAABjAAAAAAA=`) - // mustValidTgz creates a valid tgz file and panics if any error is encountered. // only for use in unit tests. func mustValidTgz(filename string, data []byte, perms os.FileMode) []byte { @@ -632,7 +626,28 @@ func mustValidTgz(filename string, data []byte, perms os.FileMode) []byte { return buf.Bytes() } +// mustValidZip creates a valid zip file and panics if any error is encountered. +// only for use in unit tests. +func mustValidZip(filename string, data []byte) []byte { + must := func(err error, msg string) { + if err != nil { + panic(xerrors.Errorf("%s: %w", msg, err)) + } + } + var buf bytes.Buffer + zw := zip.NewWriter(&buf) + w, err := zw.Create(filename) + must(err, "create zip archive") + _, err = io.Copy(w, bytes.NewReader(data)) + must(err, "write file") + err = zw.Close() + must(err, "close gzip writer") + + return buf.Bytes() +} + var _ = mustValidTgz("testing", []byte("testing"), 0777) +var _ = mustValidZip("testing", []byte("testing")) type fakeExecer struct { M map[string]fakeExecerResult From 088e37812b6cbd2464d6aab108a34c40c231d821 Mon Sep 17 00:00:00 2001 From: Cian Johnston Date: Fri, 8 Oct 2021 10:58:55 +0000 Subject: [PATCH 3/7] feat(cli): update: handle cli hotfix versions: add red unit test --- internal/cmd/update_test.go | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/internal/cmd/update_test.go b/internal/cmd/update_test.go index 87b1bda2..ded18354 100644 --- a/internal/cmd/update_test.go +++ b/internal/cmd/update_test.go @@ -32,6 +32,7 @@ const ( fakeCoderURL = "https://my.cdr.dev" fakeNewVersion = "1.23.4-rc.5+678-gabcdef-12345678" fakeOldVersion = "1.22.4-rc.5+678-gabcdef-12345678" + fakeHotfixVersion = "1.23.4-rc.5+678-gabcdef-12345678.cli.2" filenameLinux = "coder-cli-linux-amd64.tar.gz" filenameWindows = "coder-cli-windows.zip" fakeGithubReleaseURL = "https://api.github.com/repos/cdr/coder-cli/releases/tags/v1.23.4-rc.5" @@ -42,7 +43,9 @@ var ( fakeError = xerrors.New("fake error for testing") fakeNewVersionJSON = fmt.Sprintf(`{"version":%q}`, fakeNewVersion) fakeOldVersionJSON = fmt.Sprintf(`{"version":%q}`, fakeOldVersion) + fakeHotfixVersionJSON = fmt.Sprintf(`{"version":%q}`, fakeHotfixVersion) fakeNewVersionTgz = mustValidTgz("coder", []byte(fakeNewVersion), 0751) + fakeHotfixVersionTgz = mustValidTgz("coder", []byte(fakeHotfixVersion), 0751) fakeNewVersionZip = mustValidZip("coder.exe", []byte(fakeNewVersion)) fakeAssetURLLinux = "https://github.com/cdr/coder-cli/releases/download/v1.23.4-rc.5/" + filenameLinux fakeAssetURLWindows = "https://github.com/cdr/coder-cli/releases/download/v1.23.4-rc.5/" + filenameWindows @@ -198,6 +201,38 @@ func Test_updater_run(t *testing.T) { assertFileContent(t, p.Fakefs, fakeExePathLinux, strings.TrimPrefix(fakeNewVersion, "v")) // TODO: stop hard-coding this }) + run(t, "update coder - new to hotfix", func(t *testing.T, p *params) { + fakeFile(t, p.Fakefs, fakeExePathLinux, 0755, fakeNewVersion) + p.HTTPClient.M[apiPrivateVersionURL] = newFakeGetterResponse([]byte(fakeHotfixVersionJSON), 200, variadicS(), nil) + p.HTTPClient.M[fakeGithubReleaseURL] = newFakeGetterResponse([]byte(fakeGithubReleaseJSON), 200, variadicS(), nil) + p.HTTPClient.M[fakeAssetURLLinux] = newFakeGetterResponse(fakeHotfixVersionTgz, 200, variadicS(), nil) + p.VersionF = func() string { return fakeNewVersion } + p.ConfirmF = fakeConfirmYes + p.Execer.M[p.ExecutablePath+".new --version"] = fakeExecerResult{[]byte(fakeNewVersion), nil} + u := fromParams(p) + assertFileContent(t, p.Fakefs, fakeExePathLinux, fakeNewVersion) + err := u.Run(p.Ctx, false, fakeCoderURL, "") + assert.Success(t, "update coder - new to hotfix", err) + assertFileContent(t, p.Fakefs, fakeExePathLinux, fakeHotfixVersion) + }) + + run(t, "update coder - new to hotfix - windows", func(t *testing.T, p *params) { + p.OsF = func() string { return goosWindows } + p.ExecutablePath = fakeExePathWindows + fakeFile(t, p.Fakefs, fakeExePathWindows, 0755, fakeNewVersion) + p.HTTPClient.M[apiPrivateVersionURL] = newFakeGetterResponse([]byte(fakeHotfixVersionJSON), 200, variadicS(), nil) + p.HTTPClient.M[fakeGithubReleaseURL] = newFakeGetterResponse([]byte(fakeGithubReleaseJSON), 200, variadicS(), nil) + p.HTTPClient.M[fakeAssetURLLinux] = newFakeGetterResponse(fakeHotfixVersionTgz, 200, variadicS(), nil) + p.VersionF = func() string { return fakeNewVersion } + p.ConfirmF = fakeConfirmYes + p.Execer.M[p.ExecutablePath+".new --version"] = fakeExecerResult{[]byte(fakeNewVersion), nil} + u := fromParams(p) + assertFileContent(t, p.Fakefs, fakeExePathWindows, fakeNewVersion) + err := u.Run(p.Ctx, false, fakeCoderURL, "") + assert.Success(t, "update coder - new to hotfix", err) + assertFileContent(t, p.Fakefs, fakeExePathWindows, fakeHotfixVersion) + }) + run(t, "update coder - old to new - binary renamed", func(t *testing.T, p *params) { p.ExecutablePath = "/home/user/bin/coder-cli" fakeFile(t, p.Fakefs, p.ExecutablePath, 0755, fakeOldVersion) From 31e85d58d7422ce38c479f6f66b294f251b77882 Mon Sep 17 00:00:00 2001 From: Cian Johnston Date: Fri, 8 Oct 2021 12:19:44 +0000 Subject: [PATCH 4/7] feat(cli): compare cli.N build metadata to support hotfixes --- internal/cmd/update.go | 66 ++++++++++++++++++++++++++++++++++++- internal/cmd/update_test.go | 31 ++++++++++++++++- 2 files changed, 95 insertions(+), 2 deletions(-) diff --git a/internal/cmd/update.go b/internal/cmd/update.go index c9b94d80..1c3193ec 100644 --- a/internal/cmd/update.go +++ b/internal/cmd/update.go @@ -17,7 +17,9 @@ import ( "os/exec" "path" "path/filepath" + "regexp" "runtime" + "strconv" "strings" "time" @@ -139,7 +141,7 @@ func (u *updater) Run(ctx context.Context, force bool, coderURLArg string, versi currentVersion, err := semver.NewVersion(u.versionF()) if err != nil { clog.LogWarn("failed to determine current version of coder-cli", clog.Causef(err.Error())) - } else if currentVersion.Compare(desiredVersion) == 0 { + } else if compareVersions(currentVersion, desiredVersion) == 0 { clog.LogInfo("Up to date!") return nil } @@ -493,3 +495,65 @@ func HasFilePathPrefix(s, prefix string) bool { func defaultExec(ctx context.Context, cmd string, args ...string) ([]byte, error) { return exec.CommandContext(ctx, cmd, args...).CombinedOutput() } + +// hotfixExpr matches the build metadata used for identifying CLI hotfixes. +var hotfixExpr = regexp.MustCompile(`(?i)^.*?cli\.(\d+).*?$`) + +// compareVersions performs a NON-SEMVER-COMPLIANT comparison of two versions. +// If the two versions differ as per SemVer, then that result is returned. +// Otherwise, the build metadata of the two versions are compared based on +// the `cli.N` hotfix metadata. +// +// Examples: +// compareVersions(semver.MustParse("v1.0.0"), semver.MustParse("v1.0.0")) +// 0 +// compareVersions(semver.MustParse("v1.0.0"), semver.MustParse("v1.0.1")) +// 1 +// compareVersions(semver.MustParse("v1.0.1"), semver.MustParse("v1.0.0")) +// -1 +// compareVersions(semver.MustParse("v1.0.0+cli.0"), semver.MustParse("v1.0.0")) +// 1 +// compareVersions(semver.MustParse("v1.0.0+cli.0"), semver.MustParse("v1.0.0+cli.0")) +// 0 +// compareVersions(semver.MustParse("v1.0.0"), semver.MustParse("v1.0.0+cli.0")) +// -1 +// compareVersions(semver.MustParse("v1.0.0+cli.1"), semver.MustParse("v1.0.0+cli.0")) +// 1 +// compareVersions(semver.MustParse("v1.0.0+cli.0"), semver.MustParse("v1.0.0+cli.1")) +// -1 +// +func compareVersions(a, b *semver.Version) int { + semverComparison := a.Compare(b) + if semverComparison != 0 { + return semverComparison + } + + matchA := hotfixExpr.FindStringSubmatch(a.Metadata()) + matchB := hotfixExpr.FindStringSubmatch(b.Metadata()) + + hotfixA := -1 + hotfixB := -1 + + // extract hotfix versions from the metadata of a and b + if len(matchA) > 1 { + if n, err := strconv.Atoi(matchA[1]); err == nil { + hotfixA = n + } + } + if len(matchB) > 1 { + if n, err := strconv.Atoi(matchB[1]); err == nil { + hotfixB = n + } + } + + // compare hotfix versions + if hotfixA < hotfixB { + return -1 + } + if hotfixA > hotfixB { + return 1 + } + // both versions are the same if their semver and hotfix + // metadata are the same. + return 0 +} diff --git a/internal/cmd/update_test.go b/internal/cmd/update_test.go index ded18354..4de384b0 100644 --- a/internal/cmd/update_test.go +++ b/internal/cmd/update_test.go @@ -47,6 +47,7 @@ var ( fakeNewVersionTgz = mustValidTgz("coder", []byte(fakeNewVersion), 0751) fakeHotfixVersionTgz = mustValidTgz("coder", []byte(fakeHotfixVersion), 0751) fakeNewVersionZip = mustValidZip("coder.exe", []byte(fakeNewVersion)) + fakeHotfixVersionZip = mustValidZip("coder.exe", []byte(fakeHotfixVersion)) fakeAssetURLLinux = "https://github.com/cdr/coder-cli/releases/download/v1.23.4-rc.5/" + filenameLinux fakeAssetURLWindows = "https://github.com/cdr/coder-cli/releases/download/v1.23.4-rc.5/" + filenameWindows fakeGithubReleaseJSON = fmt.Sprintf(`{"assets":[{"name":%q,"browser_download_url":%q},{"name":%q,"browser_download_url":%q}]}`, filenameLinux, fakeAssetURLLinux, filenameWindows, fakeAssetURLWindows) @@ -222,7 +223,7 @@ func Test_updater_run(t *testing.T) { fakeFile(t, p.Fakefs, fakeExePathWindows, 0755, fakeNewVersion) p.HTTPClient.M[apiPrivateVersionURL] = newFakeGetterResponse([]byte(fakeHotfixVersionJSON), 200, variadicS(), nil) p.HTTPClient.M[fakeGithubReleaseURL] = newFakeGetterResponse([]byte(fakeGithubReleaseJSON), 200, variadicS(), nil) - p.HTTPClient.M[fakeAssetURLLinux] = newFakeGetterResponse(fakeHotfixVersionTgz, 200, variadicS(), nil) + p.HTTPClient.M[fakeAssetURLWindows] = newFakeGetterResponse(fakeHotfixVersionZip, 200, variadicS(), nil) p.VersionF = func() string { return fakeNewVersion } p.ConfirmF = fakeConfirmYes p.Execer.M[p.ExecutablePath+".new --version"] = fakeExecerResult{[]byte(fakeNewVersion), nil} @@ -501,6 +502,34 @@ func Test_getDesiredVersion(t *testing.T) { }) } +func Test_compareVersions(t *testing.T) { + t.Parallel() + + testCases := []struct { + Name string + V1 string + V2 string + Expected int + }{ + {"old vs old", fakeOldVersion, fakeOldVersion, 0}, + {"old vs new", fakeOldVersion, fakeNewVersion, -1}, + {"old vs hotfix", fakeOldVersion, fakeHotfixVersion, -1}, + {"new vs old", fakeNewVersion, fakeOldVersion, 1}, + {"new vs new", fakeNewVersion, fakeNewVersion, 0}, + {"new vs hotfix", fakeNewVersion, fakeHotfixVersion, -1}, + {"hotfix vs old", fakeHotfixVersion, fakeOldVersion, 1}, + {"hotfix vs new", fakeHotfixVersion, fakeNewVersion, 1}, + {"hotfix vs hotfix", fakeHotfixVersion, fakeHotfixVersion, 0}, + } + for _, testCase := range testCases { + testCase := testCase + v1 := semver.MustParse(testCase.V1) + v2 := semver.MustParse(testCase.V2) + actual := compareVersions(v1, v2) + assert.Equal(t, testCase.Name+": expected comparison differs", testCase.Expected, actual) + } +} + // fakeGetter mocks HTTP requests. type fakeGetter struct { M map[string]*fakeGetterResponse From a618b47b8b355780a0518ca1e6bfc26c000e090e Mon Sep 17 00:00:00 2001 From: Cian Johnston Date: Fri, 8 Oct 2021 13:00:22 +0000 Subject: [PATCH 5/7] add hotfix versions to asset urls --- internal/cmd/update.go | 24 ++++++++++++++++- internal/cmd/update_test.go | 51 ++++++++++++++++++++++++------------- 2 files changed, 56 insertions(+), 19 deletions(-) diff --git a/internal/cmd/update.go b/internal/cmd/update.go index 1c3193ec..4ab75996 100644 --- a/internal/cmd/update.go +++ b/internal/cmd/update.go @@ -147,10 +147,20 @@ func (u *updater) Run(ctx context.Context, force bool, coderURLArg string, versi } if !force { - label := fmt.Sprintf("Do you want to download version %d.%d.%d instead", + prerelease := "" + if desiredVersion.Prerelease() != "" { + prerelease = "-" + desiredVersion.Prerelease() + } + hotfix := "" + if hotfixVersion(desiredVersion) != "" { + hotfix = "+" + hotfixVersion(desiredVersion) + } + label := fmt.Sprintf("Do you want to download version %d.%d.%d%s%s instead", desiredVersion.Major(), desiredVersion.Minor(), desiredVersion.Patch(), + prerelease, + hotfix, ) if _, err := u.confirmF(label); err != nil { return clog.Fatal("user cancelled operation", clog.Tipf(`use "--force" to update without confirmation`)) @@ -310,6 +320,7 @@ func queryGithubAssetURL(httpClient getter, version *semver.Version, ostype stri fmt.Fprint(&b, "-") fmt.Fprint(&b, version.Prerelease()) } + fmt.Fprintf(&b, "%s", hotfixVersion(version)) // this will be empty if no hotfix urlString := fmt.Sprintf("https://api.github.com/repos/cdr/coder-cli/releases/tags/v%s", b.String()) clog.LogInfo("query github releases", fmt.Sprintf("url: %q", urlString)) @@ -499,6 +510,17 @@ func defaultExec(ctx context.Context, cmd string, args ...string) ([]byte, error // hotfixExpr matches the build metadata used for identifying CLI hotfixes. var hotfixExpr = regexp.MustCompile(`(?i)^.*?cli\.(\d+).*?$`) +// hotfixVersion returns the hotfix build metadata tag if it is present in v +// and an empty string otherwise. +func hotfixVersion(v *semver.Version) string { + match := hotfixExpr.FindStringSubmatch(v.Metadata()) + if len(match) < 2 { + return "" + } + + return fmt.Sprintf("+cli.%s", match[1]) +} + // compareVersions performs a NON-SEMVER-COMPLIANT comparison of two versions. // If the two versions differ as per SemVer, then that result is returned. // Otherwise, the build metadata of the two versions are compared based on diff --git a/internal/cmd/update_test.go b/internal/cmd/update_test.go index 4de384b0..00855a72 100644 --- a/internal/cmd/update_test.go +++ b/internal/cmd/update_test.go @@ -36,6 +36,7 @@ const ( filenameLinux = "coder-cli-linux-amd64.tar.gz" filenameWindows = "coder-cli-windows.zip" fakeGithubReleaseURL = "https://api.github.com/repos/cdr/coder-cli/releases/tags/v1.23.4-rc.5" + fakeGithubHotfixURL = fakeGithubReleaseURL + "+cli.2" ) var ( @@ -50,7 +51,8 @@ var ( fakeHotfixVersionZip = mustValidZip("coder.exe", []byte(fakeHotfixVersion)) fakeAssetURLLinux = "https://github.com/cdr/coder-cli/releases/download/v1.23.4-rc.5/" + filenameLinux fakeAssetURLWindows = "https://github.com/cdr/coder-cli/releases/download/v1.23.4-rc.5/" + filenameWindows - fakeGithubReleaseJSON = fmt.Sprintf(`{"assets":[{"name":%q,"browser_download_url":%q},{"name":%q,"browser_download_url":%q}]}`, filenameLinux, fakeAssetURLLinux, filenameWindows, fakeAssetURLWindows) + fakeHotfixURLLinux = "https://github.com/cdr/coder-cli/releases/download/v1.23.4-rc.5+cli.2/" + filenameLinux + fakeHotfixURLWindows = "https://github.com/cdr/coder-cli/releases/download/v1.23.4-rc.5+cli.2/" + filenameWindows ) func Test_updater_run(t *testing.T) { @@ -141,7 +143,7 @@ func Test_updater_run(t *testing.T) { run(t, "update coder - explicit version specified", func(t *testing.T, p *params) { fakeFile(t, p.Fakefs, fakeExePathLinux, 0755, fakeOldVersion) p.HTTPClient.M[apiPrivateVersionURL] = newFakeGetterResponse([]byte(fakeOldVersionJSON), 200, variadicS(), nil) - p.HTTPClient.M[fakeGithubReleaseURL] = newFakeGetterResponse([]byte(fakeGithubReleaseJSON), 200, variadicS(), nil) + p.HTTPClient.M[fakeGithubReleaseURL] = newFakeGetterResponse(fakeGithubReleaseJSON(filenameLinux, fakeAssetURLLinux), 200, variadicS(), nil) p.HTTPClient.M[fakeAssetURLLinux] = newFakeGetterResponse(fakeNewVersionTgz, 200, variadicS(), nil) p.VersionF = func() string { return fakeOldVersion } p.ConfirmF = fakeConfirmYes @@ -158,7 +160,7 @@ func Test_updater_run(t *testing.T) { fakeOldVersion := "v" + fakeOldVersion fakeFile(t, p.Fakefs, fakeExePathLinux, 0755, fakeOldVersion) p.HTTPClient.M[apiPrivateVersionURL] = newFakeGetterResponse([]byte(fakeOldVersionJSON), 200, variadicS(), nil) - p.HTTPClient.M[fakeGithubReleaseURL] = newFakeGetterResponse([]byte(fakeGithubReleaseJSON), 200, variadicS(), nil) + p.HTTPClient.M[fakeGithubReleaseURL] = newFakeGetterResponse(fakeGithubReleaseJSON(filenameLinux, fakeAssetURLLinux), 200, variadicS(), nil) p.HTTPClient.M[fakeAssetURLLinux] = newFakeGetterResponse(fakeNewVersionTgz, 200, variadicS(), nil) p.VersionF = func() string { return fakeOldVersion } p.ConfirmF = fakeConfirmYes @@ -173,7 +175,7 @@ func Test_updater_run(t *testing.T) { run(t, "update coder - old to new", func(t *testing.T, p *params) { fakeFile(t, p.Fakefs, fakeExePathLinux, 0755, fakeOldVersion) p.HTTPClient.M[apiPrivateVersionURL] = newFakeGetterResponse([]byte(fakeNewVersionJSON), 200, variadicS(), nil) - p.HTTPClient.M[fakeGithubReleaseURL] = newFakeGetterResponse([]byte(fakeGithubReleaseJSON), 200, variadicS(), nil) + p.HTTPClient.M[fakeGithubReleaseURL] = newFakeGetterResponse(fakeGithubReleaseJSON(filenameLinux, fakeAssetURLLinux), 200, variadicS(), nil) p.HTTPClient.M[fakeAssetURLLinux] = newFakeGetterResponse(fakeNewVersionTgz, 200, variadicS(), nil) p.VersionF = func() string { return fakeOldVersion } p.ConfirmF = fakeConfirmYes @@ -190,7 +192,7 @@ func Test_updater_run(t *testing.T) { fakeOldVersion := "v" + fakeOldVersion fakeFile(t, p.Fakefs, fakeExePathLinux, 0755, fakeOldVersion) p.HTTPClient.M[apiPrivateVersionURL] = newFakeGetterResponse([]byte(fakeNewVersionJSON), 200, variadicS(), nil) - p.HTTPClient.M[fakeGithubReleaseURL] = newFakeGetterResponse([]byte(fakeGithubReleaseJSON), 200, variadicS(), nil) + p.HTTPClient.M[fakeGithubReleaseURL] = newFakeGetterResponse(fakeGithubReleaseJSON(filenameLinux, fakeAssetURLLinux), 200, variadicS(), nil) p.HTTPClient.M[fakeAssetURLLinux] = newFakeGetterResponse(fakeNewVersionTgz, 200, variadicS(), nil) p.VersionF = func() string { return fakeOldVersion } p.ConfirmF = fakeConfirmYes @@ -205,8 +207,8 @@ func Test_updater_run(t *testing.T) { run(t, "update coder - new to hotfix", func(t *testing.T, p *params) { fakeFile(t, p.Fakefs, fakeExePathLinux, 0755, fakeNewVersion) p.HTTPClient.M[apiPrivateVersionURL] = newFakeGetterResponse([]byte(fakeHotfixVersionJSON), 200, variadicS(), nil) - p.HTTPClient.M[fakeGithubReleaseURL] = newFakeGetterResponse([]byte(fakeGithubReleaseJSON), 200, variadicS(), nil) - p.HTTPClient.M[fakeAssetURLLinux] = newFakeGetterResponse(fakeHotfixVersionTgz, 200, variadicS(), nil) + p.HTTPClient.M[fakeGithubHotfixURL] = newFakeGetterResponse(fakeGithubReleaseJSON(filenameLinux, fakeHotfixURLLinux), 200, variadicS(), nil) + p.HTTPClient.M[fakeHotfixURLLinux] = newFakeGetterResponse(fakeHotfixVersionTgz, 200, variadicS(), nil) p.VersionF = func() string { return fakeNewVersion } p.ConfirmF = fakeConfirmYes p.Execer.M[p.ExecutablePath+".new --version"] = fakeExecerResult{[]byte(fakeNewVersion), nil} @@ -222,8 +224,8 @@ func Test_updater_run(t *testing.T) { p.ExecutablePath = fakeExePathWindows fakeFile(t, p.Fakefs, fakeExePathWindows, 0755, fakeNewVersion) p.HTTPClient.M[apiPrivateVersionURL] = newFakeGetterResponse([]byte(fakeHotfixVersionJSON), 200, variadicS(), nil) - p.HTTPClient.M[fakeGithubReleaseURL] = newFakeGetterResponse([]byte(fakeGithubReleaseJSON), 200, variadicS(), nil) - p.HTTPClient.M[fakeAssetURLWindows] = newFakeGetterResponse(fakeHotfixVersionZip, 200, variadicS(), nil) + p.HTTPClient.M[fakeGithubHotfixURL] = newFakeGetterResponse(fakeGithubReleaseJSON(filenameWindows, fakeHotfixURLWindows), 200, variadicS(), nil) + p.HTTPClient.M[fakeHotfixURLWindows] = newFakeGetterResponse(fakeHotfixVersionZip, 200, variadicS(), nil) p.VersionF = func() string { return fakeNewVersion } p.ConfirmF = fakeConfirmYes p.Execer.M[p.ExecutablePath+".new --version"] = fakeExecerResult{[]byte(fakeNewVersion), nil} @@ -238,7 +240,7 @@ func Test_updater_run(t *testing.T) { p.ExecutablePath = "/home/user/bin/coder-cli" fakeFile(t, p.Fakefs, p.ExecutablePath, 0755, fakeOldVersion) p.HTTPClient.M[apiPrivateVersionURL] = newFakeGetterResponse([]byte(fakeNewVersionJSON), 200, variadicS(), nil) - p.HTTPClient.M[fakeGithubReleaseURL] = newFakeGetterResponse([]byte(fakeGithubReleaseJSON), 200, variadicS(), nil) + p.HTTPClient.M[fakeGithubReleaseURL] = newFakeGetterResponse(fakeGithubReleaseJSON(filenameLinux, fakeAssetURLLinux), 200, variadicS(), nil) p.HTTPClient.M[fakeAssetURLLinux] = newFakeGetterResponse(fakeNewVersionTgz, 200, variadicS(), nil) p.VersionF = func() string { return fakeOldVersion } p.ConfirmF = fakeConfirmYes @@ -255,7 +257,7 @@ func Test_updater_run(t *testing.T) { p.ExecutablePath = fakeExePathWindows fakeFile(t, p.Fakefs, fakeExePathWindows, 0755, fakeOldVersion) p.HTTPClient.M[apiPrivateVersionURL] = newFakeGetterResponse([]byte(fakeNewVersionJSON), 200, variadicS(), nil) - p.HTTPClient.M[fakeGithubReleaseURL] = newFakeGetterResponse([]byte(fakeGithubReleaseJSON), 200, variadicS(), nil) + p.HTTPClient.M[fakeGithubReleaseURL] = newFakeGetterResponse(fakeGithubReleaseJSON(filenameWindows, fakeAssetURLWindows), 200, variadicS(), nil) p.HTTPClient.M[fakeAssetURLWindows] = newFakeGetterResponse(fakeNewVersionZip, 200, variadicS(), nil) p.VersionF = func() string { return fakeOldVersion } p.ConfirmF = fakeConfirmYes @@ -270,7 +272,7 @@ func Test_updater_run(t *testing.T) { run(t, "update coder - old to new forced", func(t *testing.T, p *params) { fakeFile(t, p.Fakefs, fakeExePathLinux, 0755, fakeOldVersion) p.HTTPClient.M[apiPrivateVersionURL] = newFakeGetterResponse([]byte(fakeNewVersionJSON), 200, variadicS(), nil) - p.HTTPClient.M[fakeGithubReleaseURL] = newFakeGetterResponse([]byte(fakeGithubReleaseJSON), 200, variadicS(), nil) + p.HTTPClient.M[fakeGithubReleaseURL] = newFakeGetterResponse(fakeGithubReleaseJSON(filenameLinux, fakeAssetURLLinux), 200, variadicS(), nil) p.HTTPClient.M[fakeAssetURLLinux] = newFakeGetterResponse(fakeNewVersionTgz, 200, variadicS(), nil) p.VersionF = func() string { return fakeOldVersion } p.Execer.M[p.ExecutablePath+".new --version"] = fakeExecerResult{[]byte(fakeNewVersion), nil} @@ -355,7 +357,7 @@ func Test_updater_run(t *testing.T) { run(t, "update coder - failed to fetch URL", func(t *testing.T, p *params) { fakeFile(t, p.Fakefs, fakeExePathLinux, 0755, fakeOldVersion) p.HTTPClient.M[apiPrivateVersionURL] = newFakeGetterResponse([]byte(fakeNewVersionJSON), 200, variadicS(), nil) - p.HTTPClient.M[fakeGithubReleaseURL] = newFakeGetterResponse([]byte(fakeGithubReleaseJSON), 200, variadicS(), nil) + p.HTTPClient.M[fakeGithubReleaseURL] = newFakeGetterResponse(fakeGithubReleaseJSON(filenameLinux, fakeAssetURLLinux), 200, variadicS(), nil) p.HTTPClient.M[fakeAssetURLLinux] = newFakeGetterResponse([]byte{}, 0, variadicS(), fakeError) p.VersionF = func() string { return fakeOldVersion } p.ConfirmF = fakeConfirmYes @@ -369,7 +371,7 @@ func Test_updater_run(t *testing.T) { run(t, "update coder - release URL 404", func(t *testing.T, p *params) { fakeFile(t, p.Fakefs, fakeExePathLinux, 0755, fakeOldVersion) p.HTTPClient.M[apiPrivateVersionURL] = newFakeGetterResponse([]byte(fakeNewVersionJSON), 200, variadicS(), nil) - p.HTTPClient.M[fakeGithubReleaseURL] = newFakeGetterResponse([]byte(fakeGithubReleaseJSON), 200, variadicS(), nil) + p.HTTPClient.M[fakeGithubReleaseURL] = newFakeGetterResponse(fakeGithubReleaseJSON(filenameLinux, fakeAssetURLLinux), 200, variadicS(), nil) p.HTTPClient.M[fakeAssetURLLinux] = newFakeGetterResponse([]byte{}, 404, variadicS(), nil) p.VersionF = func() string { return fakeOldVersion } p.ConfirmF = fakeConfirmYes @@ -383,7 +385,7 @@ func Test_updater_run(t *testing.T) { run(t, "update coder - invalid tgz archive", func(t *testing.T, p *params) { fakeFile(t, p.Fakefs, fakeExePathLinux, 0755, fakeOldVersion) p.HTTPClient.M[apiPrivateVersionURL] = newFakeGetterResponse([]byte(fakeNewVersionJSON), 200, variadicS(), nil) - p.HTTPClient.M[fakeGithubReleaseURL] = newFakeGetterResponse([]byte(fakeGithubReleaseJSON), 200, variadicS(), nil) + p.HTTPClient.M[fakeGithubReleaseURL] = newFakeGetterResponse(fakeGithubReleaseJSON(filenameLinux, fakeAssetURLLinux), 200, variadicS(), nil) p.HTTPClient.M[fakeAssetURLLinux] = newFakeGetterResponse([]byte{}, 200, variadicS(), nil) p.VersionF = func() string { return fakeOldVersion } p.ConfirmF = fakeConfirmYes @@ -399,7 +401,7 @@ func Test_updater_run(t *testing.T) { p.ExecutablePath = fakeExePathWindows fakeFile(t, p.Fakefs, fakeExePathWindows, 0755, fakeOldVersion) p.HTTPClient.M[apiPrivateVersionURL] = newFakeGetterResponse([]byte(fakeNewVersionJSON), 200, variadicS(), nil) - p.HTTPClient.M[fakeGithubReleaseURL] = newFakeGetterResponse([]byte(fakeGithubReleaseJSON), 200, variadicS(), nil) + p.HTTPClient.M[fakeGithubReleaseURL] = newFakeGetterResponse(fakeGithubReleaseJSON(filenameWindows, fakeAssetURLWindows), 200, variadicS(), nil) p.HTTPClient.M[fakeAssetURLWindows] = newFakeGetterResponse([]byte{}, 200, variadicS(), nil) p.VersionF = func() string { return fakeOldVersion } p.ConfirmF = fakeConfirmYes @@ -415,7 +417,7 @@ func Test_updater_run(t *testing.T) { p.Fakefs = afero.NewReadOnlyFs(rwfs) fakeFile(t, rwfs, fakeExePathLinux, 0755, fakeOldVersion) p.HTTPClient.M[apiPrivateVersionURL] = newFakeGetterResponse([]byte(fakeNewVersionJSON), 200, variadicS(), nil) - p.HTTPClient.M[fakeGithubReleaseURL] = newFakeGetterResponse([]byte(fakeGithubReleaseJSON), 200, variadicS(), nil) + p.HTTPClient.M[fakeGithubReleaseURL] = newFakeGetterResponse(fakeGithubReleaseJSON(filenameLinux, fakeAssetURLLinux), 200, variadicS(), nil) p.HTTPClient.M[fakeAssetURLLinux] = newFakeGetterResponse(fakeNewVersionTgz, 200, variadicS(), nil) p.VersionF = func() string { return fakeOldVersion } p.ConfirmF = fakeConfirmYes @@ -429,7 +431,7 @@ func Test_updater_run(t *testing.T) { run(t, "update coder - cannot exec new binary", func(t *testing.T, p *params) { fakeFile(t, p.Fakefs, fakeExePathLinux, 0755, fakeOldVersion) p.HTTPClient.M[apiPrivateVersionURL] = newFakeGetterResponse([]byte(fakeNewVersionJSON), 200, variadicS(), nil) - p.HTTPClient.M[fakeGithubReleaseURL] = newFakeGetterResponse([]byte(fakeGithubReleaseJSON), 200, variadicS(), nil) + p.HTTPClient.M[fakeGithubReleaseURL] = newFakeGetterResponse(fakeGithubReleaseJSON(filenameLinux, fakeAssetURLLinux), 200, variadicS(), nil) p.HTTPClient.M[fakeAssetURLLinux] = newFakeGetterResponse(fakeNewVersionTgz, 200, variadicS(), nil) p.VersionF = func() string { return fakeOldVersion } p.ConfirmF = fakeConfirmYes @@ -740,3 +742,16 @@ type fakeExecerResult struct { Output []byte Err error } + +func fakeGithubReleaseJSON(filename, assetURL string) []byte { + jsonStr := fmt.Sprintf(` + {"assets": + [ + { + "name": %q, + "browser_download_url": %q + } + ] + }`, filename, assetURL) + return []byte(jsonStr) +} From a9ebe5c24ec186d51d6a2002334c5d6dbbf290cf Mon Sep 17 00:00:00 2001 From: Cian Johnston Date: Fri, 8 Oct 2021 13:41:15 +0000 Subject: [PATCH 6/7] remove duplicated version output --- internal/cmd/update.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/cmd/update.go b/internal/cmd/update.go index 4ab75996..838a29a7 100644 --- a/internal/cmd/update.go +++ b/internal/cmd/update.go @@ -230,7 +230,7 @@ func (u *updater) Run(ctx context.Context, force bool, coderURLArg string, versi return clog.Fatal("failed to update coder binary", clog.Causef(err.Error())) } - clog.LogSuccess("Updated coder CLI to version " + desiredVersion.String()) + clog.LogSuccess("Updated coder CLI") return nil } From 3279b10b1161bb3138a1c25a4139107318582159 Mon Sep 17 00:00:00 2001 From: Cian Johnston Date: Fri, 8 Oct 2021 13:44:34 +0000 Subject: [PATCH 7/7] fix confirm msg --- internal/cmd/update.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/cmd/update.go b/internal/cmd/update.go index 838a29a7..124662eb 100644 --- a/internal/cmd/update.go +++ b/internal/cmd/update.go @@ -153,7 +153,7 @@ func (u *updater) Run(ctx context.Context, force bool, coderURLArg string, versi } hotfix := "" if hotfixVersion(desiredVersion) != "" { - hotfix = "+" + hotfixVersion(desiredVersion) + hotfix = hotfixVersion(desiredVersion) } label := fmt.Sprintf("Do you want to download version %d.%d.%d%s%s instead", desiredVersion.Major(), 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