2020-12-02 10:26:04 +05:30
// Copyright 2020 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package doctor
import (
2022-01-20 04:56:57 +05:30
"context"
2020-12-02 10:26:04 +05:30
"fmt"
"strings"
2021-09-19 17:19:59 +05:30
"code.gitea.io/gitea/models/db"
2022-06-13 15:07:59 +05:30
issues_model "code.gitea.io/gitea/models/issues"
2021-12-10 06:57:50 +05:30
repo_model "code.gitea.io/gitea/models/repo"
2020-12-02 10:26:04 +05:30
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
2021-09-19 17:19:59 +05:30
2020-12-02 10:26:04 +05:30
"xorm.io/builder"
)
2022-06-13 15:07:59 +05:30
func iteratePRs ( ctx context . Context , repo * repo_model . Repository , each func ( * repo_model . Repository , * issues_model . PullRequest ) error ) error {
2021-09-19 17:19:59 +05:30
return db . Iterate (
2022-03-22 20:52:54 +05:30
ctx ,
2020-12-02 10:26:04 +05:30
builder . Eq { "base_repo_id" : repo . ID } ,
2022-10-31 21:21:14 +05:30
func ( ctx context . Context , bean * issues_model . PullRequest ) error {
return each ( repo , bean )
2020-12-02 10:26:04 +05:30
} ,
)
}
2022-01-20 04:56:57 +05:30
func checkPRMergeBase ( ctx context . Context , logger log . Logger , autofix bool ) error {
2020-12-02 10:26:04 +05:30
numRepos := 0
numPRs := 0
numPRsUpdated := 0
2022-03-22 20:52:54 +05:30
err := iterateRepositories ( ctx , func ( repo * repo_model . Repository ) error {
2020-12-02 10:26:04 +05:30
numRepos ++
2022-06-13 15:07:59 +05:30
return iteratePRs ( ctx , repo , func ( repo * repo_model . Repository , pr * issues_model . PullRequest ) error {
2020-12-02 10:26:04 +05:30
numPRs ++
pr . BaseRepo = repo
repoPath := repo . RepoPath ( )
oldMergeBase := pr . MergeBase
if ! pr . HasMerged {
var err error
2022-10-23 20:14:45 +05:30
pr . MergeBase , _ , err = git . NewCommand ( ctx , "merge-base" ) . AddDashesAndList ( pr . BaseBranch , pr . GetGitRefName ( ) ) . RunStdString ( & git . RunOpts { Dir : repoPath } )
2020-12-02 10:26:04 +05:30
if err != nil {
var err2 error
2022-10-23 20:14:45 +05:30
pr . MergeBase , _ , err2 = git . NewCommand ( ctx , "rev-parse" ) . AddDynamicArguments ( git . BranchPrefix + pr . BaseBranch ) . RunStdString ( & git . RunOpts { Dir : repoPath } )
2020-12-02 10:26:04 +05:30
if err2 != nil {
logger . Warn ( "Unable to get merge base for PR ID %d, #%d onto %s in %s/%s. Error: %v & %v" , pr . ID , pr . Index , pr . BaseBranch , pr . BaseRepo . OwnerName , pr . BaseRepo . Name , err , err2 )
return nil
}
}
} else {
2022-10-23 20:14:45 +05:30
parentsString , _ , err := git . NewCommand ( ctx , "rev-list" , "--parents" , "-n" , "1" ) . AddDynamicArguments ( pr . MergedCommitID ) . RunStdString ( & git . RunOpts { Dir : repoPath } )
2020-12-02 10:26:04 +05:30
if err != nil {
logger . Warn ( "Unable to get parents for merged PR ID %d, #%d onto %s in %s/%s. Error: %v" , pr . ID , pr . Index , pr . BaseBranch , pr . BaseRepo . OwnerName , pr . BaseRepo . Name , err )
return nil
}
parents := strings . Split ( strings . TrimSpace ( parentsString ) , " " )
if len ( parents ) < 2 {
return nil
}
2022-10-23 20:14:45 +05:30
refs := append ( [ ] string { } , parents [ 1 : ] ... )
refs = append ( refs , pr . GetGitRefName ( ) )
cmd := git . NewCommand ( ctx , "merge-base" ) . AddDashesAndList ( refs ... )
pr . MergeBase , _ , err = cmd . RunStdString ( & git . RunOpts { Dir : repoPath } )
2020-12-02 10:26:04 +05:30
if err != nil {
logger . Warn ( "Unable to get merge base for merged PR ID %d, #%d onto %s in %s/%s. Error: %v" , pr . ID , pr . Index , pr . BaseBranch , pr . BaseRepo . OwnerName , pr . BaseRepo . Name , err )
return nil
}
}
pr . MergeBase = strings . TrimSpace ( pr . MergeBase )
if pr . MergeBase != oldMergeBase {
if autofix {
if err := pr . UpdateCols ( "merge_base" ) ; err != nil {
logger . Critical ( "Failed to update merge_base. ERROR: %v" , err )
2022-10-25 00:59:17 +05:30
return fmt . Errorf ( "Failed to update merge_base. ERROR: %w" , err )
2020-12-02 10:26:04 +05:30
}
} else {
logger . Info ( "#%d onto %s in %s/%s: MergeBase should be %s but is %s" , pr . Index , pr . BaseBranch , pr . BaseRepo . OwnerName , pr . BaseRepo . Name , oldMergeBase , pr . MergeBase )
}
numPRsUpdated ++
}
return nil
} )
} )
if autofix {
logger . Info ( "%d PR mergebases updated of %d PRs total in %d repos" , numPRsUpdated , numPRs , numRepos )
} else {
2022-06-01 00:19:40 +05:30
if numPRsUpdated == 0 {
logger . Info ( "All %d PRs in %d repos have a correct mergebase" , numPRs , numRepos )
} else if err == nil {
2020-12-02 10:26:04 +05:30
logger . Critical ( "%d PRs with incorrect mergebases of %d PRs total in %d repos" , numPRsUpdated , numPRs , numRepos )
return fmt . Errorf ( "%d PRs with incorrect mergebases of %d PRs total in %d repos" , numPRsUpdated , numPRs , numRepos )
2022-06-01 00:19:40 +05:30
} else {
logger . Warn ( "%d PRs with incorrect mergebases of %d PRs total in %d repos" , numPRsUpdated , numPRs , numRepos )
2020-12-02 10:26:04 +05:30
}
}
return err
}
func init ( ) {
Register ( & Check {
Title : "Recalculate merge bases" ,
Name : "recalculate-merge-bases" ,
IsDefault : false ,
Run : checkPRMergeBase ,
Priority : 7 ,
} )
}