44package release
55
66import (
7+ "cmp"
78 "context"
89 "fmt"
9- "sort "
10+ "slices "
1011 "strings"
1112
12- "code.gitea.io/gitea/models/db"
1313 issues_model "code.gitea.io/gitea/models/issues"
1414 repo_model "code.gitea.io/gitea/models/repo"
1515 user_model "code.gitea.io/gitea/models/user"
@@ -44,6 +44,10 @@ func (err ErrReleaseNotesTagNotFound) Unwrap() error {
4444 return util .ErrNotExist
4545}
4646
47+ func newErrReleaseNotesTagNotFound (tagName string ) error {
48+ return util .ErrorWrapTranslatable (ErrReleaseNotesTagNotFound {TagName : tagName }, "repo.release.generate_notes_tag_not_found" , tagName )
49+ }
50+
4751// ErrReleaseNotesNoBaseTag indicates there is no tag to diff against.
4852type ErrReleaseNotesNoBaseTag struct {}
4953
@@ -55,12 +59,6 @@ func (err ErrReleaseNotesNoBaseTag) Unwrap() error {
5559 return util .ErrNotExist
5660}
5761
58- // IsErrReleaseNotesNoBaseTag reports whether the error is ErrReleaseNotesNoBaseTag.
59- func IsErrReleaseNotesNoBaseTag (err error ) bool {
60- _ , ok := err .(ErrReleaseNotesNoBaseTag )
61- return ok
62- }
63-
6462// ErrReleaseNotesTargetNotFound indicates the release target ref cannot be resolved.
6563type ErrReleaseNotesTargetNotFound struct {
6664 Ref string
@@ -74,6 +72,10 @@ func (err ErrReleaseNotesTargetNotFound) Unwrap() error {
7472 return util .ErrNotExist
7573}
7674
75+ func newErrReleaseNotesTargetNotFound (ref string ) error {
76+ return util .ErrorWrapTranslatable (ErrReleaseNotesTargetNotFound {Ref : ref }, "repo.release.generate_notes_target_not_found" , ref )
77+ }
78+
7779// GenerateReleaseNotes builds the markdown snippet for release notes.
7880func GenerateReleaseNotes (ctx context.Context , repo * repo_model.Repository , gitRepo * git.Repository , opts GenerateReleaseNotesOptions ) (* GenerateReleaseNotesResult , error ) {
7981 tagName := strings .TrimSpace (opts .TagName )
@@ -124,7 +126,7 @@ func resolveHeadCommit(repo *repo_model.Repository, gitRepo *git.Repository, tag
124126
125127 commit , err := gitRepo .GetCommit (ref )
126128 if err != nil {
127- return nil , ErrReleaseNotesTargetNotFound { Ref : ref }
129+ return nil , newErrReleaseNotesTargetNotFound ( ref )
128130 }
129131 return commit , nil
130132}
@@ -141,15 +143,15 @@ func resolveBaseTag(ctx context.Context, repo *repo_model.Repository, gitRepo *g
141143 if gitRepo .IsTagExist (requestedBase ) {
142144 baseCommit , err := gitRepo .GetCommit (requestedBase )
143145 if err != nil {
144- return nil , ErrReleaseNotesTagNotFound { TagName : requestedBase }
146+ return nil , newErrReleaseNotesTagNotFound ( requestedBase )
145147 }
146148 return & baseSelection {
147149 CompareBase : requestedBase ,
148150 PreviousTag : requestedBase ,
149151 Commit : baseCommit ,
150152 }, nil
151153 }
152- return nil , ErrReleaseNotesTagNotFound { TagName : requestedBase }
154+ return nil , newErrReleaseNotesTagNotFound ( requestedBase )
153155 }
154156
155157 rel , err := repo_model .GetLatestReleaseByRepoID (ctx , repo .ID )
@@ -160,15 +162,15 @@ func resolveBaseTag(ctx context.Context, repo *repo_model.Repository, gitRepo *g
160162 if gitRepo .IsTagExist (candidate ) {
161163 baseCommit , err := gitRepo .GetCommit (candidate )
162164 if err != nil {
163- return nil , ErrReleaseNotesTagNotFound { TagName : candidate }
165+ return nil , newErrReleaseNotesTagNotFound ( candidate )
164166 }
165167 return & baseSelection {
166168 CompareBase : candidate ,
167169 PreviousTag : candidate ,
168170 Commit : baseCommit ,
169171 }, nil
170172 }
171- return nil , ErrReleaseNotesTagNotFound { TagName : candidate }
173+ return nil , newErrReleaseNotesTagNotFound ( candidate )
172174 }
173175 case repo_model .IsErrReleaseNotExist (err ):
174176 // fall back to tags below
@@ -187,7 +189,7 @@ func resolveBaseTag(ctx context.Context, repo *repo_model.Repository, gitRepo *g
187189 }
188190 baseCommit , err := gitRepo .GetCommit (tag .Name )
189191 if err != nil {
190- return nil , ErrReleaseNotesTagNotFound { TagName : tag .Name }
192+ return nil , newErrReleaseNotesTagNotFound ( tag .Name )
191193 }
192194 return & baseSelection {
193195 CompareBase : tag .Name ,
@@ -220,7 +222,6 @@ func findInitialCommit(commit *git.Commit) (*git.Commit, error) {
220222}
221223
222224func collectPullRequestsFromCommits (ctx context.Context , repoID int64 , commits []* git.Commit ) ([]* issues_model.PullRequest , error ) {
223- seen := container.Set [int64 ]{}
224225 prs := make ([]* issues_model.PullRequest , 0 , len (commits ))
225226
226227 for _ , commit := range commits {
@@ -232,26 +233,21 @@ func collectPullRequestsFromCommits(ctx context.Context, repoID int64, commits [
232233 return nil , fmt .Errorf ("GetPullRequestByMergedCommit: %w" , err )
233234 }
234235
235- if ! pr .HasMerged || seen .Contains (pr .ID ) {
236- continue
237- }
238-
239236 if err = pr .LoadIssue (ctx ); err != nil {
240237 return nil , fmt .Errorf ("LoadIssue: %w" , err )
241238 }
242239 if err = pr .Issue .LoadAttributes (ctx ); err != nil {
243240 return nil , fmt .Errorf ("LoadIssueAttributes: %w" , err )
244241 }
245242
246- seen .Add (pr .ID )
247243 prs = append (prs , pr )
248244 }
249245
250- sort . Slice (prs , func (i , j int ) bool {
251- if prs [ i ]. MergedUnix != prs [ j ]. MergedUnix {
252- return prs [ i ]. MergedUnix > prs [ j ]. MergedUnix
246+ slices . SortFunc (prs , func (a , b * issues_model. PullRequest ) int {
247+ if cmpRes := cmp . Compare ( b . MergedUnix , a . MergedUnix ); cmpRes != 0 {
248+ return cmpRes
253249 }
254- return prs [ i ]. Issue .Index > prs [ j ] .Issue .Index
250+ return cmp . Compare ( b . Issue .Index , a .Issue .Index )
255251 })
256252
257253 return prs , nil
@@ -329,17 +325,9 @@ func collectContributors(ctx context.Context, repoID int64, prs []*issues_model.
329325}
330326
331327func isFirstContribution (ctx context.Context , repoID , posterID int64 , pr * issues_model.PullRequest ) (bool , error ) {
332- count , err := db .GetEngine (ctx ).
333- Table ("issue" ).
334- Join ("INNER" , "pull_request" , "pull_request.issue_id = issue.id" ).
335- Where ("issue.repo_id = ?" , repoID ).
336- And ("pull_request.has_merged = ?" , true ).
337- And ("issue.poster_id = ?" , posterID ).
338- And ("pull_request.id != ?" , pr .ID ).
339- And ("pull_request.merged_unix < ?" , pr .MergedUnix ).
340- Count ()
328+ hasMergedBefore , err := issues_model .HasMergedPullRequestInRepoBefore (ctx , repoID , posterID , int64 (pr .MergedUnix ), pr .ID )
341329 if err != nil {
342- return false , fmt .Errorf ("count merged PRs for contributor: %w" , err )
330+ return false , fmt .Errorf ("check merged PRs for contributor: %w" , err )
343331 }
344- return count == 0 , nil
332+ return ! hasMergedBefore , nil
345333}
0 commit comments