From 6c3c0ef75383d1227d4c748d3c9fdfd07bf4ceb1 Mon Sep 17 00:00:00 2001 From: Jenny Bryan Date: Tue, 18 Aug 2026 15:33:26 -0700 Subject: [PATCH] Provide more info around possible CRAN closure --- NEWS.md | 2 ++ R/release.R | 31 +++++++++++++++++++++++++++---- tests/testthat/_snaps/release.md | 12 ++++++++++++ tests/testthat/test-release.R | 13 +++++++++++++ 4 files changed, 54 insertions(+), 4 deletions(-) diff --git a/NEWS.md b/NEWS.md index 5270222f0..03da4ddb6 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,7 @@ # devtools (development version) +* `submit_cran()` gives a more informative error when the CRAN submission form can't be used, suggesting that the user consult to see if there's a CRAN closure (#2700). + # devtools 2.5.2 * `install()` uses a new feature of `pak::local_install_deps()` to consider the current `.libPaths()` when resolving dependencies, instead of consulting only `.libPaths()[1]`. This was an unintended behavioral change introduced in 2.5.0 (#2691). diff --git a/R/release.R b/R/release.R index 4bcdabeeb..2eb640592 100644 --- a/R/release.R +++ b/R/release.R @@ -307,7 +307,7 @@ upload_cran <- function(pkg, built_path, call = parent.frame()) { comment = comments, upload = "Upload package" ) - resp <- httr2::req_perform(req) + resp <- req_perform_cran(req, call = call) new_url <- httr2::url_parse(httr2::resp_url(resp)) # Confirmation ----------- @@ -323,20 +323,43 @@ upload_cran <- function(pkg, built_path, call = parent.frame()) { submit = "Submit package" ) - resp <- httr2::req_perform(req) + resp <- req_perform_cran(req, call = call) new_url <- httr2::url_parse(httr2::resp_url(resp)) - if (new_url$query$submit == "1") { + if (identical(new_url$query$submit, "1")) { cli::cli_inform(c( "v" = "Package submission successful", "i" = "Check your email for confirmation link." )) } else { - cli::cli_abort("Package failed to upload.", call = call) + cli::cli_abort("Unable to confirm package submission.", call = call) } invisible(TRUE) } +# The submission form is periodically unavailable: during planned CRAN vacations +# and sporadically at other times. This can take various forms, e.g. a 503 or a +# 404 or a failure to connect at all when the server is down. +req_perform_cran <- function(req, call = caller_env()) { + url <- httr2::req_get_url(req) + withCallingHandlers( + httr2::req_perform(req), + httr2_error = function(cnd) { + cli::cli_abort( + c( + "Can't submit to CRAN right now.", + "i" = "Request to {.url {url}} failed.", + "i" = "Check {.url https://cran.r-project.org} to see if there is a + planned closure or known outage." + ), + # Chain so that we surface more detail from httr2 or even curl. + parent = cnd, + call = call + ) + } + ) +} + as.object_size <- function(x) structure(x, class = "object_size") flag_release <- function(pkg = ".") { diff --git a/tests/testthat/_snaps/release.md b/tests/testthat/_snaps/release.md index 0be558b2d..ba2dac168 100644 --- a/tests/testthat/_snaps/release.md +++ b/tests/testthat/_snaps/release.md @@ -9,3 +9,15 @@ Error in `release()`: ! Interactive session required. +# req_perform_cran() reports an unavailable submission form + + Code + req_perform_cran(httr2::request(cran_submission_url)) + Condition + Error: + ! Can't submit to CRAN right now. + i Request to failed. + i Check to see if there is a planned closure or known outage. + Caused by error in `httr2::req_perform()`: + ! HTTP 503 Service Unavailable. + diff --git a/tests/testthat/test-release.R b/tests/testthat/test-release.R index 2be6ea9f7..3307d8cf3 100644 --- a/tests/testthat/test-release.R +++ b/tests/testthat/test-release.R @@ -1,3 +1,16 @@ test_that("release() is deprecated", { expect_snapshot(. <- release(), error = TRUE) }) + +test_that("req_perform_cran() reports an unavailable submission form", { + skip_if_not_installed("httr2") + + httr2::local_mocked_responses(list( + httr2::response(503, url = cran_submission_url) + )) + + expect_snapshot( + req_perform_cran(httr2::request(cran_submission_url)), + error = TRUE + ) +})