From 5e1eb39b87461ee8fc6ebdd278bca588c5deff6c Mon Sep 17 00:00:00 2001 From: takezoe Date: Thu, 11 Jul 2013 14:39:25 +0900 Subject: [PATCH 01/87] (refs #2)Experimental implementation of forking repository. --- src/main/resources/update/1_3.sql | 14 ++++ .../app/CreateRepositoryController.scala | 69 +++++++++++++++---- src/main/scala/model/Repository.scala | 8 ++- .../scala/service/RepositoryService.scala | 23 ++++--- src/main/twirl/header.scala.html | 11 +++ 5 files changed, 102 insertions(+), 23 deletions(-) diff --git a/src/main/resources/update/1_3.sql b/src/main/resources/update/1_3.sql index 8001b9e33..00c020ecf 100644 --- a/src/main/resources/update/1_3.sql +++ b/src/main/resources/update/1_3.sql @@ -1 +1,15 @@ ALTER TABLE ACCOUNT ADD COLUMN IMAGE VARCHAR(100); + +ALTER TABLE REPOSITORY ADD COLUMN ORIGIN_USER_NAME VARCHAR(100); +ALTER TABLE REPOSITORY ADD COLUMN ORIGIN_REPOSITORY_NAME VARCHAR(100); + +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, + 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_1 UNIQUE ISSUE (USER_NAME, REPOSITORY_NAME, ISSUE_ID); diff --git a/src/main/scala/app/CreateRepositoryController.scala b/src/main/scala/app/CreateRepositoryController.scala index 1e51caaaa..4edddb2c5 100644 --- a/src/main/scala/app/CreateRepositoryController.scala +++ b/src/main/scala/app/CreateRepositoryController.scala @@ -1,7 +1,7 @@ package app import util.Directory._ -import util.UsersAuthenticator +import util.{JGitUtil, UsersAuthenticator, ReferrerAuthenticator} import service._ import java.io.File import org.eclipse.jgit.api.Git @@ -11,24 +11,31 @@ import jp.sf.amateras.scalatra.forms._ class CreateRepositoryController extends CreateRepositoryControllerBase with RepositoryService with AccountService with WikiService with LabelsService with ActivityService - with UsersAuthenticator + with UsersAuthenticator with ReferrerAuthenticator /** * Creates new repository. */ trait CreateRepositoryControllerBase extends ControllerBase { self: RepositoryService with WikiService with LabelsService with ActivityService - with UsersAuthenticator => + with UsersAuthenticator with ReferrerAuthenticator => case class RepositoryCreationForm(name: String, description: Option[String], isPrivate: Boolean, createReadme: Boolean) - val form = mapping( + case class ForkRepositoryForm(owner: String, name: String) + + val newForm = mapping( "name" -> trim(label("Repository name", text(required, maxlength(40), identifier, unique))), "description" -> trim(label("Description" , optional(text()))), "isPrivate" -> trim(label("Repository Type", boolean())), "createReadme" -> trim(label("Create README" , boolean())) )(RepositoryCreationForm.apply) + val forkForm = mapping( + "owner" -> trim(label("Repository owner", text(required))), + "name" -> trim(label("Repository name", text(required))) + )(ForkRepositoryForm.apply) + /** * Show the new repository form. */ @@ -39,7 +46,7 @@ trait CreateRepositoryControllerBase extends ControllerBase { /** * Create new repository. */ - post("/new", form)(usersOnly { form => + post("/new", newForm)(usersOnly { form => val loginAccount = context.loginAccount.get val loginUserName = loginAccount.userName @@ -47,12 +54,7 @@ trait CreateRepositoryControllerBase extends ControllerBase { createRepository(form.name, loginUserName, form.description, form.isPrivate) // Insert default labels - createLabel(loginUserName, form.name, "bug", "fc2929") - createLabel(loginUserName, form.name, "duplicate", "cccccc") - createLabel(loginUserName, form.name, "enhancement", "84b6eb") - createLabel(loginUserName, form.name, "invalid", "e6e6e6") - createLabel(loginUserName, form.name, "question", "cc317c") - createLabel(loginUserName, form.name, "wontfix", "ffffff") + insertDefaultLabels(loginUserName, form.name) // Create the actual repository val gitdir = getRepositoryDir(loginUserName, form.name) @@ -97,7 +99,50 @@ trait CreateRepositoryControllerBase extends ControllerBase { // redirect to the repository redirect("/%s/%s".format(loginUserName, form.name)) }) - + + post("/:owner/:repository/_fork")(referrersOnly { repository => + val loginAccount = context.loginAccount.get + val loginUserName = loginAccount.userName + + if(getRepository(loginUserName, repository.name, baseUrl).isEmpty){ + // Insert to the database at first + // TODO Is private repository cloneable? + createRepository(repository.name, loginUserName, repository.repository.description, + repository.repository.isPrivate, Some(repository.name), Some(repository.owner)) + + // Insert default labels + insertDefaultLabels(loginUserName, repository.name) + + // clone repository actually + val git = Git.cloneRepository + .setURI(getRepositoryDir(repository.owner, repository.name).toURI.toString) + .setDirectory(getRepositoryDir(loginUserName, repository.name)) + .setBare(true).call + + val config = git.getRepository.getConfig + config.setBoolean("http", null, "receivepack", true) + config.save + + // Create Wiki repository + // TODO Wiki repository should be cloned also!! + createWikiRepository(loginAccount, repository.name) + + // TODO Record activity!! + //recordCreateRepositoryActivity(loginUserName, repositoryName, loginUserName) + } + // redirect to the repository + redirect("/%s/%s".format(loginUserName, repository.name)) + }) + + private def insertDefaultLabels(userName: String, repositoryName: String): Unit = { + createLabel(userName, repositoryName, "bug", "fc2929") + createLabel(userName, repositoryName, "duplicate", "cccccc") + createLabel(userName, repositoryName, "enhancement", "84b6eb") + createLabel(userName, repositoryName, "invalid", "e6e6e6") + createLabel(userName, repositoryName, "question", "cc317c") + createLabel(userName, repositoryName, "wontfix", "ffffff") + } + /** * Duplicate check for the repository name. */ diff --git a/src/main/scala/model/Repository.scala b/src/main/scala/model/Repository.scala index fcfb336ee..1c1f2e946 100644 --- a/src/main/scala/model/Repository.scala +++ b/src/main/scala/model/Repository.scala @@ -9,7 +9,9 @@ object Repositories extends Table[Repository]("REPOSITORY") with BasicTemplate { def registeredDate = column[java.util.Date]("REGISTERED_DATE") def updatedDate = column[java.util.Date]("UPDATED_DATE") def lastActivityDate = column[java.util.Date]("LAST_ACTIVITY_DATE") - def * = userName ~ repositoryName ~ isPrivate ~ description.? ~ defaultBranch ~ registeredDate ~ updatedDate ~ lastActivityDate <> (Repository, Repository.unapply _) + def originUserName = column[String]("ORIGIN_USER_NAME") + def originRepositoryName = column[String]("ORIGIN_REPOSITORY_NAME") + def * = userName ~ repositoryName ~ isPrivate ~ description.? ~ defaultBranch ~ registeredDate ~ updatedDate ~ lastActivityDate ~ originUserName.? ~ originRepositoryName.? <> (Repository, Repository.unapply _) def byPrimaryKey(owner: String, repository: String) = byRepository(owner, repository) } @@ -22,5 +24,7 @@ case class Repository( defaultBranch: String, registeredDate: java.util.Date, updatedDate: java.util.Date, - lastActivityDate: java.util.Date + lastActivityDate: java.util.Date, + originUserName: Option[String], + originRepositoryName: Option[String] ) diff --git a/src/main/scala/service/RepositoryService.scala b/src/main/scala/service/RepositoryService.scala index 153aa9529..d207f6d12 100644 --- a/src/main/scala/service/RepositoryService.scala +++ b/src/main/scala/service/RepositoryService.scala @@ -15,18 +15,23 @@ trait RepositoryService { self: AccountService => * @param userName the user name of the repository owner * @param description the repository description * @param isPrivate the repository type (private is true, otherwise false) + * @param originRepositoryName specify for the forked repository. (default is None) + * @param originUserName specify for the forked repository. (default is None) */ - def createRepository(repositoryName: String, userName: String, description: Option[String], isPrivate: Boolean): Unit = { + def createRepository(repositoryName: String, userName: String, description: Option[String], isPrivate: Boolean, + originRepositoryName: Option[String] = None, originUserName: Option[String] = None): Unit = { Repositories insert Repository( - userName = userName, - repositoryName = repositoryName, - isPrivate = isPrivate, - description = description, - defaultBranch = "master", - registeredDate = currentDate, - updatedDate = currentDate, - lastActivityDate = currentDate) + userName = userName, + repositoryName = repositoryName, + isPrivate = isPrivate, + description = description, + defaultBranch = "master", + registeredDate = currentDate, + updatedDate = currentDate, + lastActivityDate = currentDate, + originUserName = originUserName, + originRepositoryName = originRepositoryName) IssueId insert (userName, repositoryName, 0) } diff --git a/src/main/twirl/header.scala.html b/src/main/twirl/header.scala.html index 45b939df8..a46eecd18 100644 --- a/src/main/twirl/header.scala.html +++ b/src/main/twirl/header.scala.html @@ -6,6 +6,7 @@ @if(repository.repository.isPrivate){ } + @@ -25,11 +26,21 @@ } +
+ + +
From 6dd1299dff9b5f0af2d5b24369d8ccb490a2dc49 Mon Sep 17 00:00:00 2001 From: takezoe Date: Thu, 11 Jul 2013 18:49:03 +0900 Subject: [PATCH 02/87] (refs #2)Experimental implementation of forking repository. --- .../app/CreateRepositoryController.scala | 28 ++++++------------- src/main/scala/service/ActivityService.scala | 9 +++++- src/main/scala/service/WikiService.scala | 4 +-- .../servlet/BasicAuthenticationFilter.scala | 1 + src/main/scala/util/JGitUtil.scala | 25 +++++++++++++++++ src/main/twirl/header.scala.html | 15 +++++++--- .../webapp/assets/common/css/gitbucket.css | 10 +++++++ 7 files changed, 65 insertions(+), 27 deletions(-) diff --git a/src/main/scala/app/CreateRepositoryController.scala b/src/main/scala/app/CreateRepositoryController.scala index 4edddb2c5..ee620e84e 100644 --- a/src/main/scala/app/CreateRepositoryController.scala +++ b/src/main/scala/app/CreateRepositoryController.scala @@ -58,13 +58,7 @@ trait CreateRepositoryControllerBase extends ControllerBase { // Create the actual repository val gitdir = getRepositoryDir(loginUserName, form.name) - val repository = new RepositoryBuilder().setGitDir(gitdir).setBare.build - - repository.create - - val config = repository.getConfig - config.setBoolean("http", null, "receivepack", true) - config.save + JGitUtil.initRepository(gitdir) if(form.createReadme){ val tmpdir = getInitRepositoryDir(loginUserName, form.name) @@ -114,21 +108,17 @@ trait CreateRepositoryControllerBase extends ControllerBase { insertDefaultLabels(loginUserName, repository.name) // clone repository actually - val git = Git.cloneRepository - .setURI(getRepositoryDir(repository.owner, repository.name).toURI.toString) - .setDirectory(getRepositoryDir(loginUserName, repository.name)) - .setBare(true).call - - val config = git.getRepository.getConfig - config.setBoolean("http", null, "receivepack", true) - config.save + JGitUtil.cloneRepository( + getRepositoryDir(repository.owner, repository.name), + getRepositoryDir(loginUserName, repository.name)) // Create Wiki repository - // TODO Wiki repository should be cloned also!! - createWikiRepository(loginAccount, repository.name) + JGitUtil.cloneRepository( + getWikiRepositoryDir(repository.owner, repository.name), + getWikiRepositoryDir(loginUserName, repository.name)) - // TODO Record activity!! - //recordCreateRepositoryActivity(loginUserName, repositoryName, loginUserName) + // Record activity + recordForkActivity(repository.owner, repository.name, loginUserName) } // redirect to the repository redirect("/%s/%s".format(loginUserName, repository.name)) diff --git a/src/main/scala/service/ActivityService.scala b/src/main/scala/service/ActivityService.scala index c65331394..2ead13c88 100644 --- a/src/main/scala/service/ActivityService.scala +++ b/src/main/scala/service/ActivityService.scala @@ -102,7 +102,14 @@ trait ActivityService { s"[user:${activityUserName}] created branch [tag:${userName}/${repositoryName}#${branchName}] at [repo:${userName}/${repositoryName}]", None, currentDate) - + + def recordForkActivity(userName: String, repositoryName: String, activityUserName: String) = + Activities.autoInc insert(userName, repositoryName, activityUserName, + "forkk", + s"[user:${activityUserName}] forked [repo:${userName}/${repositoryName}] to [repo:${activityUserName}/${repositoryName}]", + None, + currentDate) + def insertCommitId(userName: String, repositoryName: String, commitId: String) = { CommitLog insert (userName, repositoryName, commitId) } diff --git a/src/main/scala/service/WikiService.scala b/src/main/scala/service/WikiService.scala index 76d742ca9..4c639bd6b 100644 --- a/src/main/scala/service/WikiService.scala +++ b/src/main/scala/service/WikiService.scala @@ -68,12 +68,10 @@ trait WikiService { lock(owner.userName, repository){ val dir = Directory.getWikiRepositoryDir(owner.userName, repository) if(!dir.exists){ - val repo = new RepositoryBuilder().setGitDir(dir).setBare.build try { - repo.create + JGitUtil.initRepository(dir) saveWikiPage(owner.userName, repository, "Home", "Home", "Welcome to the %s wiki!!".format(repository), owner, "Initial Commit") } finally { - repo.close // once delete cloned repository because initial cloned repository does not have 'branch.master.merge' FileUtils.deleteDirectory(Directory.getWikiWorkDir(owner.userName, repository)) } diff --git a/src/main/scala/servlet/BasicAuthenticationFilter.scala b/src/main/scala/servlet/BasicAuthenticationFilter.scala index a69c237b1..4b3a2c6dc 100644 --- a/src/main/scala/servlet/BasicAuthenticationFilter.scala +++ b/src/main/scala/servlet/BasicAuthenticationFilter.scala @@ -52,6 +52,7 @@ class BasicAuthenticationFilter extends Filter with RepositoryService with Accou } catch { case ex: Exception => { logger.error("error", ex) + ex.printStackTrace() requireAuth(response) } } diff --git a/src/main/scala/util/JGitUtil.scala b/src/main/scala/util/JGitUtil.scala index e69fcd30b..3cec72146 100644 --- a/src/main/scala/util/JGitUtil.scala +++ b/src/main/scala/util/JGitUtil.scala @@ -502,4 +502,29 @@ object JGitUtil { } } + def initRepository(dir: java.io.File): Unit = { + val repository = new RepositoryBuilder().setGitDir(dir).setBare.build + try { + repository.create + setReceivePack(repository) + } finally { + repository.close + } + } + + def cloneRepository(from: java.io.File, to: java.io.File): Unit = { + val git = Git.cloneRepository.setURI(from.toURI.toString).setDirectory(to).setBare(true).call + try { + setReceivePack(git.getRepository) + } finally { + git.getRepository.close + } + } + + private def setReceivePack(repository: org.eclipse.jgit.lib.Repository): Unit = { + val config = repository.getConfig + config.setBoolean("http", null, "receivepack", true) + config.save + } + } \ No newline at end of file diff --git a/src/main/twirl/header.scala.html b/src/main/twirl/header.scala.html index a46eecd18..e497af265 100644 --- a/src/main/twirl/header.scala.html +++ b/src/main/twirl/header.scala.html @@ -1,12 +1,21 @@ @(active: String, repository: service.RepositoryService.RepositoryInfo)(implicit context: app.Context) @import context._ @import view.helpers._ +
+ +
@repository.owner / @repository.name @if(repository.repository.isPrivate){ } - + @defining(repository.repository){ x => + @if(repository.repository.originRepositoryName.isDefined){ + + } + }
@@ -27,8 +36,6 @@
- -
diff --git a/src/main/twirl/pulls/list.scala.html b/src/main/twirl/pulls/list.scala.html new file mode 100644 index 000000000..a56c07e8a --- /dev/null +++ b/src/main/twirl/pulls/list.scala.html @@ -0,0 +1,8 @@ +@(repository: service.RepositoryService.RepositoryInfo)(implicit context: app.Context) +@import context._ +@import view.helpers._ +@html.main("Pull Requests - " + repository.owner + "/" + repository.name){ + @html.header("pulls", repository) + New pull request +} + From eb82af9006895c38464f3f82ba8c915b759c291b Mon Sep 17 00:00:00 2001 From: takezoe Date: Sat, 13 Jul 2013 20:09:19 +0900 Subject: [PATCH 08/87] (refs #2)Implementing the comparing view. --- .../scala/app/PullRequestsController.scala | 59 +++++++++++++++---- .../app/RepositoryViewerController.scala | 2 +- .../scala/service/RepositoryService.scala | 11 ++++ src/main/scala/util/JGitUtil.scala | 13 +++- src/main/twirl/pulls/compare.scala.html | 33 ++++++++++- 5 files changed, 104 insertions(+), 14 deletions(-) diff --git a/src/main/scala/app/PullRequestsController.scala b/src/main/scala/app/PullRequestsController.scala index dee821f24..6fb1656c4 100644 --- a/src/main/scala/app/PullRequestsController.scala +++ b/src/main/scala/app/PullRequestsController.scala @@ -6,35 +6,62 @@ 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 class PullRequestsController extends PullRequestsControllerBase with RepositoryService with AccountService with ReferrerAuthenticator trait PullRequestsControllerBase extends ControllerBase { - self: ReferrerAuthenticator => + self: ReferrerAuthenticator with RepositoryService => get("/:owner/:repository/pulls")(referrersOnly { repository => pulls.html.list(repository) }) + // TODO Replace correct authenticator + get("/:owner/:repository/pulls/compare")(referrersOnly { newRepo => + (newRepo.repository.originUserName, newRepo.repository.originRepositoryName) match { + case (None,_)|(_, None) => NotFound // TODO BadRequest? + case (Some(originUserName), Some(originRepositoryName)) => { + getRepository(originUserName, originRepositoryName, baseUrl).map { oldRepo => + withGit( + getRepositoryDir(originUserName, originRepositoryName), + getRepositoryDir(params("owner"), params("repository")) + ){ (oldGit, newGit) => + val oldBranch = JGitUtil.getDefaultBranch(oldGit, oldRepo).get._2 + val newBranch = JGitUtil.getDefaultBranch(newGit, newRepo).get._2 + + redirect(s"${context.path}/${newRepo.owner}/${newRepo.name}/pulls/compare/${originUserName}:${oldBranch}...${newBranch}") + } + } getOrElse NotFound + } + } + }) + // TODO Replace correct authenticator get("/:owner/:repository/pulls/compare/*:*...*")(referrersOnly { repository => if(repository.repository.originUserName.isEmpty || repository.repository.originRepositoryName.isEmpty){ NotFound // TODO BadRequest? } else { - val userName = params("owner") - val repositoryName = params("repository") - val Seq(origin, originId, forkedId) = multiParams("splat") + getRepository( + repository.repository.originUserName.get, + repository.repository.originRepositoryName.get, baseUrl + ).map{ originRepository => - JGitUtil.withGit(getRepositoryDir(userName, repositoryName)){ newGit => - JGitUtil.withGit(getRepositoryDir(origin, repository.repository.originRepositoryName.get)){ oldGit => + val Seq(origin, originId, forkedId) = multiParams("splat") + + withGit( + getRepositoryDir(origin, repository.repository.originRepositoryName.get), + getRepositoryDir(params("owner"), params("repository")) + ){ (oldGit, newGit) => val oldReader = oldGit.getRepository.newObjectReader val oldTreeIter = new CanonicalTreeParser - oldTreeIter.reset(oldReader, oldGit.getRepository.resolve("master^{tree}")) + oldTreeIter.reset(oldReader, oldGit.getRepository.resolve(s"${originId}^{tree}")) val newReader = newGit.getRepository.newObjectReader val newTreeIter = new CanonicalTreeParser - newTreeIter.reset(newReader, newGit.getRepository.resolve("master^{tree}")) + newTreeIter.reset(newReader, newGit.getRepository.resolve(s"${forkedId}^{tree}")) import scala.collection.JavaConverters._ import util.Implicits._ @@ -61,9 +88,21 @@ trait PullRequestsControllerBase extends ControllerBase { 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) + }, diffs.toList, origin, originId, forkedId, newId.getName, repository, originRepository) } - } + } getOrElse NotFound } }) + + 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) + try { + action(oldGit, newGit) + } finally { + oldGit.getRepository.close + newGit.getRepository.close + } + } + } diff --git a/src/main/scala/app/RepositoryViewerController.scala b/src/main/scala/app/RepositoryViewerController.scala index 43cb126b3..e4dc1ed42 100644 --- a/src/main/scala/app/RepositoryViewerController.scala +++ b/src/main/scala/app/RepositoryViewerController.scala @@ -218,7 +218,7 @@ trait RepositoryViewerControllerBase extends ControllerBase { JGitUtil.withGit(getRepositoryDir(repository.owner, repository.name)){ git => val revisions = Seq(if(revstr.isEmpty) repository.repository.defaultBranch else revstr, repository.branchList.head) // get specified commit - revisions.map { rev => (git.getRepository.resolve(rev), rev)}.find(_._1 != null).map { case (objectId, revision) => + JGitUtil.getDefaultBranch(git, repository, revstr).map { case (objectId, revision) => val revCommit = JGitUtil.getRevCommitFromId(git, objectId) // get files diff --git a/src/main/scala/service/RepositoryService.scala b/src/main/scala/service/RepositoryService.scala index d207f6d12..4ec16512e 100644 --- a/src/main/scala/service/RepositoryService.scala +++ b/src/main/scala/service/RepositoryService.scala @@ -185,6 +185,17 @@ trait RepositoryService { self: AccountService => } } +// def getBaseRepositories(userName: String, repositoryName: String, repositories: List[String] = Nil): List[String] = { +// Query(Repositories).filter { t => +// (t.originUserName is userName.bind) && (t.originRepositoryName is repositoryName.bind) +// }.map(_.userName).list match { +// case Nil => repositories.sorted +// case list => list.map { x => +// getBaseRepositories(x, repositoryName, x :: repositories) +// }.flatten +// } +// } + } object RepositoryService { diff --git a/src/main/scala/util/JGitUtil.scala b/src/main/scala/util/JGitUtil.scala index b2ce900d5..747ca66ae 100644 --- a/src/main/scala/util/JGitUtil.scala +++ b/src/main/scala/util/JGitUtil.scala @@ -15,6 +15,7 @@ import org.eclipse.jgit.util.io.DisabledOutputStream import org.eclipse.jgit.errors.MissingObjectException import java.util.Date import org.eclipse.jgit.api.errors.NoHeadException +import service.RepositoryService /** * Provides complex JGit operations. @@ -419,7 +420,7 @@ object JGitUtil { case true if(logs.size < 2) => getCommitLog(i, logs :+ i.next) case _ => logs } - + val revWalk = new RevWalk(git.getRepository) revWalk.markStart(revWalk.parseCommit(git.getRepository.resolve(id))) @@ -532,4 +533,14 @@ object JGitUtil { config.save } + def getDefaultBranch(git: Git, repository: RepositoryService.RepositoryInfo, + revstr: String = ""): Option[(ObjectId, String)] = { + Seq( + if(revstr.isEmpty) repository.repository.defaultBranch else revstr, + repository.branchList.head + ).map { rev => + (git.getRepository.resolve(rev), rev) + }.find(_._1 != null) + } + } \ No newline at end of file diff --git a/src/main/twirl/pulls/compare.scala.html b/src/main/twirl/pulls/compare.scala.html index e3deccaeb..8ea107a92 100644 --- a/src/main/twirl/pulls/compare.scala.html +++ b/src/main/twirl/pulls/compare.scala.html @@ -1,13 +1,33 @@ @(commits: Seq[Seq[util.JGitUtil.CommitInfo]], diffs: List[util.JGitUtil.DiffInfo], origin: String, originId: String, forkedId: String, commitId: String, - repository: service.RepositoryService.RepositoryInfo)(implicit context: app.Context) + repository: service.RepositoryService.RepositoryInfo, + originRepository: service.RepositoryService.RepositoryInfo)(implicit context: app.Context) @import context._ @import view.helpers._ @import org.eclipse.jgit.diff.DiffEntry.ChangeType @html.main("Pull Requests - " + repository.owner + "/" + repository.name){ @html.header("pulls", repository)
- @origin:@originId ... @repository.owner:@forkedId +
+ Edit + @origin:@originId ... @repository.owner:@forkedId +
+
Click to create a pull request for this comparison @@ -63,6 +83,15 @@ } \ No newline at end of file From b68977597bbe29021c9cf5f417c5efc098c9bb78 Mon Sep 17 00:00:00 2001 From: takezoe Date: Sun, 14 Jul 2013 14:06:48 +0900 Subject: [PATCH 18/87] (refs #2)Add tabs to the pull request page. --- .../scala/app/PullRequestsController.scala | 165 ++++++++++++------ src/main/twirl/pulls/commits.scala.html | 32 ++++ src/main/twirl/pulls/compare.scala.html | 4 +- src/main/twirl/pulls/files.scala.html | 52 ++++++ src/main/twirl/pulls/pullreq.scala.html | 6 +- src/main/twirl/pulls/tab.scala.html | 17 ++ 6 files changed, 215 insertions(+), 61 deletions(-) create mode 100644 src/main/twirl/pulls/commits.scala.html create mode 100644 src/main/twirl/pulls/files.scala.html create mode 100644 src/main/twirl/pulls/tab.scala.html diff --git a/src/main/scala/app/PullRequestsController.scala b/src/main/scala/app/PullRequestsController.scala index b9487996f..e113132d7 100644 --- a/src/main/scala/app/PullRequestsController.scala +++ b/src/main/scala/app/PullRequestsController.scala @@ -35,6 +35,60 @@ trait PullRequestsControllerBase extends ControllerBase { 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 get("/:owner/:repository/pulls/compare")(collaboratorsOnly { newRepo => (newRepo.repository.originUserName, newRepo.repository.originRepositoryName) match { @@ -64,47 +118,18 @@ trait PullRequestsControllerBase extends ControllerBase { repository.repository.originUserName.get, repository.repository.originRepositoryName.get, baseUrl ).map{ originRepository => - val Seq(origin, originId, forkedId) = multiParams("splat") + val userName = params("owner") + val repositoryName = params("repository") - withGit( - getRepositoryDir(origin, repository.repository.originRepositoryName.get), - 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}")) + JGitUtil.withGit(getRepositoryDir(userName, repositoryName)){ git => + val newId = git.getRepository.resolve(forkedId) - val newReader = newGit.getRepository.newObjectReader - val newTreeIter = new CanonicalTreeParser - newTreeIter.reset(newReader, newGit.getRepository.resolve(s"${forkedId}^{tree}")) + val pullreq = getCompareInfo( + origin, repository.repository.originRepositoryName.get, originId, + params("owner"), params("repository"), forkedId) - import scala.collection.JavaConverters._ - 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) + pulls.html.compare(pullreq._1, pullreq._2, origin, originId, forkedId, newId.getName, repository, originRepository) } } getOrElse NotFound } @@ -135,26 +160,6 @@ trait PullRequestsControllerBase extends ControllerBase { 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 = { val oldGit = Git.open(oldDir) 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) + } + } + } diff --git a/src/main/twirl/pulls/commits.scala.html b/src/main/twirl/pulls/commits.scala.html new file mode 100644 index 000000000..64bead2f8 --- /dev/null +++ b/src/main/twirl/pulls/commits.scala.html @@ -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) +
+ + @commits.map { day => + + + + @day.map { commit => + + + + + + } + } +
@date(day.head.time)
+ @avatar(commit.committer, 20) + @commit.committer + @commit.shortMessage + @commit.id.substring(0, 7) +
+
+} \ No newline at end of file diff --git a/src/main/twirl/pulls/compare.scala.html b/src/main/twirl/pulls/compare.scala.html index 3c6ab3a91..8c5740bdb 100644 --- a/src/main/twirl/pulls/compare.scala.html +++ b/src/main/twirl/pulls/compare.scala.html @@ -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, repository: service.RepositoryService.RepositoryInfo, originRepository: service.RepositoryService.RepositoryInfo)(implicit context: app.Context) @@ -33,7 +33,7 @@ -