@ -145,9 +145,21 @@ func setCsvCompareContext(ctx *context.Context) {
}
}
// CompareInfo represents the collected results from ParseCompareInfo
type CompareInfo struct {
HeadUser * models . User
HeadRepo * models . Repository
HeadGitRepo * git . Repository
CompareInfo * git . CompareInfo
BaseBranch string
HeadBranch string
DirectComparison bool
}
// ParseCompareInfo parse compare info between two commit for preparing comparing references
func ParseCompareInfo ( ctx * context . Context ) ( * models . User , * models . Repository , * git . Repository , * git . CompareInfo , string , string ) {
func ParseCompareInfo ( ctx * context . Context ) * CompareInfo {
baseRepo := ctx . Repo . Repository
ci := & CompareInfo { }
// Get compared branches information
// A full compare url is of the form:
@ -173,92 +185,97 @@ func ParseCompareInfo(ctx *context.Context) (*models.User, *models.Repository, *
// same repo: master...feature
var (
headUser * models . User
headRepo * models . Repository
headBranch string
isSameRepo bool
infoPath string
err error
)
infoPath = ctx . Params ( "*" )
infos := strings . SplitN ( infoPath , "..." , 2 )
if len ( infos ) != 2 {
infos = strings . SplitN ( infoPath , ".." , 2 )
ci . DirectComparison = true
ctx . Data [ "PageIsComparePull" ] = false
}
if len ( infos ) != 2 {
log . Trace ( "ParseCompareInfo[%d]: not enough compared branches information %s" , baseRepo . ID , infos )
ctx . NotFound ( "CompareAndPullRequest" , nil )
return nil , nil , nil , nil , "" , ""
return nil
}
ctx . Data [ "BaseName" ] = baseRepo . OwnerName
baseBranch : = infos [ 0 ]
ctx . Data [ "BaseBranch" ] = b aseBranch
ci . BaseBranch = infos [ 0 ]
ctx . Data [ "BaseBranch" ] = ci . B aseBranch
// If there is no head repository, it means compare between same repository.
headInfos := strings . Split ( infos [ 1 ] , ":" )
if len ( headInfos ) == 1 {
isSameRepo = true
h eadUser = ctx . Repo . Owner
h eadBranch = headInfos [ 0 ]
ci . H eadUser = ctx . Repo . Owner
ci . H eadBranch = headInfos [ 0 ]
} else if len ( headInfos ) == 2 {
headInfosSplit := strings . Split ( headInfos [ 0 ] , "/" )
if len ( headInfosSplit ) == 1 {
h eadUser, err = models . GetUserByName ( headInfos [ 0 ] )
ci . H eadUser, err = models . GetUserByName ( headInfos [ 0 ] )
if err != nil {
if models . IsErrUserNotExist ( err ) {
ctx . NotFound ( "GetUserByName" , nil )
} else {
ctx . ServerError ( "GetUserByName" , err )
}
return nil , nil , nil , nil , "" , ""
return nil
}
h eadBranch = headInfos [ 1 ]
isSameRepo = h eadUser. ID == ctx . Repo . Owner . ID
ci . H eadBranch = headInfos [ 1 ]
isSameRepo = ci . H eadUser. ID == ctx . Repo . Owner . ID
if isSameRepo {
h eadRepo = baseRepo
ci . H eadRepo = baseRepo
}
} else {
h eadRepo, err = models . GetRepositoryByOwnerAndName ( headInfosSplit [ 0 ] , headInfosSplit [ 1 ] )
ci . H eadRepo, err = models . GetRepositoryByOwnerAndName ( headInfosSplit [ 0 ] , headInfosSplit [ 1 ] )
if err != nil {
if models . IsErrRepoNotExist ( err ) {
ctx . NotFound ( "GetRepositoryByOwnerAndName" , nil )
} else {
ctx . ServerError ( "GetRepositoryByOwnerAndName" , err )
}
return nil , nil , nil , nil , "" , ""
return nil
}
if err := h eadRepo. GetOwner ( ) ; err != nil {
if err := ci . H eadRepo. GetOwner ( ) ; err != nil {
if models . IsErrUserNotExist ( err ) {
ctx . NotFound ( "GetUserByName" , nil )
} else {
ctx . ServerError ( "GetUserByName" , err )
}
return nil , nil , nil , nil , "" , ""
return nil
}
h eadBranch = headInfos [ 1 ]
headUser = h eadRepo. Owner
isSameRepo = h eadRepo. ID == ctx . Repo . Repository . ID
ci . H eadBranch = headInfos [ 1 ]
ci . HeadUser = ci . H eadRepo. Owner
isSameRepo = ci . H eadRepo. ID == ctx . Repo . Repository . ID
}
} else {
ctx . NotFound ( "CompareAndPullRequest" , nil )
return nil , nil , nil , nil , "" , ""
return nil
}
ctx . Data [ "HeadUser" ] = h eadUser
ctx . Data [ "HeadBranch" ] = h eadBranch
ctx . Data [ "HeadUser" ] = ci . H eadUser
ctx . Data [ "HeadBranch" ] = ci . H eadBranch
ctx . Repo . PullRequest . SameRepo = isSameRepo
// Check if base branch is valid.
baseIsCommit := ctx . Repo . GitRepo . IsCommitExist ( b aseBranch)
baseIsBranch := ctx . Repo . GitRepo . IsBranchExist ( b aseBranch)
baseIsTag := ctx . Repo . GitRepo . IsTagExist ( b aseBranch)
baseIsCommit := ctx . Repo . GitRepo . IsCommitExist ( ci . B aseBranch)
baseIsBranch := ctx . Repo . GitRepo . IsBranchExist ( ci . B aseBranch)
baseIsTag := ctx . Repo . GitRepo . IsTagExist ( ci . B aseBranch)
if ! baseIsCommit && ! baseIsBranch && ! baseIsTag {
// Check if baseBranch is short sha commit hash
if baseCommit , _ := ctx . Repo . GitRepo . GetCommit ( b aseBranch) ; baseCommit != nil {
b aseBranch = baseCommit . ID . String ( )
ctx . Data [ "BaseBranch" ] = b aseBranch
if baseCommit , _ := ctx . Repo . GitRepo . GetCommit ( ci . B aseBranch) ; baseCommit != nil {
ci . B aseBranch = baseCommit . ID . String ( )
ctx . Data [ "BaseBranch" ] = ci . B aseBranch
baseIsCommit = true
} else {
ctx . NotFound ( "IsRefExist" , nil )
return nil , nil , nil , nil , "" , ""
return nil
}
}
ctx . Data [ "BaseIsCommit" ] = baseIsCommit
@ -284,7 +301,7 @@ func ParseCompareInfo(ctx *context.Context) (*models.User, *models.Repository, *
if err != nil {
if ! models . IsErrRepoNotExist ( err ) {
ctx . ServerError ( "Unable to find root repo" , err )
return nil , nil , nil , nil , "" , ""
return nil
}
} else {
rootRepo = baseRepo . BaseRepo
@ -303,29 +320,29 @@ func ParseCompareInfo(ctx *context.Context) (*models.User, *models.Repository, *
}
}
has := h eadRepo != nil
has := ci . H eadRepo != nil
// 3. If the base is a forked from "RootRepo" and the owner of
// the "RootRepo" is the :headUser - set headRepo to that
if ! has && rootRepo != nil && rootRepo . OwnerID == h eadUser. ID {
h eadRepo = rootRepo
if ! has && rootRepo != nil && rootRepo . OwnerID == ci . H eadUser. ID {
ci . H eadRepo = rootRepo
has = true
}
// 4. If the ctx.User has their own fork of the baseRepo and the headUser is the ctx.User
// set the headRepo to the ownFork
if ! has && ownForkRepo != nil && ownForkRepo . OwnerID == h eadUser. ID {
h eadRepo = ownForkRepo
if ! has && ownForkRepo != nil && ownForkRepo . OwnerID == ci . H eadUser. ID {
ci . H eadRepo = ownForkRepo
has = true
}
// 5. If the headOwner has a fork of the baseRepo - use that
if ! has {
h eadRepo, has = models . HasForkedRepo ( h eadUser. ID , baseRepo . ID )
ci . H eadRepo, has = models . HasForkedRepo ( ci . H eadUser. ID , baseRepo . ID )
}
// 6. If the baseRepo is a fork and the headUser has a fork of that use that
if ! has && baseRepo . IsFork {
h eadRepo, has = models . HasForkedRepo ( h eadUser. ID , baseRepo . ForkID )
ci . H eadRepo, has = models . HasForkedRepo ( ci . H eadUser. ID , baseRepo . ForkID )
}
// 7. Otherwise if we're not the same repo and haven't found a repo give up
@ -334,20 +351,19 @@ func ParseCompareInfo(ctx *context.Context) (*models.User, *models.Repository, *
}
// 8. Finally open the git repo
var headGitRepo * git . Repository
if isSameRepo {
h eadRepo = ctx . Repo . Repository
h eadGitRepo = ctx . Repo . GitRepo
ci . H eadRepo = ctx . Repo . Repository
ci . H eadGitRepo = ctx . Repo . GitRepo
} else if has {
h eadGitRepo, err = git . OpenRepository ( h eadRepo. RepoPath ( ) )
ci . H eadGitRepo, err = git . OpenRepository ( ci . H eadRepo. RepoPath ( ) )
if err != nil {
ctx . ServerError ( "OpenRepository" , err )
return nil , nil , nil , nil , "" , ""
return nil
}
defer h eadGitRepo. Close ( )
defer ci . H eadGitRepo. Close ( )
}
ctx . Data [ "HeadRepo" ] = h eadRepo
ctx . Data [ "HeadRepo" ] = ci . H eadRepo
// Now we need to assert that the ctx.User has permission to read
// the baseRepo's code and pulls
@ -355,7 +371,7 @@ func ParseCompareInfo(ctx *context.Context) (*models.User, *models.Repository, *
permBase , err := models . GetUserRepoPermission ( baseRepo , ctx . User )
if err != nil {
ctx . ServerError ( "GetUserRepoPermission" , err )
return nil , nil , nil , nil , "" , ""
return nil
}
if ! permBase . CanRead ( models . UnitTypeCode ) {
if log . IsTrace ( ) {
@ -365,26 +381,26 @@ func ParseCompareInfo(ctx *context.Context) (*models.User, *models.Repository, *
permBase )
}
ctx . NotFound ( "ParseCompareInfo" , nil )
return nil , nil , nil , nil , "" , ""
return nil
}
// If we're not merging from the same repo:
if ! isSameRepo {
// Assert ctx.User has permission to read headRepo's codes
permHead , err := models . GetUserRepoPermission ( h eadRepo, ctx . User )
permHead , err := models . GetUserRepoPermission ( ci . H eadRepo, ctx . User )
if err != nil {
ctx . ServerError ( "GetUserRepoPermission" , err )
return nil , nil , nil , nil , "" , ""
return nil
}
if ! permHead . CanRead ( models . UnitTypeCode ) {
if log . IsTrace ( ) {
log . Trace ( "Permission Denied: User: %-v cannot read code in Repo: %-v\nUser in headRepo has Permissions: %-+v" ,
ctx . User ,
h eadRepo,
ci . H eadRepo,
permHead )
}
ctx . NotFound ( "ParseCompareInfo" , nil )
return nil , nil , nil , nil , "" , ""
return nil
}
}
@ -393,12 +409,12 @@ func ParseCompareInfo(ctx *context.Context) (*models.User, *models.Repository, *
// 2. the computed head
// then get the branches of it
if rootRepo != nil &&
rootRepo . ID != h eadRepo. ID &&
rootRepo . ID != ci . H eadRepo. ID &&
rootRepo . ID != baseRepo . ID {
perm , branches , tags , err := getBranchesAndTagsForRepo ( ctx . User , rootRepo )
if err != nil {
ctx . ServerError ( "GetBranchesForRepo" , err )
return nil , nil , nil , nil , "" , ""
return nil
}
if perm {
ctx . Data [ "RootRepo" ] = rootRepo
@ -413,13 +429,13 @@ func ParseCompareInfo(ctx *context.Context) (*models.User, *models.Repository, *
// 3. The rootRepo (if we have one)
// then get the branches from it.
if ownForkRepo != nil &&
ownForkRepo . ID != h eadRepo. ID &&
ownForkRepo . ID != ci . H eadRepo. ID &&
ownForkRepo . ID != baseRepo . ID &&
( rootRepo == nil || ownForkRepo . ID != rootRepo . ID ) {
perm , branches , tags , err := getBranchesAndTagsForRepo ( ctx . User , ownForkRepo )
if err != nil {
ctx . ServerError ( "GetBranchesForRepo" , err )
return nil , nil , nil , nil , "" , ""
return nil
}
if perm {
ctx . Data [ "OwnForkRepo" ] = ownForkRepo
@ -429,18 +445,18 @@ func ParseCompareInfo(ctx *context.Context) (*models.User, *models.Repository, *
}
// Check if head branch is valid.
headIsCommit := h eadGitRepo. IsCommitExist ( h eadBranch)
headIsBranch := h eadGitRepo. IsBranchExist ( h eadBranch)
headIsTag := h eadGitRepo. IsTagExist ( h eadBranch)
headIsCommit := ci . H eadGitRepo. IsCommitExist ( ci . H eadBranch)
headIsBranch := ci . H eadGitRepo. IsBranchExist ( ci . H eadBranch)
headIsTag := ci . H eadGitRepo. IsTagExist ( ci . H eadBranch)
if ! headIsCommit && ! headIsBranch && ! headIsTag {
// Check if headBranch is short sha commit hash
if headCommit , _ := h eadGitRepo. GetCommit ( h eadBranch) ; headCommit != nil {
h eadBranch = headCommit . ID . String ( )
ctx . Data [ "HeadBranch" ] = h eadBranch
if headCommit , _ := ci . H eadGitRepo. GetCommit ( ci . H eadBranch) ; headCommit != nil {
ci . H eadBranch = headCommit . ID . String ( )
ctx . Data [ "HeadBranch" ] = ci . H eadBranch
headIsCommit = true
} else {
ctx . NotFound ( "IsRefExist" , nil )
return nil , nil , nil , nil , "" , ""
return nil
}
}
ctx . Data [ "HeadIsCommit" ] = headIsCommit
@ -460,40 +476,36 @@ func ParseCompareInfo(ctx *context.Context) (*models.User, *models.Repository, *
permBase )
}
ctx . NotFound ( "ParseCompareInfo" , nil )
return nil , nil , nil , nil , "" , ""
return nil
}
baseBranchRef := b aseBranch
baseBranchRef := ci . B aseBranch
if baseIsBranch {
baseBranchRef = git . BranchPrefix + b aseBranch
baseBranchRef = git . BranchPrefix + ci . B aseBranch
} else if baseIsTag {
baseBranchRef = git . TagPrefix + b aseBranch
baseBranchRef = git . TagPrefix + ci . B aseBranch
}
headBranchRef := h eadBranch
headBranchRef := ci . H eadBranch
if headIsBranch {
headBranchRef = git . BranchPrefix + h eadBranch
headBranchRef = git . BranchPrefix + ci . H eadBranch
} else if headIsTag {
headBranchRef = git . TagPrefix + h eadBranch
headBranchRef = git . TagPrefix + ci . H eadBranch
}
compareInfo , err := h eadGitRepo. GetCompareInfo ( baseRepo . RepoPath ( ) , baseBranchRef , headBranchRef )
ci . C ompareInfo , err = ci . H eadGitRepo. GetCompareInfo ( baseRepo . RepoPath ( ) , baseBranchRef , headBranchRef , ci . DirectComparison )
if err != nil {
ctx . ServerError ( "GetCompareInfo" , err )
return nil , nil , nil , nil , "" , ""
return nil
}
ctx . Data [ "BeforeCommitID" ] = compareInfo . MergeBase
ctx . Data [ "BeforeCommitID" ] = ci . C ompareInfo . MergeBase
return headUser , headRepo , headG itRepo , compareInfo , baseBranch , headBranch
return c i
}
// PrepareCompareDiff renders compare diff page
func PrepareCompareDiff (
ctx * context . Context ,
headUser * models . User ,
headRepo * models . Repository ,
headGitRepo * git . Repository ,
compareInfo * git . CompareInfo ,
baseBranch , headBranch string ,
ci * CompareInfo ,
whitespaceBehavior string ) bool {
var (
@ -503,19 +515,20 @@ func PrepareCompareDiff(
)
// Get diff information.
ctx . Data [ "CommitRepoLink" ] = h eadRepo. Link ( )
ctx . Data [ "CommitRepoLink" ] = ci . H eadRepo. Link ( )
headCommitID := compareInfo . HeadCommitID
headCommitID := ci . C ompareInfo . HeadCommitID
ctx . Data [ "AfterCommitID" ] = headCommitID
if headCommitID == compareInfo . MergeBase {
if ( headCommitID == ci . CompareInfo . MergeBase && ! ci . DirectComparison ) ||
headCommitID == ci . CompareInfo . BaseCommitID {
ctx . Data [ "IsNothingToCompare" ] = true
if unit , err := repo . GetUnit ( models . UnitTypePullRequests ) ; err == nil {
config := unit . PullRequestsConfig ( )
if ! config . AutodetectManualMerge {
allowEmptyPr := ! ( baseBranch == h eadBranch && ctx . Repo . Repository . Name == h eadRepo. Name )
allowEmptyPr := ! ( ci . BaseBranch == ci . H eadBranch && ctx . Repo . Repository . Name == ci . H eadRepo. Name )
ctx . Data [ "AllowEmptyPr" ] = allowEmptyPr
return ! allowEmptyPr
@ -526,9 +539,14 @@ func PrepareCompareDiff(
return true
}
diff , err := gitdiff . GetDiffRangeWithWhitespaceBehavior ( headGitRepo ,
compareInfo . MergeBase , headCommitID , setting . Git . MaxGitDiffLines ,
setting . Git . MaxGitDiffLineCharacters , setting . Git . MaxGitDiffFiles , whitespaceBehavior )
beforeCommitID := ci . CompareInfo . MergeBase
if ci . DirectComparison {
beforeCommitID = ci . CompareInfo . BaseCommitID
}
diff , err := gitdiff . GetDiffRangeWithWhitespaceBehavior ( ci . HeadGitRepo ,
beforeCommitID , headCommitID , setting . Git . MaxGitDiffLines ,
setting . Git . MaxGitDiffLineCharacters , setting . Git . MaxGitDiffFiles , whitespaceBehavior , ci . DirectComparison )
if err != nil {
ctx . ServerError ( "GetDiffRangeWithWhitespaceBehavior" , err )
return false
@ -536,14 +554,14 @@ func PrepareCompareDiff(
ctx . Data [ "Diff" ] = diff
ctx . Data [ "DiffNotAvailable" ] = diff . NumFiles == 0
headCommit , err := h eadGitRepo. GetCommit ( headCommitID )
headCommit , err := ci . H eadGitRepo. GetCommit ( headCommitID )
if err != nil {
ctx . ServerError ( "GetCommit" , err )
return false
}
baseGitRepo := ctx . Repo . GitRepo
baseCommitID := compareInfo . BaseCommitID
baseCommitID := ci . C ompareInfo . BaseCommitID
baseCommit , err := baseGitRepo . GetCommit ( baseCommitID )
if err != nil {
@ -551,7 +569,7 @@ func PrepareCompareDiff(
return false
}
commits := models . ConvertFromGitCommit ( compareInfo . Commits , h eadRepo)
commits := models . ConvertFromGitCommit ( ci . C ompareInfo . Commits , ci . H eadRepo)
ctx . Data [ "Commits" ] = commits
ctx . Data [ "CommitCount" ] = len ( commits )
@ -564,7 +582,7 @@ func PrepareCompareDiff(
ctx . Data [ "content" ] = strings . Join ( body [ 1 : ] , "\n" )
}
} else {
title = h eadBranch
title = ci . H eadBranch
}
if len ( title ) > 255 {
var trailer string
@ -579,10 +597,10 @@ func PrepareCompareDiff(
}
ctx . Data [ "title" ] = title
ctx . Data [ "Username" ] = h eadUser. Name
ctx . Data [ "Reponame" ] = h eadRepo. Name
ctx . Data [ "Username" ] = ci . H eadUser. Name
ctx . Data [ "Reponame" ] = ci . H eadRepo. Name
headTarget := path . Join ( h eadUser. Name , repo . Name )
headTarget := path . Join ( ci . H eadUser. Name , repo . Name )
setCompareContext ( ctx , baseCommit , headCommit , headTarget )
return false
@ -615,17 +633,25 @@ func getBranchesAndTagsForRepo(user *models.User, repo *models.Repository) (bool
// CompareDiff show different from one commit to another commit
func CompareDiff ( ctx * context . Context ) {
headUser , headRepo , headG itRepo , compareInfo , baseBranch , headBranch := ParseCompareInfo ( ctx )
c i := ParseCompareInfo ( ctx )
defer func ( ) {
if h eadGitRepo != nil {
h eadGitRepo. Close ( )
if ci . H eadGitRepo != nil {
ci . H eadGitRepo. Close ( )
}
} ( )
if ctx . Written ( ) {
return
}
nothingToCompare := PrepareCompareDiff ( ctx , headUser , headRepo , headGitRepo , compareInfo , baseBranch , headBranch ,
ctx . Data [ "DirectComparison" ] = ci . DirectComparison
ctx . Data [ "OtherCompareSeparator" ] = ".."
ctx . Data [ "CompareSeparator" ] = "..."
if ci . DirectComparison {
ctx . Data [ "CompareSeparator" ] = ".."
ctx . Data [ "OtherCompareSeparator" ] = "..."
}
nothingToCompare := PrepareCompareDiff ( ctx , ci ,
gitdiff . GetWhitespaceFlag ( ctx . Data [ "WhitespaceBehavior" ] . ( string ) ) )
if ctx . Written ( ) {
return
@ -639,14 +665,14 @@ func CompareDiff(ctx *context.Context) {
}
ctx . Data [ "Tags" ] = baseTags
headBranches , _ , err := h eadGitRepo. GetBranches ( 0 , 0 )
headBranches , _ , err := ci . H eadGitRepo. GetBranches ( 0 , 0 )
if err != nil {
ctx . ServerError ( "GetBranches" , err )
return
}
ctx . Data [ "HeadBranches" ] = headBranches
headTags , err := h eadGitRepo. GetTags ( 0 , 0 )
headTags , err := ci . H eadGitRepo. GetTags ( 0 , 0 )
if err != nil {
ctx . ServerError ( "GetTags" , err )
return
@ -654,7 +680,7 @@ func CompareDiff(ctx *context.Context) {
ctx . Data [ "HeadTags" ] = headTags
if ctx . Data [ "PageIsComparePull" ] == true {
pr , err := models . GetUnmergedPullRequest ( h eadRepo. ID , ctx . Repo . Repository . ID , headBranch , b aseBranch, models . PullRequestFlowGithub )
pr , err := models . GetUnmergedPullRequest ( ci . H eadRepo. ID , ctx . Repo . Repository . ID , ci . HeadBranch , ci . B aseBranch, models . PullRequestFlowGithub )
if err != nil {
if ! models . IsErrPullRequestNotExist ( err ) {
ctx . ServerError ( "GetUnmergedPullRequest" , err )
@ -678,7 +704,11 @@ func CompareDiff(ctx *context.Context) {
beforeCommitID := ctx . Data [ "BeforeCommitID" ] . ( string )
afterCommitID := ctx . Data [ "AfterCommitID" ] . ( string )
ctx . Data [ "Title" ] = "Comparing " + base . ShortSha ( beforeCommitID ) + "..." + base . ShortSha ( afterCommitID )
separator := "..."
if ci . DirectComparison {
separator = ".."
}
ctx . Data [ "Title" ] = "Comparing " + base . ShortSha ( beforeCommitID ) + separator + base . ShortSha ( afterCommitID )
ctx . Data [ "IsRepoToolbarCommits" ] = true
ctx . Data [ "IsDiffCompare" ] = true