Skip to content

Commit 8a3b59b

Browse files
committed
fix: refactor existing PR message format when calling create_pull_request
1 parent eb088df commit 8a3b59b

1 file changed

Lines changed: 59 additions & 0 deletions

File tree

pkg/github/pullrequests.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"fmt"
77
"io"
88
"net/http"
9+
"strings"
910

1011
"github.com/go-viper/mapstructure/v2"
1112
"github.com/google/go-github/v89/github"
@@ -647,6 +648,45 @@ var pullRequestUpdateFormParams = map[string]struct{}{
647648
"_ui_submitted": {},
648649
}
649650

651+
// findExistingPullRequest checks whether the Create error was GitHub's
652+
// "a pull request already exists" 422, and if so, looks up and returns
653+
// that existing PR so callers can surface a useful link instead of the
654+
// raw validation error.
655+
func findExistingPullRequest(ctx context.Context, client *github.Client, owner, repo, head, base string, createErr error) (*github.PullRequest, error) {
656+
ghErr, ok := createErr.(*github.ErrorResponse)
657+
if !ok {
658+
return nil, fmt.Errorf("not a github.ErrorResponse")
659+
}
660+
661+
matched := false
662+
for _, e := range ghErr.Errors {
663+
if e.Code == "custom" && strings.Contains(e.Message, "A pull request already exists") {
664+
matched = true
665+
break
666+
}
667+
}
668+
if !matched {
669+
return nil, fmt.Errorf("error is not an 'already exists' validation failure")
670+
}
671+
672+
// head may or may not already be qualified with an owner (fork case);
673+
// the List API wants "owner:branch" form.
674+
headFilter := head
675+
if !strings.Contains(head, ":") {
676+
headFilter = fmt.Sprintf("%s:%s", owner, head)
677+
}
678+
679+
prs, _, err := client.PullRequests.List(ctx, owner, repo, &github.PullRequestListOptions{
680+
Head: headFilter,
681+
Base: base,
682+
State: "all",
683+
})
684+
if err != nil || len(prs) == 0 {
685+
return nil, fmt.Errorf("could not find existing pull request: %w", err)
686+
}
687+
return prs[0], nil
688+
}
689+
650690
// CreatePullRequest creates a tool to create a new pull request.
651691
func CreatePullRequest(t translations.TranslationHelperFunc) inventory.ServerTool {
652692
return NewTool(
@@ -796,6 +836,25 @@ func CreatePullRequest(t translations.TranslationHelperFunc) inventory.ServerToo
796836
}
797837
pr, resp, err := client.PullRequests.Create(ctx, owner, repo, newPR)
798838
if err != nil {
839+
if existingPR, findErr := findExistingPullRequest(ctx, client, owner, repo, head, base, err); findErr == nil && existingPR != nil {
840+
minimalResponse := MinimalResponse{
841+
ID: fmt.Sprintf("%d", existingPR.GetID()),
842+
URL: existingPR.GetHTMLURL(),
843+
}
844+
r, marshalErr := json.Marshal(struct {
845+
MinimalResponse
846+
Message string `json:"message"`
847+
}{
848+
MinimalResponse: minimalResponse,
849+
Message: fmt.Sprintf(
850+
"An open pull request already exists for %q into %q: #%d, titled %q at %s",
851+
head, base, existingPR.GetNumber(), existingPR.GetTitle(), existingPR.GetHTMLURL(),
852+
),
853+
})
854+
if marshalErr == nil {
855+
return utils.NewToolResultText(string(r)), nil, nil
856+
}
857+
}
799858
return ghErrors.NewGitHubAPIErrorResponse(ctx,
800859
"failed to create pull request",
801860
resp,

0 commit comments

Comments
 (0)