November 02, 2013

On Using a SBT Plugins with Heroku

One quick pro-tip for those who are using a sbt plugin as a project dependency on Heroku and run into a problem like this:

Initialized empty Git repository in /tmp/build_fa31e5a8-c0d8-4f29-b45a-c1ea4dbf3e0f/.sbt_home/.sbt/0.13/staging/e8a2b2d1a8bd62bf8e10/sbt-jasmine-plugin/.git/
fatal: Not a git repository: '.'
[error] Nonzero exit code (128): git checkout -q 0.7
[error] Use 'last' for the full log.
Project loading failed: (r)etry, (q)uit, (l)ast, or (i)gnore?  !     Failed to build app with sbt
! Push rejected, failed to compile Scala app

You might have noticed that buried in the first line of the output is a reference to the fact that I am using the sbt-jasmine-plugin. The documentation suggests using the plugin via a project dependency like:

lazy val plugins = Project("plugins", file("."))
  .dependsOn(uri("git://github.com/guardian/sbt-jasmine-plugin.git#1.0"))

Locally, sbt resolves the project fine, but using the git-based workflow of Heroku (which is pretty sweet in general), this doesn't seem to work. Rather than rock the boat and try something extra-clever (like hooking fancy before_deploy scripting into my Travis CI build), I sought out a solution that better fit into the Heroku workflow.

I found this tumblr post that described a similar situation with a library dependency. (That post goes through a lot more detail than I do here, and do read it for a more step-by-step walkthrough of the problem.)

The summary is to use git submodules and let Heroku resolve the external git repo for you. In the case of a plugin, you are adding a submodule in the project/lib directory. At that point, the line in the project/project/Plugins.scala file, looks like:

lazy val plugins = Project("root", file("."))
    .dependsOn(file("lib/sbt-jasmine-plugin"))

Push it all to Heroku, and then you should be all set!