diff --git a/README.md b/README.md
index 8faba94..df4d61a 100644
--- a/README.md
+++ b/README.md
@@ -1,16 +1,14 @@
-GitBucket
+GitBucket [](https://gitter.im/takezoe/gitbucket) [](https://buildhive.cloudbees.com/job/takezoe/job/gitbucket/)
=========
GitBucket is the easily installable Github clone written with Scala.
-[](https://gitter.im/takezoe/gitbucket)
-
Features
--------
The current version of GitBucket provides a basic features below:
-- Public / Private Git repository (http access only)
+- Public / Private Git repository (http and ssh access)
- Repository viewer and online file editing
- Repository search (Code and Issues)
- Wiki
@@ -85,7 +83,7 @@
### 1.13 - 29 Apr 2014
- Direct file editing in the repository viewer using AceEditor
- File attachment for issues
-- Atom feed for user activities
+- Atom feed of user activity
- Fix some bugs
### 1.12 - 29 Mar 2014
diff --git a/etc/icons.svg b/etc/icons.svg
index c2efe0e..a1849e3 100644
--- a/etc/icons.svg
+++ b/etc/icons.svg
@@ -2,6 +2,7 @@
diff --git a/src/main/scala/app/AccountController.scala b/src/main/scala/app/AccountController.scala
index 72244dc..3304480 100644
--- a/src/main/scala/app/AccountController.scala
+++ b/src/main/scala/app/AccountController.scala
@@ -355,47 +355,42 @@
val loginUserName = loginAccount.userName
LockUtil.lock(s"${loginUserName}/${repository.name}/create"){
- if(repository.owner == loginUserName){
- // redirect to the repository
- redirect(s"/${repository.owner}/${repository.name}")
+ if(repository.owner == loginUserName || getRepository(loginAccount.userName, repository.name, baseUrl).isDefined){
+ // redirect to the repository if repository already exists
+ redirect(s"/${loginUserName}/${repository.name}")
} else {
- getForkedRepositories(repository.owner, repository.name).find(_._1 == loginUserName).map { case (owner, name) =>
- // redirect to the repository
- redirect(s"/${owner}/${name}")
- } getOrElse {
- // Insert to the database at first
- val originUserName = repository.repository.originUserName.getOrElse(repository.owner)
- val originRepositoryName = repository.repository.originRepositoryName.getOrElse(repository.name)
+ // Insert to the database at first
+ val originUserName = repository.repository.originUserName.getOrElse(repository.owner)
+ val originRepositoryName = repository.repository.originRepositoryName.getOrElse(repository.name)
- createRepository(
- repositoryName = repository.name,
- userName = loginUserName,
- description = repository.repository.description,
- isPrivate = repository.repository.isPrivate,
- originRepositoryName = Some(originRepositoryName),
- originUserName = Some(originUserName),
- parentRepositoryName = Some(repository.name),
- parentUserName = Some(repository.owner)
- )
+ createRepository(
+ repositoryName = repository.name,
+ userName = loginUserName,
+ description = repository.repository.description,
+ isPrivate = repository.repository.isPrivate,
+ originRepositoryName = Some(originRepositoryName),
+ originUserName = Some(originUserName),
+ parentRepositoryName = Some(repository.name),
+ parentUserName = Some(repository.owner)
+ )
- // Insert default labels
- insertDefaultLabels(loginUserName, repository.name)
+ // Insert default labels
+ insertDefaultLabels(loginUserName, repository.name)
- // clone repository actually
- JGitUtil.cloneRepository(
- getRepositoryDir(repository.owner, repository.name),
- getRepositoryDir(loginUserName, repository.name))
+ // clone repository actually
+ JGitUtil.cloneRepository(
+ getRepositoryDir(repository.owner, repository.name),
+ getRepositoryDir(loginUserName, repository.name))
- // Create Wiki repository
- JGitUtil.cloneRepository(
- getWikiRepositoryDir(repository.owner, repository.name),
- getWikiRepositoryDir(loginUserName, repository.name))
+ // Create Wiki repository
+ JGitUtil.cloneRepository(
+ getWikiRepositoryDir(repository.owner, repository.name),
+ getWikiRepositoryDir(loginUserName, repository.name))
- // Record activity
- recordForkActivity(repository.owner, repository.name, loginUserName)
- // redirect to the repository
- redirect(s"/${loginUserName}/${repository.name}")
- }
+ // Record activity
+ recordForkActivity(repository.owner, repository.name, loginUserName)
+ // redirect to the repository
+ redirect(s"/${loginUserName}/${repository.name}")
}
}
})
diff --git a/src/main/scala/app/FileUploadController.scala b/src/main/scala/app/FileUploadController.scala
index ad8ea28..9798c0a 100644
--- a/src/main/scala/app/FileUploadController.scala
+++ b/src/main/scala/app/FileUploadController.scala
@@ -25,7 +25,9 @@
post("/image/:owner/:repository"){
execute { (file, fileId) =>
- FileUtils.writeByteArrayToFile(new java.io.File(getAttachedDir(params("owner"), params("repository")), fileId), file.get)
+ FileUtils.writeByteArrayToFile(new java.io.File(
+ getAttachedDir(params("owner"), params("repository")),
+ fileId + "." + FileUtil.getExtension(file.getName)), file.get)
}
}
diff --git a/src/main/scala/app/IssuesController.scala b/src/main/scala/app/IssuesController.scala
index 61bd52f..661c1e0 100644
--- a/src/main/scala/app/IssuesController.scala
+++ b/src/main/scala/app/IssuesController.scala
@@ -274,9 +274,14 @@
})
get("/:owner/:repository/_attached/:file")(referrersOnly { repository =>
- defining(new java.io.File(Directory.getAttachedDir(repository.owner, repository.name), params("file"))){ file =>
- if(file.exists) file else NotFound
- }
+ (Directory.getAttachedDir(repository.owner, repository.name) match {
+ case dir if(dir.exists && dir.isDirectory) =>
+ dir.listFiles.find(_.getName.startsWith(params("file") + ".")).map { file =>
+ contentType = FileUtil.getMimeType(file.getName)
+ file
+ }
+ case _ => None
+ }) getOrElse NotFound
})
val assignedUserName = (key: String) => params.get(key) filter (_.trim != "")
diff --git a/src/main/scala/app/WikiController.scala b/src/main/scala/app/WikiController.scala
index 07208a5..d7399ed 100644
--- a/src/main/scala/app/WikiController.scala
+++ b/src/main/scala/app/WikiController.scala
@@ -36,7 +36,8 @@
get("/:owner/:repository/wiki")(referrersOnly { repository =>
getWikiPage(repository.owner, repository.name, "Home").map { page =>
- wiki.html.page("Home", page, repository, hasWritePermission(repository.owner, repository.name, context.loginAccount))
+ wiki.html.page("Home", page, getWikiPageList(repository.owner, repository.name),
+ repository, hasWritePermission(repository.owner, repository.name, context.loginAccount))
} getOrElse redirect(s"/${repository.owner}/${repository.name}/wiki/Home/_edit")
})
@@ -44,7 +45,8 @@
val pageName = StringUtil.urlDecode(params("page"))
getWikiPage(repository.owner, repository.name, pageName).map { page =>
- wiki.html.page(pageName, page, repository, hasWritePermission(repository.owner, repository.name, context.loginAccount))
+ wiki.html.page(pageName, page, getWikiPageList(repository.owner, repository.name),
+ repository, hasWritePermission(repository.owner, repository.name, context.loginAccount))
} getOrElse redirect(s"/${repository.owner}/${repository.name}/wiki/${StringUtil.urlEncode(pageName)}/_edit")
})
diff --git a/src/main/scala/service/PullRequestService.scala b/src/main/scala/service/PullRequestService.scala
index 1298493..07f7145 100644
--- a/src/main/scala/service/PullRequestService.scala
+++ b/src/main/scala/service/PullRequestService.scala
@@ -3,7 +3,6 @@
import scala.slick.driver.H2Driver.simple._
import Database.threadLocalSession
import model._
-import util.ControlUtil._
trait PullRequestService { self: IssuesService =>
import PullRequestService._
@@ -15,11 +14,10 @@
}
}
- def updateCommitIdTo(owner: String, repository: String, issueId: Int, commitIdTo: String): Unit =
- Query(PullRequests).filter(_.byPrimaryKey(owner, repository, issueId)).map(_.commitIdTo).update(commitIdTo)
-
- def updateCommitIdFrom(owner: String, repository: String, issueId: Int, commitIdFrom: String): Unit =
- Query(PullRequests).filter(_.byPrimaryKey(owner, repository, issueId)).map(_.commitIdFrom).update(commitIdFrom)
+ def updateCommitId(owner: String, repository: String, issueId: Int, commitIdTo: String, commitIdFrom: String): Unit =
+ Query(PullRequests).filter(_.byPrimaryKey(owner, repository, issueId))
+ .map(pr => pr.commitIdTo ~ pr.commitIdFrom)
+ .update((commitIdTo, commitIdFrom))
def getPullRequestCountGroupByUser(closed: Boolean, owner: String, repository: Option[String]): List[PullRequestCount] =
Query(PullRequests)
diff --git a/src/main/scala/service/RepositoryService.scala b/src/main/scala/service/RepositoryService.scala
index 774017e..49fd102 100644
--- a/src/main/scala/service/RepositoryService.scala
+++ b/src/main/scala/service/RepositoryService.scala
@@ -40,60 +40,66 @@
}
def renameRepository(oldUserName: String, oldRepositoryName: String, newUserName: String, newRepositoryName: String): Unit = {
- (Query(Repositories) filter { t => t.byRepository(oldUserName, oldRepositoryName) } firstOption).map { repository =>
- Repositories insert repository.copy(userName = newUserName, repositoryName = newRepositoryName)
+ getAccountByUserName(newUserName).foreach { account =>
+ (Query(Repositories) filter { t => t.byRepository(oldUserName, oldRepositoryName) } firstOption).map { repository =>
+ Repositories insert repository.copy(userName = newUserName, repositoryName = newRepositoryName)
- val webHooks = Query(WebHooks ).filter(_.byRepository(oldUserName, oldRepositoryName)).list
- val milestones = Query(Milestones ).filter(_.byRepository(oldUserName, oldRepositoryName)).list
- val issueId = Query(IssueId ).filter(_.byRepository(oldUserName, oldRepositoryName)).list
- val issues = Query(Issues ).filter(_.byRepository(oldUserName, oldRepositoryName)).list
- val pullRequests = Query(PullRequests ).filter(_.byRepository(oldUserName, oldRepositoryName)).list
- val labels = Query(Labels ).filter(_.byRepository(oldUserName, oldRepositoryName)).list
- val issueComments = Query(IssueComments).filter(_.byRepository(oldUserName, oldRepositoryName)).list
- val issueLabels = Query(IssueLabels ).filter(_.byRepository(oldUserName, oldRepositoryName)).list
- val collaborators = Query(Collaborators).filter(_.byRepository(oldUserName, oldRepositoryName)).list
- val activities = Query(Activities ).filter(_.byRepository(oldUserName, oldRepositoryName)).list
+ val webHooks = Query(WebHooks ).filter(_.byRepository(oldUserName, oldRepositoryName)).list
+ val milestones = Query(Milestones ).filter(_.byRepository(oldUserName, oldRepositoryName)).list
+ val issueId = Query(IssueId ).filter(_.byRepository(oldUserName, oldRepositoryName)).list
+ val issues = Query(Issues ).filter(_.byRepository(oldUserName, oldRepositoryName)).list
+ val pullRequests = Query(PullRequests ).filter(_.byRepository(oldUserName, oldRepositoryName)).list
+ val labels = Query(Labels ).filter(_.byRepository(oldUserName, oldRepositoryName)).list
+ val issueComments = Query(IssueComments).filter(_.byRepository(oldUserName, oldRepositoryName)).list
+ val issueLabels = Query(IssueLabels ).filter(_.byRepository(oldUserName, oldRepositoryName)).list
+ val activities = Query(Activities ).filter(_.byRepository(oldUserName, oldRepositoryName)).list
+ val collaborators = Query(Collaborators).filter(_.byRepository(oldUserName, oldRepositoryName)).list
- Repositories.filter { t =>
- (t.originUserName is oldUserName.bind) && (t.originRepositoryName is oldRepositoryName.bind)
- }.map { t => t.originUserName ~ t.originRepositoryName }.update(newUserName, newRepositoryName)
+ Repositories.filter { t =>
+ (t.originUserName is oldUserName.bind) && (t.originRepositoryName is oldRepositoryName.bind)
+ }.map { t => t.originUserName ~ t.originRepositoryName }.update(newUserName, newRepositoryName)
- Repositories.filter { t =>
- (t.parentUserName is oldUserName.bind) && (t.parentRepositoryName is oldRepositoryName.bind)
- }.map { t => t.originUserName ~ t.originRepositoryName }.update(newUserName, newRepositoryName)
+ Repositories.filter { t =>
+ (t.parentUserName is oldUserName.bind) && (t.parentRepositoryName is oldRepositoryName.bind)
+ }.map { t => t.originUserName ~ t.originRepositoryName }.update(newUserName, newRepositoryName)
- PullRequests.filter { t =>
- t.requestRepositoryName is oldRepositoryName.bind
- }.map { t => t.requestUserName ~ t.requestRepositoryName }.update(newUserName, newRepositoryName)
+ PullRequests.filter { t =>
+ t.requestRepositoryName is oldRepositoryName.bind
+ }.map { t => t.requestUserName ~ t.requestRepositoryName }.update(newUserName, newRepositoryName)
- deleteRepository(oldUserName, oldRepositoryName)
+ deleteRepository(oldUserName, oldRepositoryName)
- WebHooks .insertAll(webHooks .map(_.copy(userName = newUserName, repositoryName = newRepositoryName)) :_*)
- Milestones .insertAll(milestones .map(_.copy(userName = newUserName, repositoryName = newRepositoryName)) :_*)
- IssueId .insertAll(issueId .map(_.copy(_1 = newUserName, _2 = newRepositoryName)) :_*)
- Issues .insertAll(issues .map(_.copy(userName = newUserName, repositoryName = newRepositoryName)) :_*)
- PullRequests .insertAll(pullRequests .map(_.copy(userName = newUserName, repositoryName = newRepositoryName)) :_*)
- IssueComments .insertAll(issueComments .map(_.copy(userName = newUserName, repositoryName = newRepositoryName)) :_*)
- Labels .insertAll(labels .map(_.copy(userName = newUserName, repositoryName = newRepositoryName)) :_*)
- IssueLabels .insertAll(issueLabels .map(_.copy(userName = newUserName, repositoryName = newRepositoryName)) :_*)
- Collaborators .insertAll(collaborators .map(_.copy(userName = newUserName, repositoryName = newRepositoryName)) :_*)
- Activities .insertAll(activities .map(_.copy(userName = newUserName, repositoryName = newRepositoryName)) :_*)
+ WebHooks .insertAll(webHooks .map(_.copy(userName = newUserName, repositoryName = newRepositoryName)) :_*)
+ Milestones .insertAll(milestones .map(_.copy(userName = newUserName, repositoryName = newRepositoryName)) :_*)
+ IssueId .insertAll(issueId .map(_.copy(_1 = newUserName, _2 = newRepositoryName)) :_*)
+ Issues .insertAll(issues .map(_.copy(userName = newUserName, repositoryName = newRepositoryName)) :_*)
+ PullRequests .insertAll(pullRequests .map(_.copy(userName = newUserName, repositoryName = newRepositoryName)) :_*)
+ IssueComments .insertAll(issueComments .map(_.copy(userName = newUserName, repositoryName = newRepositoryName)) :_*)
+ Labels .insertAll(labels .map(_.copy(userName = newUserName, repositoryName = newRepositoryName)) :_*)
+ IssueLabels .insertAll(issueLabels .map(_.copy(userName = newUserName, repositoryName = newRepositoryName)) :_*)
+ Activities .insertAll(activities .map(_.copy(userName = newUserName, repositoryName = newRepositoryName)) :_*)
+ if(account.isGroupAccount){
+ Collaborators.insertAll(getGroupMembers(newUserName).map(m => Collaborator(newUserName, newRepositoryName, m.userName)) :_*)
+ } else {
+ Collaborators.insertAll(collaborators.map(_.copy(userName = newUserName, repositoryName = newRepositoryName)) :_*)
+ }
- // Update activity messages
- val updateActivities = Activities.filter { t =>
- (t.message like s"%:${oldUserName}/${oldRepositoryName}]%") ||
- (t.message like s"%:${oldUserName}/${oldRepositoryName}#%")
- }.map { t => t.activityId ~ t.message }.list
+ // Update activity messages
+ val updateActivities = Activities.filter { t =>
+ (t.message like s"%:${oldUserName}/${oldRepositoryName}]%") ||
+ (t.message like s"%:${oldUserName}/${oldRepositoryName}#%")
+ }.map { t => t.activityId ~ t.message }.list
- updateActivities.foreach { case (activityId, message) =>
- Activities.filter(_.activityId is activityId.bind).map(_.message).update(
- message
- .replace(s"[repo:${oldUserName}/${oldRepositoryName}]" ,s"[repo:${newUserName}/${newRepositoryName}]")
- .replace(s"[branch:${oldUserName}/${oldRepositoryName}#" ,s"[branch:${newUserName}/${newRepositoryName}#")
- .replace(s"[tag:${oldUserName}/${oldRepositoryName}#" ,s"[tag:${newUserName}/${newRepositoryName}#")
- .replace(s"[pullreq:${oldUserName}/${oldRepositoryName}#",s"[pullreq:${newUserName}/${newRepositoryName}#")
- .replace(s"[issue:${oldUserName}/${oldRepositoryName}#" ,s"[issue:${newUserName}/${newRepositoryName}#")
- )
+ updateActivities.foreach { case (activityId, message) =>
+ Activities.filter(_.activityId is activityId.bind).map(_.message).update(
+ message
+ .replace(s"[repo:${oldUserName}/${oldRepositoryName}]" ,s"[repo:${newUserName}/${newRepositoryName}]")
+ .replace(s"[branch:${oldUserName}/${oldRepositoryName}#" ,s"[branch:${newUserName}/${newRepositoryName}#")
+ .replace(s"[tag:${oldUserName}/${oldRepositoryName}#" ,s"[tag:${newUserName}/${newRepositoryName}#")
+ .replace(s"[pullreq:${oldUserName}/${oldRepositoryName}#",s"[pullreq:${newUserName}/${newRepositoryName}#")
+ .replace(s"[issue:${oldUserName}/${oldRepositoryName}#" ,s"[issue:${newUserName}/${newRepositoryName}#")
+ )
+ }
}
}
}
diff --git a/src/main/scala/servlet/AutoUpdateListener.scala b/src/main/scala/servlet/AutoUpdateListener.scala
index 9ffed83..801ff68 100644
--- a/src/main/scala/servlet/AutoUpdateListener.scala
+++ b/src/main/scala/servlet/AutoUpdateListener.scala
@@ -9,6 +9,7 @@
import util.Directory._
import util.ControlUtil._
import org.eclipse.jgit.api.Git
+import util.Directory
object AutoUpdate {
@@ -50,6 +51,32 @@
* The history of versions. A head of this sequence is the current BitBucket version.
*/
val versions = Seq(
+ new Version(2, 0){
+ override def update(conn: Connection): Unit = {
+ import eu.medsea.mimeutil.{MimeUtil2, MimeType}
+
+ val mimeUtil = new MimeUtil2()
+ mimeUtil.registerMimeDetector("eu.medsea.mimeutil.detector.MagicMimeMimeDetector")
+
+ super.update(conn)
+ using(conn.createStatement.executeQuery("SELECT USER_NAME, REPOSITORY_NAME FROM REPOSITORY")){ rs =>
+ while(rs.next){
+ defining(Directory.getAttachedDir(rs.getString("USER_NAME"), rs.getString("REPOSITORY_NAME"))){ dir =>
+ if(dir.exists && dir.isDirectory){
+ dir.listFiles.foreach { file =>
+ if(file.getName.indexOf('.') < 0){
+ val mimeType = MimeUtil2.getMostSpecificMimeType(mimeUtil.getMimeTypes(file, new MimeType("application/octet-stream"))).toString
+ if(mimeType.startsWith("image/")){
+ file.renameTo(new File(file.getParent, file.getName + "." + mimeType.split("/")(1)))
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
Version(1, 13),
Version(1, 12),
Version(1, 11),
diff --git a/src/main/scala/servlet/GitRepositoryServlet.scala b/src/main/scala/servlet/GitRepositoryServlet.scala
index 94f0521..0e43432 100644
--- a/src/main/scala/servlet/GitRepositoryServlet.scala
+++ b/src/main/scala/servlet/GitRepositoryServlet.scala
@@ -226,13 +226,10 @@
.call
val commitIdTo = oldGit.getRepository.resolve(s"refs/pull/${pullreq.issueId}/head").getName
- updateCommitIdTo(pullreq.userName, pullreq.repositoryName, pullreq.issueId, commitIdTo)
-
val commitIdFrom = JGitUtil.getForkedCommitId(oldGit, newGit,
pullreq.userName, pullreq.repositoryName, pullreq.branch,
pullreq.requestUserName, pullreq.requestRepositoryName, pullreq.requestBranch)
- // TODO(tanacasino): commitIdFrom and commitIdTo should be updated by one query...
- updateCommitIdFrom(pullreq.userName, pullreq.repositoryName, pullreq.issueId, commitIdFrom)
+ updateCommitId(pullreq.userName, pullreq.repositoryName, pullreq.issueId, commitIdTo, commitIdFrom)
}
}
}
diff --git a/src/main/scala/util/JGitUtil.scala b/src/main/scala/util/JGitUtil.scala
index 9f48c39..282469e 100644
--- a/src/main/scala/util/JGitUtil.scala
+++ b/src/main/scala/util/JGitUtil.scala
@@ -372,7 +372,12 @@
if(commits.length >= 2){
// not initial commit
- val oldCommit = commits(1)
+ val oldCommit = if(revCommit.getParentCount >= 2) {
+ // merge commit
+ revCommit.getParents.head
+ } else {
+ commits(1)
+ }
(getDiffs(git, oldCommit.getName, id, fetchContent), Some(oldCommit.getName))
} else {
diff --git a/src/main/scala/view/Markdown.scala b/src/main/scala/view/Markdown.scala
index 4d998bd..a66f9f7 100644
--- a/src/main/scala/view/Markdown.scala
+++ b/src/main/scala/view/Markdown.scala
@@ -89,7 +89,8 @@
) with LinkConverter with RequestCache {
override protected def printImageTag(imageNode: SuperNode, url: String): Unit =
- printer.print("")
+ printer.print("")
+ .print("
")
override protected def printLink(rendering: LinkRenderer.Rendering): Unit = {
printer.print('<').print('a')
@@ -101,7 +102,7 @@
}
private def fixUrl(url: String): String = {
- if(!enableWikiLink || url.startsWith("http://") || url.startsWith("https://")){
+ if(!enableWikiLink || url.startsWith("http://") || url.startsWith("https://") || url.startsWith("#")){
url
} else {
repository.httpUrl.replaceFirst("/git/", "/").replaceFirst("\\.git$", "") + "/wiki/_blob/" + url
diff --git a/src/main/twirl/account/edit.scala.html b/src/main/twirl/account/edit.scala.html
index 23d4882..a441f09 100644
--- a/src/main/twirl/account/edit.scala.html
+++ b/src/main/twirl/account/edit.scala.html
@@ -3,63 +3,63 @@
@import view.helpers._
@import util.AccountUtil
@html.main("Edit your profile"){
-