mirror of
https://github.com/gitbucket/gitbucket.git
synced 2025-11-01 11:06:06 +01:00
(refs #2)Add tabs to the pull request page.
This commit is contained in:
@@ -35,6 +35,60 @@ trait PullRequestsControllerBase extends ControllerBase {
|
|||||||
pulls.html.list(repository)
|
pulls.html.list(repository)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
get("/:owner/:repository/pulls/:id")(referrersOnly { repository =>
|
||||||
|
val owner = repository.owner
|
||||||
|
val name = repository.name
|
||||||
|
val issueId = params("id").toInt
|
||||||
|
|
||||||
|
getPullRequest(owner, name, issueId) map { case(issue, pullreq) =>
|
||||||
|
pulls.html.pullreq(
|
||||||
|
issue, pullreq,
|
||||||
|
getComments(owner, name, issueId.toInt),
|
||||||
|
(getCollaborators(owner, name) :+ owner).sorted,
|
||||||
|
getMilestones(owner, name),
|
||||||
|
hasWritePermission(owner, name, context.loginAccount),
|
||||||
|
repository)
|
||||||
|
} getOrElse NotFound
|
||||||
|
})
|
||||||
|
|
||||||
|
get("/:owner/:repository/pulls/:id/commits")(referrersOnly { repository =>
|
||||||
|
val owner = repository.owner
|
||||||
|
val name = repository.name
|
||||||
|
val issueId = params("id").toInt
|
||||||
|
|
||||||
|
getPullRequest(owner, name, issueId) map { case(issue, pullreq) =>
|
||||||
|
pulls.html.commits(
|
||||||
|
issue, pullreq,
|
||||||
|
getCompareInfo(owner, name, pullreq.branch, pullreq.requestUserName, pullreq.requestRepositoryName, pullreq.requestBranch)._1,
|
||||||
|
hasWritePermission(owner, name, context.loginAccount),
|
||||||
|
repository)
|
||||||
|
} getOrElse NotFound
|
||||||
|
})
|
||||||
|
|
||||||
|
get("/:owner/:repository/pulls/:id/files")(referrersOnly { repository =>
|
||||||
|
val owner = repository.owner
|
||||||
|
val name = repository.name
|
||||||
|
val issueId = params("id").toInt
|
||||||
|
|
||||||
|
getPullRequest(owner, name, issueId) map { case(issue, pullreq) =>
|
||||||
|
JGitUtil.withGit(getRepositoryDir(owner, name)){ git =>
|
||||||
|
val newId = git.getRepository.resolve(pullreq.requestBranch)
|
||||||
|
|
||||||
|
pulls.html.files(
|
||||||
|
issue, pullreq,
|
||||||
|
getCompareInfo(owner, name, pullreq.branch, pullreq.requestUserName, pullreq.requestRepositoryName, pullreq.requestBranch)._2,
|
||||||
|
newId.getName,
|
||||||
|
hasWritePermission(owner, name, context.loginAccount),
|
||||||
|
repository)
|
||||||
|
}
|
||||||
|
} getOrElse NotFound
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
post("/:owner/:repository/pulls/:id/merge")(collaboratorsOnly { repository =>
|
||||||
|
// TODO Not implemented yet.
|
||||||
|
})
|
||||||
|
|
||||||
// TODO Replace correct authenticator
|
// TODO Replace correct authenticator
|
||||||
get("/:owner/:repository/pulls/compare")(collaboratorsOnly { newRepo =>
|
get("/:owner/:repository/pulls/compare")(collaboratorsOnly { newRepo =>
|
||||||
(newRepo.repository.originUserName, newRepo.repository.originRepositoryName) match {
|
(newRepo.repository.originUserName, newRepo.repository.originRepositoryName) match {
|
||||||
@@ -64,47 +118,18 @@ trait PullRequestsControllerBase extends ControllerBase {
|
|||||||
repository.repository.originUserName.get,
|
repository.repository.originUserName.get,
|
||||||
repository.repository.originRepositoryName.get, baseUrl
|
repository.repository.originRepositoryName.get, baseUrl
|
||||||
).map{ originRepository =>
|
).map{ originRepository =>
|
||||||
|
|
||||||
val Seq(origin, originId, forkedId) = multiParams("splat")
|
val Seq(origin, originId, forkedId) = multiParams("splat")
|
||||||
|
val userName = params("owner")
|
||||||
|
val repositoryName = params("repository")
|
||||||
|
|
||||||
withGit(
|
JGitUtil.withGit(getRepositoryDir(userName, repositoryName)){ git =>
|
||||||
getRepositoryDir(origin, repository.repository.originRepositoryName.get),
|
val newId = git.getRepository.resolve(forkedId)
|
||||||
getRepositoryDir(params("owner"), params("repository"))
|
|
||||||
){ (oldGit, newGit) =>
|
|
||||||
val oldReader = oldGit.getRepository.newObjectReader
|
|
||||||
val oldTreeIter = new CanonicalTreeParser
|
|
||||||
oldTreeIter.reset(oldReader, oldGit.getRepository.resolve(s"${originId}^{tree}"))
|
|
||||||
|
|
||||||
val newReader = newGit.getRepository.newObjectReader
|
val pullreq = getCompareInfo(
|
||||||
val newTreeIter = new CanonicalTreeParser
|
origin, repository.repository.originRepositoryName.get, originId,
|
||||||
newTreeIter.reset(newReader, newGit.getRepository.resolve(s"${forkedId}^{tree}"))
|
params("owner"), params("repository"), forkedId)
|
||||||
|
|
||||||
import scala.collection.JavaConverters._
|
pulls.html.compare(pullreq._1, pullreq._2, origin, originId, forkedId, newId.getName, repository, originRepository)
|
||||||
import util.Implicits._
|
|
||||||
|
|
||||||
val oldId = oldGit.getRepository.resolve(originId)
|
|
||||||
val newId = newGit.getRepository.resolve(forkedId)
|
|
||||||
val i = newGit.log.addRange(oldId, newId).call.iterator
|
|
||||||
|
|
||||||
val commits = new ArrayBuffer[CommitInfo]
|
|
||||||
while(i.hasNext){
|
|
||||||
val revCommit = i.next
|
|
||||||
commits += new CommitInfo(revCommit)
|
|
||||||
}
|
|
||||||
|
|
||||||
val diffs = newGit.diff.setOldTree(oldTreeIter).setNewTree(newTreeIter).call.asScala.map { diff =>
|
|
||||||
if(FileUtil.isImage(diff.getOldPath) || FileUtil.isImage(diff.getNewPath)){
|
|
||||||
DiffInfo(diff.getChangeType, diff.getOldPath, diff.getNewPath, None, None)
|
|
||||||
} else {
|
|
||||||
DiffInfo(diff.getChangeType, diff.getOldPath, diff.getNewPath,
|
|
||||||
JGitUtil.getContent(oldGit, diff.getOldId.toObjectId, false).filter(FileUtil.isText).map(new String(_, "UTF-8")),
|
|
||||||
JGitUtil.getContent(newGit, diff.getNewId.toObjectId, false).filter(FileUtil.isText).map(new String(_, "UTF-8")))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pulls.html.compare(commits.toList.splitWith{ (commit1, commit2) =>
|
|
||||||
view.helpers.date(commit1.time) == view.helpers.date(commit2.time)
|
|
||||||
}, diffs.toList, origin, originId, forkedId, newId.getName, repository, originRepository)
|
|
||||||
}
|
}
|
||||||
} getOrElse NotFound
|
} getOrElse NotFound
|
||||||
}
|
}
|
||||||
@@ -135,26 +160,6 @@ trait PullRequestsControllerBase extends ControllerBase {
|
|||||||
redirect(s"/${repository.owner}/${repository.name}/pulls/${issueId}")
|
redirect(s"/${repository.owner}/${repository.name}/pulls/${issueId}")
|
||||||
})
|
})
|
||||||
|
|
||||||
get("/:owner/:repository/pulls/:id")(referrersOnly { repository =>
|
|
||||||
val owner = repository.owner
|
|
||||||
val name = repository.name
|
|
||||||
val issueId = params("id").toInt
|
|
||||||
|
|
||||||
getPullRequest(owner, name, issueId) map { case(issue, pullreq) =>
|
|
||||||
pulls.html.pullreq(
|
|
||||||
issue, pullreq,
|
|
||||||
getComments(owner, name, issueId.toInt),
|
|
||||||
(getCollaborators(owner, name) :+ owner).sorted,
|
|
||||||
getMilestones(owner, name),
|
|
||||||
hasWritePermission(owner, name, context.loginAccount),
|
|
||||||
repository)
|
|
||||||
} getOrElse NotFound
|
|
||||||
})
|
|
||||||
|
|
||||||
post("/:owner/:repository/pulls/:id/merge")(collaboratorsOnly { repository =>
|
|
||||||
// TODO Not implemented yet.
|
|
||||||
})
|
|
||||||
|
|
||||||
private def withGit[T](oldDir: java.io.File, newDir: java.io.File)(action: (Git, Git) => T): T = {
|
private def withGit[T](oldDir: java.io.File, newDir: java.io.File)(action: (Git, Git) => T): T = {
|
||||||
val oldGit = Git.open(oldDir)
|
val oldGit = Git.open(oldDir)
|
||||||
val newGit = Git.open(newDir)
|
val newGit = Git.open(newDir)
|
||||||
@@ -166,4 +171,50 @@ trait PullRequestsControllerBase extends ControllerBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the commits and diffs between specified repository and revision.
|
||||||
|
*/
|
||||||
|
private def getCompareInfo(userName: String, repositoryName: String, branch: String,
|
||||||
|
requestUserName: String, requestRepositoryName: String, requestBranch: String): (Seq[Seq[CommitInfo]], Seq[DiffInfo]) = {
|
||||||
|
withGit(
|
||||||
|
getRepositoryDir(userName, repositoryName),
|
||||||
|
getRepositoryDir(requestUserName, requestRepositoryName)
|
||||||
|
){ (oldGit, newGit) =>
|
||||||
|
val oldReader = oldGit.getRepository.newObjectReader
|
||||||
|
val oldTreeIter = new CanonicalTreeParser
|
||||||
|
oldTreeIter.reset(oldReader, oldGit.getRepository.resolve(s"${branch}^{tree}"))
|
||||||
|
|
||||||
|
val newReader = newGit.getRepository.newObjectReader
|
||||||
|
val newTreeIter = new CanonicalTreeParser
|
||||||
|
newTreeIter.reset(newReader, newGit.getRepository.resolve(s"${requestBranch}^{tree}"))
|
||||||
|
|
||||||
|
import scala.collection.JavaConverters._
|
||||||
|
import util.Implicits._
|
||||||
|
|
||||||
|
val oldId = oldGit.getRepository.resolve(branch)
|
||||||
|
val newId = newGit.getRepository.resolve(requestBranch)
|
||||||
|
val i = newGit.log.addRange(oldId, newId).call.iterator
|
||||||
|
|
||||||
|
val commits = new ArrayBuffer[CommitInfo]
|
||||||
|
while(i.hasNext){
|
||||||
|
val revCommit = i.next
|
||||||
|
commits += new CommitInfo(revCommit)
|
||||||
|
}
|
||||||
|
|
||||||
|
val diffs = newGit.diff.setOldTree(oldTreeIter).setNewTree(newTreeIter).call.asScala.map { diff =>
|
||||||
|
if(FileUtil.isImage(diff.getOldPath) || FileUtil.isImage(diff.getNewPath)){
|
||||||
|
DiffInfo(diff.getChangeType, diff.getOldPath, diff.getNewPath, None, None)
|
||||||
|
} else {
|
||||||
|
DiffInfo(diff.getChangeType, diff.getOldPath, diff.getNewPath,
|
||||||
|
JGitUtil.getContent(oldGit, diff.getOldId.toObjectId, false).filter(FileUtil.isText).map(new String(_, "UTF-8")),
|
||||||
|
JGitUtil.getContent(newGit, diff.getNewId.toObjectId, false).filter(FileUtil.isText).map(new String(_, "UTF-8")))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(commits.toList.splitWith{ (commit1, commit2) =>
|
||||||
|
view.helpers.date(commit1.time) == view.helpers.date(commit2.time)
|
||||||
|
}, diffs.toSeq)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
32
src/main/twirl/pulls/commits.scala.html
Normal file
32
src/main/twirl/pulls/commits.scala.html
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
@(issue: model.Issue,
|
||||||
|
pullreq: model.PullRequest,
|
||||||
|
commits: Seq[Seq[util.JGitUtil.CommitInfo]],
|
||||||
|
hasWritePermission: Boolean,
|
||||||
|
repository: service.RepositoryService.RepositoryInfo)(implicit context: app.Context)
|
||||||
|
@import context._
|
||||||
|
@import view.helpers._
|
||||||
|
@html.main("%s - Issue #%d - %s/%s".format(issue.title, issue.issueId, repository.owner, repository.name)){
|
||||||
|
@html.header("issues", repository)
|
||||||
|
@tab("commits", issue.issueId, repository)
|
||||||
|
<div class="box">
|
||||||
|
<table class="table table-file-list" style="border: 1px solid silver;">
|
||||||
|
@commits.map { day =>
|
||||||
|
<tr>
|
||||||
|
<th colspan="3" class="box-header" style="font-weight: normal;">@date(day.head.time)</th>
|
||||||
|
</tr>
|
||||||
|
@day.map { commit =>
|
||||||
|
<tr>
|
||||||
|
<td style="width: 20%;">
|
||||||
|
@avatar(commit.committer, 20)
|
||||||
|
<a href="@url(commit.committer)" class="username">@commit.committer</a>
|
||||||
|
</td>
|
||||||
|
<td>@commit.shortMessage</td>
|
||||||
|
<td style="width: 10%; text-align: right;">
|
||||||
|
<a href="@url(repository)/commit/@commit.id" class="monospace">@commit.id.substring(0, 7)</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
@(commits: Seq[Seq[util.JGitUtil.CommitInfo]], diffs: List[util.JGitUtil.DiffInfo],
|
@(commits: Seq[Seq[util.JGitUtil.CommitInfo]], diffs: Seq[util.JGitUtil.DiffInfo],
|
||||||
origin: String, originId: String, forkedId: String, commitId: String,
|
origin: String, originId: String, forkedId: String, commitId: String,
|
||||||
repository: service.RepositoryService.RepositoryInfo,
|
repository: service.RepositoryService.RepositoryInfo,
|
||||||
originRepository: service.RepositoryService.RepositoryInfo)(implicit context: app.Context)
|
originRepository: service.RepositoryService.RepositoryInfo)(implicit context: app.Context)
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
<div style="margin-bottom: 10px;" id="create-pull-request">
|
<div style="margin-bottom: 10px;" id="create-pull-request">
|
||||||
<a href="#" class="btn" id="show-form">Click to create a pull request for this comparison</a>
|
<a href="#" class="btn" id="show-form">Click to create a pull request for this comparison</a>
|
||||||
</div>
|
</div>
|
||||||
<div id="pull-request-form" style="display: none; width: 600px;">
|
<div id="pull-request-form" style="display: none; width: 620px;">
|
||||||
<form method="POST" action="@path/@origin/@repository.name/pulls/new" validate="true">
|
<form method="POST" action="@path/@origin/@repository.name/pulls/new" validate="true">
|
||||||
<span class="error" id="error-title"></span>
|
<span class="error" id="error-title"></span>
|
||||||
<input type="text" name="title" style="width: 600px" placeholder="Title"/>
|
<input type="text" name="title" style="width: 600px" placeholder="Title"/>
|
||||||
|
|||||||
52
src/main/twirl/pulls/files.scala.html
Normal file
52
src/main/twirl/pulls/files.scala.html
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
@(issue: model.Issue,
|
||||||
|
pullreq: model.PullRequest,
|
||||||
|
diffs: Seq[util.JGitUtil.DiffInfo],
|
||||||
|
commitId: String,
|
||||||
|
hasWritePermission: Boolean,
|
||||||
|
repository: service.RepositoryService.RepositoryInfo)(implicit context: app.Context)
|
||||||
|
@import context._
|
||||||
|
@import view.helpers._
|
||||||
|
@import org.eclipse.jgit.diff.DiffEntry.ChangeType
|
||||||
|
@html.main("%s - Issue #%d - %s/%s".format(issue.title, issue.issueId, repository.owner, repository.name)){
|
||||||
|
@html.header("issues", repository)
|
||||||
|
@tab("files", issue.issueId, repository)
|
||||||
|
<div>
|
||||||
|
<div class="pull-right" style="margin-bottom: 10px;">
|
||||||
|
<input id="toggle-file-list" type="button" class="btn" value="Show file list"/>
|
||||||
|
</div>
|
||||||
|
Showing @diffs.size changed @plural(diffs.size, "file")
|
||||||
|
</div>
|
||||||
|
<ul id="commit-file-list" style="display: none;">
|
||||||
|
@diffs.zipWithIndex.map { case (diff, i) =>
|
||||||
|
<li@if(i > 0){ class="border"}>
|
||||||
|
<a href="#diff-@i">
|
||||||
|
@if(diff.changeType == ChangeType.COPY || diff.changeType == ChangeType.RENAME){
|
||||||
|
<img src="@assets/common/images/diff_move.png"/> @diff.oldPath -> @diff.newPath
|
||||||
|
}
|
||||||
|
@if(diff.changeType == ChangeType.ADD){
|
||||||
|
<img src="@assets/common/images/diff_add.png"/> @diff.newPath
|
||||||
|
}
|
||||||
|
@if(diff.changeType == ChangeType.MODIFY){
|
||||||
|
<img src="@assets/common/images/diff_edit.png"/> @diff.newPath
|
||||||
|
}
|
||||||
|
@if(diff.changeType == ChangeType.DELETE){
|
||||||
|
<img src="@assets/common/images/diff_delete.png"/> @diff.oldPath
|
||||||
|
}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
@helper.html.diff(diffs, repository, Some(commitId))
|
||||||
|
}
|
||||||
|
<script>
|
||||||
|
$(function(){
|
||||||
|
$('#toggle-file-list').click(function(){
|
||||||
|
$('#commit-file-list').toggle();
|
||||||
|
if($(this).val() == 'Show file list'){
|
||||||
|
$(this).val('Hide file list');
|
||||||
|
} else {
|
||||||
|
$(this).val('Show file list');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
@@ -9,11 +9,13 @@
|
|||||||
@import view.helpers._
|
@import view.helpers._
|
||||||
@html.main("%s - Issue #%d - %s/%s".format(issue.title, issue.issueId, repository.owner, repository.name)){
|
@html.main("%s - Issue #%d - %s/%s".format(issue.title, issue.issueId, repository.owner, repository.name)){
|
||||||
@html.header("issues", repository)
|
@html.header("issues", repository)
|
||||||
@issues.html.tab("issues", repository)
|
@tab("discussion", issue.issueId, repository)
|
||||||
|
@*
|
||||||
<ul class="nav nav-tabs">
|
<ul class="nav nav-tabs">
|
||||||
<li class="pull-left"><a href="@url(repository)/issues"><i class="icon-arrow-left"></i> Back to issue list</a></li>
|
<li class="pull-left"><a href="@url(repository)/issues"><i class="icon-arrow-left"></i> Back to issue list</a></li>
|
||||||
<li class="pull-right">Issue #@issue.issueId</li>
|
<li class="pull-right">Issue #@issue.issueId</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
*@
|
||||||
<div class="row-fluid">
|
<div class="row-fluid">
|
||||||
<div class="span10">
|
<div class="span10">
|
||||||
<div class="issue-avatar-image">@avatar(issue.openedUserName, 48)</div>
|
<div class="issue-avatar-image">@avatar(issue.openedUserName, 48)</div>
|
||||||
@@ -140,7 +142,7 @@ git push origin @{pullreq.branch}</pre>
|
|||||||
<div>
|
<div>
|
||||||
<strong>Merge pull request #@issue.issueId from @{pullreq.requestUserName}/@{pullreq.requestBranch}</strong>
|
<strong>Merge pull request #@issue.issueId from @{pullreq.requestUserName}/@{pullreq.requestBranch}</strong>
|
||||||
</div>
|
</div>
|
||||||
<textarea name="content" style="width: 680px; height: 100px;">@issue.title</textarea>
|
<textarea name="content" style="width: 680px; height: 80px;">@issue.title</textarea>
|
||||||
<div>
|
<div>
|
||||||
<input type="button" class="btn" value="Cancel" id="cancel-merge-pull-request"/>
|
<input type="button" class="btn" value="Cancel" id="cancel-merge-pull-request"/>
|
||||||
<input type="submit" class="btn btn-success" value="Confirm merge"/>
|
<input type="submit" class="btn btn-success" value="Confirm merge"/>
|
||||||
|
|||||||
17
src/main/twirl/pulls/tab.scala.html
Normal file
17
src/main/twirl/pulls/tab.scala.html
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
@(active: String, issueId: Int, repository: service.RepositoryService.RepositoryInfo)(implicit context: app.Context)
|
||||||
|
@import context._
|
||||||
|
@import view.helpers._
|
||||||
|
<ul class="nav nav-tabs">
|
||||||
|
<li@if(active == "discussion"){ class="active"}><a href="@url(repository)/pulls/@issueId">Discussion</a></li>
|
||||||
|
<li@if(active == "commits"){ class="active"}><a href="@url(repository)/pulls/@issueId/commits">Commits</a></li>
|
||||||
|
<li@if(active == "files"){ class="active"}><a href="@url(repository)/pulls/@issueId/files">Files Changed</a></li>
|
||||||
|
@*
|
||||||
|
@if(loginAccount.isDefined){
|
||||||
|
<li class="pull-right">
|
||||||
|
<div class="btn-group">
|
||||||
|
<a class="btn btn-success" href="@url(repository)/issues/new">New Issue</a>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
*@
|
||||||
|
</ul>
|
||||||
Reference in New Issue
Block a user