From 3bc7b7e7e25b75fd5d6bf9b1e3b667a21c003147 Mon Sep 17 00:00:00 2001 From: Azeem Sajid Date: Thu, 30 Jan 2025 11:40:42 +0500 Subject: [PATCH 1/5] [gh extensions install] Improve help text and error message --- pkg/cmd/extension/command.go | 10 +++++++++- pkg/cmd/extension/manager.go | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/pkg/cmd/extension/command.go b/pkg/cmd/extension/command.go index dad4021b6..ae9a917a6 100644 --- a/pkg/cmd/extension/command.go +++ b/pkg/cmd/extension/command.go @@ -298,9 +298,17 @@ func NewCmdExtension(f *cmdutil.Factory) *cobra.Command { Long: heredoc.Docf(` Install a GitHub CLI extension from a GitHub or local repository. - For GitHub repositories, the repository argument can be specified in %[1]sOWNER/REPO%[1]s format or as a full repository URL. + For GitHub repositories, the repository argument can be specified in + %[1]sOWNER/REPO%[1]s format or as a full repository URL. The URL format is useful when the repository is not hosted on github.com. + For remote repositories, the GitHub CLI first looks for the release artifacts assuming + that it's a binary extension i.e. prebuilt binaries provided as part of the release. + In the absence of a release, the repository itself is cloned assuming that it's a + script extension i.e. prebuilt executable or script exists on its root. + The %[1]s--pin%[1]s flag may be used to specify a tag or commit for binary and script + extensions respectively, the latest one is used otherwise. + For local repositories, often used while developing extensions, use %[1]s.%[1]s as the value of the repository argument. Note the following: diff --git a/pkg/cmd/extension/manager.go b/pkg/cmd/extension/manager.go index c6947f479..e83a3ed22 100644 --- a/pkg/cmd/extension/manager.go +++ b/pkg/cmd/extension/manager.go @@ -268,7 +268,7 @@ func (m *Manager) Install(repo ghrepo.Interface, target string) error { return err } if !hs { - return errors.New("extension is not installable: missing executable") + return fmt.Errorf("extension is not installable: no acceptable release artifact or script found in %s", repo) } return m.installGit(repo, target) From 6c21ab2284aed52fa92020590fdfbb9e2d8f3475 Mon Sep 17 00:00:00 2001 From: Tim Rogers Date: Mon, 3 Feb 2025 11:49:21 +0000 Subject: [PATCH 2/5] Error when `gh repo rename` is used with a new repo name that contains an owner MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `gh repo rename` can only rename a repo, but not change its owner (i.e. transfer it). As flagged in #10034, at the moment, the CLI behaves like it can do this, and produces weird results. If I ask to rename my repo to `polyseam/frappe-containers`: ```bash gh repo rename polyseam/frappe-containers ``` ..the preview suggests that it will do the right thing: ``` ? Rename polyseam/containers to polyseam/frappe-containers? Yes ``` ...but the repo gets renamed wrongly: ``` ✓ Renamed repository polyseam/polyseam-frappe-containers ``` This adds an upfront validation that looks for a slash and tells you that the command can't transfer a repo. Fixes #10034. --- .../repo/repo-rename-transfer-ownership.txtar | 9 +++++++++ pkg/cmd/repo/rename/rename.go | 7 ++++++- pkg/cmd/repo/rename/rename_test.go | 16 ++++++++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 acceptance/testdata/repo/repo-rename-transfer-ownership.txtar diff --git a/acceptance/testdata/repo/repo-rename-transfer-ownership.txtar b/acceptance/testdata/repo/repo-rename-transfer-ownership.txtar new file mode 100644 index 000000000..6b1a3e3fb --- /dev/null +++ b/acceptance/testdata/repo/repo-rename-transfer-ownership.txtar @@ -0,0 +1,9 @@ +# Create a repository with a file so it has a default branch +exec gh repo create $ORG/$SCRIPT_NAME-$RANDOM_STRING --add-readme --private + +# Attempt to rename the repo with a slash in the name +! exec gh repo rename $ORG/new-name --repo=$ORG/$SCRIPT_NAME-$RANDOM_STRING --yes +stderr 'New repository name cannot contain '/' character - to transfer a repository to a new owner, you must follow additional steps on GitHub.com. For more information on transferring repository ownership, see .' + +# Defer repo deletion +defer gh repo delete $ORG/$SCRIPT_NAME-$RANDOM_STRING --yes \ No newline at end of file diff --git a/pkg/cmd/repo/rename/rename.go b/pkg/cmd/repo/rename/rename.go index 74523e2e7..172b8b552 100644 --- a/pkg/cmd/repo/rename/rename.go +++ b/pkg/cmd/repo/rename/rename.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "net/http" + "strings" "github.com/MakeNowJust/heredoc" "github.com/cli/cli/v2/api" @@ -58,7 +59,7 @@ func NewCmdRename(f *cmdutil.Factory, runf func(*RenameOptions) error) *cobra.Co with %[1]s--repo%[1]s is renamed. To transfer repository ownership to another user account or organization, - you must follow additional steps on GitHub.com + you must follow additional steps on GitHub.com. For more information on transferring repository ownership, see: @@ -124,6 +125,10 @@ func renameRun(opts *RenameOptions) error { } } + if strings.Contains(newRepoName, "/") { + return fmt.Errorf("New repository name cannot contain '/' character - to transfer a repository to a new owner, you must follow additional steps on GitHub.com. For more information on transferring repository ownership, see .") + } + if opts.DoConfirm { var confirmed bool if confirmed, err = opts.Prompter.Confirm(fmt.Sprintf( diff --git a/pkg/cmd/repo/rename/rename_test.go b/pkg/cmd/repo/rename/rename_test.go index da40e51b0..e33e14438 100644 --- a/pkg/cmd/repo/rename/rename_test.go +++ b/pkg/cmd/repo/rename/rename_test.go @@ -113,6 +113,8 @@ func TestRenameRun(t *testing.T) { promptStubs func(*prompter.MockPrompter) wantOut string tty bool + wantErr bool + errMsg string }{ { name: "none argument", @@ -217,6 +219,16 @@ func TestRenameRun(t *testing.T) { }, wantOut: "", }, + + { + name: "error on name with slash", + tty: true, + opts: RenameOptions{ + newRepoSelector: "org/new-name", + }, + wantErr: true, + errMsg: "New repository name cannot contain '/' character - to transfer a repository to a new owner, you must follow additional steps on GitHub.com. For more information on transferring repository ownership, see .", + }, } for _, tt := range testCases { @@ -268,6 +280,10 @@ func TestRenameRun(t *testing.T) { t.Run(tt.name, func(t *testing.T) { defer reg.Verify(t) err := renameRun(&tt.opts) + if tt.wantErr { + assert.EqualError(t, err, tt.errMsg) + return + } assert.NoError(t, err) assert.Equal(t, tt.wantOut, stdout.String()) }) From 430e5abe2550c7a91c7c30ece2de57cb2a6889c6 Mon Sep 17 00:00:00 2001 From: Tim Rogers Date: Mon, 3 Feb 2025 12:04:42 +0000 Subject: [PATCH 3/5] Drop accidental help text change --- pkg/cmd/repo/rename/rename.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/cmd/repo/rename/rename.go b/pkg/cmd/repo/rename/rename.go index 172b8b552..e50095d76 100644 --- a/pkg/cmd/repo/rename/rename.go +++ b/pkg/cmd/repo/rename/rename.go @@ -59,7 +59,7 @@ func NewCmdRename(f *cmdutil.Factory, runf func(*RenameOptions) error) *cobra.Co with %[1]s--repo%[1]s is renamed. To transfer repository ownership to another user account or organization, - you must follow additional steps on GitHub.com. + you must follow additional steps on GitHub.com For more information on transferring repository ownership, see: From 91c75596ee19b13fd9dea799388b80b30d5a7db0 Mon Sep 17 00:00:00 2001 From: Azeem Sajid Date: Wed, 5 Feb 2025 12:14:39 +0500 Subject: [PATCH 4/5] Address review comments --- pkg/cmd/extension/command.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/cmd/extension/command.go b/pkg/cmd/extension/command.go index ae9a917a6..93c385374 100644 --- a/pkg/cmd/extension/command.go +++ b/pkg/cmd/extension/command.go @@ -306,8 +306,9 @@ func NewCmdExtension(f *cmdutil.Factory) *cobra.Command { that it's a binary extension i.e. prebuilt binaries provided as part of the release. In the absence of a release, the repository itself is cloned assuming that it's a script extension i.e. prebuilt executable or script exists on its root. + The %[1]s--pin%[1]s flag may be used to specify a tag or commit for binary and script - extensions respectively, the latest one is used otherwise. + extensions respectively, the latest version is used otherwise. For local repositories, often used while developing extensions, use %[1]s.%[1]s as the value of the repository argument. Note the following: From 50e7b00327520ffdbce9f637f54f3d3f1188c344 Mon Sep 17 00:00:00 2001 From: Azeem Sajid Date: Wed, 5 Feb 2025 12:21:29 +0500 Subject: [PATCH 5/5] Address review comments --- pkg/cmd/extension/manager.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/cmd/extension/manager.go b/pkg/cmd/extension/manager.go index e83a3ed22..b7f1f1c0c 100644 --- a/pkg/cmd/extension/manager.go +++ b/pkg/cmd/extension/manager.go @@ -268,7 +268,7 @@ func (m *Manager) Install(repo ghrepo.Interface, target string) error { return err } if !hs { - return fmt.Errorf("extension is not installable: no acceptable release artifact or script found in %s", repo) + return fmt.Errorf("extension is not installable: no usable release artifact or script found in %s", repo) } return m.installGit(repo, target)