From 6c21ab2284aed52fa92020590fdfbb9e2d8f3475 Mon Sep 17 00:00:00 2001 From: Tim Rogers Date: Mon, 3 Feb 2025 11:49:21 +0000 Subject: [PATCH] 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()) })