2019-09-18 08:39:45 +03:00
// Copyright 2019 The Gitea Authors.
// All rights reserved.
2022-11-27 21:20:29 +03:00
// SPDX-License-Identifier: MIT
2019-09-18 08:39:45 +03:00
package pull
import (
2022-01-20 02:26:57 +03:00
"context"
2021-09-24 14:32:56 +03:00
"code.gitea.io/gitea/models/db"
2022-06-12 18:51:54 +03:00
git_model "code.gitea.io/gitea/models/git"
2022-06-13 12:37:59 +03:00
issues_model "code.gitea.io/gitea/models/issues"
2019-09-18 08:39:45 +03:00
"code.gitea.io/gitea/modules/git"
2020-01-22 06:46:04 +03:00
"code.gitea.io/gitea/modules/structs"
2019-09-18 08:39:45 +03:00
"github.com/pkg/errors"
)
2020-01-22 06:46:04 +03:00
// MergeRequiredContextsCommitStatus returns a commit status state for given required contexts
2022-06-12 18:51:54 +03:00
func MergeRequiredContextsCommitStatus ( commitStatuses [ ] * git_model . CommitStatus , requiredContexts [ ] string ) structs . CommitStatusState {
2020-01-22 06:46:04 +03:00
if len ( requiredContexts ) == 0 {
2022-06-12 18:51:54 +03:00
status := git_model . CalcCommitStatus ( commitStatuses )
2020-01-22 06:46:04 +03:00
if status != nil {
return status . State
}
return structs . CommitStatusSuccess
}
2022-01-20 20:46:10 +03:00
returnedStatus := structs . CommitStatusSuccess
2020-01-22 06:46:04 +03:00
for _ , ctx := range requiredContexts {
var targetStatus structs . CommitStatusState
for _ , commitStatus := range commitStatuses {
if commitStatus . Context == ctx {
targetStatus = commitStatus . State
break
}
}
if targetStatus == "" {
targetStatus = structs . CommitStatusPending
2022-06-12 18:51:54 +03:00
commitStatuses = append ( commitStatuses , & git_model . CommitStatus {
2020-03-07 10:33:20 +03:00
State : targetStatus ,
Context : ctx ,
Description : "Pending" ,
} )
2020-01-22 06:46:04 +03:00
}
if targetStatus . NoBetterThan ( returnedStatus ) {
returnedStatus = targetStatus
}
}
return returnedStatus
}
2019-09-18 08:39:45 +03:00
// IsCommitStatusContextSuccess returns true if all required status check contexts succeed.
2022-06-12 18:51:54 +03:00
func IsCommitStatusContextSuccess ( commitStatuses [ ] * git_model . CommitStatus , requiredContexts [ ] string ) bool {
2019-09-30 05:33:40 +03:00
// If no specific context is required, require that last commit status is a success
if len ( requiredContexts ) == 0 {
2022-06-12 18:51:54 +03:00
status := git_model . CalcCommitStatus ( commitStatuses )
2020-01-22 06:46:04 +03:00
if status == nil || status . State != structs . CommitStatusSuccess {
2019-09-30 05:33:40 +03:00
return false
}
return true
}
2019-09-18 08:39:45 +03:00
for _ , ctx := range requiredContexts {
var found bool
for _ , commitStatus := range commitStatuses {
if commitStatus . Context == ctx {
2020-01-22 06:46:04 +03:00
if commitStatus . State != structs . CommitStatusSuccess {
2019-09-18 08:39:45 +03:00
return false
}
found = true
break
}
}
if ! found {
return false
}
}
return true
}
// IsPullCommitStatusPass returns if all required status checks PASS
2022-06-13 12:37:59 +03:00
func IsPullCommitStatusPass ( ctx context . Context , pr * issues_model . PullRequest ) ( bool , error ) {
2022-12-03 05:48:26 +03:00
if err := pr . LoadProtectedBranch ( ctx ) ; err != nil {
2019-09-18 08:39:45 +03:00
return false , errors . Wrap ( err , "GetLatestCommitStatus" )
}
if pr . ProtectedBranch == nil || ! pr . ProtectedBranch . EnableStatusCheck {
return true , nil
}
2022-01-20 02:26:57 +03:00
state , err := GetPullRequestCommitStatusState ( ctx , pr )
2020-01-22 06:46:04 +03:00
if err != nil {
return false , err
}
return state . IsSuccess ( ) , nil
}
// GetPullRequestCommitStatusState returns pull request merged commit status state
2022-06-13 12:37:59 +03:00
func GetPullRequestCommitStatusState ( ctx context . Context , pr * issues_model . PullRequest ) ( structs . CommitStatusState , error ) {
2020-02-18 22:34:08 +03:00
// Ensure HeadRepo is loaded
2022-11-19 11:12:33 +03:00
if err := pr . LoadHeadRepo ( ctx ) ; err != nil {
2020-02-18 22:34:08 +03:00
return "" , errors . Wrap ( err , "LoadHeadRepo" )
}
2019-09-18 08:39:45 +03:00
// check if all required status checks are successful
2022-01-20 02:26:57 +03:00
headGitRepo , closer , err := git . RepositoryFromContextOrOpen ( ctx , pr . HeadRepo . RepoPath ( ) )
2019-09-18 08:39:45 +03:00
if err != nil {
2020-01-22 06:46:04 +03:00
return "" , errors . Wrap ( err , "OpenRepository" )
2019-09-18 08:39:45 +03:00
}
2022-01-20 02:26:57 +03:00
defer closer . Close ( )
2019-09-18 08:39:45 +03:00
2022-06-13 12:37:59 +03:00
if pr . Flow == issues_model . PullRequestFlowGithub && ! headGitRepo . IsBranchExist ( pr . HeadBranch ) {
2021-07-28 12:42:56 +03:00
return "" , errors . New ( "Head branch does not exist, can not merge" )
}
2022-06-13 12:37:59 +03:00
if pr . Flow == issues_model . PullRequestFlowAGit && ! git . IsReferenceExist ( ctx , headGitRepo . Path , pr . GetGitRefName ( ) ) {
2020-01-22 06:46:04 +03:00
return "" , errors . New ( "Head branch does not exist, can not merge" )
2019-09-18 08:39:45 +03:00
}
2021-07-28 12:42:56 +03:00
var sha string
2022-06-13 12:37:59 +03:00
if pr . Flow == issues_model . PullRequestFlowGithub {
2021-07-28 12:42:56 +03:00
sha , err = headGitRepo . GetBranchCommitID ( pr . HeadBranch )
} else {
sha , err = headGitRepo . GetRefCommitID ( pr . GetGitRefName ( ) )
}
2019-09-18 08:39:45 +03:00
if err != nil {
2021-07-28 12:42:56 +03:00
return "" , err
2019-09-18 08:39:45 +03:00
}
2022-11-19 11:12:33 +03:00
if err := pr . LoadBaseRepo ( ctx ) ; err != nil {
2020-01-22 06:46:04 +03:00
return "" , errors . Wrap ( err , "LoadBaseRepo" )
2019-09-18 08:39:45 +03:00
}
2022-06-12 18:51:54 +03:00
commitStatuses , _ , err := git_model . GetLatestCommitStatus ( ctx , pr . BaseRepo . ID , sha , db . ListOptions { } )
2019-09-18 08:39:45 +03:00
if err != nil {
2020-01-22 06:46:04 +03:00
return "" , errors . Wrap ( err , "GetLatestCommitStatus" )
2019-09-18 08:39:45 +03:00
}
2022-12-03 05:48:26 +03:00
if err := pr . LoadProtectedBranch ( ctx ) ; err != nil {
2022-05-07 20:05:52 +03:00
return "" , errors . Wrap ( err , "LoadProtectedBranch" )
}
var requiredContexts [ ] string
if pr . ProtectedBranch != nil {
requiredContexts = pr . ProtectedBranch . StatusCheckContexts
}
return MergeRequiredContextsCommitStatus ( commitStatuses , requiredContexts ) , nil
2019-09-18 08:39:45 +03:00
}