Refactor extension command testing

This commit allows for stubbing/mocking the function used for checking update release info.  Additionally, this does a minor refactor moving from non-blocking to blocking channel.
This commit is contained in:
Andy Feller 2024-11-17 21:59:06 -05:00
parent 0d3f7cae4e
commit 7b91b17395
3 changed files with 52 additions and 30 deletions

View file

@ -19,10 +19,13 @@ type ExternalCommandExitError struct {
*exec.ExitError
}
func NewCmdExtension(io *iostreams.IOStreams, em extensions.ExtensionManager, ext extensions.Extension) *cobra.Command {
func NewCmdExtension(io *iostreams.IOStreams, em extensions.ExtensionManager, ext extensions.Extension, checkFunc func(extensions.ExtensionManager, extensions.Extension) (*update.ReleaseInfo, error)) *cobra.Command {
updateMessageChan := make(chan *update.ReleaseInfo)
cs := io.ColorScheme()
hasDebug, _ := utils.IsDebugEnabled()
if checkFunc == nil {
checkFunc = checkForExtensionUpdate
}
return &cobra.Command{
Use: ext.Name(),
@ -30,7 +33,7 @@ func NewCmdExtension(io *iostreams.IOStreams, em extensions.ExtensionManager, ex
// PreRun handles looking up whether extension has a latest version only when the command is ran.
PreRun: func(c *cobra.Command, args []string) {
go func() {
rel, err := checkForExtensionUpdate(em, ext)
rel, err := checkFunc(em, ext)
if err != nil && hasDebug {
fmt.Fprintf(io.ErrOut, "warning: checking for update failed: %v", err)
}
@ -50,24 +53,20 @@ func NewCmdExtension(io *iostreams.IOStreams, em extensions.ExtensionManager, ex
},
// PostRun handles communicating extension release information if found
PostRun: func(c *cobra.Command, args []string) {
select {
case releaseInfo := <-updateMessageChan:
if releaseInfo != nil {
stderr := io.ErrOut
fmt.Fprintf(stderr, "\n\n%s %s → %s\n",
cs.Yellowf("A new release of %s is available:", ext.Name()),
cs.Cyan(strings.TrimPrefix(ext.CurrentVersion(), "v")),
cs.Cyan(strings.TrimPrefix(releaseInfo.Version, "v")))
if ext.IsPinned() {
fmt.Fprintf(stderr, "To upgrade, run: gh extension upgrade %s --force\n", ext.Name())
} else {
fmt.Fprintf(stderr, "To upgrade, run: gh extension upgrade %s\n", ext.Name())
}
fmt.Fprintf(stderr, "%s\n\n",
cs.Yellow(releaseInfo.URL))
releaseInfo := <-updateMessageChan
if releaseInfo != nil {
stderr := io.ErrOut
fmt.Fprintf(stderr, "\n\n%s %s → %s\n",
cs.Yellowf("A new release of %s is available:", ext.Name()),
cs.Cyan(strings.TrimPrefix(ext.CurrentVersion(), "v")),
cs.Cyan(strings.TrimPrefix(releaseInfo.Version, "v")))
if ext.IsPinned() {
fmt.Fprintf(stderr, "To upgrade, run: gh extension upgrade %s --force\n", ext.Name())
} else {
fmt.Fprintf(stderr, "To upgrade, run: gh extension upgrade %s\n", ext.Name())
}
default:
// Bail on checking for new extension update as its taking too long
fmt.Fprintf(stderr, "%s\n\n",
cs.Yellow(releaseInfo.URL))
}
},
GroupID: "extension",

View file

@ -5,6 +5,7 @@ import (
"testing"
"github.com/MakeNowJust/heredoc"
"github.com/cli/cli/v2/internal/update"
"github.com/cli/cli/v2/pkg/cmd/root"
"github.com/cli/cli/v2/pkg/extensions"
"github.com/cli/cli/v2/pkg/iostreams"
@ -16,6 +17,7 @@ func TestNewCmdExtension_Updates(t *testing.T) {
tests := []struct {
name string
extCurrentVersion string
extFullName string
extIsPinned bool
extLatestVersion string
extName string
@ -26,6 +28,7 @@ func TestNewCmdExtension_Updates(t *testing.T) {
{
name: "no update available",
extName: "no-update",
extFullName: "gh-no-update",
extUpdateAvailable: false,
extCurrentVersion: "1.0.0",
extLatestVersion: "1.0.0",
@ -34,6 +37,7 @@ func TestNewCmdExtension_Updates(t *testing.T) {
{
name: "major update",
extName: "major-update",
extFullName: "gh-major-update",
extUpdateAvailable: true,
extCurrentVersion: "1.0.0",
extLatestVersion: "2.0.0",
@ -46,21 +50,23 @@ func TestNewCmdExtension_Updates(t *testing.T) {
},
{
name: "major update, pinned",
extName: "major-update",
extName: "major-update-pin",
extFullName: "gh-major-update-pin",
extUpdateAvailable: true,
extCurrentVersion: "1.0.0",
extLatestVersion: "2.0.0",
extIsPinned: true,
extURL: "https//github.com/dne/major-update",
wantStderr: heredoc.Doc(`
A new release of major-update is available: 1.0.0 2.0.0
To upgrade, run: gh extension upgrade major-update --force
A new release of major-update-pin is available: 1.0.0 2.0.0
To upgrade, run: gh extension upgrade major-update-pin --force
https//github.com/dne/major-update
`),
},
{
name: "minor update",
extName: "minor-update",
extFullName: "gh-minor-update",
extUpdateAvailable: true,
extCurrentVersion: "1.0.0",
extLatestVersion: "1.1.0",
@ -73,21 +79,23 @@ func TestNewCmdExtension_Updates(t *testing.T) {
},
{
name: "minor update, pinned",
extName: "minor-update",
extName: "minor-update-pin",
extFullName: "gh-minor-update-pin",
extUpdateAvailable: true,
extCurrentVersion: "1.0.0",
extLatestVersion: "1.1.0",
extURL: "https//github.com/dne/minor-update",
extIsPinned: true,
wantStderr: heredoc.Doc(`
A new release of minor-update is available: 1.0.0 1.1.0
To upgrade, run: gh extension upgrade minor-update --force
A new release of minor-update-pin is available: 1.0.0 1.1.0
To upgrade, run: gh extension upgrade minor-update-pin --force
https//github.com/dne/minor-update
`),
},
{
name: "patch update",
extName: "patch-update",
extFullName: "gh-patch-update",
extUpdateAvailable: true,
extCurrentVersion: "1.0.0",
extLatestVersion: "1.0.1",
@ -100,15 +108,16 @@ func TestNewCmdExtension_Updates(t *testing.T) {
},
{
name: "patch update, pinned",
extName: "patch-update",
extName: "patch-update-pin",
extFullName: "gh-patch-update-pin",
extUpdateAvailable: true,
extCurrentVersion: "1.0.0",
extLatestVersion: "1.0.1",
extURL: "https//github.com/dne/patch-update",
extIsPinned: true,
wantStderr: heredoc.Doc(`
A new release of patch-update is available: 1.0.0 1.0.1
To upgrade, run: gh extension upgrade patch-update --force
A new release of patch-update-pin is available: 1.0.0 1.0.1
To upgrade, run: gh extension upgrade patch-update-pin --force
https//github.com/dne/patch-update
`),
},
@ -128,6 +137,9 @@ func TestNewCmdExtension_Updates(t *testing.T) {
CurrentVersionFunc: func() string {
return tt.extCurrentVersion
},
FullNameFunc: func() string {
return tt.extFullName
},
IsPinnedFunc: func() bool {
return tt.extIsPinned
},
@ -145,7 +157,18 @@ func TestNewCmdExtension_Updates(t *testing.T) {
},
}
cmd := root.NewCmdExtension(ios, em, ext)
checkFunc := func(em extensions.ExtensionManager, ext extensions.Extension) (*update.ReleaseInfo, error) {
if !tt.extUpdateAvailable {
return nil, nil
}
return &update.ReleaseInfo{
Version: tt.extLatestVersion,
URL: tt.extURL,
}, nil
}
cmd := root.NewCmdExtension(ios, em, ext, checkFunc)
_, err := cmd.ExecuteC()
require.NoError(t, err)

View file

@ -172,7 +172,7 @@ func NewCmdRoot(f *cmdutil.Factory, version, buildDate string) (*cobra.Command,
// Extensions
em := f.ExtensionManager
for _, e := range em.List() {
extensionCmd := NewCmdExtension(io, em, e)
extensionCmd := NewCmdExtension(io, em, e, nil)
cmd.AddCommand(extensionCmd)
}