diff --git a/pkg/cmd/issue/transfer/transfer.go b/pkg/cmd/issue/transfer/transfer.go index 140d02b91..a6dfb9b23 100644 --- a/pkg/cmd/issue/transfer/transfer.go +++ b/pkg/cmd/issue/transfer/transfer.go @@ -20,7 +20,7 @@ type TransferOptions struct { IO *iostreams.IOStreams BaseRepo func() (ghrepo.Interface, error) - IssueSelector string + IssueNumber int DestRepoSelector string } @@ -36,8 +36,23 @@ func NewCmdTransfer(f *cmdutil.Factory, runF func(*TransferOptions) error) *cobr Short: "Transfer issue to another repository", Args: cmdutil.ExactArgs(2, "issue and destination repository are required"), RunE: func(cmd *cobra.Command, args []string) error { - opts.BaseRepo = f.BaseRepo - opts.IssueSelector = args[0] + issueNumber, baseRepo, err := shared.ParseIssueFromArg(args[0]) + if err != nil { + return err + } + + // If the args provided the base repo then use that directly. + if baseRepo, present := baseRepo.Value(); present { + opts.BaseRepo = func() (ghrepo.Interface, error) { + return baseRepo, nil + } + } else { + // support `-R, --repo` override + opts.BaseRepo = f.BaseRepo + } + + opts.IssueNumber = issueNumber + opts.DestRepoSelector = args[1] if runF != nil { @@ -57,7 +72,12 @@ func transferRun(opts *TransferOptions) error { return err } - issue, baseRepo, err := shared.IssueFromArgWithFields(httpClient, opts.BaseRepo, opts.IssueSelector, []string{"id", "number"}) + baseRepo, err := opts.BaseRepo() + if err != nil { + return err + } + + issue, err := shared.FindIssueOrPR(httpClient, baseRepo, opts.IssueNumber, []string{"id", "number"}) if err != nil { return err } diff --git a/pkg/cmd/issue/transfer/transfer_test.go b/pkg/cmd/issue/transfer/transfer_test.go index eed9c5d85..2b12db944 100644 --- a/pkg/cmd/issue/transfer/transfer_test.go +++ b/pkg/cmd/issue/transfer/transfer_test.go @@ -15,6 +15,7 @@ import ( "github.com/cli/cli/v2/test" "github.com/google/shlex" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func runCommand(rt http.RoundTripper, cli string) (*test.CmdOut, error) { @@ -57,18 +58,49 @@ func runCommand(rt http.RoundTripper, cli string) (*test.CmdOut, error) { func TestNewCmdTransfer(t *testing.T) { tests := []struct { - name string - cli string - wants TransferOptions - wantErr string + name string + cli string + wants TransferOptions + wantBaseRepo ghrepo.Interface + wantErr bool }{ { - name: "issue name", - cli: "3252 OWNER/REPO", + name: "no argument", + cli: "", + wantErr: true, + }, + { + name: "issue number argument", + cli: "--repo cli/repo 23 OWNER/REPO", wants: TransferOptions{ - IssueSelector: "3252", + IssueNumber: 23, DestRepoSelector: "OWNER/REPO", }, + wantBaseRepo: ghrepo.New("cli", "repo"), + }, + { + name: "argument is hash prefixed number", + // Escaping is required here to avoid what I think is shellex treating it as a comment. + cli: "--repo cli/repo \\#23 OWNER/REPO", + wants: TransferOptions{ + IssueNumber: 23, + DestRepoSelector: "OWNER/REPO", + }, + wantBaseRepo: ghrepo.New("cli", "repo"), + }, + { + name: "argument is a URL", + cli: "https://github.com/cli/cli/issues/23 OWNER/REPO", + wants: TransferOptions{ + IssueNumber: 23, + DestRepoSelector: "OWNER/REPO", + }, + wantBaseRepo: ghrepo.New("cli", "cli"), + }, + { + name: "argument cannot be parsed to an issue", + cli: "unparseable OWNER/REPO", + wantErr: true, }, } @@ -84,15 +116,29 @@ func TestNewCmdTransfer(t *testing.T) { gotOpts = opts return nil }) + cmdutil.EnableRepoOverride(cmd, f) + cmd.SetArgs(argv) cmd.SetIn(&bytes.Buffer{}) cmd.SetOut(&bytes.Buffer{}) cmd.SetErr(&bytes.Buffer{}) _, cErr := cmd.ExecuteC() - assert.NoError(t, cErr) - assert.Equal(t, tt.wants.IssueSelector, gotOpts.IssueSelector) + if tt.wantErr { + require.Error(t, cErr) + return + } + + require.NoError(t, cErr) + assert.Equal(t, tt.wants.IssueNumber, gotOpts.IssueNumber) assert.Equal(t, tt.wants.DestRepoSelector, gotOpts.DestRepoSelector) + actualBaseRepo, err := gotOpts.BaseRepo() + require.NoError(t, err) + assert.True( + t, + ghrepo.IsSame(tt.wantBaseRepo, actualBaseRepo), + "expected base repo %+v, got %+v", tt.wantBaseRepo, actualBaseRepo, + ) }) } }