pr merge: print instructions for merge conflicts (#5330)

Co-authored-by: Sam Coe <samcoe@users.noreply.github.com>
Co-authored-by: Mislav Marohnić <mislav@github.com>
This commit is contained in:
Kiran Adhikari 2022-04-13 16:13:05 +05:45 committed by GitHub
parent 8f046e0b77
commit 4f7c88ea4e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 65 additions and 2 deletions

View file

@ -11,6 +11,7 @@ import (
"github.com/cli/cli/v2/context"
"github.com/cli/cli/v2/git"
"github.com/cli/cli/v2/internal/config"
"github.com/cli/cli/v2/internal/ghrepo"
"github.com/cli/cli/v2/pkg/cmd/pr/shared"
"github.com/cli/cli/v2/pkg/cmdutil"
"github.com/cli/cli/v2/pkg/iostreams"
@ -72,7 +73,7 @@ func NewCmdMerge(f *cmdutil.Factory, runF func(*MergeOptions) error) *cobra.Comm
Merge a pull request on GitHub.
Without an argument, the pull request that belongs to the current branch
is selected.
is selected.
`),
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
@ -130,6 +131,7 @@ func NewCmdMerge(f *cmdutil.Factory, runF func(*MergeOptions) error) *cobra.Comm
); err != nil {
return err
}
if bodyProvided || bodyFileProvided {
opts.BodySet = true
if bodyFileProvided {
@ -139,7 +141,6 @@ func NewCmdMerge(f *cmdutil.Factory, runF func(*MergeOptions) error) *cobra.Comm
}
opts.Body = string(b)
}
}
opts.Editor = &userEditor{
@ -211,6 +212,16 @@ func mergeRun(opts *MergeOptions) error {
if reason := blockedReason(pr.MergeStateStatus, opts.UseAdmin); !opts.AutoMergeEnable && !isPRAlreadyMerged && reason != "" {
fmt.Fprintf(opts.IO.ErrOut, "%s Pull request #%d is not mergeable: %s.\n", cs.FailureIcon(), pr.Number, reason)
fmt.Fprintf(opts.IO.ErrOut, "To have the pull request merged after all the requirements have been met, add the `--auto` flag.\n")
if remote := remoteForMergeConflictResolution(baseRepo, pr, opts); remote != nil {
mergeOrRebase := "merge"
if opts.MergeMethod == PullRequestMergeMethodRebase {
mergeOrRebase = "rebase"
}
fetchBranch := fmt.Sprintf("%s %s", remote.Name, pr.BaseRefName)
mergeBranch := fmt.Sprintf("%s %s/%s", mergeOrRebase, remote.Name, pr.BaseRefName)
cmd := fmt.Sprintf("gh pr checkout %d && git fetch %s && git %s", pr.Number, fetchBranch, mergeBranch)
fmt.Fprintf(opts.IO.ErrOut, "Run the following to resolve the merge conflicts locally:\n %s\n", cs.Bold(cmd))
}
if !opts.UseAdmin && allowsAdminOverride(pr.MergeStateStatus) {
// TODO: show this flag only to repo admins
fmt.Fprintf(opts.IO.ErrOut, "To use administrator privileges to immediately merge the pull request, add the `--admin` flag.\n")
@ -562,6 +573,25 @@ func allowsAdminOverride(status string) bool {
}
}
func remoteForMergeConflictResolution(baseRepo ghrepo.Interface, pr *api.PullRequest, opts *MergeOptions) *context.Remote {
if !mergeConflictStatus(pr.MergeStateStatus) || !opts.CanDeleteLocalBranch {
return nil
}
remotes, err := opts.Remotes()
if err != nil {
return nil
}
remote, err := remotes.FindByRepo(baseRepo.RepoOwner(), baseRepo.RepoName())
if err != nil {
return nil
}
return remote
}
func mergeConflictStatus(status string) bool {
return status == "DIRTY"
}
func isImmediatelyMergeable(status string) bool {
switch status {
case "CLEAN", "HAS_HOOKS", "UNSTABLE":

View file

@ -333,6 +333,39 @@ func TestPrMerge_blocked(t *testing.T) {
`, "`"), output.Stderr())
}
func TestPrMerge_dirty(t *testing.T) {
http := initFakeHTTP()
defer http.Verify(t)
shared.RunCommandFinder(
"1",
&api.PullRequest{
ID: "THE-ID",
Number: 123,
State: "OPEN",
Title: "The title of the PR",
MergeStateStatus: "DIRTY",
BaseRefName: "trunk",
HeadRefName: "feature",
},
baseRepo("OWNER", "REPO", "master"),
)
_, cmdTeardown := run.Stub()
defer cmdTeardown(t)
output, err := runCommand(http, "master", true, "pr merge 1 --merge")
assert.EqualError(t, err, "SilentError")
assert.Equal(t, "", output.String())
assert.Equal(t, heredoc.Docf(`
X Pull request #123 is not mergeable: the merge commit cannot be cleanly created.
To have the pull request merged after all the requirements have been met, add the %[1]s--auto%[1]s flag.
Run the following to resolve the merge conflicts locally:
gh pr checkout 123 && git fetch origin trunk && git merge origin/trunk
`, "`"), output.Stderr())
}
func TestPrMerge_nontty(t *testing.T) {
http := initFakeHTTP()
defer http.Verify(t)