Quick GitHub Actions for your R package

The Actions tab of the a GitHub repository showing successful tests with tick marks next to them.

A GitHub Action in action on GitHub.

tl;dr

You can trigger GitHub Actions to build and test your R package after a push or pull request. Create .github/workflows/ in your repo and add pre-prepared actions by the r-lib team with usethis::use_github_action().

Lights, camera…

GitHub Actions is a service that can be triggered to run workflows that build, test and deploy your code on GitHub. In other words, a continuous integration platform baked right into GitHub.

Before you start, I recommend checking out Jim Hester’s talk from rstudio::conf 2020 and reading the GitHub Actions with R book.

GitHub Actions can be really helpful for developing R packages. For example, you can trigger actions with a push or pull request (PR) that:

Checking the build and coverage are standard practices for package development. They help ensure that your package works and is stable. GitHub Actions provides the icing on the cake by doing these things automatically.

I wrote this post to remind me how to do it.

…Actions

How are actions stored, recognised and triggered?

Actions are expressed in YAML script files that read like a recipe for what to run and when to run it. You put these files in your repo at the path .github/workflows/, where GitHub recognises them. The information is interpreted and the actions are run remotely given the specified trigger.

You can learn more about the content of these YAML files from the GitHub actions with R book.

You could set these up manually, but actually you can shortcut the process with the {usethis} package and some pre-written examples.

{usethis} and r-lib

{usethis} helps to shortcut the tedious setup steps of R packages and projects. It also includes functions to add GitHub Actions to your R package for you.

In particular, usethis::use_github_action() will add a GitHub Action YAML file; you just supply the name of a pre-written action.

Where do these pre-written actions come from? Well, the kind folks at r-lib have made a repo of R-focused examples that you can use.

Example: {r2eng} package

I recently used this method to set up GitHub Actions for the in-development {r2eng} package.

The first step was to create the folder .github/workflows/ where the YAML files will be added for GitHub Actions to find them.

{r2eng} has three actions in the workflow folder:

This is a typical, minimal set of actions that suit me when developing R packages. Let’s talk them through.

Build check

An R CMD check1 runs a bunch of tests on your package (including your own unit tests) and returns errors, notes and warnings. You’re aiming for a passing build to prove the package is up to scratch.

{usethis} has three actions-related functions specifically for setting up the build check. The standard one will run the R CMD check on macOS, Linux and Windows to make sure it passes across all these platforms.2

Run this line to add the R-CMD-check.yaml action to the .github/workflows/ folder:

usethis::use_github_action_check_standard()

On a push or PR, GitHub Actions will automatically set up and run the build check on each OS to make sure the package meets the requirements.

Coverage

The R CMD check runs your unit tests, but it doesn’t calculate how much of your code is actually covered by testing. Ideally you want this to be 100%, but also bear in mind that the metric doesn’t take account of the volume or quality of tests.

Add the action to your repo with:

usethis::use_github_action("test-coverage")

On push or a PR, the coverage of the tests is evaluated with the {covr} package, another r-lib package. The results are then uploaded to the Codecov site for everyone to see.

For example, the Codecov page for {r2eng} shows the percentage of coverage, a breakdown of the lines ‘hit’ and ‘missed’, and the commits that led to checks.

{pkgdown} site

{pkgdown} is yet another r-lib package that makes it easy to turn your package’s documentation into a customisable website. People can then access the help files and vignettes online.

The steps for setting up a {pkgdown} site with GitHub Actions are laid out clearly in the GitHub Actions with R book. In short, you don’t want the files associated with your site to be part of the R package itself, so you set them up in an empty ‘gh-pages’ branch instead.

The site files can be added to this branch with usethis::use_pkgdown(). To serve with GitHub pages, go to that section in the repo settings and set the source to the ‘gh-pages’ branch. Here’s the example website for the {r2eng} package.

The GitHub Action can then be added to the main branch of your repo with:

usethis::use_github_action("pkgdown")

On push, the site will be rebuilt in the ‘gh-pages’ branch and the site will be updated when you navigate to it online.

Tickety-boo

You’ll get the full results of the actions in the ‘Actions’ tab of your repo on GitHub. A successful check gets a satisfying tick next it. A failing test gets a cross. You can select a result and expand the results to trace exactly what the error was.

The Actions tab of the a GitHub repository showing successful tests with tick marks next to them.

