mirror of
https://github.com/gitbucket/gitbucket.git
synced 2025-11-01 19:15:59 +01:00
(refs #2)Create pull request is available.
This commit is contained in:
@@ -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);
|
||||
|
@@ -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 {
|
||||
|
@@ -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)
|
||||
|
@@ -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)
|
25
src/main/scala/service/PullRequestService.scala
Normal file
25
src/main/scala/service/PullRequestService.scala
Normal 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))
|
||||
|
||||
}
|
@@ -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)
|
||||
|
@@ -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'){
|
||||
|
Reference in New Issue
Block a user