Ellis Michael

Using Travis CI with Github Pages

12 Jun 2015

I’ve been using GitHub Pages for my personal website for some time now. Since I’ve never needed dynamic content, GitHub has been a perfect solution. It’s simple to use and free. GitHub will either serve a completely static site or a Jekyll site, which it automatically generates.

Travis CI is a popular testing and deployment service. You can use it to generate and deploy your website to GitHub Pages instead of using GitHub’s automatic Jekyll generator.

Why use Travis?

Most of the time, using Travis is not necessary. Vanilla Jekyll works quite well and has most of the features that you’d want out of a static site generator. However, GitHub Pages only allows the use of a limited number of Jekyll plugins and runs Jekyll builds in safe mode. If you want to use Jekyll plugins other than the ones available on GitHub Pages, use your own custom plugins, or generate parts of your site by non-Jekyll means, then you should consider using Travis to automatically do the job.

My original impetus for switching to Travis was that I wanted the generation process for my website to generate my resume automatically, which gets built from a YAML file using LaTeX and a Python script. However, now that I’m free from GitHub Pages’ limitations, I’m considering switching from Jekyll to Pelican because I like Jinja templates better than Liquid.

Making the Switch

The first thing you need to do is create a new branch, as the generated site will eventually get put into the GitHub Pages branch (either gh-pages or master depending on the type of repo). Call the new branch source (or maybe pages-source if you prefer).

$ git checkout -b source

Next, you’ll want to enable Travis for the repo. You can do so here.

You should then create a file called .travis.yml in the root of your repository in the new source branch.

Configuring Travis

Your .travis.yml file tells Travis what to do. You’ll use it to install your site’s dependencies, build your site, and then push the generated site back to GitHub.

Authenticating Travis with GitHub

In order for Travis to be able to push your site to GitHub, it will need to authenticate with GitHub. Travis has built in encryption tools which allow you to encrypt some secret which only the Travis build agent for your repo will be able to decrypt. Then, you can upload the encrypted secret to a public repo without fear that you’re giving everyone access they shouldn’t have.

Some people have suggested using an encrypted GitHub Personal Access Token. This is a decent solution, but the problem is that the permissions settings for access tokens are too coarse. They only allow you to determine whether or not the token has access to all your public repos and all your private repos. Instead, a better solution is using a deploy key on the repository. If that key somehow gets compromised, the most anyone will have access to is a single repo.

First, you’ll have to generate the key.

$ ssh-keygen

Name the file .travisdeploykey and do not put a password on the key. Upload the public key (in .travisdeploykey.pub) to your repo (Settings > Deploy keys). Now, encrypt the private key. You’ll need the Travis client installed to do that.

$ gem install travis

Then, encrypt the file.

$ travis encrypt-file .travisdeploykey

This will output the .travisdeploykey.enc file and print out a command to be added to the build script. Save that print out and add .travisdeploykey.enc to your repo. Do NOT add the unencrypted private key to the repo. If you already did, remove the public key from the repo, and start over with a new key. If not, you can go ahead and delete the private key as well as the public key.

The Build Script

Copy the following to .travis.yml

install:
  - gem install jekyll
before_script:
  # Replace with the line that travis encrypt-file printed out
  - openssl aes-256-cbc ...
  - chmod go-rwx .travisdeploykey
  - eval `ssh-agent -s`
  - ssh-add .travisdeploykey
  - git config user.name "Travis-CI"
  - git config user.email "noreply@travis-ci.org"
  - COMMIT_MESSAGE="Publishing site on `date "+%Y-%m-%d %H:%M:%S"` from
    `git log -n 1 --format='commit %h - %s'`"

script:
  - set -e
  - make # Or jekyll build or whatever command you use to generate your site
  - git checkout -b master # Replace master with gh-pages if applicable
  - git add -f _site/ # Replace _site/ with the build's output directory
  - 'git commit -m "${COMMIT_MESSAGE}"'
  - git filter-branch -f --subdirectory-filter _site/ # Again, replace _site/
  # Obviously, replace with your repo's SSH URL and the appropriate branch
  - git push -f YOUR_REPOS_SSH_URL master:master

branches:
  only:
    - source

If you have any other dependencies to install (e.g. Python packages), you should add the necessary commands under install. Otherwise, once you make the appropriate adjustments to .travis.yml, you should be good to go!

Final Notes

Caveat user: debugging your install script and adding all of the dependencies can be a somewhat frustrating process, especially if the dependencies take a while to install. You might find yourself making a change, pushing that change to the repo to kick off a Travis build, and then waiting 5 minutes only to find out that something else went wrong.

Now that you’re building your site with Travis, you don’t need GitHub to build it with it’s built-in Jekyll support. By default, GitHub will only invoke Jekyll if there is a _config.yml file present, but if you want, you can go one step further and add a .nojekyll file to the site. If you’re still using Jekyll, then you’ll need to add the following to _config.yml.

include:
  - .nojekyll