gitea源码

commit_status.go 4.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. // Copyright 2019 The Gitea Authors.
  2. // All rights reserved.
  3. // SPDX-License-Identifier: MIT
  4. package pull
  5. import (
  6. "context"
  7. "code.gitea.io/gitea/models/db"
  8. git_model "code.gitea.io/gitea/models/git"
  9. issues_model "code.gitea.io/gitea/models/issues"
  10. "code.gitea.io/gitea/modules/commitstatus"
  11. "code.gitea.io/gitea/modules/gitrepo"
  12. "code.gitea.io/gitea/modules/glob"
  13. "code.gitea.io/gitea/modules/log"
  14. "github.com/pkg/errors"
  15. )
  16. // MergeRequiredContextsCommitStatus returns a commit status state for given required contexts
  17. func MergeRequiredContextsCommitStatus(commitStatuses []*git_model.CommitStatus, requiredContexts []string) commitstatus.CommitStatusState {
  18. if len(commitStatuses) == 0 {
  19. return commitstatus.CommitStatusPending
  20. }
  21. if len(requiredContexts) == 0 {
  22. return git_model.CalcCommitStatus(commitStatuses).State
  23. }
  24. requiredContextsGlob := make(map[string]glob.Glob, len(requiredContexts))
  25. for _, ctx := range requiredContexts {
  26. if gp, err := glob.Compile(ctx); err != nil {
  27. log.Error("glob.Compile %s failed. Error: %v", ctx, err)
  28. } else {
  29. requiredContextsGlob[ctx] = gp
  30. }
  31. }
  32. requiredCommitStatuses := make([]*git_model.CommitStatus, 0, len(commitStatuses))
  33. allRequiredContextsMatched := true
  34. for _, gp := range requiredContextsGlob {
  35. requiredContextMatched := false
  36. for _, commitStatus := range commitStatuses {
  37. if gp.Match(commitStatus.Context) {
  38. requiredCommitStatuses = append(requiredCommitStatuses, commitStatus)
  39. requiredContextMatched = true
  40. }
  41. }
  42. allRequiredContextsMatched = allRequiredContextsMatched && requiredContextMatched
  43. }
  44. if len(requiredCommitStatuses) == 0 {
  45. return commitstatus.CommitStatusPending
  46. }
  47. returnedStatus := git_model.CalcCommitStatus(requiredCommitStatuses).State
  48. if allRequiredContextsMatched {
  49. return returnedStatus
  50. }
  51. if returnedStatus == commitstatus.CommitStatusFailure {
  52. return commitstatus.CommitStatusFailure
  53. }
  54. // even if part of success, return pending
  55. return commitstatus.CommitStatusPending
  56. }
  57. // IsPullCommitStatusPass returns if all required status checks PASS
  58. func IsPullCommitStatusPass(ctx context.Context, pr *issues_model.PullRequest) (bool, error) {
  59. pb, err := git_model.GetFirstMatchProtectedBranchRule(ctx, pr.BaseRepoID, pr.BaseBranch)
  60. if err != nil {
  61. return false, errors.Wrap(err, "GetLatestCommitStatus")
  62. }
  63. if pb == nil || !pb.EnableStatusCheck {
  64. return true, nil
  65. }
  66. state, err := GetPullRequestCommitStatusState(ctx, pr)
  67. if err != nil {
  68. return false, err
  69. }
  70. return state.IsSuccess(), nil
  71. }
  72. // GetPullRequestCommitStatusState returns pull request merged commit status state
  73. func GetPullRequestCommitStatusState(ctx context.Context, pr *issues_model.PullRequest) (commitstatus.CommitStatusState, error) {
  74. // Ensure HeadRepo is loaded
  75. if err := pr.LoadHeadRepo(ctx); err != nil {
  76. return "", errors.Wrap(err, "LoadHeadRepo")
  77. }
  78. // check if all required status checks are successful
  79. headGitRepo, closer, err := gitrepo.RepositoryFromContextOrOpen(ctx, pr.HeadRepo)
  80. if err != nil {
  81. return "", errors.Wrap(err, "OpenRepository")
  82. }
  83. defer closer.Close()
  84. if pr.Flow == issues_model.PullRequestFlowGithub && !gitrepo.IsBranchExist(ctx, pr.HeadRepo, pr.HeadBranch) {
  85. return "", errors.New("Head branch does not exist, can not merge")
  86. }
  87. if pr.Flow == issues_model.PullRequestFlowAGit && !gitrepo.IsReferenceExist(ctx, pr.HeadRepo, pr.GetGitHeadRefName()) {
  88. return "", errors.New("Head branch does not exist, can not merge")
  89. }
  90. var sha string
  91. if pr.Flow == issues_model.PullRequestFlowGithub {
  92. sha, err = headGitRepo.GetBranchCommitID(pr.HeadBranch)
  93. } else {
  94. sha, err = headGitRepo.GetRefCommitID(pr.GetGitHeadRefName())
  95. }
  96. if err != nil {
  97. return "", err
  98. }
  99. if err := pr.LoadBaseRepo(ctx); err != nil {
  100. return "", errors.Wrap(err, "LoadBaseRepo")
  101. }
  102. commitStatuses, err := git_model.GetLatestCommitStatus(ctx, pr.BaseRepo.ID, sha, db.ListOptionsAll)
  103. if err != nil {
  104. return "", errors.Wrap(err, "GetLatestCommitStatus")
  105. }
  106. pb, err := git_model.GetFirstMatchProtectedBranchRule(ctx, pr.BaseRepoID, pr.BaseBranch)
  107. if err != nil {
  108. return "", errors.Wrap(err, "LoadProtectedBranch")
  109. }
  110. var requiredContexts []string
  111. if pb != nil {
  112. requiredContexts = pb.StatusCheckContexts
  113. }
  114. return MergeRequiredContextsCommitStatus(commitStatuses, requiredContexts), nil
  115. }