| name | github-actions |
| description | Automated CI/CD workflows for R packages including R CMD check across platforms, test coverage reporting, and pkgdown deployment |
GitHub Actions for R Package Development
This skill covers setting up comprehensive GitHub Actions workflows for R package development, including cross-platform testing, continuous integration, automated documentation deployment, and test coverage reporting.
Rules
- Use r-lib/actions v2 for all R-related workflow steps
- Test on multiple platforms: macOS, Windows, Ubuntu (latest + devel + oldrel)
- Always include permissions blocks with minimal required scopes
- Use concurrency groups to cancel outdated workflow runs
- Cache dependencies for faster builds (handled by setup-r-dependencies)
- Set GITHUB_PAT environment variable for private repos or rate limits
- Use checkout@v4 (not v2 or v3) for repository checkout
- Deploy pkgdown only on push to main/master, not on PRs
- Report test coverage to Codecov on successful test runs
- Use workflow_dispatch for manual workflow triggering
Essential Workflows
Every R package should have these three workflows:
- R-CMD-check.yaml - Cross-platform package checking
- pkgdown.yaml - Documentation website deployment
- test-coverage.yaml - Code coverage reporting
1. R CMD Check Workflow
Complete R-CMD-check.yaml
Create .github/workflows/R-CMD-check.yaml:
on:
push:
branches: [main, master]
pull_request:
branches: [main, master]
name: R-CMD-check
permissions: read-all
jobs:
R-CMD-check:
runs-on: ${{ matrix.config.os }}
name: ${{ matrix.config.os }} (${{ matrix.config.r }})
strategy:
fail-fast: false
matrix:
config:
- {os: macos-latest, r: 'release'}
- {os: windows-latest, r: 'release'}
- {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'}
- {os: ubuntu-latest, r: 'release'}
- {os: ubuntu-latest, r: 'oldrel-1'}
env:
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
R_KEEP_PKG_SOURCE: yes
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Pandoc
uses: r-lib/actions/setup-pandoc@v2
- name: Setup R
uses: r-lib/actions/setup-r@v2
with:
r-version: ${{ matrix.config.r }}
http-user-agent: ${{ matrix.config.http-user-agent }}
use-public-rspm: true
- name: Install system dependencies
if: runner.os == 'Linux'
run: |
sudo apt-get update -y
sudo apt-get install -y libcurl4-openssl-dev
- name: Install dependencies
uses: r-lib/actions/setup-r-dependencies@v2
with:
extra-packages: any::rcmdcheck
needs: check
- name: Check package
uses: r-lib/actions/check-r-package@v2
with:
upload-snapshots: true
build_args: 'c("--no-manual","--compact-vignettes=gs+qpdf")'
Minimal R-CMD-check.yaml
For simpler packages, you can use fewer test configurations:
on:
push:
branches: [main, master]
pull_request:
branches: [main, master]
name: R-CMD-check
permissions: read-all
jobs:
R-CMD-check:
runs-on: ${{ matrix.config.os }}
name: ${{ matrix.config.os }} (${{ matrix.config.r }})
strategy:
fail-fast: false
matrix:
config:
- {os: macos-latest, r: 'release'}
- {os: windows-latest, r: 'release'}
- {os: ubuntu-latest, r: 'release'}
env:
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
R_KEEP_PKG_SOURCE: yes
steps:
- uses: actions/checkout@v4
- uses: r-lib/actions/setup-pandoc@v2
- uses: r-lib/actions/setup-r@v2
with:
r-version: ${{ matrix.config.r }}
use-public-rspm: true
- uses: r-lib/actions/setup-r-dependencies@v2
with:
extra-packages: any::rcmdcheck
needs: check
- uses: r-lib/actions/check-r-package@v2
With System Dependencies
For packages with system dependencies (e.g., gdal, jags, gsl):
- name: Install system dependencies on macOS
if: runner.os == 'macOS'
run: |
brew install gdal proj geos
- name: Install system dependencies on Linux
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y \
libgdal-dev \
libproj-dev \
libgeos-dev \
libudunits2-dev
- name: Install system dependencies on Windows
if: runner.os == 'Windows'
run: |
Build Arguments Explained
- uses: r-lib/actions/check-r-package@v2
with:
upload-snapshots: true
build_args: 'c("--no-manual","--compact-vignettes=gs+qpdf")'
error-on: '"error"'
build_args options:
--no-manual: Skip PDF manual creation (faster, requires less LaTeX)
--compact-vignettes=gs+qpdf: Compress vignettes with Ghostscript and qpdf
--no-build-vignettes: Skip vignette building entirely
--resave-data: Optimize data file compression
2. pkgdown Deployment Workflow
Complete pkgdown.yaml
Create .github/workflows/pkgdown.yaml:
on:
push:
branches: [main, master]
pull_request:
branches: [main, master]
release:
types: [published]
workflow_dispatch:
name: pkgdown
concurrency:
group: pkgdown-${{ github.event_name != 'pull_request' || github.run_id }}
permissions:
contents: write
jobs:
pkgdown:
runs-on: ubuntu-latest
env:
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Pandoc
uses: r-lib/actions/setup-pandoc@v2
- name: Setup R
uses: r-lib/actions/setup-r@v2
with:
use-public-rspm: true
- name: Install dependencies
uses: r-lib/actions/setup-r-dependencies@v2
with:
extra-packages: any::pkgdown, local::.
needs: website
- name: Build site
run: pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE)
shell: Rscript {0}
- name: Deploy to GitHub Pages
if: github.event_name != 'pull_request'
uses: JamesIves/github-pages-deploy-action@v4
with:
folder: docs
branch: gh-pages
clean: true
single-commit: false
Using deploy_to_branch Alternative
- name: Build and deploy
if: github.event_name != 'pull_request'
run: |
git config --local user.name "$GITHUB_ACTOR"
git config --local user.email "$GITHUB_ACTOR@users.noreply.github.com"
Rscript -e 'pkgdown::deploy_to_branch(new_process = FALSE)'
Build on PR (Preview Only)
- name: Build site for preview
if: github.event_name == 'pull_request'
run: |
pkgdown::build_site(preview = FALSE, install = FALSE)
shell: Rscript {0}
- name: Upload preview
if: github.event_name == 'pull_request'
uses: actions/upload-artifact@v3
with:
name: pkgdown-preview
path: docs/
3. Test Coverage Workflow
Complete test-coverage.yaml
Create .github/workflows/test-coverage.yaml:
on:
push:
branches: [main, master]
pull_request:
branches: [main, master]
name: test-coverage
permissions: read-all
jobs:
test-coverage:
runs-on: ubuntu-latest
env:
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup R
uses: r-lib/actions/setup-r@v2
with:
use-public-rspm: true
- name: Install dependencies
uses: r-lib/actions/setup-r-dependencies@v2
with:
extra-packages: any::covr, any::xml2
needs: coverage
- name: Test coverage
run: |
cov <- covr::package_coverage(
quiet = FALSE,
clean = FALSE,
install_path = file.path(normalizePath(Sys.getenv("RUNNER_TEMP"), winslash = "/"), "package")
)
covr::to_cobertura(cov)
shell: Rscript {0}
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v4
with:
fail_ci_if_error: true
files: ./cobertura.xml
token: ${{ secrets.CODECOV_TOKEN }}
verbose: true
- name: Show testthat output
if: always()
run: |
find '${{ runner.temp }}/package' -name 'testthat.Rout*' -exec cat '{}' \; || true
shell: bash
Codecov Setup
- Sign up at https://codecov.io with your GitHub account
- Add your repository
- Add
CODECOV_TOKEN to GitHub secrets (Settings > Secrets and variables > Actions)
- Add badge to README.md:
[](https://codecov.io/gh/username/packagename)
Alternative: Coveralls
- name: Upload coverage to Coveralls
uses: coverallsapp/github-action@v2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
path-to-lcov: ./coverage.lcov
Additional Useful Workflows
4. PR Commands Workflow
Respond to comments like /document or /style:
Create .github/workflows/pr-commands.yaml:
on:
issue_comment:
types: [created]
name: Commands
jobs:
document:
if: startsWith(github.event.comment.body, '/document')
runs-on: ubuntu-latest
env:
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v4
- uses: r-lib/actions/pr-fetch@v2
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
- uses: r-lib/actions/setup-r@v2
- uses: r-lib/actions/setup-r-dependencies@v2
with:
extra-packages: any::roxygen2
- name: Document
run: roxygen2::roxygenise()
shell: Rscript {0}
- name: Commit
run: |
git config --local user.name "$GITHUB_ACTOR"
git config --local user.email "$GITHUB_ACTOR@users.noreply.github.com"
git add man/\* NAMESPACE
git commit -m 'Document' || echo "No changes to commit"
- uses: r-lib/actions/pr-push@v2
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
style:
if: startsWith(github.event.comment.body, '/style')
runs-on: ubuntu-latest
env:
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v4
- uses: r-lib/actions/pr-fetch@v2
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
- uses: r-lib/actions/setup-r@v2
- name: Install styler
run: install.packages("styler")