diff --git a/pkg/cmd/extension/extension.go b/pkg/cmd/extension/extension.go index e4f109d83..9d1d61c21 100644 --- a/pkg/cmd/extension/extension.go +++ b/pkg/cmd/extension/extension.go @@ -49,8 +49,7 @@ func (e *Extension) IsPinned() bool { } func (e *Extension) UpdateAvailable() bool { - if e.isPinned || - e.isLocal || + if e.isLocal || e.currentVersion == "" || e.latestVersion == "" || e.currentVersion == e.latestVersion { diff --git a/pkg/cmd/extension/extension_test.go b/pkg/cmd/extension/extension_test.go new file mode 100644 index 000000000..0a50cbfe8 --- /dev/null +++ b/pkg/cmd/extension/extension_test.go @@ -0,0 +1,52 @@ +package extension + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestUpdateAvailable_IsLocal(t *testing.T) { + e := &Extension{ + isLocal: true, + } + + assert.False(t, e.UpdateAvailable()) +} + +func TestUpdateAvailable_NoCurrentVersion(t *testing.T) { + e := &Extension{ + isLocal: false, + } + + assert.False(t, e.UpdateAvailable()) +} + +func TestUpdateAvailable_NoLatestVersion(t *testing.T) { + e := &Extension{ + isLocal: false, + currentVersion: "1.0.0", + } + + assert.False(t, e.UpdateAvailable()) +} + +func TestUpdateAvailable_CurrentVersionIsLatestVersion(t *testing.T) { + e := &Extension{ + isLocal: false, + currentVersion: "1.0.0", + latestVersion: "1.0.0", + } + + assert.False(t, e.UpdateAvailable()) +} + +func TestUpdateAvailable(t *testing.T) { + e := &Extension{ + isLocal: false, + currentVersion: "1.0.0", + latestVersion: "1.1.0", + } + + assert.True(t, e.UpdateAvailable()) +} diff --git a/pkg/cmd/extension/manager.go b/pkg/cmd/extension/manager.go index c9f638b87..49473e0f3 100644 --- a/pkg/cmd/extension/manager.go +++ b/pkg/cmd/extension/manager.go @@ -575,7 +575,7 @@ func (m *Manager) upgradeExtension(ext Extension, force bool) error { if ext.isLocal { return localExtensionUpgradeError } - if ext.IsPinned() { + if !force && ext.IsPinned() { return pinnedExtensionUpgradeError } if !ext.UpdateAvailable() { diff --git a/pkg/cmd/extension/manager_test.go b/pkg/cmd/extension/manager_test.go index 2dbd81870..1c35ee31a 100644 --- a/pkg/cmd/extension/manager_test.go +++ b/pkg/cmd/extension/manager_test.go @@ -506,6 +506,71 @@ func TestManager_UpgradeExtension_BinaryExtension(t *testing.T) { assert.Equal(t, "", stderr.String()) } +func TestManager_UpgradeExtension_BinaryExtension_Pinned_Force(t *testing.T) { + tempDir := t.TempDir() + + reg := httpmock.Registry{} + defer reg.Verify(t) + + assert.NoError(t, stubBinaryExtension( + filepath.Join(tempDir, "extensions", "gh-bin-ext"), + binManifest{ + Owner: "owner", + Name: "gh-bin-ext", + Host: "example.com", + Tag: "v1.0.1", + IsPinned: true, + })) + + ios, _, stdout, stderr := iostreams.Test() + m := newTestManager(tempDir, &http.Client{Transport: ®}, ios) + reg.Register( + httpmock.REST("GET", "api/v3/repos/owner/gh-bin-ext/releases/latest"), + httpmock.JSONResponse( + release{ + Tag: "v1.0.2", + Assets: []releaseAsset{ + { + Name: "gh-bin-ext-windows-amd64.exe", + APIURL: "https://example.com/release/cool2", + }, + }, + })) + reg.Register( + httpmock.REST("GET", "release/cool2"), + httpmock.StringResponse("FAKE UPGRADED BINARY")) + + exts, err := m.list(false) + assert.NoError(t, err) + assert.Equal(t, 1, len(exts)) + ext := exts[0] + ext.latestVersion = "v1.0.2" + err = m.upgradeExtension(ext, true) + assert.NoError(t, err) + + manifest, err := os.ReadFile(filepath.Join(tempDir, "extensions/gh-bin-ext", manifestName)) + assert.NoError(t, err) + + var bm binManifest + err = yaml.Unmarshal(manifest, &bm) + assert.NoError(t, err) + + assert.Equal(t, binManifest{ + Name: "gh-bin-ext", + Owner: "owner", + Host: "example.com", + Tag: "v1.0.2", + Path: filepath.Join(tempDir, "extensions/gh-bin-ext/gh-bin-ext.exe"), + }, bm) + + fakeBin, err := os.ReadFile(filepath.Join(tempDir, "extensions/gh-bin-ext/gh-bin-ext.exe")) + assert.NoError(t, err) + assert.Equal(t, "FAKE UPGRADED BINARY", string(fakeBin)) + + assert.Equal(t, "", stdout.String()) + assert.Equal(t, "", stderr.String()) +} + func TestManager_UpgradeExtension_BinaryExtension_DryRun(t *testing.T) { tempDir := t.TempDir() reg := httpmock.Registry{}