Skip to content

Replace renv with a rig project for the R test environment - #15308

Draft
cderv wants to merge 9 commits into
mainfrom
chore/rig-proj-test-env
Draft

cderv wants to merge 9 commits into
mainfrom
chore/rig-proj-test-env

Conversation

@cderv

@cderv cderv commented Nov 5, 2026

Copy link
Copy Markdown
Member

Setting up the R test environment in several worktrees at once can hang for tens of minutes. With three concurrent cold renv::restore() runs sharing the renv cache, two stayed stuck for more than 28 minutes, while a single run finishes in about 80 seconds. Every R start in tests/ also pays the renv autoloader (about 10 seconds), and each R subprocess a test starts outside tests/ activates renv again through a generated .Rprofile.

The tests/ R environment is now a rig project. rig proj sync installs binary packages from a lock file without running R and without renv's shared lock, so this kind of hang goes away. On Windows, three concurrent cold setups now finish in about 30 seconds each.

What changes

  • tests/rproj.toml and tests/rproj.lock replace DESCRIPTION, renv.lock and renv/. The lock is imported from renv.lock (145 packages, R 4.6.x) and solved for Windows x86_64, macOS arm64, Linux x86_64 and source. Every package is a P3M binary on the three OS targets. Twelve packages move to a newer version in the process (e.g. gt 1.3.0 to 1.4.0, curl 8.0.0 to 8.1.0).
  • run-tests sets QUARTO_R to tests/.rvenv/bin. The wrappers there start the locked R with the project library whatever the working directory, so tests rendering from a temp dir no longer need a per-fixture .Rprofile (writeTestsRenvProfile is removed).
  • configure-test-env runs rig proj sync, then installs dev rmarkdown and knitr from r-universe into the project library, as before. It needs rig 0.11.1 or later.
  • In CI, a small setup-rig composite action installs a pinned rig (0.11.1, as rig proj is still experimental). rig proj sync --locked installs the R version the lock needs and fails on a stale lock. The renv cache and renv::status() steps are gone. extra-r-packages now goes to rig pkg install, and pkg@1.2.3 is rewritten to pkg@=1.2.3 to keep renv's exact-version meaning, because rig reads a bare version as a minimum.
  • tests/.Renviron and tests/.rvenvlib/ are rig's activation hook for R sessions started in tests/, e.g. from an IDE. rig documents them as meant to be committed. tests/.Renviron is checked out with LF, as every sync rewrites it with LF.
  • tests/README.md, dev-docs/configuring-test-deps.md and the testing notes describe the rig workflow.

