code.gitea.io/gitea@v1.19.3/modules/doctor/mergebase.go (about) 1 // Copyright 2020 The Gitea Authors. All rights reserved. 2 // SPDX-License-Identifier: MIT 3 4 package doctor 5 6 import ( 7 "context" 8 "fmt" 9 "strings" 10 11 "code.gitea.io/gitea/models/db" 12 issues_model "code.gitea.io/gitea/models/issues" 13 repo_model "code.gitea.io/gitea/models/repo" 14 "code.gitea.io/gitea/modules/git" 15 "code.gitea.io/gitea/modules/log" 16 17 "xorm.io/builder" 18 ) 19 20 func iteratePRs(ctx context.Context, repo *repo_model.Repository, each func(*repo_model.Repository, *issues_model.PullRequest) error) error { 21 return db.Iterate( 22 ctx, 23 builder.Eq{"base_repo_id": repo.ID}, 24 func(ctx context.Context, bean *issues_model.PullRequest) error { 25 return each(repo, bean) 26 }, 27 ) 28 } 29 30 func checkPRMergeBase(ctx context.Context, logger log.Logger, autofix bool) error { 31 numRepos := 0 32 numPRs := 0 33 numPRsUpdated := 0 34 err := iterateRepositories(ctx, func(repo *repo_model.Repository) error { 35 numRepos++ 36 return iteratePRs(ctx, repo, func(repo *repo_model.Repository, pr *issues_model.PullRequest) error { 37 numPRs++ 38 pr.BaseRepo = repo 39 repoPath := repo.RepoPath() 40 41 oldMergeBase := pr.MergeBase 42 43 if !pr.HasMerged { 44 var err error 45 pr.MergeBase, _, err = git.NewCommand(ctx, "merge-base").AddDashesAndList(pr.BaseBranch, pr.GetGitRefName()).RunStdString(&git.RunOpts{Dir: repoPath}) 46 if err != nil { 47 var err2 error 48 pr.MergeBase, _, err2 = git.NewCommand(ctx, "rev-parse").AddDynamicArguments(git.BranchPrefix + pr.BaseBranch).RunStdString(&git.RunOpts{Dir: repoPath}) 49 if err2 != nil { 50 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) 51 return nil 52 } 53 } 54 } else { 55 parentsString, _, err := git.NewCommand(ctx, "rev-list", "--parents", "-n", "1").AddDynamicArguments(pr.MergedCommitID).RunStdString(&git.RunOpts{Dir: repoPath}) 56 if err != nil { 57 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) 58 return nil 59 } 60 parents := strings.Split(strings.TrimSpace(parentsString), " ") 61 if len(parents) < 2 { 62 return nil 63 } 64 65 refs := append([]string{}, parents[1:]...) 66 refs = append(refs, pr.GetGitRefName()) 67 cmd := git.NewCommand(ctx, "merge-base").AddDashesAndList(refs...) 68 pr.MergeBase, _, err = cmd.RunStdString(&git.RunOpts{Dir: repoPath}) 69 if err != nil { 70 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) 71 return nil 72 } 73 } 74 pr.MergeBase = strings.TrimSpace(pr.MergeBase) 75 if pr.MergeBase != oldMergeBase { 76 if autofix { 77 if err := pr.UpdateCols("merge_base"); err != nil { 78 logger.Critical("Failed to update merge_base. ERROR: %v", err) 79 return fmt.Errorf("Failed to update merge_base. ERROR: %w", err) 80 } 81 } else { 82 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) 83 } 84 numPRsUpdated++ 85 } 86 return nil 87 }) 88 }) 89 90 if autofix { 91 logger.Info("%d PR mergebases updated of %d PRs total in %d repos", numPRsUpdated, numPRs, numRepos) 92 } else { 93 if numPRsUpdated == 0 { 94 logger.Info("All %d PRs in %d repos have a correct mergebase", numPRs, numRepos) 95 } else if err == nil { 96 logger.Critical("%d PRs with incorrect mergebases of %d PRs total in %d repos", numPRsUpdated, numPRs, numRepos) 97 return fmt.Errorf("%d PRs with incorrect mergebases of %d PRs total in %d repos", numPRsUpdated, numPRs, numRepos) 98 } else { 99 logger.Warn("%d PRs with incorrect mergebases of %d PRs total in %d repos", numPRsUpdated, numPRs, numRepos) 100 } 101 } 102 103 return err 104 } 105 106 func init() { 107 Register(&Check{ 108 Title: "Recalculate merge bases", 109 Name: "recalculate-merge-bases", 110 IsDefault: false, 111 Run: checkPRMergeBase, 112 Priority: 7, 113 }) 114 }