Merge branch 'master' into solidbase-integration

This commit is contained in:
Naoki Takezoe
2016-01-17 12:57:52 +09:00
11 changed files with 222 additions and 73 deletions

View File

@@ -19,7 +19,7 @@ The current version of GitBucket provides a basic features below:
- Gravatar support
- Plug-in system
If you want to try the development version of GitBucket, see the documentation for developers at [Wiki](https://github.com/gitbucket/gitbucket/wiki).
If you want to try the development version of GitBucket, see [Developer's Guide](https://github.com/gitbucket/gitbucket/blob/master/doc/how_to_run.md).
Installation
--------
@@ -41,35 +41,7 @@ or you can start GitBucket by `java -jar gitbucket.war` without servlet containe
To upgrade GitBucket, only replace gitbucket.war after stop GitBucket. All GitBucket data is stored in HOME/.gitbucket. So if you want to back up GitBucket data, copy this directory to the other disk.
For Installation on Windows Server with IIS see [this wiki page](https://github.com/gitbucket/gitbucket/wiki/Installation-on-IIS-and-Helicontech-Zoo)
### 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.
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, generate `gitbucket.plist` by [this script](https://raw.githubusercontent.com/gitbucket/gitbucket/master/contrib/macosx/makePlist) and copy it to `~/Library/LaunchAgents/`
Run the following commands in `Terminal` to
- start gitbucket: `launchctl load ~/Library/LaunchAgents/gitbucket.plist`
- stop gitbucket: `launchctl unload ~/Library/LaunchAgents/gitbucket.plist`
About installation on Mac or Windows Server (with IIS), configuration of Apache or Nginx and also integration with other tools or services such as Jenkins or Slack, see [Wiki](https://github.com/gitbucket/gitbucket/wiki).
Plug-ins
--------

148
doc/jrebel.md Normal file
View File

@@ -0,0 +1,148 @@
JRebel integration (optional)
=============================
[JRebel](http://zeroturnaround.com/software/jrebel/) is a JVM plugin that makes developing web apps much faster.
JRebel is generally able to eliminate the need for the following slow "app restart" in sbt following a code change:
```
> jetty:start
```
While JRebel is not open source, it does reload your code faster than the `~;copy-resources;aux-compile` way of doing things using `sbt`.
It's only used during development, and doesn't change your deployed app in any way.
JRebel used to be free for Scala developers, but that changed recently, and now there's a cost associated with usage for Scala. There are trial plans and free non-commercial licenses available if you just want to try it out.
----
## 1. Get a JRebel license
Sign up for a [usage plan](https://my.jrebel.com/). You will need to create an account.
## 2. Download JRebel
Download the most recent ["nosetup" JRebel zip](http://zeroturnaround.com/software/jrebel/download/prev-releases/).
Next, unzip the downloaded file.
## 3. Activate
Follow the [instructions on the JRebel website](http://zeroturnaround.com/software/jrebel/download/prev-releases/) to activate your downloaded JRebel.
You can use the default settings for all the configurations.
You don't need to integrate with your IDE, since we're using sbt to do the servlet deployment.
## 4. Tell jvm where JRebel is
Fortunately, the gitbucket project is already set up to use JRebel.
You only need to tell jvm where to find the jrebel jar.
To do so, edit your shell resource file (usually `~/.bash_profile` on Mac, and `~/.bashrc` on Linux), and add the following line:
```bash
export JREBEL=/path/to/jrebel/jrebel.jar
```
For example, if you unzipped your JRebel download in your home directory, you whould use:
```bash
export JREBEL=~/jrebel/jrebel.jar
```
Now reload your shell:
```
$ source ~/.bash_profile # on Mac
$ source ~/.bashrc # on Linux
```
## 5. See it in action!
Now you're ready to use JRebel with the gitbucket.
When you run sbt as normal, you will see a long message from JRebel, indicating it has loaded.
Here's an abbreviated version of what you will see:
```
$ ./sbt
[info] Loading project definition from /git/gitbucket/project
[info] Set current project to gitbucket (in build file:/git/gitbucket/)
>
```
You will start the servlet container slightly differently now that you're using sbt.
```
> jetty:start
:
[info] starting server ...
[success] Total time: 3 s, completed Jan 3, 2016 9:47:55 PM
2016-01-03 21:47:57 JRebel:
2016-01-03 21:47:57 JRebel: A newer version '6.3.1' is available for download
2016-01-03 21:47:57 JRebel: from http://zeroturnaround.com/software/jrebel/download/
2016-01-03 21:47:57 JRebel:
2016-01-03 21:47:58 JRebel: Contacting myJRebel server ..
2016-01-03 21:47:59 JRebel: Directory '/git/gitbucket/target/scala-2.11/classes' will be monitored for changes.
2016-01-03 21:47:59 JRebel: Directory '/git/gitbucket/target/scala-2.11/test-classes' will be monitored for changes.
2016-01-03 21:47:59 JRebel: Directory '/git/gitbucket/target/webapp' will be monitored for changes.
2016-01-03 21:48:00 JRebel:
2016-01-03 21:48:00 JRebel: #############################################################
2016-01-03 21:48:00 JRebel:
2016-01-03 21:48:00 JRebel: JRebel Legacy Agent 6.2.5 (201509291538)
2016-01-03 21:48:00 JRebel: (c) Copyright ZeroTurnaround AS, Estonia, Tartu.
2016-01-03 21:48:00 JRebel:
2016-01-03 21:48:00 JRebel: Over the last 30 days JRebel prevented
2016-01-03 21:48:00 JRebel: at least 182 redeploys/restarts saving you about 7.4 hours.
2016-01-03 21:48:00 JRebel:
2016-01-03 21:48:00 JRebel: Over the last 324 days JRebel prevented
2016-01-03 21:48:00 JRebel: at least 1538 redeploys/restarts saving you about 62.4 hours.
2016-01-03 21:48:00 JRebel:
2016-01-03 21:48:00 JRebel: Licensed to nazo king (using myJRebel).
2016-01-03 21:48:00 JRebel:
2016-01-03 21:48:00 JRebel:
2016-01-03 21:48:00 JRebel: #############################################################
2016-01-03 21:48:00 JRebel:
:
> ~ copy-resources
[success] Total time: 0 s, completed Jan 3, 2016 9:13:54 PM
1. Waiting for source changes... (press enter to interrupt)
```
Finally, change your code.
For example, you can change the title on `src/main/twirl/gitbucket/core/main.scala.html` like this:
```html
:
<a class="navbar-brand" href="@path/">
<img src="@assets/common/images/gitbucket.png" style="width: 24px; height: 24px;"/>GitBucket
@defining(AutoUpdate.getCurrentVersion){ version =>
<span class="header-version">@version.majorVersion.@version.minorVersion</span>
}
change code !!!!!!!!!!!!!!!!
</a>
:
```
If JRebel is doing is correctly installed you will see a notice for you:
```
1. Waiting for source changes... (press enter to interrupt)
2016-01-03 21:48:42 JRebel: Reloading class 'gitbucket.core.html.main$'.
[info] Wrote rebel.xml to /git/gitbucket/target/scala-2.11/resource_managed/main/rebel.xml
[info] Compiling 1 Scala source to /git/gitbucket/target/scala-2.11/classes...
[success] Total time: 3 s, completed Jan 3, 2016 9:48:55 PM
2. Waiting for source changes... (press enter to interrupt)
```
And you reload browser, JRebel give notice of that it has reloaded classes:
```
[success] Total time: 3 s, completed Jan 3, 2016 9:48:55 PM
2. Waiting for source changes... (press enter to interrupt)
2016-01-03 21:49:13 JRebel: Reloading class 'gitbucket.core.html.main$'.
```
## 6. Limitations
JRebel is nearly always able to eliminate the need to explicitly reload your container after a code change. However, if you change any of your routes patterns, there is nothing JRebel can do, you will have to run `jetty:start`.

View File

@@ -9,3 +9,4 @@ Developer's Guide
* [Notification Email](notification.md)
* [Automatic Schema Updating](auto_update.md)
* [Release Operation](release.md)
* [JRebel integration (optional)](jrebel.md)

View File

@@ -5,6 +5,8 @@ import sbt._
import sbtassembly.AssemblyKeys._
import sbtassembly._
import JettyPlugin.autoImport._
import fi.gekkio.sbtplugins.jrebel.JRebelPlugin._
import com.earldouglas.xwp.WebappPlugin.autoImport.webappPrepare
object MyBuild extends Build {
val Organization = "gitbucket"
@@ -78,5 +80,10 @@ object MyBuild extends Build {
testOptions in Test += Tests.Setup( () => new java.io.File("target/gitbucket_home_for_test").mkdir() ),
fork in Test := true,
packageOptions += Package.MainClass("JettyLauncher")
).settings(jrebelSettings: _*).settings(
jrebel.webLinks += (target in webappPrepare).value,
jrebel.enabled := System.getenv().get("JREBEL") != null,
javaOptions in Jetty ++= Option(System.getenv().get("JREBEL")).toSeq.flatMap(path =>
Seq("-noverify", "-XX:+UseConcMarkSweepGC", "-XX:+CMSClassUnloadingEnabled", s"-javaagent:${path}"))
).enablePlugins(SbtTwirl, JettyPlugin)
}

View File

@@ -3,3 +3,4 @@ scalacOptions ++= Seq("-unchecked", "-deprecation", "-feature")
addSbtPlugin("com.typesafe.sbt" % "sbt-twirl" % "1.0.4")
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.12.0")
addSbtPlugin("com.earldouglas" % "xsbt-web-plugin" % "2.1.0")
addSbtPlugin("fi.gekkio.sbtplugins" % "sbt-jrebel-plugin" % "0.10.0")

View File

@@ -111,6 +111,7 @@ trait RepositoryViewerControllerBase extends ControllerBase {
enableRefsLink = params("enableRefsLink").toBoolean,
enableLineBreaks = params("enableLineBreaks").toBoolean,
enableTaskList = params("enableTaskList").toBoolean,
enableAnchor = false,
hasWritePermission = hasWritePermission(repository.owner, repository.name, context.loginAccount)
)
})

View File

@@ -33,28 +33,30 @@ object Markdown {
enableTaskList: Boolean = false,
hasWritePermission: Boolean = false,
pages: List[String] = Nil)(implicit context: Context): String = {
// escape issue id
val s = if(enableRefsLink){
markdown.replaceAll("(?<=(\\W|^))#(\\d+)(?=(\\W|$))", "issue:$2")
} else markdown
// escape task list
val source = if(enableTaskList){
escapeTaskList(s)
} else s
val source = if(enableTaskList) escapeTaskList(markdown) else markdown
val options = new Options()
options.setSanitize(true)
options.setBreaks(enableLineBreaks)
val renderer = new GitBucketMarkedRenderer(options, repository, enableWikiLink, enableRefsLink, enableAnchor, enableTaskList, hasWritePermission, pages)
val renderer = new GitBucketMarkedRenderer(options, repository,
enableWikiLink, enableRefsLink, enableAnchor, enableTaskList, hasWritePermission, pages)
Marked.marked(source, options, renderer)
}
/**
* Extends markedj Renderer for GitBucket
*/
class GitBucketMarkedRenderer(options: Options, repository: RepositoryService.RepositoryInfo,
enableWikiLink: Boolean, enableRefsLink: Boolean, enableAnchor: Boolean, enableTaskList: Boolean, hasWritePermission: Boolean,
class GitBucketMarkedRenderer(options: Options,
repository: RepositoryService.RepositoryInfo,
enableWikiLink: Boolean,
enableRefsLink: Boolean,
enableAnchor: Boolean,
enableTaskList: Boolean,
hasWritePermission: Boolean,
pages: List[String])
(implicit val context: Context) extends Renderer(options) with LinkConverter with RequestCache {
@@ -62,11 +64,14 @@ object Markdown {
val id = generateAnchorName(text)
val out = new StringBuilder()
out.append("<h" + level + " id=\"" + options.getHeaderPrefix + id + "\" class=\"markdown-head\">")
out.append("<h" + level + " id=\"" + options.getHeaderPrefix + id + "\"")
if(enableAnchor){
out.append(" class=\"markdown-head\">")
out.append("<a class=\"markdown-anchor-link\" href=\"#" + id + "\"></a>")
out.append("<a class=\"markdown-anchor\" name=\"" + id + "\"></a>")
} else {
out.append(">")
}
out.append(text)
@@ -83,28 +88,27 @@ object Markdown {
var listType: String = null
if (ordered) {
listType = "ol"
}
else {
} else {
listType = "ul"
}
if(body.contains("""class="task-list-item-checkbox"""")){
return "<" + listType + " class=\"task-list\">\n" + body + "</" + listType + ">\n"
"<" + listType + " class=\"task-list\">\n" + body + "</" + listType + ">\n"
} else {
return "<" + listType + ">\n" + body + "</" + listType + ">\n"
"<" + listType + ">\n" + body + "</" + listType + ">\n"
}
}
override def listitem(text: String): String = {
if(text.contains("""class="task-list-item-checkbox" """)){
return "<li class=\"task-list-item\">" + text + "</li>\n"
"<li class=\"task-list-item\">" + text + "</li>\n"
} else {
return "<li>" + text + "</li>\n"
"<li>" + text + "</li>\n"
}
}
override def text(text: String): String = {
// convert commit id and username to link.
val t1 = if(enableRefsLink) convertRefsLinks(text, repository, "issue:", false) else text
val t1 = if(enableRefsLink) convertRefsLinks(text, repository, "#", false) else text
// convert task list to checkbox.
val t2 = if(enableTaskList) convertCheckBox(t1, hasWritePermission) else t1

View File

@@ -89,6 +89,7 @@ object helpers extends AvatarImageProvider with LinkConverter with RequestCache
enableWikiLink: Boolean,
enableRefsLink: Boolean,
enableLineBreaks: Boolean,
enableAnchor: Boolean = true,
enableTaskList: Boolean = false,
hasWritePermission: Boolean = false,
pages: List[String] = Nil)(implicit context: Context): Html =
@@ -97,7 +98,7 @@ object helpers extends AvatarImageProvider with LinkConverter with RequestCache
repository = repository,
enableWikiLink = enableWikiLink,
enableRefsLink = enableRefsLink,
enableAnchor = true,
enableAnchor = enableAnchor,
enableLineBreaks = enableLineBreaks,
enableTaskList = enableTaskList,
hasWritePermission = hasWritePermission,

View File

@@ -122,7 +122,7 @@ $(function(){
$('#editor').hide();
$('#preview').show();
$('#btn-code').removeClass('active');
$('#btn-preview').appendClass('active');
$('#btn-preview').addClass('active');
@if(fileName.map(isRenderable _).getOrElse(false)) {
// update preview
@@ -131,6 +131,7 @@ $(function(){
content : editor.getValue(),
enableWikiLink : false,
enableRefsLink : false,
enableLineBreaks : false,
enableTaskList : false
}, function(data){
$('#preview').empty().append(

View File

@@ -115,7 +115,7 @@
}</span>@file.name.split("/").toList.last
</a>
} else {
<a href="@url(repository)/tree@{(encodeRefName(branch) :: pathList).mkString("/", "/", "/")}@file.name">
<a href="@url(repository)/tree@{(branch :: pathList).map(encodeRefName).mkString("/", "/", "/")}@{encodeRefName(file.name)}">
<span class="simplified-path">@file.name.split("/").toList.init match {
case Nil => {}
case list => {@list.mkString("", "/", "/")}

View File

@@ -829,6 +829,9 @@ table.table-file-list .file-icon {
table.table-file-list .content-name {
max-width: 180px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
table.table-file-list .commit-message {
@@ -1715,28 +1718,39 @@ div.markdown-body h1 {
border-bottom: 1px solid #ddd;
font-size: 2.5em;
font-weight: bold;
line-height: 1.7;
}
div.markdown-body h2 {
border-bottom: 1px solid #eee;
font-size: 2em;
font-weight: bold;
line-height: 1.7;
}
div.markdown-body h3 {
font-size: 1.5em;
font-weight: bold;
line-height: 1.7;
}
div.markdown-body h4 {
font-size: 1.2em;
font-weight: bold;
line-height: 1.7;
}
div.markdown-body h5 {
font-size: 1em;
font-weight: bold;
line-height: 1.7;
}
div.markdown-body h6 {
color:#777;
font-size: 1em;
font-weight: bold;
line-height: 1.7;
}
div.markdown-body li {
@@ -1902,7 +1916,6 @@ div.markdown-body table colgroup + tbody tr:first-child td:last-child {
.markdown-head {
position: relative;
line-height: 1.7;
}
a.markdown-anchor-link {