2014-03-24 14:25:15 +04:00
// Copyright 2014 The Gogs 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 repo
import (
2015-09-02 16:26:56 +03:00
"container/list"
2016-10-12 16:28:51 +03:00
"fmt"
2015-09-02 02:07:02 +03:00
"path"
2015-08-08 17:43:14 +03:00
"strings"
2016-11-11 15:11:45 +03:00
"code.gitea.io/git"
2016-11-10 19:24:48 +03:00
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/auth"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log"
2017-01-28 18:59:58 +03:00
"code.gitea.io/gitea/modules/notification"
2016-11-10 19:24:48 +03:00
"code.gitea.io/gitea/modules/setting"
2017-01-28 18:59:58 +03:00
2016-11-11 15:11:45 +03:00
"github.com/Unknwon/com"
2014-03-24 14:25:15 +04:00
)
2014-06-23 07:11:12 +04:00
const (
2016-11-24 10:04:31 +03:00
tplFork base . TplName = "repo/pulls/fork"
tplComparePull base . TplName = "repo/pulls/compare"
tplPullCommits base . TplName = "repo/pulls/commits"
tplPullFiles base . TplName = "repo/pulls/files"
2016-02-18 01:21:31 +03:00
2016-11-24 10:04:31 +03:00
pullRequestTemplateKey = "PullRequestTemplate"
2016-02-18 01:21:31 +03:00
)
var (
2016-11-24 10:04:31 +03:00
pullRequestTemplateCandidates = [ ] string {
2017-01-05 03:48:23 +03:00
"PULL_REQUEST_TEMPLATE.md" ,
"pull_request_template.md" ,
".gitea/PULL_REQUEST_TEMPLATE.md" ,
".gitea/pull_request_template.md" ,
".github/PULL_REQUEST_TEMPLATE.md" ,
".github/pull_request_template.md" ,
2016-02-18 01:21:31 +03:00
}
2014-06-23 07:11:12 +04:00
)
2016-03-11 19:56:52 +03:00
func getForkRepository ( ctx * context . Context ) * models . Repository {
2015-08-08 17:43:14 +03:00
forkRepo , err := models . GetRepositoryByID ( ctx . ParamsInt64 ( ":repoid" ) )
2015-08-08 12:10:34 +03:00
if err != nil {
if models . IsErrRepoNotExist ( err ) {
2015-08-08 17:43:14 +03:00
ctx . Handle ( 404 , "GetRepositoryByID" , nil )
2015-08-08 12:10:34 +03:00
} else {
2015-08-08 17:43:14 +03:00
ctx . Handle ( 500 , "GetRepositoryByID" , err )
2015-08-08 12:10:34 +03:00
}
return nil
}
2015-09-01 18:57:02 +03:00
2017-01-03 07:41:10 +03:00
if ! forkRepo . CanBeForked ( ) || ! forkRepo . HasAccess ( ctx . User ) {
2015-09-05 21:31:52 +03:00
ctx . Handle ( 404 , "getForkRepository" , nil )
2015-09-01 18:57:02 +03:00
return nil
}
2015-08-08 12:10:34 +03:00
ctx . Data [ "repo_name" ] = forkRepo . Name
2015-11-18 23:11:37 +03:00
ctx . Data [ "description" ] = forkRepo . Description
2015-08-08 12:10:34 +03:00
ctx . Data [ "IsPrivate" ] = forkRepo . IsPrivate
if err = forkRepo . GetOwner ( ) ; err != nil {
ctx . Handle ( 500 , "GetOwner" , err )
return nil
}
ctx . Data [ "ForkFrom" ] = forkRepo . Owner . Name + "/" + forkRepo . Name
2016-12-01 13:51:50 +03:00
ctx . Data [ "ForkFromOwnerID" ] = forkRepo . Owner . ID
2015-08-08 12:10:34 +03:00
2015-12-17 10:28:47 +03:00
if err := ctx . User . GetOrganizations ( true ) ; err != nil {
2015-08-08 12:10:34 +03:00
ctx . Handle ( 500 , "GetOrganizations" , err )
return nil
}
ctx . Data [ "Orgs" ] = ctx . User . Orgs
return forkRepo
}
2016-11-24 10:04:31 +03:00
// Fork render repository fork page
2016-03-11 19:56:52 +03:00
func Fork ( ctx * context . Context ) {
2015-08-08 12:10:34 +03:00
ctx . Data [ "Title" ] = ctx . Tr ( "new_fork" )
getForkRepository ( ctx )
if ctx . Written ( ) {
return
}
ctx . Data [ "ContextUser" ] = ctx . User
2016-11-24 10:04:31 +03:00
ctx . HTML ( 200 , tplFork )
2015-08-08 12:10:34 +03:00
}
2016-11-24 10:04:31 +03:00
// ForkPost response for forking a repository
2016-03-11 19:56:52 +03:00
func ForkPost ( ctx * context . Context , form auth . CreateRepoForm ) {
2015-08-08 12:10:34 +03:00
ctx . Data [ "Title" ] = ctx . Tr ( "new_fork" )
forkRepo := getForkRepository ( ctx )
if ctx . Written ( ) {
return
}
2016-11-27 09:03:59 +03:00
ctxUser := checkContextUser ( ctx , form . UID )
2015-08-08 12:10:34 +03:00
if ctx . Written ( ) {
return
}
ctx . Data [ "ContextUser" ] = ctxUser
if ctx . HasError ( ) {
2016-11-24 10:04:31 +03:00
ctx . HTML ( 200 , tplFork )
2015-08-08 12:10:34 +03:00
return
}
// Check ownership of organization.
if ctxUser . IsOrganization ( ) {
2016-07-23 20:08:22 +03:00
if ! ctxUser . IsOwnedBy ( ctx . User . ID ) {
2015-08-08 12:10:34 +03:00
ctx . Error ( 403 )
return
}
}
repo , err := models . ForkRepository ( ctxUser , forkRepo , form . RepoName , form . Description )
if err != nil {
2015-08-31 10:24:28 +03:00
ctx . Data [ "Err_RepoName" ] = true
2015-08-08 12:10:34 +03:00
switch {
case models . IsErrRepoAlreadyExist ( err ) :
2016-11-24 10:04:31 +03:00
ctx . RenderWithErr ( ctx . Tr ( "repo.settings.new_owner_has_same_repo" ) , tplFork , & form )
2015-08-08 12:10:34 +03:00
case models . IsErrNameReserved ( err ) :
2016-11-24 10:04:31 +03:00
ctx . RenderWithErr ( ctx . Tr ( "repo.form.name_reserved" , err . ( models . ErrNameReserved ) . Name ) , tplFork , & form )
2015-08-08 12:10:34 +03:00
case models . IsErrNamePatternNotAllowed ( err ) :
2016-11-24 10:04:31 +03:00
ctx . RenderWithErr ( ctx . Tr ( "repo.form.name_pattern_not_allowed" , err . ( models . ErrNamePatternNotAllowed ) . Pattern ) , tplFork , & form )
2015-08-08 12:10:34 +03:00
default :
ctx . Handle ( 500 , "ForkPost" , err )
}
return
}
2015-08-08 17:43:14 +03:00
log . Trace ( "Repository forked[%d]: %s/%s" , forkRepo . ID , ctxUser . Name , repo . Name )
2016-11-27 13:14:25 +03:00
ctx . Redirect ( setting . AppSubURL + "/" + ctxUser . Name + "/" + repo . Name )
2015-08-08 12:10:34 +03:00
}
2016-03-11 19:56:52 +03:00
func checkPullInfo ( ctx * context . Context ) * models . Issue {
2015-10-19 02:30:39 +03:00
issue , err := models . GetIssueByIndex ( ctx . Repo . Repository . ID , ctx . ParamsInt64 ( ":index" ) )
2015-09-02 11:08:05 +03:00
if err != nil {
if models . IsErrIssueNotExist ( err ) {
ctx . Handle ( 404 , "GetIssueByIndex" , err )
} else {
ctx . Handle ( 500 , "GetIssueByIndex" , err )
}
return nil
}
2016-10-12 16:28:51 +03:00
ctx . Data [ "Title" ] = fmt . Sprintf ( "#%d - %s" , issue . Index , issue . Title )
2015-10-19 02:30:39 +03:00
ctx . Data [ "Issue" ] = issue
2015-09-02 11:08:05 +03:00
2015-10-19 02:30:39 +03:00
if ! issue . IsPull {
2015-09-02 11:08:05 +03:00
ctx . Handle ( 404 , "ViewPullCommits" , nil )
return nil
}
2016-08-16 20:19:09 +03:00
if err = issue . PullRequest . GetHeadRepo ( ) ; err != nil {
2015-10-24 10:36:47 +03:00
ctx . Handle ( 500 , "GetHeadRepo" , err )
return nil
2015-09-02 11:08:05 +03:00
}
if ctx . IsSigned {
// Update issue-user.
2016-07-23 20:08:22 +03:00
if err = issue . ReadBy ( ctx . User . ID ) ; err != nil {
2015-09-02 11:08:05 +03:00
ctx . Handle ( 500 , "ReadBy" , err )
return nil
}
}
2015-10-19 02:30:39 +03:00
return issue
2015-09-02 11:08:05 +03:00
}
2016-11-24 10:04:31 +03:00
// PrepareMergedViewPullInfo show meta information for a merged pull request view page
2016-08-16 20:19:09 +03:00
func PrepareMergedViewPullInfo ( ctx * context . Context , issue * models . Issue ) {
pull := issue . PullRequest
2015-09-02 16:26:56 +03:00
ctx . Data [ "HasMerged" ] = true
2016-08-16 20:19:09 +03:00
ctx . Data [ "HeadTarget" ] = issue . PullRequest . HeadUserName + "/" + pull . HeadBranch
2015-09-02 16:26:56 +03:00
ctx . Data [ "BaseTarget" ] = ctx . Repo . Owner . Name + "/" + pull . BaseBranch
2016-08-14 13:32:24 +03:00
var err error
2015-09-02 16:26:56 +03:00
ctx . Data [ "NumCommits" ] , err = ctx . Repo . GitRepo . CommitsCountBetween ( pull . MergeBase , pull . MergedCommitID )
if err != nil {
ctx . Handle ( 500 , "Repo.GitRepo.CommitsCountBetween" , err )
return
}
ctx . Data [ "NumFiles" ] , err = ctx . Repo . GitRepo . FilesCountBetween ( pull . MergeBase , pull . MergedCommitID )
if err != nil {
ctx . Handle ( 500 , "Repo.GitRepo.FilesCountBetween" , err )
return
}
}
2016-11-24 10:04:31 +03:00
// PrepareViewPullInfo show meta information for a pull request preview page
2016-08-16 20:19:09 +03:00
func PrepareViewPullInfo ( ctx * context . Context , issue * models . Issue ) * git . PullRequestInfo {
2015-09-02 11:08:05 +03:00
repo := ctx . Repo . Repository
2016-08-16 20:19:09 +03:00
pull := issue . PullRequest
2015-09-02 11:08:05 +03:00
2015-10-19 02:30:39 +03:00
ctx . Data [ "HeadTarget" ] = pull . HeadUserName + "/" + pull . HeadBranch
2015-09-02 12:09:12 +03:00
ctx . Data [ "BaseTarget" ] = ctx . Repo . Owner . Name + "/" + pull . BaseBranch
2015-09-02 11:08:05 +03:00
2015-10-05 03:54:06 +03:00
var (
headGitRepo * git . Repository
err error
)
2015-10-24 10:36:47 +03:00
if err = pull . GetHeadRepo ( ) ; err != nil {
ctx . Handle ( 500 , "GetHeadRepo" , err )
return nil
}
2015-10-05 03:54:06 +03:00
if pull . HeadRepo != nil {
2015-11-27 01:33:45 +03:00
headGitRepo , err = git . OpenRepository ( pull . HeadRepo . RepoPath ( ) )
2015-10-05 03:54:06 +03:00
if err != nil {
ctx . Handle ( 500 , "OpenRepository" , err )
return nil
}
2015-09-02 11:08:05 +03:00
}
2015-10-19 02:30:39 +03:00
if pull . HeadRepo == nil || ! headGitRepo . IsBranchExist ( pull . HeadBranch ) {
2015-09-02 16:26:56 +03:00
ctx . Data [ "IsPullReuqestBroken" ] = true
ctx . Data [ "HeadTarget" ] = "deleted"
ctx . Data [ "NumCommits" ] = 0
ctx . Data [ "NumFiles" ] = 0
return nil
}
2015-09-02 11:08:05 +03:00
prInfo , err := headGitRepo . GetPullRequestInfo ( models . RepoPath ( repo . Owner . Name , repo . Name ) ,
2015-10-19 02:30:39 +03:00
pull . BaseBranch , pull . HeadBranch )
2015-09-02 11:08:05 +03:00
if err != nil {
2016-07-23 13:35:16 +03:00
if strings . Contains ( err . Error ( ) , "fatal: Not a valid object name" ) {
ctx . Data [ "IsPullReuqestBroken" ] = true
ctx . Data [ "BaseTarget" ] = "deleted"
ctx . Data [ "NumCommits" ] = 0
ctx . Data [ "NumFiles" ] = 0
return nil
}
2015-09-02 11:08:05 +03:00
ctx . Handle ( 500 , "GetPullRequestInfo" , err )
return nil
}
ctx . Data [ "NumCommits" ] = prInfo . Commits . Len ( )
ctx . Data [ "NumFiles" ] = prInfo . NumFiles
return prInfo
}
2016-11-24 10:04:31 +03:00
// ViewPullCommits show commits for a pull request
2016-03-11 19:56:52 +03:00
func ViewPullCommits ( ctx * context . Context ) {
2016-08-14 13:32:24 +03:00
ctx . Data [ "PageIsPullList" ] = true
2015-09-02 11:08:05 +03:00
ctx . Data [ "PageIsPullCommits" ] = true
2016-08-16 20:19:09 +03:00
issue := checkPullInfo ( ctx )
2015-09-02 11:08:05 +03:00
if ctx . Written ( ) {
return
}
2016-08-16 20:19:09 +03:00
pull := issue . PullRequest
2015-09-02 16:26:56 +03:00
ctx . Data [ "Username" ] = pull . HeadUserName
ctx . Data [ "Reponame" ] = pull . HeadRepo . Name
2015-09-02 11:08:05 +03:00
2015-09-02 16:26:56 +03:00
var commits * list . List
if pull . HasMerged {
2016-08-16 20:19:09 +03:00
PrepareMergedViewPullInfo ( ctx , issue )
2015-09-02 16:26:56 +03:00
if ctx . Written ( ) {
return
}
startCommit , err := ctx . Repo . GitRepo . GetCommit ( pull . MergeBase )
if err != nil {
ctx . Handle ( 500 , "Repo.GitRepo.GetCommit" , err )
return
}
endCommit , err := ctx . Repo . GitRepo . GetCommit ( pull . MergedCommitID )
if err != nil {
ctx . Handle ( 500 , "Repo.GitRepo.GetCommit" , err )
return
}
commits , err = ctx . Repo . GitRepo . CommitsBetween ( endCommit , startCommit )
if err != nil {
ctx . Handle ( 500 , "Repo.GitRepo.CommitsBetween" , err )
return
}
} else {
2016-08-16 20:19:09 +03:00
prInfo := PrepareViewPullInfo ( ctx , issue )
2015-09-02 16:26:56 +03:00
if ctx . Written ( ) {
return
} else if prInfo == nil {
ctx . Handle ( 404 , "ViewPullCommits" , nil )
return
}
commits = prInfo . Commits
2015-09-02 11:08:05 +03:00
}
2015-09-02 16:26:56 +03:00
commits = models . ValidateCommitsWithEmails ( commits )
ctx . Data [ "Commits" ] = commits
ctx . Data [ "CommitCount" ] = commits . Len ( )
2016-11-24 10:04:31 +03:00
ctx . HTML ( 200 , tplPullCommits )
2015-09-02 11:08:05 +03:00
}
2016-11-24 10:04:31 +03:00
// ViewPullFiles render pull request changed files list page
2016-03-11 19:56:52 +03:00
func ViewPullFiles ( ctx * context . Context ) {
2016-08-14 13:32:24 +03:00
ctx . Data [ "PageIsPullList" ] = true
2015-09-02 11:08:05 +03:00
ctx . Data [ "PageIsPullFiles" ] = true
2016-08-16 20:19:09 +03:00
issue := checkPullInfo ( ctx )
2015-09-02 11:08:05 +03:00
if ctx . Written ( ) {
return
}
2016-08-16 20:19:09 +03:00
pull := issue . PullRequest
2015-09-02 11:08:05 +03:00
2015-09-02 16:26:56 +03:00
var (
diffRepoPath string
startCommitID string
endCommitID string
gitRepo * git . Repository
)
if pull . HasMerged {
2016-08-16 20:19:09 +03:00
PrepareMergedViewPullInfo ( ctx , issue )
2015-09-02 16:26:56 +03:00
if ctx . Written ( ) {
return
}
2015-09-02 11:08:05 +03:00
2015-09-02 16:26:56 +03:00
diffRepoPath = ctx . Repo . GitRepo . Path
startCommitID = pull . MergeBase
endCommitID = pull . MergedCommitID
gitRepo = ctx . Repo . GitRepo
} else {
2016-08-16 20:19:09 +03:00
prInfo := PrepareViewPullInfo ( ctx , issue )
2015-09-02 16:26:56 +03:00
if ctx . Written ( ) {
return
} else if prInfo == nil {
ctx . Handle ( 404 , "ViewPullFiles" , nil )
return
}
2015-09-02 11:08:05 +03:00
2015-09-02 16:26:56 +03:00
headRepoPath := models . RepoPath ( pull . HeadUserName , pull . HeadRepo . Name )
2015-09-02 11:08:05 +03:00
2015-09-02 16:26:56 +03:00
headGitRepo , err := git . OpenRepository ( headRepoPath )
if err != nil {
ctx . Handle ( 500 , "OpenRepository" , err )
return
}
2015-12-10 04:46:05 +03:00
headCommitID , err := headGitRepo . GetBranchCommitID ( pull . HeadBranch )
2015-09-02 16:26:56 +03:00
if err != nil {
2015-12-10 04:46:05 +03:00
ctx . Handle ( 500 , "GetBranchCommitID" , err )
2015-09-02 16:26:56 +03:00
return
}
diffRepoPath = headRepoPath
startCommitID = prInfo . MergeBase
endCommitID = headCommitID
gitRepo = headGitRepo
2015-09-02 11:08:05 +03:00
}
2015-09-02 16:26:56 +03:00
diff , err := models . GetDiffRange ( diffRepoPath ,
2016-06-29 18:11:00 +03:00
startCommitID , endCommitID , setting . Git . MaxGitDiffLines ,
setting . Git . MaxGitDiffLineCharacters , setting . Git . MaxGitDiffFiles )
2015-09-02 11:08:05 +03:00
if err != nil {
ctx . Handle ( 500 , "GetDiffRange" , err )
return
}
ctx . Data [ "Diff" ] = diff
ctx . Data [ "DiffNotAvailable" ] = diff . NumFiles ( ) == 0
2015-09-02 16:26:56 +03:00
commit , err := gitRepo . GetCommit ( endCommitID )
2015-09-02 11:08:05 +03:00
if err != nil {
ctx . Handle ( 500 , "GetCommit" , err )
return
}
2015-09-02 12:09:12 +03:00
headTarget := path . Join ( pull . HeadUserName , pull . HeadRepo . Name )
ctx . Data [ "Username" ] = pull . HeadUserName
ctx . Data [ "Reponame" ] = pull . HeadRepo . Name
2015-09-02 16:26:56 +03:00
ctx . Data [ "IsImageFile" ] = commit . IsImageFile
2016-11-27 13:14:25 +03:00
ctx . Data [ "SourcePath" ] = setting . AppSubURL + "/" + path . Join ( headTarget , "src" , endCommitID )
ctx . Data [ "BeforeSourcePath" ] = setting . AppSubURL + "/" + path . Join ( headTarget , "src" , startCommitID )
ctx . Data [ "RawPath" ] = setting . AppSubURL + "/" + path . Join ( headTarget , "raw" , endCommitID )
2016-01-31 19:19:02 +03:00
ctx . Data [ "RequireHighlightJS" ] = true
2015-09-02 11:08:05 +03:00
2016-11-24 10:04:31 +03:00
ctx . HTML ( 200 , tplPullFiles )
2015-09-02 11:08:05 +03:00
}
2015-08-31 10:24:28 +03:00
2016-11-24 10:04:31 +03:00
// MergePullRequest response for merging pull request
2016-03-11 19:56:52 +03:00
func MergePullRequest ( ctx * context . Context ) {
2015-10-19 02:30:39 +03:00
issue := checkPullInfo ( ctx )
2015-09-02 16:26:56 +03:00
if ctx . Written ( ) {
return
}
2015-10-19 02:30:39 +03:00
if issue . IsClosed {
2015-09-02 16:26:56 +03:00
ctx . Handle ( 404 , "MergePullRequest" , nil )
return
}
2015-10-19 02:30:39 +03:00
pr , err := models . GetPullRequestByIssueID ( issue . ID )
2015-09-02 16:26:56 +03:00
if err != nil {
if models . IsErrPullRequestNotExist ( err ) {
2015-10-19 02:30:39 +03:00
ctx . Handle ( 404 , "GetPullRequestByIssueID" , nil )
2015-09-02 16:26:56 +03:00
} else {
2015-10-19 02:30:39 +03:00
ctx . Handle ( 500 , "GetPullRequestByIssueID" , err )
2015-09-02 16:26:56 +03:00
}
return
}
2015-10-19 00:18:45 +03:00
if ! pr . CanAutoMerge ( ) || pr . HasMerged {
2015-09-02 16:26:56 +03:00
ctx . Handle ( 404 , "MergePullRequest" , nil )
return
}
2015-10-19 02:30:39 +03:00
pr . Issue = issue
pr . Issue . Repo = ctx . Repo . Repository
2015-09-02 18:13:37 +03:00
if err = pr . Merge ( ctx . User , ctx . Repo . GitRepo ) ; err != nil {
2015-10-19 02:30:39 +03:00
ctx . Handle ( 500 , "Merge" , err )
2015-09-02 16:26:56 +03:00
return
}
2017-01-28 18:59:58 +03:00
notification . Service . NotifyIssue ( pr . Issue , ctx . User . ID )
2015-09-02 16:26:56 +03:00
log . Trace ( "Pull request merged: %d" , pr . ID )
2015-10-19 02:30:39 +03:00
ctx . Redirect ( ctx . Repo . RepoLink + "/pulls/" + com . ToStr ( pr . Index ) )
2015-09-02 16:26:56 +03:00
}
2016-11-24 10:04:31 +03:00
// ParseCompareInfo parse compare info between two commit for preparing pull request
2016-03-11 19:56:52 +03:00
func ParseCompareInfo ( ctx * context . Context ) ( * models . User , * models . Repository , * git . Repository , * git . PullRequestInfo , string , string ) {
2016-03-05 00:14:02 +03:00
baseRepo := ctx . Repo . Repository
2016-03-04 23:43:01 +03:00
// Get compared branches information
// format: <base branch>...[<head repo>:]<head branch>
// base<-head: master...head:feature
// same repo: master...feature
2015-08-08 17:43:14 +03:00
infos := strings . Split ( ctx . Params ( "*" ) , "..." )
if len ( infos ) != 2 {
2016-03-05 00:14:02 +03:00
log . Trace ( "ParseCompareInfo[%d]: not enough compared branches information %s" , baseRepo . ID , infos )
2015-08-08 17:43:14 +03:00
ctx . Handle ( 404 , "CompareAndPullRequest" , nil )
2015-09-02 02:07:02 +03:00
return nil , nil , nil , nil , "" , ""
2015-08-08 17:43:14 +03:00
}
baseBranch := infos [ 0 ]
ctx . Data [ "BaseBranch" ] = baseBranch
2016-03-04 23:43:01 +03:00
var (
headUser * models . User
headBranch string
isSameRepo bool
err error
)
// If there is no head repository, it means pull request between same repository.
2015-08-08 17:43:14 +03:00
headInfos := strings . Split ( infos [ 1 ] , ":" )
2016-03-04 23:43:01 +03:00
if len ( headInfos ) == 1 {
isSameRepo = true
headUser = ctx . Repo . Owner
headBranch = headInfos [ 0 ]
2015-08-08 17:43:14 +03:00
2016-03-04 23:43:01 +03:00
} else if len ( headInfos ) == 2 {
headUser , err = models . GetUserByName ( headInfos [ 0 ] )
if err != nil {
if models . IsErrUserNotExist ( err ) {
ctx . Handle ( 404 , "GetUserByName" , nil )
} else {
ctx . Handle ( 500 , "GetUserByName" , err )
}
return nil , nil , nil , nil , "" , ""
2015-09-02 02:07:02 +03:00
}
2016-03-04 23:43:01 +03:00
headBranch = headInfos [ 1 ]
2017-03-03 11:53:59 +03:00
isSameRepo = headUser . ID == ctx . Repo . Owner . ID
2016-03-04 23:43:01 +03:00
} else {
ctx . Handle ( 404 , "CompareAndPullRequest" , nil )
2015-09-02 02:07:02 +03:00
return nil , nil , nil , nil , "" , ""
}
2015-12-20 09:06:54 +03:00
ctx . Data [ "HeadUser" ] = headUser
2016-03-04 23:43:01 +03:00
ctx . Data [ "HeadBranch" ] = headBranch
2016-03-07 07:57:46 +03:00
ctx . Repo . PullRequest . SameRepo = isSameRepo
2015-09-02 02:07:02 +03:00
// Check if base branch is valid.
if ! ctx . Repo . GitRepo . IsBranchExist ( baseBranch ) {
ctx . Handle ( 404 , "IsBranchExist" , nil )
return nil , nil , nil , nil , "" , ""
}
2015-08-08 17:43:14 +03:00
2016-03-04 23:43:01 +03:00
// Check if current user has fork of repository or in the same repository.
2016-07-23 20:08:22 +03:00
headRepo , has := models . HasForkedRepo ( headUser . ID , baseRepo . ID )
2016-03-05 00:14:02 +03:00
if ! has && ! isSameRepo {
log . Trace ( "ParseCompareInfo[%d]: does not have fork or in same repository" , baseRepo . ID )
ctx . Handle ( 404 , "ParseCompareInfo" , nil )
2015-09-02 02:07:02 +03:00
return nil , nil , nil , nil , "" , ""
2015-08-08 17:43:14 +03:00
}
2016-03-04 23:43:01 +03:00
var headGitRepo * git . Repository
if isSameRepo {
headRepo = ctx . Repo . Repository
headGitRepo = ctx . Repo . GitRepo
} else {
headGitRepo , err = git . OpenRepository ( models . RepoPath ( headUser . Name , headRepo . Name ) )
if err != nil {
ctx . Handle ( 500 , "OpenRepository" , err )
return nil , nil , nil , nil , "" , ""
}
2015-09-02 02:07:02 +03:00
}
2016-03-06 04:45:23 +03:00
if ! ctx . User . IsWriterOfRepo ( headRepo ) && ! ctx . User . IsAdmin {
2016-03-05 00:14:02 +03:00
log . Trace ( "ParseCompareInfo[%d]: does not have write access or site admin" , baseRepo . ID )
ctx . Handle ( 404 , "ParseCompareInfo" , nil )
return nil , nil , nil , nil , "" , ""
}
2015-09-02 02:07:02 +03:00
// Check if head branch is valid.
if ! headGitRepo . IsBranchExist ( headBranch ) {
ctx . Handle ( 404 , "IsBranchExist" , nil )
return nil , nil , nil , nil , "" , ""
2015-08-08 17:43:14 +03:00
}
2015-09-02 02:07:02 +03:00
2015-08-08 17:43:14 +03:00
headBranches , err := headGitRepo . GetBranches ( )
if err != nil {
ctx . Handle ( 500 , "GetBranches" , err )
2015-09-02 02:07:02 +03:00
return nil , nil , nil , nil , "" , ""
2015-08-08 17:43:14 +03:00
}
ctx . Data [ "HeadBranches" ] = headBranches
2016-03-05 00:14:02 +03:00
prInfo , err := headGitRepo . GetPullRequestInfo ( models . RepoPath ( baseRepo . Owner . Name , baseRepo . Name ) , baseBranch , headBranch )
2015-09-02 02:07:02 +03:00
if err != nil {
ctx . Handle ( 500 , "GetPullRequestInfo" , err )
return nil , nil , nil , nil , "" , ""
}
ctx . Data [ "BeforeCommitID" ] = prInfo . MergeBase
return headUser , headRepo , headGitRepo , prInfo , baseBranch , headBranch
}
2016-11-24 10:04:31 +03:00
// PrepareCompareDiff render pull request preview diff page
2015-09-02 02:07:02 +03:00
func PrepareCompareDiff (
2016-03-11 19:56:52 +03:00
ctx * context . Context ,
2015-09-02 02:07:02 +03:00
headUser * models . User ,
headRepo * models . Repository ,
headGitRepo * git . Repository ,
prInfo * git . PullRequestInfo ,
2015-09-02 12:09:12 +03:00
baseBranch , headBranch string ) bool {
2015-09-02 02:07:02 +03:00
var (
repo = ctx . Repo . Repository
err error
)
// Get diff information.
2016-07-15 16:53:43 +03:00
ctx . Data [ "CommitRepoLink" ] = headRepo . Link ( )
2015-09-02 02:07:02 +03:00
2015-12-10 04:46:05 +03:00
headCommitID , err := headGitRepo . GetBranchCommitID ( headBranch )
2015-09-02 02:07:02 +03:00
if err != nil {
2015-12-10 04:46:05 +03:00
ctx . Handle ( 500 , "GetBranchCommitID" , err )
2015-09-02 12:09:12 +03:00
return false
2015-09-02 02:07:02 +03:00
}
ctx . Data [ "AfterCommitID" ] = headCommitID
2015-09-02 12:09:12 +03:00
if headCommitID == prInfo . MergeBase {
ctx . Data [ "IsNothingToCompare" ] = true
return true
}
2015-09-02 02:07:02 +03:00
diff , err := models . GetDiffRange ( models . RepoPath ( headUser . Name , headRepo . Name ) ,
2016-06-29 18:11:00 +03:00
prInfo . MergeBase , headCommitID , setting . Git . MaxGitDiffLines ,
setting . Git . MaxGitDiffLineCharacters , setting . Git . MaxGitDiffFiles )
2015-09-02 02:07:02 +03:00
if err != nil {
ctx . Handle ( 500 , "GetDiffRange" , err )
2015-09-02 12:09:12 +03:00
return false
2015-09-02 02:07:02 +03:00
}
ctx . Data [ "Diff" ] = diff
ctx . Data [ "DiffNotAvailable" ] = diff . NumFiles ( ) == 0
headCommit , err := headGitRepo . GetCommit ( headCommitID )
if err != nil {
ctx . Handle ( 500 , "GetCommit" , err )
2015-09-02 12:09:12 +03:00
return false
2015-09-02 02:07:02 +03:00
}
prInfo . Commits = models . ValidateCommitsWithEmails ( prInfo . Commits )
ctx . Data [ "Commits" ] = prInfo . Commits
ctx . Data [ "CommitCount" ] = prInfo . Commits . Len ( )
ctx . Data [ "Username" ] = headUser . Name
ctx . Data [ "Reponame" ] = headRepo . Name
2015-09-02 11:08:05 +03:00
ctx . Data [ "IsImageFile" ] = headCommit . IsImageFile
headTarget := path . Join ( headUser . Name , repo . Name )
2016-11-27 13:14:25 +03:00
ctx . Data [ "SourcePath" ] = setting . AppSubURL + "/" + path . Join ( headTarget , "src" , headCommitID )
ctx . Data [ "BeforeSourcePath" ] = setting . AppSubURL + "/" + path . Join ( headTarget , "src" , prInfo . MergeBase )
ctx . Data [ "RawPath" ] = setting . AppSubURL + "/" + path . Join ( headTarget , "raw" , headCommitID )
2015-09-02 12:09:12 +03:00
return false
2015-09-02 02:07:02 +03:00
}
2016-11-24 10:04:31 +03:00
// CompareAndPullRequest render pull request preview page
2016-03-11 19:56:52 +03:00
func CompareAndPullRequest ( ctx * context . Context ) {
2015-09-02 02:07:02 +03:00
ctx . Data [ "Title" ] = ctx . Tr ( "repo.pulls.compare_changes" )
ctx . Data [ "PageIsComparePull" ] = true
ctx . Data [ "IsDiffCompare" ] = true
2016-01-31 19:19:02 +03:00
ctx . Data [ "RequireHighlightJS" ] = true
2016-11-24 10:04:31 +03:00
setTemplateIfExists ( ctx , pullRequestTemplateKey , pullRequestTemplateCandidates )
2015-09-02 02:07:02 +03:00
renderAttachmentSettings ( ctx )
headUser , headRepo , headGitRepo , prInfo , baseBranch , headBranch := ParseCompareInfo ( ctx )
if ctx . Written ( ) {
return
}
2015-10-19 02:30:39 +03:00
pr , err := models . GetUnmergedPullRequest ( headRepo . ID , ctx . Repo . Repository . ID , headBranch , baseBranch )
if err != nil {
if ! models . IsErrPullRequestNotExist ( err ) {
ctx . Handle ( 500 , "GetUnmergedPullRequest" , err )
return
}
} else {
ctx . Data [ "HasPullRequest" ] = true
ctx . Data [ "PullRequest" ] = pr
2016-11-24 10:04:31 +03:00
ctx . HTML ( 200 , tplComparePull )
2015-10-19 02:30:39 +03:00
return
}
2015-09-02 02:07:02 +03:00
2015-09-02 12:09:12 +03:00
nothingToCompare := PrepareCompareDiff ( ctx , headUser , headRepo , headGitRepo , prInfo , baseBranch , headBranch )
2015-08-31 10:24:28 +03:00
if ctx . Written ( ) {
return
}
2015-09-02 12:09:12 +03:00
if ! nothingToCompare {
// Setup information for new form.
RetrieveRepoMetas ( ctx , ctx . Repo . Repository )
if ctx . Written ( ) {
return
}
}
2016-11-24 10:04:31 +03:00
ctx . HTML ( 200 , tplComparePull )
2015-08-08 17:43:14 +03:00
}
2016-11-24 10:04:31 +03:00
// CompareAndPullRequestPost response for creating pull request
2016-03-11 19:56:52 +03:00
func CompareAndPullRequestPost ( ctx * context . Context , form auth . CreateIssueForm ) {
2015-09-02 02:07:02 +03:00
ctx . Data [ "Title" ] = ctx . Tr ( "repo.pulls.compare_changes" )
ctx . Data [ "PageIsComparePull" ] = true
ctx . Data [ "IsDiffCompare" ] = true
2016-08-16 00:04:44 +03:00
ctx . Data [ "RequireHighlightJS" ] = true
2015-09-02 02:07:02 +03:00
renderAttachmentSettings ( ctx )
var (
repo = ctx . Repo . Repository
attachments [ ] string
)
2015-09-02 02:26:39 +03:00
headUser , headRepo , headGitRepo , prInfo , baseBranch , headBranch := ParseCompareInfo ( ctx )
2015-09-02 02:07:02 +03:00
if ctx . Written ( ) {
return
}
labelIDs , milestoneID , assigneeID := ValidateRepoMetas ( ctx , form )
if ctx . Written ( ) {
return
}
if setting . AttachmentEnabled {
2016-08-11 15:48:08 +03:00
attachments = form . Files
2015-09-02 02:07:02 +03:00
}
if ctx . HasError ( ) {
2016-08-16 00:04:44 +03:00
auth . AssignForm ( form , ctx . Data )
// This stage is already stop creating new pull request, so it does not matter if it has
// something to compare or not.
PrepareCompareDiff ( ctx , headUser , headRepo , headGitRepo , prInfo , baseBranch , headBranch )
if ctx . Written ( ) {
return
}
2016-11-24 10:04:31 +03:00
ctx . HTML ( 200 , tplComparePull )
2015-09-02 02:07:02 +03:00
return
}
2016-08-16 00:04:44 +03:00
patch , err := headGitRepo . GetPatch ( prInfo . MergeBase , headBranch )
if err != nil {
ctx . Handle ( 500 , "GetPatch" , err )
return
}
2016-02-24 15:56:54 +03:00
pullIssue := & models . Issue {
2015-09-02 02:07:02 +03:00
RepoID : repo . ID ,
2015-09-03 10:49:50 +03:00
Index : repo . NextIssueIndex ( ) ,
2016-08-14 13:32:24 +03:00
Title : form . Title ,
2016-07-23 20:08:22 +03:00
PosterID : ctx . User . ID ,
2015-09-02 02:07:02 +03:00
Poster : ctx . User ,
MilestoneID : milestoneID ,
AssigneeID : assigneeID ,
IsPull : true ,
Content : form . Content ,
}
2016-02-24 15:56:54 +03:00
pullRequest := & models . PullRequest {
2015-09-02 02:26:39 +03:00
HeadRepoID : headRepo . ID ,
BaseRepoID : repo . ID ,
HeadUserName : headUser . Name ,
2015-10-19 02:30:39 +03:00
HeadBranch : headBranch ,
2015-09-02 02:26:39 +03:00
BaseBranch : baseBranch ,
2016-02-24 15:56:54 +03:00
HeadRepo : headRepo ,
BaseRepo : repo ,
2015-09-02 02:26:39 +03:00
MergeBase : prInfo . MergeBase ,
2016-11-07 18:37:32 +03:00
Type : models . PullRequestGitea ,
2016-02-24 15:56:54 +03:00
}
2016-08-16 00:04:44 +03:00
// FIXME: check error in the case two people send pull request at almost same time, give nice error prompt
// instead of 500.
2016-02-24 15:56:54 +03:00
if err := models . NewPullRequest ( repo , pullIssue , labelIDs , attachments , pullRequest , patch ) ; err != nil {
2015-09-02 02:07:02 +03:00
ctx . Handle ( 500 , "NewPullRequest" , err )
return
2016-03-04 23:43:01 +03:00
} else if err := pullRequest . PushToBaseRepo ( ) ; err != nil {
2016-02-24 15:56:54 +03:00
ctx . Handle ( 500 , "PushToBaseRepo" , err )
return
2015-12-10 19:18:56 +03:00
}
2017-01-28 18:59:58 +03:00
notification . Service . NotifyIssue ( pullIssue , ctx . User . ID )
2016-02-24 15:56:54 +03:00
log . Trace ( "Pull request created: %d/%d" , repo . ID , pullIssue . ID )
ctx . Redirect ( ctx . Repo . RepoLink + "/pulls/" + com . ToStr ( pullIssue . Index ) )
2014-03-24 14:25:15 +04:00
}
2015-10-24 10:36:47 +03:00
2016-11-24 10:04:31 +03:00
// TriggerTask response for a trigger task request
2016-03-11 19:56:52 +03:00
func TriggerTask ( ctx * context . Context ) {
2016-08-14 13:32:24 +03:00
pusherID := ctx . QueryInt64 ( "pusher" )
2015-12-15 01:06:54 +03:00
branch := ctx . Query ( "branch" )
secret := ctx . Query ( "secret" )
2016-08-14 13:32:24 +03:00
if len ( branch ) == 0 || len ( secret ) == 0 || pusherID <= 0 {
2015-12-15 01:06:54 +03:00
ctx . Error ( 404 )
2016-08-14 13:32:24 +03:00
log . Trace ( "TriggerTask: branch or secret is empty, or pusher ID is not valid" )
2015-12-15 01:06:54 +03:00
return
}
owner , repo := parseOwnerAndRepo ( ctx )
2015-10-24 10:36:47 +03:00
if ctx . Written ( ) {
return
}
2015-12-15 01:06:54 +03:00
if secret != base . EncodeMD5 ( owner . Salt ) {
ctx . Error ( 404 )
log . Trace ( "TriggerTask [%s/%s]: invalid secret" , owner . Name , repo . Name )
2015-10-24 10:36:47 +03:00
return
}
2016-08-14 13:32:24 +03:00
pusher , err := models . GetUserByID ( pusherID )
if err != nil {
if models . IsErrUserNotExist ( err ) {
ctx . Error ( 404 )
} else {
ctx . Handle ( 500 , "GetUserByID" , err )
}
return
}
log . Trace ( "TriggerTask '%s/%s' by %s" , repo . Name , branch , pusher . Name )
2015-10-24 10:36:47 +03:00
go models . HookQueue . Add ( repo . ID )
2016-08-14 13:32:24 +03:00
go models . AddTestPullRequestTask ( pusher , repo . ID , branch , true )
2015-10-24 10:36:47 +03:00
ctx . Status ( 202 )
}