mirror of
https://github.com/gitbucket/gitbucket.git
synced 2025-11-02 11:36:05 +01:00
(refs #2)Comparing between all forked repositories.
This commit is contained in:
@@ -10,6 +10,7 @@ import jp.sf.amateras.scalatra.forms._
|
||||
import org.eclipse.jgit.transport.RefSpec
|
||||
import org.apache.commons.io.FileUtils
|
||||
import scala.collection.JavaConverters._
|
||||
import service.RepositoryService.RepositoryTreeNode
|
||||
|
||||
class PullRequestsController extends PullRequestsControllerBase
|
||||
with RepositoryService with AccountService with IssuesService with PullRequestService with MilestonesService with ActivityService
|
||||
@@ -137,37 +138,38 @@ trait PullRequestsControllerBase extends ControllerBase {
|
||||
|
||||
private def checkConflict(userName: String, repositoryName: String, branch: String,
|
||||
requestUserName: String, requestRepositoryName: String, requestBranch: String): Boolean = {
|
||||
LockUtil.lock(s"${userName}/${repositoryName}/merge-check"){
|
||||
val remote = getRepositoryDir(userName, repositoryName)
|
||||
val tmpdir = new java.io.File(getTemporaryDir(userName, repositoryName), "merge-check")
|
||||
if(tmpdir.exists()){
|
||||
FileUtils.deleteDirectory(tmpdir)
|
||||
}
|
||||
|
||||
val git = Git.cloneRepository.setDirectory(tmpdir).setURI(remote.toURI.toString).call
|
||||
try {
|
||||
git.checkout.setName(branch).call
|
||||
|
||||
git.fetch
|
||||
.setRemote(getRepositoryDir(requestUserName, requestRepositoryName).toURI.toString)
|
||||
.setRefSpecs(new RefSpec(s"refs/heads/${branch}:refs/heads/${requestBranch}")).call
|
||||
|
||||
val result = git.merge
|
||||
.include(git.getRepository.resolve("FETCH_HEAD"))
|
||||
.setCommit(false).call
|
||||
|
||||
result.getConflicts != null
|
||||
|
||||
} finally {
|
||||
git.getRepository.close
|
||||
FileUtils.deleteDirectory(tmpdir)
|
||||
}
|
||||
}
|
||||
// LockUtil.lock(s"${userName}/${repositoryName}/merge-check"){
|
||||
// val remote = getRepositoryDir(userName, repositoryName)
|
||||
// val tmpdir = new java.io.File(getTemporaryDir(userName, repositoryName), "merge-check")
|
||||
// if(tmpdir.exists()){
|
||||
// FileUtils.deleteDirectory(tmpdir)
|
||||
// }
|
||||
//
|
||||
// val git = Git.cloneRepository.setDirectory(tmpdir).setURI(remote.toURI.toString).call
|
||||
// try {
|
||||
// git.checkout.setName(branch).call
|
||||
//
|
||||
// git.fetch
|
||||
// .setRemote(getRepositoryDir(requestUserName, requestRepositoryName).toURI.toString)
|
||||
// .setRefSpecs(new RefSpec(s"refs/heads/${branch}:refs/heads/${requestBranch}")).call
|
||||
//
|
||||
// val result = git.merge
|
||||
// .include(git.getRepository.resolve("FETCH_HEAD"))
|
||||
// .setCommit(false).call
|
||||
//
|
||||
// result.getConflicts != null
|
||||
//
|
||||
// } finally {
|
||||
// git.getRepository.close
|
||||
// FileUtils.deleteDirectory(tmpdir)
|
||||
// }
|
||||
// }
|
||||
true
|
||||
}
|
||||
|
||||
get("/:owner/:repository/pulls/compare")(collaboratorsOnly { newRepo =>
|
||||
(newRepo.repository.originUserName, newRepo.repository.originRepositoryName) match {
|
||||
case (None,_)|(_, None) => NotFound // TODO BadRequest?
|
||||
case (None,_)|(_, None) => NotFound // TODO Compare to self branch?
|
||||
case (Some(originUserName), Some(originRepositoryName)) => {
|
||||
getRepository(originUserName, originRepositoryName, baseUrl).map { oldRepo =>
|
||||
withGit(
|
||||
@@ -184,39 +186,63 @@ trait PullRequestsControllerBase extends ControllerBase {
|
||||
}
|
||||
})
|
||||
|
||||
get("/:owner/:repository/pulls/compare/*:*...*")(collaboratorsOnly { repository =>
|
||||
if(repository.repository.originUserName.isEmpty || repository.repository.originRepositoryName.isEmpty){
|
||||
NotFound // TODO BadRequest?
|
||||
private def parseCompareIdentifie(value: String, defaultOwner: String): (String, String) =
|
||||
if(value.contains(':')){
|
||||
val array = value.split(":")
|
||||
(array(0), array(1))
|
||||
} else {
|
||||
val originUserName = repository.repository.originUserName.get
|
||||
val originRepositoryName = repository.repository.originRepositoryName.get
|
||||
(defaultOwner, value)
|
||||
}
|
||||
|
||||
getRepository(originUserName, originRepositoryName, baseUrl).map{ originRepository =>
|
||||
val Seq(compareUserName, compareFrom, compareTo) = multiParams("splat")
|
||||
get("/:owner/:repository/pulls/compare/*...*")(collaboratorsOnly { repository =>
|
||||
val Seq(origin, forked) = multiParams("splat")
|
||||
val (originOwner, tmpOriginBranch) = parseCompareIdentifie(origin, repository.owner)
|
||||
val (forkedOwner, tmpForkedBranch) = parseCompareIdentifie(forked, repository.owner)
|
||||
|
||||
(getRepository(originOwner, repository.name, baseUrl),
|
||||
getRepository(forkedOwner, repository.name, baseUrl)) match {
|
||||
case (Some(originRepository), Some(forkedRepository)) => {
|
||||
withGit(
|
||||
getRepositoryDir(originUserName, originRepositoryName),
|
||||
getRepositoryDir(repository.owner, repository.name)
|
||||
getRepositoryDir(originOwner, repository.name),
|
||||
getRepositoryDir(forkedOwner, repository.name)
|
||||
){ case (oldGit, newGit) =>
|
||||
val originBranch = JGitUtil.getDefaultBranch(oldGit, originRepository, tmpOriginBranch).get._2
|
||||
val forkedBranch = JGitUtil.getDefaultBranch(newGit, forkedRepository, tmpForkedBranch).get._2
|
||||
|
||||
val forkedId = getForkedCommitId(oldGit, newGit, originUserName, originRepositoryName, compareFrom,
|
||||
repository.owner, repository.name, compareTo)
|
||||
val forkedId = getForkedCommitId(oldGit, newGit,
|
||||
originOwner, repository.name, originBranch,
|
||||
forkedOwner, repository.name, forkedBranch)
|
||||
|
||||
val oldId = oldGit.getRepository.resolve(forkedId)
|
||||
val newId = newGit.getRepository.resolve(compareTo)
|
||||
val newId = newGit.getRepository.resolve(forkedBranch)
|
||||
|
||||
val (commits, diffs) = getRequestCompareInfo(
|
||||
compareUserName, repository.repository.originRepositoryName.get, forkedId,
|
||||
repository.owner, repository.name, compareTo)
|
||||
originOwner, repository.name, oldId.getName,
|
||||
forkedOwner, repository.name, newId.getName)
|
||||
|
||||
pulls.html.compare(commits, diffs, compareUserName, compareFrom, compareTo, oldId.getName, newId.getName,
|
||||
checkConflict(originUserName, originRepositoryName, compareFrom, repository.owner, repository.name, compareTo),
|
||||
repository, originRepository)
|
||||
pulls.html.compare(
|
||||
commits,
|
||||
diffs,
|
||||
repository.repository.originUserName.map { userName =>
|
||||
getRepositoryNames(getForkedRepositoryTree(userName, repository.name))
|
||||
} getOrElse Nil,
|
||||
originBranch,
|
||||
forkedBranch,
|
||||
oldId.getName,
|
||||
newId.getName,
|
||||
checkConflict(originOwner, repository.name, originBranch, forkedOwner, repository.name, forkedBranch),
|
||||
repository,
|
||||
originRepository,
|
||||
forkedRepository)
|
||||
}
|
||||
} getOrElse NotFound
|
||||
}
|
||||
case _ => NotFound
|
||||
}
|
||||
})
|
||||
|
||||
private def getRepositoryNames(node: RepositoryTreeNode): List[String] =
|
||||
node.owner :: node.children.map { child => getRepositoryNames(child) }.flatten
|
||||
|
||||
post("/:owner/:repository/pulls/new", pullRequestForm)(referrersOnly { (form, repository) =>
|
||||
val loginUserName = context.loginAccount.get.userName
|
||||
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
@(buttonValue: String = "")(body: Html)
|
||||
@(buttonValue: String = "", prefix: String = "")(body: Html)
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-mini dropdown-toggle" data-toggle="dropdown">
|
||||
@if(buttonValue == ""){
|
||||
@if(buttonValue.isEmpty){
|
||||
<i class="icon-cog"></i>
|
||||
} else {
|
||||
@if(prefix.nonEmpty){
|
||||
<span class="muted">@prefix:</span>
|
||||
}
|
||||
<strong>@buttonValue</strong>
|
||||
}
|
||||
<span class="caret"></span>
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
@(commits: Seq[Seq[util.JGitUtil.CommitInfo]],
|
||||
diffs: Seq[util.JGitUtil.DiffInfo],
|
||||
origin: String,
|
||||
members: List[String],
|
||||
originId: String,
|
||||
forkedId: String,
|
||||
sourceId: String,
|
||||
commitId: String,
|
||||
hasConflict: Boolean,
|
||||
repository: service.RepositoryService.RepositoryInfo,
|
||||
originRepository: service.RepositoryService.RepositoryInfo)(implicit context: app.Context)
|
||||
originRepository: service.RepositoryService.RepositoryInfo,
|
||||
forkedRepository: service.RepositoryService.RepositoryInfo)(implicit context: app.Context)
|
||||
@import context._
|
||||
@import view.helpers._
|
||||
@import org.eclipse.jgit.diff.DiffEntry.ChangeType
|
||||
@@ -16,21 +17,29 @@
|
||||
<div style="border: 1px solid #eee; background-color: #f8f8f8; margin-bottom: 10px; padding: 8px;">
|
||||
<div id="compare-info">
|
||||
<a href="#" id="edit-compare-condition" class="btn btn-mini pull-right">Edit</a>
|
||||
<span class="label label-info monospace">@origin:@originId</span> ... <span class="label label-info monospace">@repository.owner:@forkedId</span>
|
||||
<span class="label label-info monospace">@originRepository.owner:@originId</span> ... <span class="label label-info monospace">@forkedRepository.owner:@forkedId</span>
|
||||
</div>
|
||||
<div id="compare-edit" style="display: none;">
|
||||
<a href="#" id="refresh-compare" class="pull-right"><i class="icon-remove-circle"></i></a>
|
||||
<span class="label label-info monospace">@origin/@repository.name:</span>
|
||||
@helper.html.dropdown(originId) {
|
||||
<a href="#" id="cancel-condition-editing" class="pull-right"><i class="icon-remove-circle"></i></a>
|
||||
@helper.html.dropdown(originRepository.owner + "/" + repository.name, "base fork") {
|
||||
@members.map { member =>
|
||||
<li><a href="#" class="origin-owner" data-name="@member">@helper.html.checkicon(member == originRepository.owner) @member/@repository.name</a></li>
|
||||
}
|
||||
}
|
||||
@helper.html.dropdown(originId, "base") {
|
||||
@originRepository.branchList.map { branch =>
|
||||
<li><a href="#" class="origin-branch" data-branch="@branch">@helper.html.checkicon(branch == originId) @branch</a></li>
|
||||
<li><a href="#" class="origin-branch" data-name="@branch">@helper.html.checkicon(branch == originId) @branch</a></li>
|
||||
}
|
||||
}
|
||||
...
|
||||
<span class="label label-info monospace">@repository.owner/@repository.name:</span>
|
||||
@helper.html.dropdown(forkedId) {
|
||||
@repository.branchList.map { branch =>
|
||||
<li><a href="#" class="forked-branch" data-branch="@branch">@helper.html.checkicon(branch == forkedId) @branch</a></li>
|
||||
@helper.html.dropdown(forkedRepository.owner + "/" + repository.name, "head fork") {
|
||||
@members.map { member =>
|
||||
<li><a href="#" class="forked-owner" data-name="@member">@helper.html.checkicon(member == forkedRepository.owner) @member/@repository.name</a></li>
|
||||
}
|
||||
}
|
||||
@helper.html.dropdown(forkedId, "compare") {
|
||||
@forkedRepository.branchList.map { branch =>
|
||||
<li><a href="#" class="forked-branch" data-name="@branch">@helper.html.checkicon(branch == forkedId) @branch</a></li>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
@@ -41,7 +50,7 @@
|
||||
</div>
|
||||
<div id="pull-request-form" class="box" style="display: none;">
|
||||
<div class="box-content">
|
||||
<form method="POST" action="@path/@origin/@repository.name/pulls/new" validate="true">
|
||||
<form method="POST" action="@path/@originRepository.owner/@repository.name/pulls/new" validate="true">
|
||||
<div style="width: 260px; position: absolute; margin-left: 635px;">
|
||||
@if(hasConflict){
|
||||
<h4>We can’t automatically merge these branches</h4>
|
||||
@@ -71,7 +80,7 @@
|
||||
<tr>
|
||||
<td style="padding: 20px; background-color: #eee; text-align: center;">
|
||||
<h4>There isn't anything to compare.</h4>
|
||||
<strong>@origin:@originId</strong> and <strong>@repository.owner:@forkedId</strong> are identical.
|
||||
<strong>@originRepository.owner:@originId</strong> and <strong>@forkedRepository.owner:@forkedId</strong> are identical.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@@ -133,17 +142,22 @@ $(function(){
|
||||
$('#compare-edit').show();
|
||||
});
|
||||
|
||||
$('a.origin-branch, a.forked-branch').click(function(){
|
||||
$('#cancel-condition-editing').click(function(){
|
||||
$('#compare-info').show();
|
||||
$('#compare-edit').hide();
|
||||
});
|
||||
|
||||
$('a.origin-owner, a.forked-owner, a.origin-branch, a.forked-branch').click(function(){
|
||||
var e = $(this);
|
||||
e.parents('ul').find('i').attr('class', 'icon-white');
|
||||
e.find('i').attr('class', 'icon-ok');
|
||||
e.parents('div.btn-group').find('button strong').text(e.data('branch'));
|
||||
});
|
||||
e.parents('div.btn-group').find('button strong').text(e.text());
|
||||
|
||||
$('#refresh-compare').click(function(){
|
||||
location.href = '@url(repository)/pulls/compare/@origin:' +
|
||||
$.trim($('i.icon-ok').parents('a.origin-branch').text()) + '...' +
|
||||
$.trim($('i.icon-ok').parents('a.forked-branch').text());
|
||||
location.href = '@url(repository)/pulls/compare/' +
|
||||
$.trim($('i.icon-ok').parents('a.origin-owner' ).data('name')) + ':' +
|
||||
$.trim($('i.icon-ok').parents('a.origin-branch').data('name')) + '...' +
|
||||
$.trim($('i.icon-ok').parents('a.forked-owner' ).data('name')) + ':' +
|
||||
$.trim($('i.icon-ok').parents('a.forked-branch').data('name'));
|
||||
});
|
||||
|
||||
$('#show-form').click(function(){
|
||||
|
||||
@@ -280,15 +280,23 @@ div.account-image {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
ul.dropdown-menu {
|
||||
padding: 2px 0;
|
||||
}
|
||||
|
||||
ul.dropdown-menu li {
|
||||
border-bottom: 1px solid #eee;
|
||||
font-size: 85%;
|
||||
}
|
||||
|
||||
ul.dropdown-menu li a {
|
||||
padding: 2px 10px;
|
||||
}
|
||||
|
||||
ul.dropdown-menu :last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************/
|
||||
/* Sign-in form */
|
||||
/****************************************************************************/
|
||||
|
||||
Reference in New Issue
Block a user