(refs #2)Create pull request is available.

This commit is contained in:
takezoe
2013-07-14 02:43:45 +09:00
parent bf3380755b
commit 0903721a62
7 changed files with 160 additions and 64 deletions

View File

@@ -1,13 +1,13 @@
CREATE TABLE PULL_REQUEST(
PULL_REQUEST_ID INT AUTO_INCREMENT,
USER_NAME VARCHAR(100) NOT NULL,
REPOSITORY_NAME VARCHAR(100) NOT NULL,
ISSUE_ID INT NOT NULL,
ORIGIN_BRANCH VARCHAR(100) NOT NULL,
REQUEST_USER_NAME VARCHAR(100) NOT NULL,
REQUEST_REPOSITORY_NAME VARCHAR(100) NOT NULL,
REQUEST_COMMIT_ID VARCHAR(40) NOT NULL
);
ALTER TABLE PULL_REQUEST ADD CONSTRAINT IDX_PULL_REQUEST_PK PRIMARY KEY (PULL_REQUEST_ID);
ALTER TABLE PULL_REQUEST ADD CONSTRAINT IDX_PULL_REQUEST_PK PRIMARY KEY (USER_NAME, REPOSITORY_NAME, ISSUE_ID);
ALTER TABLE PULL_REQUEST ADD CONSTRAINT IDX_PULL_REQUEST_FK0 FOREIGN KEY (USER_NAME, REPOSITORY_NAME, ISSUE_ID) REFERENCES ISSUE (USER_NAME, REPOSITORY_NAME, ISSUE_ID);
ALTER TABLE PULL_REQUEST ADD CONSTRAINT IDX_PULL_REQUEST_FK1 FOREIGN KEY (REQUEST_USER_NAME, REQUEST_REPOSITORY_NAME) REFERENCES REPOSITORY (USER_NAME, REPOSITORY_NAME);

View File

@@ -80,7 +80,9 @@ trait CreateRepositoryControllerBase extends ControllerBase {
val git = Git.open(tmpdir)
git.add.addFilepattern("README.md").call
git.commit.setMessage("Initial commit").call
git.commit
.setCommitter(new PersonIdent(loginUserName, loginAccount.mailAddress))
.setMessage("Initial commit").call
git.push.call
} finally {

View File

@@ -1,26 +1,42 @@
package app
import util.{FileUtil, JGitUtil, ReferrerAuthenticator}
import util.{CollaboratorsAuthenticator, FileUtil, JGitUtil, ReferrerAuthenticator}
import util.Directory._
import service._
import org.eclipse.jgit.treewalk.CanonicalTreeParser
import util.JGitUtil.{DiffInfo, CommitInfo}
import scala.collection.mutable.ArrayBuffer
import org.eclipse.jgit.api.Git
import org.eclipse.jgit.lib.ObjectId
import jp.sf.amateras.scalatra.forms._
import util.JGitUtil.DiffInfo
import scala.Some
import util.JGitUtil.CommitInfo
class PullRequestsController extends PullRequestsControllerBase
with RepositoryService with AccountService with ReferrerAuthenticator
with RepositoryService with AccountService with IssuesService with PullRequestService
with ReferrerAuthenticator with CollaboratorsAuthenticator
trait PullRequestsControllerBase extends ControllerBase {
self: ReferrerAuthenticator with RepositoryService =>
self: ReferrerAuthenticator with RepositoryService with IssuesService
with PullRequestService with CollaboratorsAuthenticator =>
val form = mapping(
"title" -> trim(label("Title" , text(required, maxlength(100)))),
"content" -> trim(label("Content", optional(text()))),
"branch" -> trim(text(required, maxlength(100))),
"requestUserName" -> trim(text(required, maxlength(100))),
"requestCommitId" -> trim(text(required, maxlength(40)))
)(PullRequestForm.apply)
case class PullRequestForm(title: String, content: Option[String], branch: String,
requestUserName: String, requestCommitId: String)
get("/:owner/:repository/pulls")(referrersOnly { repository =>
pulls.html.list(repository)
})
// TODO Replace correct authenticator
get("/:owner/:repository/pulls/compare")(referrersOnly { newRepo =>
get("/:owner/:repository/pulls/compare")(collaboratorsOnly { newRepo =>
(newRepo.repository.originUserName, newRepo.repository.originRepositoryName) match {
case (None,_)|(_, None) => NotFound // TODO BadRequest?
case (Some(originUserName), Some(originRepositoryName)) => {
@@ -40,7 +56,7 @@ trait PullRequestsControllerBase extends ControllerBase {
})
// TODO Replace correct authenticator
get("/:owner/:repository/pulls/compare/*:*...*")(referrersOnly { repository =>
get("/:owner/:repository/pulls/compare/*:*...*")(collaboratorsOnly { repository =>
if(repository.repository.originUserName.isEmpty || repository.repository.originRepositoryName.isEmpty){
NotFound // TODO BadRequest?
} else {
@@ -94,6 +110,29 @@ trait PullRequestsControllerBase extends ControllerBase {
}
})
post("/:owner/:repository/pulls/new", form)(referrersOnly { (form, repository) =>
val loginUserName = context.loginAccount.get.userName
val issueId = createIssue(
repository.owner,
repository.name,
loginUserName,
form.title,
form.content,
None, None)
createPullRequest(
repository.owner,
repository.name,
issueId,
form.branch,
form.requestUserName,
repository.name,
form.requestCommitId)
redirect(s"/${repository.owner}/${repository.name}/pulls/${issueId}")
})
private def withGit[T](oldDir: java.io.File, newDir: java.io.File)(action: (Git, Git) => T): T = {
val oldGit = Git.open(oldDir)
val newGit = Git.open(newDir)

View File

@@ -3,21 +3,21 @@ package model
import scala.slick.driver.H2Driver.simple._
object PullRequests extends Table[PullRequest]("PULL_REQUEST") with IssueTemplate {
def pullRequestId = column[Int]("PULL_REQUEST_ID")
def requestUserName = column[String]("REQUEST_USER_NAME")
def requestRepositoryName = column[String]("REQUEST_REPOSITORY_NAME")
def requestCommitId = column[String]("REQUEST_COMMIT_ID")
def * = pullRequestId ~ userName ~ repositoryName ~ issueId ~ requestUserName ~ requestRepositoryName ~ requestCommitId <> (PullRequest, PullRequest.unapply _)
def originBranch = column[String]("ORIGIN_BRANCH")
def * = userName ~ repositoryName ~ issueId ~ originBranch ~ requestUserName ~ requestRepositoryName ~ requestCommitId <> (PullRequest, PullRequest.unapply _)
def autoinc = userName ~ repositoryName ~ issueId ~ requestUserName ~ requestRepositoryName ~ requestCommitId returning pullRequestId
def byPrimaryKey(pullRequestId: Int) = this.pullRequestId is pullRequestId.bind
def byPrimaryKey(userName: String, repositoryName: String, issueId: Int) = byIssue(userName, repositoryName, issueId)
def byPrimaryKey(userName: Column[String], repositoryName: Column[String], issueId: Column[Int]) = byIssue(userName, repositoryName, issueId)
}
case class PullRequest(
pullRequestId: Int,
userName: String,
repositoryName: String,
issueId: Int,
originBranch: String,
requestUserName: String,
requestRepositoryName: String,
requestCommitId: String)

View File

@@ -0,0 +1,25 @@
package service
import scala.slick.driver.H2Driver.simple._
import Database.threadLocalSession
import model._
//import scala.slick.jdbc.{StaticQuery => Q}
//import Q.interpolation
trait PullRequestService {
def createPullRequest(originUserName: String, originRepositoryName: String, issueId: Int,
originBranch: String, requestUserName: String, requestRepositoryName: String, requestCommitId: String): Unit =
PullRequests insert (PullRequest(
originUserName,
originRepositoryName,
issueId,
originBranch,
requestUserName,
requestRepositoryName,
requestCommitId))
}

View File

@@ -49,6 +49,7 @@ object AutoUpdate {
* The history of versions. A head of this sequence is the current BitBucket version.
*/
val versions = Seq(
Version(1, 4),
new Version(1, 3){
override def update(conn: Connection): Unit = {
super.update(conn)

View File

@@ -12,7 +12,7 @@
<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>
</div>
<div id="compare-edit" style="display: none;">
<div id="compare-edit" style="display: none; width: 620px;">
<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) {
@@ -29,57 +29,81 @@
}
</div>
</div>
<div style="margin-bottom: 10px;">
<a href="#" class="btn">Click to create a pull request for this comparison</a>
</div>
<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>
<div>
<div class="pull-right" style="margin-bottom: 10px;">
<input id="toggle-file-list" type="button" class="btn" value="Show file list"/>
@if(commits.nonEmpty){
<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>
</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
<div id="pull-request-form" style="display: none; width: 600px;">
<form method="POST" action="@path/@origin/@repository.name/pulls/new" validate="true">
<span class="error" id="error-title"></span>
<input type="text" name="title" style="width: 600px" placeholder="Title"/>
@helper.html.preview(repository, "", false, true, "width: 600px; height: 200px;")
<input type="hidden" name="branch" value="@originId"/>
<input type="hidden" name="requestUserName" value="@repository.owner"/>
<input type="hidden" name="requestCommitId" value="@commitId"/>
<input type="submit" class="btn btn-success" value="Send pull request"/>
</form>
</div>
}
@if(commits.isEmpty){
<table class="table table-bordered table-hover table-issues">
<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.
</td>
</tr>
</table>
} else {
<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>
}
}
@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))
</table>
</div>
<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(){
@@ -101,6 +125,11 @@ $(function(){
$.trim($('i.icon-ok').parents('a.forked-branch').text());
});
$('#show-form').click(function(){
$(this).hide();
$('#pull-request-form').show();
});
$('#toggle-file-list').click(function(){
$('#commit-file-list').toggle();
if($(this).val() == 'Show file list'){