Let’s build a Bitbucket add-on in Clojure! – Part 5: Deploying our add-on to Bitbucket

Reading Time: 5 minutes

In part 4 of this series we added the Bitbucket UI to our add-on. Although there’s more tweaks we’ll do in later installments, for now we have enough to do an initial test against Bitbucket. In this post we’ll show how to do this running from our development machine, and how to build and run a standalone deployment image of our add-on.

Hooking our add-on into Bitbucket

In the last installment we added the last major pieces to produce our working Clojure Bitbucket add-on. So now we need to take it for a spin.

Authentication requires a URL

As mentioned in the installment about generating a descriptor, Bitbucket Connect requires that we generate an OAuth key to identify who is responsible for our add-on. This key in turn is tied the URL where out add-on is hosted, so the first thing we need to do is decide where our add-on will live. If you already have a development hosting environment you can use that. However if you’re just want a quick test from your development environment then ngrok is a good choice. ngrok acts as an ad-hoc tunnel a port on our machine and the wider internet. So let’s get that running:

ngrok -proto https 3000

This will produce output that looks something like:

The part we’re interested in is the generated URL: https://1a222264.ngrok.com. Now we have this we can generate our OAuth identifier in Bitbucket. Login to your account and go to your setting (in the drop-down in the top-right corner). Then go to OAuth, click on Add Consumer and fill out with the following settings:

This will result in an entry in the OAuth Consumers list. Click on it and retrieve the Key (not the Secret):

Note: If your ngrok URL changes you’ll need to update this OAuth key. This can be down using the Edit entry in the key options.

Building a standalone application

Now we have a URL and its key we can pass this to our add-on to use in the descriptor as described in part 2. As we’re building a 12 Factor application we set this using the environment. In previous installments we’ve used Leiningen to set the environment and run the application, but this time let’s try something a little different. Leiningen can be used to run applications in production, but the more common method is to pack our application and all qits dependencies into an uberjar, which can be distributed and run in the JVM.

To do this we need to make a minor modification to our core module; Clojure is a dynamic language that can compile its code at runtime or ahead of time. However we JVM expects a main class as an entry-point to the application. To ensure this exists we need to tell Clojure and Leiningen to generate a full Java class for the core module. To do this we just add (:gen-class) to the namespace clause:

(ns hello-connect.core
  (:require [clojure.tools.logging :as log]

            [hello-connect.handler :refer [app init shutdown]]

            [immutant.web :as web]
            [immutant.web.middleware :refer [wrap-development]]

            [environ.core :refer [env]]))

Now we can ask Leiningen to construct our uberjar:

[ssmith:~/projects/hello-connect] $ lein uberjar
Compiling hello-connect.bitbucket
Compiling hello-connect.core
Compiling hello-connect.handler
Compiling hello-connect.storage
Created /Users/ssmith/projects/hello-connect/target/uberjar+uberjar/hello-connect-0.1.0-SNAPSHOT.jar
Created /Users/ssmith/projects/hello-connect/target/uberjar/hello-connect-0.1.0-SNAPSHOT-standalone.jar

Running the add-on

The JAR we’re interested in is the -standalone one, which contains our application, all its dependencies, and Clojure itself. This can be run from the vanilla JVM, but before we do that we need to pass our configuration in via environment variables:

export BASE_URL=https://1a222264.ngrok.com

(Obviously fill in the details above with your own values.)

With the environment configured we can run the application, making it available on the internet via ngrok (which should still be running):

[ssmith:~/projects/hello-connect] $ java -jar target/uberjar/hello-connect-0.1.0-SNAPSHOT-standalone.jar
12:27:40.564 [main] INFO  hello-connect.handler - Initialising application
log4j:WARN No appenders could be found for logger (org.jboss.logging).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
12:27:41.391 INFO  [org.projectodd.wunderboss.web.Web] (main) Registered web context /
12:27:41.396 INFO  [hello-connect.core] (main) server started on port: 3000

We can test this by retrieving the descriptor with cURL:

[ssmith:~] $ curl https://1a222264.ngrok.com/atlassian-connect.json
   "key": "hello-connect",
   "name": "Hello Connect",
   "description": "An example Clojure add-on for Bitbucket",
   "vendor": {
       "name": "Angry Nerds",
       "url": "https://www.atlassian.com/angrynerds"

Installing our add-on in Bitbucket

Now that we’ve got our add-on up, running and on the internet let’s get it into Bitbucket. Luckily Bitbucket makes it very easy to add custom add-ons to our personal accounts. All we need to do is tell it the URL; go to your account settings again and select Manage add-ons:

Click on Install add-on from URL and enter the ngrok URL we generated earlier:

This will then verify that you wish to grant permissions to the add-on. Confirm this and you will see our add-on in the list:

Checking out our add-on

Now you can go to any of your repositories in Bitbucket and you should see (after a brief loading time) the web panel we produced in the previous installment:

Next time

Now that we have a running Connect add-on we can start on the real fun, which is improving it. In the next installment we’ll the Javascript we added in part 4 and introduce ClojureScript, an implementation of Clojure in Javascript. We’ll then use this to reimplement our client-side code in Clojure, and look into the project changes necessary to integrate this into our build-chain.