(refs #2)Comparing between all forked repositories.

This commit is contained in:
takezoe
2013-07-27 04:11:33 +09:00
parent 59d85531ce
commit 66f3a1fe7d
4 changed files with 119 additions and 68 deletions

View File

@@ -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

View File

@@ -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>

View File

@@ -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 cant 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(){

View File

@@ -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 */
/****************************************************************************/