Things to know

  • Release mode of test-smokes-built.yml on a tag from before this change now fails early with a clear error, as those tags have no tests/rproj.lock. A renv fallback in the workflow was not added.
  • On Windows, the rig activation shim misses that a parent R process already activated the project (rvenv shim: "already activated" check is always FALSE on Windows, so child R processes re-read ~/.Renviron r-lib/rig#502). It only matters with a ~/.Renviron, and no test is affected. The committed shim will be regenerated once rig has a fix.
  • macOS arm64 is first exercised by the nightly smoke tests after merge. A backport to the stable branch will be considered once main is green.

Verification

  • Windows: full configure-test-env, three concurrent cold setups, knitr tests rendering from outside tests/, binary mode
  • Windows and Linux CI, including a run with extra-r-packages
  • macOS arm64 in the first nightly after merge

Checklist

I have (if applicable):

  • referenced the GitHub issue this PR closes
  • updated the appropriate changelog in the PR
  • ensured the present test suite passes
  • added new tests
  • created a separate documentation PR in Quarto's website repo and linked it to this PR
AI-assisted PR
  • AI tool used: Claude Code
  • Codebase grounding: local clone, Context7 MCP (rig docs)
  • Human review: I have reviewed, tested, and verified the AI-generated content before submitting.

Note: autonomous AI agents submitting PRs without human oversight are not permitted — see the Code of Conduct.

cderv added 8 commits November 5, 2026 16:13
The tests/ R environment moves from renv to rig projects. Several
worktrees setting up their R environment at once hang for tens of
minutes on renv's shared cache and lock, and every R start in tests/
pays the renv autoloader. rig proj sync installs binaries without
running R or taking renv's lock.

rproj.toml is imported from renv.lock (renv itself dropped) and pins
R 4.6.x. rproj.lock is solved for Windows, macOS arm64, glibc Linux
and source; every package resolves to a P3M binary on the three OS
targets. .rvenvlib holds rig's generated activation shim and must be
committed. Nothing reads these files yet.
configure-test-env now runs rig proj sync, then installs the dev
rmarkdown and knitr from r-universe into the project library. The
install has to name both the library and the exact R version: rig's
default target is the default R's user library, which the project
library would shadow anyway.

run-tests points QUARTO_R at tests/.rvenv/bin. Quarto resolves Rscript
from QUARTO_R first, and the wrapper sets the R version and project
library itself, so R subprocesses started outside tests/ no longer need
a per-fixture .Rprofile. writeTestsRenvProfile and its two callers go.

tests/.Rprofile is deleted rather than left unused: it activated renv
in every R started in tests/, which is where the setup hangs came from.
tests/.Renviron is rig's committed hook for IDEs and a bare Rscript in
tests/. Every sync rewrites it with LF line endings, so it is checked
out as LF to stay unmodified under core.autocrlf. DESCRIPTION and
.renvignore only served renv's dependency discovery; rproj.toml is now
the manifest.
The smoke-test workflow installs a pinned rig and runs
rig proj sync --locked --no-install-r, so a stale lock fails the job
and the R from setup-r is used. The renv steps, including the renv
cache save and the renv::status() check, are gone; every locked package
is a P3M binary, so there is no cache for now.

Dev rmarkdown/knitr, extra-r-packages and sessioninfo are installed
into the project library afterwards, then checked through the project's
Rscript wrapper so the check sees what the tests load. extra-r-packages
now goes to rig pkg install; renv's pkg@1.2.3 is rewritten to
pkg@=1.2.3 because rig reads a bare version as a minimum.
README, the testing rules and the test-pattern notes described renv:
how to add a dependency, and the per-fixture .Rprofile that R tests
outside tests/ needed. With QUARTO_R pointing at the project's Rscript
wrapper that workaround and its rule are gone.
rBinaryPath() checks QUARTO_R against the current working directory on
every call and does not cache it, so a relative tests/.rvenv/bin stops
resolving once a test changes cwd and Quarto falls back to the R on
PATH. run-tests already exports an absolute path; the docs telling
contributors to set it themselves now say so too.
run-tests sets QUARTO_R to tests/.rvenv/bin, but the "Run Quarto test"
launch config starts deno test directly. Without QUARTO_R, tests that
run knitr from a cwd outside tests/ get the R on PATH and no project
library when debugged, now that no per-fixture .Rprofile activates one.
The lock targets Windows x86_64, macOS arm64 and Linux x86_64 only;
other platforms resolve to source packages. Release mode on a tag from
before the rig project now fails in each smoke leg, so D10 names that
requirement too. Also restore the trailing newline in
configuring-test-deps.md.
setup-r installs R on Windows into C:\R, but rig only looks for R
under C:\Program Files\R, so with --no-install-r the sync bound to the
runner image's own R rather than the pinned 4.6.1, and would fail once
the image moves to the next R minor. Dropping setup-r and letting
rig proj sync install the R version the lock needs gives every OS the
same R source as a contributor's machine: the latest 4.6.x, which the
lock was solved for, instead of a separately pinned patch release.
@posit-snyk-bot

posit-snyk-bot commented Nov 5, 2026 •

Copy link
Copy Markdown
Collaborator

✅ Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
✅ Open Source Security 0 0 0 0 0 issues
✅ Licenses 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

On Linux, when rig proj sync has to install R it re-runs the whole
sync under sudo, not only the R install. The project library in
tests/.rvenv/lib then ends up owned by root, and every later
rig pkg install as the runner user fails (rig reports only
"0 succeeded, 1 failed", without the permission error). This broke
all Linux smoke jobs at the dev/extra R packages step.

Installing R with rig add first keeps sudo to the R install, and the
sync goes back to --no-install-r, which rig's help suggests for CI.
The version comes from rproj.lock, so it stays the latest patch of
the minor the lock was solved for. Admin mode is kept over user mode,
which rig documents as less tested on Linux.
@mcanouil

mcanouil commented Nov 6, 2026

Copy link
Copy Markdown
Collaborator

FWIW, I've started switching to rig and so far I like it more than renv.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants