Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
753403b4c8 | ||
|
|
5a0f9f8bbb | ||
|
|
8fa22b4de2 | ||
|
|
d17cae16fd | ||
|
|
c4c48962cf | ||
|
|
4140e92f0b | ||
|
|
887e560a1b | ||
|
|
e2d70181e8 | ||
|
|
148c453dbc | ||
|
|
f6ee9d311d | ||
|
|
35209e43bb | ||
|
|
4a3ecf063d | ||
|
|
4c79101624 | ||
|
|
921b01661b | ||
|
|
c63301d8e6 | ||
|
|
c9ed9d2237 | ||
|
|
ca55cbe456 | ||
|
|
d4828613ee | ||
|
|
a0be02ce2f | ||
|
|
9b8016a4d5 | ||
|
|
8fdd3bfd21 | ||
|
|
695a061e3c | ||
|
|
bd50d9218e | ||
|
|
d8f13bc1ce | ||
|
|
ed84d1a3c9 | ||
|
|
3c765d879c |
2
.gitignore
vendored
@@ -2,6 +2,8 @@
|
|||||||
*.log
|
*.log
|
||||||
.ensime
|
.ensime
|
||||||
.ensime_cache
|
.ensime_cache
|
||||||
|
.DS_Store
|
||||||
|
.java-version
|
||||||
|
|
||||||
# sbt specific
|
# sbt specific
|
||||||
dist/*
|
dist/*
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
All changes to the project will be documented in this file.
|
All changes to the project will be documented in this file.
|
||||||
|
|
||||||
|
## 4.38.3 - 30 Oct 2022
|
||||||
|
- Fix several issues around multiple assignees in issues and pull requests
|
||||||
|
- Fix IllegalStateException when returning unknown avatar image
|
||||||
|
|
||||||
## 4.38.2 - 20 Sep 2022
|
## 4.38.2 - 20 Sep 2022
|
||||||
- Resurrect assignee icons on the issue list
|
- Resurrect assignee icons on the issue list
|
||||||
|
|
||||||
|
|||||||
@@ -61,6 +61,10 @@ Support
|
|||||||
|
|
||||||
What's New in 4.38.x
|
What's New in 4.38.x
|
||||||
-------------
|
-------------
|
||||||
|
## 4.38.3 - 30 Oct 2022
|
||||||
|
- Fix several issues around multiple assignees in issues and pull requests
|
||||||
|
- Fix IllegalStateException when returning unknown avatar image
|
||||||
|
|
||||||
## 4.38.2 - 20 Sep 2022
|
## 4.38.2 - 20 Sep 2022
|
||||||
- Resurrect assignee icons on the issue list
|
- Resurrect assignee icons on the issue list
|
||||||
|
|
||||||
|
|||||||
28
build.sbt
@@ -3,8 +3,8 @@ import com.jsuereth.sbtpgp.PgpKeys._
|
|||||||
|
|
||||||
val Organization = "io.github.gitbucket"
|
val Organization = "io.github.gitbucket"
|
||||||
val Name = "gitbucket"
|
val Name = "gitbucket"
|
||||||
val GitBucketVersion = "4.38.2"
|
val GitBucketVersion = "4.38.3"
|
||||||
val ScalatraVersion = "2.8.2"
|
val ScalatraVersion = "2.8.4"
|
||||||
val JettyVersion = "9.4.49.v20220914"
|
val JettyVersion = "9.4.49.v20220914"
|
||||||
val JgitVersion = "5.13.1.202206130422-r"
|
val JgitVersion = "5.13.1.202206130422-r"
|
||||||
|
|
||||||
@@ -15,9 +15,9 @@ sourcesInBase := false
|
|||||||
organization := Organization
|
organization := Organization
|
||||||
name := Name
|
name := Name
|
||||||
version := GitBucketVersion
|
version := GitBucketVersion
|
||||||
scalaVersion := "2.13.9"
|
scalaVersion := "2.13.10"
|
||||||
|
|
||||||
scalafmtOnCompile := true
|
// scalafmtOnCompile := true
|
||||||
|
|
||||||
coverageExcludedPackages := ".*\\.html\\..*"
|
coverageExcludedPackages := ".*\\.html\\..*"
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@ libraryDependencies ++= Seq(
|
|||||||
"org.scalatra" %% "scalatra" % ScalatraVersion cross CrossVersion.for3Use2_13,
|
"org.scalatra" %% "scalatra" % ScalatraVersion cross CrossVersion.for3Use2_13,
|
||||||
"org.scalatra" %% "scalatra-json" % ScalatraVersion cross CrossVersion.for3Use2_13,
|
"org.scalatra" %% "scalatra-json" % ScalatraVersion cross CrossVersion.for3Use2_13,
|
||||||
"org.scalatra" %% "scalatra-forms" % ScalatraVersion cross CrossVersion.for3Use2_13,
|
"org.scalatra" %% "scalatra-forms" % ScalatraVersion cross CrossVersion.for3Use2_13,
|
||||||
"org.json4s" %% "json4s-jackson" % "4.0.5" cross CrossVersion.for3Use2_13,
|
"org.json4s" %% "json4s-jackson" % "4.0.6" cross CrossVersion.for3Use2_13,
|
||||||
"commons-io" % "commons-io" % "2.11.0",
|
"commons-io" % "commons-io" % "2.11.0",
|
||||||
"io.github.gitbucket" % "solidbase" % "1.0.5",
|
"io.github.gitbucket" % "solidbase" % "1.0.5",
|
||||||
"io.github.gitbucket" % "markedj" % "1.0.17",
|
"io.github.gitbucket" % "markedj" % "1.0.17",
|
||||||
@@ -42,11 +42,11 @@ libraryDependencies ++= Seq(
|
|||||||
"commons-net" % "commons-net" % "3.8.0",
|
"commons-net" % "commons-net" % "3.8.0",
|
||||||
"org.apache.httpcomponents" % "httpclient" % "4.5.13",
|
"org.apache.httpcomponents" % "httpclient" % "4.5.13",
|
||||||
"org.apache.sshd" % "apache-sshd" % "2.9.1" exclude ("org.slf4j", "slf4j-jdk14") exclude ("org.apache.sshd", "sshd-mina") exclude ("org.apache.sshd", "sshd-netty"),
|
"org.apache.sshd" % "apache-sshd" % "2.9.1" exclude ("org.slf4j", "slf4j-jdk14") exclude ("org.apache.sshd", "sshd-mina") exclude ("org.apache.sshd", "sshd-netty"),
|
||||||
"org.apache.tika" % "tika-core" % "2.4.1",
|
"org.apache.tika" % "tika-core" % "2.5.0",
|
||||||
"com.github.takezoe" %% "blocking-slick-32" % "0.0.12" cross CrossVersion.for3Use2_13,
|
"com.github.takezoe" %% "blocking-slick-32" % "0.0.12" cross CrossVersion.for3Use2_13,
|
||||||
"com.novell.ldap" % "jldap" % "2009-10-07",
|
"com.novell.ldap" % "jldap" % "2009-10-07",
|
||||||
"com.h2database" % "h2" % "1.4.199",
|
"com.h2database" % "h2" % "1.4.199",
|
||||||
"org.mariadb.jdbc" % "mariadb-java-client" % "3.0.7",
|
"org.mariadb.jdbc" % "mariadb-java-client" % "3.0.8",
|
||||||
"org.postgresql" % "postgresql" % "42.5.0",
|
"org.postgresql" % "postgresql" % "42.5.0",
|
||||||
"ch.qos.logback" % "logback-classic" % "1.2.11",
|
"ch.qos.logback" % "logback-classic" % "1.2.11",
|
||||||
"com.zaxxer" % "HikariCP" % "4.0.3" exclude ("org.slf4j", "slf4j-api"),
|
"com.zaxxer" % "HikariCP" % "4.0.3" exclude ("org.slf4j", "slf4j-api"),
|
||||||
@@ -54,21 +54,21 @@ libraryDependencies ++= Seq(
|
|||||||
"fr.brouillard.oss.security.xhub" % "xhub4j-core" % "1.1.0",
|
"fr.brouillard.oss.security.xhub" % "xhub4j-core" % "1.1.0",
|
||||||
"io.github.java-diff-utils" % "java-diff-utils" % "4.12",
|
"io.github.java-diff-utils" % "java-diff-utils" % "4.12",
|
||||||
"org.cache2k" % "cache2k-all" % "1.6.0.Final",
|
"org.cache2k" % "cache2k-all" % "1.6.0.Final",
|
||||||
"net.coobird" % "thumbnailator" % "0.4.17",
|
"net.coobird" % "thumbnailator" % "0.4.18",
|
||||||
"com.github.zafarkhaja" % "java-semver" % "0.9.0",
|
"com.github.zafarkhaja" % "java-semver" % "0.9.0",
|
||||||
"com.nimbusds" % "oauth2-oidc-sdk" % "9.43.1",
|
"com.nimbusds" % "oauth2-oidc-sdk" % "10.1",
|
||||||
"org.eclipse.jetty" % "jetty-webapp" % JettyVersion % "provided",
|
"org.eclipse.jetty" % "jetty-webapp" % JettyVersion % "provided",
|
||||||
"javax.servlet" % "javax.servlet-api" % "3.1.0" % "provided",
|
"javax.servlet" % "javax.servlet-api" % "3.1.0" % "provided",
|
||||||
"junit" % "junit" % "4.13.2" % "test",
|
"junit" % "junit" % "4.13.2" % "test",
|
||||||
"org.scalatra" %% "scalatra-scalatest" % ScalatraVersion % "test" cross CrossVersion.for3Use2_13,
|
"org.scalatra" %% "scalatra-scalatest" % ScalatraVersion % "test" cross CrossVersion.for3Use2_13,
|
||||||
"org.mockito" % "mockito-core" % "4.8.0" % "test",
|
"org.mockito" % "mockito-core" % "4.8.1" % "test",
|
||||||
"com.dimafeng" %% "testcontainers-scala" % "0.40.10" % "test",
|
"com.dimafeng" %% "testcontainers-scala" % "0.40.11" % "test",
|
||||||
"org.testcontainers" % "mysql" % "1.17.3" % "test",
|
"org.testcontainers" % "mysql" % "1.17.5" % "test",
|
||||||
"org.testcontainers" % "postgresql" % "1.17.3" % "test",
|
"org.testcontainers" % "postgresql" % "1.17.5" % "test",
|
||||||
"net.i2p.crypto" % "eddsa" % "0.3.0",
|
"net.i2p.crypto" % "eddsa" % "0.3.0",
|
||||||
"is.tagomor.woothee" % "woothee-java" % "1.11.0",
|
"is.tagomor.woothee" % "woothee-java" % "1.11.0",
|
||||||
"org.ec4j.core" % "ec4j-core" % "0.3.0",
|
"org.ec4j.core" % "ec4j-core" % "0.3.0",
|
||||||
"org.kohsuke" % "github-api" % "1.308" % "test"
|
"org.kohsuke" % "github-api" % "1.313" % "test"
|
||||||
)
|
)
|
||||||
|
|
||||||
libraryDependencies ~= {
|
libraryDependencies ~= {
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 203 KiB After Width: | Height: | Size: 112 KiB |
@@ -1 +1 @@
|
|||||||
sbt.version=1.7.1
|
sbt.version=1.7.2
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ scalacOptions ++= Seq("-unchecked", "-deprecation", "-feature")
|
|||||||
|
|
||||||
addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.6")
|
addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.6")
|
||||||
addSbtPlugin("com.typesafe.sbt" % "sbt-twirl" % "1.5.1")
|
addSbtPlugin("com.typesafe.sbt" % "sbt-twirl" % "1.5.1")
|
||||||
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "1.2.0")
|
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "2.0.0")
|
||||||
addSbtPlugin("org.scalatra.sbt" % "sbt-scalatra" % "1.0.4")
|
addSbtPlugin("org.scalatra.sbt" % "sbt-scalatra" % "1.0.4")
|
||||||
addSbtPlugin("com.github.sbt" % "sbt-pgp" % "2.1.2")
|
addSbtPlugin("com.github.sbt" % "sbt-pgp" % "2.1.2")
|
||||||
addSbtPlugin("com.typesafe.sbt" % "sbt-license-report" % "1.2.0")
|
addSbtPlugin("com.typesafe.sbt" % "sbt-license-report" % "1.2.0")
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 1.5 KiB |
@@ -113,5 +113,6 @@ object GitBucketCoreModule
|
|||||||
new Version("4.37.2"),
|
new Version("4.37.2"),
|
||||||
new Version("4.38.0", new LiquibaseMigration("update/gitbucket-core_4.38.xml")),
|
new Version("4.38.0", new LiquibaseMigration("update/gitbucket-core_4.38.xml")),
|
||||||
new Version("4.38.1"),
|
new Version("4.38.1"),
|
||||||
new Version("4.38.2")
|
new Version("4.38.2"),
|
||||||
|
new Version("4.38.3")
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -100,4 +100,16 @@ trait ApiControllerBase extends ControllerBase {
|
|||||||
get("/api/v3/gitbucket/plugins") {
|
get("/api/v3/gitbucket/plugins") {
|
||||||
PluginRegistry().getPlugins().map { ApiPlugin(_) }
|
PluginRegistry().getPlugins().map { ApiPlugin(_) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://docs.github.com/en/enterprise-server@2.21/rest/reference/meta#get-github-enterprise-server-meta-information
|
||||||
|
*/
|
||||||
|
get("/api/v3/meta") {
|
||||||
|
JsonFormat(
|
||||||
|
Map(
|
||||||
|
"https://api.github.com/meta" -> context.loginAccount.isDefined,
|
||||||
|
"installed_version" -> "2.21.0"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ trait PullRequestsControllerBase extends ControllerBase {
|
|||||||
"commitIdFrom" -> trim(text(required, maxlength(40))),
|
"commitIdFrom" -> trim(text(required, maxlength(40))),
|
||||||
"commitIdTo" -> trim(text(required, maxlength(40))),
|
"commitIdTo" -> trim(text(required, maxlength(40))),
|
||||||
"isDraft" -> trim(boolean(required)),
|
"isDraft" -> trim(boolean(required)),
|
||||||
"assignedUserName" -> trim(optional(text())),
|
"assigneeUserNames" -> trim(optional(text())),
|
||||||
"milestoneId" -> trim(optional(number())),
|
"milestoneId" -> trim(optional(number())),
|
||||||
"priorityId" -> trim(optional(number())),
|
"priorityId" -> trim(optional(number())),
|
||||||
"labelNames" -> trim(optional(text()))
|
"labelNames" -> trim(optional(text()))
|
||||||
@@ -92,7 +92,7 @@ trait PullRequestsControllerBase extends ControllerBase {
|
|||||||
commitIdFrom: String,
|
commitIdFrom: String,
|
||||||
commitIdTo: String,
|
commitIdTo: String,
|
||||||
isDraft: Boolean,
|
isDraft: Boolean,
|
||||||
assignedUserNames: Option[String],
|
assigneeUserNames: Option[String],
|
||||||
milestoneId: Option[Int],
|
milestoneId: Option[Int],
|
||||||
priorityId: Option[Int],
|
priorityId: Option[Int],
|
||||||
labelNames: Option[String]
|
labelNames: Option[String]
|
||||||
@@ -144,25 +144,6 @@ trait PullRequestsControllerBase extends ControllerBase {
|
|||||||
getRepository(pullreq.requestUserName, pullreq.requestRepositoryName),
|
getRepository(pullreq.requestUserName, pullreq.requestRepositoryName),
|
||||||
flash.iterator.map(f => f._1 -> f._2.toString).toMap
|
flash.iterator.map(f => f._1 -> f._2.toString).toMap
|
||||||
)
|
)
|
||||||
|
|
||||||
// html.pullreq(
|
|
||||||
// issue,
|
|
||||||
// pullreq,
|
|
||||||
// comments,
|
|
||||||
// getIssueLabels(owner, name, issueId),
|
|
||||||
// getAssignableUserNames(owner, name),
|
|
||||||
// getMilestonesWithIssueCount(owner, name),
|
|
||||||
// getPriorities(owner, name),
|
|
||||||
// getLabels(owner, name),
|
|
||||||
// commits,
|
|
||||||
// diffs,
|
|
||||||
// isEditable(repository),
|
|
||||||
// isManageable(repository),
|
|
||||||
// hasDeveloperRole(pullreq.requestUserName, pullreq.requestRepositoryName, context.loginAccount),
|
|
||||||
// repository,
|
|
||||||
// getRepository(pullreq.requestUserName, pullreq.requestRepositoryName),
|
|
||||||
// flash.toMap.map(f => f._1 -> f._2.toString)
|
|
||||||
// )
|
|
||||||
}
|
}
|
||||||
} getOrElse NotFound()
|
} getOrElse NotFound()
|
||||||
})
|
})
|
||||||
@@ -396,9 +377,9 @@ trait PullRequestsControllerBase extends ControllerBase {
|
|||||||
})
|
})
|
||||||
|
|
||||||
get("/:owner/:repository/compare")(referrersOnly { forkedRepository =>
|
get("/:owner/:repository/compare")(referrersOnly { forkedRepository =>
|
||||||
val headBranch: Option[String] = params.get("head")
|
val headBranch = params.get("head")
|
||||||
(forkedRepository.repository.originUserName, forkedRepository.repository.originRepositoryName) match {
|
(forkedRepository.repository.originUserName, forkedRepository.repository.originRepositoryName) match {
|
||||||
case (Some(originUserName), Some(originRepositoryName)) => {
|
case (Some(originUserName), Some(originRepositoryName)) =>
|
||||||
getRepository(originUserName, originRepositoryName).map {
|
getRepository(originUserName, originRepositoryName).map {
|
||||||
originRepository =>
|
originRepository =>
|
||||||
Using.resources(
|
Using.resources(
|
||||||
@@ -415,8 +396,7 @@ trait PullRequestsControllerBase extends ControllerBase {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
} getOrElse NotFound()
|
} getOrElse NotFound()
|
||||||
}
|
case _ =>
|
||||||
case _ => {
|
|
||||||
Using.resource(Git.open(getRepositoryDir(forkedRepository.owner, forkedRepository.name))) { git =>
|
Using.resource(Git.open(getRepositoryDir(forkedRepository.owner, forkedRepository.name))) { git =>
|
||||||
JGitUtil.getDefaultBranch(git, forkedRepository).map {
|
JGitUtil.getDefaultBranch(git, forkedRepository).map {
|
||||||
case (_, defaultBranch) =>
|
case (_, defaultBranch) =>
|
||||||
@@ -427,41 +407,48 @@ trait PullRequestsControllerBase extends ControllerBase {
|
|||||||
redirect(s"/${forkedRepository.owner}/${forkedRepository.name}")
|
redirect(s"/${forkedRepository.owner}/${forkedRepository.name}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
private def getOriginRepositoryName(
|
||||||
|
originOwner: String,
|
||||||
|
forkedOwner: String,
|
||||||
|
forkedRepository: RepositoryInfo
|
||||||
|
): Option[String] = {
|
||||||
|
if (originOwner == forkedOwner) {
|
||||||
|
// Self repository
|
||||||
|
Some(forkedRepository.name)
|
||||||
|
} else if (forkedRepository.repository.originUserName.isEmpty) {
|
||||||
|
// when ForkedRepository is the original repository
|
||||||
|
getForkedRepositories(forkedRepository.owner, forkedRepository.name)
|
||||||
|
.find(_.userName == originOwner)
|
||||||
|
.map(_.repositoryName)
|
||||||
|
} else if (Some(originOwner) == forkedRepository.repository.originUserName) {
|
||||||
|
// Original repository
|
||||||
|
forkedRepository.repository.originRepositoryName
|
||||||
|
} else {
|
||||||
|
// Sibling repository
|
||||||
|
getUserRepositories(originOwner)
|
||||||
|
.find { x =>
|
||||||
|
x.repository.originUserName == forkedRepository.repository.originUserName &&
|
||||||
|
x.repository.originRepositoryName == forkedRepository.repository.originRepositoryName
|
||||||
|
}
|
||||||
|
.map(_.repository.repositoryName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
get("/:owner/:repository/compare/*...*")(referrersOnly { forkedRepository =>
|
get("/:owner/:repository/compare/*...*")(referrersOnly { forkedRepository =>
|
||||||
val Seq(origin, forked) = multiParams("splat")
|
val Seq(origin, forked) = multiParams("splat")
|
||||||
val (originOwner, originId) = parseCompareIdentifier(origin, forkedRepository.owner)
|
val (originOwner, originId) = parseCompareIdentifier(origin, forkedRepository.owner)
|
||||||
val (forkedOwner, forkedId) = parseCompareIdentifier(forked, forkedRepository.owner)
|
val (forkedOwner, forkedId) = parseCompareIdentifier(forked, forkedRepository.owner)
|
||||||
|
|
||||||
(for (originRepositoryName <- if (originOwner == forkedOwner) {
|
(for (originRepositoryName <- getOriginRepositoryName(originOwner, forkedOwner, forkedRepository);
|
||||||
// Self repository
|
|
||||||
Some(forkedRepository.name)
|
|
||||||
} else if (forkedRepository.repository.originUserName.isEmpty) {
|
|
||||||
// when ForkedRepository is the original repository
|
|
||||||
getForkedRepositories(forkedRepository.owner, forkedRepository.name)
|
|
||||||
.find(_.userName == originOwner)
|
|
||||||
.map(_.repositoryName)
|
|
||||||
} else if (Some(originOwner) == forkedRepository.repository.originUserName) {
|
|
||||||
// Original repository
|
|
||||||
forkedRepository.repository.originRepositoryName
|
|
||||||
} else {
|
|
||||||
// Sibling repository
|
|
||||||
getUserRepositories(originOwner)
|
|
||||||
.find { x =>
|
|
||||||
x.repository.originUserName == forkedRepository.repository.originUserName &&
|
|
||||||
x.repository.originRepositoryName == forkedRepository.repository.originRepositoryName
|
|
||||||
}
|
|
||||||
.map(_.repository.repositoryName)
|
|
||||||
};
|
|
||||||
originRepository <- getRepository(originOwner, originRepositoryName)) yield {
|
originRepository <- getRepository(originOwner, originRepositoryName)) yield {
|
||||||
val (oldId, newId) =
|
val (oldId, newId) =
|
||||||
getPullRequestCommitFromTo(originRepository, forkedRepository, originId, forkedId)
|
getPullRequestCommitFromTo(originRepository, forkedRepository, originId, forkedId)
|
||||||
|
|
||||||
(oldId, newId) match {
|
(oldId, newId) match {
|
||||||
case (Some(oldId), Some(newId)) => {
|
case (Some(oldId), Some(newId)) =>
|
||||||
val (commits, diffs) = getRequestCompareInfo(
|
val (commits, diffs) = getRequestCompareInfo(
|
||||||
originRepository.owner,
|
originRepository.owner,
|
||||||
originRepository.name,
|
originRepository.name,
|
||||||
@@ -512,7 +499,6 @@ trait PullRequestsControllerBase extends ControllerBase {
|
|||||||
getLabels(originRepository.owner, originRepository.name),
|
getLabels(originRepository.owner, originRepository.name),
|
||||||
getCustomFields(originRepository.owner, originRepository.name).filter(_.enableForPullRequests)
|
getCustomFields(originRepository.owner, originRepository.name).filter(_.enableForPullRequests)
|
||||||
)
|
)
|
||||||
}
|
|
||||||
case (oldId, newId) =>
|
case (oldId, newId) =>
|
||||||
redirect(
|
redirect(
|
||||||
s"/${forkedRepository.owner}/${forkedRepository.name}/compare/" +
|
s"/${forkedRepository.owner}/${forkedRepository.name}/compare/" +
|
||||||
@@ -524,6 +510,54 @@ trait PullRequestsControllerBase extends ControllerBase {
|
|||||||
}) getOrElse NotFound()
|
}) getOrElse NotFound()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
ajaxGet("/:owner/:repository/diff/:id")(referrersOnly { repository =>
|
||||||
|
(for {
|
||||||
|
commitId <- params.get("id")
|
||||||
|
path <- params.get("path")
|
||||||
|
diff <- getSingleDiff(repository.owner, repository.name, commitId, path)
|
||||||
|
} yield {
|
||||||
|
contentType = formats("json")
|
||||||
|
org.json4s.jackson.Serialization.write(
|
||||||
|
Map(
|
||||||
|
"oldContent" -> diff.oldContent,
|
||||||
|
"newContent" -> diff.newContent
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}) getOrElse NotFound()
|
||||||
|
})
|
||||||
|
|
||||||
|
ajaxGet("/:owner/:repository/diff/*...*")(referrersOnly { forkedRepository =>
|
||||||
|
val Seq(origin, forked) = multiParams("splat")
|
||||||
|
val (originOwner, originId) = parseCompareIdentifier(origin, forkedRepository.owner)
|
||||||
|
val (forkedOwner, forkedId) = parseCompareIdentifier(forked, forkedRepository.owner)
|
||||||
|
|
||||||
|
(for {
|
||||||
|
path <- params.get("path")
|
||||||
|
originRepositoryName <- getOriginRepositoryName(originOwner, forkedOwner, forkedRepository)
|
||||||
|
originRepository <- getRepository(originOwner, originRepositoryName)
|
||||||
|
(oldId, newId) = getPullRequestCommitFromTo(originRepository, forkedRepository, originId, forkedId)
|
||||||
|
oldId <- oldId
|
||||||
|
newId <- newId
|
||||||
|
diff <- getSingleDiff(
|
||||||
|
originRepository.owner,
|
||||||
|
originRepository.name,
|
||||||
|
oldId.getName,
|
||||||
|
forkedRepository.owner,
|
||||||
|
forkedRepository.name,
|
||||||
|
newId.getName,
|
||||||
|
path
|
||||||
|
)
|
||||||
|
} yield {
|
||||||
|
contentType = formats("json")
|
||||||
|
org.json4s.jackson.Serialization.write(
|
||||||
|
Map(
|
||||||
|
"oldContent" -> diff.oldContent,
|
||||||
|
"newContent" -> diff.newContent
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}) getOrElse NotFound()
|
||||||
|
})
|
||||||
|
|
||||||
ajaxGet("/:owner/:repository/compare/*...*/mergecheck")(readableUsersOnly { forkedRepository =>
|
ajaxGet("/:owner/:repository/compare/*...*/mergecheck")(readableUsersOnly { forkedRepository =>
|
||||||
val Seq(origin, forked) = multiParams("splat")
|
val Seq(origin, forked) = multiParams("splat")
|
||||||
val (originOwner, tmpOriginBranch) = parseCompareIdentifier(origin, forkedRepository.owner)
|
val (originOwner, tmpOriginBranch) = parseCompareIdentifier(origin, forkedRepository.owner)
|
||||||
@@ -593,7 +627,7 @@ trait PullRequestsControllerBase extends ControllerBase {
|
|||||||
|
|
||||||
if (manageable) {
|
if (manageable) {
|
||||||
// insert assignees
|
// insert assignees
|
||||||
form.assignedUserNames.foreach { value =>
|
form.assigneeUserNames.foreach { value =>
|
||||||
value.split(",").foreach { userName =>
|
value.split(",").foreach { userName =>
|
||||||
registerIssueAssignee(repository.owner, repository.name, issueId, userName)
|
registerIssueAssignee(repository.owner, repository.name, issueId, userName)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -331,15 +331,12 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
|||||||
post("/:owner/:repository/upload", uploadForm)(writableUsersOnly { (form, repository) =>
|
post("/:owner/:repository/upload", uploadForm)(writableUsersOnly { (form, repository) =>
|
||||||
def _commit(
|
def _commit(
|
||||||
branchName: String,
|
branchName: String,
|
||||||
//files: Seq[CommitFile],
|
|
||||||
newFiles: Seq[CommitFile],
|
newFiles: Seq[CommitFile],
|
||||||
loginAccount: Account
|
loginAccount: Account
|
||||||
): Either[String, ObjectId] = {
|
): Either[String, ObjectId] = {
|
||||||
commitFiles(
|
commitFiles(
|
||||||
repository = repository,
|
repository = repository,
|
||||||
branch = branchName,
|
branch = branchName,
|
||||||
//path = form.path,
|
|
||||||
//files = files.toIndexedSeq,
|
|
||||||
message = form.message.getOrElse("Add files via upload"),
|
message = form.message.getOrElse("Add files via upload"),
|
||||||
loginAccount = loginAccount,
|
loginAccount = loginAccount,
|
||||||
settings = context.settings
|
settings = context.settings
|
||||||
@@ -614,7 +611,7 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
|||||||
} else {
|
} else {
|
||||||
_commit(form.branch, loginAccount) match {
|
_commit(form.branch, loginAccount) match {
|
||||||
case Right(_) =>
|
case Right(_) =>
|
||||||
if (form.path.length == 0) {
|
if (form.path.isEmpty) {
|
||||||
redirect(s"/${repository.owner}/${repository.name}/tree/${encodeRefName(form.branch)}")
|
redirect(s"/${repository.owner}/${repository.name}/tree/${encodeRefName(form.branch)}")
|
||||||
} else {
|
} else {
|
||||||
redirect(
|
redirect(
|
||||||
|
|||||||
@@ -242,14 +242,17 @@ trait IssuesService {
|
|||||||
case (issue, commentCount, _, _, _, milestone, priority, commitId, _) =>
|
case (issue, commentCount, _, _, _, milestone, priority, commitId, _) =>
|
||||||
IssueInfo(
|
IssueInfo(
|
||||||
issue,
|
issue,
|
||||||
issues.flatMap { t =>
|
issues
|
||||||
t._3.map(Label(issue.userName, issue.repositoryName, _, t._4.get, t._5.get))
|
.flatMap { t =>
|
||||||
} toList,
|
t._3.map(Label(issue.userName, issue.repositoryName, _, t._4.get, t._5.get))
|
||||||
|
}
|
||||||
|
.distinct
|
||||||
|
.toList,
|
||||||
milestone,
|
milestone,
|
||||||
priority,
|
priority,
|
||||||
commentCount,
|
commentCount,
|
||||||
commitId,
|
commitId,
|
||||||
issues.flatMap(_._9)
|
issues.flatMap(_._9).distinct
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} toList
|
} toList
|
||||||
|
|||||||
@@ -472,6 +472,40 @@ trait PullRequestService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def getSingleDiff(
|
||||||
|
userName: String,
|
||||||
|
repositoryName: String,
|
||||||
|
commitId: String,
|
||||||
|
path: String
|
||||||
|
): Option[DiffInfo] = {
|
||||||
|
Using.resource(
|
||||||
|
Git.open(getRepositoryDir(userName, repositoryName))
|
||||||
|
) { git =>
|
||||||
|
val newId = git.getRepository.resolve(commitId)
|
||||||
|
JGitUtil.getDiff(git, None, newId.getName, path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def getSingleDiff(
|
||||||
|
userName: String,
|
||||||
|
repositoryName: String,
|
||||||
|
branch: String,
|
||||||
|
requestUserName: String,
|
||||||
|
requestRepositoryName: String,
|
||||||
|
requestCommitId: String,
|
||||||
|
path: String
|
||||||
|
): Option[DiffInfo] = {
|
||||||
|
Using.resources(
|
||||||
|
Git.open(getRepositoryDir(userName, repositoryName)),
|
||||||
|
Git.open(getRepositoryDir(requestUserName, requestRepositoryName))
|
||||||
|
) { (oldGit, newGit) =>
|
||||||
|
val oldId = oldGit.getRepository.resolve(branch)
|
||||||
|
val newId = newGit.getRepository.resolve(requestCommitId)
|
||||||
|
|
||||||
|
JGitUtil.getDiff(newGit, Some(oldId.getName), newId.getName, path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def getRequestCompareInfo(
|
def getRequestCompareInfo(
|
||||||
userName: String,
|
userName: String,
|
||||||
repositoryName: String,
|
repositoryName: String,
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ object JGitUtil {
|
|||||||
|
|
||||||
private val logger = LoggerFactory.getLogger(JGitUtil.getClass)
|
private val logger = LoggerFactory.getLogger(JGitUtil.getClass)
|
||||||
|
|
||||||
implicit val objectDatabaseReleasable: Releasable[ObjectDatabase] =
|
private implicit val objectDatabaseReleasable: Releasable[ObjectDatabase] =
|
||||||
_.close()
|
_.close()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -690,7 +690,7 @@ object JGitUtil {
|
|||||||
|
|
||||||
val toCommit = revWalk.parseCommit(git.getRepository.resolve(to))
|
val toCommit = revWalk.parseCommit(git.getRepository.resolve(to))
|
||||||
(from match {
|
(from match {
|
||||||
case None => {
|
case None =>
|
||||||
toCommit.getParentCount match {
|
toCommit.getParentCount match {
|
||||||
case 0 =>
|
case 0 =>
|
||||||
df.scan(
|
df.scan(
|
||||||
@@ -700,11 +700,9 @@ object JGitUtil {
|
|||||||
.asScala
|
.asScala
|
||||||
case _ => df.scan(toCommit.getParent(0), toCommit.getTree).asScala
|
case _ => df.scan(toCommit.getParent(0), toCommit.getTree).asScala
|
||||||
}
|
}
|
||||||
}
|
case Some(from) =>
|
||||||
case Some(from) => {
|
|
||||||
val fromCommit = revWalk.parseCommit(git.getRepository.resolve(from))
|
val fromCommit = revWalk.parseCommit(git.getRepository.resolve(from))
|
||||||
df.scan(fromCommit.getTree, toCommit.getTree).asScala
|
df.scan(fromCommit.getTree, toCommit.getTree).asScala
|
||||||
}
|
|
||||||
}).toSeq
|
}).toSeq
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -719,6 +717,29 @@ object JGitUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def getDiff(git: Git, from: Option[String], to: String, path: String): Option[DiffInfo] = {
|
||||||
|
getDiffEntries(git, from, to).find(_.getNewPath == path).map { diff =>
|
||||||
|
val oldIsImage = FileUtil.isImage(diff.getOldPath)
|
||||||
|
val newIsImage = FileUtil.isImage(diff.getNewPath)
|
||||||
|
val includeContent = oldIsImage || newIsImage
|
||||||
|
DiffInfo(
|
||||||
|
changeType = diff.getChangeType,
|
||||||
|
oldPath = diff.getOldPath,
|
||||||
|
newPath = diff.getNewPath,
|
||||||
|
oldContent = if (includeContent) None else getTextContent(git, diff.getOldId.toObjectId),
|
||||||
|
newContent = if (includeContent) None else getTextContent(git, diff.getNewId.toObjectId),
|
||||||
|
oldIsImage = oldIsImage,
|
||||||
|
newIsImage = newIsImage,
|
||||||
|
oldObjectId = Option(diff.getOldId).map(_.name),
|
||||||
|
newObjectId = Option(diff.getNewId).map(_.name),
|
||||||
|
oldMode = diff.getOldMode.toString,
|
||||||
|
newMode = diff.getNewMode.toString,
|
||||||
|
tooLarge = false,
|
||||||
|
patch = None
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def getDiffs(
|
def getDiffs(
|
||||||
git: Git,
|
git: Git,
|
||||||
from: Option[String],
|
from: Option[String],
|
||||||
@@ -728,7 +749,7 @@ object JGitUtil {
|
|||||||
): List[DiffInfo] = {
|
): List[DiffInfo] = {
|
||||||
val diffs = getDiffEntries(git, from, to)
|
val diffs = getDiffEntries(git, from, to)
|
||||||
diffs.map { diff =>
|
diffs.map { diff =>
|
||||||
if (diffs.size > 100) {
|
if (diffs.size > 100) { // Don't show diff if there are more than 100 files
|
||||||
DiffInfo(
|
DiffInfo(
|
||||||
changeType = diff.getChangeType,
|
changeType = diff.getChangeType,
|
||||||
oldPath = diff.getOldPath,
|
oldPath = diff.getOldPath,
|
||||||
@@ -747,49 +768,35 @@ object JGitUtil {
|
|||||||
} else {
|
} else {
|
||||||
val oldIsImage = FileUtil.isImage(diff.getOldPath)
|
val oldIsImage = FileUtil.isImage(diff.getOldPath)
|
||||||
val newIsImage = FileUtil.isImage(diff.getNewPath)
|
val newIsImage = FileUtil.isImage(diff.getNewPath)
|
||||||
if (!fetchContent || oldIsImage || newIsImage) {
|
val patch = if (oldIsImage || newIsImage) None else Some(makePatchFromDiffEntry(git, diff)) // TODO use DiffFormatter
|
||||||
DiffInfo(
|
val tooLarge = patch.exists(_.count(_ == '\n') > 1000) // Don't show diff if the file has more than 1000 lines diff
|
||||||
changeType = diff.getChangeType,
|
val includeContent = tooLarge || !fetchContent || oldIsImage || newIsImage
|
||||||
oldPath = diff.getOldPath,
|
DiffInfo(
|
||||||
newPath = diff.getNewPath,
|
changeType = diff.getChangeType,
|
||||||
oldContent = None,
|
oldPath = diff.getOldPath,
|
||||||
newContent = None,
|
newPath = diff.getNewPath,
|
||||||
oldIsImage = oldIsImage,
|
oldContent = if (includeContent) None else getTextContent(git, diff.getOldId.toObjectId),
|
||||||
newIsImage = newIsImage,
|
newContent = if (includeContent) None else getTextContent(git, diff.getNewId.toObjectId),
|
||||||
oldObjectId = Option(diff.getOldId).map(_.name),
|
oldIsImage = oldIsImage,
|
||||||
newObjectId = Option(diff.getNewId).map(_.name),
|
newIsImage = newIsImage,
|
||||||
oldMode = diff.getOldMode.toString,
|
oldObjectId = Option(diff.getOldId).map(_.name),
|
||||||
newMode = diff.getNewMode.toString,
|
newObjectId = Option(diff.getNewId).map(_.name),
|
||||||
tooLarge = false,
|
oldMode = diff.getOldMode.toString,
|
||||||
patch = (if (makePatch) Some(makePatchFromDiffEntry(git, diff)) else None) // TODO use DiffFormatter
|
newMode = diff.getNewMode.toString,
|
||||||
)
|
tooLarge = tooLarge,
|
||||||
} else {
|
patch = if (makePatch) patch else None
|
||||||
DiffInfo(
|
)
|
||||||
changeType = diff.getChangeType,
|
|
||||||
oldPath = diff.getOldPath,
|
|
||||||
newPath = diff.getNewPath,
|
|
||||||
oldContent = JGitUtil
|
|
||||||
.getContentFromId(git, diff.getOldId.toObjectId, false)
|
|
||||||
.filter(FileUtil.isText)
|
|
||||||
.map(convertFromByteArray),
|
|
||||||
newContent = JGitUtil
|
|
||||||
.getContentFromId(git, diff.getNewId.toObjectId, false)
|
|
||||||
.filter(FileUtil.isText)
|
|
||||||
.map(convertFromByteArray),
|
|
||||||
oldIsImage = oldIsImage,
|
|
||||||
newIsImage = newIsImage,
|
|
||||||
oldObjectId = Option(diff.getOldId).map(_.name),
|
|
||||||
newObjectId = Option(diff.getNewId).map(_.name),
|
|
||||||
oldMode = diff.getOldMode.toString,
|
|
||||||
newMode = diff.getNewMode.toString,
|
|
||||||
tooLarge = false,
|
|
||||||
patch = (if (makePatch) Some(makePatchFromDiffEntry(git, diff)) else None) // TODO use DiffFormatter
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}.toList
|
}.toList
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private def getTextContent(git: Git, objectId: ObjectId): Option[String] = {
|
||||||
|
JGitUtil
|
||||||
|
.getContentFromId(git, objectId, false)
|
||||||
|
.filter(FileUtil.isText)
|
||||||
|
.map(convertFromByteArray)
|
||||||
|
}
|
||||||
|
|
||||||
private def makePatchFromDiffEntry(git: Git, diff: DiffEntry): String = {
|
private def makePatchFromDiffEntry(git: Git, diff: DiffEntry): String = {
|
||||||
val out = new ByteArrayOutputStream()
|
val out = new ByteArrayOutputStream()
|
||||||
Using.resource(new DiffFormatter(out)) { formatter =>
|
Using.resource(new DiffFormatter(out)) { formatter =>
|
||||||
|
|||||||
@@ -100,38 +100,48 @@
|
|||||||
</tr>
|
</tr>
|
||||||
<tr class="diff-collapse-@i collapse in">
|
<tr class="diff-collapse-@i collapse in">
|
||||||
<td style="padding: 0;">
|
<td style="padding: 0;">
|
||||||
@if(diff.oldObjectId == diff.newObjectId){
|
@if(diff.tooLarge) {
|
||||||
@if(diff.oldPath != diff.newPath){
|
<div style="padding: 12px;" id="show-diff-@i">
|
||||||
<div class="diff-same">File renamed without changes</div>
|
@if(oldCommitId.isEmpty && newCommitId.isDefined) {
|
||||||
} else {
|
Too large (<a href="javascript:showDiff(@i, '', '@newCommitId', '@diff.newPath')">Show diff</a>)
|
||||||
<div class="diff-same">File mode changed</div>
|
}
|
||||||
}
|
@if(oldCommitId.isDefined && newCommitId.isDefined) {
|
||||||
|
Too large (<a href="javascript:showDiff(@i, '@oldCommitId', '@newCommitId', '@diff.newPath')">Show diff</a>)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<div id="diffText-@i" class="diffText"></div>
|
||||||
|
<input type="hidden" id="newText-@i" data-file-name="@diff.newPath" data-val="">
|
||||||
|
<input type="hidden" id="oldText-@i" data-file-name="@diff.oldPath" data-val="">
|
||||||
} else {
|
} else {
|
||||||
@if(diff.newContent != None || diff.oldContent != None){
|
@if(diff.oldObjectId == diff.newObjectId) {
|
||||||
<div id="diffText-@i" class="diffText"></div>
|
@if(diff.oldPath != diff.newPath) {
|
||||||
<input type="hidden" id="newText-@i" data-file-name="@diff.newPath" data-val="@diff.newContent">
|
<div class="diff-same">File renamed without changes</div>
|
||||||
<input type="hidden" id="oldText-@i" data-file-name="@diff.oldPath" data-val="@diff.oldContent">
|
|
||||||
} else {
|
|
||||||
@if(diff.newIsImage || diff.oldIsImage){
|
|
||||||
<div class="diff-image-render diff2up">
|
|
||||||
@if(oldCommitId.isDefined && diff.oldIsImage){
|
|
||||||
<div class="diff-image-frame diff-old"><img src="@helpers.url(repository)/raw/@oldCommitId.get/@diff.oldPath" class="diff-image" onload="onLoadedDiffImages(this)" style="display:none" /></div>
|
|
||||||
} else {
|
|
||||||
@if(diff.changeType != ChangeType.ADD){
|
|
||||||
<div style="padding: 12px;">Not supported</div>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@if(newCommitId.isDefined && diff.newIsImage){
|
|
||||||
<div class="diff-image-frame diff-new"><img src="@helpers.url(repository)/raw/@newCommitId.get/@diff.newPath" class="diff-image" onload="onLoadedDiffImages(this)" style="display:none" /></div>
|
|
||||||
} else {
|
|
||||||
@if(diff.changeType != ChangeType.DELETE){
|
|
||||||
<div style="padding: 12px;">Not supported</div>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
} else {
|
} else {
|
||||||
@if(diff.tooLarge){
|
<div class="diff-same">File mode changed</div>
|
||||||
<div style="padding: 12px;">Too large</div>
|
}
|
||||||
|
} else {
|
||||||
|
@if(diff.newContent != None || diff.oldContent != None){
|
||||||
|
<div id="diffText-@i" class="diffText"></div>
|
||||||
|
<input type="hidden" id="newText-@i" data-file-name="@diff.newPath" data-val="@diff.newContent">
|
||||||
|
<input type="hidden" id="oldText-@i" data-file-name="@diff.oldPath" data-val="@diff.oldContent">
|
||||||
|
} else {
|
||||||
|
@if(diff.newIsImage || diff.oldIsImage){
|
||||||
|
<div class="diff-image-render diff2up">
|
||||||
|
@if(oldCommitId.isDefined && diff.oldIsImage){
|
||||||
|
<div class="diff-image-frame diff-old"><img src="@helpers.url(repository)/raw/@oldCommitId.get/@diff.oldPath" class="diff-image" onload="onLoadedDiffImages(this)" style="display:none" /></div>
|
||||||
|
} else {
|
||||||
|
@if(diff.changeType != ChangeType.ADD){
|
||||||
|
<div style="padding: 12px;">Not supported</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@if(newCommitId.isDefined && diff.newIsImage){
|
||||||
|
<div class="diff-image-frame diff-new"><img src="@helpers.url(repository)/raw/@newCommitId.get/@diff.newPath" class="diff-image" onload="onLoadedDiffImages(this)" style="display:none" /></div>
|
||||||
|
} else {
|
||||||
|
@if(diff.changeType != ChangeType.DELETE){
|
||||||
|
<div style="padding: 12px;">Not supported</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</div>
|
||||||
} else {
|
} else {
|
||||||
<div style="padding: 12px;">Not supported</div>
|
<div style="padding: 12px;">Not supported</div>
|
||||||
}
|
}
|
||||||
@@ -200,53 +210,10 @@ $(function(){
|
|||||||
renderOneDiff($(this).closest("table").find(".diffText"), window.viewType, $(this).closest("table").find(".file-hash")[0].id);
|
renderOneDiff($(this).closest("table").find(".diffText"), window.viewType, $(this).closest("table").find(".file-hash")[0].id);
|
||||||
});
|
});
|
||||||
|
|
||||||
function getInlineContainer(where) {
|
|
||||||
if (window.viewType == 0) {
|
|
||||||
if (where === 'new') {
|
|
||||||
return $('<tr class="not-diff"><td colspan="2"></td><td colspan="2" class="comment-box-container"></td></tr>');
|
|
||||||
} else {
|
|
||||||
return $('<tr class="not-diff"><td colspan="2" class="comment-box-container"></td><td colspan="2"></td></tr>');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $('<tr class="not-diff"><td colspan="3" class="comment-box-container"></td></tr>');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof $('#show-notes')[0] !== 'undefined' && !$('#show-notes')[0].checked) {
|
if (typeof $('#show-notes')[0] !== 'undefined' && !$('#show-notes')[0].checked) {
|
||||||
$('#comment-list').children('.inline-comment').hide();
|
$('#comment-list').children('.inline-comment').hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
function showCommentForm(commitId, fileName, oldLineNumber, newLineNumber, $tr){
|
|
||||||
// assemble Ajax url
|
|
||||||
let url = '@helpers.url(repository)/commit/' + commitId + '/comment/_form?fileName=' + fileName@issueId.map { id => + '&issueId=@id' };
|
|
||||||
if (!isNaN(oldLineNumber) && oldLineNumber) {
|
|
||||||
url += ('&oldLineNumber=' + oldLineNumber)
|
|
||||||
}
|
|
||||||
if (!isNaN(newLineNumber) && newLineNumber) {
|
|
||||||
url += ('&newLineNumber=' + newLineNumber)
|
|
||||||
}
|
|
||||||
// send Ajax request
|
|
||||||
$.get(url, { dataType : 'html' }, function(responseContent) {
|
|
||||||
// create container
|
|
||||||
let tmp;
|
|
||||||
if (!isNaN(oldLineNumber) && oldLineNumber) {
|
|
||||||
if (!isNaN(newLineNumber) && newLineNumber) {
|
|
||||||
tmp = getInlineContainer();
|
|
||||||
} else {
|
|
||||||
tmp = getInlineContainer('old');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
tmp = getInlineContainer('new');
|
|
||||||
}
|
|
||||||
// add comment textarea
|
|
||||||
tmp.addClass('inline-comment-form').children('.comment-box-container').html(responseContent);
|
|
||||||
$tr.nextAll(':not(.not-diff):first').before(tmp);
|
|
||||||
// hide reply comment field
|
|
||||||
$(tmp).closest('.not-diff').prev().find('.reply-comment').closest('.not-diff').hide();
|
|
||||||
// focus textarea
|
|
||||||
tmp.find('textarea').focus();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add comment button
|
// Add comment button
|
||||||
$('.diff-outside').on('click','table.diff .add-comment',function() {
|
$('.diff-outside').on('click','table.diff .add-comment',function() {
|
||||||
const $this = $(this);
|
const $this = $(this);
|
||||||
@@ -302,11 +269,156 @@ $(function(){
|
|||||||
getSelection().empty();
|
getSelection().empty();
|
||||||
updateHighlighting();
|
updateHighlighting();
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function getInlineContainer(where) {
|
||||||
|
if (window.viewType == 0) {
|
||||||
|
if (where === 'new') {
|
||||||
|
return $('<tr class="not-diff"><td colspan="2"></td><td colspan="2" class="comment-box-container"></td></tr>');
|
||||||
|
} else {
|
||||||
|
return $('<tr class="not-diff"><td colspan="2" class="comment-box-container"></td><td colspan="2"></td></tr>');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $('<tr class="not-diff"><td colspan="3" class="comment-box-container"></td></tr>');
|
||||||
|
}
|
||||||
|
|
||||||
|
function showCommentForm(commitId, fileName, oldLineNumber, newLineNumber, $tr){
|
||||||
|
// assemble Ajax url
|
||||||
|
let url = '@helpers.url(repository)/commit/' + commitId + '/comment/_form?fileName=' + fileName@issueId.map { id => + '&issueId=@id' };
|
||||||
|
if (!isNaN(oldLineNumber) && oldLineNumber) {
|
||||||
|
url += ('&oldLineNumber=' + oldLineNumber)
|
||||||
|
}
|
||||||
|
if (!isNaN(newLineNumber) && newLineNumber) {
|
||||||
|
url += ('&newLineNumber=' + newLineNumber)
|
||||||
|
}
|
||||||
|
// send Ajax request
|
||||||
|
$.get(url, { dataType : 'html' }, function(responseContent) {
|
||||||
|
// create container
|
||||||
|
let tmp;
|
||||||
|
if (!isNaN(oldLineNumber) && oldLineNumber) {
|
||||||
|
if (!isNaN(newLineNumber) && newLineNumber) {
|
||||||
|
tmp = getInlineContainer();
|
||||||
|
} else {
|
||||||
|
tmp = getInlineContainer('old');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tmp = getInlineContainer('new');
|
||||||
|
}
|
||||||
|
// add comment textarea
|
||||||
|
tmp.addClass('inline-comment-form').children('.comment-box-container').html(responseContent);
|
||||||
|
$tr.nextAll(':not(.not-diff):first').before(tmp);
|
||||||
|
// hide reply comment field
|
||||||
|
$(tmp).closest('.not-diff').prev().find('.reply-comment').closest('.not-diff').hide();
|
||||||
|
// focus textarea
|
||||||
|
tmp.find('textarea').focus();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderOneCommitCommentIntoDiff($v, diff){
|
||||||
|
//var filename = $v.attr('filename');
|
||||||
|
const oldline = $v.attr('oldline');
|
||||||
|
const newline = $v.attr('newline');
|
||||||
|
let tmp;
|
||||||
|
if (typeof oldline !== 'undefined') {
|
||||||
|
if (typeof newline !== 'undefined') {
|
||||||
|
tmp = getInlineContainer();
|
||||||
|
} else {
|
||||||
|
tmp = getInlineContainer('old');
|
||||||
|
}
|
||||||
|
tmp.children('td:first').html($v.clone().show());
|
||||||
|
diff.find('table.diff').find('.oldline[line-number=' + oldline + ']').parent().nextAll(':not(.not-diff):first').before(tmp);
|
||||||
|
} else {
|
||||||
|
tmp = getInlineContainer('new');
|
||||||
|
tmp.children('td:last').html($v.clone().show());
|
||||||
|
diff.find('table.diff').find('.newline[line-number=' + newline + ']').parent().nextAll(':not(.not-diff):first').before(tmp);
|
||||||
|
}
|
||||||
|
if (!diff.find('.toggle-notes').prop('checked')) {
|
||||||
|
tmp.hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderStatBar(add, del){
|
||||||
|
if(add + del > 5){
|
||||||
|
if(add){
|
||||||
|
if(add < del){
|
||||||
|
add = Math.floor(1 + (add * 4 / (add + del)));
|
||||||
|
} else {
|
||||||
|
add = Math.ceil(1 + (add * 4 / (add + del)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
del = 5 - add;
|
||||||
|
}
|
||||||
|
const ret = $('<div class="diffstat-bar">');
|
||||||
|
for(let i = 0; i < 5; i++){
|
||||||
|
if(add){
|
||||||
|
ret.append('<span class="text-diff-added">■</span>');
|
||||||
|
add--;
|
||||||
|
} else if(del){
|
||||||
|
ret.append('<span class="text-diff-deleted">■</span>');
|
||||||
|
del--;
|
||||||
|
} else {
|
||||||
|
ret.append('■');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderOneDiff(diffText, viewType, fileHash){
|
||||||
|
const table = diffText.closest("table[data-diff-id]");
|
||||||
|
const i = table.data("diff-id");
|
||||||
|
const ignoreWhiteSpace = table.find('.ignore-whitespace').prop('checked');
|
||||||
|
diffUsingJS('oldText-' + i, 'newText-' + i, diffText.attr('id'), viewType, ignoreWhiteSpace, fileHash);
|
||||||
|
const add = diffText.find("table").attr("add") * 1;
|
||||||
|
const del = diffText.find("table").attr("del") * 1;
|
||||||
|
table.find(".diffstat").text(add + del + " ").append(renderStatBar(add, del)).attr("title", add + " additions & " + del + " deletions").tooltip();
|
||||||
|
$('span.diffstat[data-diff-id="' + i + '"]')
|
||||||
|
.html('<span class="text-diff-added">+' + add + '</span><span class="text-diff-deleted">-' + del + '</span>')
|
||||||
|
.append(renderStatBar(add, del).attr('title', (add + del) + " lines changed").tooltip());
|
||||||
|
|
||||||
|
@if(hasWritePermission) {
|
||||||
|
diffText.find('.body').filter(function(i, e) {
|
||||||
|
return $(e).has('span').length > 0;
|
||||||
|
}).each(function(){
|
||||||
|
$('<b class="add-comment">+</b>').prependTo(this);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@if(showLineNotes){
|
||||||
|
const fileName = table.attr('filename');
|
||||||
|
$('.inline-comment').each(function(i, v) {
|
||||||
|
if($(this).attr('filename') == fileName){
|
||||||
|
renderOneCommitCommentIntoDiff($(this), table);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return table;
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderReplyComment($table){
|
||||||
|
const elements = {};
|
||||||
|
let filename, newline, oldline;
|
||||||
|
$table.find('.comment-box-container .inline-comment').each(function(i, e){
|
||||||
|
filename = $(e).attr('filename');
|
||||||
|
newline = $(e).attr('newline');
|
||||||
|
oldline = $(e).attr('oldline');
|
||||||
|
const key = filename + '-' + newline + '-' + oldline;
|
||||||
|
elements[key] = {
|
||||||
|
element: $(e),
|
||||||
|
filename: filename,
|
||||||
|
newline: newline,
|
||||||
|
oldline: oldline
|
||||||
|
};
|
||||||
|
});
|
||||||
|
for(const key in elements){
|
||||||
|
filename = elements[key]['filename'];
|
||||||
|
oldline = elements[key]['oldline']; //? elements[key]['oldline'] : '';
|
||||||
|
newline = elements[key]['newline']; //? elements[key]['newline'] : '';
|
||||||
|
|
||||||
|
const $v = $('<div class="commit-comment-box reply-comment-box">')
|
||||||
|
.append($('<input type="text" class="form-control reply-comment" placeholder="Reply..." '
|
||||||
|
+ 'data-filename="' + filename + '" '
|
||||||
|
+ 'data-newline="' + newline + '" '
|
||||||
|
+ 'data-oldline="' + oldline + '">'));
|
||||||
|
|
||||||
function renderOneCommitCommentIntoDiff($v, diff){
|
|
||||||
//var filename = $v.attr('filename');
|
|
||||||
const oldline = $v.attr('oldline');
|
|
||||||
const newline = $v.attr('newline');
|
|
||||||
let tmp;
|
let tmp;
|
||||||
if (typeof oldline !== 'undefined') {
|
if (typeof oldline !== 'undefined') {
|
||||||
if (typeof newline !== 'undefined') {
|
if (typeof newline !== 'undefined') {
|
||||||
@@ -314,134 +426,51 @@ $(function(){
|
|||||||
} else {
|
} else {
|
||||||
tmp = getInlineContainer('old');
|
tmp = getInlineContainer('old');
|
||||||
}
|
}
|
||||||
tmp.children('td:first').html($v.clone().show());
|
tmp.children('td:first').html($v);
|
||||||
diff.find('table.diff').find('.oldline[line-number=' + oldline + ']').parent().nextAll(':not(.not-diff):first').before(tmp);
|
|
||||||
} else {
|
} else {
|
||||||
tmp = getInlineContainer('new');
|
tmp = getInlineContainer('new');
|
||||||
tmp.children('td:last').html($v.clone().show());
|
tmp.children('td:last').html($v);
|
||||||
diff.find('table.diff').find('.newline[line-number=' + newline + ']').parent().nextAll(':not(.not-diff):first').before(tmp);
|
|
||||||
}
|
|
||||||
if (!diff.find('.toggle-notes').prop('checked')) {
|
|
||||||
tmp.hide();
|
|
||||||
}
|
}
|
||||||
|
elements[key]['element'].closest('.not-diff').after(tmp);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function renderStatBar(add, del){
|
function renderDiffs() {
|
||||||
if(add + del > 5){
|
const diffs = $('.diffText');
|
||||||
if(add){
|
let i = 0;
|
||||||
if(add < del){
|
function render(){
|
||||||
add = Math.floor(1 + (add * 4 / (add + del)));
|
if (diffs[i]) {
|
||||||
} else {
|
const $table = renderOneDiff($(diffs[i]), window.viewType, $('.file-hash')[i].id);
|
||||||
add = Math.ceil(1 + (add * 4 / (add + del)));
|
@if(hasWritePermission) {
|
||||||
}
|
renderReplyComment($table);
|
||||||
}
|
}
|
||||||
del = 5 - add;
|
i++;
|
||||||
}
|
setTimeout(render);
|
||||||
const ret = $('<div class="diffstat-bar">');
|
} else {
|
||||||
for(let i = 0; i < 5; i++){
|
updateHighlighting();
|
||||||
if(add){
|
|
||||||
ret.append('<span class="text-diff-added">■</span>');
|
|
||||||
add--;
|
|
||||||
} else if(del){
|
|
||||||
ret.append('<span class="text-diff-deleted">■</span>');
|
|
||||||
del--;
|
|
||||||
} else {
|
|
||||||
ret.append('■');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderOneDiff(diffText, viewType, fileHash){
|
|
||||||
const table = diffText.closest("table[data-diff-id]");
|
|
||||||
const i = table.data("diff-id");
|
|
||||||
const ignoreWhiteSpace = table.find('.ignore-whitespace').prop('checked');
|
|
||||||
diffUsingJS('oldText-' + i, 'newText-' + i, diffText.attr('id'), viewType, ignoreWhiteSpace, fileHash);
|
|
||||||
const add = diffText.find("table").attr("add") * 1;
|
|
||||||
const del = diffText.find("table").attr("del") * 1;
|
|
||||||
table.find(".diffstat").text(add + del + " ").append(renderStatBar(add, del)).attr("title", add + " additions & " + del + " deletions").tooltip();
|
|
||||||
$('span.diffstat[data-diff-id="' + i + '"]')
|
|
||||||
.html('<span class="text-diff-added">+' + add + '</span><span class="text-diff-deleted">-' + del + '</span>')
|
|
||||||
.append(renderStatBar(add, del).attr('title', (add + del) + " lines changed").tooltip());
|
|
||||||
|
|
||||||
@if(hasWritePermission) {
|
|
||||||
diffText.find('.body').filter(function(i, e) {
|
|
||||||
return $(e).has('span').length > 0;
|
|
||||||
}).each(function(){
|
|
||||||
$('<b class="add-comment">+</b>').prependTo(this);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@if(showLineNotes){
|
|
||||||
const fileName = table.attr('filename');
|
|
||||||
$('.inline-comment').each(function(i, v) {
|
|
||||||
if($(this).attr('filename') == fileName){
|
|
||||||
renderOneCommitCommentIntoDiff($(this), table);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return table;
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderReplyComment($table){
|
|
||||||
const elements = {};
|
|
||||||
let filename, newline, oldline;
|
|
||||||
$table.find('.comment-box-container .inline-comment').each(function(i, e){
|
|
||||||
filename = $(e).attr('filename');
|
|
||||||
newline = $(e).attr('newline');
|
|
||||||
oldline = $(e).attr('oldline');
|
|
||||||
const key = filename + '-' + newline + '-' + oldline;
|
|
||||||
elements[key] = {
|
|
||||||
element: $(e),
|
|
||||||
filename: filename,
|
|
||||||
newline: newline,
|
|
||||||
oldline: oldline
|
|
||||||
};
|
|
||||||
});
|
|
||||||
for(const key in elements){
|
|
||||||
filename = elements[key]['filename'];
|
|
||||||
oldline = elements[key]['oldline']; //? elements[key]['oldline'] : '';
|
|
||||||
newline = elements[key]['newline']; //? elements[key]['newline'] : '';
|
|
||||||
|
|
||||||
const $v = $('<div class="commit-comment-box reply-comment-box">')
|
|
||||||
.append($('<input type="text" class="form-control reply-comment" placeholder="Reply..." '
|
|
||||||
+ 'data-filename="' + filename + '" '
|
|
||||||
+ 'data-newline="' + newline + '" '
|
|
||||||
+ 'data-oldline="' + oldline + '">'));
|
|
||||||
|
|
||||||
let tmp;
|
|
||||||
if (typeof oldline !== 'undefined') {
|
|
||||||
if (typeof newline !== 'undefined') {
|
|
||||||
tmp = getInlineContainer();
|
|
||||||
} else {
|
|
||||||
tmp = getInlineContainer('old');
|
|
||||||
}
|
|
||||||
tmp.children('td:first').html($v);
|
|
||||||
} else {
|
|
||||||
tmp = getInlineContainer('new');
|
|
||||||
tmp.children('td:last').html($v);
|
|
||||||
}
|
|
||||||
elements[key]['element'].closest('.not-diff').after(tmp);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
render();
|
||||||
|
}
|
||||||
|
|
||||||
function renderDiffs() {
|
function showDiff(index, fromId, toId, path){
|
||||||
|
let url = '@helpers.url(repository)/diff/';
|
||||||
|
if (fromId == '') {
|
||||||
|
url = url + encodeURIComponent(toId);
|
||||||
|
} else {
|
||||||
|
url = url + encodeURIComponent(fromId) + '...' + encodeURIComponent(toId);
|
||||||
|
}
|
||||||
|
$.get(url, { path : path }, function(data) {
|
||||||
|
$('#oldText-' + index).attr('data-val', data.oldContent);
|
||||||
|
$('#newText-' + index).attr('data-val', data.newContent);
|
||||||
const diffs = $('.diffText');
|
const diffs = $('.diffText');
|
||||||
let i = 0;
|
const $table = renderOneDiff($(diffs[index]), window.viewType, $('.file-hash')[index].id);
|
||||||
function render(){
|
@if(hasWritePermission) {
|
||||||
if (diffs[i]) {
|
renderReplyComment($table);
|
||||||
const $table = renderOneDiff($(diffs[i]), window.viewType, $('.file-hash')[i].id);
|
|
||||||
@if(hasWritePermission) {
|
|
||||||
renderReplyComment($table);
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
setTimeout(render);
|
|
||||||
} else {
|
|
||||||
updateHighlighting();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
render();
|
$('#show-diff-' + index).hide();
|
||||||
}
|
});
|
||||||
});
|
}
|
||||||
|
|
||||||
function changeDisplaySetting(key, value){
|
function changeDisplaySetting(key, value){
|
||||||
let url = '';
|
let url = '';
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
comments: Seq[gitbucket.core.model.Comment],
|
comments: Seq[gitbucket.core.model.Comment],
|
||||||
changedFileSize: Int,
|
changedFileSize: Int,
|
||||||
issueLabels: List[gitbucket.core.model.Label],
|
issueLabels: List[gitbucket.core.model.Label],
|
||||||
issueAsignees: List[gitbucket.core.model.IssueAssignee],
|
issueAssignees: List[gitbucket.core.model.IssueAssignee],
|
||||||
collaborators: List[String],
|
collaborators: List[String],
|
||||||
milestones: List[(gitbucket.core.model.Milestone, Int, Int)],
|
milestones: List[(gitbucket.core.model.Milestone, Int, Int)],
|
||||||
priorities: List[gitbucket.core.model.Priority],
|
priorities: List[gitbucket.core.model.Priority],
|
||||||
@@ -56,7 +56,7 @@
|
|||||||
Some(issue),
|
Some(issue),
|
||||||
comments.toList,
|
comments.toList,
|
||||||
issueLabels,
|
issueLabels,
|
||||||
issueAsignees,
|
issueAssignees,
|
||||||
collaborators,
|
collaborators,
|
||||||
milestones,
|
milestones,
|
||||||
priorities,
|
priorities,
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 949 B After Width: | Height: | Size: 85 B |
|
Before Width: | Height: | Size: 691 B After Width: | Height: | Size: 625 B |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 6.9 KiB |
|
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 4.8 KiB |