diff --git a/.github/actions/setup-r/action.yml b/.github/actions/setup-r/action.yml index 197ea92892..c4843e799c 100644 --- a/.github/actions/setup-r/action.yml +++ b/.github/actions/setup-r/action.yml @@ -10,7 +10,7 @@ inputs: description: "R version to install" required: false # Bump together with the snapshot date below: Posit Package Manager serves - # noble binaries per R minor version, so a new R needs a snapshot that has them. + # resolute binaries per R minor version, so a new R needs a snapshot that has them. default: "4.6.1" runs: @@ -49,9 +49,13 @@ runs: # install.packages auto-resolves transitive dependencies that a hand-written # renv.lock used to miss (munsell, gtable, colorspace, R6, RColorBrewer, ...). # Pinning to a dated Posit Package Manager snapshot keeps versions - # reproducible without needing a fully-populated lockfile. The `noble` URL - # matches the current ubuntu-latest runner image — update if GitHub moves - # the runner OS, and bump the snapshot date deliberately. + # reproducible without needing a fully-populated lockfile. The `resolute` + # URL matches the ubuntu-latest runner image (Ubuntu 26.04 since October + # 2026). Change the codename whenever GitHub moves the runner OS: Posit + # builds each binary against one release's system libraries, and the + # former `noble` (24.04) binaries installed fine on 26.04 but stringi + # failed to load there (it links libicuuc.so.74; 26.04 ships ICU 78). + # Bump the snapshot date deliberately. # # Snapshot 2026-10-20 ships ggplot2 4.0.3. The repository has no R lock # file, so this line stands in for one: core/library_versions.py reads @@ -60,7 +64,7 @@ runs: # tests/unit/core/test_version_sources.py until this line names the ggplot2 # version the new snapshot installs (packageVersion("ggplot2") in a run). # - # Every package below installs from this snapshot as a noble binary for + # Every package below installs from this snapshot as a resolute binary for # R 4.6.1. ggplot2 4.0 changes rendering defaults; the changes that matter # to generated code are listed in prompts/library/ggplot2.md. # @@ -73,7 +77,7 @@ runs: run: | Rscript -e ' options( - repos = c(CRAN = "https://packagemanager.posit.co/cran/__linux__/noble/2026-10-20"), + repos = c(CRAN = "https://packagemanager.posit.co/cran/__linux__/resolute/2026-10-20"), Ncpus = parallel::detectCores() ) install.packages( @@ -85,10 +89,15 @@ runs: ' - name: Smoke-test ggplot2 renders a PNG + # Loading tidyr and stringr also loads stringi, whose binary links the + # distro ICU by soname; str_detect() then calls into it. A Posit binary + # built for another Ubuntu release installs without error and fails only + # here, at load time, instead of in the middle of a generation run. shell: bash run: | Rscript -e ' - library(ggplot2); library(ragg) + library(ggplot2); library(ragg); library(tidyr); library(stringr) + stopifnot(str_detect("anyplot", "plot")) tmp <- tempfile(fileext = ".png") ggsave(tmp, ggplot(mtcars, aes(wt, mpg)) + geom_point(), device = ragg::agg_png, width = 4, height = 3, dpi = 100) diff --git a/changelog.d/setup-r-resolute.md b/changelog.d/setup-r-resolute.md new file mode 100644 index 0000000000..f7c2c7283e --- /dev/null +++ b/changelog.d/setup-r-resolute.md @@ -0,0 +1,12 @@ +### Fixed + +- **The R setup installs packages built for the Ubuntu 26.04 runner image.** The + setup-r action installed Posit's `noble` (Ubuntu 24.04) binaries. On the 26.04 + image they install without error, but stringi links ICU 74 while 26.04 ships + ICU 78, so loading stringr fails. No catalogue implementation reaches stringi + today: all 325 render the same on both builds. A generated implementation that + used stringr, or tidyr's `separate()` or `extract()`, would have failed + mid-run. The action now installs the `resolute` binaries from the same + 2026-10-20 snapshot. Its smoke test also loads tidyr and stringr, so a binary + built for another Ubuntu release fails the setup step instead of a generation + run. (#12263) diff --git a/tests/unit/core/test_version_sources.py b/tests/unit/core/test_version_sources.py index defe11a93c..51c59b07d6 100644 --- a/tests/unit/core/test_version_sources.py +++ b/tests/unit/core/test_version_sources.py @@ -135,7 +135,7 @@ def test_uv_lock_with_a_duplicated_block_does_not_resolve(tmp_path: Path) -> Non SETUP_R = """ # Snapshot {note} ships ggplot2 3.5.1. The repository has no R lock file. run: | - Rscript -e 'options(repos = c(CRAN = "https://packagemanager.posit.co/cran/__linux__/noble/{url}"))' + Rscript -e 'options(repos = c(CRAN = "https://packagemanager.posit.co/cran/__linux__/resolute/{url}"))' """