X Tutup
Skip to content

Commit d7277e3

Browse files
committed
pinning binary exts
1 parent e361fd4 commit d7277e3

File tree

5 files changed

+90
-40
lines changed

5 files changed

+90
-40
lines changed

pkg/cmd/extension/command.go

Lines changed: 34 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,12 @@ func NewCmdExtension(f *cmdutil.Factory) *cobra.Command {
7676
return t.Render()
7777
},
7878
},
79-
&cobra.Command{
80-
Use: "install <repository>",
81-
Short: "Install a gh extension from a repository",
82-
Long: heredoc.Doc(`
79+
func() *cobra.Command {
80+
var pinFlag string
81+
cmd := &cobra.Command{
82+
Use: "install <repository>",
83+
Short: "Install a gh extension from a repository",
84+
Long: heredoc.Doc(`
8385
Install a GitHub repository locally as a GitHub CLI extension.
8486
8587
The repository argument can be specified in "owner/repo" format as well as a full URL.
@@ -90,41 +92,44 @@ func NewCmdExtension(f *cmdutil.Factory) *cobra.Command {
9092
9193
See the list of available extensions at <https://github.com/topics/gh-extension>.
9294
`),
93-
Example: heredoc.Doc(`
95+
Example: heredoc.Doc(`
9496
$ gh extension install owner/gh-extension
9597
$ gh extension install https://git.example.com/owner/gh-extension
9698
$ gh extension install .
9799
`),
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()
100+
Args: cmdutil.MinimumArgs(1, "must specify a repository to install from"),
101+
RunE: func(cmd *cobra.Command, args []string) error {
102+
if args[0] == "." {
103+
wd, err := os.Getwd()
104+
if err != nil {
105+
return err
106+
}
107+
return m.InstallLocal(wd)
108+
}
109+
110+
repo, err := ghrepo.FromFullName(args[0])
102111
if err != nil {
103112
return err
104113
}
105-
return m.InstallLocal(wd)
106-
}
107-
108-
repo, err := ghrepo.FromFullName(args[0])
109-
if err != nil {
110-
return err
111-
}
112114

113-
if err := checkValidExtension(cmd.Root(), m, repo.RepoName()); err != nil {
114-
return err
115-
}
115+
if err := checkValidExtension(cmd.Root(), m, repo.RepoName()); err != nil {
116+
return err
117+
}
116118

117-
if err := m.Install(repo); err != nil {
118-
return err
119-
}
119+
if err := m.Install(repo, pinFlag); err != nil {
120+
return err
121+
}
120122

121-
if io.IsStdoutTTY() {
122-
cs := io.ColorScheme()
123-
fmt.Fprintf(io.Out, "%s Installed extension %s\n", cs.SuccessIcon(), args[0])
124-
}
125-
return nil
126-
},
127-
},
123+
if io.IsStdoutTTY() {
124+
cs := io.ColorScheme()
125+
fmt.Fprintf(io.Out, "%s Installed extension %s\n", cs.SuccessIcon(), args[0])
126+
}
127+
return nil
128+
},
129+
}
130+
cmd.Flags().StringVar(&pinFlag, "pin", "", "pin extension to a release tag or commit sha")
131+
return cmd
132+
}(),
128133
func() *cobra.Command {
129134
var flagAll bool
130135
var flagForce bool

pkg/cmd/extension/http.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,3 +112,37 @@ func fetchLatestRelease(httpClient *http.Client, baseRepo ghrepo.Interface) (*re
112112

113113
return &r, nil
114114
}
115+
116+
// fetchRelease finds release by tag name for a repository
117+
func fetchReleaseFromTag(httpClient *http.Client, baseRepo ghrepo.Interface, tagName string) (*release, error) {
118+
fullRepoName := fmt.Sprintf("%s/%s", baseRepo.RepoOwner(), baseRepo.RepoName())
119+
path := fmt.Sprintf("repos/%s/releases/tags/%s", fullRepoName, tagName)
120+
url := ghinstance.RESTPrefix(baseRepo.RepoHost()) + path
121+
req, err := http.NewRequest("GET", url, nil)
122+
if err != nil {
123+
return nil, err
124+
}
125+
126+
resp, err := httpClient.Do(req)
127+
defer resp.Body.Close()
128+
if err != nil {
129+
return nil, err
130+
}
131+
132+
if resp.StatusCode > 299 {
133+
return nil, api.HandleHTTPError(resp)
134+
}
135+
136+
b, err := ioutil.ReadAll(resp.Body)
137+
if err != nil {
138+
return nil, err
139+
}
140+
141+
var r release
142+
err = json.Unmarshal(b, &r)
143+
if err != nil {
144+
return nil, err
145+
}
146+
147+
return &r, nil
148+
}

pkg/cmd/extension/manager.go

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -320,13 +320,13 @@ type binManifest struct {
320320
Path string
321321
}
322322

323-
func (m *Manager) Install(repo ghrepo.Interface) error {
323+
func (m *Manager) Install(repo ghrepo.Interface, targetCommitish string) error {
324324
isBin, err := isBinExtension(m.client, repo)
325325
if err != nil {
326326
return fmt.Errorf("could not check for binary extension: %w", err)
327327
}
328328
if isBin {
329-
return m.installBin(repo)
329+
return m.installBin(repo, targetCommitish)
330330
}
331331

332332
hs, err := hasScript(m.client, repo)
@@ -341,9 +341,14 @@ func (m *Manager) Install(repo ghrepo.Interface) error {
341341
return m.installGit(ghrepo.FormatRemoteURL(repo, protocol), m.io.Out, m.io.ErrOut)
342342
}
343343

344-
func (m *Manager) installBin(repo ghrepo.Interface) error {
344+
func (m *Manager) installBin(repo ghrepo.Interface, targetCommitish string) error {
345345
var r *release
346-
r, err := fetchLatestRelease(m.client, repo)
346+
var err error
347+
if targetCommitish == "" {
348+
r, err = fetchLatestRelease(m.client, repo)
349+
} else {
350+
r, err = fetchReleaseFromTag(m.client, repo, targetCommitish)
351+
}
347352
if err != nil {
348353
return err
349354
}
@@ -498,7 +503,7 @@ func (m *Manager) upgradeExtension(ext Extension, force bool) error {
498503
if err != nil {
499504
return fmt.Errorf("failed to migrate to new precompiled extension format: %w", err)
500505
}
501-
return m.installBin(repo)
506+
return m.installBin(repo, "")
502507
}
503508
err = m.upgradeGitExtension(ext, force)
504509
}
@@ -525,7 +530,7 @@ func (m *Manager) upgradeBinExtension(ext Extension) error {
525530
if err != nil {
526531
return fmt.Errorf("failed to parse URL %s: %w", ext.url, err)
527532
}
528-
return m.installBin(repo)
533+
return m.installBin(repo, "")
529534
}
530535

531536
func (m *Manager) Remove(name string) error {

pkg/extensions/extension.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ type Extension interface {
2828
//go:generate moq -rm -out manager_mock.go . ExtensionManager
2929
type ExtensionManager interface {
3030
List(includeMetadata bool) []Extension
31-
Install(ghrepo.Interface) error
31+
Install(ghrepo.Interface, string) error
3232
InstallLocal(dir string) error
3333
Upgrade(name string, force bool) error
3434
Remove(name string) error

pkg/extensions/manager_mock.go

Lines changed: 10 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)
X Tutup