Yet Another Octopress2.0 + TravisCI Guide

So there’s only about 30 50 thousand pages on this general topic, but I found that about half of them were out of date, so I figured I should try and collect all the info into one big post. I’ve referenced where I’ve found some of the stuff that’s harder to find from Googling using the wonders of Octopress footnotes.

Unfortunately, as I was finishing up this post, the post announcing Octopress 3.0 comes out. While I had known it was coming, I wasn’t expecting it to be so soon. Obviously this post will be less useful, but it should still be informative. I’ve included what I think will need to be modified to function on 3.0 at the bottom.

My Site Flow

  • Local
  • Private Github Repo
  • Built and Deployed using TravisCI to a DigitalOcean droplet

I’ve got a drafts workflow using a couple tasks I found online1 and then promptly modified:

## -- Misc Configs -- ##

drafts_dir      = "_drafts" # directory for draft files

# usage rake new_draft[my-new-draft] or rake new_draft['my new draft'] #
desc "Begin a new draft in #{source_dir}/#{drafts_dir}"
task :new_draft, :title do |t, args|
if args.title
title = args.title
title = get_stdin("Enter a title for your post: ")
raise "### You haven't set anything up yet. First run `rake install` to set up an Octopress theme." unless
mkdir_p "#{source_dir}/#{drafts_dir}"
filename = "#{source_dir}/#{drafts_dir}/#{title.to_url}.#{new_post_ext}"
if File.exist?(filename)
abort("rake aborted!") if ask("#{filename} already exists. Do you want to overwrite?", ['y', 'n']) == 'n'
puts "Creating new draft: #{filename}"
open(filename, 'w') do |post|
post.puts "---"
post.puts "layout: post"
post.puts "title: \"#{title.gsub(/&/,'&')}\""
post.puts "comments: true"
post.puts "#placeholder"
post.puts "categories: "
post.puts "---"

# usage rake publish_draft
desc "Select a draft to publish from #{source_dir}/#{drafts_dir} on the current date."
task :publish_draft do
drafts_path = "#{source_dir}/#{drafts_dir}"
drafts = Dir.glob("#{drafts_path}/*.#{new_post_ext}")
drafts.each_with_index do |draft, index|
content =
if content =~ /\A(---\s*\n.*?\n?)^(---\s*$\n?)/m
data = YAML.load($1)
rescue => e
puts "Error reading file #{draft}: #{e.message}"
rescue SyntaxError => e
puts "YAML Exception reading #{draft}: #{e.message}"
puts "  [#{index}]  #{data['title']}"
puts "Publish which draft? "
answer = STDIN.gets.chomp
if /\d+/.match(answer) and not drafts[answer.to_i].nil?
mkdir_p "#{source_dir}/#{posts_dir}"
source = drafts[answer.to_i]
filename = source.gsub(/#{drafts_path}\//, '')
dest = "#{source_dir}/#{posts_dir}/#{'%Y-%m-%d')}-#{filename}"
puts "Publishing post to: #{dest}" { |source_file|
  contents =
  contents.gsub!(/^#placeholder$/, "date: #{'%Y-%m-%d %H:%M %z')}"), "w+") { |f| f.write(contents) }
puts "Index not found!"

For this to work using rake preview, you’ll need to modify your preview task slightly, add the flag --drafts to the jekyll call.

system "compass compile --css-dir #{source_dir}/stylesheets" unless File.exist?("#{source_dir}/stylesheets/screen.css")
jekyllPid = Process.spawn({"OCTOPRESS_ENV"=>"preview"}, "jekyll build --watch --drafts")
compassPid = Process.spawn("compass watch")

The Build Process

Personally, I don’t want to have to deal with building and uploading my site. Instead I use Travis-CI targeted to a specific Github repo branch, and some modified rsync scripts.

language: ruby
cache: bundler

- 1.9.3
- master

- echo -e "Host *\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config
- echo -e "$DEPLOY_PRIVATE_KEY" > ~/.ssh/id_rsa
- chmod 600 ~/.ssh/id_rsa
- eval `ssh-agent -s`
- ssh-add ~/.ssh/id_rsa

- bundle exec rake integrate #move any stashed posts to source
- bundle exec rake generate #generate static to /public
- bundle exec rake deploy #rsync /public to server

Rsync Setup

Where to put the key.

You’ll need to configure your deployment account’s SSH private key in Travis-CI by replacing all new lines with \n, and then escaping that to \\n, so that it ends up being one line with \\n in between each original line.2 (NOTE: Make sure the key was generated without ssh-agent running, and set a blank passphrase.) Next, go to your Travis-CI settings, create a new environment variable, name it whatever you want, I used $DEPLOY_PRIVATE_KEY, then paste in your one-line private key into the variable section. Now that it’s a environment variable in all Travis workers your builds will use, the before_install tasks will disable strict host key checking (requires input, which Travis doesn’t allow), and then echo the contents of DEPLOY_PRIVATE_KEY to id_rsa, then add that key to the ssh-agent, in my case, allowing the worker to connect using the user travis-ci to my droplet.

If the user you’re connecting with in your Rakefile’s settings isn’t the owner of your specific directories on your hosting server, rsync will probably fail to sync properly. In that case, you’ll need to add --omit-dir-times to rsync-args in the Rakefile.

After all of this, you should be good to go. If you’re using the master deploy method, push your site up to master, and it should build properly on Travis, and deploy to your rsync destination.

Octopress 3.0

For the most part, as far as I can tell, these modifications will mostly still work for 3.0. The drafts changes will no longer be needed anymore, as the Jekyll drafts workflow is now using a separate drafts folder. The .travis.yml will need to be tweaked slightly, as well as the _config.yml having an exclude added to keep Jekyll running on Travis-CI from trying to build the templates in /vendor, but other than that, this post is mostly forwards compatible to Octopress 3.0.

Related Posts

A Change to Travis

Porting to Jekyll 3.0 & Octopress 3.0

LSI on Travis

Pubster for Atom

Thoughts on Tay – a Postmortem

Tubster Syntax - Atom

pa11y – a Work in Progress Atom Theme

YOURLS Hexadecimal