Permalink
Browse files

New post, plus trying some extra .gitignore

  • Loading branch information...
nealrichardson committed May 24, 2017
1 parent 042f4fc commit 8b11e195b6782ca791835bbbede54462ac14489e
View
@@ -1,2 +1,4 @@
public/*
themes/*
content/post/*.html
static/post/*_files/*
View
@@ -0,0 +1,7 @@
---
title: ""
description: ""
categories: []
tags: []
draft: false
---
@@ -0,0 +1,112 @@
---
title: "Using Travis-CI to Build Blogdown"
description: "Automate the building and publishing of your R Markdown static site with Travis-CI and GitHub Pages."
date: "2017-05-23T21:49:57-07:00"
categories: ["general"]
tags: ["travis-ci", "automation", "meta"]
draft: false
---
Over on the Crunch.io dev blog, I wrote about how we used Travis-CI to automate the building of our various static sites. I thought I'd do the same for my personal blog, though with one twist: using R and the [blogdown](https://github.com/rstudio/blogdown) package on top of Hugo.
The thread on [this issue](https://github.com/rstudio/blogdown/issues/26) in the blogdown repository pointed to [Yihui's guide to building bookdown pages on Travis](https://bookdown.org/yihui/bookdown/github.html), as well as a project that had [adapted](https://github.com/curso-r/verao2017) that flow for `blogdown`. Both were helpful, and combined with my experience building other non-blogdown sites on Travis, I was able to simplify and improve on those examples. It was shockingly straightforward.
This post outlines the steps I took to automate the Hugo/blogdown build on Travis-CI. It starts from the point of having already installed blogdown locally, created the Hugo project, played around with themes and customization, and having something serving locally that's worth deploying. It assumes that you have a GitHub account and have used Travis before (surely you have continuous integration running on your code projects, right?).
There are three main steps: setting up your repository on GitHub and Travis-CI, adding the build script, and setting up your GitHub API token access.
# Setup on GitHub, git, and Travis-CI
First, we need to [create a new repository on GitHub](https://github.com/new). Then, initialize a git repository locally and link it with your new repo on GitHub:
git init
git remote add origin git@github.com:nealrichardson/nealrichardson.github.io.git
of course, substituting in your user/organization name and repository name. (GitHub will tell you the exact code to run after you create the repository there.)
Next, go to [Travis](https://travis-ci.org/profile) and enable Travis to run on your new GitHub repository. You'll have to click the "sync" button in order for the new project to show in the list if you just created it.
## User page vs. project page
For a typical repository on GitHub, the usual way GitHub Pages are supported is on a `gh-pages` branch, though there are some options. However, if this is your [user or organization page](https://help.github.com/articles/user-organization-and-project-pages/), the static site must be on `master` branch. So, I put my markdown and blogdown/Hugo code on a `src` branch, and will use Travis to build from that and push the generated site to `master`.
Given that I already had started the project locally, and I'd done `git init`, I created the `src` branch before committing my initial blog code:
git checkout -b src
git add .
git commit -m "Initial commit"
and then checked out `master` and pushed an empty README.md file up there, just so the branch would exist on GitHub. Travis will need it to exist in order to start pushing to it.
# Add some files
## .travis.yml
The .travis.yml file is where the action happens—it's what tells Travis what to do. The examples I found for using Travis to build bookdown or blogdown sites followed the model of putting "build" and "deploy" logic into Bash scripts, which the .travis.yml file makes executable ([which you could instead do through git](http://stackoverflow.com/a/38285462)) and then calls. I found this unnecessarily indirect. Travis treats the YAML file like a script anyway, so you can just enter the shell commands you want to run there. That way, you can look in one file to see everything that is happening.
[My .travis.yml](https://github.com/nealrichardson/nealrichardson.github.io/blob/src/.travis.yml) is grouped into a few sections. To start, it sets the language/container type to "R" and indicates that packages should be cached for faster repeat building. Second, this block
branches:
only:
- src
tells Travis only to build when I push to my `src` branch. I want to be free to make other branches in my repository and not have them trigger a build of my site—that could lead to very unexpected changes! Moreover, on success, Travis will be pushing to the `master` branch, and I don't want that push to attempt a re-build of the site.
Next, the YAML file directs the installation of the blogdown package from GitHub using the `r_github_packages` block. It's not yet on CRAN, so GitHub is the way, and while you can (and others may) specify that it be installed via the DESCRIPTION file using some `devtools` special hooks, I've had success installing GitHub packages on Travis this way in the past, and it worked here too.
I grouped the main action in .travis.yml into a `before_script` block and a `script` block, but that's purely for aesthetics. The "before" block sets my GitHub user name and email—the `git commit` will need them—installs Hugo via blogdown, and then adds my Hugo theme. You could use the `blogdown::install_theme` function, but all you need it to do is checkout the theme repository to your "themes" directory, so I just do that directly.
At that point, building the site is just `R -e 'blogdown::build_site()'`. That's it.
The last step is to commit the built site to a different branch, in this case "master", and push that. Even though the Travis job has already cloned your repository from GitHub to start the build, it has only cloned the current branch, so `git checkout master` won't work. To change branches, we have to do a fresh `git clone`.
Note that the `clone` command involves a `GH_TOKEN` environment variable. That's your API token—we'll discuss that below.
On the `git push`, I have the output redirected to `/dev/null`. I saw this suggested before when I was setting up my sites at work because without a quiet push, the Travis log would reveal the GitHub API token that was encrypted in the YAML file (see below). It turns out that this was a [security vulnerability](https://blog.travis-ci.com/2017-05-08-security-advisory) that Travis has since fixed, but I've left the redirection in there for extra comfort.
## DESCRIPTION
Because we're going to use an R language build on Travis, the job will expect that we're testing an R package, so we need a DESCRIPTION file. In practice, it is useful for installing packages your R code will need, and ostensibly for installing `blogdown` itself. But since I installed blogdown in the .travis.yml file, and I'm just starting the blog and don't have any meaningful R code to run on it, there aren't any other dependencies to install. So, [my DESCRIPTION](https://github.com/nealrichardson/nealrichardson.github.io/blob/src/DESCRIPTION) is pretty empty. But it exists.
## .gitignore
For Hugo projects, you want to .gitignore the "themes" directory because they aren't really part of your project; you add your customization of templates and stylesheets on top of a theme. I also like to ignore the "public" directory where the build static site gets written—the build on Travis will overwrite it anyway.
By that logic, you may also want to ignore the `static/post` directory where blogdown appears to write generated images and other artifacts from the .Rmd code, and `*.html` from the `content/post` directory, which is the built version of the .Rmd files. I don't have enough experience with blogdown at this point to be sure, though.
# Add GitHub API token
As mentioned above, you need to [generate a GitHub API token](https://github.com/settings/tokens) so that your job on Travis is authorized to push. The page will give you a bunch of checkboxes for authorization scopes to give to the token, but you only need to select the `public_repo` scope.
Token in hand, encrypt it and add it to your YAML file using Travis's Ruby library. To install that library,
gem install travis
You only need to install this the first time you deal with adding encrypted variables to Travis. In using the utility
([instructions here](https://docs.travis-ci.com/user/encryption-keys/)), note that you're not just encrypting the API token, you're encrypting the pair of `NAME=tokenstring`. As mentioned above, I'm using `GH_TOKEN` as the environment variable name, so, in the project directory, run:
travis encrypt GH_TOKEN=token --add
where `token` is the string copied from the GitHub page when the token was generated. The `--add` flag will add the result to the .travis.yml file for you.
While clearly this step has to happen before you can proceed with your build, I put it last in this discussion because some of the steps outlined above have to happen first. You can't run `travis encrypt --add` until you've enabled Travis on your repository (on travis-ci.org), and you have to have done `git remote add origin` so that your local repository points to the same project that Travis is expecting.
Once you've done all this, commit and `git push` your blogdown code and Travis config. You can now ~~go to the Travis site and watch the build run~~ forget about it and trust that your site is being built for you—that's the point of automating it!^[If the build fails, as in when you're setting it up or adding a new dependency, Travis will notify you by email. No news is good news.]
# Conclusion
Given that `blogdown` is a relatively new tool, I expected that using it would show some rough edges, and that trying to build it on Travis would be challenging. It took me ten attempts to figure out the build automation for our Hugo blog at Crunch. I'd hoped I'd learned a few things about how to use Travis for static sites and could do better this time, but adding R to the mix was a complication.
In the end, it was a breeze. I got the site built in only four commits this time, all trivially tweaking the setup to install blogdown itself. The complications I feared—having to install go and Hugo on top of a container configured to run R—were seamlessly handled by blogdown.
And finally, to demonstrate that this post is R Markdown and not regular markdown, here's Figure \@ref(fig:pie) from the example site that `blogdown` generates.
```{r pie, fig.cap='A fancy pie chart.', tidy=FALSE}
par(mar = c(0, 1, 0, 1))
pie(
c(280, 60, 20),
c('Sky', 'Sunny side of pyramid', 'Shady side of pyramid'),
col = c('#0292D8', '#F7EA39', '#C4B632'),
init.angle = -50, border = NA
)
```

This file was deleted.

Oops, something went wrong.

This file was deleted.

Oops, something went wrong.

This file was deleted.

Oops, something went wrong.
View
@@ -0,0 +1,10 @@
---
categories: ["general"]
date: 2017-05-22T21:11:48-07:00
description: ""
draft: false
tags: []
title: "This Is a Blog"
---
This page left intentionally blank.

This file was deleted.

Oops, something went wrong.

This file was deleted.

Oops, something went wrong.
Binary file not shown.
Binary file not shown.

0 comments on commit 8b11e19

Please sign in to comment.