Github-Actions: Build Docker Image, run R CMD Check, push to Dockerhub

I have an R package and I am trying to use Github-actions to first build a docker image then use this image to run R CMD Check on the package and, if this succeeds, push this image to dockerhub.

I have tested that my dockerfile will build correctly and also that my R package will complete R CMD check using this image so the only bit I am struggling with is creating the github-action .yaml file to automate this.

My current approach to the .yaml file is:

  1. Checkout the repository
  2. Get R package version from DESCRIPTION file for docker tag
  3. Set up the docker build
  4. Build the image
  5. Run R CMD check
  6. Log in to dockerhub
  7. Push to dockerhub

I want to do this so that as new versions of package dependencies are released, I can use the image to ensure nothing breaks before pushing it. However it is failing at step 5 with the following error:

Run rcmdcheck::rcmdcheck(args = "--no-manual", error_on = "error")
Error: Error in loadNamespace(x) : there is no package called ‘rcmdcheck’
Calls: loadNamespace -> withRestarts -> withOneRestart -> doWithOneRestart
Execution halted
Error: Process completed with exit code 1.

This is odd since I do install rcmdcheck in my docker image and have tested locally to ensure it is installed correctly. So this makes me believe my step 5 is not using the created image but I don't know how to correct this? I want the R CMD Check step to run in my created image.

This is my .yaml file:

name: R GitHub Actions

on:
  push:
    branches:
      - main
      - master
      - dev-am
  pull_request:
    branches:
      - main
      - master

jobs:
  R-CMD-check:
    name: R-CMD-check
    runs-on: ubuntu-latest
    env:
      GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
      RGL_USE_NULL: TRUE
    steps:
      - uses: actions/checkout@v2
      - name: Setup R
        uses: r-lib/actions/setup-r@v1
        with:
          install-r: false
      
      - name: Get R package version
        run: |
          version=$(grep Version DESCRIPTION | grep -o "[0-9.]\+")
          echo "packageVersion=${version}" >> $GITHUB_ENV
        shell: bash {0}    
      
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v1

      - name: Build service
        uses: docker/build-push-action@v2
        with:
          load: true
          tags: almurphy/scfdev:${{ env.packageVersion }}
        
      - name: Check
        run: rcmdcheck::rcmdcheck(args = "--no-manual", error_on = "error")
        shell: Rscript {0}

      - name: Login to DockerHub
        uses: docker/login-action@v1
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_TOKEN }}

      - name: push service
        run: |
          docker push almurphy/scfdev:${{ env.packageVersion }}

And here is my Dockerfile:

## Use rstudio installs binaries from RStudio's RSPM service by default, 
## Uses the latest stable ubuntu, R and Bioconductor versions. Created on unbuntu 20.04, R 4.0 and BiocManager 3.12
FROM rocker/rstudio


## Add packages dependencies
RUN apt-get update \
    && apt-get install -y --no-install-recommends apt-utils \
    && apt-get install -y --no-install-recommends \
    ## Basic deps
    gdb \
    libxml2-dev \
    python3-pip \
    libz-dev \
    liblzma-dev \
    libbz2-dev \
    libpng-dev \
    libgit2-dev \
    ## sys deps from bioc_full
    pkg-config \
    fortran77-compiler \
    byacc \
    automake \
    curl \
    ## This section installs libraries
    libpcre2-dev \
    libnetcdf-dev \
    libhdf5-serial-dev \
    libfftw3-dev \
    libopenbabel-dev \
    libopenmpi-dev \
    libxt-dev \
    libudunits2-dev \
    libgeos-dev \
    libproj-dev \
    libcairo2-dev \
    libtiff5-dev \
    libreadline-dev \
    libgsl0-dev \
    libgslcblas0 \
    libgtk2.0-dev \
    libgl1-mesa-dev \
    libglu1-mesa-dev \
    libgmp3-dev \
    libhdf5-dev \
    libncurses-dev \
    libbz2-dev \
    libxpm-dev \
    liblapack-dev \
    libv8-dev \
    libgtkmm-2.4-dev \
    libmpfr-dev \
    libmodule-build-perl \
    libapparmor-dev \
    libprotoc-dev \
    librdf0-dev \
    libmagick++-dev \
    libsasl2-dev \
    libpoppler-cpp-dev \
    libprotobuf-dev \
    libpq-dev \
    libperl-dev \
    ## software - perl extentions and modules
    libarchive-extract-perl \
    libfile-copy-recursive-perl \
    libcgi-pm-perl \
    libdbi-perl \
    libdbd-mysql-perl \
    libxml-simple-perl \
    libmysqlclient-dev \
    default-libmysqlclient-dev \
    libgdal-dev \
    ## new libs
    libglpk-dev \
    ## Databases and other software
    sqlite \
    openmpi-bin \
    mpi-default-bin \
    openmpi-common \
    openmpi-doc \
    tcl8.6-dev \
    tk-dev \
    default-jdk \
    imagemagick \
    tabix \
    ggobi \
    graphviz \
    protobuf-compiler \
    jags \
    ## Additional resources
    xfonts-100dpi \
    xfonts-75dpi \
    biber \
    libsbml5-dev \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

