I really like Octopress, which is built on Jekyll. You can read a lot of articles about the advantages and disadvantages of pre-baked blogs, so I won't bore you with those details. Instead, I'll bore you on the subject of the one feature I miss with pre-baked blogs: scheduling posts for later publication.
When I switched to a pre-baked blogging tool like Octopress, I gave up the ability to upload a post, but publish it later. Well, I didn't really give it up entirely, but pre-baking my blog means thinking of my blog as a static web site, rather than a dynamic one, which implies having to re-deploy every time I wanted to change its content. This makes scheduling posts in the future a bit more tricky.
Using Heroku and its read-only file system make it even trickier, since I can't regenerate the blog in production.
I just wanted to share my solution with you, in case it interests you.
First, I added to Octopress the ability to generate the blog without future-dated posts. This looked difficult, especially with Octopress's existing "preview mode" feature, but I discovered that Jekyll supports omitting future-dated posts directly with
jekyll --no-future, so I augmented Octopress to use this feature. If you'd like to explore the details, click here.1
Next, I needed a way to republish my Octopress site regularly in order to include new posts as their publication instant arrives. I asked my tweeps for ideas, and we agreed that we couldn't get around having a machine Out There Somewhere that's always on that would poll a
git repository for changes, then regenerate and publish to Heroku. I settled on the following architecture.
I followed these basic steps:
Added an SSH public key from "Monitor/Staging" to "Production", so that the former could
pushto the latter.
Installed a script into "Monitor/Staging" to, well, monitor, stage, then
Cloned my local
gitrepository to "Integration" so that it will always be available to "Monitor/Staging".
Complicated, sure, but--and you'll tell me if you disagree--just barely sufficiently complicated, and no worse. I can handle that.
My workflow hasn't changed much. I compose posts, preview, and
push to "Integration" when I finish. "Monitor/Staging" runs the following script every 10 minutes.
pushd $HOME/Workspaces/blog.thecodewhisperer.com # I have to do this by hand, apparently. . .rvmrc</p> <h1 id="i-cant-assume-that-im-on-the-right-branch">I can't assume that I'm on the right branch</h1> <p>git checkout -q master git pull -q origin master git checkout -q publish git merge -q master</p> <h1 id="check-the-diff-before-regenerating-to-avoid-spurious">Check the diff /before/ regenerating, to avoid spurious</h1> <h1 id="timestamp-differences">timestamp differences</h1> <p>DIFF="<span class="math">$(git diff --stat publish heroku/master)" NOW=
date if [ -n "$DIFF" ]; then echo "Publishing $NOW..." bundle exec rake generate git add -A && git commit -m "Published $NOW" && git push heroku publish:master else echo "No need to publish at $NOW."; fi popd
I write posts to the branch
master, and "Monitor/Staging" merges them to the branch
publish, then deploys them to "Production"'s branch
Of course, I will monitor this closely over the next few days, looking for anomalies. In particular, I worry a little about what happens when "Monitor/Staging" can't merge
publish automatically. I suppose in that case I'll have something to worry about, and in the worst case, no changes will publish to production, which could cause annoyance, but sounds like safe default behavior.
If you see any problems with this setup, please don't keep them to yourself!
In 2014 Jason Fox of neverstopbuilding.com wrote about how he used Heroku to run a little blog updating application that wakes up on a schedule and tries to publish queued-up posts. He used this article as a jumping-off point. Finally, after two years of looking, I found Jason's article and adapted his approach for myself, rather than needing to run own custom process on a custom server somewhere. I plan to replace this sentence with details on how I did it and a link to a repository you can use as the starting point for solving this problem for yourself. If I haven't done this by December 1, 2014, then tell me that I haven't done it yet. Be sure to link to this article.