From c0bf43ed586f961b22403dc3be2f2c18492f7f1a Mon Sep 17 00:00:00 2001 From: b4b4r07 Date: Sat, 18 Mar 2023 11:42:25 +0900 Subject: [PATCH] Support gh extension --- docs/configuration/package/github.md | 22 +++++++++++++++++ docs/index.md | 2 ++ pkg/config/github.go | 35 +++++++++++++++++++++++++--- pkg/github/github.go | 16 +++++++++++++ 4 files changed, 72 insertions(+), 3 deletions(-) diff --git a/docs/configuration/package/github.md b/docs/configuration/package/github.md index 1894053..d2e4896 100644 --- a/docs/configuration/package/github.md +++ b/docs/configuration/package/github.md @@ -87,6 +87,28 @@ number | `0` (all commits) Limit fetching to the specified number of commits from the tip of each remote branch history. If fetching to a shallow repository, specify 1 or more number, deepen or shorten the history to the specified number of commits. +### as + +Type | Default +---|--- +string | `""` + +Available arguments: + +- gh-extension + +=== "gh-extension" + + Install a package as [gh extension](https://github.blog/2023-01-13-new-github-cli-extension-tools/). Officially gh extensions can be installed with `gh extension install owern/repo` command ([guide](https://cli.github.com/manual/gh_extension_install)) but it's difficult to manage what we downloaded as code. In afx, by handling them as the same as other packages, it allows us to codenize them. + + ```yaml + - name: dlvhdr/gh-dash + description: A beautiful CLI dashboard for GitHub + owner: dlvhdr + repo: gh-dash + as: gh-extension + ``` + ### release.name Type | Default diff --git a/docs/index.md b/docs/index.md index 6e67319..fef01e3 100644 --- a/docs/index.md +++ b/docs/index.md @@ -29,3 +29,5 @@ Flags: Use "afx [command] --help" for more information about a command. ``` + +![](https://user-images.githubusercontent.com/4442708/224565945-2c09b729-82b7-4829-9cbc-e247b401b689.gif) diff --git a/pkg/config/github.go b/pkg/config/github.go index 09a2256..d73009f 100644 --- a/pkg/config/github.go +++ b/pkg/config/github.go @@ -5,6 +5,7 @@ import ( "fmt" "io/ioutil" "log" + "net/http" "os" "path/filepath" @@ -22,16 +23,19 @@ import ( "github.com/fatih/color" ) +const GHExtension = "gh-extension" + // GitHub represents GitHub repository type GitHub struct { Name string `yaml:"name" validate:"required"` - Owner string `yaml:"owner" validate:"required"` - Repo string `yaml:"repo" validate:"required"` + Owner string `yaml:"owner" validate:"required"` + Repo string `yaml:"repo" validate:"required"` Description string `yaml:"description"` Branch string `yaml:"branch"` Option *GitHubOption `yaml:"with"` + As string `yaml:"as" validate:"excluded_with=Release"` Release *GitHubRelease `yaml:"release"` @@ -167,6 +171,20 @@ func (c GitHub) Install(ctx context.Context, status chan<- Status) error { } } + switch c.As { + case GHExtension: + // https://github.com/cli/cli/tree/trunk/pkg/cmd/extension + ok, _ := github.HasRelease(http.DefaultClient, c.Owner, c.Repo) + if ok { + err := c.InstallFromRelease(ctx) + if err != nil { + err = errors.Wrapf(err, "%s: failed to get from release", c.Name) + status <- Status{Name: c.GetName(), Done: true, Err: true} + return err + } + } + } + var errs errors.Errors if c.HasPluginBlock() { errs.Append(c.Plugin.Install(c)) @@ -202,13 +220,20 @@ func (c GitHub) Installed() bool { return check(list) } +func (c GitHub) GetReleaseTag() string { + if c.Release != nil { + return c.Release.Tag + } + return "latest" +} + // InstallFromRelease runs install from GitHub release, from not repository func (c GitHub) InstallFromRelease(ctx context.Context) error { ctx, cancel := context.WithCancel(ctx) defer cancel() release, err := github.NewRelease( - ctx, c.Owner, c.Repo, c.Release.Tag, + ctx, c.Owner, c.Repo, c.GetReleaseTag(), github.WithWorkdir(c.GetHome()), github.WithFilter(func(filename string) github.FilterFunc { if filename == "" { @@ -343,6 +368,10 @@ func (c GitHub) GetName() string { // GetHome returns a path func (c GitHub) GetHome() string { + switch c.As { + case GHExtension: + return filepath.Join(os.Getenv("HOME"), ".local", "share", "gh", "extensions", c.Repo) + } return filepath.Join(os.Getenv("HOME"), ".afx", "github.com", c.Owner, c.Repo) } diff --git a/pkg/github/github.go b/pkg/github/github.go index ef1108d..9183e1e 100644 --- a/pkg/github/github.go +++ b/pkg/github/github.go @@ -376,3 +376,19 @@ func (r *Release) Install(to string) error { TargetPath: to, }) } + +func HasRelease(httpClient *http.Client, owner, repo string) (bool, error) { + // https://github.com/cli/cli/blob/9596fd5368cdbd30d08555266890a2312e22eba9/pkg/cmd/extension/http.go#L110 + url := fmt.Sprintf("https://api.github.com/repos/%s/%s/releases/latest", owner, repo) + req, err := http.NewRequest("GET", url, nil) + if err != nil { + return false, err + } + + resp, err := httpClient.Do(req) + if err != nil { + return false, err + } + defer resp.Body.Close() + return resp.StatusCode < 299, nil +}