X Tutup
Skip to content

Commit be5fc07

Browse files
Merge pull request cli#899 from cli/merge-interactive-merge
Interactive merge
2 parents 9ebeb5f + d7c933b commit be5fc07

File tree

6 files changed

+316
-18
lines changed

6 files changed

+316
-18
lines changed

api/queries_pr.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ type PullRequest struct {
4848
BaseRefName string
4949
HeadRefName string
5050
Body string
51+
Mergeable string
5152

5253
Author struct {
5354
Login string
@@ -264,6 +265,7 @@ func PullRequests(client *Client, repo ghrepo.Interface, currentPRNumber int, cu
264265
state
265266
url
266267
headRefName
268+
mergeable
267269
headRepositoryOwner {
268270
login
269271
}
@@ -418,6 +420,7 @@ func PullRequestByNumber(client *Client, repo ghrepo.Interface, number int) (*Pu
418420
state
419421
closed
420422
body
423+
mergeable
421424
author {
422425
login
423426
}
@@ -526,6 +529,7 @@ func PullRequestForBranch(client *Client, repo ghrepo.Interface, baseBranch, hea
526529
title
527530
state
528531
body
532+
mergeable
529533
author {
530534
login
531535
}

api/queries_repo.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ func GitHubRepo(client *Client, repo ghrepo.Interface) (*Repository, error) {
8484
hasIssuesEnabled
8585
description
8686
viewerPermission
87+
defaultBranchRef {
88+
name
89+
}
8790
}
8891
}`
8992
variables := map[string]interface{}{

command/pr.go

Lines changed: 131 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
package command
22

33
import (
4+
"errors"
45
"fmt"
56
"io"
67
"regexp"
78
"sort"
89
"strconv"
910
"strings"
1011

12+
"github.com/AlecAivazis/survey/v2"
1113
"github.com/cli/cli/api"
1214
"github.com/cli/cli/context"
1315
"github.com/cli/cli/git"
@@ -26,7 +28,8 @@ func init() {
2628
prCmd.AddCommand(prCloseCmd)
2729
prCmd.AddCommand(prReopenCmd)
2830
prCmd.AddCommand(prMergeCmd)
29-
prMergeCmd.Flags().BoolP("merge", "m", true, "Merge the commits with the base branch")
31+
prMergeCmd.Flags().BoolP("delete-branch", "d", true, "Delete the local branch after merge")
32+
prMergeCmd.Flags().BoolP("merge", "m", false, "Merge the commits with the base branch")
3033
prMergeCmd.Flags().BoolP("rebase", "r", false, "Rebase the commits onto the base branch")
3134
prMergeCmd.Flags().BoolP("squash", "s", false, "Squash the commits into one commit and merge it into the base branch")
3235
prCmd.AddCommand(prReadyCmd)
@@ -451,7 +454,15 @@ func prMerge(cmd *cobra.Command, args []string) error {
451454

452455
var pr *api.PullRequest
453456
if len(args) > 0 {
454-
pr, err = prFromArg(apiClient, baseRepo, args[0])
457+
var prNumber string
458+
n, _ := prFromURL(args[0])
459+
if n != "" {
460+
prNumber = n
461+
} else {
462+
prNumber = args[0]
463+
}
464+
465+
pr, err = prFromArg(apiClient, baseRepo, prNumber)
455466
if err != nil {
456467
return err
457468
}
@@ -471,41 +482,146 @@ func prMerge(cmd *cobra.Command, args []string) error {
471482
}
472483
}
473484

474-
if pr.State == "MERGED" {
485+
if pr.Mergeable == "CONFLICTING" {
486+
err := fmt.Errorf("%s Pull request #%d has conflicts and isn't mergeable ", utils.Red("!"), pr.Number)
487+
return err
488+
} else if pr.Mergeable == "UNKNOWN" {
489+
err := fmt.Errorf("%s Pull request #%d can't be merged right now; try again in a few seconds", utils.Red("!"), pr.Number)
490+
return err
491+
} else if pr.State == "MERGED" {
475492
err := fmt.Errorf("%s Pull request #%d was already merged", utils.Red("!"), pr.Number)
476493
return err
477494
}
478495

479-
rebase, err := cmd.Flags().GetBool("rebase")
496+
var mergeMethod api.PullRequestMergeMethod
497+
deleteBranch, err := cmd.Flags().GetBool("delete-branch")
480498
if err != nil {
481499
return err
482500
}
483-
squash, err := cmd.Flags().GetBool("squash")
484-
if err != nil {
485-
return err
501+
502+
// Ensure only one merge method is specified
503+
enabledFlagCount := 0
504+
isInteractive := false
505+
if b, _ := cmd.Flags().GetBool("merge"); b {
506+
enabledFlagCount++
507+
mergeMethod = api.PullRequestMergeMethodMerge
508+
}
509+
if b, _ := cmd.Flags().GetBool("rebase"); b {
510+
enabledFlagCount++
511+
mergeMethod = api.PullRequestMergeMethodRebase
512+
}
513+
if b, _ := cmd.Flags().GetBool("squash"); b {
514+
enabledFlagCount++
515+
mergeMethod = api.PullRequestMergeMethodSquash
516+
}
517+
518+
if enabledFlagCount == 0 {
519+
isInteractive = true
520+
} else if enabledFlagCount > 1 {
521+
return errors.New("expected exactly one of --merge, --rebase, or --squash to be true")
522+
}
523+
524+
if isInteractive {
525+
mergeMethod, deleteBranch, err = prInteractiveMerge()
526+
if err != nil {
527+
return nil
528+
}
486529
}
487530

488-
var output string
489-
if rebase {
490-
output = fmt.Sprintf("%s Rebased and merged pull request #%d\n", utils.Green("✔"), pr.Number)
531+
var action string
532+
if mergeMethod == api.PullRequestMergeMethodRebase {
533+
action = "Rebased and merged"
491534
err = api.PullRequestMerge(apiClient, baseRepo, pr, api.PullRequestMergeMethodRebase)
492-
} else if squash {
493-
output = fmt.Sprintf("%s Squashed and merged pull request #%d\n", utils.Green("✔"), pr.Number)
535+
} else if mergeMethod == api.PullRequestMergeMethodSquash {
536+
action = "Squashed and merged"
494537
err = api.PullRequestMerge(apiClient, baseRepo, pr, api.PullRequestMergeMethodSquash)
495-
} else {
496-
output = fmt.Sprintf("%s Merged pull request #%d\n", utils.Green("✔"), pr.Number)
538+
} else if mergeMethod == api.PullRequestMergeMethodMerge {
539+
action = "Merged"
497540
err = api.PullRequestMerge(apiClient, baseRepo, pr, api.PullRequestMergeMethodMerge)
541+
} else {
542+
err = fmt.Errorf("unknown merge method (%d) used", mergeMethod)
543+
return err
498544
}
499545

500546
if err != nil {
501547
return fmt.Errorf("API call failed: %w", err)
502548
}
503549

504-
fmt.Fprint(colorableOut(cmd), output)
550+
fmt.Fprintf(colorableOut(cmd), "%s %s pull request #%d\n", utils.Magenta("✔"), action, pr.Number)
551+
552+
if deleteBranch && !cmd.Flags().Changed("repo") {
553+
repo, err := api.GitHubRepo(apiClient, baseRepo)
554+
if err != nil {
555+
return err
556+
}
557+
558+
currentBranch, err := ctx.Branch()
559+
if err != nil {
560+
return err
561+
}
562+
563+
if currentBranch == pr.HeadRefName {
564+
err = git.CheckoutBranch(repo.DefaultBranchRef.Name)
565+
if err != nil {
566+
return err
567+
}
568+
}
569+
570+
err = git.DeleteLocalBranch(pr.HeadRefName)
571+
if err != nil {
572+
fmt.Fprintf(colorableErr(cmd), "%s Could not delete local branch %s: %s\n", utils.Red("!"), utils.Cyan(pr.HeadRefName), err)
573+
return err
574+
}
575+
fmt.Fprintf(colorableOut(cmd), "%s Deleted local branch %s\n", utils.Red("✔"), utils.Cyan(pr.HeadRefName))
576+
}
505577

506578
return nil
507579
}
508580

581+
func prInteractiveMerge() (api.PullRequestMergeMethod, bool, error) {
582+
mergeMethodQuestion := &survey.Question{
583+
Name: "mergeMethod",
584+
Prompt: &survey.Select{
585+
Message: "What merge method would you like to use?",
586+
Options: []string{"Create a merge commit", "Rebase and merge", "Squash and merge"},
587+
Default: "Create a merge commit",
588+
},
589+
}
590+
591+
deleteBranchQuestion := &survey.Question{
592+
Name: "deleteBranch",
593+
Prompt: &survey.Confirm{
594+
Message: "Delete the branch locally?",
595+
Default: true,
596+
},
597+
}
598+
599+
qs := []*survey.Question{mergeMethodQuestion, deleteBranchQuestion}
600+
601+
answers := struct {
602+
MergeMethod int
603+
DeleteBranch bool
604+
}{}
605+
606+
err := SurveyAsk(qs, &answers)
607+
if err != nil {
608+
return 0, false, fmt.Errorf("could not prompt: %w", err)
609+
}
610+
611+
var mergeMethod api.PullRequestMergeMethod
612+
switch answers.MergeMethod {
613+
case 0:
614+
mergeMethod = api.PullRequestMergeMethodMerge
615+
case 1:
616+
mergeMethod = api.PullRequestMergeMethodRebase
617+
case 2:
618+
mergeMethod = api.PullRequestMergeMethodSquash
619+
}
620+
621+
deleteBranch := answers.DeleteBranch
622+
return mergeMethod, deleteBranch, nil
623+
}
624+
509625
func printPrPreview(out io.Writer, pr *api.PullRequest) error {
510626
// Header (Title and State)
511627
fmt.Fprintln(out, utils.Bold(pr.Title))

0 commit comments

Comments
 (0)
X Tutup