4.2 GitHub Actions
GitHub Actions is a service for running highly-customizable and flexible automated workflows, fully integrated with GitHub and very suitable to CI/CD pipelines.
Workflows use YAML
syntax and should be stored in the .github/workflows
directory in the root of the repository.
Workflows are constituted of jobs and each job is a set of steps to perform individual tasks, e.g. commands or actions.
The next sections describe in detail the relevant workflow steps of a typical CI/CD pipeline for a packages Shiny app, also covering the usage of renv
to track package dependencies. Finally, we will show how you can use the convenience function usethis::use_github_action()
for including such workflows in you project.
4.2.1 Workflow steps
A workflow should have an identifying name
and an on
section that indicates upon which events the workflow should be triggered. It should include at least one job and each job will have a set of steps fully specifying what to execute. Such steps can be an action (predefined, sourcing from GitHub repos that contain such actions) or custom shell commands. With the introduction of composite Actions, most of the relevant workflow steps for an R project are covered by actions provided by the r-lib/actions.
4.2.1.1 Setup
- Checkout the source package from the repository, using
actions/checkout
provided by GitHub. - Setup R using the action
r-lib/actions/setup-r
. - Install package dependencies (including system requirements and caching) using
r-lib/actions/setup-r-dependencies
.
Using renv
If your project relies on package renv for tracking dependencies via an renv.lock
file, caching and installation of R package dependencies requires a different setup, as described in the Using renv with Continuous Integration vignette. As shown in the complete workflow files below:
- system requirements are installed explicitly (for the
ubuntu
runner defined for the workflow) based onremotes::system_requirements()
- dependencies tracked by renv are installed (including caching) using
r-lib/actions/setup-renv
4.2.1.3 Deployment
- Continuous deployment to shinyapps.io is automated upon any push to the
master
branch- In order to provide credentials for the deployment, account name and corresponding tokens for shinyapps.io are defined as environment variables
SHINYAPPS_ACCOUNT
,SHINYAPPS_TOKEN
andSHINYAPPS_SECRET
, specified / accessible as GitHub secrets. - A convenience R script, e.g.
deploy/deploy-shinyapps.R
(build-ignored viausethis::use_build_ignore("deploy")
), defines the deployment commands based on the environment variables.
- In order to provide credentials for the deployment, account name and corresponding tokens for shinyapps.io are defined as environment variables
# deploy/deploy-shinyapps.R
# usethis::use_build_ignore("deploy")
::setAccountInfo(
rsconnectSys.getenv("SHINYAPPS_ACCOUNT"),
Sys.getenv("SHINYAPPS_TOKEN"),
Sys.getenv("SHINYAPPS_SECRET")
)::deployApp(appName = "ShinyCICD") rsconnect
4.2.2 Workflow file
The steps
described in the previous section are defined in the .yml
workflow file as follows:
# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples
# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help
# Name of the workflow => usethis::use_github_actions_badge("CI-CD")
name: CI-CD
on:
# Triggered on push and pull request events
push:
pull_request:
# Allow manual runs from the Actions tab
workflow_dispatch:
jobs:
CI-CD:
runs-on: ${{ matrix.config.os }}
name: ${{ matrix.config.os }} (${{ matrix.config.r }})
strategy:
# We keep a matrix for convenience, but we would typically just run on one
# single OS and R version, aligned with the target deployment environment
matrix:
config:
- {os: ubuntu-latest, r: 'release'}
env:
# Access token for GitHub
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
# Preserve package sources for informative references in case of errors
R_KEEP_PKG_SOURCE: yes
steps:
- name: Checkout repo
uses: actions/checkout@v3
- name: Setup R
uses: r-lib/actions/setup-r@v2
with:
r-version: ${{ matrix.config.r }}
# Enable RStudio Package Manager to speed up package installation
use-public-rspm: true
- name: Install and cache dependencies
uses: r-lib/actions/setup-r-dependencies@v2
with:
extra-packages: any::rcmdcheck
- name: Check package
uses: r-lib/actions/check-r-package@v2
- name: Deploy to shinyapps.io
# Continuous deployment only for pushes to the main / master branch
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master'
env:
SHINYAPPS_ACCOUNT: ${{ secrets.SHINYAPPS_ACCOUNT }}
SHINYAPPS_TOKEN: ${{ secrets.SHINYAPPS_TOKEN }}
SHINYAPPS_SECRET: ${{ secrets.SHINYAPPS_SECRET }}
run: Rscript deploy/deploy-shinyapps.R
As visible from the run logs that can be found in the GitHub repository under the Actions
tab, all the CI/CD pipeline steps are performed subsequently, and are identifiable by the name
field. See the example below, showing how the deployment step is skipped for a run not triggered by a push action the main
(or master
) branch:
4.2.3 Complete workflows and usethis::use_github_action()
Full YAML workflows for CI and CI/CD pipelines, with and without renv
, are shown below and provided as part of this guide.
In order to setup and use CI/CD GitHub Actions workflows as described above, you can simply include the relevant workflow file your project via:
::use_github_action(url = paste0(
usethis"https://github.com/miraisolutions/techguides/blob/master/",
"shiny-ci-cd/actions/ci-cd.yml"
# "shiny-ci-cd/actions/ci-cd-renv.yml"
# "shiny-ci-cd/actions/ci.yml"
# "shiny-ci-cd/actions/ci-renv.yml"
))::use_github_actions_badge("CI-CD") # or "CI" usethis
4.2.3.1 Complete workflow files
shiny-ci-cd/actions/ci-cd.yml
# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples
# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help
# Name of the workflow => usethis::use_github_actions_badge("CI-CD")
name: CI-CD
on:
# Triggered on push and pull request events
push:
pull_request:
# Allow manual runs from the Actions tab
workflow_dispatch:
jobs:
CI-CD:
runs-on: ${{ matrix.config.os }}
name: ${{ matrix.config.os }} (${{ matrix.config.r }})
strategy:
# We keep a matrix for convenience, but we would typically just run on one
# single OS and R version, aligned with the target deployment environment
matrix:
config:
- {os: ubuntu-latest, r: 'release'}
env:
# Access token for GitHub
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
# Preserve package sources for informative references in case of errors
R_KEEP_PKG_SOURCE: yes
steps:
- name: Checkout repo
uses: actions/checkout@v3
- name: Setup R
uses: r-lib/actions/setup-r@v2
with:
r-version: ${{ matrix.config.r }}
# Enable RStudio Package Manager to speed up package installation
use-public-rspm: true
- name: Install and cache dependencies
uses: r-lib/actions/setup-r-dependencies@v2
with:
extra-packages: any::rcmdcheck
- name: Check package
uses: r-lib/actions/check-r-package@v2
- name: Deploy to shinyapps.io
# Continuous deployment only for pushes to the main / master branch
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master'
env:
SHINYAPPS_ACCOUNT: ${{ secrets.SHINYAPPS_ACCOUNT }}
SHINYAPPS_TOKEN: ${{ secrets.SHINYAPPS_TOKEN }}
SHINYAPPS_SECRET: ${{ secrets.SHINYAPPS_SECRET }}
run: Rscript deploy/deploy-shinyapps.R
shiny-ci-cd/actions/ci-cd-renv.yml
# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples
# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help
# Name of the workflow => usethis::use_github_actions_badge("CI-CD-renv")
name: CI-CD-renv
on:
# Triggered on push and pull request events
push:
pull_request:
# Allow manual runs from the Actions tab
workflow_dispatch:
jobs:
CI-CD:
runs-on: ${{ matrix.config.os }}
name: ${{ matrix.config.os }} (${{ matrix.config.r }})
strategy:
# We keep a matrix for convenience, but we would typically just run on one
# single OS and R version, aligned with the target deployment environment
matrix:
config:
- {os: ubuntu-latest, r: 'release'}
env:
# Access token for GitHub
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
# Preserve package sources for informative references in case of errors
R_KEEP_PKG_SOURCE: yes
steps:
- name: Checkout repo
uses: actions/checkout@v3
- name: Setup R
uses: r-lib/actions/setup-r@v2
with:
r-version: ${{ matrix.config.r }}
# Enable RStudio Package Manager to speed up package installation
use-public-rspm: true
- name: Install system dependencies
# This is not taken care of (yet) by r-lib/actions/setup-renv
# Package distro used to get the distro for the used ubuntu-latest
run: |
Rscript -e "install.packages(c('remotes', 'distro'))"
while read -r cmd
do
eval sudo $cmd
done < <(Rscript -e 'writeLines(with(distro::distro(), remotes::system_requirements(id, short_version)))')
- name: Activate renv and restore packages with cache
uses: r-lib/actions/setup-renv@v2
- name: Install R CMD check
run: install.packages("rcmdcheck")
shell: Rscript {0}
- name: Check package
uses: r-lib/actions/check-r-package@v2
- name: Deploy to shinyapps.io
# Continuous deployment only for pushes to the main / master branch
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master'
env:
SHINYAPPS_ACCOUNT: ${{ secrets.SHINYAPPS_ACCOUNT }}
SHINYAPPS_TOKEN: ${{ secrets.SHINYAPPS_TOKEN }}
SHINYAPPS_SECRET: ${{ secrets.SHINYAPPS_SECRET }}
run: Rscript deploy/deploy-shinyapps.R
shiny-ci-cd/actions/ci.yml
# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples
# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help
# Name of the workflow => usethis::use_github_actions_badge("CI")
name: CI
on:
# Triggered on push and pull request events
push:
pull_request:
# Allow manual runs from the Actions tab
workflow_dispatch:
jobs:
CI-CD:
runs-on: ${{ matrix.config.os }}
name: ${{ matrix.config.os }} (${{ matrix.config.r }})
strategy:
# We keep a matrix for convenience, but we would typically just run on one
# single OS and R version, aligned with the target deployment environment
matrix:
config:
- {os: ubuntu-latest, r: 'release'}
env:
# Access token for GitHub
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
# Preserve package sources for informative references in case of errors
R_KEEP_PKG_SOURCE: yes
steps:
- name: Checkout repo
uses: actions/checkout@v3
- name: Setup R
uses: r-lib/actions/setup-r@v2
with:
r-version: ${{ matrix.config.r }}
# Enable RStudio Package Manager to speed up package installation
use-public-rspm: true
- name: Install and cache dependencies
uses: r-lib/actions/setup-r-dependencies@v2
with:
extra-packages: any::rcmdcheck
- name: Check package
uses: r-lib/actions/check-r-package@v2
shiny-ci-cd/actions/ci-renv.yml
# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples
# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help
# Name of the workflow => usethis::use_github_actions_badge("CI-renv")
name: CI-renv
on:
# Triggered on push and pull request events
push:
pull_request:
# Allow manual runs from the Actions tab
workflow_dispatch:
jobs:
CI-CD:
runs-on: ${{ matrix.config.os }}
name: ${{ matrix.config.os }} (${{ matrix.config.r }})
strategy:
# We keep a matrix for convenience, but we would typically just run on one
# single OS and R version, aligned with the target deployment environment
matrix:
config:
- {os: ubuntu-latest, r: 'release'}
env:
# Access token for GitHub
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
# Preserve package sources for informative references in case of errors
R_KEEP_PKG_SOURCE: yes
steps:
- name: Checkout repo
uses: actions/checkout@v3
- name: Setup R
uses: r-lib/actions/setup-r@v2
with:
r-version: ${{ matrix.config.r }}
# Enable RStudio Package Manager to speed up package installation
use-public-rspm: true
- name: Install system dependencies
# This is not taken care of (yet) by r-lib/actions/setup-renv
# Package distro used to get the distro for the used ubuntu-latest
run: |
Rscript -e "install.packages(c('remotes', 'distro'))"
while read -r cmd
do
eval sudo $cmd
done < <(Rscript -e 'writeLines(with(distro::distro(), remotes::system_requirements(id, short_version)))')
- name: Activate renv and restore packages with cache
uses: r-lib/actions/setup-renv@v2
- name: Install R CMD check
run: install.packages("rcmdcheck")
shell: Rscript {0}
- name: Check package
uses: r-lib/actions/check-r-package@v2