@ -17,6 +17,7 @@ import (
"code.gitea.io/gitea/modules/private"
"code.gitea.io/gitea/modules/private"
"code.gitea.io/gitea/modules/repofiles"
"code.gitea.io/gitea/modules/repofiles"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/util"
pull_service "code.gitea.io/gitea/services/pull"
"gitea.com/macaron/macaron"
"gitea.com/macaron/macaron"
)
)
@ -98,6 +99,7 @@ func HookPreReceive(ctx *macaron.Context, opts private.HookOptions) {
canPush = protectBranch . CanUserPush ( opts . UserID )
canPush = protectBranch . CanUserPush ( opts . UserID )
}
}
if ! canPush && opts . ProtectedBranchID > 0 {
if ! canPush && opts . ProtectedBranchID > 0 {
// Manual merge
pr , err := models . GetPullRequestByID ( opts . ProtectedBranchID )
pr , err := models . GetPullRequestByID ( opts . ProtectedBranchID )
if err != nil {
if err != nil {
log . Error ( "Unable to get PullRequest %d Error: %v" , opts . ProtectedBranchID , err )
log . Error ( "Unable to get PullRequest %d Error: %v" , opts . ProtectedBranchID , err )
@ -106,24 +108,55 @@ func HookPreReceive(ctx *macaron.Context, opts private.HookOptions) {
} )
} )
return
return
}
}
if ! protectBranch . HasEnoughApprovals ( pr ) {
user , err := models . GetUserByID ( opts . UserID )
log . Warn ( "Forbidden: User %d cannot push to protected branch: %s in %-v and pr #%d does not have enough approvals" , opts . UserID , branchName , repo , pr . Index )
if err != nil {
ctx . JSON ( http . StatusForbidden , map [ string ] interface { } {
log . Error ( "Unable to get User id %d Error: %v" , opts . UserID , err )
"err" : fmt . Sprintf ( "protected branch %s can not be pushed to and pr #%d does not have enough approvals" , branchName , opts . ProtectedBranchID ) ,
ctx . JSON ( http . StatusInternalServerError , map [ string ] interface { } {
"err" : fmt . Sprintf ( "Unable to get User id %d Error: %v" , opts . UserID , err ) ,
} )
return
}
perm , err := models . GetUserRepoPermission ( repo , user )
if err != nil {
log . Error ( "Unable to get Repo permission of repo %s/%s of User %s" , repo . OwnerName , repo . Name , user . Name , err )
ctx . JSON ( http . StatusInternalServerError , map [ string ] interface { } {
"err" : fmt . Sprintf ( "Unable to get Repo permission of repo %s/%s of User %s: %v" , repo . OwnerName , repo . Name , user . Name , err ) ,
} )
} )
return
return
}
}
if protectBranch . MergeBlockedByRejectedReview ( pr ) {
allowedMerge , err := pull_service . IsUserAllowedToMerge ( pr , perm , user )
log . Warn ( "Forbidden: User %d cannot push to protected branch: %s in %-v and pr #%d has requested changes" , opts . UserID , branchName , repo , pr . Index )
if err != nil {
log . Error ( "Error calculating if allowed to merge: %v" , err )
ctx . JSON ( http . StatusInternalServerError , map [ string ] interface { } {
"err" : fmt . Sprintf ( "Error calculating if allowed to merge: %v" , err ) ,
} )
return
}
if ! allowedMerge {
log . Warn ( "Forbidden: User %d is not allowed to push to protected branch: %s in %-v and is not allowed to merge pr #%d" , opts . UserID , branchName , repo , pr . Index )
ctx . JSON ( http . StatusForbidden , map [ string ] interface { } {
ctx . JSON ( http . StatusForbidden , map [ string ] interface { } {
"err" : fmt . Sprintf ( "protected branch %s can not be pushed to and pr #%d has requested changes" , branchName , opts . ProtectedBranchID ) ,
"err" : fmt . Sprintf ( "Not allowed to push to protected branch % s" , branchName ) ,
} )
} )
return
return
}
}
// Manual merge only allowed if PR is ready (even if admin)
if err := pull_service . CheckPRReadyToMerge ( pr ) ; err != nil {
if models . IsErrNotAllowedToMerge ( err ) {
log . Warn ( "Forbidden: User %d is not allowed push to protected branch %s in %-v and pr #%d is not ready to be merged: %s" , opts . UserID , branchName , repo , pr . Index , err . Error ( ) )
ctx . JSON ( http . StatusForbidden , map [ string ] interface { } {
"err" : fmt . Sprintf ( "Not allowed to push to protected branch %s and pr #%d is not ready to be merged: %s" , branchName , opts . ProtectedBranchID , err . Error ( ) ) ,
} )
return
}
log . Error ( "Unable to check if mergable: protected branch %s in %-v and pr #%d. Error: %v" , opts . UserID , branchName , repo , pr . Index , err )
ctx . JSON ( http . StatusInternalServerError , map [ string ] interface { } {
"err" : fmt . Sprintf ( "Unable to get status of pull request %d. Error: %v" , opts . ProtectedBranchID , err ) ,
} )
}
} else if ! canPush {
} else if ! canPush {
log . Warn ( "Forbidden: User %d cannot push to protected branch: %s in %-v" , opts . UserID , branchName , repo )
log . Warn ( "Forbidden: User %d is not allowed to push to protected branch: %s in %-v" , opts . UserID , branchName , repo )
ctx . JSON ( http . StatusForbidden , map [ string ] interface { } {
ctx . JSON ( http . StatusForbidden , map [ string ] interface { } {
"err" : fmt . Sprintf ( "protected branch %s can not be pushed to" , branchName ) ,
"err" : fmt . Sprintf ( "Not allowed to push to protected branch %s" , branchName ) ,
} )
} )
return
return
}
}