You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

mergebase.go 3.7 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. // Copyright 2020 The Gitea Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package doctor
  5. import (
  6. "fmt"
  7. "strings"
  8. "code.gitea.io/gitea/models"
  9. "code.gitea.io/gitea/modules/git"
  10. "code.gitea.io/gitea/modules/log"
  11. "xorm.io/builder"
  12. )
  13. func iteratePRs(repo *models.Repository, each func(*models.Repository, *models.PullRequest) error) error {
  14. return models.Iterate(
  15. models.DefaultDBContext(),
  16. new(models.PullRequest),
  17. builder.Eq{"base_repo_id": repo.ID},
  18. func(idx int, bean interface{}) error {
  19. return each(repo, bean.(*models.PullRequest))
  20. },
  21. )
  22. }
  23. func checkPRMergeBase(logger log.Logger, autofix bool) error {
  24. numRepos := 0
  25. numPRs := 0
  26. numPRsUpdated := 0
  27. err := iterateRepositories(func(repo *models.Repository) error {
  28. numRepos++
  29. return iteratePRs(repo, func(repo *models.Repository, pr *models.PullRequest) error {
  30. numPRs++
  31. pr.BaseRepo = repo
  32. repoPath := repo.RepoPath()
  33. oldMergeBase := pr.MergeBase
  34. if !pr.HasMerged {
  35. var err error
  36. pr.MergeBase, err = git.NewCommand("merge-base", "--", pr.BaseBranch, pr.GetGitRefName()).RunInDir(repoPath)
  37. if err != nil {
  38. var err2 error
  39. pr.MergeBase, err2 = git.NewCommand("rev-parse", git.BranchPrefix+pr.BaseBranch).RunInDir(repoPath)
  40. if err2 != nil {
  41. 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)
  42. return nil
  43. }
  44. }
  45. } else {
  46. parentsString, err := git.NewCommand("rev-list", "--parents", "-n", "1", pr.MergedCommitID).RunInDir(repoPath)
  47. if err != nil {
  48. 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)
  49. return nil
  50. }
  51. parents := strings.Split(strings.TrimSpace(parentsString), " ")
  52. if len(parents) < 2 {
  53. return nil
  54. }
  55. args := append([]string{"merge-base", "--"}, parents[1:]...)
  56. args = append(args, pr.GetGitRefName())
  57. pr.MergeBase, err = git.NewCommand(args...).RunInDir(repoPath)
  58. if err != nil {
  59. 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)
  60. return nil
  61. }
  62. }
  63. pr.MergeBase = strings.TrimSpace(pr.MergeBase)
  64. if pr.MergeBase != oldMergeBase {
  65. if autofix {
  66. if err := pr.UpdateCols("merge_base"); err != nil {
  67. logger.Critical("Failed to update merge_base. ERROR: %v", err)
  68. return fmt.Errorf("Failed to update merge_base. ERROR: %v", err)
  69. }
  70. } else {
  71. 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)
  72. }
  73. numPRsUpdated++
  74. }
  75. return nil
  76. })
  77. })
  78. if autofix {
  79. logger.Info("%d PR mergebases updated of %d PRs total in %d repos", numPRsUpdated, numPRs, numRepos)
  80. } else {
  81. if numPRsUpdated > 0 && err == nil {
  82. logger.Critical("%d PRs with incorrect mergebases of %d PRs total in %d repos", numPRsUpdated, numPRs, numRepos)
  83. return fmt.Errorf("%d PRs with incorrect mergebases of %d PRs total in %d repos", numPRsUpdated, numPRs, numRepos)
  84. }
  85. logger.Warn("%d PRs with incorrect mergebases of %d PRs total in %d repos", numPRsUpdated, numPRs, numRepos)
  86. }
  87. return err
  88. }
  89. func init() {
  90. Register(&Check{
  91. Title: "Recalculate merge bases",
  92. Name: "recalculate-merge-bases",
  93. IsDefault: false,
  94. Run: checkPRMergeBase,
  95. Priority: 7,
  96. })
  97. }