pinning script exts

This commit is contained in:
meiji163 2022-03-02 19:25:25 -08:00
parent d7277e396c
commit db53df102c
3 changed files with 78 additions and 7 deletions

View file

@ -116,18 +116,28 @@ func NewCmdExtension(f *cmdutil.Factory) *cobra.Command {
return err
}
cs := io.ColorScheme()
if err := m.Install(repo, pinFlag); err != nil {
if errors.Is(err, releaseNotFoundErr) {
return fmt.Errorf("%s Could not find a release of %s for %s",
cs.FailureIcon(), args[0], cs.Cyan(pinFlag))
} else if errors.Is(err, commitNotFoundErr) {
return fmt.Errorf("%s %s does not exist in %s",
cs.FailureIcon(), cs.Cyan(pinFlag), args[0])
}
return err
}
if io.IsStdoutTTY() {
cs := io.ColorScheme()
fmt.Fprintf(io.Out, "%s Installed extension %s\n", cs.SuccessIcon(), args[0])
if pinFlag != "" {
fmt.Fprintf(io.Out, "%s Pinned extension at %s\n", cs.SuccessIcon(), cs.Cyan(pinFlag))
}
}
return nil
},
}
cmd.Flags().StringVar(&pinFlag, "pin", "", "pin extension to a release tag or commit sha")
cmd.Flags().StringVar(&pinFlag, "pin", "", "pin extension to a release tag or commit ref")
return cmd
}(),
func() *cobra.Command {

View file

@ -2,6 +2,7 @@ package extension
import (
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
@ -80,6 +81,9 @@ func downloadAsset(httpClient *http.Client, asset releaseAsset, destPath string)
return err
}
var releaseNotFoundErr = errors.New("release not found")
var commitNotFoundErr = errors.New("commit not found")
// fetchLatestRelease finds the latest published release for a repository.
func fetchLatestRelease(httpClient *http.Client, baseRepo ghrepo.Interface) (*release, error) {
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
return &r, nil
}
// fetchRelease finds release by tag name for a repository
// fetchReleaseFromTag finds release by tag name for a repository
func fetchReleaseFromTag(httpClient *http.Client, baseRepo ghrepo.Interface, tagName string) (*release, error) {
fullRepoName := fmt.Sprintf("%s/%s", baseRepo.RepoOwner(), baseRepo.RepoName())
path := fmt.Sprintf("repos/%s/releases/tags/%s", fullRepoName, tagName)
@ -129,6 +133,9 @@ func fetchReleaseFromTag(httpClient *http.Client, baseRepo ghrepo.Interface, tag
return nil, err
}
if resp.StatusCode == 404 {
return nil, releaseNotFoundErr
}
if resp.StatusCode > 299 {
return nil, api.HandleHTTPError(resp)
}
@ -146,3 +153,34 @@ func fetchReleaseFromTag(httpClient *http.Client, baseRepo ghrepo.Interface, tag
return &r, nil
}
// fetchCommitSHA finds full commit SHA from a target ref in a repo
func fetchCommitSHA(httpClient *http.Client, baseRepo ghrepo.Interface, targetRef string) (string, error) {
path := fmt.Sprintf("repos/%s/%s/commits/%s", baseRepo.RepoOwner(), baseRepo.RepoName(), targetRef)
url := ghinstance.RESTPrefix(baseRepo.RepoHost()) + path
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return "", err
}
req.Header.Set("Accept", "application/vnd.github.VERSION.sha")
resp, err := httpClient.Do(req)
defer resp.Body.Close()
if err != nil {
return "", err
}
if resp.StatusCode == 422 {
return "", commitNotFoundErr
}
if resp.StatusCode > 299 {
return "", api.HandleHTTPError(resp)
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", err
}
return string(body), nil
}

View file

@ -8,6 +8,7 @@ import (
"io"
"io/fs"
"io/ioutil"
"log"
"net/http"
"os"
"os/exec"
@ -320,6 +321,7 @@ type binManifest struct {
Path string
}
// Install an extension from repo, and pin to commitish if provided
func (m *Manager) Install(repo ghrepo.Interface, targetCommitish string) error {
isBin, err := isBinExtension(m.client, repo)
if err != nil {
@ -337,11 +339,11 @@ func (m *Manager) Install(repo ghrepo.Interface, targetCommitish string) error {
return errors.New("extension is not installable: missing executable")
}
protocol, _ := m.config.GetOrDefault(repo.RepoHost(), "git_protocol")
return m.installGit(ghrepo.FormatRemoteURL(repo, protocol), m.io.Out, m.io.ErrOut)
return m.installGit(repo, targetCommitish, m.io.Out, m.io.ErrOut)
}
func (m *Manager) installBin(repo ghrepo.Interface, targetCommitish string) error {
log.Println("Installing binary extension")
var r *release
var err error
if targetCommitish == "" {
@ -413,19 +415,40 @@ func (m *Manager) installBin(repo ghrepo.Interface, targetCommitish string) erro
return nil
}
func (m *Manager) installGit(cloneURL string, stdout, stderr io.Writer) error {
func (m *Manager) installGit(repo ghrepo.Interface, targetCommitish string, stdout, stderr io.Writer) error {
protocol, _ := m.config.GetOrDefault(repo.RepoHost(), "git_protocol")
cloneURL := ghrepo.FormatRemoteURL(repo, protocol)
exe, err := m.lookPath("git")
if err != nil {
return err
}
var commitSHA string
if targetCommitish != "" {
commitSHA, err = fetchCommitSHA(m.client, repo, targetCommitish)
if err != nil {
return err
}
}
name := strings.TrimSuffix(path.Base(cloneURL), ".git")
targetDir := filepath.Join(m.installDir(), name)
externalCmd := m.newCommand(exe, "clone", cloneURL, targetDir)
externalCmd.Stdout = stdout
externalCmd.Stderr = stderr
return externalCmd.Run()
if err := externalCmd.Run(); err != nil {
return err
}
if commitSHA == "" {
return nil
}
checkoutCmd := m.newCommand(exe, "-C", targetDir, "checkout", commitSHA)
checkoutCmd.Stdout = stdout
checkoutCmd.Stderr = stderr
return checkoutCmd.Run()
}
var localExtensionUpgradeError = errors.New("local extensions can not be upgraded")