mirror of
				https://github.com/gitbucket/gitbucket.git
				synced 2025-11-03 20:15:59 +01:00 
			
		
		
		
	(refs #2)Create pull request is available.
This commit is contained in:
		@@ -1,13 +1,13 @@
 | 
				
			|||||||
CREATE TABLE PULL_REQUEST(
 | 
					CREATE TABLE PULL_REQUEST(
 | 
				
			||||||
		PULL_REQUEST_ID INT AUTO_INCREMENT,
 | 
					 | 
				
			||||||
		USER_NAME VARCHAR(100) NOT NULL,
 | 
							USER_NAME VARCHAR(100) NOT NULL,
 | 
				
			||||||
		REPOSITORY_NAME VARCHAR(100) NOT NULL,
 | 
							REPOSITORY_NAME VARCHAR(100) NOT NULL,
 | 
				
			||||||
		ISSUE_ID INT NOT NULL,
 | 
							ISSUE_ID INT NOT NULL,
 | 
				
			||||||
 | 
							ORIGIN_BRANCH VARCHAR(100) NOT NULL,
 | 
				
			||||||
		REQUEST_USER_NAME VARCHAR(100) NOT NULL,
 | 
							REQUEST_USER_NAME VARCHAR(100) NOT NULL,
 | 
				
			||||||
		REQUEST_REPOSITORY_NAME VARCHAR(100) NOT NULL,
 | 
							REQUEST_REPOSITORY_NAME VARCHAR(100) NOT NULL,
 | 
				
			||||||
		REQUEST_COMMIT_ID VARCHAR(40) 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_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);
 | 
					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)
 | 
					        val git = Git.open(tmpdir)
 | 
				
			||||||
        git.add.addFilepattern("README.md").call
 | 
					        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
 | 
					        git.push.call
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      } finally {
 | 
					      } finally {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,26 +1,42 @@
 | 
				
			|||||||
package app
 | 
					package app
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import util.{FileUtil, JGitUtil, ReferrerAuthenticator}
 | 
					import util.{CollaboratorsAuthenticator, FileUtil, JGitUtil, ReferrerAuthenticator}
 | 
				
			||||||
import util.Directory._
 | 
					import util.Directory._
 | 
				
			||||||
import service._
 | 
					import service._
 | 
				
			||||||
import org.eclipse.jgit.treewalk.CanonicalTreeParser
 | 
					import org.eclipse.jgit.treewalk.CanonicalTreeParser
 | 
				
			||||||
import util.JGitUtil.{DiffInfo, CommitInfo}
 | 
					import util.JGitUtil.{DiffInfo, CommitInfo}
 | 
				
			||||||
import scala.collection.mutable.ArrayBuffer
 | 
					import scala.collection.mutable.ArrayBuffer
 | 
				
			||||||
import org.eclipse.jgit.api.Git
 | 
					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
 | 
					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 {
 | 
					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 =>
 | 
					  get("/:owner/:repository/pulls")(referrersOnly { repository =>
 | 
				
			||||||
    pulls.html.list(repository)
 | 
					    pulls.html.list(repository)
 | 
				
			||||||
  })
 | 
					  })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // TODO Replace correct authenticator
 | 
					  // 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 {
 | 
					    (newRepo.repository.originUserName, newRepo.repository.originRepositoryName) match {
 | 
				
			||||||
      case (None,_)|(_, None) => NotFound // TODO BadRequest?
 | 
					      case (None,_)|(_, None) => NotFound // TODO BadRequest?
 | 
				
			||||||
      case (Some(originUserName), Some(originRepositoryName)) => {
 | 
					      case (Some(originUserName), Some(originRepositoryName)) => {
 | 
				
			||||||
@@ -40,7 +56,7 @@ trait PullRequestsControllerBase extends ControllerBase {
 | 
				
			|||||||
  })
 | 
					  })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // TODO Replace correct authenticator
 | 
					  // 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){
 | 
					    if(repository.repository.originUserName.isEmpty || repository.repository.originRepositoryName.isEmpty){
 | 
				
			||||||
      NotFound // TODO BadRequest?
 | 
					      NotFound // TODO BadRequest?
 | 
				
			||||||
    } else {
 | 
					    } 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 = {
 | 
					  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)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,21 +3,21 @@ package model
 | 
				
			|||||||
import scala.slick.driver.H2Driver.simple._
 | 
					import scala.slick.driver.H2Driver.simple._
 | 
				
			||||||
 | 
					
 | 
				
			||||||
object PullRequests extends Table[PullRequest]("PULL_REQUEST") with IssueTemplate {
 | 
					object PullRequests extends Table[PullRequest]("PULL_REQUEST") with IssueTemplate {
 | 
				
