| 20 | } |
| 21 | |
| 22 | func NewCmdExtension(io *iostreams.IOStreams, em extensions.ExtensionManager, ext extensions.Extension, checkExtensionReleaseInfo func(extensions.ExtensionManager, extensions.Extension) (*update.ReleaseInfo, error)) *cobra.Command { |
| 23 | updateMessageChan := make(chan *update.ReleaseInfo) |
| 24 | cs := io.ColorScheme() |
| 25 | hasDebug, _ := utils.IsDebugEnabled() |
| 26 | if checkExtensionReleaseInfo == nil { |
| 27 | checkExtensionReleaseInfo = checkForExtensionUpdate |
| 28 | } |
| 29 | |
| 30 | cmd := &cobra.Command{ |
| 31 | Use: ext.Name(), |
| 32 | Short: fmt.Sprintf("Extension %s", ext.Name()), |
| 33 | // PreRun handles looking up whether extension has a latest version only when the command is ran. |
| 34 | PreRun: func(c *cobra.Command, args []string) { |
| 35 | go func() { |
| 36 | releaseInfo, err := checkExtensionReleaseInfo(em, ext) |
| 37 | if err != nil && hasDebug { |
| 38 | fmt.Fprintf(io.ErrOut, "warning: checking for update failed: %v", err) |
| 39 | } |
| 40 | updateMessageChan <- releaseInfo |
| 41 | }() |
| 42 | }, |
| 43 | RunE: func(c *cobra.Command, args []string) error { |
| 44 | args = append([]string{ext.Name()}, args...) |
| 45 | if _, err := em.Dispatch(args, io.In, io.Out, io.ErrOut); err != nil { |
| 46 | var execError *exec.ExitError |
| 47 | if errors.As(err, &execError) { |
| 48 | return &ExternalCommandExitError{execError} |
| 49 | } |
| 50 | return fmt.Errorf("failed to run extension: %w\n", err) |
| 51 | } |
| 52 | return nil |
| 53 | }, |
| 54 | // PostRun handles communicating extension release information if found |
| 55 | PostRun: func(c *cobra.Command, args []string) { |
| 56 | select { |
| 57 | case releaseInfo := <-updateMessageChan: |
| 58 | if releaseInfo != nil { |
| 59 | stderr := io.ErrOut |
| 60 | fmt.Fprintf(stderr, "\n\n%s %s → %s\n", |
| 61 | cs.Yellowf("A new release of %s is available:", ext.Name()), |
| 62 | cs.Cyan(strings.TrimPrefix(ext.CurrentVersion(), "v")), |
| 63 | cs.Cyan(strings.TrimPrefix(releaseInfo.Version, "v"))) |
| 64 | if ext.IsPinned() { |
| 65 | fmt.Fprintf(stderr, "To upgrade, run: gh extension upgrade %s --force\n", ext.Name()) |
| 66 | } else { |
| 67 | fmt.Fprintf(stderr, "To upgrade, run: gh extension upgrade %s\n", ext.Name()) |
| 68 | } |
| 69 | fmt.Fprintf(stderr, "%s\n\n", |
| 70 | cs.Yellow(releaseInfo.URL)) |
| 71 | } |
| 72 | default: |
| 73 | // Do not make the user wait for extension update check if incomplete by this time. |
| 74 | // This is being handled in non-blocking default as there is no context to cancel like in gh update checks. |
| 75 | } |
| 76 | }, |
| 77 | GroupID: "extension", |
| 78 | DisableFlagParsing: true, |
| 79 | } |