mirror of
https://github.com/gitbucket/gitbucket.git
synced 2026-05-08 12:57:25 +02:00
Compare commits
35 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c4a682773c | ||
|
|
07e1873cb3 | ||
|
|
14d0c4dc32 | ||
|
|
19f79b6e54 | ||
|
|
e0b9fc9481 | ||
|
|
16c28ad938 | ||
|
|
0e5af9ffa9 | ||
|
|
a0f6f03d4e | ||
|
|
f4cdfc5f32 | ||
|
|
b45988705b | ||
|
|
dd50239759 | ||
|
|
7297a07466 | ||
|
|
e5fa43f91c | ||
|
|
88080c8d02 | ||
|
|
d38dfee540 | ||
|
|
4da6a7b6f9 | ||
|
|
957dfeed6d | ||
|
|
aa5a07b98e | ||
|
|
fd1ee07297 | ||
|
|
07026125a9 | ||
|
|
badb747d24 | ||
|
|
e27c20d600 | ||
|
|
eb46c94c7c | ||
|
|
2e58f82a61 | ||
|
|
df28013b18 | ||
|
|
8f4e285974 | ||
|
|
08c4eeeefe | ||
|
|
1fdc2c629c | ||
|
|
a6767a1c3d | ||
|
|
c539d6b643 | ||
|
|
80c3ffdfd7 | ||
|
|
f80f2106fe | ||
|
|
cbfae66882 | ||
|
|
8a5014fcbe | ||
|
|
a2c26f0f2c |
@@ -1,3 +1,5 @@
|
||||
language: scala
|
||||
scala:
|
||||
- 2.11.6
|
||||
sudo: false
|
||||
script:
|
||||
- . env.sh
|
||||
- sbt test
|
||||
|
||||
37
README.md
37
README.md
@@ -54,20 +54,22 @@ For Installation on Windows Server with IIS see [this wiki page](https://github.
|
||||
### Mac OS X
|
||||
#### Installing Via Homebrew
|
||||
|
||||
$ brew install gitbucket
|
||||
==> Downloading https://github.com/takezoe/gitbucket/releases/download/1.10/gitbucket.war
|
||||
######################################################################## 100.0%
|
||||
==> Caveats
|
||||
Note: When using launchctl the port will be 8080.
|
||||
```
|
||||
$ brew install gitbucket
|
||||
==> Downloading https://github.com/takezoe/gitbucket/releases/download/1.10/gitbucket.war
|
||||
######################################################################## 100.0%
|
||||
==> Caveats
|
||||
Note: When using launchctl the port will be 8080.
|
||||
|
||||
To have launchd start gitbucket at login:
|
||||
ln -sfv /usr/local/opt/gitbucket/*.plist ~/Library/LaunchAgents
|
||||
Then to load gitbucket now:
|
||||
launchctl load ~/Library/LaunchAgents/homebrew.mxcl.gitbucket.plist
|
||||
Or, if you don't want/need launchctl, you can just run:
|
||||
java -jar /usr/local/opt/gitbucket/libexec/gitbucket.war
|
||||
==> Summary
|
||||
/usr/local/Cellar/gitbucket/1.10: 3 files, 42M, built in 11 seconds
|
||||
To have launchd start gitbucket at login:
|
||||
ln -sfv /usr/local/opt/gitbucket/*.plist ~/Library/LaunchAgents
|
||||
Then to load gitbucket now:
|
||||
launchctl load ~/Library/LaunchAgents/homebrew.mxcl.gitbucket.plist
|
||||
Or, if you don't want/need launchctl, you can just run:
|
||||
java -jar /usr/local/opt/gitbucket/libexec/gitbucket.war
|
||||
==> Summary
|
||||
/usr/local/Cellar/gitbucket/1.10: 3 files, 42M, built in 11 seconds
|
||||
```
|
||||
|
||||
#### Manual Installation
|
||||
On OS X, copy the [gitbucket.plist](https://raw.github.com/takezoe/gitbucket/master/contrib/macosx/gitbucket.plist) file to `~/Library/LaunchAgents/`
|
||||
@@ -79,6 +81,11 @@ Run the following commands in `Terminal` to
|
||||
|
||||
Release Notes
|
||||
--------
|
||||
### 3.4 - 27 Jun 2015
|
||||
- Declarative style plug-in definition
|
||||
- New extension point to add markup render
|
||||
- go-import support
|
||||
|
||||
### 3.3 - 31 May 2015
|
||||
- Rich graphical diff for images
|
||||
- File finder is available in the repository viewer
|
||||
@@ -286,3 +293,7 @@ Release Notes
|
||||
|
||||
### 1.0 - 04 Jul 2013
|
||||
- This is a first public release
|
||||
|
||||
Sponsors
|
||||
--------
|
||||
[](https://www.jetbrains.com/idea/)
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>jp.sf.amateras</groupId>
|
||||
<artifactId>gitbucket-assembly</artifactId>
|
||||
<version>0.0.1</version>
|
||||
<build>
|
||||
<extensions>
|
||||
<extension>
|
||||
<groupId>org.apache.maven.wagon</groupId>
|
||||
<artifactId>wagon-ssh</artifactId>
|
||||
<version>1.0-beta-6</version>
|
||||
</extension>
|
||||
</extensions>
|
||||
</build>
|
||||
</project>
|
||||
@@ -6,17 +6,6 @@ Update version number
|
||||
|
||||
Note to update version number in files below:
|
||||
|
||||
### project/build.scala
|
||||
|
||||
```scala
|
||||
object MyBuild extends Build {
|
||||
val Organization = "gitbucket"
|
||||
val Name = "gitbucket"
|
||||
val Version = "3.2.0" // <---- update here!!
|
||||
val ScalaVersion = "2.11.6"
|
||||
val ScalatraVersion = "2.3.1"
|
||||
```
|
||||
|
||||
### src/main/scala/gitbucket/core/servlet/AutoUpdate.scala
|
||||
|
||||
```scala
|
||||
@@ -26,25 +15,15 @@ object AutoUpdate {
|
||||
* The history of versions. A head of this sequence is the current BitBucket version.
|
||||
*/
|
||||
val versions = Seq(
|
||||
new Version(3, 2), // <---- add this!!
|
||||
new Version(3, 1),
|
||||
...
|
||||
new Version(3, 3), // <---- add this line!!
|
||||
new Version(3, 2),
|
||||
```
|
||||
|
||||
### deploy-assembly/deploy-assembly-jar.sh
|
||||
### env.sh
|
||||
|
||||
```bash
|
||||
#!/bin/sh
|
||||
./sbt.sh assembly
|
||||
|
||||
mvn deploy:deploy-file \
|
||||
-DgroupId=gitbucket\
|
||||
-DartifactId=gitbucket-assembly\
|
||||
-Dversion=3.2.0\ # <---- update here!!
|
||||
-Dpackaging=jar\
|
||||
-Dfile=../target/scala-2.11/gitbucket-assembly-x.x.x.jar\ # <---- update here!!
|
||||
-DrepositoryId=sourceforge.jp\
|
||||
-Durl=scp://shell.sourceforge.jp/home/groups/a/am/amateras/htdocs/mvn/
|
||||
export GITBUCKET_VERSION=3.3.0 # <---- update here!!
|
||||
```
|
||||
|
||||
Generate release files
|
||||
@@ -54,15 +33,18 @@ Note: Release operation requires [Ant](http://ant.apache.org/) and [Maven](https
|
||||
|
||||
### Make release war file
|
||||
|
||||
Run ant with `build.xml` in the root directory. The release war file is generated into `target/scala-2.11/gitbucket.war`.
|
||||
Run `release/make-release-war.sh`. The release war file is generated into `target/scala-2.11/gitbucket.war`.
|
||||
|
||||
### Deploy assemnbly jar file
|
||||
|
||||
For plug-in development, we have to publish the assembly jar file to the public Maven repository.
|
||||
|
||||
```
|
||||
cd deploy-assembly/
|
||||
./deploy-assembly-jar.sh
|
||||
```bash
|
||||
$ cd release
|
||||
$ ./make-release-war.sh
|
||||
```
|
||||
|
||||
This script runs `sbt assembly` and `mvn deploy`.
|
||||
### Deploy assembly jar file
|
||||
|
||||
For plug-in development, we have to publish the assembly jar file to the public Maven repository by `release/deploy-assembly-jar.sh`.
|
||||
|
||||
```bash
|
||||
$ cd release/
|
||||
$ ./deploy-assembly-jar.sh
|
||||
```
|
||||
|
||||
@@ -10,7 +10,7 @@ import sbtassembly.AssemblyKeys._
|
||||
object MyBuild extends Build {
|
||||
val Organization = "gitbucket"
|
||||
val Name = "gitbucket"
|
||||
val Version = "3.3.0"
|
||||
val Version = System.getenv("GITBUCKET_VERSION")
|
||||
val ScalaVersion = "2.11.6"
|
||||
val ScalatraVersion = "2.3.1"
|
||||
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<project name="gitbucket" default="all" basedir=".">
|
||||
<project name="gitbucket" default="all" basedir="..">
|
||||
|
||||
<property environment="env"/>
|
||||
<property name="target.dir" value="target"/>
|
||||
<property name="embed.classes.dir" value="${target.dir}/embed-classes"/>
|
||||
<property name="jetty.dir" value="embed-jetty"/>
|
||||
<property name="scala.version" value="2.11"/>
|
||||
<property name="gitbucket.version" value="3.2.0"/>
|
||||
<property name="gitbucket.version" value="${env.GITBUCKET_VERSION}"/>
|
||||
<property name="jetty.version" value="8.1.16.v20140903"/>
|
||||
<property name="servlet.version" value="3.0.0.v201112011016"/>
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
#!/bin/sh
|
||||
source ../env.sh
|
||||
|
||||
cd ../
|
||||
./sbt.sh clean assembly
|
||||
|
||||
cd release
|
||||
mvn deploy:deploy-file \
|
||||
-DgroupId=gitbucket\
|
||||
-DartifactId=gitbucket-assembly\
|
||||
-Dversion=3.2.0\
|
||||
-Dversion=$GITBUCKET_VERSION\
|
||||
-Dpackaging=jar\
|
||||
-Dfile=../target/scala-2.11/gitbucket-assembly-3.3.0.jar\
|
||||
-Dfile=../target/scala-2.11/gitbucket-assembly-$GITBUCKET_VERSION.jar\
|
||||
-DrepositoryId=sourceforge.jp\
|
||||
-Durl=scp://shell.sourceforge.jp/home/groups/a/am/amateras/htdocs/mvn/
|
||||
3
release/make-release-war.sh
Executable file
3
release/make-release-war.sh
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
source ../env.sh
|
||||
ant -f build.xml all
|
||||
1
sbt.sh
1
sbt.sh
@@ -1,2 +1,3 @@
|
||||
#!/bin/sh
|
||||
source ./env.sh
|
||||
java -Dsbt.log.noformat=true -XX:+CMSClassUnloadingEnabled -XX:MaxPermSize=256m -Xmx512M -Xss2M -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005 -jar `dirname $0`/sbt-launch-0.13.8.jar "$@"
|
||||
|
||||
@@ -348,9 +348,12 @@ trait IssuesControllerBase extends ControllerBase {
|
||||
|
||||
private def createReferComment(owner: String, repository: String, fromIssue: Issue, message: String) = {
|
||||
StringUtil.extractIssueId(message).foreach { issueId =>
|
||||
val content = fromIssue.issueId + ":" + fromIssue.title
|
||||
if(getIssue(owner, repository, issueId).isDefined){
|
||||
createComment(owner, repository, context.loginAccount.get.userName, issueId.toInt,
|
||||
fromIssue.issueId + ":" + fromIssue.title, "refer")
|
||||
// Not add if refer comment already exist.
|
||||
if(!getComments(owner, repository, issueId.toInt).exists { x => x.action == "refer" && x.content == content }) {
|
||||
createComment(owner, repository, context.loginAccount.get.userName, issueId.toInt, content, "refer")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -281,12 +281,18 @@ trait PullRequestsControllerBase extends ControllerBase {
|
||||
val (forkedOwner, forkedId) = parseCompareIdentifie(forked, forkedRepository.owner)
|
||||
|
||||
(for(
|
||||
originRepositoryName <- if(originOwner == forkedOwner){
|
||||
originRepositoryName <- if(originOwner == forkedOwner) {
|
||||
// Self repository
|
||||
Some(forkedRepository.name)
|
||||
} else if(Some(originOwner) == forkedRepository.repository.originUserName){
|
||||
// Original repository
|
||||
forkedRepository.repository.originRepositoryName
|
||||
} else {
|
||||
forkedRepository.repository.originRepositoryName.orElse {
|
||||
getForkedRepositories(forkedRepository.owner, forkedRepository.name).find(_._1 == originOwner).map(_._2)
|
||||
}
|
||||
// Sibling repository
|
||||
getUserRepositories(originOwner, context.baseUrl).find { x =>
|
||||
x.repository.originUserName == forkedRepository.repository.originUserName &&
|
||||
x.repository.originRepositoryName == forkedRepository.repository.originRepositoryName
|
||||
}.map(_.repository.repositoryName)
|
||||
};
|
||||
originRepository <- getRepository(originOwner, originRepositoryName, context.baseUrl)
|
||||
) yield {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package gitbucket.core.controller
|
||||
|
||||
import gitbucket.core.api._
|
||||
import gitbucket.core.plugin.PluginRegistry
|
||||
import gitbucket.core.repo.html
|
||||
import gitbucket.core.helper
|
||||
import gitbucket.core.service._
|
||||
@@ -546,7 +547,9 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
||||
}
|
||||
|
||||
|
||||
private val readmeFiles = view.helpers.renderableSuffixes.map(suffix => s"readme${suffix}") ++ Seq("readme.txt", "readme")
|
||||
private val readmeFiles = PluginRegistry().renderableExtensions.map { extension =>
|
||||
s"readme.${extension}"
|
||||
} ++ Seq("readme.txt", "readme")
|
||||
|
||||
/**
|
||||
* Provides HTML of the file list.
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package gitbucket.core.plugin
|
||||
|
||||
import javax.servlet.ServletContext
|
||||
import gitbucket.core.controller.ControllerBase
|
||||
import gitbucket.core.service.SystemSettingsService.SystemSettings
|
||||
import gitbucket.core.util.ControlUtil._
|
||||
import gitbucket.core.util.Version
|
||||
|
||||
/**
|
||||
@@ -15,16 +17,59 @@ trait Plugin {
|
||||
val description: String
|
||||
val versions: Seq[Version]
|
||||
|
||||
/**
|
||||
* Override to declare this plug-in provides images.
|
||||
*/
|
||||
val images: Seq[(String, Array[Byte])] = Nil
|
||||
|
||||
/**
|
||||
* Override to declare this plug-in provides controllers.
|
||||
*/
|
||||
val controllers: Seq[(String, ControllerBase)] = Nil
|
||||
|
||||
/**
|
||||
* Override to declare this plug-in provides JavaScript.
|
||||
*/
|
||||
val javaScripts: Seq[(String, String)] = Nil
|
||||
|
||||
/**
|
||||
* Override to declare this plug-in provides renderers.
|
||||
*/
|
||||
val renderers: Seq[(String, Renderer)] = Nil
|
||||
|
||||
/**
|
||||
* This method is invoked in initialization of plugin system.
|
||||
* Register plugin functionality to PluginRegistry.
|
||||
*/
|
||||
def initialize(registry: PluginRegistry, context: ServletContext, settings: SystemSettings): Unit
|
||||
def initialize(registry: PluginRegistry, context: ServletContext, settings: SystemSettings): Unit = {
|
||||
images.foreach { case (id, in) =>
|
||||
registry.addImage(id, in)
|
||||
}
|
||||
controllers.foreach { case (path, controller) =>
|
||||
registry.addController(path, controller)
|
||||
}
|
||||
javaScripts.foreach { case (path, script) =>
|
||||
registry.addJavaScript(path, script)
|
||||
}
|
||||
renderers.foreach { case (extension, renderer) =>
|
||||
registry.addRenderer(extension, renderer)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is invoked in shutdown of plugin system.
|
||||
* If the plugin has any resources, release them in this method.
|
||||
*/
|
||||
def shutdown(registry: PluginRegistry, context: ServletContext, settings: SystemSettings): Unit
|
||||
def shutdown(registry: PluginRegistry, context: ServletContext, settings: SystemSettings): Unit = {}
|
||||
|
||||
/**
|
||||
* Helper method to get a resource from classpath.
|
||||
*/
|
||||
protected def fromClassPath(path: String): Array[Byte] =
|
||||
using(getClass.getClassLoader.getResourceAsStream(path)){ in =>
|
||||
val bytes = new Array[Byte](in.available)
|
||||
in.read(bytes)
|
||||
bytes
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,6 +24,10 @@ class PluginRegistry {
|
||||
private val javaScripts = new ListBuffer[(String, String)]
|
||||
private val controllers = new ListBuffer[(ControllerBase, String)]
|
||||
private val images = mutable.Map[String, String]()
|
||||
private val renderers = mutable.Map[String, Renderer]()
|
||||
renderers ++= Seq(
|
||||
"md" -> MarkdownRenderer, "markdown" -> MarkdownRenderer
|
||||
)
|
||||
|
||||
def addPlugin(pluginInfo: PluginInfo): Unit = {
|
||||
plugins += pluginInfo
|
||||
@@ -31,34 +35,52 @@ class PluginRegistry {
|
||||
|
||||
def getPlugins(): List[PluginInfo] = plugins.toList
|
||||
|
||||
def addImage(id: String, bytes: Array[Byte]): Unit = {
|
||||
val encoded = StringUtils.newStringUtf8(Base64.encodeBase64(bytes, false))
|
||||
images += ((id, encoded))
|
||||
}
|
||||
|
||||
@deprecated("Use addImage(id: String, bytes: Array[Byte]) instead", "3.4.0")
|
||||
def addImage(id: String, in: InputStream): Unit = {
|
||||
val bytes = using(in){ in =>
|
||||
val bytes = new Array[Byte](in.available)
|
||||
in.read(bytes)
|
||||
bytes
|
||||
}
|
||||
val encoded = StringUtils.newStringUtf8(Base64.encodeBase64(bytes, false))
|
||||
images += ((id, encoded))
|
||||
addImage(id, bytes)
|
||||
}
|
||||
|
||||
def getImage(id: String): String = images(id)
|
||||
|
||||
def addController(controller: ControllerBase, path: String): Unit = {
|
||||
def addController(path: String, controller: ControllerBase): Unit = {
|
||||
controllers += ((controller, path))
|
||||
}
|
||||
|
||||
@deprecated("Use addController(path: String, controller: ControllerBase) instead", "3.4.0")
|
||||
def addController(controller: ControllerBase, path: String): Unit = {
|
||||
addController(path, controller)
|
||||
}
|
||||
|
||||
def getControllers(): List[(ControllerBase, String)] = controllers.toList
|
||||
|
||||
def addJavaScript(path: String, script: String): Unit = {
|
||||
javaScripts += Tuple2(path, script)
|
||||
javaScripts += ((path, script))
|
||||
}
|
||||
|
||||
//def getJavaScripts(): List[(String, String)] = javaScripts.toList
|
||||
|
||||
def getJavaScript(currentPath: String): List[String] = {
|
||||
javaScripts.filter(x => currentPath.matches(x._1)).toList.map(_._2)
|
||||
}
|
||||
|
||||
def addRenderer(extension: String, renderer: Renderer): Unit = {
|
||||
renderers += ((extension, renderer))
|
||||
}
|
||||
|
||||
def getRenderer(extension: String): Renderer = {
|
||||
renderers.get(extension).getOrElse(DefaultRenderer)
|
||||
}
|
||||
|
||||
def renderableExtensions: Seq[String] = renderers.keys.toSeq
|
||||
|
||||
private case class GlobalAction(
|
||||
method: String,
|
||||
path: String,
|
||||
|
||||
44
src/main/scala/gitbucket/core/plugin/Renderer.scala
Normal file
44
src/main/scala/gitbucket/core/plugin/Renderer.scala
Normal file
@@ -0,0 +1,44 @@
|
||||
package gitbucket.core.plugin
|
||||
|
||||
import gitbucket.core.controller.Context
|
||||
import gitbucket.core.service.RepositoryService
|
||||
import gitbucket.core.view.Markdown
|
||||
import play.twirl.api.Html
|
||||
|
||||
/**
|
||||
* A render engine to render content to HTML.
|
||||
*/
|
||||
trait Renderer {
|
||||
|
||||
/**
|
||||
* Render the given request to HTML.
|
||||
*/
|
||||
def render(request: RenderRequest): Html
|
||||
|
||||
}
|
||||
|
||||
object MarkdownRenderer extends Renderer {
|
||||
override def render(request: RenderRequest): Html = {
|
||||
import request._
|
||||
Html(Markdown.toHtml(fileContent, repository, enableWikiLink, enableRefsLink)(context))
|
||||
}
|
||||
}
|
||||
|
||||
object DefaultRenderer extends Renderer {
|
||||
override def render(request: RenderRequest): Html = {
|
||||
import request._
|
||||
Html(
|
||||
s"<tt>${
|
||||
fileContent.split("(\\r\\n)|\\n").map(xml.Utility.escape(_)).mkString("<br/>")
|
||||
}</tt>"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
case class RenderRequest(filePath: List[String],
|
||||
fileContent: String,
|
||||
branch: String,
|
||||
repository: RepositoryService.RepositoryInfo,
|
||||
enableWikiLink: Boolean,
|
||||
enableRefsLink: Boolean,
|
||||
context: Context)
|
||||
@@ -21,6 +21,7 @@ object AutoUpdate {
|
||||
* The history of versions. A head of this sequence is the current BitBucket version.
|
||||
*/
|
||||
val versions = Seq(
|
||||
new Version(3, 4),
|
||||
new Version(3, 3),
|
||||
new Version(3, 2),
|
||||
new Version(3, 1),
|
||||
|
||||
@@ -794,7 +794,12 @@ object JGitUtil {
|
||||
def getBranches(owner: String, name: String, defaultBranch: String): Seq[BranchInfo] = {
|
||||
using(Git.open(getRepositoryDir(owner, name))){ git =>
|
||||
val repo = git.getRepository
|
||||
val defaultObject = repo.resolve(defaultBranch)
|
||||
val defaultObject = if (repo.getAllRefs.keySet().contains(defaultBranch)) {
|
||||
repo.resolve(defaultBranch)
|
||||
} else {
|
||||
git.branchList().call().iterator().next().getObjectId
|
||||
}
|
||||
|
||||
git.branchList.call.asScala.map { ref =>
|
||||
val walk = new RevWalk(repo)
|
||||
try{
|
||||
|
||||
@@ -2,7 +2,6 @@ package gitbucket.core.view
|
||||
|
||||
import gitbucket.core.controller.Context
|
||||
import gitbucket.core.service.{RepositoryService, RequestCache}
|
||||
import gitbucket.core.util.Implicits
|
||||
import gitbucket.core.util.Implicits.RichString
|
||||
|
||||
trait LinkConverter { self: RequestCache =>
|
||||
@@ -11,10 +10,12 @@ trait LinkConverter { self: RequestCache =>
|
||||
* Converts issue id, username and commit id to link.
|
||||
*/
|
||||
protected def convertRefsLinks(value: String, repository: RepositoryService.RepositoryInfo,
|
||||
issueIdPrefix: String = "#")(implicit context: Context): String = {
|
||||
value
|
||||
// escape HTML tags
|
||||
.replace("&", "&").replace("<", "<").replace(">", ">").replace("\"", """)
|
||||
issueIdPrefix: String = "#", escapeHtml: Boolean = true)(implicit context: Context): String = {
|
||||
|
||||
// escape HTML tags
|
||||
val escaped = if(escapeHtml) value.replace("&", "&").replace("<", "<").replace(">", ">").replace("\"", """) else value
|
||||
|
||||
escaped
|
||||
// convert issue id to link
|
||||
.replaceBy(("(?<=(^|\\W))" + issueIdPrefix + "([0-9]+)(?=(\\W|$))").r){ m =>
|
||||
getIssue(repository.owner, repository.name, m.group(2)) match {
|
||||
|
||||
@@ -177,6 +177,18 @@ class GitBucketHtmlSerializer(
|
||||
}
|
||||
}
|
||||
|
||||
override def visit(node: VerbatimNode) {
|
||||
val printer = new Printer()
|
||||
val serializer = verbatimSerializers.get(VerbatimSerializer.DEFAULT)
|
||||
serializer.serialize(node, printer)
|
||||
val html = printer.getString
|
||||
|
||||
// convert commit id and username to link.
|
||||
val t = if(enableRefsLink) convertRefsLinks(html, repository, "issue:", escapeHtml = false) else html
|
||||
|
||||
this.printer.print(t)
|
||||
}
|
||||
|
||||
override def visit(node: BulletListNode): Unit = {
|
||||
if (printChildrenToString(node).contains("""class="task-list-item-checkbox" """)) {
|
||||
printer.println().print("""<ul class="task-list">""").indent(+2)
|
||||
|
||||
@@ -5,14 +5,12 @@ import java.util.{Date, Locale, TimeZone}
|
||||
|
||||
import gitbucket.core.controller.Context
|
||||
import gitbucket.core.model.CommitState
|
||||
import gitbucket.core.plugin.{RenderRequest, PluginRegistry, Renderer}
|
||||
import gitbucket.core.service.{RepositoryService, RequestCache}
|
||||
import gitbucket.core.util.{JGitUtil, StringUtil}
|
||||
import gitbucket.core.util.{FileUtil, JGitUtil, StringUtil}
|
||||
|
||||
import play.twirl.api.Html
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Provides helper methods for Twirl templates.
|
||||
*/
|
||||
@@ -83,14 +81,6 @@ object helpers extends AvatarImageProvider with LinkConverter with RequestCache
|
||||
def plural(count: Int, singular: String, plural: String = ""): String =
|
||||
if(count == 1) singular else if(plural.isEmpty) singular + "s" else plural
|
||||
|
||||
private[this] val renderersBySuffix: Seq[(String, (List[String], String, String, RepositoryService.RepositoryInfo, Boolean, Boolean, Context) => Html)] =
|
||||
Seq(
|
||||
".md" -> ((filePath, fileContent, branch, repository, enableWikiLink, enableRefsLink, context) => markdown(fileContent, repository, enableWikiLink, enableRefsLink)(context)),
|
||||
".markdown" -> ((filePath, fileContent, branch, repository, enableWikiLink, enableRefsLink, context) => markdown(fileContent, repository, enableWikiLink, enableRefsLink)(context))
|
||||
)
|
||||
|
||||
def renderableSuffixes: Seq[String] = renderersBySuffix.map(_._1)
|
||||
|
||||
/**
|
||||
* Converts Markdown of Wiki pages to HTML.
|
||||
*/
|
||||
@@ -107,15 +97,14 @@ object helpers extends AvatarImageProvider with LinkConverter with RequestCache
|
||||
repository: RepositoryService.RepositoryInfo,
|
||||
enableWikiLink: Boolean, enableRefsLink: Boolean)(implicit context: Context): Html = {
|
||||
|
||||
val fileNameLower = filePath.reverse.head.toLowerCase
|
||||
renderersBySuffix.find { case (suffix, _) => fileNameLower.endsWith(suffix) } match {
|
||||
case Some((_, handler)) => handler(filePath, fileContent, branch, repository, enableWikiLink, enableRefsLink, context)
|
||||
case None => Html(
|
||||
s"<tt>${
|
||||
fileContent.split("(\\r\\n)|\\n").map(xml.Utility.escape(_)).mkString("<br/>")
|
||||
}</tt>"
|
||||
)
|
||||
}
|
||||
val fileName = filePath.reverse.head.toLowerCase
|
||||
val extension = FileUtil.getExtension(fileName)
|
||||
val renderer = PluginRegistry().getRenderer(extension)
|
||||
renderer.render(RenderRequest(filePath, fileContent, branch, repository, enableWikiLink, enableRefsLink, context))
|
||||
}
|
||||
|
||||
def isRenderable(fileName: String): Boolean = {
|
||||
PluginRegistry().renderableExtensions.exists(extension => fileName.toLowerCase.endsWith("." + extension))
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -30,6 +30,11 @@
|
||||
<script src="@assets/vendors/elastic/jquery.elastic.source.js"></script>
|
||||
<script src="@assets/vendors/facebox/facebox.js"></script>
|
||||
<script src="@assets/vendors/jquery-hotkeys/jquery.hotkeys.js"></script>
|
||||
@repository.map { repository =>
|
||||
@if(!repository.repository.isPrivate){
|
||||
<meta name="go-import" content="@context.baseUrl.replaceFirst("^https?://", "")/@repository.owner/@repository.name git @repository.httpUrl" />
|
||||
}
|
||||
}
|
||||
</head>
|
||||
<body>
|
||||
<form id="search" action="@path/search" method="POST">
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
<tr>
|
||||
<td>
|
||||
@if(content.viewType == "text"){
|
||||
@defining(renderableSuffixes.find(suffix => pathList.reverse.head.toLowerCase.endsWith(suffix))) { isRrenderable =>
|
||||
@defining(isRenderable(pathList.reverse.head)){ isRrenderable =>
|
||||
@if(!isBlame && isRrenderable) {
|
||||
<div class="box-content markdown-body" style="border: none; padding-left: 16px; padding-right: 16px;">
|
||||
@renderMarkup(pathList, content.content.get, branch, repository, false, false)
|
||||
@@ -152,7 +152,7 @@ $(window).load(function(){
|
||||
});
|
||||
|
||||
function updateBlame(){
|
||||
var m = /^\/(blame|blob)(\/.*)$/.exec(location.pathname.substring(repository.length));
|
||||
var m = /^\/(blame|blob)(\/.*)$/.exec(location.href.substring(repository.length));
|
||||
var mode = m[1];
|
||||
$('.blame-action').toggleClass("active", mode=='blame').attr('href', repository + (m[1]=='blame'?'/blob':'/blame')+m[2]);
|
||||
if(pre.parents("td").find(".blame").length){
|
||||
|
||||
@@ -120,7 +120,7 @@ $(function(){
|
||||
$('#editor').hide();
|
||||
$('#preview').show()
|
||||
|
||||
@if(renderableSuffixes.find(suffix => fileName.map(_.toLowerCase.endsWith(suffix)).getOrElse(false))) {
|
||||
@if(fileName.map(isRenderable _).getOrElse(false)) {
|
||||
// update preview
|
||||
$('#preview').html('<img src="@assets/common/images/indicator.gif"> Previewing...');
|
||||
$.post('@url(repository)/_preview', {
|
||||
|
||||
@@ -1774,3 +1774,11 @@ div.container.blame-container{
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
/* Print */
|
||||
/****************************************************************************/
|
||||
a[href]:after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
@@ -109,7 +109,7 @@ function JsDiffRender(params){
|
||||
var headTextLines = (params.newText==="")?[]:params.newText.split(/\r\n|\r|\n/);
|
||||
var sm, ctx;
|
||||
if(params.ignoreSpace){
|
||||
var ignoreSpace = function(a){ return a.replace(/\s+/,' ').replace(/^\s+|\s+$/,''); };
|
||||
var ignoreSpace = function(a){ return a.replace(/\s+/g,''); };
|
||||
sm = new difflib.SequenceMatcher(
|
||||
$.map(baseTextLines, ignoreSpace),
|
||||
$.map(headTextLines, ignoreSpace));
|
||||
|
||||
Reference in New Issue
Block a user