2020-01-17 09:03:40 +03:00
// Copyright 2020 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package pull
import (
2022-01-20 02:26:57 +03:00
"context"
2020-01-17 09:03:40 +03:00
"fmt"
"code.gitea.io/gitea/models"
2022-06-13 12:37:59 +03:00
issues_model "code.gitea.io/gitea/models/issues"
2022-05-11 13:09:36 +03:00
access_model "code.gitea.io/gitea/models/perm/access"
2021-12-10 04:27:50 +03:00
repo_model "code.gitea.io/gitea/models/repo"
2022-03-04 11:30:49 +03:00
"code.gitea.io/gitea/models/unit"
2021-11-24 12:49:20 +03:00
user_model "code.gitea.io/gitea/models/user"
2020-01-17 09:03:40 +03:00
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
2022-05-08 19:46:32 +03:00
repo_module "code.gitea.io/gitea/modules/repository"
2020-01-17 09:03:40 +03:00
)
// Update updates pull request with base branch.
2022-06-13 12:37:59 +03:00
func Update ( ctx context . Context , pull * issues_model . PullRequest , doer * user_model . User , message string , rebase bool ) error {
2021-08-31 17:03:45 +03:00
var (
2022-06-13 12:37:59 +03:00
pr * issues_model . PullRequest
2021-12-10 04:27:50 +03:00
style repo_model . MergeStyle
2021-08-31 17:03:45 +03:00
)
2022-05-04 19:06:23 +03:00
pullWorkingPool . CheckIn ( fmt . Sprint ( pull . ID ) )
defer pullWorkingPool . CheckOut ( fmt . Sprint ( pull . ID ) )
2021-08-31 17:03:45 +03:00
if rebase {
pr = pull
2021-12-10 04:27:50 +03:00
style = repo_model . MergeStyleRebaseUpdate
2021-08-31 17:03:45 +03:00
} else {
2022-01-20 20:46:10 +03:00
// use merge functions but switch repo's and branch's
2022-06-13 12:37:59 +03:00
pr = & issues_model . PullRequest {
2021-08-31 17:03:45 +03:00
HeadRepoID : pull . BaseRepoID ,
BaseRepoID : pull . HeadRepoID ,
HeadBranch : pull . BaseBranch ,
BaseBranch : pull . HeadBranch ,
}
2021-12-10 04:27:50 +03:00
style = repo_model . MergeStyleMerge
2020-01-17 09:03:40 +03:00
}
2022-06-13 12:37:59 +03:00
if pull . Flow == issues_model . PullRequestFlowAGit {
2021-07-28 12:42:56 +03:00
// TODO: Not support update agit flow pull request's head branch
return fmt . Errorf ( "Not support update agit flow pull request's head branch" )
}
2022-04-28 14:48:48 +03:00
if err := pr . LoadHeadRepoCtx ( ctx ) ; err != nil {
2020-01-17 09:03:40 +03:00
log . Error ( "LoadHeadRepo: %v" , err )
return fmt . Errorf ( "LoadHeadRepo: %v" , err )
2022-04-28 14:48:48 +03:00
} else if err = pr . LoadBaseRepoCtx ( ctx ) ; err != nil {
2020-01-17 09:03:40 +03:00
log . Error ( "LoadBaseRepo: %v" , err )
return fmt . Errorf ( "LoadBaseRepo: %v" , err )
}
2022-01-20 02:26:57 +03:00
diffCount , err := GetDiverging ( ctx , pull )
2020-01-17 09:03:40 +03:00
if err != nil {
return err
} else if diffCount . Behind == 0 {
return fmt . Errorf ( "HeadBranch of PR %d is up to date" , pull . Index )
}
2022-01-20 02:26:57 +03:00
_ , err = rawMerge ( ctx , pr , doer , style , "" , message )
2020-02-10 02:09:31 +03:00
2020-01-17 09:03:40 +03:00
defer func ( ) {
2021-08-31 17:03:45 +03:00
if rebase {
go AddTestPullRequestTask ( doer , pr . BaseRepo . ID , pr . BaseBranch , false , "" , "" )
return
}
2020-01-17 09:03:40 +03:00
go AddTestPullRequestTask ( doer , pr . HeadRepo . ID , pr . HeadBranch , false , "" , "" )
} ( )
2020-02-10 02:09:31 +03:00
return err
2020-01-17 09:03:40 +03:00
}
// IsUserAllowedToUpdate check if user is allowed to update PR with given permissions and branch protections
2022-06-13 12:37:59 +03:00
func IsUserAllowedToUpdate ( ctx context . Context , pull * issues_model . PullRequest , user * user_model . User ) ( mergeAllowed , rebaseAllowed bool , err error ) {
if pull . Flow == issues_model . PullRequestFlowAGit {
2021-08-31 17:03:45 +03:00
return false , false , nil
2021-07-28 12:42:56 +03:00
}
2021-03-04 21:27:54 +03:00
if user == nil {
2021-08-31 17:03:45 +03:00
return false , false , nil
2021-03-04 21:27:54 +03:00
}
2022-05-11 13:09:36 +03:00
headRepoPerm , err := access_model . GetUserRepoPermission ( ctx , pull . HeadRepo , user )
2020-01-17 09:03:40 +03:00
if err != nil {
2021-08-31 17:03:45 +03:00
return false , false , err
2020-01-17 09:03:40 +03:00
}
2022-06-13 12:37:59 +03:00
pr := & issues_model . PullRequest {
2020-01-17 09:03:40 +03:00
HeadRepoID : pull . BaseRepoID ,
BaseRepoID : pull . HeadRepoID ,
HeadBranch : pull . BaseBranch ,
BaseBranch : pull . HeadBranch ,
}
2020-05-17 03:48:30 +03:00
err = pr . LoadProtectedBranch ( )
if err != nil {
2021-08-31 17:03:45 +03:00
return false , false , err
}
// can't do rebase on protected branch because need force push
if pr . ProtectedBranch == nil {
2022-03-04 11:30:49 +03:00
prUnit , err := pr . BaseRepo . GetUnit ( unit . TypePullRequests )
if err != nil {
log . Error ( "pr.BaseRepo.GetUnit(unit.TypePullRequests): %v" , err )
return false , false , err
}
rebaseAllowed = prUnit . PullRequestsConfig ( ) . AllowRebaseUpdate
2020-05-17 03:48:30 +03:00
}
// Update function need push permission
if pr . ProtectedBranch != nil && ! pr . ProtectedBranch . CanUserPush ( user . ID ) {
2021-08-31 17:03:45 +03:00
return false , false , nil
}
2022-05-11 13:09:36 +03:00
baseRepoPerm , err := access_model . GetUserRepoPermission ( ctx , pull . BaseRepo , user )
2022-04-28 18:45:33 +03:00
if err != nil {
return false , false , err
}
2022-05-03 22:46:28 +03:00
mergeAllowed , err = IsUserAllowedToMerge ( ctx , pr , headRepoPerm , user )
2021-08-31 17:03:45 +03:00
if err != nil {
return false , false , err
2020-05-17 03:48:30 +03:00
}
2022-04-28 18:45:33 +03:00
if pull . AllowMaintainerEdit {
2022-05-03 22:46:28 +03:00
mergeAllowedMaintainer , err := IsUserAllowedToMerge ( ctx , pr , baseRepoPerm , user )
2022-04-28 18:45:33 +03:00
if err != nil {
return false , false , err
}
mergeAllowed = mergeAllowed || mergeAllowedMaintainer
}
2021-08-31 17:03:45 +03:00
return mergeAllowed , rebaseAllowed , nil
2020-01-17 09:03:40 +03:00
}
// GetDiverging determines how many commits a PR is ahead or behind the PR base branch
2022-06-13 12:37:59 +03:00
func GetDiverging ( ctx context . Context , pr * issues_model . PullRequest ) ( * git . DivergeObject , error ) {
2020-04-01 22:03:08 +03:00
log . Trace ( "GetDiverging[%d]: compare commits" , pr . ID )
2022-04-28 14:48:48 +03:00
if err := pr . LoadBaseRepoCtx ( ctx ) ; err != nil {
2020-01-17 09:03:40 +03:00
return nil , err
}
2022-04-28 14:48:48 +03:00
if err := pr . LoadHeadRepoCtx ( ctx ) ; err != nil {
2020-01-17 09:03:40 +03:00
return nil , err
}
2022-01-20 02:26:57 +03:00
tmpRepo , err := createTemporaryRepo ( ctx , pr )
2020-01-17 09:03:40 +03:00
if err != nil {
2021-07-13 02:26:25 +03:00
if ! models . IsErrBranchDoesNotExist ( err ) {
log . Error ( "CreateTemporaryRepo: %v" , err )
}
2020-04-01 22:03:08 +03:00
return nil , err
2020-01-17 09:03:40 +03:00
}
defer func ( ) {
2022-05-08 19:46:32 +03:00
if err := repo_module . RemoveTemporaryPath ( tmpRepo ) ; err != nil {
2020-04-01 22:03:08 +03:00
log . Error ( "Merge: RemoveTemporaryPath: %s" , err )
2020-01-17 09:03:40 +03:00
}
} ( )
2022-01-20 02:26:57 +03:00
diff , err := git . GetDivergingCommits ( ctx , tmpRepo , "base" , "tracking" )
2020-04-01 22:03:08 +03:00
return & diff , err
2020-01-17 09:03:40 +03:00
}