An R package can behave differently across operating systems and R releases because compiled dependencies, examples, vignettes, and tests all participate in R CMD check. GitHub Actions can run those checks for every pull request before a change reaches the package's main branch.
The maintained r-lib/actions components separate R setup, dependency installation, and package checking. The standard matrix covers release R on Linux, macOS, and Windows, then adds development and previous R releases on Linux so platform failures and version regressions appear as distinct jobs.
GitHub supplies each job with a repository-scoped GITHUB_TOKEN that can read the checked-out repository contents, so a personal token is unnecessary. The final API check reads the workflow run for the tested commit and its matrix jobs without changing the repository.
$ mkdir -p .github/workflows
# 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 on: push: branches: [main, master] pull_request: branches: [main, master] name: R-CMD-check permissions: contents: read
The pull_request event checks changes proposed for main or master, while the push event checks commits that reach those branches. The token can read repository contents for checkout; every unlisted permission is none.
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'}
fail-fast: false lets every platform report its result even when another matrix job fails.
env: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} R_KEEP_PKG_SOURCE: yes
The GITHUB_PAT value comes from GitHub's per-job token. A personal token is unnecessary unless the package genuinely needs access beyond the current repository.
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 }} http-user-agent: ${{ matrix.config.http-user-agent }} use-public-rspm: true
- uses: r-lib/actions/setup-r-dependencies@v2 with: extra-packages: any::rcmdcheck needs: check
The dependency action reads the package's DESCRIPTION file and adds packages declared under Config/Needs/check.
Related: How to install an R package from GitHub
- uses: r-lib/actions/check-r-package@v2 with: upload-snapshots: true
upload-snapshots preserves changed test snapshots when a job fails. A reviewed full commit SHA is the immutable alternative to a version tag when organizational policy requires pinned actions.
# 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 on: push: branches: [main, master] pull_request: branches: [main, master] name: R-CMD-check permissions: contents: read 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: - uses: actions/checkout@v4 - uses: r-lib/actions/setup-pandoc@v2 - 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 - uses: r-lib/actions/setup-r-dependencies@v2 with: extra-packages: any::rcmdcheck needs: check - uses: r-lib/actions/check-r-package@v2 with: upload-snapshots: true
$ git add .github/workflows/R-CMD-check.yaml
$ git commit -m "Add R package checks"
$ git push --set-upstream origin HEAD
$ gh pr create --fill
GitHub starts one R-CMD-check job for each matrix row. A warning or error produces a failed job; open that job's artifact to inspect the retained check directory.
$ OWNER=your-github-user-or-organization
$ REPOSITORY=your-r-package-repository
$ COMMIT=your-current-commit-sha
$ curl -fsSL \
"https://api.github.com/repos/${OWNER}/${REPOSITORY}/actions/workflows/R-CMD-check.yaml/runs?head_sha=${COMMIT}&per_page=1" \
-o R-CMD-check-runs.json
$ jq -r '.workflow_runs[0] | [.id, .status, .conclusion, .head_branch] | @tsv' \ R-CMD-check-runs.json
The status value becomes completed after the run finishes. A successful run reports success under conclusion and supplies the run ID needed for the matrix-job request.
$ RUN_ID=your-completed-run-id
$ curl -fsSL \
"https://api.github.com/repos/${OWNER}/${REPOSITORY}/actions/runs/${RUN_ID}/jobs?per_page=100" \
-o R-CMD-check-jobs.json
$ jq -r '.jobs[] | [.name, .conclusion] | @tsv' R-CMD-check-jobs.json
All five rows must report success. A different conclusion identifies the operating system and R release whose job log needs review.
$ rm R-CMD-check-runs.json R-CMD-check-jobs.json