Automatically deploy a bookdown ebook with GitHub actions
In this post, I’ll walk you (or future me 👋 😉) through getting a bookdown-generated ebook to automatically deploy as a static website (using GitHub pages) any time you make changes to your GitHub repository (using GitHub actions). This guide is intended to get you started with a (mostly) minimal example.
This guide assumes familiarity with each of the tools and services that we’ll use; I’m just here to help you duct tape them all together ☺️!
TL;DR: See this GitHub repository for the fully functional demo.
Ingredients 🍲
- bookdown is an R package that can generate an ebook (or pdf, Word doc, etc.) from a collection of R markdown (and vanilla markdown) documents.
- R markdown supports a wide range of languages in addition to R (e.g., Python, Julia, etc.)
- GitHub - we’ll use a GitHub repository to store our bookdown-enabled project.
- GitHub Pages - we’ll use GitHub pages to host our bookdown-generated ebook.
- Github actions - we’ll use GitHub actions to automatically build and deploy our ebook to GitHub pages when changes are made to the GitHub repository.
- docker - we’ll compile our ebook using a docker container loaded with the requisite dependencies.
Step 1. Setting up our bookdown ebook
Make a new GitHub repository, and inside of it, we’ll pull together a minimal-working book that we can compile locally. The files below are a modified subset of the files in the canonical bookdown demo. You’ll need to install all of bookdown’s prerequisites if you want to be able to build your book locally (which is useful for debugging).
index.Rmd
will define the first page of our ebook. This will also be the landing page for our GitHub pages site.
---
title: "An automatically deploying ebook"
author: "Alexander Lalejini"
date: "`r Sys.Date()`"
output: bookdown::gitbook
documentclass: book
github-repo: amlalejini/auto-deploying-bookdown-example
description: "This is a demo for automatically deploying your bookdown ebook to GitHub pages."
---
# Introduction
Check out the GitHub repository with all the gears and levers to generate this example: <https://github.com/amlalejini/auto-deploying-bookdown-example>.
_bookdown.yml
contains general configuration for our bookdown build.
book_filename: "demo"
language:
ui:
chapter_name: "Chapter "
delete_merged_file: true
rmd_files: [
"index.Rmd"
]
_output.yml
species configuration details for particular output types. Documentation here.
bookdown::gitbook:
css: style.css
split_by: "chapter"
citation_package: natbib
config:
toc:
before: |
<li><a href="./">Auto-deploy Example</a></li>
after: |
<li><a href="https://github.com/rstudio/bookdown" target="blank">Published with ❤ and bookdown</a></li>
edit: https://github.com/amlalejini/auto-deploying-bookdown-example/tree/main/%s
download: ["pdf"]
bookdown::pdf_book:
latex_engine: pdflatex
citation_package: natbib
keep_tex: yes
split_by: "chapter"
style.css
gives custom styling for the HTML output. The file below is pulled directly from the canonical bookdown demo.
p.caption {
color: #777;
margin-top: 10px;
}
p code {
white-space: inherit;
}
pre {
word-break: normal;
word-wrap: normal;
}
pre code {
white-space: inherit;
}
build_book.sh
is a convenience script that will build our ebook using bookdown. This script is modified from the build script in the canonical bookdown demo.
#!/bin/sh
set -ev
Rscript -e "bookdown::render_book('index.Rmd', 'bookdown::gitbook')"
Rscript -e "bookdown::render_book('index.Rmd', 'bookdown::pdf_book')"
Running build_book.sh
should compile your bookdown book into both an HTML and pdf document. Run python -m http.server
for local viewing!
Adding references using bibtex
Want to incorporate references? How about citing all of the packages that you used to compile your book? Easy!
book.bib
will hold the bibtex references we want to cite. E.g.,
@book{xie_r_2019,
address = {Boca Raton},
title = {R {Markdown}: the definitive guide},
isbn = {978-0-429-78296-1},
shorttitle = {R {Markdown}},
publisher = {CRC Press, Taylor and Francis Group},
author = {Xie, Yihui and Allaire, J. J. and Grolemund, Garrett},
year = {2019},
keywords = {Computer programs, Markdown (Document markup language), R (Computer program language), Web site development},
}
You can cite things in text like [@xie_r_2019]
tail.Rmd
will define the references section at the end of our ebook.
`r if (knitr::is_html_output()) '# References {-}'`
```{r, include=FALSE}
knitr::write_bib(c(.packages(), "bookdown"), file="packages.bib")
```
You’ll also notice that tail.Rmd
writes out packages.bib
, which will contain bibtex entries for all of the R packages used to generate your bookdown book.
You’ll also want to modify the front matter at the top of index.Rmd
to configuration the bibliography:
---
title: "An automatically deploying ebook"
author: "Alexander Lalejini"
date: "`r Sys.Date()`"
output: bookdown::gitbook
documentclass: book
bibliography: ["book.bib", "packages.bib"]
biblio-style: apalike
nocite: '@*'
link-citations: yes
github-repo: amlalejini/auto-deploying-bookdown-example
description: "This is a demo for automatically deploying your bookdown ebook to GitHub pages."
---
The nocite: '@*'
line tells bookdown to add everything from book.bib
and packages.bib
to the references section regardless of whether or not it was actually cited in text.
All of these example files can also be found on GitHub: https://github.com/amlalejini/auto-deploying-bookdown-example.
Step 2. Setting up a Dockerfile to run bookdown
With our ebook compiling locally, we want to specify a docker image with the requisite environment to compile everything.
Dockerfile
# Pull a base image
FROM ubuntu:20.04
# Copy everything (minus anything specified in .dockerignore) into the image
COPY . /opt/auto-deploying-bookdown-example
# To make installs not ask questions about timezones
ARG DEBIAN_FRONTEND=noninteractive
ENV TZ=America/New_York
##############################
# install base dependencies
# - for R repository
# - dirmngr
# - gpg-agent
# - for bookdown compilation
# - pandoc, pandoc-citeproc, texlive-base, texlive-latex-extra
##############################
RUN \
apt-get update \
&& \
apt-get install -y -qq --no-install-recommends \
software-properties-common \
curl=7.68.0-1ubuntu2.4 \
g++-10=10.2.0-5ubuntu1~20.04 \
make=4.2.1-1.2 \
cmake=3.16.3-1ubuntu1 \
python3=3.8.2-0ubuntu2 \
python3-pip \
python3-virtualenv \
git=1:2.25.1-1ubuntu3 \
dirmngr \
gpg-agent \
pandoc \
pandoc-citeproc \
texlive-base \
texlive-latex-extra \
lmodern \
&& \
echo "installed base dependencies"
########################################################
# install r with whatever r packages we need/want
# - source: https://rtask.thinkr.fr/installation-of-r-4-0-on-ubuntu-20-04-lts-and-tips-for-spatial-packages/
########################################################
RUN \
gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys E298A3A825C0D65DFD57CBB651716619E084DAB9 \
&& \
gpg -a --export E298A3A825C0D65DFD57CBB651716619E084DAB9 | apt-key add - \
&& \
apt update \
&& \
add-apt-repository 'deb https://cloud.r-project.org/bin/linux/ubuntu focal-cran40/' \
&& \
apt-get install -y -q --no-install-recommends \
r-base=4.0.3-1.2004.0 \
r-base-dev \
libssl-dev \
libcurl4-openssl-dev \
libfreetype6-dev \
libmagick++-dev \
libxml2-dev \
libfontconfig1-dev \
cargo \
&& \
R -e "install.packages('rmarkdown', dependencies=NA, repos='http://cran.rstudio.com/')" \
&& \
R -e "install.packages('knitr', dependencies=NA, repos='http://cran.rstudio.com/')" \
&& \
R -e "install.packages('bookdown', dependencies=NA, repos='http://cran.rstudio.com/')" \
&& \
R -e "install.packages('tidyverse',dependencies=NA, repos='http://cran.rstudio.com/')" \
&& \
R -e "install.packages('cowplot',dependencies=NA, repos='http://cran.rstudio.com/')" \
&& \
echo "installed r and configured r environment"
########################################################
# build supplemental material (will also run data analyses)
########################################################
RUN \
cd /opt/auto-deploying-bookdown-example \
&& \
./build_book.sh \
&& \
echo "compiled bookdown ebook
This Dockerfile assumes that everything you need to build your bookdown site is inside your GitHub repository. What if you need data that you don’t want to add to your GitHub repository (e.g., too big/too much)?
Using data stored on OSF
Downloading data stored on the Open Science Framework into your docker image is easy using the osfclient python package.
E.g., in your Dockerfile
before running the build_book.sh
script, add something along the lines of:
########################################################
# install osfclient, use to download project data
########################################################
RUN \
pip3 install osfclient \
&& \
export OSF_PROJECT=w95ne \
&& \
export PROJECT_PATH=/opt/auto-deploying-bookdown-example/ \
&& \
osf -p ${OSF_PROJECT} fetch data.tar.gz ${PROJECT_PATH}/data.tar.gz \
&& \
tar -xzf ${PROJECT_PATH}/data.tar.gz -C ${PROJECT_PATH}/ \
&& \
echo "download"
Step 3. Using GitHub actions to automatically build and deploy your ebook
Now that we have a Dockerfile that specifies how to build our ebook, we can wire up some GitHub actions to watch our repository for new commits, build our ebook, and deploy to github pages.
First, turn on GitHub pages for your repository (under the repo’s Settings tab).
Select the gh-pages
branch, and save the changes.
Next, we need to tell GitHub not to use jekyll to generate your site because we’ll be generating the site ourselves using bookdown. All you need to do is add an empty .nojekyll
file to your gh-pages branch. You can do this manually or directly on GitHub with the Add file button.
Finally, we’re ready to add a workflow (.github/workflows/deploy-bookdown.yml
) to our GitHub repository that will string together GitHub actions to automatically build and deploy our bookdown site.
.github/workflows/deploy-bookdown.yml
name: Build and deploy to GitHub Pages
on:
push:
branches:
- master
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v2
with:
persist-credentials: false
- name: docker build
run:
|
docker build . --file Dockerfile --tag example
docker container create --name pages_build example:latest
docker cp pages_build:/opt/auto-deploying-bookdown-example/_book ./_book
- name: deploy to github pages
uses: JamesIves/github-pages-deploy-action@3.7.1
with:
GITHUB_TOKEN: $
BRANCH: gh-pages # The branch the action should deploy to
FOLDER: _book # The folder the action should deploy
CLEAN: true # Automatically remove deleted files from the deploy branch
Done!
You can check out the Actions tab on your github repository to see the output log resulting from your workflow. E.g., for this example repository.
Useful resources
- bookdown
- Bookdown has really good documentation in the form of a bookdown-generated ebook, bookdown: Authoring Books and Technical Documents with R Markdown
- bookdown demo GitHub repository
- GitHub actions/workflows
- GitHub’s learning lab has fantastic interactive tutorials for working with all sorts of GitHub features, including actions!