From 6fad6db46002457ea0fe18a86d1c544a096502d0 Mon Sep 17 00:00:00 2001 From: Vincent Guyader Date: Sat, 25 Apr 2026 23:14:26 +0200 Subject: [PATCH 1/3] =?UTF-8?q?fix:=203=20issues=20=E2=80=94=20ggplot2=20d?= =?UTF-8?q?eprecation=20(#13),=20random=5Fimage=20args=20(#9),=20n=5Fbars?= =?UTF-8?q?=20(#5)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - #13: random_ggplot('line') was using geom_line(size=) which ggplot2 >= 3.4 deprecated in favour of linewidth=. Switch the call. Regression test builds a 'line' plot and asserts no lifecycle warning, plus a static sweep on Plot.R. - #9: random_image() now accepts width / height / alt and includes them in the returned list when set. Default shape unchanged (just src). - #5: random_ggplot('bar', n_bars = n) generates a synthetic categorical data frame so the rendered plot has *exactly* n bars. Without the argument, the legacy datasets-based behaviour is kept. Tracking notes in dev/SUIVI_ISSUES.md. --- R/Image.R | 17 +++++++++-- R/Plot.R | 39 ++++++++++++++++++++++-- dev/SUIVI_ISSUES.md | 17 +++++++++++ man/random_ggplot.Rd | 7 ++++- man/random_image.Rd | 14 +++++++-- man/shinipsum-package.Rd | 3 +- tests/testthat/test-bar_n.R | 24 +++++++++++++++ tests/testthat/test-image_args.R | 20 ++++++++++++ tests/testthat/test-no_deprecated_args.R | 26 ++++++++++++++++ 9 files changed, 157 insertions(+), 10 deletions(-) create mode 100644 dev/SUIVI_ISSUES.md create mode 100644 tests/testthat/test-bar_n.R create mode 100644 tests/testthat/test-image_args.R create mode 100644 tests/testthat/test-no_deprecated_args.R diff --git a/R/Image.R b/R/Image.R index a3fbadd..d7a8d96 100644 --- a/R/Image.R +++ b/R/Image.R @@ -2,14 +2,25 @@ #' #' This function returns a random image that can be passed into `renderImage` and `plotOutput`. #' -#' @return an image +#' @param width image width passed through to the rendered `` tag. +#' `NULL` (default) leaves the attribute unset (#9). +#' @param height image height, same semantics as `width` (#9). +#' @param alt `alt` attribute for accessibility. `NULL` (default) leaves +#' the attribute unset (#9). +#' +#' @return a list compatible with `shiny::renderImage()`: `src`, plus the +#' `width` / `height` / `alt` attributes when provided. #' #' @export -random_image <- function(){ +random_image <- function(width = NULL, height = NULL, alt = NULL){ l <- list.files(system.file("img", package = "shinipsum"), full.names = TRUE) img <- normalizePath(sample(l, 1)) tmpimg <- paste(tempfile(), basename(img), sep = "-") file.copy(img, tmpimg) - list(src = tmpimg) + out <- list(src = tmpimg) + if (!is.null(width)) out$width <- width + if (!is.null(height)) out$height <- height + if (!is.null(alt)) out$alt <- alt + out } diff --git a/R/Plot.R b/R/Plot.R index 217f78e..0fdeabe 100644 --- a/R/Plot.R +++ b/R/Plot.R @@ -1,8 +1,21 @@ +#' Build the categorical labels used by random_ggplot('bar', n_bars=). +#' @noRd +make_bar_labels <- function(n) { + if (n <= 26L) { + LETTERS[seq_len(n)] + } else { + sprintf("Cat%02d", seq_len(n)) + } +} + #' A Random ggplot #' #' This function returns a ggplot object, which can be passed to `renderPlot` and `plotOutput` #' #' @param type type of the geom. Can be any of "random", "point", "bar", "boxplot","col", "tile", "line", "bin2d", "contour", "density", "density_2d", "dotplot", "hex", "freqpoly", "histogram", "ribbon", "raster", "tile", "violin" and defines the geom of the ggplot. Default is "random", and chooses a random geom for you. +#' @param n_bars integer, number of bars to draw when `type == "bar"`. When +#' `NULL` (default), one of the built-in datasets is sampled; otherwise +#' a synthetic data frame with `n_bars` categories is used (#5). #' #' @importFrom ggplot2 ggplot aes geom_point geom_bar scale_color_viridis_d theme_minimal geom_boxplot labs coord_flip geom_tile geom_line facet_grid geom_col scale_fill_viridis_c #' @importFrom ggplot2 xlim ylim geom_bin2d geom_contour geom_density geom_density_2d geom_dotplot @@ -18,7 +31,8 @@ random_ggplot <- function(type = c("random", "point", "bar", "density", "density_2d", "dotplot", "hex", "freqpoly", "histogram", "ribbon", "raster", "tile", - "violin")) { + "violin"), + n_bars = NULL) { type_matched <- match.arg(type) if (type_matched == "random") { @@ -28,6 +42,27 @@ random_ggplot <- function(type = c("random", "point", "bar", type_matched <- sample( form, 1 ) } + # User asked for a specific number of bars -> short-circuit the + # builtin-dataset switch with synthetic data so we hit exactly n_bars (#5). + if (type_matched == "bar" && !is.null(n_bars)) { + stopifnot(is.numeric(n_bars), length(n_bars) == 1L, + !is.na(n_bars), n_bars >= 1L) + n_bars <- as.integer(n_bars) + df <- data.frame( + category = factor(make_bar_labels(n_bars), + levels = make_bar_labels(n_bars)), + value = sample.int(100L, n_bars, replace = TRUE) + ) + return( + ggplot2::ggplot(df) + + ggplot2::aes(category, value, fill = category) + + ggplot2::geom_col() + + ggplot2::scale_fill_viridis_d() + + ggplot2::theme_minimal() + + ggplot2::theme(legend.position = "none") + ) + } + r <- switch(as.character(type_matched), "point" = sample(0:5, 1), "bar" = sample(10:11, 1), @@ -144,7 +179,7 @@ random_ggplot <- function(type = c("random", "point", "bar", "50" = list( ggplot(datasets::women) + aes(height, weight) + - geom_line(size = 2) + + geom_line(linewidth = 2) + theme_minimal() ), "51" = list( diff --git a/dev/SUIVI_ISSUES.md b/dev/SUIVI_ISSUES.md new file mode 100644 index 0000000..492b58d --- /dev/null +++ b/dev/SUIVI_ISSUES.md @@ -0,0 +1,17 @@ +# Suivi — passe `fix/multiple-issues` + +| # | Type | Résumé | Fix | Test | +|---|---|---|---|---| +| #13 | bug | `random_ggplot("line")` triggered ggplot2's `size→linewidth` deprecation warning | `geom_line(size = 2)` -> `geom_line(linewidth = 2)` | `tests/testthat/test-no_deprecated_args.R` (build no warning + static sweep) | +| #9 | feat | `random_image()` couldn't propagate `width` / `height` / `alt` | new params `width = NULL, height = NULL, alt = NULL` (kept default `list(src = ...)` shape) | `tests/testthat/test-image_args.R` | +| #5 | feat | no way to control the number of bars in `random_ggplot("bar")` | new `n_bars = NULL` parameter — when set, generates a synthetic categorical data frame so the rendered plot has *exactly* that many bars | `tests/testthat/test-bar_n.R` (1 / 3 / 7 / 27 bars + invalid input) | + +## Issues envisagées mais non traitées + +| # | Pourquoi pas | +|---|---| +| #4 | "time series option" — design choice (date axis, density, faceting) à arbitrer avec mainteneur. | +| #3 | "other lorem ipsum options" — choix de corpora alternatifs (cat ipsum, hipster ipsum…), demande d'inclure de nouveaux assets. | +| #2 | "Release 0.1.0" — meta. | +| #1 | `mock_frame()` — feature, demande design. | +| #10 | `_R_CHECK_USE_CODETOOLS_=false` — dépend du contexte de test downstream. | diff --git a/man/random_ggplot.Rd b/man/random_ggplot.Rd index 07a25c6..bf2257f 100644 --- a/man/random_ggplot.Rd +++ b/man/random_ggplot.Rd @@ -7,11 +7,16 @@ random_ggplot( type = c("random", "point", "bar", "boxplot", "col", "tile", "line", "bin2d", "contour", "density", "density_2d", "dotplot", "hex", "freqpoly", "histogram", - "ribbon", "raster", "tile", "violin") + "ribbon", "raster", "tile", "violin"), + n_bars = NULL ) } \arguments{ \item{type}{type of the geom. Can be any of "random", "point", "bar", "boxplot","col", "tile", "line", "bin2d", "contour", "density", "density_2d", "dotplot", "hex", "freqpoly", "histogram", "ribbon", "raster", "tile", "violin" and defines the geom of the ggplot. Default is "random", and chooses a random geom for you.} + +\item{n_bars}{integer, number of bars to draw when \code{type == "bar"}. When +\code{NULL} (default), one of the built-in datasets is sampled; otherwise +a synthetic data frame with \code{n_bars} categories is used (#5).} } \value{ a ggplot diff --git a/man/random_image.Rd b/man/random_image.Rd index c699a5e..d150da0 100644 --- a/man/random_image.Rd +++ b/man/random_image.Rd @@ -4,10 +4,20 @@ \alias{random_image} \title{A Random Image} \usage{ -random_image() +random_image(width = NULL, height = NULL, alt = NULL) +} +\arguments{ +\item{width}{image width passed through to the rendered \verb{} tag. +\code{NULL} (default) leaves the attribute unset (#9).} + +\item{height}{image height, same semantics as \code{width} (#9).} + +\item{alt}{\code{alt} attribute for accessibility. \code{NULL} (default) leaves +the attribute unset (#9).} } \value{ -an image +a list compatible with \code{shiny::renderImage()}: \code{src}, plus the +\code{width} / \code{height} / \code{alt} attributes when provided. } \description{ This function returns a random image that can be passed into \code{renderImage} and \code{plotOutput}. diff --git a/man/shinipsum-package.Rd b/man/shinipsum-package.Rd index b0b0ca3..0fa84ce 100644 --- a/man/shinipsum-package.Rd +++ b/man/shinipsum-package.Rd @@ -6,8 +6,7 @@ \alias{shinipsum-package} \title{shinipsum: Lorem-Ipsum-like Helpers for fast Shiny Prototyping} \description{ -Prototype your shiny apps quickly with these - Lorem-Ipsum-like Helpers. +Prototype your shiny apps quickly with these Lorem-Ipsum-like Helpers. } \seealso{ Useful links: diff --git a/tests/testthat/test-bar_n.R b/tests/testthat/test-bar_n.R new file mode 100644 index 0000000..afc7747 --- /dev/null +++ b/tests/testthat/test-bar_n.R @@ -0,0 +1,24 @@ +test_that("random_ggplot('bar', n_bars=) produces exactly n bars (#5)", { + for (n in c(1L, 3L, 7L, 27L)) { + p <- random_ggplot("bar", n_bars = n) + expect_s3_class(p, "ggplot") + # Build the plot and count distinct bars in the rendered data layer. + built <- ggplot2::ggplot_build(p) + bars <- nrow(built$data[[1]]) + expect_equal(bars, n, + info = paste0("requested ", n, " bars, got ", bars)) + } +}) + +test_that("random_ggplot('bar') without n_bars keeps the legacy datasets behaviour", { + withr::with_seed(1, { + p <- random_ggplot("bar") + }) + expect_s3_class(p, "ggplot") +}) + +test_that("random_ggplot rejects nonsense n_bars (#5)", { + expect_error(random_ggplot("bar", n_bars = -1)) + expect_error(random_ggplot("bar", n_bars = "five")) + expect_error(random_ggplot("bar", n_bars = c(3, 4))) +}) diff --git a/tests/testthat/test-image_args.R b/tests/testthat/test-image_args.R new file mode 100644 index 0000000..3dfc011 --- /dev/null +++ b/tests/testthat/test-image_args.R @@ -0,0 +1,20 @@ +test_that("random_image() returns just `src` by default (regression)", { + res <- random_image() + expect_type(res, "list") + expect_named(res, "src") + expect_true(file.exists(res$src)) +}) + +test_that("random_image(width=, height=, alt=) propagates the arguments (#9)", { + res <- random_image(width = "100px", height = "80px", alt = "Yo") + expect_named(res, c("src", "width", "height", "alt")) + expect_equal(res$width, "100px") + expect_equal(res$height, "80px") + expect_equal(res$alt, "Yo") +}) + +test_that("random_image() drops NULL extras (#9)", { + res <- random_image(width = "200px") + expect_named(res, c("src", "width")) + expect_equal(res$width, "200px") +}) diff --git a/tests/testthat/test-no_deprecated_args.R b/tests/testthat/test-no_deprecated_args.R new file mode 100644 index 0000000..c6be9d3 --- /dev/null +++ b/tests/testthat/test-no_deprecated_args.R @@ -0,0 +1,26 @@ +test_that("random_ggplot('line') does not emit ggplot2 'size' deprecation (#13)", { + # ggplot2 >= 3.4 deprecated size= for line geoms in favour of linewidth=. + # Force the line geom by passing type = 'line'; either of the two line + # variants must be deprecation-clean. + withr::with_seed(42, { + p <- random_ggplot("line") + }) + # Building the plot is what triggers the lifecycle warning, not the + # construction. expect_no_warning() requires testthat 3.1.5+. + if (utils::packageVersion("testthat") >= "3.1.5") { + expect_no_warning(invisible(ggplot2::ggplot_build(p))) + } else { + msgs <- capture_warnings(invisible(ggplot2::ggplot_build(p))) + expect_false(any(grepl("size.*deprecated", msgs))) + } +}) + +test_that("Plot.R does not reference geom_line(size = ...) (#13)", { + # Static sweep: ggplot2 deprecated size= on every line geom in 3.4. + src <- readLines(system.file("R", "Plot.R", package = "shinipsum")) + if (length(src) == 0) { + src <- readLines(file.path(testthat::test_path(), "..", "..", "R", "Plot.R")) + } + expect_false(any(grepl("geom_line\\([^)]*size\\s*=", src)), + info = "geom_line() should use linewidth = ... instead of size = ...") +}) From 01b3e386a9ac3c9847d81fcaea1de5776fddaca0 Mon Sep 17 00:00:00 2001 From: Vincent Guyader Date: Sat, 25 Apr 2026 23:23:53 +0200 Subject: [PATCH 2/3] fix(asciify): clean R CMD check (no withr in tests, declare globals, drop brittle sweep) - Drop withr::with_seed() in tests in favour of an inline set.seed/.Random.seed save-restore: withr is not declared in the package's DESCRIPTION, R CMD check NOTE'd '::' import not declared. - Declare 'category' and 'value' in R/globals.R: random_ggplot('bar', n_bars=) uses them in aes() and was raising 'no visible binding'. - Drop the static-sweep test in test-no_deprecated_args.R: it tried to read R/Plot.R from the source tree, which doesn't exist past installation, so R CMD check tests errored. The first regression test (build the plot, assert no lifecycle warning) is sufficient. --- DESCRIPTION | 2 +- R/globals.R | 4 +++- tests/testthat/test-bar_n.R | 15 ++++++++++++--- tests/testthat/test-no_deprecated_args.R | 24 ++++++++++++------------ 4 files changed, 28 insertions(+), 17 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index af6527b..b1faa67 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -36,4 +36,4 @@ Suggests: Encoding: UTF-8 LazyData: true Roxygen: list(markdown = TRUE) -RoxygenNote: 7.1.1 +RoxygenNote: 7.3.3 diff --git a/R/globals.R b/R/globals.R index 9560def..5a79f87 100644 --- a/R/globals.R +++ b/R/globals.R @@ -13,7 +13,9 @@ utils::globalVariables(unique(c( "x", "y", "depth", "cut", "carat", "price", "color", "year", "level", - "z", "w" + "z", "w", + # random_ggplot('bar', n_bars=) + "category", "value" # random dygraphs # @importFrom datasets mdeaths fdeaths ldeaths nhtemp AirPassengers discoveries presidents austres diff --git a/tests/testthat/test-bar_n.R b/tests/testthat/test-bar_n.R index afc7747..0682d5c 100644 --- a/tests/testthat/test-bar_n.R +++ b/tests/testthat/test-bar_n.R @@ -11,9 +11,18 @@ test_that("random_ggplot('bar', n_bars=) produces exactly n bars (#5)", { }) test_that("random_ggplot('bar') without n_bars keeps the legacy datasets behaviour", { - withr::with_seed(1, { - p <- random_ggplot("bar") - }) + old_seed <- if (exists(".Random.seed", envir = .GlobalEnv, inherits = FALSE)) { + get(".Random.seed", envir = .GlobalEnv) + } else NULL + on.exit( + if (!is.null(old_seed)) assign(".Random.seed", old_seed, envir = .GlobalEnv) + else if (exists(".Random.seed", envir = .GlobalEnv, inherits = FALSE)) { + rm(list = ".Random.seed", envir = .GlobalEnv) + }, + add = TRUE + ) + set.seed(1) + p <- random_ggplot("bar") expect_s3_class(p, "ggplot") }) diff --git a/tests/testthat/test-no_deprecated_args.R b/tests/testthat/test-no_deprecated_args.R index c6be9d3..18a238e 100644 --- a/tests/testthat/test-no_deprecated_args.R +++ b/tests/testthat/test-no_deprecated_args.R @@ -2,9 +2,18 @@ test_that("random_ggplot('line') does not emit ggplot2 'size' deprecation (#13)" # ggplot2 >= 3.4 deprecated size= for line geoms in favour of linewidth=. # Force the line geom by passing type = 'line'; either of the two line # variants must be deprecation-clean. - withr::with_seed(42, { - p <- random_ggplot("line") - }) + old_seed <- if (exists(".Random.seed", envir = .GlobalEnv, inherits = FALSE)) { + get(".Random.seed", envir = .GlobalEnv) + } else NULL + on.exit( + if (!is.null(old_seed)) assign(".Random.seed", old_seed, envir = .GlobalEnv) + else if (exists(".Random.seed", envir = .GlobalEnv, inherits = FALSE)) { + rm(list = ".Random.seed", envir = .GlobalEnv) + }, + add = TRUE + ) + set.seed(42) + p <- random_ggplot("line") # Building the plot is what triggers the lifecycle warning, not the # construction. expect_no_warning() requires testthat 3.1.5+. if (utils::packageVersion("testthat") >= "3.1.5") { @@ -15,12 +24,3 @@ test_that("random_ggplot('line') does not emit ggplot2 'size' deprecation (#13)" } }) -test_that("Plot.R does not reference geom_line(size = ...) (#13)", { - # Static sweep: ggplot2 deprecated size= on every line geom in 3.4. - src <- readLines(system.file("R", "Plot.R", package = "shinipsum")) - if (length(src) == 0) { - src <- readLines(file.path(testthat::test_path(), "..", "..", "R", "Plot.R")) - } - expect_false(any(grepl("geom_line\\([^)]*size\\s*=", src)), - info = "geom_line() should use linewidth = ... instead of size = ...") -}) From c1ced3ea97b25b0a258d59f6eb7e51a3a887bead Mon Sep 17 00:00:00 2001 From: Vincent Guyader Date: Sat, 25 Apr 2026 23:24:36 +0200 Subject: [PATCH 3/3] ci: modernize workflows (cache@v2 / R-CMD-check checkout) Pre-existing CI used actions/cache@v2 (now hard-failed by GitHub) and r-lib/actions setup-r@v1. Replace test-coverage and pkgdown with the standard r-lib/actions v2 templates on ubuntu-latest, bump R-CMD-check checkout v3 -> v5 (Node.js 24). --- .github/workflows/R-CMD-check.yaml | 2 +- .github/workflows/pkgdown.yaml | 54 +++++++++++++--------------- .github/workflows/test-coverage.yaml | 42 +++++++--------------- 3 files changed, 38 insertions(+), 60 deletions(-) diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml index a3ac618..21efb73 100644 --- a/.github/workflows/R-CMD-check.yaml +++ b/.github/workflows/R-CMD-check.yaml @@ -29,7 +29,7 @@ jobs: R_KEEP_PKG_SOURCE: yes steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v5 - uses: r-lib/actions/setup-pandoc@v2 diff --git a/.github/workflows/pkgdown.yaml b/.github/workflows/pkgdown.yaml index ea362c8..1194d5e 100644 --- a/.github/workflows/pkgdown.yaml +++ b/.github/workflows/pkgdown.yaml @@ -1,47 +1,41 @@ +# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples on: push: branches: [main, master] + workflow_dispatch: name: pkgdown jobs: pkgdown: - runs-on: macOS-latest + runs-on: ubuntu-latest env: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} - steps: - - uses: actions/checkout@v2 + permissions: + contents: write - - uses: r-lib/actions/setup-r@v1 + steps: + - uses: actions/checkout@v5 - - uses: r-lib/actions/setup-pandoc@v1 + - uses: r-lib/actions/setup-pandoc@v2 - - name: Query dependencies - run: | - install.packages('remotes') - saveRDS(remotes::dev_package_deps(dependencies = TRUE), ".github/depends.Rds", version = 2) - writeLines(sprintf("R-%i.%i", getRversion()$major, getRversion()$minor), ".github/R-version") - shell: Rscript {0} + - uses: r-lib/actions/setup-r@v2 + with: + use-public-rspm: true - - name: Cache R packages - uses: actions/cache@v2 + - uses: r-lib/actions/setup-r-dependencies@v2 with: - path: ${{ env.R_LIBS_USER }} - key: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1-${{ hashFiles('.github/depends.Rds') }} - restore-keys: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1- - - - name: Install dependencies - run: | - remotes::install_deps(dependencies = TRUE) - remotes::install_github("ThinkR-open/thinkrtemplate") - install.packages("pkgdown", type = "binary") - shell: Rscript {0} + extra-packages: any::pkgdown, ThinkR-open/thinkrtemplate + needs: website - - name: Install package - run: R CMD INSTALL . + - name: Build site + run: pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE) + shell: Rscript {0} - - name: Deploy package - run: | - git config --local user.email "actions@github.com" - git config --local user.name "GitHub Actions" - Rscript -e 'pkgdown::deploy_to_branch(new_process = FALSE)' + - name: Deploy to GitHub pages + if: github.event_name != 'pull_request' + uses: JamesIves/github-pages-deploy-action@v4.5.0 + with: + clean: false + branch: gh-pages + folder: docs diff --git a/.github/workflows/test-coverage.yaml b/.github/workflows/test-coverage.yaml index 0182b4e..731cc6c 100644 --- a/.github/workflows/test-coverage.yaml +++ b/.github/workflows/test-coverage.yaml @@ -1,46 +1,30 @@ +# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples on: push: - branches: - - master + branches: [main, master] pull_request: - branches: - - master + branches: [main, master] name: test-coverage jobs: test-coverage: - runs-on: macOS-latest + runs-on: ubuntu-latest env: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} - steps: - - uses: actions/checkout@v2 - - - uses: r-lib/actions/setup-r@v1 - - uses: r-lib/actions/setup-pandoc@v1 - - - name: Query dependencies - run: | - install.packages('remotes') - saveRDS(remotes::dev_package_deps(dependencies = TRUE), ".github/depends.Rds", version = 2) - writeLines(sprintf("R-%i.%i", getRversion()$major, getRversion()$minor), ".github/R-version") - shell: Rscript {0} + steps: + - uses: actions/checkout@v5 - - name: Cache R packages - uses: actions/cache@v2 + - uses: r-lib/actions/setup-r@v2 with: - path: ${{ env.R_LIBS_USER }} - key: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1-${{ hashFiles('.github/depends.Rds') }} - restore-keys: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1- + use-public-rspm: true - - name: Install dependencies - run: | - install.packages(c("remotes")) - remotes::install_deps(dependencies = TRUE) - remotes::install_cran("covr") - shell: Rscript {0} + - uses: r-lib/actions/setup-r-dependencies@v2 + with: + extra-packages: any::covr + needs: coverage - name: Test coverage - run: covr::codecov() + run: covr::codecov(quiet = FALSE) shell: Rscript {0}