RUN install2.r -e \
testthat \
covr \
knitr \
purrr \
stringr \
cli \
dplyr \
data.table \
R.utils \
vroom \
ggpubr \
ggplot2 \
rmarkdown \
rlang \
future \
future.apply \
plotly \
threejs \
plyr \
assertthat \
httr \
prettydoc \
leaflet \
gdtools \
formattable \
ggdendro \
ggridges \
cowplot \
forcats \
ggrepel \
igraph \
tibble \
tidyr \
tidyselect \
tidyverse \
ids \
snow \
remotes \
rliger \
argparse \
Hmisc \
rcmdcheck

## Install remaining packages from source
COPY ./misc/requirements-src.R .
RUN Rscript requirements-src.R

## Install Bioconductor packages
COPY ./misc/requirements-bioc.R .
RUN apt-get update \
 && apt-get install -y --no-install-recommends \
   libfftw3-dev \
   gcc && apt-get clean \
 && rm -rf /var/lib/apt/lists/*
RUN Rscript -e 'requireNamespace("BiocManager"); BiocManager::install(ask=F);' \
&& Rscript requirements-bioc.R

## Install from GH the following
RUN installGithub.r neurogenomics/EWCE \
chris-mcginnis-ucsf/DoubletFinder \
theislab/kBET \
combiz/RANN.L1 \
NathanSkene/One2One \
hhoeflin/hdf5r \
mojaveazure/loomR \
cole-trapnell-lab/monocle3 \
neurogenomics/scFlowExample \
neurogenomics/scFlowData

## Install scFlow package
# Copy description
WORKDIR scFlow
ADD . .

# Install R package from source
RUN Rscript -e "remotes::install_local()"
RUN rm -rf *

You would presumably have to specify that the check step is using your docker container?

e.g. using a using: for that step or setting container: for the whole job.

Hey Jim, thank you very much for your reply! I can definitely add a using: parameter but I worried about how to set this to the container which was built in the previous step? If I used using: almurphy/scfdev:${{ env.packageVersion }} will that know to take the image built in the previous step?

Thanks so much,
Alan.

I don't know, doing what you are trying to do is not something I have ever seen someone attempt.

I think it would probably work though.

Seems to cause an error with using::

.github/workflows/r_package.yaml#L46
The workflow is not valid. .github/workflows/r_package.yaml (Line: 46, Col: 9): Unexpected value 'using'

code:

      - name: Check
        run: rcmdcheck::rcmdcheck(args = "--no-manual", error_on = "error")
        shell: Rscript {0}
        using: almurphy/scfdev:${{ env.packageVersion }}

Maybe the parameter shouldn't be using but something else? Sorry, my knowledge of Github actions isn't great.

@jimhester I was trying to think of alternative ways of doing this and one option that struck me was to use the remotes::install_local() in the Dockerfile to run a check. This leaves two questions, does remotes::install_local() build the vignette by default (if the vignette runs that would be a form of a check for the package)? Secondly, is there a way to either run R-CMD-Check or to run the package's unit tests when installing with install_local()? I think if the vignette and unit tests run without error this should be enough of a check