diff --git a/src/main/scala/gitbucket/core/service/MergeService.scala b/src/main/scala/gitbucket/core/service/MergeService.scala index c67f255..6ad30a6 100644 --- a/src/main/scala/gitbucket/core/service/MergeService.scala +++ b/src/main/scala/gitbucket/core/service/MergeService.scala @@ -3,25 +3,26 @@ import gitbucket.core.model.Account import gitbucket.core.util.Directory._ import gitbucket.core.util.SyntaxSugars._ - import org.eclipse.jgit.merge.MergeStrategy import org.eclipse.jgit.api.Git import org.eclipse.jgit.transport.RefSpec import org.eclipse.jgit.errors.NoMergeBaseException -import org.eclipse.jgit.lib.{ObjectId, CommitBuilder, PersonIdent, Repository} -import org.eclipse.jgit.revwalk.RevWalk +import org.eclipse.jgit.lib.{CommitBuilder, ObjectId, PersonIdent, Repository} +import org.eclipse.jgit.revwalk.{RevCommit, RevWalk} trait MergeService { import MergeService._ + /** * Checks whether conflict will be caused in merging within pull request. * Returns true if conflict will be caused. */ def checkConflict(userName: String, repositoryName: String, branch: String, issueId: Int): Boolean = { using(Git.open(getRepositoryDir(userName, repositoryName))) { git => - MergeCacheInfo(git, branch, issueId).checkConflict() + new MergeCacheInfo(git, branch, issueId).checkConflict() } } + /** * Checks whether conflict will be caused in merging within pull request. * only cache check. @@ -30,13 +31,15 @@ */ def checkConflictCache(userName: String, repositoryName: String, branch: String, issueId: Int): Option[Boolean] = { using(Git.open(getRepositoryDir(userName, repositoryName))) { git => - MergeCacheInfo(git, branch, issueId).checkConflictCache() + new MergeCacheInfo(git, branch, issueId).checkConflictCache() } } + /** merge pull request */ - def mergePullRequest(git:Git, branch: String, issueId: Int, message:String, committer:PersonIdent): Unit = { - MergeCacheInfo(git, branch, issueId).merge(message, committer) + def mergePullRequest(git:Git, branch: String, issueId: Int, message:String, committer: PersonIdent): Unit = { + new MergeCacheInfo(git, branch, issueId).merge(message, committer) } + /** fetch remote branch to my repository refs/pull/{issueId}/head */ def fetchAsPullRequest(userName: String, repositoryName: String, requestUserName: String, requestRepositoryName: String, requestBranch:String, issueId:Int){ using(Git.open(getRepositoryDir(userName, repositoryName))){ git => @@ -46,6 +49,7 @@ .call } } + /** * Checks whether conflict will be caused in merging. Returns true if conflict will be caused. */ @@ -81,6 +85,7 @@ } } } + /** * Checks whether conflict will be caused in merging. Returns true if conflict will be caused. */ @@ -102,7 +107,9 @@ } } + object MergeService{ + object Util{ // return treeId def createMergeCommit(repository: Repository, treeId: ObjectId, committer: PersonIdent, message: String, parents: Seq[ObjectId]): ObjectId = { @@ -119,7 +126,8 @@ inserter.close() mergeCommitId } - def updateRefs(repository: Repository, ref: String, newObjectId: ObjectId, force: Boolean, committer: PersonIdent, refLogMessage: Option[String] = None):Unit = { + + def updateRefs(repository: Repository, ref: String, newObjectId: ObjectId, force: Boolean, committer: PersonIdent, refLogMessage: Option[String] = None): Unit = { // update refs val refUpdate = repository.updateRef(ref) refUpdate.setNewObjectId(newObjectId) @@ -129,21 +137,25 @@ refUpdate.update() } } - case class MergeCacheInfo(git:Git, branch:String, issueId:Int){ - val repository = git.getRepository - val mergedBranchName = s"refs/pull/${issueId}/merge" - val conflictedBranchName = s"refs/pull/${issueId}/conflict" + + class MergeCacheInfo(git: Git, branch: String, issueId: Int){ + + private val repository = git.getRepository + private val mergedBranchName = s"refs/pull/${issueId}/merge" + private val conflictedBranchName = s"refs/pull/${issueId}/conflict" + lazy val mergeBaseTip = repository.resolve(s"refs/heads/${branch}") lazy val mergeTip = repository.resolve(s"refs/pull/${issueId}/head") + def checkConflictCache(): Option[Boolean] = { - Option(repository.resolve(mergedBranchName)).flatMap{ merged => - if(parseCommit(merged).getParents().toSet == Set( mergeBaseTip, mergeTip )){ - // merged branch exists - Some(false) - } else { - None - } - }.orElse(Option(repository.resolve(conflictedBranchName)).flatMap{ conflicted => + Option(repository.resolve(mergedBranchName)).flatMap { merged => + if(parseCommit(merged).getParents().toSet == Set( mergeBaseTip, mergeTip )){ + // merged branch exists + Some(false) + } else { + None + } + }.orElse(Option(repository.resolve(conflictedBranchName)).flatMap { conflicted => if(parseCommit(conflicted).getParents().toSet == Set( mergeBaseTip, mergeTip )){ // conflict branch exists Some(true) @@ -152,10 +164,12 @@ } }) } - def checkConflict():Boolean ={ + + def checkConflict(): Boolean = { checkConflictCache.getOrElse(checkConflictForce) } - def checkConflictForce():Boolean ={ + + def checkConflictForce(): Boolean = { val merger = MergeStrategy.RECURSIVE.newMerger(repository, true) val conflicted = try { !merger.merge(mergeBaseTip, mergeTip) @@ -164,11 +178,13 @@ } val mergeTipCommit = using(new RevWalk( repository ))(_.parseCommit( mergeTip )) val committer = mergeTipCommit.getCommitterIdent - def updateBranch(treeId:ObjectId, message:String, branchName:String){ + + def updateBranch(treeId: ObjectId, message: String, branchName: String){ // creates merge commit val mergeCommitId = createMergeCommit(treeId, committer, message) Util.updateRefs(repository, branchName, mergeCommitId, true, committer) } + if(!conflicted){ updateBranch(merger.getResultTreeId, s"Merge ${mergeTip.name} into ${mergeBaseTip.name}", mergedBranchName) git.branchDelete().setForce(true).setBranchNames(conflictedBranchName).call() @@ -178,21 +194,26 @@ } conflicted } + // update branch from cache - def merge(message:String, committer:PersonIdent) = { + def merge(message: String, committer: PersonIdent) = { if(checkConflict()){ throw new RuntimeException("This pull request can't merge automatically.") } - val mergeResultCommit = parseCommit( Option(repository.resolve(mergedBranchName)).getOrElse(throw new RuntimeException(s"not found branch ${mergedBranchName}")) ) + val mergeResultCommit = parseCommit(Option(repository.resolve(mergedBranchName)).getOrElse { + throw new RuntimeException(s"not found branch ${mergedBranchName}") + }) // creates merge commit val mergeCommitId = createMergeCommit(mergeResultCommit.getTree().getId(), committer, message) // update refs Util.updateRefs(repository, s"refs/heads/${branch}", mergeCommitId, false, committer, Some("merged")) } + // return treeId private def createMergeCommit(treeId: ObjectId, committer: PersonIdent, message: String) = Util.createMergeCommit(repository, treeId, committer, message, Seq[ObjectId](mergeBaseTip, mergeTip)) private def parseCommit(id:ObjectId) = using(new RevWalk( repository ))(_.parseCommit(id)) + } } diff --git a/src/main/scala/gitbucket/core/util/JGitUtil.scala b/src/main/scala/gitbucket/core/util/JGitUtil.scala index fd70e67..e34627e 100644 --- a/src/main/scala/gitbucket/core/util/JGitUtil.scala +++ b/src/main/scala/gitbucket/core/util/JGitUtil.scala @@ -981,7 +981,7 @@ val blame = blamer.call() var blameMap = Map[String, JGitUtil.BlameInfo]() var idLine = List[(String, Int)]() - val commits = 0.to(blame.getResultContents().size() - 1).map{ i => + val commits = 0.to(blame.getResultContents().size() - 1).map { i => val c = blame.getSourceCommit(i) if(!blameMap.contains(c.name)){ blameMap += c.name -> JGitUtil.BlameInfo(