Skip to content

Commit

Permalink
Add version checking when executing extensions
Browse files Browse the repository at this point in the history
Building on logic from the `gh ext list` for retrieving and assessing extension release information, this commit enhances the logic around invoking extensions to check for new releases.

Using the same user experience from checking `gh` version, this should only output information when the extension is used and gives the user information on how to upgrade depending on the type of extension and whether it is pinned or not.

```shell
andrewfeller@Andrews-MacBook-Pro cli % gh ext install dlvhdr/gh-dash --pin v4.6.0
✓ Installed extension dlvhdr/gh-dash
✓ Pinned extension at v4.6.0
andrewfeller@Andrews-MacBook-Pro cli % ./bin/gh dash

A new release of dash is available: 4.6.0 → 4.7.0
To upgrade, run: gh extension upgrade dash --force
https://github.com/dlvhdr/gh-dash
```
  • Loading branch information
Andrew Feller authored and Andrew Feller committed Nov 2, 2024
1 parent bb1a6f2 commit 47d77bd
Showing 1 changed file with 43 additions and 0 deletions.
43 changes: 43 additions & 0 deletions pkg/cmd/root/extension.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,45 @@ import (
"errors"
"fmt"
"os/exec"
"strings"

"github.com/cli/cli/v2/pkg/extensions"
"github.com/cli/cli/v2/pkg/iostreams"
"github.com/mgutz/ansi"
"github.com/spf13/cobra"
)

type ExternalCommandExitError struct {
*exec.ExitError
}

type extensionReleaseInfo struct {
CurrentVersion string
LatestVersion string
Pinned bool
URL string
}

func NewCmdExtension(io *iostreams.IOStreams, em extensions.ExtensionManager, ext extensions.Extension) *cobra.Command {
// Setup channel containing information about potential latest release info
updateMessageChan := make(chan *extensionReleaseInfo)

return &cobra.Command{
Use: ext.Name(),
Short: fmt.Sprintf("Extension %s", ext.Name()),
// 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() {
if ext.UpdateAvailable() {
updateMessageChan <- &extensionReleaseInfo{
CurrentVersion: ext.CurrentVersion(),
LatestVersion: ext.LatestVersion(),
Pinned: ext.IsPinned(),
URL: ext.URL(),
}
}
}()
},
RunE: func(c *cobra.Command, args []string) error {
args = append([]string{ext.Name()}, args...)
if _, err := em.Dispatch(args, io.In, io.Out, io.ErrOut); err != nil {
Expand All @@ -29,6 +54,24 @@ func NewCmdExtension(io *iostreams.IOStreams, em extensions.ExtensionManager, ex
}
return nil
},
// PostRun handles communicating extension release information if found
PostRun: func(c *cobra.Command, args []string) {
releaseInfo := <-updateMessageChan
if releaseInfo != nil {
stderr := io.ErrOut
fmt.Fprintf(stderr, "\n\n%s %s → %s\n",
ansi.Color(fmt.Sprintf("A new release of %s is available:", ext.Name()), "yellow"),
ansi.Color(strings.TrimPrefix(releaseInfo.CurrentVersion, "v"), "cyan"),
ansi.Color(strings.TrimPrefix(releaseInfo.LatestVersion, "v"), "cyan"))
if releaseInfo.Pinned {
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",
ansi.Color(releaseInfo.URL, "yellow"))
}
},
GroupID: "extension",
Annotations: map[string]string{
"skipAuthCheck": "true",
Expand Down

0 comments on commit 47d77bd

Please sign in to comment.