Allow passing full extension name (#5464)

This commit is contained in:
Heath Stewart 2022-05-17 23:35:47 -07:00 committed by GitHub
parent bec49152cf
commit 00e97121ec
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 90 additions and 31 deletions

View file

@ -31,7 +31,8 @@ func NewCmdExtension(f *cmdutil.Factory) *cobra.Command {
executable of the same name. All arguments passed to the %[1]sgh <extname>%[1]s invocation
will be forwarded to the %[1]sgh-<extname>%[1]s executable of the extension.
An extension cannot override any of the core gh commands.
An extension cannot override any of the core gh commands. If an extension name conflicts
with a core gh command you can use %[1]sgh extension exec <extname>%[1]s.
See the list of available extensions at <https://github.com/topics/gh-extension>.
`, "`"),
@ -79,21 +80,21 @@ func NewCmdExtension(f *cmdutil.Factory) *cobra.Command {
Use: "install <repository>",
Short: "Install a gh extension from a repository",
Long: heredoc.Doc(`
Install a GitHub repository locally as a GitHub CLI extension.
Install a GitHub repository locally as a GitHub CLI extension.
The repository argument can be specified in "owner/repo" format as well as a full URL.
The URL format is useful when the repository is not hosted on github.com.
The repository argument can be specified in "owner/repo" format as well as a full URL.
The URL format is useful when the repository is not hosted on github.com.
To install an extension in development from the current directory, use "." as the
value of the repository argument.
To install an extension in development from the current directory, use "." as the
value of the repository argument.
See the list of available extensions at <https://github.com/topics/gh-extension>.
`),
See the list of available extensions at <https://github.com/topics/gh-extension>.
`),
Example: heredoc.Doc(`
$ gh extension install owner/gh-extension
$ gh extension install https://git.example.com/owner/gh-extension
$ gh extension install .
`),
$ gh extension install owner/gh-extension
$ gh extension install https://git.example.com/owner/gh-extension
$ gh extension install .
`),
Args: cmdutil.MinimumArgs(1, "must specify a repository to install from"),
RunE: func(cmd *cobra.Command, args []string) error {
if args[0] == "." {
@ -216,6 +217,31 @@ func NewCmdExtension(f *cmdutil.Factory) *cobra.Command {
return nil
},
},
&cobra.Command{
Use: "exec <name> [args]",
Short: "Execute an installed extension",
Long: heredoc.Doc(`
Execute an extension using the short name. For example, if the extension repository is
"owner/gh-extension", you should pass "extension". You can use this command when
the short name conflicts with a core gh command.
All arguments after the extension name will be forwarded to the executable
of the extension.
`),
Example: heredoc.Doc(`
# execute a label extension instead of the core gh label command
$ gh extension exec label
`),
Args: cobra.MinimumNArgs(1),
DisableFlagParsing: true,
RunE: func(cmd *cobra.Command, args []string) error {
if found, err := m.Dispatch(args, io.In, io.Out, io.ErrOut); !found {
return fmt.Errorf("extension %q not found", args[0])
} else {
return err
}
},
},
func() *cobra.Command {
promptCreate := func() (string, extensions.ExtTemplateType, error) {
var extName string
@ -241,17 +267,17 @@ func NewCmdExtension(f *cmdutil.Factory) *cobra.Command {
Use: "create [<name>]",
Short: "Create a new extension",
Example: heredoc.Doc(`
# Use interactively
gh extension create
# Use interactively
gh extension create
# Create a script-based extension
gh extension create foobar
# Create a script-based extension
gh extension create foobar
# Create a Go extension
gh extension create --precompiled=go foobar
# Create a Go extension
gh extension create --precompiled=go foobar
# Create a non-Go precompiled extension
gh extension create --precompiled=other foobar
# Create a non-Go precompiled extension
gh extension create --precompiled=other foobar
`),
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
@ -317,19 +343,19 @@ func NewCmdExtension(f *cmdutil.Factory) *cobra.Command {
}
link := "https://docs.github.com/github-cli/github-cli/creating-github-cli-extensions"
out := heredoc.Docf(`
%[1]s Created directory %[2]s
%[1]s Initialized git repository
%[1]s Set up extension scaffolding
%[6]s
%[2]s is ready for development!
%[1]s Created directory %[2]s
%[1]s Initialized git repository
%[1]s Set up extension scaffolding
%[6]s
%[2]s is ready for development!
%[4]s
%[5]s
- commit and use 'gh repo create' to share your extension with others
%[4]s
%[5]s
- commit and use 'gh repo create' to share your extension with others
For more information on writing extensions:
%[3]s
`, cs.SuccessIcon(), fullName, link, cs.Bold("Next Steps"), steps, goBinChecks)
For more information on writing extensions:
%[3]s
`, cs.SuccessIcon(), fullName, link, cs.Bold("Next Steps"), steps, goBinChecks)
fmt.Fprint(io.Out, out)
return nil
},

View file

@ -2,6 +2,7 @@ package extension
import (
"errors"
"fmt"
"io"
"net/http"
"os"
@ -515,6 +516,38 @@ func TestNewCmdExtension(t *testing.T) {
isTTY: false,
wantStdout: "",
},
{
name: "exec extension missing",
args: []string{"exec", "invalid"},
managerStubs: func(em *extensions.ExtensionManagerMock) func(*testing.T) {
em.DispatchFunc = func(args []string, stdin io.Reader, stdout, stderr io.Writer) (bool, error) {
return false, nil
}
return func(t *testing.T) {
calls := em.DispatchCalls()
assert.Equal(t, 1, len(calls))
assert.EqualValues(t, []string{"invalid"}, calls[0].Args)
}
},
wantErr: true,
errMsg: `extension "invalid" not found`,
},
{
name: "exec extension with arguments",
args: []string{"exec", "test", "arg1", "arg2", "--flag1"},
managerStubs: func(em *extensions.ExtensionManagerMock) func(*testing.T) {
em.DispatchFunc = func(args []string, stdin io.Reader, stdout, stderr io.Writer) (bool, error) {
fmt.Fprintf(stdout, "test output")
return true, nil
}
return func(t *testing.T) {
calls := em.DispatchCalls()
assert.Equal(t, 1, len(calls))
assert.EqualValues(t, []string{"test", "arg1", "arg2", "--flag1"}, calls[0].Args)
}
},
wantStdout: "test output",
},
}
for _, tt := range tests {