randallb.tv

I'm a father, husband, and startup founder who thinks it's too difficult to produce video content.

Right now, I help build Vidpresso, a way for TV stations to integrate social media posts directly into their broadcasts. I write here mostly about building interesting things, be they companies, projects, or otherwise.
Recent Tweets @randallb

TL;DR: Go clone this and set up the configuration variables and get up and going with your own ghetto CI in about 5 minutes.

I saw Zach Holman’s talk on continuous deployment / automating everything, and it inspired me to do something I had been itching to do for a while… specifically eliminate one step of the deploy process.

For most developers, their source control is different from the servers running the code. Normally, a developer will check code in to a place like github, then push the code to her/his server through rsync scripts, or perhaps through git itself when pushing to Heroku or DotCloud, for instance.

Why have two steps? And why not have automated things happen to said code once its ready? Maybe checking for errors through tests, for instance?

Good idea, continuous integrator. We’re using Hubot to pull this off. We have a persistent Google Talk chatroom called partychat which we use to talk as a team. We added Hubot a while ago for general hilarity, and so we could know when critical things happen on the site.1

The process

  1. Set up Hubot
  2. Configure Hubot to work with Github webhook
  3. Generate SSH keys / add them to Hubot securely
  4. Set up pull/push script (maybe add testing?)
  5. Rejoice at how awesome you are.

Set up Hubot

I won’t go over how to set up Hubot because there are better places to go for that. I will say it’s really easy if you’ve ever set up a Node.JS app. Get Hubot so it’s talking to the web, and if you have a persistent chat client, get it working with that so you can talk to Hubot directly in chat, and more importantly, it can tell you what it’s doing.

Configure Hubot to work with Github

Hubot scripts live in the gasp scripts directory. Throw one in there called github.coffee or whatever you want to call it. Make sure you’re writing it in CoffeeScript. You could also use our example script too, if you’re so inclined.

Our example script does a few things. First, it sets up a route for the external world to hit. We chose /github but you could pick whatever you wanted. We’ll take this webhook URL, and enter it in Github as a post-commit webhook.

Then, once you’ve got that going, you can test your webhook, and it’ll send a payload of your last commit to master. You can use the tool Github recommends to easily inspect the result of the webhook POST.

You’ll notice that Github sends a payload variable with a JSON string inside of it. So in order to use that JSON string, we parse it into a real object.

Then, we check for which branch the commit applies by checking the ref section of the payload. People who know more about git than me can explain why that would be different than refs/heads/#{branchname}, but for our purposes that’s what we expect.

So then we check for the master branch, we’ll notify the room that we’re ready to start processing, and we’ll start a shell script which checks out code and sends it to production.2 The same thing happens with develop sending to staging, but the script for doing that is a little different.

Setting up SSH keys

Generate a key with ssh-keygen. No passphrase. Nuff said.

Now you need to store the key somewhere. Since we’re on Heroku, I’m storing the key as an environment variable. I figure if it’s secure enough for DB strings, it’s secure enough for my SSH key.

heroku config:add PRIV="[paste your key here]"

Note that the double quotes will keep your linebreaks intact, which is crucial.

Set up scripts for push / pull

To actually use the key, I went through a plethora of different options, but since we’re deploying to Heroku and essentially our servers are ephemeral, I decided to echo the environment variable to the main ~/.ssh/id_rsa file. If you have other keys and want to specify an identity file, you might try GIT_SSH, which has some helpful [stack overflow questions] [13] to get you on the right track. You also might be able to use ssh-agent.

As for our actual bash script, it’s really simple.

  1. Set up SSH by copying the key to the location specified. When you’re echoing out the key, be certain to use echo "$PRIV" instead of just echo $PRIV. That’ll keep your line break formatting intact. Also, you probably want to turn off StrictHostKeyChecking for github and heroku, which you could add to ssh config, etc.
  2. Clone your repo to a temp directory.
  3. Add your heroku / other git URL and push, or push using rsync or whatever.
  4. Clean up the files you created.

Rejoice.

Now you’re set. You could probably add testing into the mix, and if you’re needing ruby or something you could add a custom buildpack which would be able to perform the tests for you.


  1. For instance… we actually know whenever a credit card gets charged. We use [Stripe][http://stripe.com] for our credit card processing, and then hook up their webhook interface to Hubot. So we know whenever money is coming in. We also plan to make a financial dashboard, and have Hubot be our central point of integration with [Xero][http://xero.com], our accounting software. We also integrated Twilio, so we know whenever someone calls our interest number. 

  2. I realize you could probably write all of the scripty things in Node / CoffeeScript, which would be a really good idea. I’m lazy so I did a bash script for the first pass. It has some limitations, like by using exec I only get a dump of stdout when the process exits, which is totally lame. 

  1. randallcbennett posted this