Tutorial: R Package CI
This tutorial sets up local continuous integration for an R package. Every commit triggers a full check cycle: documentation, linting, testing, coverage, and R CMD check.
Scaffolding
From your package root:
daggle init pkg-checkThis generates a pipeline.yaml with the standard package check steps. Below is the full DAG with a git trigger and failure hooks added.
The pipeline
name: pkg-check
trigger:
git:
branch: main
poll_interval: 30s
steps:
- id: restore
renv_restore: "."
- id: document
document: "."
depends: [restore]
- id: lint
lint: "."
depends: [document]
- id: test
test: "."
depends: [document]
- id: coverage
coverage: "."
depends: [test]
- id: check
check: "."
error_on: warning
depends: [document]
on_failure:
r_expr: |
dag <- Sys.getenv("DAGGLE_DAG_NAME")
run <- Sys.getenv("DAGGLE_RUN_ID")
cat(sprintf("FAILED: %s run %s at %s\n", dag, run, Sys.time()))How the DAG executes
restore -> document -> lint
-> test -> coverage
-> check
After document completes, three branches run in parallel:
lintchecks code styletestruns the test suite, thencoveragemeasures what was testedcheckrunsR CMD check
This parallelism means the total wall time is the longest branch, not the sum of all steps.
The git trigger
trigger:
git:
branch: main
poll_interval: 30sWhen daggle serve is running, it polls the local git repo every 30 seconds. If the commit hash on main has changed, the DAG runs automatically. This gives you CI behavior without leaving your machine.
Start the scheduler:
daggle serveNow commit and watch the pipeline kick off.
Structured output from built-in steps
The test:, check:, and coverage: step types automatically emit structured output via ::daggle-output:: markers. You do not need to write any parsing code.
test emits:
passed– number of passing testsfailed– number of failing testsskipped– number of skipped tests
check emits:
errors– number of R CMD check errorswarnings– number of warningsnotes– number of notes
coverage emits:
coverage– overall coverage percentage
Downstream steps or hooks can read these values. For example, a failure hook could include the test counts in a notification:
on_failure:
r_expr: |
failed <- Sys.getenv("DAGGLE_OUTPUT_TEST_FAILED")
errors <- Sys.getenv("DAGGLE_OUTPUT_CHECK_ERRORS")
warnings <- Sys.getenv("DAGGLE_OUTPUT_CHECK_WARNINGS")
msg <- sprintf("Tests failed: %s | Check errors: %s, warnings: %s",
failed, errors, warnings)
cat(msg, "\n")Not all variables will be set if the corresponding step did not run (e.g., if restore failed, none of the downstream outputs exist). Use nchar(Sys.getenv("...")) > 0 to check before reading.
Controlling check strictness
The error_on field on the check: step controls what triggers a failure:
- id: check
check: "."
error_on: warning # fail on warnings or errors (default: error)Options: error (default), warning, note.
Running manually
You do not need the git trigger to run the pipeline. Run it directly any time:
daggle run pkg-checkOr run a subset:
daggle run pkg-check --only testViewing results
daggle status pkg-check
daggle logs pkg-check test
daggle logs pkg-check check