@@ -10,9 +10,11 @@ import (
1010
1111 "code.gitea.io/gitea/models/db"
1212 repo_model "code.gitea.io/gitea/models/repo"
13+ "code.gitea.io/gitea/models/unit"
1314 user_model "code.gitea.io/gitea/models/user"
1415 "code.gitea.io/gitea/modules/git"
1516 "code.gitea.io/gitea/modules/log"
17+ "code.gitea.io/gitea/modules/optional"
1618 "code.gitea.io/gitea/modules/timeutil"
1719 "code.gitea.io/gitea/modules/util"
1820
@@ -102,8 +104,9 @@ func (err ErrBranchesEqual) Unwrap() error {
102104// for pagination, keyword search and filtering
103105type Branch struct {
104106 ID int64
105- RepoID int64 `xorm:"UNIQUE(s)"`
106- Name string `xorm:"UNIQUE(s) NOT NULL"` // git's ref-name is case-sensitive internally, however, in some databases (mssql, mysql, by default), it's case-insensitive at the moment
107+ RepoID int64 `xorm:"UNIQUE(s)"`
108+ Repo * repo_model.Repository `xorm:"-"`
109+ Name string `xorm:"UNIQUE(s) NOT NULL"` // git's ref-name is case-sensitive internally, however, in some databases (mssql, mysql, by default), it's case-insensitive at the moment
107110 CommitID string
108111 CommitMessage string `xorm:"TEXT"` // it only stores the message summary (the first line)
109112 PusherID int64
@@ -139,6 +142,14 @@ func (b *Branch) LoadPusher(ctx context.Context) (err error) {
139142 return err
140143}
141144
145+ func (b * Branch ) LoadRepo (ctx context.Context ) (err error ) {
146+ if b .Repo != nil || b .RepoID == 0 {
147+ return nil
148+ }
149+ b .Repo , err = repo_model .GetRepositoryByID (ctx , b .RepoID )
150+ return err
151+ }
152+
142153func init () {
143154 db .RegisterModel (new (Branch ))
144155 db .RegisterModel (new (RenamedBranch ))
@@ -400,24 +411,111 @@ func RenameBranch(ctx context.Context, repo *repo_model.Repository, from, to str
400411 return committer .Commit ()
401412}
402413
403- // FindRecentlyPushedNewBranches return at most 2 new branches pushed by the user in 6 hours which has no opened PRs created
404- // except the indicate branch
405- func FindRecentlyPushedNewBranches (ctx context.Context , repoID , userID int64 , excludeBranchName string ) (BranchList , error ) {
406- branches := make (BranchList , 0 , 2 )
407- subQuery := builder .Select ("head_branch" ).From ("pull_request" ).
408- InnerJoin ("issue" , "issue.id = pull_request.issue_id" ).
409- Where (builder.Eq {
410- "pull_request.head_repo_id" : repoID ,
411- "issue.is_closed" : false ,
412- })
413- err := db .GetEngine (ctx ).
414- Where ("pusher_id=? AND is_deleted=?" , userID , false ).
415- And ("name <> ?" , excludeBranchName ).
416- And ("repo_id = ?" , repoID ).
417- And ("commit_time >= ?" , time .Now ().Add (- time .Hour * 6 ).Unix ()).
418- NotIn ("name" , subQuery ).
419- OrderBy ("branch.commit_time DESC" ).
420- Limit (2 ).
421- Find (& branches )
422- return branches , err
414+ type FindRecentlyPushedNewBranchesOptions struct {
415+ Repo * repo_model.Repository
416+ BaseRepo * repo_model.Repository
417+ CommitAfterUnix int64
418+ MaxCount int
419+ }
420+
421+ type RecentlyPushedNewBranch struct {
422+ BranchDisplayName string
423+ BranchLink string
424+ BranchCompareURL string
425+ CommitTime timeutil.TimeStamp
426+ }
427+
428+ // FindRecentlyPushedNewBranches return at most 2 new branches pushed by the user in 2 hours which has no opened PRs created
429+ // if opts.CommitAfterUnix is 0, we will find the branches that were committed to in the last 2 hours
430+ // if opts.ListOptions is not set, we will only display top 2 latest branch
431+ func FindRecentlyPushedNewBranches (ctx context.Context , doer * user_model.User , opts * FindRecentlyPushedNewBranchesOptions ) ([]* RecentlyPushedNewBranch , error ) {
432+ if doer == nil {
433+ return []* RecentlyPushedNewBranch {}, nil
434+ }
435+
436+ // find all related repo ids
437+ repoOpts := repo_model.SearchRepoOptions {
438+ Actor : doer ,
439+ Private : true ,
440+ AllPublic : false , // Include also all public repositories of users and public organisations
441+ AllLimited : false , // Include also all public repositories of limited organisations
442+ Fork : optional .Some (true ),
443+ ForkFrom : opts .BaseRepo .ID ,
444+ Archived : optional .Some (false ),
445+ }
446+ repoCond := repo_model .SearchRepositoryCondition (& repoOpts ).And (repo_model .AccessibleRepositoryCondition (doer , unit .TypeCode ))
447+ if opts .Repo .ID == opts .BaseRepo .ID {
448+ // should also include the base repo's branches
449+ repoCond = repoCond .Or (builder.Eq {"id" : opts .BaseRepo .ID })
450+ } else {
451+ // in fork repo, we only detect the fork repo's branch
452+ repoCond = repoCond .And (builder.Eq {"id" : opts .Repo .ID })
453+ }
454+ repoIDs := builder .Select ("id" ).From ("repository" ).Where (repoCond )
455+
456+ if opts .CommitAfterUnix == 0 {
457+ opts .CommitAfterUnix = time .Now ().Add (- time .Hour * 2 ).Unix ()
458+ }
459+
460+ baseBranch , err := GetBranch (ctx , opts .BaseRepo .ID , opts .BaseRepo .DefaultBranch )
461+ if err != nil {
462+ return nil , err
463+ }
464+
465+ // find all related branches, these branches may already created PRs, we will check later
466+ var branches []* Branch
467+ if err := db .GetEngine (ctx ).
468+ Where (builder .And (
469+ builder.Eq {
470+ "pusher_id" : doer .ID ,
471+ "is_deleted" : false ,
472+ },
473+ builder.Gte {"commit_time" : opts .CommitAfterUnix },
474+ builder .In ("repo_id" , repoIDs ),
475+ // newly created branch have no changes, so skip them
476+ builder.Neq {"commit_id" : baseBranch .CommitID },
477+ )).
478+ OrderBy (db .SearchOrderByRecentUpdated .String ()).
479+ Find (& branches ); err != nil {
480+ return nil , err
481+ }
482+
483+ newBranches := make ([]* RecentlyPushedNewBranch , 0 , len (branches ))
484+ if opts .MaxCount == 0 {
485+ // by default we display 2 recently pushed new branch
486+ opts .MaxCount = 2
487+ }
488+ for _ , branch := range branches {
489+ // whether branch have already created PR
490+ count , err := db .GetEngine (ctx ).Table ("pull_request" ).
491+ // we should not only use branch name here, because if there are branches with same name in other repos,
492+ // we can not detect them correctly
493+ Where (builder.Eq {"head_repo_id" : branch .RepoID , "head_branch" : branch .Name }).Count ()
494+ if err != nil {
495+ return nil , err
496+ }
497+
498+ // if no PR, we add to the result
499+ if count == 0 {
500+ if err := branch .LoadRepo (ctx ); err != nil {
501+ return nil , err
502+ }
503+
504+ branchDisplayName := branch .Name
505+ if branch .Repo .ID != opts .BaseRepo .ID && branch .Repo .ID != opts .Repo .ID {
506+ branchDisplayName = fmt .Sprintf ("%s:%s" , branch .Repo .FullName (), branchDisplayName )
507+ }
508+ newBranches = append (newBranches , & RecentlyPushedNewBranch {
509+ BranchDisplayName : branchDisplayName ,
510+ BranchLink : fmt .Sprintf ("%s/src/branch/%s" , branch .Repo .Link (), util .PathEscapeSegments (branch .Name )),
511+ BranchCompareURL : branch .Repo .ComposeBranchCompareURL (opts .BaseRepo , branch .Name ),
512+ CommitTime : branch .CommitTime ,
513+ })
514+ }
515+ if len (newBranches ) == opts .MaxCount {
516+ break
517+ }
518+ }
519+
520+ return newBranches , nil
423521}
0 commit comments