diff --git a/doc/jrebel.md b/doc/jrebel.md new file mode 100644 index 0000000..9ea1f68 --- /dev/null +++ b/doc/jrebel.md @@ -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 +: + + GitBucket + @defining(AutoUpdate.getCurrentVersion){ version => + @version.majorVersion.@version.minorVersion + } + change code !!!!!!!!!!!!!!!! + +: +``` + +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`. diff --git a/doc/readme.md b/doc/readme.md index d4e3c58..f8b23de 100644 --- a/doc/readme.md +++ b/doc/readme.md @@ -9,3 +9,4 @@ * [Notification Email](notification.md) * [Automatic Schema Updating](auto_update.md) * [Release Operation](release.md) + * [JRebel integration (optional)](jrebel.md) diff --git a/project/build.scala b/project/build.scala index ff54248..39f88f4 100644 --- a/project/build.scala +++ b/project/build.scala @@ -5,6 +5,8 @@ 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" @@ -77,5 +79,10 @@ 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) } diff --git a/project/plugins.sbt b/project/plugins.sbt index 5ed803b..fe0d1bd 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -2,4 +2,5 @@ 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") \ No newline at end of file +addSbtPlugin("com.earldouglas" % "xsbt-web-plugin" % "2.1.0") +addSbtPlugin("fi.gekkio.sbtplugins" % "sbt-jrebel-plugin" % "0.10.0")