2020-12-02 05:56:04 +01:00
// Copyright 2020 The Gitea Authors. All rights reserved.
2022-11-27 19:20:29 +01:00
// SPDX-License-Identifier: MIT
2020-12-02 05:56:04 +01:00
package doctor
import (
2022-01-20 00:26:57 +01:00
"context"
2020-12-02 05:56:04 +01:00
"fmt"
"strings"
2021-09-19 13:49:59 +02:00
"code.gitea.io/gitea/models/db"
2022-06-13 11:37:59 +02:00
issues_model "code.gitea.io/gitea/models/issues"
2021-12-10 02:27:50 +01:00
repo_model "code.gitea.io/gitea/models/repo"
2020-12-02 05:56:04 +01:00
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
2021-09-19 13:49:59 +02:00
2020-12-02 05:56:04 +01:00
"xorm.io/builder"
)
2022-06-13 11:37:59 +02:00
func iteratePRs ( ctx context . Context , repo * repo_model . Repository , each func ( * repo_model . Repository , * issues_model . PullRequest ) error ) error {
2021-09-19 13:49:59 +02:00
return db . Iterate (
2022-03-22 16:22:54 +01:00
ctx ,
2020-12-02 05:56:04 +01:00
builder . Eq { "base_repo_id" : repo . ID } ,
2022-10-31 16:51:14 +01:00
func ( ctx context . Context , bean * issues_model . PullRequest ) error {
return each ( repo , bean )
2020-12-02 05:56:04 +01:00
} ,
)
}
2022-01-20 00:26:57 +01:00
func checkPRMergeBase ( ctx context . Context , logger log . Logger , autofix bool ) error {
2020-12-02 05:56:04 +01:00
numRepos := 0
numPRs := 0
numPRsUpdated := 0
2022-03-22 16:22:54 +01:00
err := iterateRepositories ( ctx , func ( repo * repo_model . Repository ) error {
2020-12-02 05:56:04 +01:00
numRepos ++
2022-06-13 11:37:59 +02:00
return iteratePRs ( ctx , repo , func ( repo * repo_model . Repository , pr * issues_model . PullRequest ) error {
2020-12-02 05:56:04 +01:00
numPRs ++
pr . BaseRepo = repo
repoPath := repo . RepoPath ( )
oldMergeBase := pr . MergeBase
if ! pr . HasMerged {
var err error
2022-10-23 16:44:45 +02:00
pr . MergeBase , _ , err = git . NewCommand ( ctx , "merge-base" ) . AddDashesAndList ( pr . BaseBranch , pr . GetGitRefName ( ) ) . RunStdString ( & git . RunOpts { Dir : repoPath } )
2020-12-02 05:56:04 +01:00
if err != nil {
var err2 error
2022-10-23 16:44:45 +02:00
pr . MergeBase , _ , err2 = git . NewCommand ( ctx , "rev-parse" ) . AddDynamicArguments ( git . BranchPrefix + pr . BaseBranch ) . RunStdString ( & git . RunOpts { Dir : repoPath } )
2020-12-02 05:56:04 +01:00
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 16:44:45 +02:00
parentsString , _ , err := git . NewCommand ( ctx , "rev-list" , "--parents" , "-n" , "1" ) . AddDynamicArguments ( pr . MergedCommitID ) . RunStdString ( & git . RunOpts { Dir : repoPath } )
2020-12-02 05:56:04 +01:00
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 16:44:45 +02:00
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 05:56:04 +01:00
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-24 21:29:17 +02:00
return fmt . Errorf ( "Failed to update merge_base. ERROR: %w" , err )
2020-12-02 05:56:04 +01:00
}
} 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-05-31 20:49:40 +02:00
if numPRsUpdated == 0 {
logger . Info ( "All %d PRs in %d repos have a correct mergebase" , numPRs , numRepos )
} else if err == nil {
2020-12-02 05:56:04 +01:00
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-05-31 20:49:40 +02:00
} else {
logger . Warn ( "%d PRs with incorrect mergebases of %d PRs total in %d repos" , numPRsUpdated , numPRs , numRepos )
2020-12-02 05:56:04 +01:00
}
}
return err
}
func init ( ) {
Register ( & Check {
Title : "Recalculate merge bases" ,
Name : "recalculate-merge-bases" ,
IsDefault : false ,
Run : checkPRMergeBase ,
Priority : 7 ,
} )
}