Skip to content

Commit db53df1

Browse files
committed
pinning script exts
1 parent d7277e3 commit db53df1

File tree

3 files changed

+78
-7
lines changed

3 files changed

+78
-7
lines changed

pkg/cmd/extension/command.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,18 +116,28 @@ func NewCmdExtension(f *cmdutil.Factory) *cobra.Command {
116116
return err
117117
}
118118

119+
cs := io.ColorScheme()
119120
if err := m.Install(repo, pinFlag); err != nil {
121+
if errors.Is(err, releaseNotFoundErr) {
122+
return fmt.Errorf("%s Could not find a release of %s for %s",
123+
cs.FailureIcon(), args[0], cs.Cyan(pinFlag))
124+
} else if errors.Is(err, commitNotFoundErr) {
125+
return fmt.Errorf("%s %s does not exist in %s",
126+
cs.FailureIcon(), cs.Cyan(pinFlag), args[0])
127+
}
120128
return err
121129
}
122130

123131
if io.IsStdoutTTY() {
124-
cs := io.ColorScheme()
125132
fmt.Fprintf(io.Out, "%s Installed extension %s\n", cs.SuccessIcon(), args[0])
133+
if pinFlag != "" {
134+
fmt.Fprintf(io.Out, "%s Pinned extension at %s\n", cs.SuccessIcon(), cs.Cyan(pinFlag))
135+
}
126136
}
127137
return nil
128138
},
129139
}
130-
cmd.Flags().StringVar(&pinFlag, "pin", "", "pin extension to a release tag or commit sha")
140+
cmd.Flags().StringVar(&pinFlag, "pin", "", "pin extension to a release tag or commit ref")
131141
return cmd
132142
}(),
133143
func() *cobra.Command {

pkg/cmd/extension/http.go

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package extension
22

33
import (
44
"encoding/json"
5+
"errors"
56
"fmt"
67
"io"
78
"io/ioutil"
@@ -80,6 +81,9 @@ func downloadAsset(httpClient *http.Client, asset releaseAsset, destPath string)
8081
return err
8182
}
8283

84+
var releaseNotFoundErr = errors.New("release not found")
85+
var commitNotFoundErr = errors.New("commit not found")
86+
8387
// fetchLatestRelease finds the latest published release for a repository.
8488
func fetchLatestRelease(httpClient *http.Client, baseRepo ghrepo.Interface) (*release, error) {
8589
path := fmt.Sprintf("repos/%s/%s/releases/latest", baseRepo.RepoOwner(), baseRepo.RepoName())
@@ -113,7 +117,7 @@ func fetchLatestRelease(httpClient *http.Client, baseRepo ghrepo.Interface) (*re
113117
return &r, nil
114118
}
115119

116-
// fetchRelease finds release by tag name for a repository
120+
// fetchReleaseFromTag finds release by tag name for a repository
117121
func fetchReleaseFromTag(httpClient *http.Client, baseRepo ghrepo.Interface, tagName string) (*release, error) {
118122
fullRepoName := fmt.Sprintf("%s/%s", baseRepo.RepoOwner(), baseRepo.RepoName())
119123
path := fmt.Sprintf("repos/%s/releases/tags/%s", fullRepoName, tagName)
@@ -129,6 +133,9 @@ func fetchReleaseFromTag(httpClient *http.Client, baseRepo ghrepo.Interface, tag
129133
return nil, err
130134
}
131135

136+
if resp.StatusCode == 404 {
137+
return nil, releaseNotFoundErr
138+
}
132139
if resp.StatusCode > 299 {
133140
return nil, api.HandleHTTPError(resp)
134141
}
@@ -146,3 +153,34 @@ func fetchReleaseFromTag(httpClient *http.Client, baseRepo ghrepo.Interface, tag
146153

147154
return &r, nil
148155
}
156+
157+
// fetchCommitSHA finds full commit SHA from a target ref in a repo
158+
func fetchCommitSHA(httpClient *http.Client, baseRepo ghrepo.Interface, targetRef string) (string, error) {
159+
path := fmt.Sprintf("repos/%s/%s/commits/%s", baseRepo.RepoOwner(), baseRepo.RepoName(), targetRef)
160+
url := ghinstance.RESTPrefix(baseRepo.RepoHost()) + path
161+
req, err := http.NewRequest("GET", url, nil)
162+
if err != nil {
163+
return "", err
164+
}
165+
166+
req.Header.Set("Accept", "application/vnd.github.VERSION.sha")
167+
resp, err := httpClient.Do(req)
168+
defer resp.Body.Close()
169+
if err != nil {
170+
return "", err
171+
}
172+
173+
if resp.StatusCode == 422 {
174+
return "", commitNotFoundErr
175+
}
176+
if resp.StatusCode > 299 {
177+
return "", api.HandleHTTPError(resp)
178+
}
179+
180+
body, err := ioutil.ReadAll(resp.Body)
181+
if err != nil {
182+
return "", err
183+
}
184+
185+
return string(body), nil
186+
}

pkg/cmd/extension/manager.go

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"io"
99
"io/fs"
1010
"io/ioutil"
11+
"log"
1112
"net/http"
1213
"os"
1314
"os/exec"
@@ -320,6 +321,7 @@ type binManifest struct {
320321
Path string
321322
}
322323

324+
// Install an extension from repo, and pin to commitish if provided
323325
func (m *Manager) Install(repo ghrepo.Interface, targetCommitish string) error {
324326
isBin, err := isBinExtension(m.client, repo)
325327
if err != nil {
@@ -337,11 +339,11 @@ func (m *Manager) Install(repo ghrepo.Interface, targetCommitish string) error {
337339
return errors.New("extension is not installable: missing executable")
338340
}
339341

340-
protocol, _ := m.config.GetOrDefault(repo.RepoHost(), "git_protocol")
341-
return m.installGit(ghrepo.FormatRemoteURL(repo, protocol), m.io.Out, m.io.ErrOut)
342+
return m.installGit(repo, targetCommitish, m.io.Out, m.io.ErrOut)
342343
}
343344

344345
func (m *Manager) installBin(repo ghrepo.Interface, targetCommitish string) error {
346+
log.Println("Installing binary extension")
345347
var r *release
346348
var err error
347349
if targetCommitish == "" {
@@ -413,19 +415,40 @@ func (m *Manager) installBin(repo ghrepo.Interface, targetCommitish string) erro
413415
return nil
414416
}
415417

416-
func (m *Manager) installGit(cloneURL string, stdout, stderr io.Writer) error {
418+
func (m *Manager) installGit(repo ghrepo.Interface, targetCommitish string, stdout, stderr io.Writer) error {
419+
protocol, _ := m.config.GetOrDefault(repo.RepoHost(), "git_protocol")
420+
cloneURL := ghrepo.FormatRemoteURL(repo, protocol)
421+
417422
exe, err := m.lookPath("git")
418423
if err != nil {
419424
return err
420425
}
421426

427+
var commitSHA string
428+
if targetCommitish != "" {
429+
commitSHA, err = fetchCommitSHA(m.client, repo, targetCommitish)
430+
if err != nil {
431+
return err
432+
}
433+
}
434+
422435
name := strings.TrimSuffix(path.Base(cloneURL), ".git")
423436
targetDir := filepath.Join(m.installDir(), name)
424437

425438
externalCmd := m.newCommand(exe, "clone", cloneURL, targetDir)
426439
externalCmd.Stdout = stdout
427440
externalCmd.Stderr = stderr
428-
return externalCmd.Run()
441+
if err := externalCmd.Run(); err != nil {
442+
return err
443+
}
444+
if commitSHA == "" {
445+
return nil
446+
}
447+
448+
checkoutCmd := m.newCommand(exe, "-C", targetDir, "checkout", commitSHA)
449+
checkoutCmd.Stdout = stdout
450+
checkoutCmd.Stderr = stderr
451+
return checkoutCmd.Run()
429452
}
430453

431454
var localExtensionUpgradeError = errors.New("local extensions can not be upgraded")

0 commit comments

Comments
 (0)