@@ -389,8 +389,7 @@ func CreatePullRequest(ctx *context.APIContext) {
389389
390390	form  :=  * web .GetForm (ctx ).(* api.CreatePullRequestOption )
391391	if  form .Head  ==  form .Base  {
392- 		ctx .Error (http .StatusUnprocessableEntity , "BaseHeadSame" ,
393- 			"Invalid PullRequest: There are no changes between the head and the base" )
392+ 		ctx .Error (http .StatusUnprocessableEntity , "BaseHeadSame" , "Invalid PullRequest: There are no changes between the head and the base" )
394393		return 
395394	}
396395
@@ -401,14 +400,22 @@ func CreatePullRequest(ctx *context.APIContext) {
401400	)
402401
403402	// Get repo/branch information 
404- 	headRepo ,  headGitRepo ,  compareInfo ,  baseBranch ,  headBranch  :=  parseCompareInfo (ctx , form )
403+ 	compareResult ,  closer  :=  parseCompareInfo (ctx , form )
405404	if  ctx .Written () {
406405		return 
407406	}
408- 	defer  headGitRepo .Close ()
407+ 	defer  closer ()
408+ 
409+ 	if  ! compareResult .baseRef .IsBranch () ||  ! compareResult .headRef .IsBranch () {
410+ 		ctx .Error (http .StatusUnprocessableEntity , "BaseHeadInvalidRefType" , "Invalid PullRequest: base and head must be branches" )
411+ 		return 
412+ 	}
409413
410414	// Check if another PR exists with the same targets 
411- 	existingPr , err  :=  issues_model .GetUnmergedPullRequest (ctx , headRepo .ID , ctx .Repo .Repository .ID , headBranch , baseBranch , issues_model .PullRequestFlowGithub )
415+ 	existingPr , err  :=  issues_model .GetUnmergedPullRequest (ctx , compareResult .headRepo .ID , ctx .Repo .Repository .ID ,
416+ 		compareResult .headRef .ShortName (), compareResult .baseRef .ShortName (),
417+ 		issues_model .PullRequestFlowGithub ,
418+ 	)
412419	if  err  !=  nil  {
413420		if  ! issues_model .IsErrPullRequestNotExist (err ) {
414421			ctx .Error (http .StatusInternalServerError , "GetUnmergedPullRequest" , err )
@@ -484,13 +491,13 @@ func CreatePullRequest(ctx *context.APIContext) {
484491		DeadlineUnix : deadlineUnix ,
485492	}
486493	pr  :=  & issues_model.PullRequest {
487- 		HeadRepoID : headRepo .ID ,
494+ 		HeadRepoID : compareResult . headRepo .ID ,
488495		BaseRepoID : repo .ID ,
489- 		HeadBranch : headBranch ,
490- 		BaseBranch : baseBranch ,
491- 		HeadRepo :   headRepo ,
496+ 		HeadBranch : compareResult . headRef . ShortName () ,
497+ 		BaseBranch : compareResult . baseRef . ShortName () ,
498+ 		HeadRepo :   compareResult . headRepo ,
492499		BaseRepo :   repo ,
493- 		MergeBase :  compareInfo .MergeBase ,
500+ 		MergeBase :  compareResult . compareInfo .MergeBase ,
494501		Type :       issues_model .PullRequestGitea ,
495502	}
496503
@@ -1080,71 +1087,62 @@ func MergePullRequest(ctx *context.APIContext) {
10801087	ctx .Status (http .StatusOK )
10811088}
10821089
1083- func  parseCompareInfo (ctx  * context.APIContext , form  api.CreatePullRequestOption ) (* repo_model.Repository , * git.Repository , * git.CompareInfo , string , string ) {
1084- 	baseRepo  :=  ctx .Repo .Repository 
1090+ type  parseCompareInfoResult  struct  {
1091+ 	headRepo     * repo_model.Repository 
1092+ 	headGitRepo  * git.Repository 
1093+ 	compareInfo  * git.CompareInfo 
1094+ 	baseRef      git.RefName 
1095+ 	headRef      git.RefName 
1096+ }
10851097
1098+ // parseCompareInfo returns non-nil if it succeeds, it always writes to the context and returns nil if it fails 
1099+ func  parseCompareInfo (ctx  * context.APIContext , form  api.CreatePullRequestOption ) (result  * parseCompareInfoResult , closer  func ()) {
1100+ 	var  err  error 
10861101	// Get compared branches information 
10871102	// format: <base branch>...[<head repo>:]<head branch> 
10881103	// base<-head: master...head:feature 
10891104	// same repo: master...feature 
1105+ 	baseRepo  :=  ctx .Repo .Repository 
1106+ 	baseRefToGuess  :=  form .Base 
10901107
1091- 	// TODO: Validate form first? 
1092- 
1093- 	baseBranch  :=  form .Base 
1094- 
1095- 	var  (
1096- 		headUser    * user_model.User 
1097- 		headBranch  string 
1098- 		isSameRepo  bool 
1099- 		err         error 
1100- 	)
1101- 
1102- 	// If there is no head repository, it means pull request between same repository. 
1103- 	headInfos  :=  strings .Split (form .Head , ":" )
1104- 	if  len (headInfos ) ==  1  {
1105- 		isSameRepo  =  true 
1106- 		headUser  =  ctx .Repo .Owner 
1107- 		headBranch  =  headInfos [0 ]
1108+ 	headUser  :=  ctx .Repo .Owner 
1109+ 	headRefToGuess  :=  form .Head 
1110+ 	if  headInfos  :=  strings .Split (form .Head , ":" ); len (headInfos ) ==  1  {
1111+ 		// If there is no head repository, it means pull request between same repository. 
1112+ 		// Do nothing here because the head variables have been assigned above. 
11081113	} else  if  len (headInfos ) ==  2  {
1114+ 		// There is a head repository (the head repository could also be the same base repo) 
1115+ 		headRefToGuess  =  headInfos [1 ]
11091116		headUser , err  =  user_model .GetUserByName (ctx , headInfos [0 ])
11101117		if  err  !=  nil  {
11111118			if  user_model .IsErrUserNotExist (err ) {
11121119				ctx .NotFound ("GetUserByName" )
11131120			} else  {
11141121				ctx .Error (http .StatusInternalServerError , "GetUserByName" , err )
11151122			}
1116- 			return  nil , nil ,  nil ,  "" ,  "" 
1123+ 			return  nil , nil 
11171124		}
1118- 		headBranch  =  headInfos [1 ]
1119- 		// The head repository can also point to the same repo 
1120- 		isSameRepo  =  ctx .Repo .Owner .ID  ==  headUser .ID 
11211125	} else  {
11221126		ctx .NotFound ()
1123- 		return  nil , nil ,  nil ,  "" ,  "" 
1127+ 		return  nil , nil 
11241128	}
11251129
1126- 	ctx .Repo .PullRequest .SameRepo  =  isSameRepo 
1127- 	log .Trace ("Repo path: %q, base branch: %q, head branch: %q" , ctx .Repo .GitRepo .Path , baseBranch , headBranch )
1128- 	// Check if base branch is valid. 
1129- 	if  ! ctx .Repo .GitRepo .IsBranchExist (baseBranch ) &&  ! ctx .Repo .GitRepo .IsTagExist (baseBranch ) {
1130- 		ctx .NotFound ("BaseNotExist" )
1131- 		return  nil , nil , nil , "" , "" 
1132- 	}
1130+ 	isSameRepo  :=  ctx .Repo .Owner .ID  ==  headUser .ID 
11331131
11341132	// Check if current user has fork of repository or in the same repository. 
11351133	headRepo  :=  repo_model .GetForkedRepo (ctx , headUser .ID , baseRepo .ID )
11361134	if  headRepo  ==  nil  &&  ! isSameRepo  {
1137- 		err  : =  baseRepo .GetBaseRepo (ctx )
1135+ 		err  =  baseRepo .GetBaseRepo (ctx )
11381136		if  err  !=  nil  {
11391137			ctx .Error (http .StatusInternalServerError , "GetBaseRepo" , err )
1140- 			return  nil , nil ,  nil ,  "" ,  "" 
1138+ 			return  nil , nil 
11411139		}
11421140
11431141		// Check if baseRepo's base repository is the same as headUser's repository. 
11441142		if  baseRepo .BaseRepo  ==  nil  ||  baseRepo .BaseRepo .OwnerID  !=  headUser .ID  {
11451143			log .Trace ("parseCompareInfo[%d]: does not have fork or in same repository" , baseRepo .ID )
11461144			ctx .NotFound ("GetBaseRepo" )
1147- 			return  nil , nil ,  nil ,  "" ,  "" 
1145+ 			return  nil , nil 
11481146		}
11491147		// Assign headRepo so it can be used below. 
11501148		headRepo  =  baseRepo .BaseRepo 
@@ -1154,67 +1152,68 @@ func parseCompareInfo(ctx *context.APIContext, form api.CreatePullRequestOption)
11541152	if  isSameRepo  {
11551153		headRepo  =  ctx .Repo .Repository 
11561154		headGitRepo  =  ctx .Repo .GitRepo 
1155+ 		closer  =  func () {} // no need to close the head repo because it shares the base repo 
11571156	} else  {
11581157		headGitRepo , err  =  gitrepo .OpenRepository (ctx , headRepo )
11591158		if  err  !=  nil  {
11601159			ctx .Error (http .StatusInternalServerError , "OpenRepository" , err )
1161- 			return  nil , nil ,  nil ,  "" ,  "" 
1160+ 			return  nil , nil 
11621161		}
1162+ 		closer  =  func () { _  =  headGitRepo .Close () }
11631163	}
1164+ 	defer  func () {
1165+ 		if  result  ==  nil  &&  ! isSameRepo  {
1166+ 			_  =  headGitRepo .Close ()
1167+ 		}
1168+ 	}()
11641169
11651170	// user should have permission to read baseRepo's codes and pulls, NOT headRepo's 
11661171	permBase , err  :=  access_model .GetUserRepoPermission (ctx , baseRepo , ctx .Doer )
11671172	if  err  !=  nil  {
1168- 		headGitRepo .Close ()
11691173		ctx .Error (http .StatusInternalServerError , "GetUserRepoPermission" , err )
1170- 		return  nil , nil ,  nil ,  "" ,  "" 
1174+ 		return  nil , nil 
11711175	}
1176+ 
11721177	if  ! permBase .CanReadIssuesOrPulls (true ) ||  ! permBase .CanRead (unit .TypeCode ) {
1173- 		if  log .IsTrace () {
1174- 			log .Trace ("Permission Denied: User %-v cannot create/read pull requests or cannot read code in Repo %-v\n User in baseRepo has Permissions: %-+v" ,
1175- 				ctx .Doer ,
1176- 				baseRepo ,
1177- 				permBase )
1178- 		}
1179- 		headGitRepo .Close ()
1178+ 		log .Trace ("Permission Denied: User %-v cannot create/read pull requests or cannot read code in Repo %-v\n User in baseRepo has Permissions: %-+v" , ctx .Doer , baseRepo , permBase )
11801179		ctx .NotFound ("Can't read pulls or can't read UnitTypeCode" )
1181- 		return  nil , nil ,  nil ,  "" ,  "" 
1180+ 		return  nil , nil 
11821181	}
11831182
1184- 	// user should have permission to read headrepo's codes 
1183+ 	// user should have permission to read headRepo's codes 
1184+ 	// TODO: could the logic be simplified if the headRepo is the same as the baseRepo? Need to think more about it. 
11851185	permHead , err  :=  access_model .GetUserRepoPermission (ctx , headRepo , ctx .Doer )
11861186	if  err  !=  nil  {
1187- 		headGitRepo .Close ()
11881187		ctx .Error (http .StatusInternalServerError , "GetUserRepoPermission" , err )
1189- 		return  nil , nil ,  nil ,  "" ,  "" 
1188+ 		return  nil , nil 
11901189	}
11911190	if  ! permHead .CanRead (unit .TypeCode ) {
1192- 		if  log .IsTrace () {
1193- 			log .Trace ("Permission Denied: User: %-v cannot read code in Repo: %-v\n User in headRepo has Permissions: %-+v" ,
1194- 				ctx .Doer ,
1195- 				headRepo ,
1196- 				permHead )
1197- 		}
1198- 		headGitRepo .Close ()
1191+ 		log .Trace ("Permission Denied: User: %-v cannot read code in Repo: %-v\n User in headRepo has Permissions: %-+v" , ctx .Doer , headRepo , permHead )
11991192		ctx .NotFound ("Can't read headRepo UnitTypeCode" )
1200- 		return  nil , nil ,  nil ,  "" ,  "" 
1193+ 		return  nil , nil 
12011194	}
12021195
1203- 	// Check if head branch is valid. 
1204- 	if  ! headGitRepo .IsBranchExist (headBranch ) &&  ! headGitRepo .IsTagExist (headBranch ) {
1205- 		headGitRepo .Close ()
1196+ 	baseRef  :=  ctx .Repo .GitRepo .UnstableGuessRefByShortName (baseRefToGuess )
1197+ 	headRef  :=  headGitRepo .UnstableGuessRefByShortName (headRefToGuess )
1198+ 
1199+ 	log .Trace ("Repo path: %q, base ref: %q->%q, head ref: %q->%q" , ctx .Repo .GitRepo .Path , baseRefToGuess , baseRef , headRefToGuess , headRef )
1200+ 
1201+ 	baseRefValid  :=  baseRef .IsBranch () ||  baseRef .IsTag () ||  git .IsStringLikelyCommitID (git .ObjectFormatFromName (ctx .Repo .Repository .ObjectFormatName ), baseRef .ShortName ())
1202+ 	headRefValid  :=  headRef .IsBranch () ||  headRef .IsTag () ||  git .IsStringLikelyCommitID (git .ObjectFormatFromName (headRepo .ObjectFormatName ), headRef .ShortName ())
1203+ 	// Check if base&head ref are valid. 
1204+ 	if  ! baseRefValid  ||  ! headRefValid  {
12061205		ctx .NotFound ()
1207- 		return  nil , nil ,  nil ,  "" ,  "" 
1206+ 		return  nil , nil 
12081207	}
12091208
1210- 	compareInfo , err  :=  headGitRepo .GetCompareInfo (repo_model .RepoPath (baseRepo .Owner .Name , baseRepo .Name ), baseBranch ,  headBranch , false , false )
1209+ 	compareInfo , err  :=  headGitRepo .GetCompareInfo (repo_model .RepoPath (baseRepo .Owner .Name , baseRepo .Name ), baseRef . ShortName (),  headRef . ShortName () , false , false )
12111210	if  err  !=  nil  {
1212- 		headGitRepo .Close ()
12131211		ctx .Error (http .StatusInternalServerError , "GetCompareInfo" , err )
1214- 		return  nil , nil ,  nil ,  "" ,  "" 
1212+ 		return  nil , nil 
12151213	}
12161214
1217- 	return  headRepo , headGitRepo , compareInfo , baseBranch , headBranch 
1215+ 	result  =  & parseCompareInfoResult {headRepo : headRepo , headGitRepo : headGitRepo , compareInfo : compareInfo , baseRef : baseRef , headRef : headRef }
1216+ 	return  result , closer 
12181217}
12191218
12201219// UpdatePullRequest merge PR's baseBranch into headBranch 
0 commit comments