			||||||
  def pullRequestId = column[Int]("PULL_REQUEST_ID")
 | 
					 | 
				
			||||||
  def requestUserName = column[String]("REQUEST_USER_NAME")
 | 
					  def requestUserName = column[String]("REQUEST_USER_NAME")
 | 
				
			||||||
  def requestRepositoryName = column[String]("REQUEST_REPOSITORY_NAME")
 | 
					  def requestRepositoryName = column[String]("REQUEST_REPOSITORY_NAME")
 | 
				
			||||||
  def requestCommitId = column[String]("REQUEST_COMMIT_ID")
 | 
					  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(userName: String, repositoryName: String, issueId: Int) = byIssue(userName, repositoryName, issueId)
 | 
				
			||||||
  def byPrimaryKey(pullRequestId: Int) = this.pullRequestId is pullRequestId.bind
 | 
					  def byPrimaryKey(userName: Column[String], repositoryName: Column[String], issueId: Column[Int]) = byIssue(userName, repositoryName, issueId)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
case class PullRequest(
 | 
					case class PullRequest(
 | 
				
			||||||
  pullRequestId: Int,
 | 
					 | 
				
			||||||
  userName: String,
 | 
					  userName: String,
 | 
				
			||||||
  repositoryName: String,
 | 
					  repositoryName: String,
 | 
				
			||||||
  issueId: Int,
 | 
					  issueId: Int,
 | 
				
			||||||
 | 
					  originBranch: String,
 | 
				
			||||||
  requestUserName: String,
 | 
					  requestUserName: String,
 | 
				
			||||||
  requestRepositoryName: String,
 | 
					  requestRepositoryName: String,
 | 
				
			||||||
  requestCommitId: 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.
 | 
					   * The history of versions. A head of this sequence is the current BitBucket version.
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  val versions = Seq(
 | 
					  val versions = Seq(
 | 
				
			||||||
 | 
					    Version(1, 4),
 | 
				
			||||||
    new Version(1, 3){
 | 
					    new Version(1, 3){
 | 
				
			||||||
      override def update(conn: Connection): Unit = {
 | 
					      override def update(conn: Connection): Unit = {
 | 
				
			||||||
        super.update(conn)
 | 
					        super.update(conn)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,7 +12,7 @@
 | 
				
			|||||||
      <a href="#" id="edit-compare-condition" class="btn btn-mini pull-right">Edit</a>
 | 
					      <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">@origin:@originId</span> ... <span class="label label-info monospace">@repository.owner:@forkedId</span>
 | 
				
			||||||
    </div>
 | 
					    </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>
 | 
					      <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>
 | 
					      <span class="label label-info monospace">@origin/@repository.name:</span>
 | 
				
			||||||
      @helper.html.dropdown(originId) {
 | 
					      @helper.html.dropdown(originId) {
 | 
				
			||||||
@@ -29,9 +29,32 @@
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
  <div style="margin-bottom: 10px;">
 | 
					  @if(commits.nonEmpty){
 | 
				
			||||||
    <a href="#" class="btn">Click to create a pull request for this comparison</a>
 | 
					    <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>
 | 
					    </div>
 | 
				
			||||||
 | 
					    <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">
 | 
					    <div class="box">
 | 
				
			||||||
      <table class="table table-file-list" style="border: 1px solid silver;">
 | 
					      <table class="table table-file-list" style="border: 1px solid silver;">
 | 
				
			||||||
        @commits.map { day =>
 | 
					        @commits.map { day =>
 | 
				
			||||||
@@ -80,6 +103,7 @@
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    </ul>
 | 
					    </ul>
 | 
				
			||||||
    @helper.html.diff(diffs, repository, Some(commitId))
 | 
					    @helper.html.diff(diffs, repository, Some(commitId))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
<script>
 | 
					<script>
 | 
				
			||||||
$(function(){
 | 
					$(function(){
 | 
				
			||||||
@@ -101,6 +125,11 @@ $(function(){
 | 
				
			|||||||
      $.trim($('i.icon-ok').parents('a.forked-branch').text());
 | 
					      $.trim($('i.icon-ok').parents('a.forked-branch').text());
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  $('#show-form').click(function(){
 | 
				
			||||||
 | 
					    $(this).hide();
 | 
				
			||||||
 | 
					    $('#pull-request-form').show();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  $('#toggle-file-list').click(function(){
 | 
					  $('#toggle-file-list').click(function(){
 | 
				
			||||||
    $('#commit-file-list').toggle();
 | 
					    $('#commit-file-list').toggle();
 | 
				
			||||||
    if($(this).val() == 'Show file list'){
 | 
					    if($(this).val() == 'Show file list'){
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user