From 1749d2f7f60633d8520a2495459f8fdac2740abd Mon Sep 17 00:00:00 2001 From: bircni Date: Sun, 11 Oct 2026 23:15:43 +0200 Subject: [PATCH] fix(issue): show merged pull requests as merged in issue lists and search issue list --kind all, milestone issue list and search pr reported a merged pull request as closed. Their state is now merged, in tables and in JSON, which also tells issues and pull requests apart by kind. Signed-off-by: bircni --- internal/services/issues.go | 13 +++++++++++-- internal/services/issues_test.go | 19 +++++++++++++++++++ internal/services/search.go | 2 +- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/internal/services/issues.go b/internal/services/issues.go index f5769567..8c66956d 100644 --- a/internal/services/issues.go +++ b/internal/services/issues.go @@ -39,16 +39,25 @@ const ( KindPull = "pull" ) -// discussionFrom converts an issue or a pull request listed among issues. +// discussionFrom converts an issue or a pull request listed among issues; the state of a merged +// pull request is "merged" rather than "closed". func discussionFrom(issue *gitea.Issue) Issue { item := issueFrom(issue) - item.Kind = KindIssue + item.Kind, item.State = KindIssue, discussionState(issue) if issue.PullRequest != nil { item.Kind = KindPull } return item } +// discussionState is the state of an issue, or "merged" for a merged pull request. +func discussionState(issue *gitea.Issue) string { + if issue.PullRequest != nil && issue.PullRequest.HasMerged { + return "merged" + } + return string(issue.State) +} + // IssueMilestone identifies the milestone associated with an issue or pull request. type IssueMilestone struct { ID int64 `json:"id"` diff --git a/internal/services/issues_test.go b/internal/services/issues_test.go index 94b5b550..a4d907cd 100644 --- a/internal/services/issues_test.go +++ b/internal/services/issues_test.go @@ -77,6 +77,25 @@ func TestIssueDependenciesMapReferencesAndTreatMissingSupportAsNone(t *testing.T require.Equal(t, IssueDependencies{}, dependencies) } +func TestDiscussionsTellPullRequestsAndMergesApart(t *testing.T) { + list := `[{"number":1,"state":"open"},{"number":2,"state":"closed","pull_request":{"merged":false}},` + + `{"number":3,"state":"closed","pull_request":{"merged":true}},{"number":4,"state":"open","pull_request":{"merged":false}}]` + client := newTestClient(t, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + _, _ = w.Write([]byte(list)) + })) + want := []struct{ kind, state string }{{KindIssue, "open"}, {KindPull, "closed"}, {KindPull, "merged"}, {KindPull, "open"}} + issues, _, err := (Issues{Client: client, Repository: "alice/project"}).List(context.Background(), ListOptions{Kind: "all", State: "all", Limit: 30, Page: 1}) + require.NoError(t, err) + found, err := (Issues{Client: client, Repository: "alice/project"}).Search(context.Background(), DiscussionSearchOptions{State: "all", Limit: 30, Page: 1}) + require.NoError(t, err) + require.Len(t, issues, len(want)) + for i, item := range want { + require.Equal(t, item.kind, issues[i].Kind, issues[i].Number) + require.Equal(t, item.state, issues[i].State, issues[i].Number) + require.Equal(t, item.state, found[i].State, found[i].Number) + } +} + func TestIssueTemplatesAcceptCheckboxOptionObjects(t *testing.T) { body := `[{"name":"Form","body":[{"type":"checkboxes","attributes":{"options":[{"label":"I searched","required":true}]}}]}]` client := newTestClient(t, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { diff --git a/internal/services/search.go b/internal/services/search.go index 60901c17..8b6cbc1c 100644 --- a/internal/services/search.go +++ b/internal/services/search.go @@ -60,7 +60,7 @@ func (s Issues) Search(ctx context.Context, opts DiscussionSearchOptions) ([]Sea repository = issue.Repository.FullName } return SearchItem{ - ID: issue.ID, Number: issue.Index, Title: issue.Title, Body: issue.Body, URL: issue.HTMLURL, State: string(issue.State), + ID: issue.ID, Number: issue.Index, Title: issue.Title, Body: issue.Body, URL: issue.HTMLURL, State: discussionState(issue), Type: resultType, Repository: repository, CreatedAt: timestamp(issue.Created), UpdatedAt: timestamp(issue.Updated), } }), nil