From ca2009f897e9b5e5fe15e750d8efa4da7432eb4d Mon Sep 17 00:00:00 2001 From: Hadley Wickham Date: Thu, 12 Feb 2026 14:56:15 -0600 Subject: [PATCH 1/2] Move remotes to suggests Fixes #2663 --- DESCRIPTION | 2 +- NEWS.md | 2 ++ R/check-devtools.R | 2 +- R/check.R | 5 ++++- R/install.R | 2 ++ R/remotes.R | 15 +++++++++++++++ R/sitrep.R | 33 +++++++++++++++++++++++++++++---- R/vignettes.R | 2 +- README.md | 5 ++--- man/build_vignettes.Rd | 25 ------------------------- tests/testthat/_snaps/sitrep.md | 4 ++-- tests/testthat/test-sitrep.R | 19 +++++++++++++++++++ 12 files changed, 78 insertions(+), 38 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 9f9e4ba8a..6540061a9 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -31,7 +31,6 @@ Imports: pkgload (>= 1.4.1), profvis (>= 0.4.0), rcmdcheck (>= 1.4.0), - remotes (>= 2.5.0), rlang (>= 1.1.6), roxygen2 (>= 7.3.3), rversions (>= 2.1.2), @@ -51,6 +50,7 @@ Suggests: httr (>= 1.4.3), knitr (>= 1.39), lintr (>= 3.0.0), + remotes (>= 2.5.0), rmarkdown (>= 2.14), rstudioapi (>= 0.13), spelling (>= 2.2) diff --git a/NEWS.md b/NEWS.md index 16cb6e9e7..f93a8941b 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,11 +1,13 @@ # devtools (development version) +* remotes has moved from Imports to Suggests (#2663). * `bash()`, `create()`, `missing_s3()`, `reload()`, `show_news()`, and `wd()` are now deprecated. These functions are all historical parts of our workflow that we no longer use or recommend. `create()` is superseded by `usethis::create_package()`. * `build_manual()` reports more details on failure (#2586). * `check_doc_fields()` is a new function that checks for missing `\value` and `\examples` fields in Rd files, which are commonly flagged by CRAN (#2525). * `build_vignettes()` and `clean_vignettes()` are now deprecated. We no longer recommend building vignettes in this way; instead use `pkgdown::build_article()` to render articles locally (#2488). * `build_site()` now just calls `pkgdown::build_site()`, meaning that you will get more (informative) output by default (#2578). * New `check_mac_devel()` function to check a package using the macOS builder at https://mac.r-project.org/macbuilder/submit.html (@nfrerebeau, #2507) +* `dev_sitrep()` now uses pak instead of remotes to check for outdated dependencies (#2663). * `dev_sitrep()` now uses cli for user-facing messages instead of deprecated usethis UI functions. * `dev_sitrep()` now works correctly in Positron (#2618). * `is_loading()` is now re-exported from pkgload (#2556). diff --git a/R/check-devtools.R b/R/check-devtools.R index 29e767b2c..a2b2f9d83 100644 --- a/R/check-devtools.R +++ b/R/check-devtools.R @@ -22,7 +22,7 @@ release_checks <- function(pkg = ".", built_path = NULL) { check_dev_versions <- function(pkg = ".") { pkg <- as.package(pkg) - dep_list <- pkg[tolower(remotes::standardise_dep(TRUE))] + dep_list <- pkg[tolower(c("Depends", "Imports", "LinkingTo", "Suggests"))] deps <- do.call("rbind", unname(compact(lapply(dep_list, parse_deps)))) deps <- deps[!is.na(deps$version), , drop = FALSE] diff --git a/R/check.R b/R/check.R index 50adc42cd..5e49fc945 100644 --- a/R/check.R +++ b/R/check.R @@ -133,7 +133,10 @@ check <- function( ) } -can_document <- function(required, installed = utils::packageVersion("roxygen2")) { +can_document <- function( + required, + installed = utils::packageVersion("roxygen2") +) { if (is.null(required)) { return(FALSE) } diff --git a/R/install.R b/R/install.R index 99040b5dd..6a26b1fca 100644 --- a/R/install.R +++ b/R/install.R @@ -181,6 +181,7 @@ install_deps <- function( check_dots_used(action = getOption("devtools.ellipsis_action", warn)) + check_installed("remotes") remotes::install_deps( pkg$path, dependencies = dependencies, @@ -212,6 +213,7 @@ install_dev_deps <- function( "install_dev_deps()", "pak::local_install_dev_deps()" ) + check_installed("remotes") remotes::update_packages("roxygen2") pkg <- as.package(pkg) diff --git a/R/remotes.R b/R/remotes.R index ed9d57d48..d57abeb5d 100644 --- a/R/remotes.R +++ b/R/remotes.R @@ -40,6 +40,7 @@ install_bioc <- function(...) { "install_bioc()", I('pak::pak("bioc::pkg")') ) + check_installed("remotes") pkgbuild::with_build_tools(remotes::install_bioc(...), required = FALSE) } @@ -51,6 +52,7 @@ install_bitbucket <- function(...) { "install_bitbucket()", "remotes::install_bitbucket()" ) + check_installed("remotes") pkgbuild::with_build_tools(remotes::install_bitbucket(...), required = FALSE) } @@ -58,6 +60,7 @@ install_bitbucket <- function(...) { #' @export install_cran <- function(...) { lifecycle::deprecate_warn("2.5.0", "install_cran()", "pak::pak()") + check_installed("remotes") pkgbuild::with_build_tools(remotes::install_cran(...), required = FALSE) } @@ -65,6 +68,7 @@ install_cran <- function(...) { #' @export install_dev <- function(...) { lifecycle::deprecate_warn("2.5.0", "install_dev()", "remotes::install_dev()") + check_installed("remotes") pkgbuild::with_build_tools(remotes::install_dev(...), required = FALSE) } @@ -72,6 +76,7 @@ install_dev <- function(...) { #' @export install_git <- function(...) { lifecycle::deprecate_warn("2.5.0", "install_git()", I('pak::pak("git::url")')) + check_installed("remotes") pkgbuild::with_build_tools(remotes::install_git(...), required = FALSE) } @@ -83,6 +88,7 @@ install_github <- function(...) { "install_github()", I('pak::pak("user/repo")') ) + check_installed("remotes") pkgbuild::with_build_tools(remotes::install_github(...), required = FALSE) } @@ -94,6 +100,7 @@ install_gitlab <- function(...) { "install_gitlab()", I('pak::pak("gitlab::user/repo")') ) + check_installed("remotes") pkgbuild::with_build_tools(remotes::install_gitlab(...), required = FALSE) } @@ -105,6 +112,7 @@ install_local <- function(...) { "install_local()", I('pak::pak("local::path")') ) + check_installed("remotes") pkgbuild::with_build_tools(remotes::install_local(...), required = FALSE) } @@ -112,6 +120,7 @@ install_local <- function(...) { #' @export install_svn <- function(...) { lifecycle::deprecate_warn("2.5.0", "install_svn()", "remotes::install_svn()") + check_installed("remotes") pkgbuild::with_build_tools(remotes::install_svn(...), required = FALSE) } @@ -119,6 +128,7 @@ install_svn <- function(...) { #' @export install_url <- function(...) { lifecycle::deprecate_warn("2.5.0", "install_url()", I('pak::pak("url::url")')) + check_installed("remotes") pkgbuild::with_build_tools(remotes::install_url(...), required = FALSE) } @@ -130,6 +140,7 @@ install_version <- function(...) { "install_version()", I('pak::pak("pkg@version")') ) + check_installed("remotes") pkgbuild::with_build_tools(remotes::install_version(...), required = FALSE) } @@ -137,6 +148,7 @@ install_version <- function(...) { #' @export update_packages <- function(...) { lifecycle::deprecate_warn("2.5.0", "update_packages()", "pak::pak()") + check_installed("remotes") pkgbuild::with_build_tools(remotes::update_packages(...), required = FALSE) } @@ -148,6 +160,7 @@ dev_package_deps <- function(...) { "dev_package_deps()", "pak::local_dev_deps()" ) + check_installed("remotes") pkgbuild::with_build_tools(remotes::dev_package_deps(...), required = FALSE) } @@ -155,6 +168,7 @@ dev_package_deps <- function(...) { #' @export github_pull <- function(...) { lifecycle::deprecate_warn("2.5.0", "github_pull()", "remotes::github_pull()") + check_installed("remotes") remotes::github_pull(...) } @@ -166,5 +180,6 @@ github_release <- function(...) { "github_release()", "remotes::github_release()" ) + check_installed("remotes") remotes::github_release(...) } diff --git a/R/sitrep.R b/R/sitrep.R index c37adbaff..997c6948d 100644 --- a/R/sitrep.R +++ b/R/sitrep.R @@ -112,9 +112,9 @@ dev_sitrep <- function(pkg = ".", debug = FALSE) { has_build_tools = has_build_tools, rtools_path = if (has_build_tools) pkgbuild::rtools_path(), devtools_version = utils::packageVersion("devtools"), - devtools_deps = remotes::package_deps("devtools", dependencies = NA), + devtools_deps = outdated_deps(pak::pkg_deps("devtools", dependencies = NA)), pkg_deps = if (!is.null(pkg)) { - remotes::dev_package_deps(pkg$path, dependencies = TRUE) + outdated_deps(pak::local_dev_deps(pkg$path, dependencies = TRUE)) }, rstudio_version = if (is_rstudio_running()) rstudioapi::getVersion(), rstudio_msg = if (!is_positron()) check_for_rstudio_updates() @@ -199,7 +199,7 @@ print.dev_sitrep <- function(x, ...) { cli::cli_bullets(c( "!" = "{.pkg devtools} or its dependencies out of date:", " " = "{.val {x$devtools_deps$package[devtools_deps_old]}}", - " " = "Update them with {.code devtools::update_packages(\"devtools\")}" + " " = "Update them with {.code pak::pak(\"devtools\")}" )) all_ok <- FALSE } @@ -213,7 +213,7 @@ print.dev_sitrep <- function(x, ...) { cli::cli_bullets(c( "!" = "{.field {x$pkg$package}} dependencies out of date:", " " = "{.val {x$pkg_deps$package[pkg_deps_old]}}", - " " = "Update them with {.code devtools::install_dev_deps()}" + " " = "Update them with {.code pak::local_install_dev_deps()}" )) all_ok <- FALSE } @@ -228,6 +228,31 @@ print.dev_sitrep <- function(x, ...) { # Helpers ----------------------------------------------------------------- +outdated_deps <- function(deps) { + installed <- vapply( + deps$package, + function(p) { + tryCatch( + as.character(utils::packageVersion(p)), + error = function(e) NA_character_ + ) + }, + character(1) + ) + diff <- mapply( + function(inst, avail) { + if (is.na(inst)) { + return(-1L) + } + as.integer(utils::compareVersion(inst, avail)) + }, + installed, + deps$version, + USE.NAMES = FALSE + ) + data.frame(package = deps$package, diff = diff) +} + kv_line <- function(key, value, path = FALSE) { if (is.null(value)) { cli::cli_inform(c("*" = "{key}: {.silver }")) diff --git a/R/vignettes.R b/R/vignettes.R index 453f54424..d4ae701a2 100644 --- a/R/vignettes.R +++ b/R/vignettes.R @@ -18,7 +18,6 @@ #' outputs. See #' . #' @inheritParams tools::buildVignettes -#' @inheritParams remotes::install_deps #' @importFrom stats update #' @keywords internal #' @export @@ -40,6 +39,7 @@ build_vignettes <- function( return(invisible()) } + check_installed("remotes") deps <- remotes::dev_package_deps(pkg$path, dependencies) update(deps, upgrade = upgrade) diff --git a/README.md b/README.md index 22bdf6a70..e19b980a8 100644 --- a/README.md +++ b/README.md @@ -130,8 +130,7 @@ includes: * [roxygen2](https://github.com/r-lib/roxygen2): Function and package documentation (i.e. `document()`). -* [remotes](https://github.com/r-lib/remotes): Installing packages (i.e. - `install_github()`). +* [pak](https://pak.r-lib.org): Installing packages (i.e. `pak::pak()`). * [pkgbuild](https://github.com/r-lib/pkgbuild): Building binary packages (including checking if build tools are available) (i.e. `build()`). @@ -161,7 +160,7 @@ You may also need to care if you are trying to use some devtools functionality in your own package or deployed application. Generally in these cases it is better to depend on the particular package directly rather than depend on devtools, e.g. use `sessioninfo::session_info()` rather than `devtools::session_info()`, -or `remotes::install_github()` vs `devtools::install_github()`. +or `pak::pak("user/repo")` vs `devtools::install_github("user/repo")`. However for day to day development we recommend you continue to use `library(devtools)` to quickly load all needed development tools, just like diff --git a/man/build_vignettes.Rd b/man/build_vignettes.Rd index 0818811ac..57e41c3be 100644 --- a/man/build_vignettes.Rd +++ b/man/build_vignettes.Rd @@ -18,34 +18,9 @@ build_vignettes( \item{pkg}{The package to use, can be a file path to the package or a package object. See \code{\link[=as.package]{as.package()}} for more information.} -\item{dependencies}{Which dependencies do you want to check? -Can be a character vector (selecting from "Depends", "Imports", -"LinkingTo", "Suggests", or "Enhances"), or a logical vector. - -\code{TRUE} is shorthand for "Depends", "Imports", "LinkingTo" and -"Suggests". \code{NA} is shorthand for "Depends", "Imports" and "LinkingTo" -and is the default. \code{FALSE} is shorthand for no dependencies (i.e. -just check this package, not its dependencies). - -The value "soft" means the same as \code{TRUE}, "hard" means the same as \code{NA}. - -You can also specify dependencies from one or more additional fields, -common ones include: -\itemize{ -\item Config/Needs/website - for dependencies used in building the pkgdown site. -\item Config/Needs/coverage for dependencies used in calculating test coverage. -}} - \item{clean}{Remove all files generated by the build, even if there were copies there before.} -\item{upgrade}{Should package dependencies be upgraded? One of "default", "ask", "always", or "never". "default" -respects the value of the \code{R_REMOTES_UPGRADE} environment variable if set, -and falls back to "ask" if unset. "ask" prompts the user for which out of -date packages to upgrade. For non-interactive sessions "ask" is equivalent -to "always". \code{TRUE} and \code{FALSE} are also accepted and correspond to -"always" and "never" respectively.} - \item{quiet}{If \code{TRUE}, suppresses most output. Set to \code{FALSE} if you need to debug.} diff --git a/tests/testthat/_snaps/sitrep.md b/tests/testthat/_snaps/sitrep.md index 548c26c8e..9ea602c0f 100644 --- a/tests/testthat/_snaps/sitrep.md +++ b/tests/testthat/_snaps/sitrep.md @@ -40,7 +40,7 @@ * version: 2.4.6 ! devtools or its dependencies out of date: "cli" - Update them with `devtools::update_packages("devtools")` + Update them with `pak::pak("devtools")` -- dev package --------------------------------------------- * package: * path: @@ -60,7 +60,7 @@ * path: '/tmp/mypkg' ! mypkg dependencies out of date: "dplyr" and "tidyr" - Update them with `devtools::install_dev_deps()` + Update them with `pak::local_install_dev_deps()` # print shows RStudio update message diff --git a/tests/testthat/test-sitrep.R b/tests/testthat/test-sitrep.R index c2debee42..cbe14f69c 100644 --- a/tests/testthat/test-sitrep.R +++ b/tests/testthat/test-sitrep.R @@ -55,6 +55,25 @@ test_that("print shows RStudio update message", { expect_snapshot(print(x)) }) +test_that("outdated_deps detects outdated packages", { + deps <- data.frame( + package = c("rlang", "cli"), + version = c("0.0.1", "0.0.1") + ) + result <- outdated_deps(deps) + expect_equal(result$package, c("rlang", "cli")) + expect_equal(result$diff, c(1, 1)) +}) + +test_that("outdated_deps reports missing packages as outdated", { + deps <- data.frame( + package = c("rlang", "thereIsNoSuchPackage"), + version = c("0.0.1", "1.0.0") + ) + result <- outdated_deps(deps) + expect_equal(result$diff[[2]], -1L) +}) + test_that("check_for_rstudio_updates", { skip_if_offline() skip_on_cran() From b8b193ab81f6351bf2db80932ea3e600398e6ac7 Mon Sep 17 00:00:00 2001 From: Hadley Wickham Date: Thu, 12 Feb 2026 14:58:19 -0600 Subject: [PATCH 2/2] Restore inheritParams --- R/vignettes.R | 1 + man/build_vignettes.Rd | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/R/vignettes.R b/R/vignettes.R index d4ae701a2..cd5dce38c 100644 --- a/R/vignettes.R +++ b/R/vignettes.R @@ -18,6 +18,7 @@ #' outputs. See #' . #' @inheritParams tools::buildVignettes +#' @inheritParams remotes::install_deps #' @importFrom stats update #' @keywords internal #' @export diff --git a/man/build_vignettes.Rd b/man/build_vignettes.Rd index 57e41c3be..0818811ac 100644 --- a/man/build_vignettes.Rd +++ b/man/build_vignettes.Rd @@ -18,9 +18,34 @@ build_vignettes( \item{pkg}{The package to use, can be a file path to the package or a package object. See \code{\link[=as.package]{as.package()}} for more information.} +\item{dependencies}{Which dependencies do you want to check? +Can be a character vector (selecting from "Depends", "Imports", +"LinkingTo", "Suggests", or "Enhances"), or a logical vector. + +\code{TRUE} is shorthand for "Depends", "Imports", "LinkingTo" and +"Suggests". \code{NA} is shorthand for "Depends", "Imports" and "LinkingTo" +and is the default. \code{FALSE} is shorthand for no dependencies (i.e. +just check this package, not its dependencies). + +The value "soft" means the same as \code{TRUE}, "hard" means the same as \code{NA}. + +You can also specify dependencies from one or more additional fields, +common ones include: +\itemize{ +\item Config/Needs/website - for dependencies used in building the pkgdown site. +\item Config/Needs/coverage for dependencies used in calculating test coverage. +}} + \item{clean}{Remove all files generated by the build, even if there were copies there before.} +\item{upgrade}{Should package dependencies be upgraded? One of "default", "ask", "always", or "never". "default" +respects the value of the \code{R_REMOTES_UPGRADE} environment variable if set, +and falls back to "ask" if unset. "ask" prompts the user for which out of +date packages to upgrade. For non-interactive sessions "ask" is equivalent +to "always". \code{TRUE} and \code{FALSE} are also accepted and correspond to +"always" and "never" respectively.} + \item{quiet}{If \code{TRUE}, suppresses most output. Set to \code{FALSE} if you need to debug.}