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
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.
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.
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.
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.
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.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.
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. ↩
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. ↩