From 69f3d3f25d6acee1325a6052f6e5d88596a69151 Mon Sep 17 00:00:00 2001 From: Justin Willhite <5132924+thejdubb02@users.noreply.github.com> Date: Mon, 7 Sep 2026 22:14:33 +0000 Subject: [PATCH] Include merge_commit_sha in the minimal pull request result pull_request_read (method get) and list_pull_requests return a trimmed MinimalPullRequest built by convertToMinimalPullRequest, which had no merge_commit_sha field, so a merged pull request gave no way to reach the commit the merge produced without a second call (#3235). Add MergeCommitSHA to MinimalPullRequest and populate it, but only once the PR is merged. An open PR's merge_commit_sha is GitHub's ephemeral test-merge ref (refs/pull/N/merge), not a commit on the base branch, so gating on the merged signal (merged_at present, or merged) avoids handing that back as if it were the merge commit. Add merge_commit_sha to listPullRequestsItemFieldEnum so list_pull_requests can select it, and regenerate that tool's snapshot. Add a converter unit test asserting the field is emitted for a merged PR and withheld for an open or closed-unmerged one. --- .../__toolsnaps__/list_pull_requests.snap | 1 + pkg/github/minimal_types.go | 8 +++- pkg/github/pullrequests_test.go | 44 +++++++++++++++++++ 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/pkg/github/__toolsnaps__/list_pull_requests.snap b/pkg/github/__toolsnaps__/list_pull_requests.snap index d37986d529..18a0061e68 100644 --- a/pkg/github/__toolsnaps__/list_pull_requests.snap +++ b/pkg/github/__toolsnaps__/list_pull_requests.snap @@ -29,6 +29,7 @@ "state", "draft", "merged", + "merge_commit_sha", "mergeable_state", "html_url", "user", diff --git a/pkg/github/minimal_types.go b/pkg/github/minimal_types.go index 2eba9a1628..71826a6d9b 100644 --- a/pkg/github/minimal_types.go +++ b/pkg/github/minimal_types.go @@ -45,7 +45,7 @@ var listIssuesItemFieldEnum = []any{ // MinimalPullRequest. The body field is the heaviest, so omitting it is the main // lever for shrinking large result sets. var listPullRequestsItemFieldEnum = []any{ - "number", "title", "body", "state", "draft", "merged", "mergeable_state", + "number", "title", "body", "state", "draft", "merged", "merge_commit_sha", "mergeable_state", "html_url", "user", "labels", "assignees", "requested_reviewers", "merged_by", "head", "base", "additions", "deletions", "changed_files", "commits", "comments", "created_at", "updated_at", "closed_at", "merged_at", "milestone", @@ -717,6 +717,7 @@ type MinimalPullRequest struct { State string `json:"state"` Draft bool `json:"draft"` Merged bool `json:"merged"` + MergeCommitSHA string `json:"merge_commit_sha,omitempty"` MergeableState string `json:"mergeable_state,omitempty"` HTMLURL string `json:"html_url"` User *MinimalUser `json:"user,omitempty"` @@ -1111,6 +1112,11 @@ func convertToMinimalPullRequest(pr *github.PullRequest) MinimalPullRequest { if pr.MergedAt != nil { m.MergedAt = pr.MergedAt.Format(time.RFC3339) } + // merge_commit_sha is a real base-branch commit only once merged; an open PR's + // is an ephemeral test-merge ref, so omit it there (#3235). + if pr.GetMerged() || pr.MergedAt != nil { + m.MergeCommitSHA = pr.GetMergeCommitSHA() + } for _, label := range pr.Labels { if label != nil { diff --git a/pkg/github/pullrequests_test.go b/pkg/github/pullrequests_test.go index c0e392aea6..d5c414e27a 100644 --- a/pkg/github/pullrequests_test.go +++ b/pkg/github/pullrequests_test.go @@ -180,6 +180,50 @@ func Test_GetPullRequest(t *testing.T) { } } +// Test_convertToMinimalPullRequestMergeCommitSHA pins that merge_commit_sha is +// emitted only once a PR is merged, not for an open PR's ephemeral test-merge +// ref (#3235). +func Test_convertToMinimalPullRequestMergeCommitSHA(t *testing.T) { + const sha = "f1e2d3c4b5a6978012345678901234567890abcd" + tests := []struct { + name string + pr *github.PullRequest + want string + }{ + { + name: "merged PR exposes the merge commit", + pr: &github.PullRequest{ + State: github.Ptr("closed"), + Merged: github.Ptr(true), + MergedAt: &github.Timestamp{Time: time.Now()}, + MergeCommitSHA: github.Ptr(sha), + }, + want: sha, + }, + { + name: "open PR withholds the ephemeral test-merge SHA", + pr: &github.PullRequest{ + State: github.Ptr("open"), + MergeCommitSHA: github.Ptr(sha), + }, + want: "", + }, + { + name: "closed-unmerged PR withholds any test-merge SHA", + pr: &github.PullRequest{ + State: github.Ptr("closed"), + MergeCommitSHA: github.Ptr(sha), + }, + want: "", + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + assert.Equal(t, tc.want, convertToMinimalPullRequest(tc.pr).MergeCommitSHA) + }) + } +} + func Test_UpdatePullRequest(t *testing.T) { // Verify tool definition once serverTool := UpdatePullRequest(translations.NullTranslationHelper)