2018-01-05 11:56:52 +01:00
// Copyright 2018 The Gitea Authors.
// Copyright 2014 The Gogs Authors.
// All rights reserved.
2014-03-24 18:25:15 +08:00
// 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 09:26:56 -04:00
"container/list"
2016-10-12 10:28:51 -03:00
"fmt"
2018-01-07 14:10:20 +01:00
"io"
2015-09-01 19:07:02 -04:00
"path"
2015-08-08 22:43:14 +08:00
"strings"
2016-11-10 17:24:48 +01:00
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/auth"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context"
2019-03-27 17:33:00 +08:00
"code.gitea.io/gitea/modules/git"
2016-11-10 17:24:48 +01:00
"code.gitea.io/gitea/modules/log"
2017-01-28 13:59:58 -02:00
"code.gitea.io/gitea/modules/notification"
2019-06-22 18:35:34 +01:00
"code.gitea.io/gitea/modules/pull"
2016-11-10 17:24:48 +01:00
"code.gitea.io/gitea/modules/setting"
2019-01-21 12:45:32 +01:00
"code.gitea.io/gitea/modules/util"
2017-01-28 13:59:58 -02:00
2016-11-11 13:11:45 +01:00
"github.com/Unknwon/com"
2014-03-24 18:25:15 +08:00
)
2014-06-22 23:11:12 -04:00
const (
2016-11-24 15:04:31 +08:00
tplFork base . TplName = "repo/pulls/fork"
2019-06-07 22:29:29 +02:00
tplCompareDiff base . TplName = "repo/diff/compare"
2016-11-24 15:04:31 +08:00
tplPullCommits base . TplName = "repo/pulls/commits"
tplPullFiles base . TplName = "repo/pulls/files"
2016-02-17 20:21:31 -02:00
2016-11-24 15:04:31 +08:00
pullRequestTemplateKey = "PullRequestTemplate"
2016-02-17 20:21:31 -02:00
)
var (
2016-11-24 15:04:31 +08:00
pullRequestTemplateCandidates = [ ] string {
2017-01-05 01:48:23 +01: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-17 20:21:31 -02:00
}
2014-06-22 23:11:12 -04:00
)
2016-03-11 11:56:52 -05:00
func getForkRepository ( ctx * context . Context ) * models . Repository {
2015-08-08 22:43:14 +08:00
forkRepo , err := models . GetRepositoryByID ( ctx . ParamsInt64 ( ":repoid" ) )
2015-08-08 17:10:34 +08:00
if err != nil {
if models . IsErrRepoNotExist ( err ) {
2018-01-10 22:34:17 +01:00
ctx . NotFound ( "GetRepositoryByID" , nil )
2015-08-08 17:10:34 +08:00
} else {
2018-01-10 22:34:17 +01:00
ctx . ServerError ( "GetRepositoryByID" , err )
2015-08-08 17:10:34 +08:00
}
return nil
}
2015-09-01 11:57:02 -04:00
2018-11-28 19:26:14 +08:00
perm , err := models . GetUserRepoPermission ( forkRepo , ctx . User )
if err != nil {
ctx . ServerError ( "GetUserRepoPermission" , err )
return nil
}
2019-01-18 00:01:04 +00:00
if forkRepo . IsEmpty || ! perm . CanRead ( models . UnitTypeCode ) {
2019-04-22 21:40:51 +01:00
if log . IsTrace ( ) {
if forkRepo . IsEmpty {
log . Trace ( "Empty fork repository %-v" , forkRepo )
} else {
log . Trace ( "Permission Denied: User %-v cannot read %-v of forkRepo %-v\n" +
"User in forkRepo has Permissions: %-+v" ,
ctx . User ,
models . UnitTypeCode ,
ctx . Repo ,
perm )
}
}
2018-01-10 22:34:17 +01:00
ctx . NotFound ( "getForkRepository" , nil )
2015-09-01 11:57:02 -04:00
return nil
}
2015-08-08 17:10:34 +08:00
ctx . Data [ "repo_name" ] = forkRepo . Name
2015-11-18 15:11:37 -05:00
ctx . Data [ "description" ] = forkRepo . Description
2015-08-08 17:10:34 +08:00
ctx . Data [ "IsPrivate" ] = forkRepo . IsPrivate
2017-10-15 18:06:07 +03:00
canForkToUser := forkRepo . OwnerID != ctx . User . ID && ! ctx . User . HasForkedRepo ( forkRepo . ID )
2015-08-08 17:10:34 +08:00
if err = forkRepo . GetOwner ( ) ; err != nil {
2018-01-10 22:34:17 +01:00
ctx . ServerError ( "GetOwner" , err )
2015-08-08 17:10:34 +08:00
return nil
}
ctx . Data [ "ForkFrom" ] = forkRepo . Owner . Name + "/" + forkRepo . Name
2016-12-01 18:51:50 +08:00
ctx . Data [ "ForkFromOwnerID" ] = forkRepo . Owner . ID
2015-08-08 17:10:34 +08:00
2017-10-15 18:06:07 +03:00
if err := ctx . User . GetOwnedOrganizations ( ) ; err != nil {
2018-01-10 22:34:17 +01:00
ctx . ServerError ( "GetOwnedOrganizations" , err )
2015-08-08 17:10:34 +08:00
return nil
}
2017-10-15 18:06:07 +03:00
var orgs [ ] * models . User
for _ , org := range ctx . User . OwnedOrgs {
if forkRepo . OwnerID != org . ID && ! org . HasForkedRepo ( forkRepo . ID ) {
orgs = append ( orgs , org )
}
}
2017-11-06 12:12:55 +08:00
var traverseParentRepo = forkRepo
for {
if ctx . User . ID == traverseParentRepo . OwnerID {
canForkToUser = false
} else {
for i , org := range orgs {
if org . ID == traverseParentRepo . OwnerID {
orgs = append ( orgs [ : i ] , orgs [ i + 1 : ] ... )
break
}
}
}
if ! traverseParentRepo . IsFork {
break
}
traverseParentRepo , err = models . GetRepositoryByID ( traverseParentRepo . ForkID )
if err != nil {
2018-01-10 22:34:17 +01:00
ctx . ServerError ( "GetRepositoryByID" , err )
2017-11-06 12:12:55 +08:00
return nil
}
}
ctx . Data [ "CanForkToUser" ] = canForkToUser
2017-10-15 18:06:07 +03:00
ctx . Data [ "Orgs" ] = orgs
if canForkToUser {
ctx . Data [ "ContextUser" ] = ctx . User
} else if len ( orgs ) > 0 {
ctx . Data [ "ContextUser" ] = orgs [ 0 ]
}
2015-08-08 17:10:34 +08:00
return forkRepo
}
2016-11-24 15:04:31 +08:00
// Fork render repository fork page
2016-03-11 11:56:52 -05:00
func Fork ( ctx * context . Context ) {
2015-08-08 17:10:34 +08:00
ctx . Data [ "Title" ] = ctx . Tr ( "new_fork" )
getForkRepository ( ctx )
if ctx . Written ( ) {
return
}
2016-11-24 15:04:31 +08:00
ctx . HTML ( 200 , tplFork )
2015-08-08 17:10:34 +08:00
}
2016-11-24 15:04:31 +08:00
// ForkPost response for forking a repository
2016-03-11 11:56:52 -05:00
func ForkPost ( ctx * context . Context , form auth . CreateRepoForm ) {
2015-08-08 17:10:34 +08:00
ctx . Data [ "Title" ] = ctx . Tr ( "new_fork" )
2017-10-15 18:06:07 +03:00
ctxUser := checkContextUser ( ctx , form . UID )
2015-08-08 17:10:34 +08:00
if ctx . Written ( ) {
return
}
2017-10-15 18:06:07 +03:00
forkRepo := getForkRepository ( ctx )
2015-08-08 17:10:34 +08:00
if ctx . Written ( ) {
return
}
2017-10-15 18:06:07 +03:00
2015-08-08 17:10:34 +08:00
ctx . Data [ "ContextUser" ] = ctxUser
if ctx . HasError ( ) {
2016-11-24 15:04:31 +08:00
ctx . HTML ( 200 , tplFork )
2015-08-08 17:10:34 +08:00
return
}
2017-11-06 12:12:55 +08:00
var err error
var traverseParentRepo = forkRepo
for {
if ctxUser . ID == traverseParentRepo . OwnerID {
ctx . RenderWithErr ( ctx . Tr ( "repo.settings.new_owner_has_same_repo" ) , tplFork , & form )
return
}
repo , has := models . HasForkedRepo ( ctxUser . ID , traverseParentRepo . ID )
if has {
ctx . Redirect ( setting . AppSubURL + "/" + ctxUser . Name + "/" + repo . Name )
return
}
if ! traverseParentRepo . IsFork {
break
}
traverseParentRepo , err = models . GetRepositoryByID ( traverseParentRepo . ForkID )
if err != nil {
2018-01-10 22:34:17 +01:00
ctx . ServerError ( "GetRepositoryByID" , err )
2017-11-06 12:12:55 +08:00
return
}
2017-07-26 09:17:38 +02:00
}
2015-08-08 17:10:34 +08:00
// Check ownership of organization.
if ctxUser . IsOrganization ( ) {
2017-12-20 23:43:26 -08:00
isOwner , err := ctxUser . IsOwnedBy ( ctx . User . ID )
if err != nil {
2018-01-10 22:34:17 +01:00
ctx . ServerError ( "IsOwnedBy" , err )
2017-12-20 23:43:26 -08:00
return
} else if ! isOwner {
2015-08-08 17:10:34 +08:00
ctx . Error ( 403 )
return
}
}
2017-09-03 01:20:24 -07:00
repo , err := models . ForkRepository ( ctx . User , ctxUser , forkRepo , form . RepoName , form . Description )
2015-08-08 17:10:34 +08:00
if err != nil {
2015-08-31 16:24:28 +09:00
ctx . Data [ "Err_RepoName" ] = true
2015-08-08 17:10:34 +08:00
switch {
case models . IsErrRepoAlreadyExist ( err ) :
2016-11-24 15:04:31 +08:00
ctx . RenderWithErr ( ctx . Tr ( "repo.settings.new_owner_has_same_repo" ) , tplFork , & form )
2015-08-08 17:10:34 +08:00
case models . IsErrNameReserved ( err ) :
2016-11-24 15:04:31 +08:00
ctx . RenderWithErr ( ctx . Tr ( "repo.form.name_reserved" , err . ( models . ErrNameReserved ) . Name ) , tplFork , & form )
2015-08-08 17:10:34 +08:00
case models . IsErrNamePatternNotAllowed ( err ) :
2016-11-24 15:04:31 +08:00
ctx . RenderWithErr ( ctx . Tr ( "repo.form.name_pattern_not_allowed" , err . ( models . ErrNamePatternNotAllowed ) . Pattern ) , tplFork , & form )
2015-08-08 17:10:34 +08:00
default :
2018-01-10 22:34:17 +01:00
ctx . ServerError ( "ForkPost" , err )
2015-08-08 17:10:34 +08:00
}
return
}
2015-08-08 22:43:14 +08:00
log . Trace ( "Repository forked[%d]: %s/%s" , forkRepo . ID , ctxUser . Name , repo . Name )
2016-11-27 18:14:25 +08:00
ctx . Redirect ( setting . AppSubURL + "/" + ctxUser . Name + "/" + repo . Name )
2015-08-08 17:10:34 +08:00
}
2016-03-11 11:56:52 -05:00
func checkPullInfo ( ctx * context . Context ) * models . Issue {
2015-10-18 19:30:39 -04:00
issue , err := models . GetIssueByIndex ( ctx . Repo . Repository . ID , ctx . ParamsInt64 ( ":index" ) )
2015-09-02 04:08:05 -04:00
if err != nil {
if models . IsErrIssueNotExist ( err ) {
2018-01-10 22:34:17 +01:00
ctx . NotFound ( "GetIssueByIndex" , err )
2015-09-02 04:08:05 -04:00
} else {
2018-01-10 22:34:17 +01:00
ctx . ServerError ( "GetIssueByIndex" , err )
2015-09-02 04:08:05 -04:00
}
return nil
}
2018-12-13 23:55:43 +08:00
if err = issue . LoadPoster ( ) ; err != nil {
ctx . ServerError ( "LoadPoster" , err )
return nil
}
2016-10-12 10:28:51 -03:00
ctx . Data [ "Title" ] = fmt . Sprintf ( "#%d - %s" , issue . Index , issue . Title )
2015-10-18 19:30:39 -04:00
ctx . Data [ "Issue" ] = issue
2015-09-02 04:08:05 -04:00
2015-10-18 19:30:39 -04:00
if ! issue . IsPull {
2018-01-10 22:34:17 +01:00
ctx . NotFound ( "ViewPullCommits" , nil )
2015-09-02 04:08:05 -04:00
return nil
}
2018-12-13 23:55:43 +08:00
if err = issue . LoadPullRequest ( ) ; err != nil {
ctx . ServerError ( "LoadPullRequest" , err )
return nil
}
2016-08-16 10:19:09 -07:00
if err = issue . PullRequest . GetHeadRepo ( ) ; err != nil {
2018-01-10 22:34:17 +01:00
ctx . ServerError ( "GetHeadRepo" , err )
2015-10-24 03:36:47 -04:00
return nil
2015-09-02 04:08:05 -04:00
}
if ctx . IsSigned {
// Update issue-user.
2016-07-24 01:08:22 +08:00
if err = issue . ReadBy ( ctx . User . ID ) ; err != nil {
2018-01-10 22:34:17 +01:00
ctx . ServerError ( "ReadBy" , err )
2015-09-02 04:08:05 -04:00
return nil
}
}
2015-10-18 19:30:39 -04:00
return issue
2015-09-02 04:08:05 -04:00
}
2017-10-05 02:35:01 +09:00
func setMergeTarget ( ctx * context . Context , pull * models . PullRequest ) {
if ctx . Repo . Owner . Name == pull . HeadUserName {
ctx . Data [ "HeadTarget" ] = pull . HeadBranch
} else if pull . HeadRepo == nil {
ctx . Data [ "HeadTarget" ] = pull . HeadUserName + ":" + pull . HeadBranch
} else {
ctx . Data [ "HeadTarget" ] = pull . HeadUserName + "/" + pull . HeadRepo . Name + ":" + pull . HeadBranch
}
ctx . Data [ "BaseTarget" ] = pull . BaseBranch
}
2016-11-24 15:04:31 +08:00
// PrepareMergedViewPullInfo show meta information for a merged pull request view page
2019-06-07 22:29:29 +02:00
func PrepareMergedViewPullInfo ( ctx * context . Context , issue * models . Issue ) * git . CompareInfo {
2016-08-16 10:19:09 -07:00
pull := issue . PullRequest
2015-09-02 09:26:56 -04:00
2017-10-05 02:35:01 +09:00
setMergeTarget ( ctx , pull )
ctx . Data [ "HasMerged" ] = true
2019-06-12 01:32:08 +02:00
compareInfo , err := ctx . Repo . GitRepo . GetCompareInfo ( ctx . Repo . Repository . RepoPath ( ) ,
2018-01-19 08:18:51 +02:00
pull . MergeBase , pull . GetGitRefName ( ) )
2017-11-25 05:47:19 -08:00
2015-09-02 09:26:56 -04:00
if err != nil {
2018-01-19 08:18:51 +02:00
if strings . Contains ( err . Error ( ) , "fatal: Not a valid object name" ) {
2018-08-01 05:00:35 +02:00
ctx . Data [ "IsPullRequestBroken" ] = true
2018-01-19 08:18:51 +02:00
ctx . Data [ "BaseTarget" ] = "deleted"
ctx . Data [ "NumCommits" ] = 0
ctx . Data [ "NumFiles" ] = 0
return nil
}
2019-06-07 22:29:29 +02:00
ctx . ServerError ( "GetCompareInfo" , err )
2018-01-19 08:18:51 +02:00
return nil
2015-09-02 09:26:56 -04:00
}
2019-06-12 01:32:08 +02:00
ctx . Data [ "NumCommits" ] = compareInfo . Commits . Len ( )
ctx . Data [ "NumFiles" ] = compareInfo . NumFiles
return compareInfo
2015-09-02 09:26:56 -04:00
}
2016-11-24 15:04:31 +08:00
// PrepareViewPullInfo show meta information for a pull request preview page
2019-06-07 22:29:29 +02:00
func PrepareViewPullInfo ( ctx * context . Context , issue * models . Issue ) * git . CompareInfo {
2015-09-02 04:08:05 -04:00
repo := ctx . Repo . Repository
2016-08-16 10:19:09 -07:00
pull := issue . PullRequest
2015-09-02 04:08:05 -04:00
2017-10-05 02:35:01 +09:00
var err error
2015-10-24 03:36:47 -04:00
if err = pull . GetHeadRepo ( ) ; err != nil {
2018-01-10 22:34:17 +01:00
ctx . ServerError ( "GetHeadRepo" , err )
2015-10-24 03:36:47 -04:00
return nil
}
2017-10-05 02:35:01 +09:00
setMergeTarget ( ctx , pull )
var headGitRepo * git . Repository
2015-10-04 20:54:06 -04:00
if pull . HeadRepo != nil {
2015-11-26 17:33:45 -05:00
headGitRepo , err = git . OpenRepository ( pull . HeadRepo . RepoPath ( ) )
2015-10-04 20:54:06 -04:00
if err != nil {
2018-01-10 22:34:17 +01:00
ctx . ServerError ( "OpenRepository" , err )
2015-10-04 20:54:06 -04:00
return nil
}
2015-09-02 04:08:05 -04:00
}
2015-10-18 19:30:39 -04:00
if pull . HeadRepo == nil || ! headGitRepo . IsBranchExist ( pull . HeadBranch ) {
2018-08-01 05:00:35 +02:00
ctx . Data [ "IsPullRequestBroken" ] = true
2015-09-02 09:26:56 -04:00
ctx . Data [ "HeadTarget" ] = "deleted"
ctx . Data [ "NumCommits" ] = 0
ctx . Data [ "NumFiles" ] = 0
return nil
}
2019-06-12 01:32:08 +02:00
compareInfo , err := headGitRepo . GetCompareInfo ( models . RepoPath ( repo . Owner . Name , repo . Name ) ,
2015-10-18 19:30:39 -04:00
pull . BaseBranch , pull . HeadBranch )
2015-09-02 04:08:05 -04:00
if err != nil {
2016-07-23 18:35:16 +08:00
if strings . Contains ( err . Error ( ) , "fatal: Not a valid object name" ) {
2018-08-01 05:00:35 +02:00
ctx . Data [ "IsPullRequestBroken" ] = true
2016-07-23 18:35:16 +08:00
ctx . Data [ "BaseTarget" ] = "deleted"
ctx . Data [ "NumCommits" ] = 0
ctx . Data [ "NumFiles" ] = 0
return nil
}
2019-06-07 22:29:29 +02:00
ctx . ServerError ( "GetCompareInfo" , err )
2015-09-02 04:08:05 -04:00
return nil
}
2018-08-13 21:04:39 +02:00
if pull . IsWorkInProgress ( ) {
ctx . Data [ "IsPullWorkInProgress" ] = true
ctx . Data [ "WorkInProgressPrefix" ] = pull . GetWorkInProgressPrefix ( )
}
2019-02-05 19:54:49 +08:00
if pull . IsFilesConflicted ( ) {
ctx . Data [ "IsPullFilesConflicted" ] = true
ctx . Data [ "ConflictedFiles" ] = pull . ConflictedFiles
}
2019-06-12 01:32:08 +02:00
ctx . Data [ "NumCommits" ] = compareInfo . Commits . Len ( )
ctx . Data [ "NumFiles" ] = compareInfo . NumFiles
return compareInfo
2015-09-02 04:08:05 -04:00
}
2016-11-24 15:04:31 +08:00
// ViewPullCommits show commits for a pull request
2016-03-11 11:56:52 -05:00
func ViewPullCommits ( ctx * context . Context ) {
2016-08-14 03:32:24 -07:00
ctx . Data [ "PageIsPullList" ] = true
2015-09-02 04:08:05 -04:00
ctx . Data [ "PageIsPullCommits" ] = true
2016-08-16 10:19:09 -07:00
issue := checkPullInfo ( ctx )
2015-09-02 04:08:05 -04:00
if ctx . Written ( ) {
return
}
2016-08-16 10:19:09 -07:00
pull := issue . PullRequest
2015-09-02 04:08:05 -04:00
2015-09-02 09:26:56 -04:00
var commits * list . List
if pull . HasMerged {
2018-01-19 08:18:51 +02:00
prInfo := PrepareMergedViewPullInfo ( ctx , issue )
2015-09-02 09:26:56 -04:00
if ctx . Written ( ) {
return
2018-01-19 08:18:51 +02:00
} else if prInfo == nil {
ctx . NotFound ( "ViewPullCommits" , nil )
return
2015-09-02 09:26:56 -04:00
}
2017-06-21 01:25:38 +03:00
ctx . Data [ "Username" ] = ctx . Repo . Owner . Name
ctx . Data [ "Reponame" ] = ctx . Repo . Repository . Name
2018-01-19 08:18:51 +02:00
commits = prInfo . Commits
2015-09-02 09:26:56 -04:00
} else {
2016-08-16 10:19:09 -07:00
prInfo := PrepareViewPullInfo ( ctx , issue )
2015-09-02 09:26:56 -04:00
if ctx . Written ( ) {
return
} else if prInfo == nil {
2018-01-10 22:34:17 +01:00
ctx . NotFound ( "ViewPullCommits" , nil )
2015-09-02 09:26:56 -04:00
return
}
2017-06-21 01:25:38 +03:00
ctx . Data [ "Username" ] = pull . HeadUserName
ctx . Data [ "Reponame" ] = pull . HeadRepo . Name
2015-09-02 09:26:56 -04:00
commits = prInfo . Commits
2015-09-02 04:08:05 -04:00
}
2015-09-02 09:26:56 -04:00
commits = models . ValidateCommitsWithEmails ( commits )
2017-05-07 17:40:31 +03:00
commits = models . ParseCommitsWithSignature ( commits )
commits = models . ParseCommitsWithStatus ( commits , ctx . Repo . Repository )
2015-09-02 09:26:56 -04:00
ctx . Data [ "Commits" ] = commits
ctx . Data [ "CommitCount" ] = commits . Len ( )
2016-11-24 15:04:31 +08:00
ctx . HTML ( 200 , tplPullCommits )
2015-09-02 04:08:05 -04:00
}
2016-11-24 15:04:31 +08:00
// ViewPullFiles render pull request changed files list page
2016-03-11 11:56:52 -05:00
func ViewPullFiles ( ctx * context . Context ) {
2016-08-14 03:32:24 -07:00
ctx . Data [ "PageIsPullList" ] = true
2015-09-02 04:08:05 -04:00
ctx . Data [ "PageIsPullFiles" ] = true
2016-08-16 10:19:09 -07:00
issue := checkPullInfo ( ctx )
2015-09-02 04:08:05 -04:00
if ctx . Written ( ) {
return
}
2016-08-16 10:19:09 -07:00
pull := issue . PullRequest
2015-09-02 04:08:05 -04:00
2018-08-14 19:49:33 +02:00
whitespaceFlags := map [ string ] string {
"ignore-all" : "-w" ,
"ignore-change" : "-b" ,
"ignore-eol" : "--ignore-space-at-eol" ,
"" : "" }
2015-09-02 09:26:56 -04:00
var (
diffRepoPath string
startCommitID string
endCommitID string
gitRepo * git . Repository
)
2017-06-21 01:25:38 +03:00
var headTarget string
2015-09-02 09:26:56 -04:00
if pull . HasMerged {
2018-01-19 08:18:51 +02:00
prInfo := PrepareMergedViewPullInfo ( ctx , issue )
2015-09-02 09:26:56 -04:00
if ctx . Written ( ) {
return
2018-01-19 08:18:51 +02:00
} else if prInfo == nil {
ctx . NotFound ( "ViewPullFiles" , nil )
return
2015-09-02 09:26:56 -04:00
}
2015-09-02 04:08:05 -04:00
2015-09-02 09:26:56 -04:00
diffRepoPath = ctx . Repo . GitRepo . Path
2018-01-19 08:18:51 +02:00
gitRepo = ctx . Repo . GitRepo
headCommitID , err := gitRepo . GetRefCommitID ( pull . GetGitRefName ( ) )
2017-11-25 05:47:19 -08:00
if err != nil {
2018-01-19 08:18:51 +02:00
ctx . ServerError ( "GetRefCommitID" , err )
2017-11-25 05:47:19 -08:00
return
}
2018-01-19 08:18:51 +02:00
startCommitID = prInfo . MergeBase
endCommitID = headCommitID
2017-06-21 01:25:38 +03:00
headTarget = path . Join ( ctx . Repo . Owner . Name , ctx . Repo . Repository . Name )
ctx . Data [ "Username" ] = ctx . Repo . Owner . Name
ctx . Data [ "Reponame" ] = ctx . Repo . Repository . Name
2015-09-02 09:26:56 -04:00
} else {
2016-08-16 10:19:09 -07:00
prInfo := PrepareViewPullInfo ( ctx , issue )
2015-09-02 09:26:56 -04:00
if ctx . Written ( ) {
return
} else if prInfo == nil {
2018-01-10 22:34:17 +01:00
ctx . NotFound ( "ViewPullFiles" , nil )
2015-09-02 09:26:56 -04:00
return
}
2015-09-02 04:08:05 -04:00
2015-09-02 09:26:56 -04:00
headRepoPath := models . RepoPath ( pull . HeadUserName , pull . HeadRepo . Name )
2015-09-02 04:08:05 -04:00
2015-09-02 09:26:56 -04:00
headGitRepo , err := git . OpenRepository ( headRepoPath )
if err != nil {
2018-01-10 22:34:17 +01:00
ctx . ServerError ( "OpenRepository" , err )
2015-09-02 09:26:56 -04:00
return
}
2015-12-09 20:46:05 -05:00
headCommitID , err := headGitRepo . GetBranchCommitID ( pull . HeadBranch )
2015-09-02 09:26:56 -04:00
if err != nil {
2018-01-10 22:34:17 +01:00
ctx . ServerError ( "GetBranchCommitID" , err )
2015-09-02 09:26:56 -04:00
return
}
diffRepoPath = headRepoPath
startCommitID = prInfo . MergeBase
endCommitID = headCommitID
gitRepo = headGitRepo
2017-06-21 01:25:38 +03:00
headTarget = path . Join ( pull . HeadUserName , pull . HeadRepo . Name )
ctx . Data [ "Username" ] = pull . HeadUserName
ctx . Data [ "Reponame" ] = pull . HeadRepo . Name
2015-09-02 04:08:05 -04:00
}
2018-08-14 19:49:33 +02:00
diff , err := models . GetDiffRangeWithWhitespaceBehavior ( diffRepoPath ,
2016-06-29 12:11:00 -03:00
startCommitID , endCommitID , setting . Git . MaxGitDiffLines ,
2018-08-14 19:49:33 +02:00
setting . Git . MaxGitDiffLineCharacters , setting . Git . MaxGitDiffFiles ,
whitespaceFlags [ ctx . Data [ "WhitespaceBehavior" ] . ( string ) ] )
2015-09-02 04:08:05 -04:00
if err != nil {
2018-08-14 19:49:33 +02:00
ctx . ServerError ( "GetDiffRangeWithWhitespaceBehavior" , err )
2015-09-02 04:08:05 -04:00
return
}
2018-08-06 07:43:22 +03:00
if err = diff . LoadComments ( issue , ctx . User ) ; err != nil {
ctx . ServerError ( "LoadComments" , err )
return
}
2015-09-02 04:08:05 -04:00
ctx . Data [ "Diff" ] = diff
ctx . Data [ "DiffNotAvailable" ] = diff . NumFiles ( ) == 0
2015-09-02 09:26:56 -04:00
commit , err := gitRepo . GetCommit ( endCommitID )
2015-09-02 04:08:05 -04:00
if err != nil {
2018-01-10 22:34:17 +01:00
ctx . ServerError ( "GetCommit" , err )
2015-09-02 04:08:05 -04:00
return
}
2015-09-02 09:26:56 -04:00
ctx . Data [ "IsImageFile" ] = commit . IsImageFile
2017-11-27 02:58:54 +02:00
ctx . Data [ "SourcePath" ] = setting . AppSubURL + "/" + path . Join ( headTarget , "src" , "commit" , endCommitID )
ctx . Data [ "BeforeSourcePath" ] = setting . AppSubURL + "/" + path . Join ( headTarget , "src" , "commit" , startCommitID )
ctx . Data [ "RawPath" ] = setting . AppSubURL + "/" + path . Join ( headTarget , "raw" , "commit" , endCommitID )
2016-01-31 14:19:02 -02:00
ctx . Data [ "RequireHighlightJS" ] = true
2018-08-06 07:43:22 +03:00
ctx . Data [ "RequireTribute" ] = true
if ctx . Data [ "Assignees" ] , err = ctx . Repo . Repository . GetAssignees ( ) ; err != nil {
ctx . ServerError ( "GetAssignees" , err )
return
}
ctx . Data [ "CurrentReview" ] , err = models . GetCurrentReview ( ctx . User , issue )
if err != nil && ! models . IsErrReviewNotExist ( err ) {
ctx . ServerError ( "GetCurrentReview" , err )
return
}
2016-11-24 15:04:31 +08:00
ctx . HTML ( 200 , tplPullFiles )
2015-09-02 04:08:05 -04:00
}
2015-08-31 16:24:28 +09:00
2016-11-24 15:04:31 +08:00
// MergePullRequest response for merging pull request
2018-01-05 20:56:50 +02:00
func MergePullRequest ( ctx * context . Context , form auth . MergePullRequestForm ) {
2015-10-18 19:30:39 -04:00
issue := checkPullInfo ( ctx )
2015-09-02 09:26:56 -04:00
if ctx . Written ( ) {
return
}
2015-10-18 19:30:39 -04:00
if issue . IsClosed {
2018-01-10 22:34:17 +01:00
ctx . NotFound ( "MergePullRequest" , nil )
2015-09-02 09:26:56 -04:00
return
}
2018-12-13 23:55:43 +08:00
pr := issue . PullRequest
2015-09-02 09:26:56 -04:00
2015-10-18 17:18:45 -04:00
if ! pr . CanAutoMerge ( ) || pr . HasMerged {
2018-01-10 22:34:17 +01:00
ctx . NotFound ( "MergePullRequest" , nil )
2015-09-02 09:26:56 -04:00
return
}
2018-08-13 21:04:39 +02:00
if pr . IsWorkInProgress ( ) {
ctx . Flash . Error ( ctx . Tr ( "repo.pulls.no_merge_wip" ) )
ctx . Redirect ( ctx . Repo . RepoLink + "/pulls/" + com . ToStr ( pr . Index ) )
return
}
2018-01-05 20:56:50 +02:00
if ctx . HasError ( ) {
ctx . Flash . Error ( ctx . Data [ "ErrorMsg" ] . ( string ) )
ctx . Redirect ( ctx . Repo . RepoLink + "/pulls/" + com . ToStr ( pr . Index ) )
return
}
message := strings . TrimSpace ( form . MergeTitleField )
if len ( message ) == 0 {
if models . MergeStyle ( form . Do ) == models . MergeStyleMerge {
message = pr . GetDefaultMergeMessage ( )
}
2018-12-27 11:27:08 +01:00
if models . MergeStyle ( form . Do ) == models . MergeStyleRebaseMerge {
message = pr . GetDefaultMergeMessage ( )
}
2018-01-05 20:56:50 +02:00
if models . MergeStyle ( form . Do ) == models . MergeStyleSquash {
message = pr . GetDefaultSquashMessage ( )
}
}
form . MergeMessageField = strings . TrimSpace ( form . MergeMessageField )
if len ( form . MergeMessageField ) > 0 {
message += "\n\n" + form . MergeMessageField
}
2015-10-18 19:30:39 -04:00
pr . Issue = issue
pr . Issue . Repo = ctx . Repo . Repository
2018-07-17 23:23:58 +02:00
noDeps , err := models . IssueNoDependenciesLeft ( issue )
if err != nil {
return
}
if ! noDeps {
ctx . Flash . Error ( ctx . Tr ( "repo.issues.dependency.pr_close_blocked" ) )
ctx . Redirect ( ctx . Repo . RepoLink + "/pulls/" + com . ToStr ( pr . Index ) )
return
}
2019-06-22 18:35:34 +01:00
if err = pull . Merge ( pr , ctx . User , ctx . Repo . GitRepo , models . MergeStyle ( form . Do ) , message ) ; err != nil {
2018-01-05 20:56:50 +02:00
if models . IsErrInvalidMergeStyle ( err ) {
ctx . Flash . Error ( ctx . Tr ( "repo.pulls.invalid_merge_option" ) )
ctx . Redirect ( ctx . Repo . RepoLink + "/pulls/" + com . ToStr ( pr . Index ) )
return
}
2018-01-10 22:34:17 +01:00
ctx . ServerError ( "Merge" , err )
2015-09-02 09:26:56 -04:00
return
}
2019-02-05 12:38:11 +01:00
if err := stopTimerIfAvailable ( ctx . User , issue ) ; err != nil {
ctx . ServerError ( "CreateOrStopIssueStopwatch" , err )
return
}
2018-10-18 19:23:05 +08:00
notification . NotifyMergePullRequest ( pr , ctx . User , ctx . Repo . GitRepo )
2017-01-28 13:59:58 -02:00
2015-09-02 09:26:56 -04:00
log . Trace ( "Pull request merged: %d" , pr . ID )
2015-10-18 19:30:39 -04:00
ctx . Redirect ( ctx . Repo . RepoLink + "/pulls/" + com . ToStr ( pr . Index ) )
2015-09-02 09:26:56 -04:00
}
2019-02-05 12:38:11 +01:00
func stopTimerIfAvailable ( user * models . User , issue * models . Issue ) error {
if models . StopwatchExists ( user . ID , issue . ID ) {
if err := models . CreateOrStopIssueStopwatch ( user , issue ) ; err != nil {
return err
}
}
return nil
}
2016-11-24 15:04:31 +08:00
// CompareAndPullRequestPost response for creating pull request
2016-03-11 11:56:52 -05:00
func CompareAndPullRequestPost ( ctx * context . Context , form auth . CreateIssueForm ) {
2015-09-01 19:07:02 -04:00
ctx . Data [ "Title" ] = ctx . Tr ( "repo.pulls.compare_changes" )
ctx . Data [ "PageIsComparePull" ] = true
ctx . Data [ "IsDiffCompare" ] = true
2016-08-15 14:04:44 -07:00
ctx . Data [ "RequireHighlightJS" ] = true
2018-08-13 21:04:39 +02:00
ctx . Data [ "PullRequestWorkInProgressPrefixes" ] = setting . Repository . PullRequest . WorkInProgressPrefixes
2015-09-01 19:07:02 -04:00
renderAttachmentSettings ( ctx )
var (
repo = ctx . Repo . Repository
attachments [ ] string
)
2015-09-01 19:26:39 -04:00
headUser , headRepo , headGitRepo , prInfo , baseBranch , headBranch := ParseCompareInfo ( ctx )
2015-09-01 19:07:02 -04:00
if ctx . Written ( ) {
return
}
2018-11-28 19:26:14 +08:00
labelIDs , assigneeIDs , milestoneID := ValidateRepoMetas ( ctx , form , true )
2015-09-01 19:07:02 -04:00
if ctx . Written ( ) {
return
}
if setting . AttachmentEnabled {
2016-08-11 05:48:08 -07:00
attachments = form . Files
2015-09-01 19:07:02 -04:00
}
if ctx . HasError ( ) {
2016-08-15 14:04:44 -07: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
}
2019-06-07 22:29:29 +02:00
ctx . HTML ( 200 , tplCompareDiff )
2015-09-01 19:07:02 -04:00
return
}
2019-01-21 12:45:32 +01:00
if util . IsEmptyString ( form . Title ) {
PrepareCompareDiff ( ctx , headUser , headRepo , headGitRepo , prInfo , baseBranch , headBranch )
if ctx . Written ( ) {
return
}
2019-06-07 22:29:29 +02:00
ctx . RenderWithErr ( ctx . Tr ( "repo.issues.new.title_empty" ) , tplCompareDiff , form )
2019-01-21 12:45:32 +01:00
return
}
2016-08-15 14:04:44 -07:00
patch , err := headGitRepo . GetPatch ( prInfo . MergeBase , headBranch )
if err != nil {
2018-01-10 22:34:17 +01:00
ctx . ServerError ( "GetPatch" , err )
2016-08-15 14:04:44 -07:00
return
}
2019-05-18 10:37:49 +08:00
maxIndex , err := models . GetMaxIndexOfIssue ( repo . ID )
if err != nil {
ctx . ServerError ( "GetPatch" , err )
return
}
2016-02-24 13:56:54 +01:00
pullIssue := & models . Issue {
2015-09-01 19:07:02 -04:00
RepoID : repo . ID ,
2019-05-18 10:37:49 +08:00
Index : maxIndex + 1 ,
2016-08-14 03:32:24 -07:00
Title : form . Title ,
2016-07-24 01:08:22 +08:00
PosterID : ctx . User . ID ,
2015-09-01 19:07:02 -04:00
Poster : ctx . User ,
MilestoneID : milestoneID ,
IsPull : true ,
Content : form . Content ,
}
2016-02-24 13:56:54 +01:00
pullRequest := & models . PullRequest {
2015-09-01 19:26:39 -04:00
HeadRepoID : headRepo . ID ,
BaseRepoID : repo . ID ,
HeadUserName : headUser . Name ,
2015-10-18 19:30:39 -04:00
HeadBranch : headBranch ,
2015-09-01 19:26:39 -04:00
BaseBranch : baseBranch ,
2016-02-24 13:56:54 +01:00
HeadRepo : headRepo ,
BaseRepo : repo ,
2015-09-01 19:26:39 -04:00
MergeBase : prInfo . MergeBase ,
2016-11-07 16:37:32 +01:00
Type : models . PullRequestGitea ,
2016-02-24 13:56:54 +01:00
}
2016-08-15 14:04:44 -07:00
// FIXME: check error in the case two people send pull request at almost same time, give nice error prompt
// instead of 500.
2018-05-09 18:29:04 +02:00
if err := models . NewPullRequest ( repo , pullIssue , labelIDs , attachments , pullRequest , patch , assigneeIDs ) ; err != nil {
if models . IsErrUserDoesNotHaveAccessToRepo ( err ) {
ctx . Error ( 400 , "UserDoesNotHaveAccessToRepo" , err . Error ( ) )
return
}
2018-01-10 22:34:17 +01:00
ctx . ServerError ( "NewPullRequest" , err )
2015-09-01 19:07:02 -04:00
return
2016-03-04 15:43:01 -05:00
} else if err := pullRequest . PushToBaseRepo ( ) ; err != nil {
2018-01-10 22:34:17 +01:00
ctx . ServerError ( "PushToBaseRepo" , err )
2016-02-24 13:56:54 +01:00
return
2015-12-10 11:18:56 -05:00
}
2018-10-18 19:23:05 +08:00
notification . NotifyNewPullRequest ( pullRequest )
2017-01-28 13:59:58 -02:00
2016-02-24 13:56:54 +01: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 18:25:15 +08:00
}
2015-10-24 03:36:47 -04:00
2016-11-24 15:04:31 +08:00
// TriggerTask response for a trigger task request
2016-03-11 11:56:52 -05:00
func TriggerTask ( ctx * context . Context ) {
2016-08-14 03:32:24 -07:00
pusherID := ctx . QueryInt64 ( "pusher" )
2015-12-14 17:06:54 -05:00
branch := ctx . Query ( "branch" )
secret := ctx . Query ( "secret" )
2016-08-14 03:32:24 -07:00
if len ( branch ) == 0 || len ( secret ) == 0 || pusherID <= 0 {
2015-12-14 17:06:54 -05:00
ctx . Error ( 404 )
2016-08-14 03:32:24 -07:00
log . Trace ( "TriggerTask: branch or secret is empty, or pusher ID is not valid" )
2015-12-14 17:06:54 -05:00
return
}
owner , repo := parseOwnerAndRepo ( ctx )
2015-10-24 03:36:47 -04:00
if ctx . Written ( ) {
return
}
2015-12-14 17:06:54 -05:00
if secret != base . EncodeMD5 ( owner . Salt ) {
ctx . Error ( 404 )
log . Trace ( "TriggerTask [%s/%s]: invalid secret" , owner . Name , repo . Name )
2015-10-24 03:36:47 -04:00
return
}
2016-08-14 03:32:24 -07:00
pusher , err := models . GetUserByID ( pusherID )
if err != nil {
if models . IsErrUserNotExist ( err ) {
ctx . Error ( 404 )
} else {
2018-01-10 22:34:17 +01:00
ctx . ServerError ( "GetUserByID" , err )
2016-08-14 03:32:24 -07:00
}
return
}
log . Trace ( "TriggerTask '%s/%s' by %s" , repo . Name , branch , pusher . Name )
2015-10-24 03:36:47 -04:00
go models . HookQueue . Add ( repo . ID )
2016-08-14 03:32:24 -07:00
go models . AddTestPullRequestTask ( pusher , repo . ID , branch , true )
2015-10-24 03:36:47 -04:00
ctx . Status ( 202 )
}
2017-06-21 04:00:03 +03:00
// CleanUpPullRequest responses for delete merged branch when PR has been merged
func CleanUpPullRequest ( ctx * context . Context ) {
issue := checkPullInfo ( ctx )
if ctx . Written ( ) {
return
}
2018-12-13 23:55:43 +08:00
pr := issue . PullRequest
2017-06-21 04:00:03 +03:00
2019-04-20 22:50:34 +02:00
// Don't cleanup unmerged and unclosed PRs
if ! pr . HasMerged && ! issue . IsClosed {
2018-01-10 22:34:17 +01:00
ctx . NotFound ( "CleanUpPullRequest" , nil )
2017-06-21 04:00:03 +03:00
return
}
2018-12-13 23:55:43 +08:00
if err := pr . GetHeadRepo ( ) ; err != nil {
2018-01-10 22:34:17 +01:00
ctx . ServerError ( "GetHeadRepo" , err )
2017-06-21 04:00:03 +03:00
return
} else if pr . HeadRepo == nil {
// Forked repository has already been deleted
2018-01-10 22:34:17 +01:00
ctx . NotFound ( "CleanUpPullRequest" , nil )
2017-06-21 04:00:03 +03:00
return
2019-06-12 21:41:28 +02:00
} else if err = pr . GetBaseRepo ( ) ; err != nil {
2018-01-10 22:34:17 +01:00
ctx . ServerError ( "GetBaseRepo" , err )
2017-06-21 04:00:03 +03:00
return
2019-06-12 21:41:28 +02:00
} else if err = pr . HeadRepo . GetOwner ( ) ; err != nil {
2018-01-10 22:34:17 +01:00
ctx . ServerError ( "HeadRepo.GetOwner" , err )
2017-06-21 04:00:03 +03:00
return
}
2018-11-28 19:26:14 +08:00
perm , err := models . GetUserRepoPermission ( pr . HeadRepo , ctx . User )
if err != nil {
ctx . ServerError ( "GetUserRepoPermission" , err )
return
}
if ! perm . CanWrite ( models . UnitTypeCode ) {
2018-01-10 22:34:17 +01:00
ctx . NotFound ( "CleanUpPullRequest" , nil )
2017-06-21 04:00:03 +03:00
return
}
fullBranchName := pr . HeadRepo . Owner . Name + "/" + pr . HeadBranch
gitRepo , err := git . OpenRepository ( pr . HeadRepo . RepoPath ( ) )
if err != nil {
2018-01-10 22:34:17 +01:00
ctx . ServerError ( fmt . Sprintf ( "OpenRepository[%s]" , pr . HeadRepo . RepoPath ( ) ) , err )
2017-06-21 04:00:03 +03:00
return
}
gitBaseRepo , err := git . OpenRepository ( pr . BaseRepo . RepoPath ( ) )
if err != nil {
2018-01-10 22:34:17 +01:00
ctx . ServerError ( fmt . Sprintf ( "OpenRepository[%s]" , pr . BaseRepo . RepoPath ( ) ) , err )
2017-06-21 04:00:03 +03:00
return
}
defer func ( ) {
ctx . JSON ( 200 , map [ string ] interface { } {
"redirect" : pr . BaseRepo . Link ( ) + "/pulls/" + com . ToStr ( issue . Index ) ,
} )
} ( )
if pr . HeadBranch == pr . HeadRepo . DefaultBranch || ! gitRepo . IsBranchExist ( pr . HeadBranch ) {
ctx . Flash . Error ( ctx . Tr ( "repo.branch.deletion_failed" , fullBranchName ) )
return
}
// Check if branch is not protected
2017-09-14 16:16:22 +08:00
if protected , err := pr . HeadRepo . IsProtectedBranch ( pr . HeadBranch , ctx . User ) ; err != nil || protected {
2017-06-21 04:00:03 +03:00
if err != nil {
2019-04-02 08:48:31 +01:00
log . Error ( "HeadRepo.IsProtectedBranch: %v" , err )
2017-06-21 04:00:03 +03:00
}
ctx . Flash . Error ( ctx . Tr ( "repo.branch.deletion_failed" , fullBranchName ) )
return
}
// Check if branch has no new commits
2018-01-30 14:29:39 +02:00
headCommitID , err := gitBaseRepo . GetRefCommitID ( pr . GetGitRefName ( ) )
if err != nil {
2019-04-02 08:48:31 +01:00
log . Error ( "GetRefCommitID: %v" , err )
2018-01-30 14:29:39 +02:00
ctx . Flash . Error ( ctx . Tr ( "repo.branch.deletion_failed" , fullBranchName ) )
return
}
branchCommitID , err := gitRepo . GetBranchCommitID ( pr . HeadBranch )
if err != nil {
2019-04-02 08:48:31 +01:00
log . Error ( "GetBranchCommitID: %v" , err )
2018-01-30 14:29:39 +02:00
ctx . Flash . Error ( ctx . Tr ( "repo.branch.deletion_failed" , fullBranchName ) )
return
}
if headCommitID != branchCommitID {
ctx . Flash . Error ( ctx . Tr ( "repo.branch.delete_branch_has_new_commits" , fullBranchName ) )
return
2017-06-21 04:00:03 +03:00
}
if err := gitRepo . DeleteBranch ( pr . HeadBranch , git . DeleteBranchOptions {
Force : true ,
} ) ; err != nil {
2019-04-02 08:48:31 +01:00
log . Error ( "DeleteBranch: %v" , err )
2017-06-21 04:00:03 +03:00
ctx . Flash . Error ( ctx . Tr ( "repo.branch.deletion_failed" , fullBranchName ) )
return
}
if err := models . AddDeletePRBranchComment ( ctx . User , pr . BaseRepo , issue . ID , pr . HeadBranch ) ; err != nil {
// Do not fail here as branch has already been deleted
2019-04-02 08:48:31 +01:00
log . Error ( "DeleteBranch: %v" , err )
2017-06-21 04:00:03 +03:00
}
ctx . Flash . Success ( ctx . Tr ( "repo.branch.deletion_success" , fullBranchName ) )
}
2018-01-05 11:56:52 +01:00
// DownloadPullDiff render a pull's raw diff
func DownloadPullDiff ( ctx * context . Context ) {
issue , err := models . GetIssueByIndex ( ctx . Repo . Repository . ID , ctx . ParamsInt64 ( ":index" ) )
if err != nil {
if models . IsErrIssueNotExist ( err ) {
2018-01-10 22:34:17 +01:00
ctx . NotFound ( "GetIssueByIndex" , err )
2018-01-05 11:56:52 +01:00
} else {
2018-01-10 22:34:17 +01:00
ctx . ServerError ( "GetIssueByIndex" , err )
2018-01-05 11:56:52 +01:00
}
return
}
2018-01-07 14:10:20 +01:00
// Return not found if it's not a pull request
2018-01-05 11:56:52 +01:00
if ! issue . IsPull {
2018-01-10 22:34:17 +01:00
ctx . NotFound ( "DownloadPullDiff" ,
2018-01-05 11:56:52 +01:00
fmt . Errorf ( "Issue is not a pull request" ) )
return
}
2018-12-13 23:55:43 +08:00
if err = issue . LoadPullRequest ( ) ; err != nil {
ctx . ServerError ( "LoadPullRequest" , err )
return
}
2018-01-05 11:56:52 +01:00
2018-12-13 23:55:43 +08:00
pr := issue . PullRequest
2018-01-05 11:56:52 +01:00
if err = pr . GetBaseRepo ( ) ; err != nil {
2018-01-10 22:34:17 +01:00
ctx . ServerError ( "GetBaseRepo" , err )
2018-01-05 11:56:52 +01:00
return
}
patch , err := pr . BaseRepo . PatchPath ( pr . Index )
if err != nil {
2018-01-10 22:34:17 +01:00
ctx . ServerError ( "PatchPath" , err )
2018-01-05 11:56:52 +01:00
return
}
ctx . ServeFileContent ( patch )
}
2018-01-07 14:10:20 +01:00
// DownloadPullPatch render a pull's raw patch
func DownloadPullPatch ( ctx * context . Context ) {
issue , err := models . GetIssueByIndex ( ctx . Repo . Repository . ID , ctx . ParamsInt64 ( ":index" ) )
if err != nil {
if models . IsErrIssueNotExist ( err ) {
2018-01-10 22:34:17 +01:00
ctx . NotFound ( "GetIssueByIndex" , err )
2018-01-07 14:10:20 +01:00
} else {
2018-01-10 22:34:17 +01:00
ctx . ServerError ( "GetIssueByIndex" , err )
2018-01-07 14:10:20 +01:00
}
return
}
// Return not found if it's not a pull request
if ! issue . IsPull {
2018-01-10 22:34:17 +01:00
ctx . NotFound ( "DownloadPullDiff" ,
2018-01-07 14:10:20 +01:00
fmt . Errorf ( "Issue is not a pull request" ) )
return
}
2018-12-13 23:55:43 +08:00
if err = issue . LoadPullRequest ( ) ; err != nil {
ctx . ServerError ( "LoadPullRequest" , err )
return
}
2018-01-07 14:10:20 +01:00
2018-12-13 23:55:43 +08:00
pr := issue . PullRequest
2018-01-07 14:10:20 +01:00
if err = pr . GetHeadRepo ( ) ; err != nil {
2018-01-10 22:34:17 +01:00
ctx . ServerError ( "GetHeadRepo" , err )
2018-01-07 14:10:20 +01:00
return
}
headGitRepo , err := git . OpenRepository ( pr . HeadRepo . RepoPath ( ) )
if err != nil {
2018-01-10 22:34:17 +01:00
ctx . ServerError ( "OpenRepository" , err )
2018-01-07 14:10:20 +01:00
return
}
patch , err := headGitRepo . GetFormatPatch ( pr . MergeBase , pr . HeadBranch )
if err != nil {
2018-01-10 22:34:17 +01:00
ctx . ServerError ( "GetFormatPatch" , err )
2018-01-07 14:10:20 +01:00
return
}
_ , err = io . Copy ( ctx , patch )
if err != nil {
2018-01-10 22:34:17 +01:00
ctx . ServerError ( "io.Copy" , err )
2018-01-07 14:10:20 +01:00
return
}
}