Deploying Pelican Sites Using Travis CI

After learning about Travis CI through browsing open-source projects on GitHub, I became interested in seeing if it was possible to incorporate it into my already existing workflow based on GitHub Pages. Even though Pelican is a static site generator, adding Travis CI into the mix would allow changes to the theme or content to be made from anywhere that can push to a Git repository — even directly from the GitHub website — and the newly generated files would be pushed to the live server in a fairly timely manner, almost like a WordPress site. Thankfully, quite a few other people had already combined Pelican and Travis CI, so setting it up was fairly straightforward.

Most of the solutions that I found suggested using the ghp-import package to handle pushing to the GitHub repository. I was not satisfied with this solution as I wanted to keep intact the incremental changes being tracked by the repository itself (one of the upsides of using GitHub Pages as a host, in my opinion). I came across Andrea Zonca’s post, which described a setup using rsync and git clone to update the branch. Since his blog post is written in a very detailed manner, I won’t rewrite it here verbatim. In short:

  1. Add .travis.yml (which describes to Travis how to build your project) and requirements.txt (which lists the packages to be installed via pip) to the source file branch of your site’s repository.
  2. Create an OAuth token from your GitHub applications page which gets used by Travis to push changes to the GitHub Pages branch of your repository.
  3. Install the travis gem and encrypt the OAuth token using the travis encrypt command.
  4. Enable Travis CI for the repository and push changes.

The travis.yml file works in stages. The install stage issues a pip install command which references requirements.txt for the list of packages to install. After that comes the script stage, which serves as the actual build phase for the project. Most projects would run tests here, but in this case, it executes the pelican command in order to generate the static site files. Following the build, after_success can be given commands to run which are executed after the build itself, and this is when new site files are pushed to the GitHub repository.

One of the issues that I ran into in the process of setting this up was installing the travis gem, which is needed to encrypt the OAuth token that allows Travis to push to the GitHub repository. What ended up solving the problem in the end was updating the version of Ruby on my computer.

Since I liked some of the features that I had previously included in my site generation Bash script, I rewrote Andrea’s deploy.sh script to work similarly to my existing workflow. The entirety of the file can be found in the GitHub repository of my website’s source. My rewritten script grabs the hash and message of the most recent commit to the source branch:

#!bash
commitHash=`git rev-parse HEAD`
commitMessage=`git log -1 --pretty=%B`

These variables are used during the git commit command to create a descriptive commit message. The commit message in the source branch is used as the first line of the commit message, and the commit hash and Travis build number are included as the extended part of the commit message:

#!bash
git commit -m "$commitMessage" -m "Generated by commit $commitHash; pushed by Travis build $TRAVIS_BUILD_NUMBER."

There are a few minor changes I made to the rsync and git commands of Andrea’s script as well. Within the rsync command, I removed the asterisk from the source directory and added the --delete flag to instruct the script to delete files in the destination directory that are not present in the source directory. Simply adding the --delete flag to the version of the command present in Andrea’s script will not affect the command as a result of the to the wildcard search caused by the asterisk:

#!bash
rsync -r --exclude=.git --delete ../$PELICAN_OUTPUT_FOLDER/ ./

I also changed the flag on git add to -A in order to stage deleted files as well as added and modified ones and added the git status -s command which echos a nice overview of what changes were actually staged (which gets stored in Travis’ build logs):

$ git status -s
A  2014/06/deploying-pelican-sites-using-travis-ci/index.html
A  2014/06/index.html
M  2014/index.html
M  archive/index.html
M  index.html

Since my version of deploy.sh was based on the script that I used to test and deploy changes locally, I wrote it so that it could be executed from a local development machine by checking against the $TRAVIS variable. When run locally, it can be used to check what changes would be pushed to the GitHub Pages branch given the modifications that have been made locally. In practice, it wouldn’t ever be useful to push changes manually since Travis would automatically repeat the exact same steps, but if the integration between GitHub and Travis were to ever stop working, I would still have a way to make modifications to the GitHub Pages branch.