Successful builds in the ‘pkgdown’ workflow.

This is handy because you and your users can check the results of your checks from the ‘Actions’ tab of you repo without leaving GitHub.

It also means you can spot a failing PR and provide more commits to fix it before it gets merged.

A GitHub pull request showing the successful results of each test run with GitHub Actions.

Ticks! Ticks! Ticks!

You can also generate Markdown badges3 for your README that display the results of these actions and automatically update when they’re re-run. These are great for an at-a-glance understanding of a package’s development state.

GitHub's 'create status badge' tool showing a badge for the R CMD check and the Markdown needed to reproduce it.

More easily obtained than having to defeat a Pokémon gym leader.

For example, you can see the badges in the {r2eng} README, showing the check status and percentage of test coverage. I’ve copied them here:

R build status codecov

Clicking them takes you to the relevant page for the full breakdown of results (the ‘Actions’ tab for the build check and codecov.io for the coverage).

Other platforms are available

So, I think a combo of {usethis} and r-lib’s pre-prepared YAML files is the simplest route to auto-checking your R package and rebuilding its site.

There are many other YAML examples from r-lib though, and you can write your own. There’s also an ‘awesome list’ of more general-purpose actions to explore.

It’s important to note that there are several other platforms for continuous integration, like Travis CI and Appveyor (see Roger Peng’s book for an overview), but this requires you to setup multiple accounts and configuration files. At time of writing, GitHub Actions has the benefit of testing across all the major operating systems and is easier to set up (learn more in Jim Hester’s talk).


Session info

## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value                       
##  version  R version 4.0.2 (2020-06-22)
##  os       macOS Mojave 10.14.6        
##  system   x86_64, darwin17.0          
##  ui       X11                         
##  language (EN)                        
##  collate  en_GB.UTF-8                 
##  ctype    en_GB.UTF-8                 
##  tz       Europe/London               
##  date     2020-08-09                  
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package     * version date       lib source        
##  assertthat    0.2.1   2019-03-21 [1] CRAN (R 4.0.0)
##  blogdown      0.19    2020-05-22 [1] CRAN (R 4.0.0)
##  bookdown      0.19    2020-05-15 [1] CRAN (R 4.0.0)
##  cli           2.0.2   2020-02-28 [1] CRAN (R 4.0.0)
##  crayon        1.3.4   2017-09-16 [1] CRAN (R 4.0.0)
##  digest        0.6.25  2020-02-23 [1] CRAN (R 4.0.0)
##  evaluate      0.14    2019-05-28 [1] CRAN (R 4.0.0)
##  fansi         0.4.1   2020-01-08 [1] CRAN (R 4.0.0)
##  glue          1.4.1   2020-05-13 [1] CRAN (R 4.0.0)
##  htmltools     0.4.0   2019-10-04 [1] CRAN (R 4.0.0)
##  knitr         1.29    2020-06-23 [1] CRAN (R 4.0.2)
##  magrittr      1.5     2014-11-22 [1] CRAN (R 4.0.0)
##  Rcpp          1.0.5   2020-07-06 [1] CRAN (R 4.0.2)
##  rlang         0.4.7   2020-07-09 [1] CRAN (R 4.0.2)
##  rmarkdown     2.1     2020-01-20 [1] CRAN (R 4.0.0)
##  sessioninfo   1.1.1   2018-11-05 [1] CRAN (R 4.0.0)
##  stringi       1.4.6   2020-02-17 [1] CRAN (R 4.0.0)
##  stringr       1.4.0   2019-02-10 [1] CRAN (R 4.0.0)
##  withr         2.2.0   2020-04-20 [1] CRAN (R 4.0.0)
##  xfun          0.16    2020-07-24 [1] CRAN (R 4.0.2)
##  yaml          2.2.1   2020-02-01 [1] CRAN (R 4.0.0)
## 
## [1] /Library/Frameworks/R.framework/Versions/4.0/Resources/library

  1. Learn more about checks from Hadley Wickham and Karl Broman.↩︎

  2. The other two functions test on macOS only (use_github_action_check_release()) and on all three operating systems and also on some minor R releases too (use_github_action_check_full()), though the latter is considered ‘overkill’ according to the documentation.↩︎

  3. I showed how to create these sorts of badges in an earlier blog post: ‘Make a README badge with {badgr}’.↩︎