Transiton from Travis CI to GitHub Actions

Overview

The recent introduction of GitHub Actions makes a lot of our Travis CI build configurations redundant.

In particular, the examples actions include:

  • R-CMD-check using rcmdcheck::rcmdcheck() to check the package.
  • test-coverage using covr::codecov() to publish the unit test coverage of the package to https://codecov.io/.
  • pkgdown using pkgdown::deploy_to_branch() to push the pkgdown website to the gh-pages branch of the repository.

However, Bioconductor packages need a bit of extra tweaking to run those workflows, as we will see below.

In addition, it is useful to combine those individual example actions into a single workflow, as some of those actions only make sense to run when other have successfully completed.

Use case

Let’s pick up one of my Bioconductor-to-be packages that needs updating, namely https://github.com/kevinrue/deeperTools.

Issue

Recent updates of the GitHub and Travis integration have caused the latest Travis run to fail deploying the pkgdown website to the gh-pages branch of the repository.

── Deploying to GitHub Pages ───────────────────────────────────────────────────
Running git remote -v
origin  https://github.com/kevinrue/deeperTools.git (fetch)
origin  https://github.com/kevinrue/deeperTools.git (push)
Running git push --force origin 'HEAD:gh-pages'
remote: Invalid username or password.
fatal: Authentication failed for 'https://github.com/kevinrue/deeperTools.git/'
Error: System command 'git' failed, exit status: 128, stdout & stderr were printed
 Stack trace:
 1. pkgdown::deploy_site_github()
 2. pkgdown:::deploy_to_branch(pkg, commit_message = commit_message,  ...
 3. pkgdown:::github_push(dest_dir, commit_message, remote, branch)
 4. pkgdown:::with_dir(dir, { ...
 5. base:::force(code)
 6. pkgdown:::git("push", "--force", remote, paste0("HEAD:", branch))
 7. processx::run("git", c(...), echo_cmd = echo_cmd, echo = echo,  ...
 8. throw(new_process_error(res, call = sys.call(), echo = echo,  ...
 x System command 'git' failed, exit status: 128, stdout & stderr were printed 
── Removing worktree ───────────────────────────────────────────────────────────
Running git worktree remove /tmp/Rtmpzu14jy/file3f67f42389b
Execution halted
Script failed with status 1
failed to deploy

As Hadley Wickham wrote, it is now recommended to move away from Travis CI and use GitHub Action instead.

We now recommend using the github actions workflow instead; which avoids all this configuration pain.

Initialise the GitHub action

Having open the RStudio project located at the root of my repository, I use the usethis package to fetch and set up the R-CMD-check example workflow.

usethis::use_github_action_check_full()

Edit the R-CMD-check GitHub action as necessary

I proceed to edit some steps of the workflow for my package. Some of those edits are necessary, others are for my own convenience. The following command opens the file in the RStudio editor.

file.edit("github/workflows/R-CMD-check.yaml")

First, I remove the restriction on branches for the push event. This will trigger the action on every push to any branch.

on:
  push:
  pull_request:
    branches:
      - master

Then, I keep only the latest ubuntu version, mainly to reduce the number of configurations run as separate jobs.

strategy:
  fail-fast: false
  matrix:
    config:
      - {os: windows-latest, r: '3.6'}
      - {os: macOS-latest, r: '3.6'}
      - {os: macOS-latest, r: 'devel'}
      - {os: ubuntu-16.04, r: '3.6', rspm: "https://demo.rstudiopm.com/all/__linux__/xenial/latest"}

When working with a Bioconductor package, BiocManager should be installed during the Query dependencies step. This allows BiocManager::repositories() to be called to add Bioconductor package repositories to be added to the global session options. In turn, this allows remotes::dev_package_deps() to query all repositories when identifying dependencies, as it uses the default argument value repos = getOption("repos").

- name: Query dependencies
  run: |
    install.packages(c('remotes', 'BiocManager'))
    options(repos = c(getOption("repos"), BiocManager::repositories()))
    saveRDS(remotes::dev_package_deps(dependencies = TRUE), "depends.Rds", version = 2)
  shell: Rscript {0}

Again, when working with a Bioconductor package, we add Bioconductor package repositories to the global session options during the Install dependencies step. Similarly, the remotes::install_deps(dependencies = TRUE) uses the default argument value repos = getOption("repos").

In this step, you may also add any dependency that is not explicitly declared in the DESCRIPTION file of your package, or installed as an indirect dependency, as well as any esoteric development version of your dependencies.

- name: Install dependencies
  run: |
    options(repos = c(getOption("repos"), BiocManager::repositories()))
    remotes::install_deps(dependencies = TRUE)
    remotes::install_cran("rcmdcheck")
  shell: Rscript {0}

You may wish to set error_on = "error" during R CMD check. Otherwise, deprecation warnings would cause the step (and as a consequence the entire workflow) to fail.

- name: Check
  run: rcmdcheck::rcmdcheck(args = "--no-manual", error_on = "error", check_dir = "check")
  shell: Rscript {0}

Remove redundant actions from the Travis CI build

The Test coverage step of the R-CMD-check GitHub action deploys the website. Remove the following sections from the Travis build configuration.

after_success:
  - Rscript -e 'library(covr); codecov()'

The Deploy step of the R-CMD-check GitHub action deploys the website. Remove the following sections from the Travis build configuration.

before_cache: Rscript -e 'remotes::install_cran("pkgdown")'
deploy:
  provider: script
  script: Rscript -e 'pkgdown::deploy_site_github()'
  skip_cleanup: true

Credits

Thanks to Charlotte Soneson for discussion and advice!