@@ -65,7 +65,13 @@ func NewCmdExtension(f *cmdutil.Factory) *cobra.Command {
6565 if ! c .IsBinary () && len (version ) > 8 {
6666 version = version [:8 ]
6767 }
68- t .AddField (version , nil , nil )
68+
69+ if c .IsPinned () {
70+ t .AddField (version , nil , cs .Cyan )
71+ } else {
72+ t .AddField (version , nil , nil )
73+ }
74+
6975 var updateAvailable string
7076 if c .UpdateAvailable () {
7177 updateAvailable = "Upgrade available"
@@ -76,10 +82,12 @@ func NewCmdExtension(f *cmdutil.Factory) *cobra.Command {
7682 return t .Render ()
7783 },
7884 },
79- & cobra.Command {
80- Use : "install <repository>" ,
81- Short : "Install a gh extension from a repository" ,
82- Long : heredoc .Doc (`
85+ func () * cobra.Command {
86+ var pinFlag string
87+ cmd := & cobra.Command {
88+ Use : "install <repository>" ,
89+ Short : "Install a gh extension from a repository" ,
90+ Long : heredoc .Doc (`
8391 Install a GitHub repository locally as a GitHub CLI extension.
8492
8593 The repository argument can be specified in "owner/repo" format as well as a full URL.
@@ -90,41 +98,57 @@ func NewCmdExtension(f *cmdutil.Factory) *cobra.Command {
9098
9199 See the list of available extensions at <https://github.com/topics/gh-extension>.
92100 ` ),
93- Example : heredoc .Doc (`
101+ Example : heredoc .Doc (`
94102 $ gh extension install owner/gh-extension
95103 $ gh extension install https://git.example.com/owner/gh-extension
96104 $ gh extension install .
97105 ` ),
98- Args : cmdutil .MinimumArgs (1 , "must specify a repository to install from" ),
99- RunE : func (cmd * cobra.Command , args []string ) error {
100- if args [0 ] == "." {
101- wd , err := os .Getwd ()
106+ Args : cmdutil .MinimumArgs (1 , "must specify a repository to install from" ),
107+ RunE : func (cmd * cobra.Command , args []string ) error {
108+ if args [0 ] == "." {
109+ if pinFlag != "" {
110+ return fmt .Errorf ("local extensions cannot be pinned" )
111+ }
112+ wd , err := os .Getwd ()
113+ if err != nil {
114+ return err
115+ }
116+ return m .InstallLocal (wd )
117+ }
118+
119+ repo , err := ghrepo .FromFullName (args [0 ])
102120 if err != nil {
103121 return err
104122 }
105- return m .InstallLocal (wd )
106- }
107-
108- repo , err := ghrepo .FromFullName (args [0 ])
109- if err != nil {
110- return err
111- }
112-
113- if err := checkValidExtension (cmd .Root (), m , repo .RepoName ()); err != nil {
114- return err
115- }
116123
117- if err := m . Install ( repo ); err != nil {
118- return err
119- }
124+ if err := checkValidExtension ( cmd . Root (), m , repo . RepoName () ); err != nil {
125+ return err
126+ }
120127
121- if io .IsStdoutTTY () {
122128 cs := io .ColorScheme ()
123- fmt .Fprintf (io .Out , "%s Installed extension %s\n " , cs .SuccessIcon (), args [0 ])
124- }
125- return nil
126- },
127- },
129+ if err := m .Install (repo , pinFlag ); err != nil {
130+ if errors .Is (err , releaseNotFoundErr ) {
131+ return fmt .Errorf ("%s Could not find a release of %s for %s" ,
132+ cs .FailureIcon (), args [0 ], cs .Cyan (pinFlag ))
133+ } else if errors .Is (err , commitNotFoundErr ) {
134+ return fmt .Errorf ("%s %s does not exist in %s" ,
135+ cs .FailureIcon (), cs .Cyan (pinFlag ), args [0 ])
136+ }
137+ return err
138+ }
139+
140+ if io .IsStdoutTTY () {
141+ fmt .Fprintf (io .Out , "%s Installed extension %s\n " , cs .SuccessIcon (), args [0 ])
142+ if pinFlag != "" {
143+ fmt .Fprintf (io .Out , "%s Pinned extension at %s\n " , cs .SuccessIcon (), cs .Cyan (pinFlag ))
144+ }
145+ }
146+ return nil
147+ },
148+ }
149+ cmd .Flags ().StringVar (& pinFlag , "pin" , "" , "pin extension to a release tag or commit ref" )
150+ return cmd
151+ }(),
128152 func () * cobra.Command {
129153 var flagAll bool
130154 var flagForce bool
@@ -153,6 +177,9 @@ func NewCmdExtension(f *cmdutil.Factory) *cobra.Command {
153177 if err != nil && ! errors .Is (err , upToDateError ) {
154178 if name != "" {
155179 fmt .Fprintf (io .ErrOut , "%s Failed upgrading extension %s: %s\n " , cs .FailureIcon (), name , err )
180+ } else if errors .Is (err , noExtensionsInstalledError ) {
181+ fmt .Fprintf (io .ErrOut , "%s No installed extensions found\n " , cs .WarningIcon ())
182+ return nil
156183 } else {
157184 fmt .Fprintf (io .ErrOut , "%s Failed upgrading extensions\n " , cs .FailureIcon ())
158185 }
0 commit comments