1730 lines
54 KiB
Go
1730 lines
54 KiB
Go
package command
|
||
|
||
import (
|
||
"bytes"
|
||
"os/exec"
|
||
"reflect"
|
||
"regexp"
|
||
"strings"
|
||
"testing"
|
||
|
||
"github.com/cli/cli/api"
|
||
"github.com/cli/cli/internal/run"
|
||
"github.com/cli/cli/pkg/httpmock"
|
||
"github.com/cli/cli/test"
|
||
"github.com/google/go-cmp/cmp"
|
||
"github.com/stretchr/testify/assert"
|
||
)
|
||
|
||
func eq(t *testing.T, got interface{}, expected interface{}) {
|
||
t.Helper()
|
||
if !reflect.DeepEqual(got, expected) {
|
||
t.Errorf("expected: %v, got: %v", expected, got)
|
||
}
|
||
}
|
||
|
||
func TestPRStatus(t *testing.T) {
|
||
initBlankContext("", "OWNER/REPO", "blueberries")
|
||
http := initFakeHTTP()
|
||
http.StubRepoResponse("OWNER", "REPO")
|
||
http.Register(httpmock.GraphQL(`query PullRequestStatus\b`), httpmock.FileResponse("../test/fixtures/prStatus.json"))
|
||
|
||
output, err := RunCommand("pr status")
|
||
if err != nil {
|
||
t.Errorf("error running command `pr status`: %v", err)
|
||
}
|
||
|
||
expectedPrs := []*regexp.Regexp{
|
||
regexp.MustCompile(`#8.*\[strawberries\]`),
|
||
regexp.MustCompile(`#9.*\[apples\]`),
|
||
regexp.MustCompile(`#10.*\[blueberries\]`),
|
||
regexp.MustCompile(`#11.*\[figs\]`),
|
||
}
|
||
|
||
for _, r := range expectedPrs {
|
||
if !r.MatchString(output.String()) {
|
||
t.Errorf("output did not match regexp /%s/", r)
|
||
}
|
||
}
|
||
}
|
||
|
||
func TestPRStatus_fork(t *testing.T) {
|
||
initBlankContext("", "OWNER/REPO", "blueberries")
|
||
http := initFakeHTTP()
|
||
http.StubForkedRepoResponse("OWNER/REPO", "PARENT/REPO")
|
||
http.Register(httpmock.GraphQL(`query PullRequestStatus\b`), httpmock.FileResponse("../test/fixtures/prStatusFork.json"))
|
||
|
||
defer run.SetPrepareCmd(func(cmd *exec.Cmd) run.Runnable {
|
||
switch strings.Join(cmd.Args, " ") {
|
||
case `git config --get-regexp ^branch\.blueberries\.(remote|merge)$`:
|
||
return &test.OutputStub{Out: []byte(`branch.blueberries.remote origin
|
||
branch.blueberries.merge refs/heads/blueberries`)}
|
||
default:
|
||
panic("not implemented")
|
||
}
|
||
})()
|
||
|
||
output, err := RunCommand("pr status")
|
||
if err != nil {
|
||
t.Fatalf("error running command `pr status`: %v", err)
|
||
}
|
||
|
||
branchRE := regexp.MustCompile(`#10.*\[OWNER:blueberries\]`)
|
||
if !branchRE.MatchString(output.String()) {
|
||
t.Errorf("did not match current branch:\n%v", output.String())
|
||
}
|
||
}
|
||
|
||
func TestPRStatus_reviewsAndChecks(t *testing.T) {
|
||
initBlankContext("", "OWNER/REPO", "blueberries")
|
||
http := initFakeHTTP()
|
||
http.StubRepoResponse("OWNER", "REPO")
|
||
http.Register(httpmock.GraphQL(`query PullRequestStatus\b`), httpmock.FileResponse("../test/fixtures/prStatusChecks.json"))
|
||
|
||
output, err := RunCommand("pr status")
|
||
if err != nil {
|
||
t.Errorf("error running command `pr status`: %v", err)
|
||
}
|
||
|
||
expected := []string{
|
||
"✓ Checks passing + Changes requested",
|
||
"- Checks pending ✓ Approved",
|
||
"× 1/3 checks failing - Review required",
|
||
}
|
||
|
||
for _, line := range expected {
|
||
if !strings.Contains(output.String(), line) {
|
||
t.Errorf("output did not contain %q: %q", line, output.String())
|
||
}
|
||
}
|
||
}
|
||
|
||
func TestPRStatus_currentBranch_showTheMostRecentPR(t *testing.T) {
|
||
initBlankContext("", "OWNER/REPO", "blueberries")
|
||
http := initFakeHTTP()
|
||
http.StubRepoResponse("OWNER", "REPO")
|
||
http.Register(httpmock.GraphQL(`query PullRequestStatus\b`), httpmock.FileResponse("../test/fixtures/prStatusCurrentBranch.json"))
|
||
|
||
output, err := RunCommand("pr status")
|
||
if err != nil {
|
||
t.Errorf("error running command `pr status`: %v", err)
|
||
}
|
||
|
||
expectedLine := regexp.MustCompile(`#10 Blueberries are certainly a good fruit \[blueberries\]`)
|
||
if !expectedLine.MatchString(output.String()) {
|
||
t.Errorf("output did not match regexp /%s/\n> output\n%s\n", expectedLine, output)
|
||
return
|
||
}
|
||
|
||
unexpectedLines := []*regexp.Regexp{
|
||
regexp.MustCompile(`#9 Blueberries are a good fruit \[blueberries\] - Merged`),
|
||
regexp.MustCompile(`#8 Blueberries are probably a good fruit \[blueberries\] - Closed`),
|
||
}
|
||
for _, r := range unexpectedLines {
|
||
if r.MatchString(output.String()) {
|
||
t.Errorf("output unexpectedly match regexp /%s/\n> output\n%s\n", r, output)
|
||
return
|
||
}
|
||
}
|
||
}
|
||
|
||
func TestPRStatus_currentBranch_defaultBranch(t *testing.T) {
|
||
initBlankContext("", "OWNER/REPO", "blueberries")
|
||
http := initFakeHTTP()
|
||
http.StubRepoResponseWithDefaultBranch("OWNER", "REPO", "blueberries")
|
||
http.Register(httpmock.GraphQL(`query PullRequestStatus\b`), httpmock.FileResponse("../test/fixtures/prStatusCurrentBranch.json"))
|
||
|
||
output, err := RunCommand("pr status")
|
||
if err != nil {
|
||
t.Errorf("error running command `pr status`: %v", err)
|
||
}
|
||
|
||
expectedLine := regexp.MustCompile(`#10 Blueberries are certainly a good fruit \[blueberries\]`)
|
||
if !expectedLine.MatchString(output.String()) {
|
||
t.Errorf("output did not match regexp /%s/\n> output\n%s\n", expectedLine, output)
|
||
return
|
||
}
|
||
}
|
||
|
||
func TestPRStatus_currentBranch_defaultBranch_repoFlag(t *testing.T) {
|
||
initBlankContext("", "OWNER/REPO", "blueberries")
|
||
http := initFakeHTTP()
|
||
http.Register(httpmock.GraphQL(`query PullRequestStatus\b`), httpmock.FileResponse("../test/fixtures/prStatusCurrentBranchClosedOnDefaultBranch.json"))
|
||
|
||
output, err := RunCommand("pr status -R OWNER/REPO")
|
||
if err != nil {
|
||
t.Errorf("error running command `pr status`: %v", err)
|
||
}
|
||
|
||
expectedLine := regexp.MustCompile(`#8 Blueberries are a good fruit \[blueberries\]`)
|
||
if expectedLine.MatchString(output.String()) {
|
||
t.Errorf("output not expected to match regexp /%s/\n> output\n%s\n", expectedLine, output)
|
||
return
|
||
}
|
||
}
|
||
|
||
func TestPRStatus_currentBranch_Closed(t *testing.T) {
|
||
initBlankContext("", "OWNER/REPO", "blueberries")
|
||
http := initFakeHTTP()
|
||
http.StubRepoResponse("OWNER", "REPO")
|
||
http.Register(httpmock.GraphQL(`query PullRequestStatus\b`), httpmock.FileResponse("../test/fixtures/prStatusCurrentBranchClosed.json"))
|
||
|
||
output, err := RunCommand("pr status")
|
||
if err != nil {
|
||
t.Errorf("error running command `pr status`: %v", err)
|
||
}
|
||
|
||
expectedLine := regexp.MustCompile(`#8 Blueberries are a good fruit \[blueberries\] - Closed`)
|
||
if !expectedLine.MatchString(output.String()) {
|
||
t.Errorf("output did not match regexp /%s/\n> output\n%s\n", expectedLine, output)
|
||
return
|
||
}
|
||
}
|
||
|
||
func TestPRStatus_currentBranch_Closed_defaultBranch(t *testing.T) {
|
||
initBlankContext("", "OWNER/REPO", "blueberries")
|
||
http := initFakeHTTP()
|
||
http.StubRepoResponseWithDefaultBranch("OWNER", "REPO", "blueberries")
|
||
http.Register(httpmock.GraphQL(`query PullRequestStatus\b`), httpmock.FileResponse("../test/fixtures/prStatusCurrentBranchClosedOnDefaultBranch.json"))
|
||
|
||
output, err := RunCommand("pr status")
|
||
if err != nil {
|
||
t.Errorf("error running command `pr status`: %v", err)
|
||
}
|
||
|
||
expectedLine := regexp.MustCompile(`There is no pull request associated with \[blueberries\]`)
|
||
if !expectedLine.MatchString(output.String()) {
|
||
t.Errorf("output did not match regexp /%s/\n> output\n%s\n", expectedLine, output)
|
||
return
|
||
}
|
||
}
|
||
|
||
func TestPRStatus_currentBranch_Merged(t *testing.T) {
|
||
initBlankContext("", "OWNER/REPO", "blueberries")
|
||
http := initFakeHTTP()
|
||
http.StubRepoResponse("OWNER", "REPO")
|
||
http.Register(httpmock.GraphQL(`query PullRequestStatus\b`), httpmock.FileResponse("../test/fixtures/prStatusCurrentBranchMerged.json"))
|
||
|
||
output, err := RunCommand("pr status")
|
||
if err != nil {
|
||
t.Errorf("error running command `pr status`: %v", err)
|
||
}
|
||
|
||
expectedLine := regexp.MustCompile(`#8 Blueberries are a good fruit \[blueberries\] - Merged`)
|
||
if !expectedLine.MatchString(output.String()) {
|
||
t.Errorf("output did not match regexp /%s/\n> output\n%s\n", expectedLine, output)
|
||
return
|
||
}
|
||
}
|
||
|
||
func TestPRStatus_currentBranch_Merged_defaultBranch(t *testing.T) {
|
||
initBlankContext("", "OWNER/REPO", "blueberries")
|
||
http := initFakeHTTP()
|
||
http.StubRepoResponseWithDefaultBranch("OWNER", "REPO", "blueberries")
|
||
http.Register(httpmock.GraphQL(`query PullRequestStatus\b`), httpmock.FileResponse("../test/fixtures/prStatusCurrentBranchMergedOnDefaultBranch.json"))
|
||
|
||
output, err := RunCommand("pr status")
|
||
if err != nil {
|
||
t.Errorf("error running command `pr status`: %v", err)
|
||
}
|
||
|
||
expectedLine := regexp.MustCompile(`There is no pull request associated with \[blueberries\]`)
|
||
if !expectedLine.MatchString(output.String()) {
|
||
t.Errorf("output did not match regexp /%s/\n> output\n%s\n", expectedLine, output)
|
||
return
|
||
}
|
||
}
|
||
|
||
func TestPRStatus_blankSlate(t *testing.T) {
|
||
initBlankContext("", "OWNER/REPO", "blueberries")
|
||
http := initFakeHTTP()
|
||
http.StubRepoResponse("OWNER", "REPO")
|
||
http.Register(httpmock.GraphQL(`query PullRequestStatus\b`), httpmock.StringResponse(`{"data": {}}`))
|
||
|
||
output, err := RunCommand("pr status")
|
||
if err != nil {
|
||
t.Errorf("error running command `pr status`: %v", err)
|
||
}
|
||
|
||
expected := `
|
||
Relevant pull requests in OWNER/REPO
|
||
|
||
Current branch
|
||
There is no pull request associated with [blueberries]
|
||
|
||
Created by you
|
||
You have no open pull requests
|
||
|
||
Requesting a code review from you
|
||
You have no pull requests to review
|
||
|
||
`
|
||
if output.String() != expected {
|
||
t.Errorf("expected %q, got %q", expected, output.String())
|
||
}
|
||
}
|
||
|
||
func TestPRStatus_detachedHead(t *testing.T) {
|
||
initBlankContext("", "OWNER/REPO", "")
|
||
http := initFakeHTTP()
|
||
http.StubRepoResponse("OWNER", "REPO")
|
||
http.Register(httpmock.GraphQL(`query PullRequestStatus\b`), httpmock.StringResponse(`{"data": {}}`))
|
||
|
||
output, err := RunCommand("pr status")
|
||
if err != nil {
|
||
t.Errorf("error running command `pr status`: %v", err)
|
||
}
|
||
|
||
expected := `
|
||
Relevant pull requests in OWNER/REPO
|
||
|
||
Current branch
|
||
There is no current branch
|
||
|
||
Created by you
|
||
You have no open pull requests
|
||
|
||
Requesting a code review from you
|
||
You have no pull requests to review
|
||
|
||
`
|
||
if output.String() != expected {
|
||
t.Errorf("expected %q, got %q", expected, output.String())
|
||
}
|
||
}
|
||
|
||
func TestPRList(t *testing.T) {
|
||
initBlankContext("", "OWNER/REPO", "master")
|
||
defer stubTerminal(true)()
|
||
http := initFakeHTTP()
|
||
http.StubRepoResponse("OWNER", "REPO")
|
||
http.Register(httpmock.GraphQL(`query PullRequestList\b`), httpmock.FileResponse("../test/fixtures/prList.json"))
|
||
|
||
output, err := RunCommand("pr list")
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
|
||
assert.Equal(t, `
|
||
Showing 3 of 3 pull requests in OWNER/REPO
|
||
|
||
`, output.Stderr())
|
||
|
||
lines := strings.Split(output.String(), "\n")
|
||
res := []*regexp.Regexp{
|
||
regexp.MustCompile(`#32.*New feature.*feature`),
|
||
regexp.MustCompile(`#29.*Fixed bad bug.*hubot:bug-fix`),
|
||
regexp.MustCompile(`#28.*Improve documentation.*docs`),
|
||
}
|
||
|
||
for i, r := range res {
|
||
if !r.MatchString(lines[i]) {
|
||
t.Errorf("%s did not match %s", lines[i], r)
|
||
}
|
||
}
|
||
}
|
||
|
||
func TestPRList_nontty(t *testing.T) {
|
||
initBlankContext("", "OWNER/REPO", "master")
|
||
defer stubTerminal(false)()
|
||
http := initFakeHTTP()
|
||
http.StubRepoResponse("OWNER", "REPO")
|
||
http.Register(httpmock.GraphQL(`query PullRequestList\b`), httpmock.FileResponse("../test/fixtures/prList.json"))
|
||
|
||
output, err := RunCommand("pr list")
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
|
||
assert.Equal(t, "", output.Stderr())
|
||
|
||
assert.Equal(t, `32 New feature feature DRAFT
|
||
29 Fixed bad bug hubot:bug-fix OPEN
|
||
28 Improve documentation docs MERGED
|
||
`, output.String())
|
||
}
|
||
|
||
func TestPRList_filtering(t *testing.T) {
|
||
initBlankContext("", "OWNER/REPO", "master")
|
||
defer stubTerminal(true)()
|
||
http := initFakeHTTP()
|
||
http.StubRepoResponse("OWNER", "REPO")
|
||
http.Register(
|
||
httpmock.GraphQL(`query PullRequestList\b`),
|
||
httpmock.GraphQLQuery(`{}`, func(_ string, params map[string]interface{}) {
|
||
assert.Equal(t, []interface{}{"OPEN", "CLOSED", "MERGED"}, params["state"].([]interface{}))
|
||
assert.Equal(t, []interface{}{"one", "two", "three"}, params["labels"].([]interface{}))
|
||
}))
|
||
|
||
output, err := RunCommand(`pr list -s all -l one,two -l three`)
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
|
||
eq(t, output.String(), "")
|
||
eq(t, output.Stderr(), `
|
||
No pull requests match your search in OWNER/REPO
|
||
|
||
`)
|
||
}
|
||
|
||
func TestPRList_filteringRemoveDuplicate(t *testing.T) {
|
||
initBlankContext("", "OWNER/REPO", "master")
|
||
defer stubTerminal(true)()
|
||
http := initFakeHTTP()
|
||
http.StubRepoResponse("OWNER", "REPO")
|
||
http.Register(
|
||
httpmock.GraphQL(`query PullRequestList\b`),
|
||
httpmock.FileResponse("../test/fixtures/prListWithDuplicates.json"))
|
||
|
||
output, err := RunCommand("pr list -l one,two")
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
|
||
lines := strings.Split(output.String(), "\n")
|
||
|
||
res := []*regexp.Regexp{
|
||
regexp.MustCompile(`#32.*New feature.*feature`),
|
||
regexp.MustCompile(`#29.*Fixed bad bug.*hubot:bug-fix`),
|
||
regexp.MustCompile(`#28.*Improve documentation.*docs`),
|
||
}
|
||
|
||
for i, r := range res {
|
||
if !r.MatchString(lines[i]) {
|
||
t.Errorf("%s did not match %s", lines[i], r)
|
||
}
|
||
}
|
||
}
|
||
|
||
func TestPRList_filteringClosed(t *testing.T) {
|
||
initBlankContext("", "OWNER/REPO", "master")
|
||
defer stubTerminal(true)()
|
||
http := initFakeHTTP()
|
||
http.StubRepoResponse("OWNER", "REPO")
|
||
http.Register(
|
||
httpmock.GraphQL(`query PullRequestList\b`),
|
||
httpmock.GraphQLQuery(`{}`, func(_ string, params map[string]interface{}) {
|
||
assert.Equal(t, []interface{}{"CLOSED", "MERGED"}, params["state"].([]interface{}))
|
||
}))
|
||
|
||
_, err := RunCommand(`pr list -s closed`)
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
}
|
||
|
||
func TestPRList_filteringAssignee(t *testing.T) {
|
||
initBlankContext("", "OWNER/REPO", "master")
|
||
defer stubTerminal(true)()
|
||
http := initFakeHTTP()
|
||
http.StubRepoResponse("OWNER", "REPO")
|
||
http.Register(
|
||
httpmock.GraphQL(`query PullRequestList\b`),
|
||
httpmock.GraphQLQuery(`{}`, func(_ string, params map[string]interface{}) {
|
||
assert.Equal(t, `repo:OWNER/REPO assignee:hubot is:pr sort:created-desc is:merged label:"needs tests" base:"develop"`, params["q"].(string))
|
||
}))
|
||
|
||
_, err := RunCommand(`pr list -s merged -l "needs tests" -a hubot -B develop`)
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
}
|
||
|
||
func TestPRList_filteringAssigneeLabels(t *testing.T) {
|
||
initBlankContext("", "OWNER/REPO", "master")
|
||
defer stubTerminal(true)()
|
||
initFakeHTTP()
|
||
|
||
_, err := RunCommand(`pr list -l one,two -a hubot`)
|
||
if err == nil && err.Error() != "multiple labels with --assignee are not supported" {
|
||
t.Fatal(err)
|
||
}
|
||
}
|
||
|
||
func TestPRList_withInvalidLimitFlag(t *testing.T) {
|
||
initBlankContext("", "OWNER/REPO", "master")
|
||
defer stubTerminal(true)()
|
||
initFakeHTTP()
|
||
|
||
_, err := RunCommand(`pr list --limit=0`)
|
||
if err == nil && err.Error() != "invalid limit: 0" {
|
||
t.Errorf("error running command `issue list`: %v", err)
|
||
}
|
||
}
|
||
|
||
func TestPRList_web(t *testing.T) {
|
||
initBlankContext("", "OWNER/REPO", "master")
|
||
defer stubTerminal(true)()
|
||
http := initFakeHTTP()
|
||
http.StubRepoResponse("OWNER", "REPO")
|
||
|
||
var seenCmd *exec.Cmd
|
||
restoreCmd := run.SetPrepareCmd(func(cmd *exec.Cmd) run.Runnable {
|
||
seenCmd = cmd
|
||
return &test.OutputStub{}
|
||
})
|
||
defer restoreCmd()
|
||
|
||
output, err := RunCommand("pr list --web -a peter -l bug -l docs -L 10 -s merged -B trunk")
|
||
if err != nil {
|
||
t.Errorf("error running command `pr list` with `--web` flag: %v", err)
|
||
}
|
||
|
||
expectedURL := "https://github.com/OWNER/REPO/pulls?q=is%3Apr+is%3Amerged+assignee%3Apeter+label%3Abug+label%3Adocs+base%3Atrunk"
|
||
|
||
eq(t, output.String(), "")
|
||
eq(t, output.Stderr(), "Opening github.com/OWNER/REPO/pulls in your browser.\n")
|
||
|
||
if seenCmd == nil {
|
||
t.Fatal("expected a command to run")
|
||
}
|
||
url := seenCmd.Args[len(seenCmd.Args)-1]
|
||
eq(t, url, expectedURL)
|
||
}
|
||
|
||
func TestPRView_Preview_nontty(t *testing.T) {
|
||
defer stubTerminal(false)()
|
||
tests := map[string]struct {
|
||
ownerRepo string
|
||
args string
|
||
fixture string
|
||
expectedOutputs []string
|
||
}{
|
||
"Open PR without metadata": {
|
||
ownerRepo: "master",
|
||
args: "pr view 12",
|
||
fixture: "../test/fixtures/prViewPreview.json",
|
||
expectedOutputs: []string{
|
||
`title:\tBlueberries are from a fork\n`,
|
||
`state:\tOPEN\n`,
|
||
`author:\tnobody\n`,
|
||
`labels:\t\n`,
|
||
`assignees:\t\n`,
|
||
`reviewers:\t\n`,
|
||
`projects:\t\n`,
|
||
`milestone:\t\n`,
|
||
`blueberries taste good`,
|
||
},
|
||
},
|
||
"Open PR with metadata by number": {
|
||
ownerRepo: "master",
|
||
args: "pr view 12",
|
||
fixture: "../test/fixtures/prViewPreviewWithMetadataByNumber.json",
|
||
expectedOutputs: []string{
|
||
`title:\tBlueberries are from a fork\n`,
|
||
`reviewers:\t2 \(Approved\), 3 \(Commented\), 1 \(Requested\)\n`,
|
||
`assignees:\tmarseilles, monaco\n`,
|
||
`labels:\tone, two, three, four, five\n`,
|
||
`projects:\tProject 1 \(column A\), Project 2 \(column B\), Project 3 \(column C\), Project 4 \(Awaiting triage\)\n`,
|
||
`milestone:\tuluru\n`,
|
||
`\*\*blueberries taste good\*\*`,
|
||
},
|
||
},
|
||
"Open PR with reviewers by number": {
|
||
ownerRepo: "master",
|
||
args: "pr view 12",
|
||
fixture: "../test/fixtures/prViewPreviewWithReviewersByNumber.json",
|
||
expectedOutputs: []string{
|
||
`title:\tBlueberries are from a fork\n`,
|
||
`state:\tOPEN\n`,
|
||
`author:\tnobody\n`,
|
||
`labels:\t\n`,
|
||
`assignees:\t\n`,
|
||
`projects:\t\n`,
|
||
`milestone:\t\n`,
|
||
`reviewers:\tDEF \(Commented\), def \(Changes requested\), ghost \(Approved\), hubot \(Commented\), xyz \(Approved\), 123 \(Requested\), Team 1 \(Requested\), abc \(Requested\)\n`,
|
||
`\*\*blueberries taste good\*\*`,
|
||
},
|
||
},
|
||
"Open PR with metadata by branch": {
|
||
ownerRepo: "master",
|
||
args: "pr view blueberries",
|
||
fixture: "../test/fixtures/prViewPreviewWithMetadataByBranch.json",
|
||
expectedOutputs: []string{
|
||
`title:\tBlueberries are a good fruit`,
|
||
`state:\tOPEN`,
|
||
`author:\tnobody`,
|
||
`assignees:\tmarseilles, monaco\n`,
|
||
`labels:\tone, two, three, four, five\n`,
|
||
`projects:\tProject 1 \(column A\), Project 2 \(column B\), Project 3 \(column C\)\n`,
|
||
`milestone:\tuluru\n`,
|
||
`blueberries taste good`,
|
||
},
|
||
},
|
||
"Open PR for the current branch": {
|
||
ownerRepo: "blueberries",
|
||
args: "pr view",
|
||
fixture: "../test/fixtures/prView.json",
|
||
expectedOutputs: []string{
|
||
`title:\tBlueberries are a good fruit`,
|
||
`state:\tOPEN`,
|
||
`author:\tnobody`,
|
||
`assignees:\t\n`,
|
||
`labels:\t\n`,
|
||
`projects:\t\n`,
|
||
`milestone:\t\n`,
|
||
`\*\*blueberries taste good\*\*`,
|
||
},
|
||
},
|
||
"Open PR wth empty body for the current branch": {
|
||
ownerRepo: "blueberries",
|
||
args: "pr view",
|
||
fixture: "../test/fixtures/prView_EmptyBody.json",
|
||
expectedOutputs: []string{
|
||
`title:\tBlueberries are a good fruit`,
|
||
`state:\tOPEN`,
|
||
`author:\tnobody`,
|
||
`assignees:\t\n`,
|
||
`labels:\t\n`,
|
||
`projects:\t\n`,
|
||
`milestone:\t\n`,
|
||
},
|
||
},
|
||
"Closed PR": {
|
||
ownerRepo: "master",
|
||
args: "pr view 12",
|
||
fixture: "../test/fixtures/prViewPreviewClosedState.json",
|
||
expectedOutputs: []string{
|
||
`state:\tCLOSED\n`,
|
||
`author:\tnobody\n`,
|
||
`labels:\t\n`,
|
||
`assignees:\t\n`,
|
||
`reviewers:\t\n`,
|
||
`projects:\t\n`,
|
||
`milestone:\t\n`,
|
||
`\*\*blueberries taste good\*\*`,
|
||
},
|
||
},
|
||
"Merged PR": {
|
||
ownerRepo: "master",
|
||
args: "pr view 12",
|
||
fixture: "../test/fixtures/prViewPreviewMergedState.json",
|
||
expectedOutputs: []string{
|
||
`state:\tMERGED\n`,
|
||
`author:\tnobody\n`,
|
||
`labels:\t\n`,
|
||
`assignees:\t\n`,
|
||
`reviewers:\t\n`,
|
||
`projects:\t\n`,
|
||
`milestone:\t\n`,
|
||
`\*\*blueberries taste good\*\*`,
|
||
},
|
||
},
|
||
"Draft PR": {
|
||
ownerRepo: "master",
|
||
args: "pr view 12",
|
||
fixture: "../test/fixtures/prViewPreviewDraftState.json",
|
||
expectedOutputs: []string{
|
||
`title:\tBlueberries are from a fork\n`,
|
||
`state:\tDRAFT\n`,
|
||
`author:\tnobody\n`,
|
||
`labels:`,
|
||
`assignees:`,
|
||
`projects:`,
|
||
`milestone:`,
|
||
`\*\*blueberries taste good\*\*`,
|
||
},
|
||
},
|
||
"Draft PR by branch": {
|
||
ownerRepo: "master",
|
||
args: "pr view blueberries",
|
||
fixture: "../test/fixtures/prViewPreviewDraftStatebyBranch.json",
|
||
expectedOutputs: []string{
|
||
`title:\tBlueberries are a good fruit\n`,
|
||
`state:\tDRAFT\n`,
|
||
`author:\tnobody\n`,
|
||
`labels:`,
|
||
`assignees:`,
|
||
`projects:`,
|
||
`milestone:`,
|
||
`\*\*blueberries taste good\*\*`,
|
||
},
|
||
},
|
||
}
|
||
|
||
for name, tc := range tests {
|
||
t.Run(name, func(t *testing.T) {
|
||
initBlankContext("", "OWNER/REPO", tc.ownerRepo)
|
||
http := initFakeHTTP()
|
||
http.StubRepoResponse("OWNER", "REPO")
|
||
http.Register(httpmock.GraphQL(`query PullRequest(ByNumber|ForBranch)\b`), httpmock.FileResponse(tc.fixture))
|
||
|
||
output, err := RunCommand(tc.args)
|
||
if err != nil {
|
||
t.Errorf("error running command `%v`: %v", tc.args, err)
|
||
}
|
||
|
||
eq(t, output.Stderr(), "")
|
||
|
||
test.ExpectLines(t, output.String(), tc.expectedOutputs...)
|
||
})
|
||
}
|
||
}
|
||
|
||
func TestPRView_Preview(t *testing.T) {
|
||
defer stubTerminal(true)()
|
||
tests := map[string]struct {
|
||
ownerRepo string
|
||
args string
|
||
fixture string
|
||
expectedOutputs []string
|
||
}{
|
||
"Open PR without metadata": {
|
||
ownerRepo: "master",
|
||
args: "pr view 12",
|
||
fixture: "../test/fixtures/prViewPreview.json",
|
||
expectedOutputs: []string{
|
||
`Blueberries are from a fork`,
|
||
`Open.*nobody wants to merge 12 commits into master from blueberries`,
|
||
`blueberries taste good`,
|
||
`View this pull request on GitHub: https://github.com/OWNER/REPO/pull/12`,
|
||
},
|
||
},
|
||
"Open PR with metadata by number": {
|
||
ownerRepo: "master",
|
||
args: "pr view 12",
|
||
fixture: "../test/fixtures/prViewPreviewWithMetadataByNumber.json",
|
||
expectedOutputs: []string{
|
||
`Blueberries are from a fork`,
|
||
`Open.*nobody wants to merge 12 commits into master from blueberries`,
|
||
`Reviewers:.*2 \(.*Approved.*\), 3 \(Commented\), 1 \(.*Requested.*\)\n`,
|
||
`Assignees:.*marseilles, monaco\n`,
|
||
`Labels:.*one, two, three, four, five\n`,
|
||
`Projects:.*Project 1 \(column A\), Project 2 \(column B\), Project 3 \(column C\), Project 4 \(Awaiting triage\)\n`,
|
||
`Milestone:.*uluru\n`,
|
||
`blueberries taste good`,
|
||
`View this pull request on GitHub: https://github.com/OWNER/REPO/pull/12\n`,
|
||
},
|
||
},
|
||
"Open PR with reviewers by number": {
|
||
ownerRepo: "master",
|
||
args: "pr view 12",
|
||
fixture: "../test/fixtures/prViewPreviewWithReviewersByNumber.json",
|
||
expectedOutputs: []string{
|
||
`Blueberries are from a fork`,
|
||
`Reviewers:.*DEF \(.*Commented.*\), def \(.*Changes requested.*\), ghost \(.*Approved.*\), hubot \(Commented\), xyz \(.*Approved.*\), 123 \(.*Requested.*\), Team 1 \(.*Requested.*\), abc \(.*Requested.*\)\n`,
|
||
`blueberries taste good`,
|
||
`View this pull request on GitHub: https://github.com/OWNER/REPO/pull/12\n`,
|
||
},
|
||
},
|
||
"Open PR with metadata by branch": {
|
||
ownerRepo: "master",
|
||
args: "pr view blueberries",
|
||
fixture: "../test/fixtures/prViewPreviewWithMetadataByBranch.json",
|
||
expectedOutputs: []string{
|
||
`Blueberries are a good fruit`,
|
||
`Open.*nobody wants to merge 8 commits into master from blueberries`,
|
||
`Assignees:.*marseilles, monaco\n`,
|
||
`Labels:.*one, two, three, four, five\n`,
|
||
`Projects:.*Project 1 \(column A\), Project 2 \(column B\), Project 3 \(column C\)\n`,
|
||
`Milestone:.*uluru\n`,
|
||
`blueberries taste good`,
|
||
`View this pull request on GitHub: https://github.com/OWNER/REPO/pull/10\n`,
|
||
},
|
||
},
|
||
"Open PR for the current branch": {
|
||
ownerRepo: "blueberries",
|
||
args: "pr view",
|
||
fixture: "../test/fixtures/prView.json",
|
||
expectedOutputs: []string{
|
||
`Blueberries are a good fruit`,
|
||
`Open.*nobody wants to merge 8 commits into master from blueberries`,
|
||
`blueberries taste good`,
|
||
`View this pull request on GitHub: https://github.com/OWNER/REPO/pull/10`,
|
||
},
|
||
},
|
||
"Open PR wth empty body for the current branch": {
|
||
ownerRepo: "blueberries",
|
||
args: "pr view",
|
||
fixture: "../test/fixtures/prView_EmptyBody.json",
|
||
expectedOutputs: []string{
|
||
`Blueberries are a good fruit`,
|
||
`Open.*nobody wants to merge 8 commits into master from blueberries`,
|
||
`View this pull request on GitHub: https://github.com/OWNER/REPO/pull/10`,
|
||
},
|
||
},
|
||
"Closed PR": {
|
||
ownerRepo: "master",
|
||
args: "pr view 12",
|
||
fixture: "../test/fixtures/prViewPreviewClosedState.json",
|
||
expectedOutputs: []string{
|
||
`Blueberries are from a fork`,
|
||
`Closed.*nobody wants to merge 12 commits into master from blueberries`,
|
||
`blueberries taste good`,
|
||
`View this pull request on GitHub: https://github.com/OWNER/REPO/pull/12`,
|
||
},
|
||
},
|
||
"Merged PR": {
|
||
ownerRepo: "master",
|
||
args: "pr view 12",
|
||
fixture: "../test/fixtures/prViewPreviewMergedState.json",
|
||
expectedOutputs: []string{
|
||
`Blueberries are from a fork`,
|
||
`Merged.*nobody wants to merge 12 commits into master from blueberries`,
|
||
`blueberries taste good`,
|
||
`View this pull request on GitHub: https://github.com/OWNER/REPO/pull/12`,
|
||
},
|
||
},
|
||
"Draft PR": {
|
||
ownerRepo: "master",
|
||
args: "pr view 12",
|
||
fixture: "../test/fixtures/prViewPreviewDraftState.json",
|
||
expectedOutputs: []string{
|
||
`Blueberries are from a fork`,
|
||
`Draft.*nobody wants to merge 12 commits into master from blueberries`,
|
||
`blueberries taste good`,
|
||
`View this pull request on GitHub: https://github.com/OWNER/REPO/pull/12`,
|
||
},
|
||
},
|
||
"Draft PR by branch": {
|
||
ownerRepo: "master",
|
||
args: "pr view blueberries",
|
||
fixture: "../test/fixtures/prViewPreviewDraftStatebyBranch.json",
|
||
expectedOutputs: []string{
|
||
`Blueberries are a good fruit`,
|
||
`Draft.*nobody wants to merge 8 commits into master from blueberries`,
|
||
`blueberries taste good`,
|
||
`View this pull request on GitHub: https://github.com/OWNER/REPO/pull/10`,
|
||
},
|
||
},
|
||
}
|
||
|
||
for name, tc := range tests {
|
||
t.Run(name, func(t *testing.T) {
|
||
initBlankContext("", "OWNER/REPO", tc.ownerRepo)
|
||
http := initFakeHTTP()
|
||
http.StubRepoResponse("OWNER", "REPO")
|
||
http.Register(httpmock.GraphQL(`query PullRequest(ByNumber|ForBranch)\b`), httpmock.FileResponse(tc.fixture))
|
||
|
||
output, err := RunCommand(tc.args)
|
||
if err != nil {
|
||
t.Errorf("error running command `%v`: %v", tc.args, err)
|
||
}
|
||
|
||
eq(t, output.Stderr(), "")
|
||
|
||
test.ExpectLines(t, output.String(), tc.expectedOutputs...)
|
||
})
|
||
}
|
||
}
|
||
|
||
func TestPRView_web_currentBranch(t *testing.T) {
|
||
initBlankContext("", "OWNER/REPO", "blueberries")
|
||
defer stubTerminal(true)()
|
||
http := initFakeHTTP()
|
||
http.StubRepoResponse("OWNER", "REPO")
|
||
http.Register(httpmock.GraphQL(`query PullRequestForBranch\b`), httpmock.FileResponse("../test/fixtures/prView.json"))
|
||
|
||
var seenCmd *exec.Cmd
|
||
restoreCmd := run.SetPrepareCmd(func(cmd *exec.Cmd) run.Runnable {
|
||
switch strings.Join(cmd.Args, " ") {
|
||
case `git config --get-regexp ^branch\.blueberries\.(remote|merge)$`:
|
||
return &test.OutputStub{}
|
||
default:
|
||
seenCmd = cmd
|
||
return &test.OutputStub{}
|
||
}
|
||
})
|
||
defer restoreCmd()
|
||
|
||
output, err := RunCommand("pr view -w")
|
||
if err != nil {
|
||
t.Errorf("error running command `pr view`: %v", err)
|
||
}
|
||
|
||
eq(t, output.String(), "")
|
||
eq(t, output.Stderr(), "Opening https://github.com/OWNER/REPO/pull/10 in your browser.\n")
|
||
|
||
if seenCmd == nil {
|
||
t.Fatal("expected a command to run")
|
||
}
|
||
url := seenCmd.Args[len(seenCmd.Args)-1]
|
||
if url != "https://github.com/OWNER/REPO/pull/10" {
|
||
t.Errorf("got: %q", url)
|
||
}
|
||
}
|
||
|
||
func TestPRView_web_noResultsForBranch(t *testing.T) {
|
||
initBlankContext("", "OWNER/REPO", "blueberries")
|
||
defer stubTerminal(true)()
|
||
http := initFakeHTTP()
|
||
http.StubRepoResponse("OWNER", "REPO")
|
||
http.Register(httpmock.GraphQL(`query PullRequestForBranch\b`), httpmock.FileResponse("../test/fixtures/prView_NoActiveBranch.json"))
|
||
|
||
var seenCmd *exec.Cmd
|
||
restoreCmd := run.SetPrepareCmd(func(cmd *exec.Cmd) run.Runnable {
|
||
switch strings.Join(cmd.Args, " ") {
|
||
case `git config --get-regexp ^branch\.blueberries\.(remote|merge)$`:
|
||
return &test.OutputStub{}
|
||
default:
|
||
seenCmd = cmd
|
||
return &test.OutputStub{}
|
||
}
|
||
})
|
||
defer restoreCmd()
|
||
|
||
_, err := RunCommand("pr view -w")
|
||
if err == nil || err.Error() != `no open pull requests found for branch "blueberries"` {
|
||
t.Errorf("error running command `pr view`: %v", err)
|
||
}
|
||
|
||
if seenCmd != nil {
|
||
t.Fatalf("unexpected command: %v", seenCmd.Args)
|
||
}
|
||
}
|
||
|
||
func TestPRView_web_numberArg(t *testing.T) {
|
||
initBlankContext("", "OWNER/REPO", "master")
|
||
defer stubTerminal(true)()
|
||
http := initFakeHTTP()
|
||
http.StubRepoResponse("OWNER", "REPO")
|
||
|
||
http.StubResponse(200, bytes.NewBufferString(`
|
||
{ "data": { "repository": { "pullRequest": {
|
||
"url": "https://github.com/OWNER/REPO/pull/23"
|
||
} } } }
|
||
`))
|
||
|
||
var seenCmd *exec.Cmd
|
||
restoreCmd := run.SetPrepareCmd(func(cmd *exec.Cmd) run.Runnable {
|
||
seenCmd = cmd
|
||
return &test.OutputStub{}
|
||
})
|
||
defer restoreCmd()
|
||
|
||
output, err := RunCommand("pr view -w 23")
|
||
if err != nil {
|
||
t.Errorf("error running command `pr view`: %v", err)
|
||
}
|
||
|
||
eq(t, output.String(), "")
|
||
|
||
if seenCmd == nil {
|
||
t.Fatal("expected a command to run")
|
||
}
|
||
url := seenCmd.Args[len(seenCmd.Args)-1]
|
||
eq(t, url, "https://github.com/OWNER/REPO/pull/23")
|
||
}
|
||
|
||
func TestPRView_web_numberArgWithHash(t *testing.T) {
|
||
initBlankContext("", "OWNER/REPO", "master")
|
||
defer stubTerminal(true)()
|
||
http := initFakeHTTP()
|
||
http.StubRepoResponse("OWNER", "REPO")
|
||
|
||
http.StubResponse(200, bytes.NewBufferString(`
|
||
{ "data": { "repository": { "pullRequest": {
|
||
"url": "https://github.com/OWNER/REPO/pull/23"
|
||
} } } }
|
||
`))
|
||
|
||
var seenCmd *exec.Cmd
|
||
restoreCmd := run.SetPrepareCmd(func(cmd *exec.Cmd) run.Runnable {
|
||
seenCmd = cmd
|
||
return &test.OutputStub{}
|
||
})
|
||
defer restoreCmd()
|
||
|
||
output, err := RunCommand("pr view -w \"#23\"")
|
||
if err != nil {
|
||
t.Errorf("error running command `pr view`: %v", err)
|
||
}
|
||
|
||
eq(t, output.String(), "")
|
||
|
||
if seenCmd == nil {
|
||
t.Fatal("expected a command to run")
|
||
}
|
||
url := seenCmd.Args[len(seenCmd.Args)-1]
|
||
eq(t, url, "https://github.com/OWNER/REPO/pull/23")
|
||
}
|
||
|
||
func TestPRView_web_urlArg(t *testing.T) {
|
||
initBlankContext("", "OWNER/REPO", "master")
|
||
defer stubTerminal(true)()
|
||
http := initFakeHTTP()
|
||
http.StubResponse(200, bytes.NewBufferString(`
|
||
{ "data": { "repository": { "pullRequest": {
|
||
"url": "https://github.com/OWNER/REPO/pull/23"
|
||
} } } }
|
||
`))
|
||
|
||
var seenCmd *exec.Cmd
|
||
restoreCmd := run.SetPrepareCmd(func(cmd *exec.Cmd) run.Runnable {
|
||
seenCmd = cmd
|
||
return &test.OutputStub{}
|
||
})
|
||
defer restoreCmd()
|
||
|
||
output, err := RunCommand("pr view -w https://github.com/OWNER/REPO/pull/23/files")
|
||
if err != nil {
|
||
t.Errorf("error running command `pr view`: %v", err)
|
||
}
|
||
|
||
eq(t, output.String(), "")
|
||
|
||
if seenCmd == nil {
|
||
t.Fatal("expected a command to run")
|
||
}
|
||
url := seenCmd.Args[len(seenCmd.Args)-1]
|
||
eq(t, url, "https://github.com/OWNER/REPO/pull/23")
|
||
}
|
||
|
||
func TestPRView_web_branchArg(t *testing.T) {
|
||
initBlankContext("", "OWNER/REPO", "master")
|
||
defer stubTerminal(true)()
|
||
http := initFakeHTTP()
|
||
http.StubRepoResponse("OWNER", "REPO")
|
||
|
||
http.StubResponse(200, bytes.NewBufferString(`
|
||
{ "data": { "repository": { "pullRequests": { "nodes": [
|
||
{ "headRefName": "blueberries",
|
||
"isCrossRepository": false,
|
||
"url": "https://github.com/OWNER/REPO/pull/23" }
|
||
] } } } }
|
||
`))
|
||
|
||
var seenCmd *exec.Cmd
|
||
restoreCmd := run.SetPrepareCmd(func(cmd *exec.Cmd) run.Runnable {
|
||
seenCmd = cmd
|
||
return &test.OutputStub{}
|
||
})
|
||
defer restoreCmd()
|
||
|
||
output, err := RunCommand("pr view -w blueberries")
|
||
if err != nil {
|
||
t.Errorf("error running command `pr view`: %v", err)
|
||
}
|
||
|
||
eq(t, output.String(), "")
|
||
|
||
if seenCmd == nil {
|
||
t.Fatal("expected a command to run")
|
||
}
|
||
url := seenCmd.Args[len(seenCmd.Args)-1]
|
||
eq(t, url, "https://github.com/OWNER/REPO/pull/23")
|
||
}
|
||
|
||
func TestPRView_web_branchWithOwnerArg(t *testing.T) {
|
||
initBlankContext("", "OWNER/REPO", "master")
|
||
defer stubTerminal(true)()
|
||
http := initFakeHTTP()
|
||
http.StubRepoResponse("OWNER", "REPO")
|
||
|
||
http.StubResponse(200, bytes.NewBufferString(`
|
||
{ "data": { "repository": { "pullRequests": { "nodes": [
|
||
{ "headRefName": "blueberries",
|
||
"isCrossRepository": true,
|
||
"headRepositoryOwner": { "login": "hubot" },
|
||
"url": "https://github.com/hubot/REPO/pull/23" }
|
||
] } } } }
|
||
`))
|
||
|
||
var seenCmd *exec.Cmd
|
||
restoreCmd := run.SetPrepareCmd(func(cmd *exec.Cmd) run.Runnable {
|
||
seenCmd = cmd
|
||
return &test.OutputStub{}
|
||
})
|
||
defer restoreCmd()
|
||
|
||
output, err := RunCommand("pr view -w hubot:blueberries")
|
||
if err != nil {
|
||
t.Errorf("error running command `pr view`: %v", err)
|
||
}
|
||
|
||
eq(t, output.String(), "")
|
||
|
||
if seenCmd == nil {
|
||
t.Fatal("expected a command to run")
|
||
}
|
||
url := seenCmd.Args[len(seenCmd.Args)-1]
|
||
eq(t, url, "https://github.com/hubot/REPO/pull/23")
|
||
}
|
||
|
||
func TestReplaceExcessiveWhitespace(t *testing.T) {
|
||
eq(t, replaceExcessiveWhitespace("hello\ngoodbye"), "hello goodbye")
|
||
eq(t, replaceExcessiveWhitespace(" hello goodbye "), "hello goodbye")
|
||
eq(t, replaceExcessiveWhitespace("hello goodbye"), "hello goodbye")
|
||
eq(t, replaceExcessiveWhitespace(" hello \n goodbye "), "hello goodbye")
|
||
}
|
||
|
||
func TestPrStateTitleWithColor(t *testing.T) {
|
||
tests := map[string]struct {
|
||
pr api.PullRequest
|
||
want string
|
||
}{
|
||
"Format OPEN state": {pr: api.PullRequest{State: "OPEN", IsDraft: false}, want: "Open"},
|
||
"Format OPEN state for Draft PR": {pr: api.PullRequest{State: "OPEN", IsDraft: true}, want: "Draft"},
|
||
"Format CLOSED state": {pr: api.PullRequest{State: "CLOSED", IsDraft: false}, want: "Closed"},
|
||
"Format MERGED state": {pr: api.PullRequest{State: "MERGED", IsDraft: false}, want: "Merged"},
|
||
}
|
||
|
||
for name, tc := range tests {
|
||
t.Run(name, func(t *testing.T) {
|
||
got := prStateTitleWithColor(tc.pr)
|
||
diff := cmp.Diff(tc.want, got)
|
||
if diff != "" {
|
||
t.Fatalf(diff)
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
func TestPrClose(t *testing.T) {
|
||
initBlankContext("", "OWNER/REPO", "master")
|
||
http := initFakeHTTP()
|
||
http.StubRepoResponse("OWNER", "REPO")
|
||
|
||
http.StubResponse(200, bytes.NewBufferString(`
|
||
{ "data": { "repository": {
|
||
"pullRequest": { "number": 96, "title": "The title of the PR" }
|
||
} } }
|
||
`))
|
||
|
||
http.StubResponse(200, bytes.NewBufferString(`{"id": "THE-ID"}`))
|
||
|
||
output, err := RunCommand("pr close 96")
|
||
if err != nil {
|
||
t.Fatalf("error running command `pr close`: %v", err)
|
||
}
|
||
|
||
r := regexp.MustCompile(`Closed pull request #96 \(The title of the PR\)`)
|
||
|
||
if !r.MatchString(output.Stderr()) {
|
||
t.Fatalf("output did not match regexp /%s/\n> output\n%q\n", r, output.Stderr())
|
||
}
|
||
}
|
||
|
||
func TestPrClose_alreadyClosed(t *testing.T) {
|
||
initBlankContext("", "OWNER/REPO", "master")
|
||
http := initFakeHTTP()
|
||
http.StubRepoResponse("OWNER", "REPO")
|
||
|
||
http.StubResponse(200, bytes.NewBufferString(`
|
||
{ "data": { "repository": {
|
||
"pullRequest": { "number": 101, "title": "The title of the PR", "closed": true }
|
||
} } }
|
||
`))
|
||
|
||
http.StubResponse(200, bytes.NewBufferString(`{"id": "THE-ID"}`))
|
||
|
||
output, err := RunCommand("pr close 101")
|
||
if err != nil {
|
||
t.Fatalf("error running command `pr close`: %v", err)
|
||
}
|
||
|
||
r := regexp.MustCompile(`Pull request #101 \(The title of the PR\) is already closed`)
|
||
|
||
if !r.MatchString(output.Stderr()) {
|
||
t.Fatalf("output did not match regexp /%s/\n> output\n%q\n", r, output.Stderr())
|
||
}
|
||
}
|
||
|
||
func TestPRReopen(t *testing.T) {
|
||
initBlankContext("", "OWNER/REPO", "master")
|
||
http := initFakeHTTP()
|
||
http.StubRepoResponse("OWNER", "REPO")
|
||
|
||
http.StubResponse(200, bytes.NewBufferString(`
|
||
{ "data": { "repository": {
|
||
"pullRequest": { "number": 666, "title": "The title of the PR", "closed": true}
|
||
} } }
|
||
`))
|
||
|
||
http.StubResponse(200, bytes.NewBufferString(`{"id": "THE-ID"}`))
|
||
|
||
output, err := RunCommand("pr reopen 666")
|
||
if err != nil {
|
||
t.Fatalf("error running command `pr reopen`: %v", err)
|
||
}
|
||
|
||
r := regexp.MustCompile(`Reopened pull request #666 \(The title of the PR\)`)
|
||
|
||
if !r.MatchString(output.Stderr()) {
|
||
t.Fatalf("output did not match regexp /%s/\n> output\n%q\n", r, output.Stderr())
|
||
}
|
||
}
|
||
|
||
func TestPRReopen_alreadyOpen(t *testing.T) {
|
||
initBlankContext("", "OWNER/REPO", "master")
|
||
http := initFakeHTTP()
|
||
http.StubRepoResponse("OWNER", "REPO")
|
||
|
||
http.StubResponse(200, bytes.NewBufferString(`
|
||
{ "data": { "repository": {
|
||
"pullRequest": { "number": 666, "title": "The title of the PR", "closed": false}
|
||
} } }
|
||
`))
|
||
|
||
http.StubResponse(200, bytes.NewBufferString(`{"id": "THE-ID"}`))
|
||
|
||
output, err := RunCommand("pr reopen 666")
|
||
if err != nil {
|
||
t.Fatalf("error running command `pr reopen`: %v", err)
|
||
}
|
||
|
||
r := regexp.MustCompile(`Pull request #666 \(The title of the PR\) is already open`)
|
||
|
||
if !r.MatchString(output.Stderr()) {
|
||
t.Fatalf("output did not match regexp /%s/\n> output\n%q\n", r, output.Stderr())
|
||
}
|
||
}
|
||
|
||
func TestPRReopen_alreadyMerged(t *testing.T) {
|
||
initBlankContext("", "OWNER/REPO", "master")
|
||
http := initFakeHTTP()
|
||
http.StubRepoResponse("OWNER", "REPO")
|
||
|
||
http.StubResponse(200, bytes.NewBufferString(`
|
||
{ "data": { "repository": {
|
||
"pullRequest": { "number": 666, "title": "The title of the PR", "closed": true, "state": "MERGED"}
|
||
} } }
|
||
`))
|
||
|
||
http.StubResponse(200, bytes.NewBufferString(`{"id": "THE-ID"}`))
|
||
|
||
output, err := RunCommand("pr reopen 666")
|
||
if err == nil {
|
||
t.Fatalf("expected an error running command `pr reopen`: %v", err)
|
||
}
|
||
|
||
r := regexp.MustCompile(`Pull request #666 \(The title of the PR\) can't be reopened because it was already merged`)
|
||
|
||
if !r.MatchString(err.Error()) {
|
||
t.Fatalf("output did not match regexp /%s/\n> output\n%q\n", r, output.Stderr())
|
||
}
|
||
}
|
||
|
||
func TestPrMerge(t *testing.T) {
|
||
initBlankContext("", "OWNER/REPO", "master")
|
||
defer stubTerminal(true)()
|
||
http := initFakeHTTP()
|
||
defer http.Verify(t)
|
||
http.StubRepoResponse("OWNER", "REPO")
|
||
http.Register(
|
||
httpmock.GraphQL(`query PullRequestByNumber\b`),
|
||
httpmock.StringResponse(`
|
||
{ "data": { "repository": { "pullRequest": {
|
||
"id": "THE-ID",
|
||
"number": 1,
|
||
"title": "The title of the PR",
|
||
"state": "OPEN",
|
||
"headRefName": "blueberries",
|
||
"headRepositoryOwner": {"login": "OWNER"}
|
||
} } } }`))
|
||
http.Register(
|
||
httpmock.GraphQL(`mutation PullRequestMerge\b`),
|
||
httpmock.GraphQLMutation(`{}`, func(input map[string]interface{}) {
|
||
assert.Equal(t, "THE-ID", input["pullRequestId"].(string))
|
||
assert.Equal(t, "MERGE", input["mergeMethod"].(string))
|
||
}))
|
||
http.Register(
|
||
httpmock.REST("DELETE", "repos/OWNER/REPO/git/refs/heads/blueberries"),
|
||
httpmock.StringResponse(`{}`))
|
||
|
||
cs, cmdTeardown := test.InitCmdStubber()
|
||
defer cmdTeardown()
|
||
|
||
cs.Stub("branch.blueberries.remote origin\nbranch.blueberries.merge refs/heads/blueberries") // git config --get-regexp ^branch\.master\.(remote|merge)
|
||
cs.Stub("") // git config --get-regexp ^branch\.blueberries\.(remote|merge)$
|
||
cs.Stub("") // git symbolic-ref --quiet --short HEAD
|
||
cs.Stub("") // git checkout master
|
||
cs.Stub("")
|
||
|
||
output, err := RunCommand("pr merge 1 --merge")
|
||
if err != nil {
|
||
t.Fatalf("error running command `pr merge`: %v", err)
|
||
}
|
||
|
||
r := regexp.MustCompile(`Merged pull request #1 \(The title of the PR\)`)
|
||
|
||
if !r.MatchString(output.Stderr()) {
|
||
t.Fatalf("output did not match regexp /%s/\n> output\n%q\n", r, output.Stderr())
|
||
}
|
||
}
|
||
|
||
func TestPrMerge_nontty(t *testing.T) {
|
||
initBlankContext("", "OWNER/REPO", "master")
|
||
defer stubTerminal(false)()
|
||
http := initFakeHTTP()
|
||
http.StubRepoResponse("OWNER", "REPO")
|
||
http.Register(
|
||
httpmock.GraphQL(`query PullRequestByNumber\b`),
|
||
httpmock.StringResponse(`
|
||
{ "data": { "repository": {
|
||
"pullRequest": { "number": 1, "title": "The title of the PR", "state": "OPEN", "id": "THE-ID"}
|
||
} } }`))
|
||
http.Register(
|
||
httpmock.GraphQL(`mutation PullRequestMerge\b`),
|
||
httpmock.GraphQLMutation(`{}`, func(input map[string]interface{}) {
|
||
assert.Equal(t, "THE-ID", input["pullRequestId"].(string))
|
||
assert.Equal(t, "MERGE", input["mergeMethod"].(string))
|
||
}))
|
||
http.Register(
|
||
httpmock.GraphQL(`query RepositoryInfo\b`),
|
||
httpmock.StringResponse(`{
|
||
"data": {
|
||
"repository": {
|
||
"defaultBranchRef": {"name": "master"}
|
||
}
|
||
}
|
||
}`))
|
||
http.Register(
|
||
httpmock.REST("DELETE", "repos/OWNER/REPO/git/refs/heads/blueberries"),
|
||
httpmock.StringResponse(`{}`))
|
||
|
||
cs, cmdTeardown := test.InitCmdStubber()
|
||
defer cmdTeardown()
|
||
|
||
cs.Stub("branch.blueberries.remote origin\nbranch.blueberries.merge refs/heads/blueberries") // git config --get-regexp ^branch\.master\.(remote|merge)
|
||
cs.Stub("") // git config --get-regexp ^branch\.blueberries\.(remote|merge)$
|
||
cs.Stub("") // git symbolic-ref --quiet --short HEAD
|
||
cs.Stub("") // git checkout master
|
||
cs.Stub("")
|
||
|
||
output, err := RunCommand("pr merge 1 --merge")
|
||
if err != nil {
|
||
t.Fatalf("error running command `pr merge`: %v", err)
|
||
}
|
||
|
||
assert.Equal(t, "", output.String())
|
||
assert.Equal(t, "", output.Stderr())
|
||
}
|
||
|
||
func TestPrMerge_nontty_insufficient_flags(t *testing.T) {
|
||
initBlankContext("", "OWNER/REPO", "master")
|
||
defer stubTerminal(false)()
|
||
http := initFakeHTTP()
|
||
http.StubRepoResponse("OWNER", "REPO")
|
||
http.Register(
|
||
httpmock.GraphQL(`query PullRequestByNumber\b`),
|
||
httpmock.StringResponse(`
|
||
{ "data": { "repository": {
|
||
"pullRequest": { "number": 1, "title": "The title of the PR", "state": "OPEN", "id": "THE-ID"}
|
||
} } }`))
|
||
|
||
output, err := RunCommand("pr merge 1")
|
||
if err == nil {
|
||
t.Fatal("expected error")
|
||
}
|
||
|
||
assert.Equal(t, "--merge, --rebase, or --squash required when not attached to a tty", err.Error())
|
||
assert.Equal(t, "", output.String())
|
||
}
|
||
|
||
func TestPrMerge_withRepoFlag(t *testing.T) {
|
||
initBlankContext("", "OWNER/REPO", "master")
|
||
defer stubTerminal(true)()
|
||
http := initFakeHTTP()
|
||
defer http.Verify(t)
|
||
http.Register(
|
||
httpmock.GraphQL(`query PullRequestByNumber\b`),
|
||
httpmock.GraphQLQuery(`
|
||
{ "data": { "repository": {
|
||
"pullRequest": { "number": 1, "title": "The title of the PR", "state": "OPEN", "id": "THE-ID"}
|
||
} } }`, func(_ string, params map[string]interface{}) {
|
||
assert.Equal(t, "stinky", params["owner"].(string))
|
||
assert.Equal(t, "boi", params["repo"].(string))
|
||
}))
|
||
http.Register(
|
||
httpmock.GraphQL(`mutation PullRequestMerge\b`),
|
||
httpmock.GraphQLMutation(`{}`, func(input map[string]interface{}) {
|
||
assert.Equal(t, "THE-ID", input["pullRequestId"].(string))
|
||
assert.Equal(t, "MERGE", input["mergeMethod"].(string))
|
||
}))
|
||
|
||
cs, cmdTeardown := test.InitCmdStubber()
|
||
defer cmdTeardown()
|
||
|
||
eq(t, len(cs.Calls), 0)
|
||
|
||
output, err := RunCommand("pr merge 1 --merge -R stinky/boi")
|
||
if err != nil {
|
||
t.Fatalf("error running command `pr merge`: %v", err)
|
||
}
|
||
|
||
r := regexp.MustCompile(`Merged pull request #1 \(The title of the PR\)`)
|
||
|
||
if !r.MatchString(output.Stderr()) {
|
||
t.Fatalf("output did not match regexp /%s/\n> output\n%q\n", r, output.Stderr())
|
||
}
|
||
}
|
||
|
||
func TestPrMerge_deleteBranch(t *testing.T) {
|
||
initBlankContext("", "OWNER/REPO", "blueberries")
|
||
defer stubTerminal(true)()
|
||
http := initFakeHTTP()
|
||
defer http.Verify(t)
|
||
http.StubRepoResponse("OWNER", "REPO")
|
||
http.Register(
|
||
httpmock.GraphQL(`query PullRequestForBranch\b`),
|
||
httpmock.FileResponse("../test/fixtures/prViewPreviewWithMetadataByBranch.json"))
|
||
http.Register(
|
||
httpmock.GraphQL(`mutation PullRequestMerge\b`),
|
||
httpmock.GraphQLMutation(`{}`, func(input map[string]interface{}) {
|
||
assert.Equal(t, "PR_10", input["pullRequestId"].(string))
|
||
assert.Equal(t, "MERGE", input["mergeMethod"].(string))
|
||
}))
|
||
http.Register(
|
||
httpmock.REST("DELETE", "repos/OWNER/REPO/git/refs/heads/blueberries"),
|
||
httpmock.StringResponse(`{}`))
|
||
|
||
cs, cmdTeardown := test.InitCmdStubber()
|
||
defer cmdTeardown()
|
||
|
||
cs.Stub("") // git config --get-regexp ^branch\.blueberries\.(remote|merge)$
|
||
cs.Stub("") // git checkout master
|
||
cs.Stub("") // git rev-parse --verify blueberries`
|
||
cs.Stub("") // git branch -d
|
||
cs.Stub("") // git push origin --delete blueberries
|
||
|
||
output, err := RunCommand(`pr merge --merge --delete-branch`)
|
||
if err != nil {
|
||
t.Fatalf("Got unexpected error running `pr merge` %s", err)
|
||
}
|
||
|
||
test.ExpectLines(t, output.Stderr(), `Merged pull request #10 \(Blueberries are a good fruit\)`, `Deleted branch.*blueberries`)
|
||
}
|
||
|
||
func TestPrMerge_deleteNonCurrentBranch(t *testing.T) {
|
||
initBlankContext("", "OWNER/REPO", "another-branch")
|
||
defer stubTerminal(true)()
|
||
http := initFakeHTTP()
|
||
defer http.Verify(t)
|
||
http.StubRepoResponse("OWNER", "REPO")
|
||
http.Register(
|
||
httpmock.GraphQL(`query PullRequestForBranch\b`),
|
||
httpmock.FileResponse("../test/fixtures/prViewPreviewWithMetadataByBranch.json"))
|
||
http.Register(
|
||
httpmock.GraphQL(`mutation PullRequestMerge\b`),
|
||
httpmock.GraphQLMutation(`{}`, func(input map[string]interface{}) {
|
||
assert.Equal(t, "PR_10", input["pullRequestId"].(string))
|
||
assert.Equal(t, "MERGE", input["mergeMethod"].(string))
|
||
}))
|
||
http.Register(
|
||
httpmock.REST("DELETE", "repos/OWNER/REPO/git/refs/heads/blueberries"),
|
||
httpmock.StringResponse(`{}`))
|
||
|
||
cs, cmdTeardown := test.InitCmdStubber()
|
||
defer cmdTeardown()
|
||
// We don't expect the default branch to be checked out, just that blueberries is deleted
|
||
cs.Stub("") // git rev-parse --verify blueberries
|
||
cs.Stub("") // git branch -d blueberries
|
||
cs.Stub("") // git push origin --delete blueberries
|
||
|
||
output, err := RunCommand(`pr merge --merge --delete-branch blueberries`)
|
||
if err != nil {
|
||
t.Fatalf("Got unexpected error running `pr merge` %s", err)
|
||
}
|
||
|
||
test.ExpectLines(t, output.Stderr(), `Merged pull request #10 \(Blueberries are a good fruit\)`, `Deleted branch.*blueberries`)
|
||
}
|
||
|
||
func TestPrMerge_noPrNumberGiven(t *testing.T) {
|
||
initBlankContext("", "OWNER/REPO", "blueberries")
|
||
defer stubTerminal(true)()
|
||
http := initFakeHTTP()
|
||
defer http.Verify(t)
|
||
http.StubRepoResponse("OWNER", "REPO")
|
||
http.Register(
|
||
httpmock.GraphQL(`query PullRequestForBranch\b`),
|
||
httpmock.FileResponse("../test/fixtures/prViewPreviewWithMetadataByBranch.json"))
|
||
http.Register(
|
||
httpmock.GraphQL(`mutation PullRequestMerge\b`),
|
||
httpmock.GraphQLMutation(`{}`, func(input map[string]interface{}) {
|
||
assert.Equal(t, "PR_10", input["pullRequestId"].(string))
|
||
assert.Equal(t, "MERGE", input["mergeMethod"].(string))
|
||
}))
|
||
http.Register(
|
||
httpmock.REST("DELETE", "repos/OWNER/REPO/git/refs/heads/blueberries"),
|
||
httpmock.StringResponse(`{}`))
|
||
|
||
cs, cmdTeardown := test.InitCmdStubber()
|
||
defer cmdTeardown()
|
||
|
||
cs.Stub("branch.blueberries.remote origin\nbranch.blueberries.merge refs/heads/blueberries") // git config --get-regexp ^branch\.master\.(remote|merge)
|
||
cs.Stub("") // git config --get-regexp ^branch\.blueberries\.(remote|merge)$
|
||
cs.Stub("") // git symbolic-ref --quiet --short HEAD
|
||
cs.Stub("") // git checkout master
|
||
cs.Stub("") // git branch -d
|
||
|
||
output, err := RunCommand("pr merge --merge")
|
||
if err != nil {
|
||
t.Fatalf("error running command `pr merge`: %v", err)
|
||
}
|
||
|
||
r := regexp.MustCompile(`Merged pull request #10 \(Blueberries are a good fruit\)`)
|
||
|
||
if !r.MatchString(output.Stderr()) {
|
||
t.Fatalf("output did not match regexp /%s/\n> output\n%q\n", r, output.Stderr())
|
||
}
|
||
}
|
||
|
||
func TestPrMerge_rebase(t *testing.T) {
|
||
initBlankContext("", "OWNER/REPO", "master")
|
||
defer stubTerminal(true)()
|
||
http := initFakeHTTP()
|
||
defer http.Verify(t)
|
||
http.StubRepoResponse("OWNER", "REPO")
|
||
http.Register(
|
||
httpmock.GraphQL(`query PullRequestByNumber\b`),
|
||
httpmock.StringResponse(`
|
||
{ "data": { "repository": { "pullRequest": {
|
||
"id": "THE-ID",
|
||
"number": 2,
|
||
"title": "The title of the PR",
|
||
"state": "OPEN",
|
||
"headRefName": "blueberries",
|
||
"headRepositoryOwner": {"login": "OWNER"}
|
||
} } } }`))
|
||
http.Register(
|
||
httpmock.GraphQL(`mutation PullRequestMerge\b`),
|
||
httpmock.GraphQLMutation(`{}`, func(input map[string]interface{}) {
|
||
assert.Equal(t, "THE-ID", input["pullRequestId"].(string))
|
||
assert.Equal(t, "REBASE", input["mergeMethod"].(string))
|
||
}))
|
||
http.Register(
|
||
httpmock.REST("DELETE", "repos/OWNER/REPO/git/refs/heads/blueberries"),
|
||
httpmock.StringResponse(`{}`))
|
||
|
||
cs, cmdTeardown := test.InitCmdStubber()
|
||
defer cmdTeardown()
|
||
|
||
cs.Stub("") // git config --get-regexp ^branch\.blueberries\.(remote|merge)$
|
||
cs.Stub("") // git symbolic-ref --quiet --short HEAD
|
||
cs.Stub("") // git checkout master
|
||
cs.Stub("") // git branch -d
|
||
|
||
output, err := RunCommand("pr merge 2 --rebase")
|
||
if err != nil {
|
||
t.Fatalf("error running command `pr merge`: %v", err)
|
||
}
|
||
|
||
r := regexp.MustCompile(`Rebased and merged pull request #2 \(The title of the PR\)`)
|
||
|
||
if !r.MatchString(output.Stderr()) {
|
||
t.Fatalf("output did not match regexp /%s/\n> output\n%q\n", r, output.Stderr())
|
||
}
|
||
}
|
||
|
||
func TestPrMerge_squash(t *testing.T) {
|
||
initBlankContext("", "OWNER/REPO", "master")
|
||
defer stubTerminal(true)()
|
||
http := initFakeHTTP()
|
||
defer http.Verify(t)
|
||
http.StubRepoResponse("OWNER", "REPO")
|
||
http.Register(
|
||
httpmock.GraphQL(`query PullRequestByNumber\b`),
|
||
httpmock.StringResponse(`
|
||
{ "data": { "repository": { "pullRequest": {
|
||
"id": "THE-ID",
|
||
"number": 3,
|
||
"title": "The title of the PR",
|
||
"state": "OPEN",
|
||
"headRefName": "blueberries",
|
||
"headRepositoryOwner": {"login": "OWNER"}
|
||
} } } }`))
|
||
http.Register(
|
||
httpmock.GraphQL(`mutation PullRequestMerge\b`),
|
||
httpmock.GraphQLMutation(`{}`, func(input map[string]interface{}) {
|
||
assert.Equal(t, "THE-ID", input["pullRequestId"].(string))
|
||
assert.Equal(t, "SQUASH", input["mergeMethod"].(string))
|
||
}))
|
||
http.Register(
|
||
httpmock.REST("DELETE", "repos/OWNER/REPO/git/refs/heads/blueberries"),
|
||
httpmock.StringResponse(`{}`))
|
||
|
||
cs, cmdTeardown := test.InitCmdStubber()
|
||
defer cmdTeardown()
|
||
|
||
cs.Stub("") // git config --get-regexp ^branch\.blueberries\.(remote|merge)$
|
||
cs.Stub("") // git symbolic-ref --quiet --short HEAD
|
||
cs.Stub("") // git checkout master
|
||
cs.Stub("") // git branch -d
|
||
|
||
output, err := RunCommand("pr merge 3 --squash")
|
||
if err != nil {
|
||
t.Fatalf("error running command `pr merge`: %v", err)
|
||
}
|
||
|
||
test.ExpectLines(t, output.Stderr(), "Squashed and merged pull request #3", `Deleted branch.*blueberries`)
|
||
}
|
||
|
||
func TestPrMerge_alreadyMerged(t *testing.T) {
|
||
initBlankContext("", "OWNER/REPO", "master")
|
||
defer stubTerminal(true)()
|
||
http := initFakeHTTP()
|
||
defer http.Verify(t)
|
||
http.StubRepoResponse("OWNER", "REPO")
|
||
http.Register(
|
||
httpmock.GraphQL(`query PullRequestByNumber\b`),
|
||
httpmock.StringResponse(`
|
||
{ "data": { "repository": {
|
||
"pullRequest": { "number": 4, "title": "The title of the PR", "state": "MERGED"}
|
||
} } }`))
|
||
|
||
cs, cmdTeardown := test.InitCmdStubber()
|
||
defer cmdTeardown()
|
||
|
||
cs.Stub("") // git config --get-regexp ^branch\.blueberries\.(remote|merge)$
|
||
cs.Stub("") // git symbolic-ref --quiet --short HEAD
|
||
cs.Stub("") // git checkout master
|
||
cs.Stub("") // git branch -d
|
||
|
||
output, err := RunCommand("pr merge 4")
|
||
if err == nil {
|
||
t.Fatalf("expected an error running command `pr merge`: %v", err)
|
||
}
|
||
|
||
r := regexp.MustCompile(`Pull request #4 \(The title of the PR\) was already merged`)
|
||
|
||
if !r.MatchString(err.Error()) {
|
||
t.Fatalf("output did not match regexp /%s/\n> output\n%q\n", r, output.Stderr())
|
||
}
|
||
}
|
||
|
||
func TestPRMerge_interactive(t *testing.T) {
|
||
initBlankContext("", "OWNER/REPO", "blueberries")
|
||
defer stubTerminal(true)()
|
||
http := initFakeHTTP()
|
||
defer http.Verify(t)
|
||
http.StubRepoResponse("OWNER", "REPO")
|
||
http.Register(
|
||
httpmock.GraphQL(`query PullRequestForBranch\b`),
|
||
httpmock.StringResponse(`
|
||
{ "data": { "repository": { "pullRequests": { "nodes": [{
|
||
"headRefName": "blueberries",
|
||
"headRepositoryOwner": {"login": "OWNER"},
|
||
"id": "THE-ID",
|
||
"number": 3
|
||
}] } } } }`))
|
||
http.Register(
|
||
httpmock.GraphQL(`mutation PullRequestMerge\b`),
|
||
httpmock.GraphQLMutation(`{}`, func(input map[string]interface{}) {
|
||
assert.Equal(t, "THE-ID", input["pullRequestId"].(string))
|
||
assert.Equal(t, "MERGE", input["mergeMethod"].(string))
|
||
}))
|
||
http.Register(
|
||
httpmock.REST("DELETE", "repos/OWNER/REPO/git/refs/heads/blueberries"),
|
||
httpmock.StringResponse(`{}`))
|
||
|
||
cs, cmdTeardown := test.InitCmdStubber()
|
||
defer cmdTeardown()
|
||
|
||
cs.Stub("") // git config --get-regexp ^branch\.blueberries\.(remote|merge)$
|
||
cs.Stub("") // git symbolic-ref --quiet --short HEAD
|
||
cs.Stub("") // git checkout master
|
||
cs.Stub("") // git push origin --delete blueberries
|
||
cs.Stub("") // git branch -d
|
||
|
||
as, surveyTeardown := initAskStubber()
|
||
defer surveyTeardown()
|
||
|
||
as.Stub([]*QuestionStub{
|
||
{
|
||
Name: "mergeMethod",
|
||
Value: 0,
|
||
},
|
||
{
|
||
Name: "deleteBranch",
|
||
Value: true,
|
||
},
|
||
})
|
||
|
||
output, err := RunCommand(`pr merge`)
|
||
if err != nil {
|
||
t.Fatalf("Got unexpected error running `pr merge` %s", err)
|
||
}
|
||
|
||
test.ExpectLines(t, output.Stderr(), "Merged pull request #3", `Deleted branch.*blueberries`)
|
||
}
|
||
|
||
func TestPrMerge_multipleMergeMethods(t *testing.T) {
|
||
initBlankContext("", "OWNER/REPO", "master")
|
||
defer stubTerminal(true)()
|
||
|
||
_, err := RunCommand("pr merge 1 --merge --squash")
|
||
if err == nil {
|
||
t.Fatal("expected error running `pr merge` with multiple merge methods")
|
||
}
|
||
}
|
||
|
||
func TestPrMerge_multipleMergeMethods_nontty(t *testing.T) {
|
||
initBlankContext("", "OWNER/REPO", "master")
|
||
defer stubTerminal(false)()
|
||
|
||
_, err := RunCommand("pr merge 1 --merge --squash")
|
||
if err == nil {
|
||
t.Fatal("expected error running `pr merge` with multiple merge methods")
|
||
}
|
||
}
|
||
|
||
func TestPRReady(t *testing.T) {
|
||
initBlankContext("", "OWNER/REPO", "master")
|
||
http := initFakeHTTP()
|
||
http.StubRepoResponse("OWNER", "REPO")
|
||
http.StubResponse(200, bytes.NewBufferString(`
|
||
{ "data": { "repository": {
|
||
"pullRequest": { "number": 444, "closed": false, "isDraft": true}
|
||
} } }
|
||
`))
|
||
http.StubResponse(200, bytes.NewBufferString(`{"id": "THE-ID"}`))
|
||
|
||
output, err := RunCommand("pr ready 444")
|
||
if err != nil {
|
||
t.Fatalf("error running command `pr ready`: %v", err)
|
||
}
|
||
|
||
r := regexp.MustCompile(`Pull request #444 is marked as "ready for review"`)
|
||
|
||
if !r.MatchString(output.Stderr()) {
|
||
t.Fatalf("output did not match regexp /%s/\n> output\n%q\n", r, output.Stderr())
|
||
}
|
||
}
|
||
|
||
func TestPRReady_alreadyReady(t *testing.T) {
|
||
initBlankContext("", "OWNER/REPO", "master")
|
||
http := initFakeHTTP()
|
||
http.StubRepoResponse("OWNER", "REPO")
|
||
http.StubResponse(200, bytes.NewBufferString(`
|
||
{ "data": { "repository": {
|
||
"pullRequest": { "number": 445, "closed": false, "isDraft": false}
|
||
} } }
|
||
`))
|
||
http.StubResponse(200, bytes.NewBufferString(`{"id": "THE-ID"}`))
|
||
|
||
output, err := RunCommand("pr ready 445")
|
||
if err != nil {
|
||
t.Fatalf("error running command `pr ready`: %v", err)
|
||
}
|
||
|
||
r := regexp.MustCompile(`Pull request #445 is already "ready for review"`)
|
||
|
||
if !r.MatchString(output.Stderr()) {
|
||
t.Fatalf("output did not match regexp /%s/\n> output\n%q\n", r, output.Stderr())
|
||
}
|
||
}
|
||
|
||
func TestPRReady_closed(t *testing.T) {
|
||
initBlankContext("", "OWNER/REPO", "master")
|
||
http := initFakeHTTP()
|
||
http.StubRepoResponse("OWNER", "REPO")
|
||
http.StubResponse(200, bytes.NewBufferString(`
|
||
{ "data": { "repository": {
|
||
"pullRequest": { "number": 446, "closed": true, "isDraft": true}
|
||
} } }
|
||
`))
|
||
http.StubResponse(200, bytes.NewBufferString(`{"id": "THE-ID"}`))
|
||
|
||
_, err := RunCommand("pr ready 446")
|
||
if err == nil {
|
||
t.Fatalf("expected an error running command `pr ready` on a review that is closed!: %v", err)
|
||
}
|
||
|
||
r := regexp.MustCompile(`Pull request #446 is closed. Only draft pull requests can be marked as "ready for review"`)
|
||
|
||
if !r.MatchString(err.Error()) {
|
||
t.Fatalf("output did not match regexp /%s/\n> output\n%q\n", r, err.Error())
|
||
}
|
||
}
|