Creating a CD-friendly blog

Alright. So. I've got an extensive background as a developer. I automate things. All of the things. Anything I have to do more than once needs to be automated. It's an OCD thing[1]. In all of my recent programming jobs, I've worked to replace myself with a very small shell script.

Got Code?

This requirement means that I need a blog that allows me to write my posts as some form of code. The common code-like denominator these days is Markdown. That's fine, as far as I'm concerned. It's text-like, but Markdown processors exist everywhere. If I don't have to actually write HTML tags all over the place, so much the better.

I have plenty of experience using Wordpress, because that's what I inherited as the blogging software for my fraternity's website a number of years ago when I took that over. However, that's an exercise in much pointing and clicking inside a web-based CMS, which saves its information to a database...Just a little too much for me.


Then I found Jekyll. sudo gem install jekyll, jekyll new blog, cd blog, jekyll serve -w and it's up and running on localhost:4000. Holy wow. And the process was exactly the same on my dev box (my Mac laptop) as my production box (an Ubuntu Linode.) Now that's nice.

The initial theme was OK, but doing a search for jekyll themes was a quick enough way to get started. There's an entire post to be made around that topic, so let's just say for now that I found one that was good enough to get started and easy enough to install, and I'm using it[2].

Since the code for all posts in Jekyll is Markdown, that means all my code can easily be put into source control. I run my own git server on for all my personal projects, so creating another repository was really simple.


Now that I have a code repository, I can hook that up to my already-existing Jenkins server. Doing that is a two-step process; one in git, and the other in Jenkins when creating/configuring my job.

First, the git part. On my git server, I created a post-receive script inside $GIT_REPO_HOME/blog/hooks. $GIT_REPO_HOME is where all my git repositories live, and blog is the name of the repository for this code. The post-receive script looks like this:



curl http://$USERNAME:$PASSWORD@$JENKINS_URL:$JENKINS_PORT/git/notifyCommit?url=$GIT_URL


The second part of the equation is in the job configuration in Jenkins. In the Source Code Management section of my Jenkins job's configuration, I set the Git repository URL to /path/to/git/blog, which matches the URL-encoded GIT_URL above. In order to really enable the post-receive hook in Git to successfully notify Jenkins when a new push has been made, you also need to turn on SCM polling. However, it doesn't need to be a frequent poll, so set it to H 0 1 1 0[3].

Bingo! Now, when I commit/push code from my dev machine to my Git server, it will automatically invoke my Jenkins job. All that remains is the actual Jekyll part of the equation for job configuration. This is where Jekyll steps in and makes life really easy!

I had to add a Shell build step, and the command to build my blog is jekyll build --destination /final/path/to/blog. That'll have Jekyll take all of my Markdown code, Liquid templates, CSS, and everything else, and turn it into a static website that can be easily served up by your favorite webserver.

Note that since Jenkins released version 1.583 last week, all files it produces have mode 0640, which generally means that they're not readable by your webserver. To counteract this, I've added a couple more shell script lines to my build step. The full script looks like this:

jekyll build --destination /final/path/to/blog
cd /final/path/to/blog
find . -type d | xargs chmod 755
find . -type f | xargs chmod 644


That's really it. Assuming your web server is configured properly (which I didn't touch on), it should Just Work.

1: OK, so not really OCD, but the special attention-to-detail-ness that programmers tend to have.

2: Mostly.

3: January 1, at midnight, when January 1st is on a Sunday. Seriously. Jenkins' helpful explanatory text for my job is: Would last have run at Sunday, January 1, 2012 12:00:02 AM CST; would next run at Sunday, January 1, 2017 12:00:02 AM CST.