github.com/cli/cli@v1.14.1-0.20210902173923-1af6a669e342/pkg/cmd/pr/close/close_test.go (about)

     1  package close
     2  
     3  import (
     4  	"bytes"
     5  	"io/ioutil"
     6  	"net/http"
     7  	"strings"
     8  	"testing"
     9  
    10  	"github.com/MakeNowJust/heredoc"
    11  	"github.com/cli/cli/api"
    12  	"github.com/cli/cli/internal/ghrepo"
    13  	"github.com/cli/cli/internal/run"
    14  	"github.com/cli/cli/pkg/cmd/pr/shared"
    15  	"github.com/cli/cli/pkg/cmdutil"
    16  	"github.com/cli/cli/pkg/httpmock"
    17  	"github.com/cli/cli/pkg/iostreams"
    18  	"github.com/cli/cli/test"
    19  	"github.com/google/shlex"
    20  	"github.com/stretchr/testify/assert"
    21  )
    22  
    23  // repo: either "baseOwner/baseRepo" or "baseOwner/baseRepo:defaultBranch"
    24  // prHead: "headOwner/headRepo:headBranch"
    25  func stubPR(repo, prHead string) (ghrepo.Interface, *api.PullRequest) {
    26  	defaultBranch := ""
    27  	if idx := strings.IndexRune(repo, ':'); idx >= 0 {
    28  		defaultBranch = repo[idx+1:]
    29  		repo = repo[:idx]
    30  	}
    31  	baseRepo, err := ghrepo.FromFullName(repo)
    32  	if err != nil {
    33  		panic(err)
    34  	}
    35  	if defaultBranch != "" {
    36  		baseRepo = api.InitRepoHostname(&api.Repository{
    37  			Name:             baseRepo.RepoName(),
    38  			Owner:            api.RepositoryOwner{Login: baseRepo.RepoOwner()},
    39  			DefaultBranchRef: api.BranchRef{Name: defaultBranch},
    40  		}, baseRepo.RepoHost())
    41  	}
    42  
    43  	idx := strings.IndexRune(prHead, ':')
    44  	headRefName := prHead[idx+1:]
    45  	headRepo, err := ghrepo.FromFullName(prHead[:idx])
    46  	if err != nil {
    47  		panic(err)
    48  	}
    49  
    50  	return baseRepo, &api.PullRequest{
    51  		ID:                  "THE-ID",
    52  		Number:              96,
    53  		State:               "OPEN",
    54  		HeadRefName:         headRefName,
    55  		HeadRepositoryOwner: api.Owner{Login: headRepo.RepoOwner()},
    56  		HeadRepository:      &api.PRRepository{Name: headRepo.RepoName()},
    57  		IsCrossRepository:   !ghrepo.IsSame(baseRepo, headRepo),
    58  	}
    59  }
    60  
    61  func runCommand(rt http.RoundTripper, isTTY bool, cli string) (*test.CmdOut, error) {
    62  	io, _, stdout, stderr := iostreams.Test()
    63  	io.SetStdoutTTY(isTTY)
    64  	io.SetStdinTTY(isTTY)
    65  	io.SetStderrTTY(isTTY)
    66  
    67  	factory := &cmdutil.Factory{
    68  		IOStreams: io,
    69  		HttpClient: func() (*http.Client, error) {
    70  			return &http.Client{Transport: rt}, nil
    71  		},
    72  		Branch: func() (string, error) {
    73  			return "trunk", nil
    74  		},
    75  	}
    76  
    77  	cmd := NewCmdClose(factory, nil)
    78  
    79  	argv, err := shlex.Split(cli)
    80  	if err != nil {
    81  		return nil, err
    82  	}
    83  	cmd.SetArgs(argv)
    84  
    85  	cmd.SetIn(&bytes.Buffer{})
    86  	cmd.SetOut(ioutil.Discard)
    87  	cmd.SetErr(ioutil.Discard)
    88  
    89  	_, err = cmd.ExecuteC()
    90  	return &test.CmdOut{
    91  		OutBuf: stdout,
    92  		ErrBuf: stderr,
    93  	}, err
    94  }
    95  
    96  func TestPrClose(t *testing.T) {
    97  	http := &httpmock.Registry{}
    98  	defer http.Verify(t)
    99  
   100  	baseRepo, pr := stubPR("OWNER/REPO", "OWNER/REPO:feature")
   101  	pr.Title = "The title of the PR"
   102  	shared.RunCommandFinder("96", pr, baseRepo)
   103  
   104  	http.Register(
   105  		httpmock.GraphQL(`mutation PullRequestClose\b`),
   106  		httpmock.GraphQLMutation(`{"id": "THE-ID"}`,
   107  			func(inputs map[string]interface{}) {
   108  				assert.Equal(t, inputs["pullRequestId"], "THE-ID")
   109  			}),
   110  	)
   111  
   112  	output, err := runCommand(http, true, "96")
   113  	assert.NoError(t, err)
   114  	assert.Equal(t, "", output.String())
   115  	assert.Equal(t, "✓ Closed pull request #96 (The title of the PR)\n", output.Stderr())
   116  }
   117  
   118  func TestPrClose_alreadyClosed(t *testing.T) {
   119  	http := &httpmock.Registry{}
   120  	defer http.Verify(t)
   121  
   122  	baseRepo, pr := stubPR("OWNER/REPO", "OWNER/REPO:feature")
   123  	pr.State = "CLOSED"
   124  	pr.Title = "The title of the PR"
   125  	shared.RunCommandFinder("96", pr, baseRepo)
   126  
   127  	output, err := runCommand(http, true, "96")
   128  	assert.NoError(t, err)
   129  	assert.Equal(t, "", output.String())
   130  	assert.Equal(t, "! Pull request #96 (The title of the PR) is already closed\n", output.Stderr())
   131  }
   132  
   133  func TestPrClose_deleteBranch_sameRepo(t *testing.T) {
   134  	http := &httpmock.Registry{}
   135  	defer http.Verify(t)
   136  
   137  	baseRepo, pr := stubPR("OWNER/REPO", "OWNER/REPO:blueberries")
   138  	pr.Title = "The title of the PR"
   139  	shared.RunCommandFinder("96", pr, baseRepo)
   140  
   141  	http.Register(
   142  		httpmock.GraphQL(`mutation PullRequestClose\b`),
   143  		httpmock.GraphQLMutation(`{"id": "THE-ID"}`,
   144  			func(inputs map[string]interface{}) {
   145  				assert.Equal(t, inputs["pullRequestId"], "THE-ID")
   146  			}),
   147  	)
   148  	http.Register(
   149  		httpmock.REST("DELETE", "repos/OWNER/REPO/git/refs/heads/blueberries"),
   150  		httpmock.StringResponse(`{}`))
   151  
   152  	cs, cmdTeardown := run.Stub()
   153  	defer cmdTeardown(t)
   154  
   155  	cs.Register(`git rev-parse --verify refs/heads/blueberries`, 0, "")
   156  	cs.Register(`git branch -D blueberries`, 0, "")
   157  
   158  	output, err := runCommand(http, true, `96 --delete-branch`)
   159  	assert.NoError(t, err)
   160  	assert.Equal(t, "", output.String())
   161  	assert.Equal(t, heredoc.Doc(`
   162  		✓ Closed pull request #96 (The title of the PR)
   163  		✓ Deleted branch blueberries
   164  	`), output.Stderr())
   165  }
   166  
   167  func TestPrClose_deleteBranch_crossRepo(t *testing.T) {
   168  	http := &httpmock.Registry{}
   169  	defer http.Verify(t)
   170  
   171  	baseRepo, pr := stubPR("OWNER/REPO", "hubot/REPO:blueberries")
   172  	pr.Title = "The title of the PR"
   173  	shared.RunCommandFinder("96", pr, baseRepo)
   174  
   175  	http.Register(
   176  		httpmock.GraphQL(`mutation PullRequestClose\b`),
   177  		httpmock.GraphQLMutation(`{"id": "THE-ID"}`,
   178  			func(inputs map[string]interface{}) {
   179  				assert.Equal(t, inputs["pullRequestId"], "THE-ID")
   180  			}),
   181  	)
   182  
   183  	cs, cmdTeardown := run.Stub()
   184  	defer cmdTeardown(t)
   185  
   186  	cs.Register(`git rev-parse --verify refs/heads/blueberries`, 0, "")
   187  	cs.Register(`git branch -D blueberries`, 0, "")
   188  
   189  	output, err := runCommand(http, true, `96 --delete-branch`)
   190  	assert.NoError(t, err)
   191  	assert.Equal(t, "", output.String())
   192  	assert.Equal(t, heredoc.Doc(`
   193  		✓ Closed pull request #96 (The title of the PR)
   194  		! Skipped deleting the remote branch of a pull request from fork
   195  		✓ Deleted branch blueberries
   196  	`), output.Stderr())
   197  }
   198  
   199  func TestPrClose_deleteBranch_sameBranch(t *testing.T) {
   200  	http := &httpmock.Registry{}
   201  	defer http.Verify(t)
   202  
   203  	baseRepo, pr := stubPR("OWNER/REPO:main", "OWNER/REPO:trunk")
   204  	pr.Title = "The title of the PR"
   205  	shared.RunCommandFinder("96", pr, baseRepo)
   206  
   207  	http.Register(
   208  		httpmock.GraphQL(`mutation PullRequestClose\b`),
   209  		httpmock.GraphQLMutation(`{"id": "THE-ID"}`,
   210  			func(inputs map[string]interface{}) {
   211  				assert.Equal(t, inputs["pullRequestId"], "THE-ID")
   212  			}),
   213  	)
   214  	http.Register(
   215  		httpmock.REST("DELETE", "repos/OWNER/REPO/git/refs/heads/trunk"),
   216  		httpmock.StringResponse(`{}`))
   217  
   218  	cs, cmdTeardown := run.Stub()
   219  	defer cmdTeardown(t)
   220  
   221  	cs.Register(`git checkout main`, 0, "")
   222  	cs.Register(`git rev-parse --verify refs/heads/trunk`, 0, "")
   223  	cs.Register(`git branch -D trunk`, 0, "")
   224  
   225  	output, err := runCommand(http, true, `96 --delete-branch`)
   226  	assert.NoError(t, err)
   227  	assert.Equal(t, "", output.String())
   228  	assert.Equal(t, heredoc.Doc(`
   229  		✓ Closed pull request #96 (The title of the PR)
   230  		✓ Deleted branch trunk and switched to branch main
   231  	`), output.Stderr())
   232  }