fix: show purple merged icon for recently merged PRs (#1483)

GitHub's /search/issues API returns merged PRs with state "closed" and a
non-empty pull_request.merged_at, so the my-github search list rendered them
with the red closed icon while the detail view (which checks merged_at) showed
the correct purple merged icon.

Plumb pull_request.merged_at through both the gh CLI and PAT search converters
and promote those PRs to the "merged" state.
This commit is contained in:
José Almeida
2026-06-24 11:03:49 +01:00
committed by GitHub
parent 4d19fb32f1
commit 23345c75d7
4 changed files with 43 additions and 9 deletions
@@ -399,11 +399,17 @@ func isNewerCheck(a, b CheckRun) bool {
}
// convertSearchItemToPR converts common search result fields into a PR struct.
// GitHub's /search/issues API returns merged PRs with state "closed" and a
// non-empty pull_request.merged_at; promote those to the "merged" state so the
// UI renders the purple merged icon instead of the red closed one.
func convertSearchItemToPR(
number int, title, htmlURL, state, authorLogin, repositoryURL string,
number int, title, htmlURL, state, authorLogin, repositoryURL, mergedAt string,
draft bool, createdAt, updatedAt time.Time,
) *PR {
owner, repo := parseRepoURL(repositoryURL)
if mergedAt != "" {
state = prStateMerged
}
return &PR{
Number: number,
Title: title,
@@ -415,6 +421,7 @@ func convertSearchItemToPR(
RepoName: repo,
CreatedAt: createdAt,
UpdatedAt: updatedAt,
MergedAt: parseTimePtr(mergedAt),
}
}
@@ -322,7 +322,7 @@ func TestConvertSearchItemToPR(t *testing.T) {
now := time.Now()
pr := convertSearchItemToPR(
42, "Fix bug", "https://github.com/owner/repo/pull/42", "open",
"alice", "https://api.github.com/repos/myorg/myrepo", false,
"alice", "https://api.github.com/repos/myorg/myrepo", "", false,
now, now,
)
@@ -338,6 +338,29 @@ func TestConvertSearchItemToPR(t *testing.T) {
if pr.RepoName != "myrepo" {
t.Errorf("expected repo myrepo, got %s", pr.RepoName)
}
if pr.State != "open" {
t.Errorf("expected state open, got %s", pr.State)
}
}
// GitHub's search API returns merged PRs with state "closed" plus a non-empty
// pull_request.merged_at. The converter must promote those to "merged" so the
// UI shows the purple merged icon instead of the red closed one.
func TestConvertSearchItemToPRMerged(t *testing.T) {
now := time.Now()
mergedAt := "2025-01-02T03:04:05Z"
pr := convertSearchItemToPR(
7, "Land feature", "https://github.com/owner/repo/pull/7", "closed",
"bob", "https://api.github.com/repos/myorg/myrepo", mergedAt, false,
now, now,
)
if pr.State != prStateMerged {
t.Errorf("expected state %q, got %q", prStateMerged, pr.State)
}
if pr.MergedAt == nil {
t.Fatal("expected MergedAt to be set, got nil")
}
}
func TestLatestReviewByAuthor(t *testing.T) {
+4 -3
View File
@@ -1049,7 +1049,8 @@ type ghSearchItem struct {
Login string `json:"login"`
} `json:"user"`
PullRequest struct {
URL string `json:"url"`
URL string `json:"url"`
MergedAt string `json:"merged_at"`
} `json:"pull_request"`
RepositoryURL string `json:"repository_url"`
}
@@ -1063,8 +1064,8 @@ func (c *GHClient) parseSearchResults(data string) ([]*PR, error) {
for i, item := range items {
prs[i] = convertSearchItemToPR(
item.Number, item.Title, item.HTMLURL, item.State,
item.User.Login, item.RepositoryURL, item.Draft,
item.CreatedAt, item.UpdatedAt,
item.User.Login, item.RepositoryURL, item.PullRequest.MergedAt,
item.Draft, item.CreatedAt, item.UpdatedAt,
)
}
return prs, nil
+7 -4
View File
@@ -222,8 +222,8 @@ func (c *PATClient) ListReviewRequestedPRs(ctx context.Context, scope, filter, c
for i, item := range result.Items {
prs[i] = convertSearchItemToPR(
item.Number, item.Title, item.HTMLURL, item.State,
item.User.Login, item.RepositoryURL, item.Draft,
item.CreatedAt, item.UpdatedAt,
item.User.Login, item.RepositoryURL, item.PullRequest.MergedAt,
item.Draft, item.CreatedAt, item.UpdatedAt,
)
}
return prs, nil
@@ -253,8 +253,8 @@ func (c *PATClient) SearchPRsPaged(ctx context.Context, filter, customQuery stri
for i, item := range result.Items {
prs[i] = convertSearchItemToPR(
item.Number, item.Title, item.HTMLURL, item.State,
item.User.Login, item.RepositoryURL, item.Draft,
item.CreatedAt, item.UpdatedAt,
item.User.Login, item.RepositoryURL, item.PullRequest.MergedAt,
item.Draft, item.CreatedAt, item.UpdatedAt,
)
}
return &PRSearchPage{PRs: prs, TotalCount: result.TotalCount, Page: page, PerPage: perPage}, nil
@@ -946,6 +946,9 @@ type patSearchItem struct {
User struct {
Login string `json:"login"`
} `json:"user"`
PullRequest struct {
MergedAt string `json:"merged_at"`
} `json:"pull_request"`
}
func convertPatPR(raw *patPR, owner, repo string) *PR {