diff --git a/DESCRIPTION b/DESCRIPTION index 83d14908d..75375abcc 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: usethis Title: Automate Package and Project Setup -Version: 3.0.0.9000 +Version: 3.1.0 Authors@R: c( person("Hadley", "Wickham", , "hadley@posit.co", role = "aut", comment = c(ORCID = "0000-0003-4757-117X")), diff --git a/NEWS.md b/NEWS.md index 311e2707d..04abe487c 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,15 +1,21 @@ -# usethis (development version) +# usethis 3.1.0 -## Bug fixes and minor improvements +* `use_vignette()` and `use_article()` support Quarto. The `name` of the new + vignette or article can optionally include a file extension to signal whether + `.Rmd` or `.qmd` is desired, with `.Rmd` remaining the default for now. Thanks + to @olivroy for getting the ball rolling (#1997). + +* `use_data()` defaults to serialization version 3 (@laurabrianna, #2044). + +* `use_package()` can lower a minimum version requirement + (@jplecavalier, #1957). -* `use_package()` now decreases a package minimum version required when - `min_version` is lower than what is currently specified in the DESCRIPTION - file (@jplecavalier, #1957). - -* `use_data()` now uses serialization version 3 by default. (@laurabrianna, #2044) +* `use_release_issue()` only suggests doing reverse dependency checks if there + are, in fact, reverse dependencies (#1817, @seankross). -* Reverse dependency checks are only suggested if they exist - (#1817, @seankross). +* `use_tidy_upkeep_issue()` records the year it is being run in the + `Config/usethis/upkeep` field in DESCRIPTION. If this value exists, it is + used to filter the checklist when making the issue. # usethis 3.0.0 diff --git a/R/author.R b/R/author.R index 7e396e4ac..374423133 100644 --- a/R/author.R +++ b/R/author.R @@ -22,8 +22,7 @@ #' DESCRIPTION file and the user hasn't given any author information via the #' `fields` argument or the global option `"usethis.description"`. The #' placeholder looks something like `First Last [aut, -#' cre] (YOUR-ORCID-ID)` and `use_author()` offers to remove it in interactive -#' sessions. +#' cre]` and `use_author()` offers to remove it in interactive sessions. #' #' @inheritParams utils::person #' @inheritDotParams utils::person diff --git a/R/data.R b/R/data.R index 5003c0c77..b7d44165f 100644 --- a/R/data.R +++ b/R/data.R @@ -44,11 +44,13 @@ use_data <- function(..., objs <- get_objs_from_dots(dots(...)) - if (version < 3) { - use_dependency("R", "depends", "2.10") - } else { - use_dependency("R", "depends", "3.5") + original_minimum_r_version <- pkg_minimum_r_version() + serialization_minimum_r_version <- if (version < 3) "2.10" else "3.5" + if (is.na(original_minimum_r_version) || + original_minimum_r_version < serialization_minimum_r_version) { + use_dependency("R", "depends", serialization_minimum_r_version) } + if (internal) { use_directory("R") paths <- path("R", "sysdata.rda") diff --git a/R/description.R b/R/description.R index 4e15ef633..d98336eb1 100644 --- a/R/description.R +++ b/R/description.R @@ -124,7 +124,7 @@ usethis_description_defaults <- function(package = NULL) { Version = "0.0.0.9000", Title = "What the Package Does (One Line, Title Case)", Description = "What the package does (one paragraph).", - "Authors@R" = 'person("First", "Last", email = "first.last@example.com", role = c("aut", "cre"), comment = c(ORCID = "YOUR-ORCID-ID"))', + "Authors@R" = 'person("First", "Last", email = "first.last@example.com", role = c("aut", "cre"))', License = "`use_mit_license()`, `use_gpl3_license()` or friends to pick a license", Encoding = "UTF-8" ) diff --git a/R/release.R b/R/release.R index 1748b3544..6f2196245 100644 --- a/R/release.R +++ b/R/release.R @@ -534,10 +534,11 @@ author_has_rstudio_email <- function() { pkg_minimum_r_version <- function() { deps <- proj_desc()$get_deps() r_dep <- deps[deps$package == "R" & deps$type == "Depends", "version"] - if (length(r_dep) == 0) { - return(numeric_version("0")) + if (length(r_dep) > 0) { + numeric_version(gsub("[^0-9.]", "", r_dep)) + } else { + NA_character_ } - numeric_version(gsub("[^0-9.]", "", r_dep)) } # Borrowed from pak, but modified also retain user's non-cran repos: diff --git a/R/roxygen.R b/R/roxygen.R index 1071c8c77..afbf3fb4b 100644 --- a/R/roxygen.R +++ b/R/roxygen.R @@ -56,7 +56,7 @@ use_roxygen_md <- function(overwrite = FALSE) { } # FALSE: no Roxygen field -# TRUE: plain old "list(markdown = TRUE)" +# TRUE: matches regex targetting 'markdown = TRUE', with some whitespace slop # NA: everything else uses_roxygen_md <- function() { desc <- proj_desc() @@ -66,8 +66,7 @@ uses_roxygen_md <- function() { } roxygen <- desc$get_field("Roxygen", "") - if (identical(roxygen, "list(markdown = TRUE)") || - identical(roxygen, "list(markdown = TRUE, r6 = FALSE)")) { + if (grepl("markdown\\s*=\\s*TRUE", roxygen)) { TRUE } else { NA diff --git a/R/tidyverse.R b/R/tidyverse.R index 0e101e413..f3a83389d 100644 --- a/R/tidyverse.R +++ b/R/tidyverse.R @@ -44,7 +44,9 @@ #' tidyverse conventions around GitHub issue label names and colours. #' #' * `use_tidy_upkeep_issue()` creates an issue containing a checklist of -#' actions to bring your package up to current tidyverse standards. +#' actions to bring your package up to current tidyverse standards. Also +#' records the current date in the `Config/usethis/last-upkeep` field in +#' `DESCRIPTION`. #' #' * `use_tidy_logo()` calls `use_logo()` on the appropriate hex sticker PNG #' file at . diff --git a/R/upkeep.R b/R/upkeep.R index 0de6d48fb..6f93573c7 100644 --- a/R/upkeep.R +++ b/R/upkeep.R @@ -16,13 +16,13 @@ #' @export #' @examples #' \dontrun{ -#' use_upkeep_issue(2023) +#' use_upkeep_issue() #' } use_upkeep_issue <- function(year = NULL) { make_upkeep_issue(year = year, tidy = FALSE) } -make_upkeep_issue <- function(year, tidy) { +make_upkeep_issue <- function(year, last_upkeep, tidy) { who <- if (tidy) "use_tidy_upkeep_issue()" else "use_upkeep_issue()" check_is_package(who) @@ -41,7 +41,7 @@ make_upkeep_issue <- function(year, tidy) { gh <- gh_tr(tr) if (tidy) { - checklist <- tidy_upkeep_checklist(year, repo_spec = tr$repo_spec) + checklist <- tidy_upkeep_checklist(last_upkeep, repo_spec = tr$repo_spec) } else { checklist <- upkeep_checklist(tr) } @@ -118,22 +118,25 @@ upkeep_checklist <- function(target_repo = NULL) { #' @export #' @rdname tidyverse -#' @param year Approximate year when you last touched this package. If `NULL`, -#' the default, will give you a full set of actions to perform. -use_tidy_upkeep_issue <- function(year = NULL) { - make_upkeep_issue(year = year, tidy = TRUE) +#' @param last_upkeep Year of last upkeep. By default, the +#' `Config/usethis/last-upkeep` field in `DESCRIPTION` is consulted for this, if +#' it's defined. If there's no information on the last upkeep, the issue will +#' contain the full checklist. +use_tidy_upkeep_issue <- function(last_upkeep = last_upkeep_year()) { + make_upkeep_issue(year = NULL, last_upkeep = last_upkeep, tidy = TRUE) + record_upkeep_date(Sys.Date()) } # for mocking Sys.Date <- NULL -tidy_upkeep_checklist <- function(year = NULL, repo_spec = "OWNER/REPO") { +tidy_upkeep_checklist <- function(last_upkeep = last_upkeep_year(), + repo_spec = "OWNER/REPO") { + desc <- proj_desc() posit_pkg <- is_posit_pkg() posit_person_ok <- is_posit_person_canonical() - year <- year %||% 2000 - bullets <- c( "### To begin", "", @@ -141,7 +144,7 @@ tidy_upkeep_checklist <- function(year = NULL, repo_spec = "OWNER/REPO") { "" ) - if (year <= 2000) { + if (last_upkeep <= 2000) { bullets <- c( bullets, "### Pre-history", @@ -156,7 +159,7 @@ tidy_upkeep_checklist <- function(year = NULL, repo_spec = "OWNER/REPO") { "" ) } - if (year <= 2020) { + if (last_upkeep <= 2020) { bullets <- c( bullets, "### 2020", @@ -167,7 +170,7 @@ tidy_upkeep_checklist <- function(year = NULL, repo_spec = "OWNER/REPO") { "" ) } - if (year <= 2021) { + if (last_upkeep <= 2021) { bullets <- c( bullets, "### 2021", @@ -177,7 +180,7 @@ tidy_upkeep_checklist <- function(year = NULL, repo_spec = "OWNER/REPO") { "" ) } - if (year <= 2022) { + if (last_upkeep <= 2022) { bullets <- c( bullets, "### 2022", @@ -190,9 +193,7 @@ tidy_upkeep_checklist <- function(year = NULL, repo_spec = "OWNER/REPO") { ) } - if (year <= 2023) { - desc <- proj_desc() - + if (last_upkeep <= 2023) { bullets <- c( bullets, "### 2023", @@ -242,6 +243,7 @@ tidy_upkeep_checklist <- function(year = NULL, repo_spec = "OWNER/REPO") { ) } + minimum_r_version <- pkg_minimum_r_version() bullets <- c( bullets, "### To finish", @@ -249,7 +251,7 @@ tidy_upkeep_checklist <- function(year = NULL, repo_spec = "OWNER/REPO") { todo("`usethis::use_mit_license()`", grepl("MIT", desc$get_field("License"))), todo( '`usethis::use_package("R", "Depends", "{tidy_minimum_r_version()}")`', - tidy_minimum_r_version() > pkg_minimum_r_version() + is.na(minimum_r_version) || tidy_minimum_r_version() > minimum_r_version ), todo("`usethis::use_tidy_description()`"), todo("`usethis::use_tidy_github_actions()`"), @@ -327,3 +329,18 @@ has_old_cran_comments <- function() { file_exists(cc) && any(grepl("# test environment", readLines(cc), ignore.case = TRUE)) } + +last_upkeep_date <- function() { + as.Date( + proj_desc()$get_field("Config/usethis/last-upkeep", "2000-01-01"), + format = "%Y-%m-%d" + ) +} + +last_upkeep_year <- function() { + as.integer(format(last_upkeep_date(), "%Y")) +} + +record_upkeep_date <- function(date) { + proj_desc_field_update("Config/usethis/last-upkeep", format(date, "%Y-%m-%d")) +} diff --git a/R/vignette.R b/R/vignette.R index ceab26aa0..515f28c08 100644 --- a/R/vignette.R +++ b/R/vignette.R @@ -10,43 +10,85 @@ #' * Adds `inst/doc` to `.gitignore` so built vignettes aren't tracked. #' * Adds `vignettes/*.html` and `vignettes/*.R` to `.gitignore` so #' you never accidentally track rendered vignettes. -#' @param name Base for file name to use for new vignette. Should consist only -#' of numbers, letters, `_` and `-`. Lower case is recommended. -#' @param title The title of the vignette. -#' @seealso The [vignettes chapter](https://r-pkgs.org/vignettes.html) of -#' [R Packages](https://r-pkgs.org). +#' * For `*.qmd`, adds Quarto-related patterns to `.gitignore` and +#' `.Rbuildignore`. +#' @param name File name to use for new vignette. Should consist only of +#' numbers, letters, `_` and `-`. Lower case is recommended. Can include the +#' `".Rmd"` or `".qmd"` file extension, which also dictates whether to place +#' an R Markdown or Quarto vignette. R Markdown (`".Rmd"`) is the current +#' default, but it is anticipated that Quarto (`".qmd"`) will become the +#' default in the future. +#' @param title The title of the vignette. If not provided, a title is generated +#' from `name`. +#' @seealso +#' * The [vignettes chapter](https://r-pkgs.org/vignettes.html) of +#' [R Packages](https://r-pkgs.org) +#' * The pkgdown vignette on Quarto: +#' `vignette("quarto", package = "pkgdown")` +#' * The quarto (as in the R package) vignette on HTML vignettes: +#' `vignette("hello", package = "quarto")` #' @export #' @examples #' \dontrun{ #' use_vignette("how-to-do-stuff", "How to do stuff") +#' use_vignette("r-markdown-is-classic.Rmd", "R Markdown is classic") +#' use_vignette("quarto-is-cool.qmd", "Quarto is cool") #' } -use_vignette <- function(name, title = name) { +use_vignette <- function(name, title = NULL) { check_is_package("use_vignette()") check_required(name) + maybe_name(title) + + ext <- get_vignette_extension(name) + if (ext == "qmd") { + check_installed("quarto") + check_installed("pkgdown", version = "2.1.0") + } + + name <- path_ext_remove(name) check_vignette_name(name) + title <- title %||% name use_dependency("knitr", "Suggests") - use_dependency("rmarkdown", "Suggests") - - proj_desc_field_update("VignetteBuilder", "knitr", overwrite = TRUE) use_git_ignore("inst/doc") - use_vignette_template("vignette.Rmd", name, title) + if (tolower(ext) == "rmd") { + use_dependency("rmarkdown", "Suggests") + proj_desc_field_update("VignetteBuilder", "knitr", overwrite = TRUE, append = TRUE) + use_vignette_template("vignette.Rmd", name, title) + } else { + use_dependency("quarto", "Suggests") + proj_desc_field_update("VignetteBuilder", "quarto", overwrite = TRUE, append = TRUE) + use_vignette_template("vignette.qmd", name, title) + } invisible() } #' @export #' @rdname use_vignette -use_article <- function(name, title = name) { +use_article <- function(name, title = NULL) { check_is_package("use_article()") + check_required(name) + maybe_name(title) - deps <- proj_deps() - if (!"rmarkdown" %in% deps$package) { - proj_desc_field_update("Config/Needs/website", "rmarkdown", append = TRUE) + ext <- get_vignette_extension(name) + if (ext == "qmd") { + check_installed("quarto") + check_installed("pkgdown", version = "2.1.0") } - use_vignette_template("article.Rmd", name, title, subdir = "articles") + name <- path_ext_remove(name) + title <- title %||% name + + if (tolower(ext) == "rmd") { + proj_desc_field_update("Config/Needs/website", "rmarkdown", overwrite = TRUE, append = TRUE) + use_vignette_template("article.Rmd", name, title, subdir = "articles") + } else { + use_dependency("quarto", "Suggests") + proj_desc_field_update("Config/Needs/website", "quarto", overwrite = TRUE, append = TRUE) + use_vignette_template("article.qmd", name, title, subdir = "articles") + } use_build_ignore("vignettes/articles") invisible() @@ -58,18 +100,26 @@ use_vignette_template <- function(template, name, title, subdir = NULL) { check_name(title) maybe_name(subdir) - use_directory("vignettes") - if (!is.null(subdir)) { - use_directory(path("vignettes", subdir)) - } - use_git_ignore(c("*.html", "*.R"), directory = "vignettes") + ext <- get_vignette_extension(template) if (is.null(subdir)) { - path <- path("vignettes", asciify(name), ext = "Rmd") + target_dir <- "vignettes" } else { - path <- path("vignettes", subdir, asciify(name), ext = "Rmd") + target_dir <- path("vignettes", subdir) + } + + use_directory(target_dir) + + use_git_ignore(c("*.html", "*.R"), directory = target_dir) + if (ext == "qmd") { + use_git_ignore("**/.quarto/") + use_git_ignore("*_files", target_dir) + use_build_ignore(path(target_dir, ".quarto")) + use_build_ignore(path(target_dir, "*_files")) } + path <- path(target_dir, asciify(name), ext = ext) + data <- list( Package = project_name(), vignette_title = title, @@ -102,3 +152,28 @@ check_vignette_name <- function(name) { valid_vignette_name <- function(x) { grepl("^[[:alpha:]][[:alnum:]_-]*$", x) } + +check_vignette_extension <- function(ext) { + # Quietly accept "rmd" here, tho we'll always write ".Rmd" in such a filepath + if (! ext %in% c("Rmd", "rmd", "qmd")) { + valid_exts_cli <- cli::cli_vec( + c("Rmd", "qmd"), + style = list("vec-sep2" = " or ") + ) + ui_abort(c( + "Unsupported file extension: {.val {ext}}", + "usethis can only create a vignette or article with one of these + extensions: {.val {valid_exts_cli}}." + )) + } +} + +get_vignette_extension <- function(name) { + ext <- path_ext(name) + if (nzchar(ext)) { + check_vignette_extension(ext) + } else { + ext <- "Rmd" + } + ext +} diff --git a/README.Rmd b/README.Rmd index 35d75aa9b..6c92d55a9 100644 --- a/README.Rmd +++ b/README.Rmd @@ -66,7 +66,7 @@ proj_activate(path) # Modify the description ---------------------------------------------- use_mit_license("My Name") -use_package("ggplot2", "Suggests") +use_package("rmarkdown", "Suggests") # Set up other files ------------------------------------------------- use_readme_md() diff --git a/README.md b/README.md index 2dc670044..4defaa652 100644 --- a/README.md +++ b/README.md @@ -60,15 +60,15 @@ library(usethis) # Create a new package ------------------------------------------------- path <- file.path(tempdir(), "mypkg") create_package(path) -#> ✔ Creating '/tmp/RtmpCJHMlj/mypkg/'. -#> ✔ Setting active project to "/private/tmp/RtmpCJHMlj/mypkg". +#> ✔ Creating '/tmp/RtmpPZsquk/mypkg/'. +#> ✔ Setting active project to "/private/tmp/RtmpPZsquk/mypkg". #> ✔ Creating 'R/'. #> ✔ Writing 'DESCRIPTION'. #> Package: mypkg #> Title: What the Package Does (One Line, Title Case) #> Version: 0.0.0.9000 #> Authors@R (parsed): -#> * First Last [aut, cre] (YOUR-ORCID-ID) +#> * First Last [aut, cre] #> Description: What the package does (one paragraph). #> License: `use_mit_license()`, `use_gpl3_license()` or friends to pick a #> license @@ -79,8 +79,8 @@ create_package(path) #> ✔ Setting active project to "". # only needed since this session isn't interactive proj_activate(path) -#> ✔ Setting active project to "/private/tmp/RtmpCJHMlj/mypkg". -#> ✔ Changing working directory to '/tmp/RtmpCJHMlj/mypkg/' +#> ✔ Setting active project to "/private/tmp/RtmpPZsquk/mypkg". +#> ✔ Changing working directory to '/tmp/RtmpPZsquk/mypkg/' # Modify the description ---------------------------------------------- use_mit_license("My Name") @@ -89,11 +89,11 @@ use_mit_license("My Name") #> ✔ Writing 'LICENSE.md'. #> ✔ Adding "^LICENSE\\.md$" to '.Rbuildignore'. -use_package("ggplot2", "Suggests") -#> ✔ Adding ggplot2 to 'Suggests' field in DESCRIPTION. -#> ☐ Use `requireNamespace("ggplot2", quietly = TRUE)` to test if ggplot2 is +use_package("rmarkdown", "Suggests") +#> ✔ Adding rmarkdown to 'Suggests' field in DESCRIPTION. +#> ☐ Use `requireNamespace("rmarkdown", quietly = TRUE)` to test if rmarkdown is #> installed. -#> ☐ Then directly refer to functions with `ggplot2::fun()`. +#> ☐ Then directly refer to functions with `rmarkdown::fun()`. # Set up other files ------------------------------------------------- use_readme_md() diff --git a/cran-comments.md b/cran-comments.md index 6df713ca7..d81007fa1 100644 --- a/cran-comments.md +++ b/cran-comments.md @@ -1,26 +1,6 @@ -## R CMD check results - -0 errors | 0 warnings | 0 notes - ## revdepcheck results -We checked 217 reverse dependencies, comparing R CMD check results across CRAN and dev versions of this package. +We checked 227 reverse dependencies, comparing R CMD check results across CRAN and dev versions of this package. - * We saw 2 new problems + * We saw 0 new problems * We failed to check 0 packages - -Issues with CRAN packages are summarised below. - -### New problems - -* circle - This package makes reference to a function that is now removed from usethis. - This function has been hard-deprecated (i.e. throws an error with advice on - how to update) since usethis v2.2.0, released in December 2020. - I have opened an issue in circle's GitHub repository. - -* exampletestr - This package has a brittle test that checks for exact wording of an error - message originating in usethis. - That test fails because usethis's error message has changed slightly. - I have opened an issue in exampletestr's GitHub repository. diff --git a/inst/WORDLIST b/inst/WORDLIST index 8668cf190..0d27b9594 100644 --- a/inst/WORDLIST +++ b/inst/WORDLIST @@ -82,6 +82,7 @@ behaviour bzip ci cli +cli's clipr clisymbols codecov @@ -101,6 +102,7 @@ eval favour fiascos filenaming +foofy formidabel frontmatter fs @@ -112,6 +114,7 @@ gh's gitcreds github gitignore +googledrive grey gzip href @@ -121,6 +124,7 @@ ing initialisation initialises initialising +inlined io jsonlite labelled @@ -128,7 +132,7 @@ labelling learnr libgit lifecycle -macOS +ly macbook magrittr magrittr's @@ -136,6 +140,7 @@ md mergeable minimise msg +namespacing nano noninteractive oldrel @@ -145,6 +150,7 @@ ort pak pandoc pkgdown +pos pre programmatically purrr @@ -169,10 +175,13 @@ rmarkdown ropensci roxygen rprojroot +rstd +shortcode shortlink shortlinks signalling sitrep +solarized src styler symlink @@ -184,9 +193,11 @@ tibble tidymodels tidyverse todo +todo's travis triaged uation +ui un unpushed useR @@ -197,3 +208,5 @@ withr xyz xz yaml +yyy +zzz diff --git a/inst/templates/article.qmd b/inst/templates/article.qmd new file mode 100644 index 000000000..a4f4ac1fa --- /dev/null +++ b/inst/templates/article.qmd @@ -0,0 +1,12 @@ +--- +title: "{{{ vignette_title }}}" +knitr: + opts_chunk: + collapse: true + comment: '#>' +--- + +```{r} +#| label: setup +library({{Package}}) +``` diff --git a/inst/templates/vignette.qmd b/inst/templates/vignette.qmd new file mode 100644 index 000000000..e46284de0 --- /dev/null +++ b/inst/templates/vignette.qmd @@ -0,0 +1,16 @@ +--- +title: "{{{ vignette_title }}}" +vignette: > + %\VignetteIndexEntry{{{ braced_vignette_title }}} + %\VignetteEngine{quarto::html} + %\VignetteEncoding{UTF-8} +knitr: + opts_chunk: + collapse: true + comment: '#>' +--- + +```{r} +#| label: setup +library({{Package}}) +``` diff --git a/man/tidyverse.Rd b/man/tidyverse.Rd index 277a65452..fe1cd455f 100644 --- a/man/tidyverse.Rd +++ b/man/tidyverse.Rd @@ -38,7 +38,7 @@ use_tidy_style(strict = TRUE) use_tidy_logo(geometry = "240x278", retina = TRUE) -use_tidy_upkeep_issue(year = NULL) +use_tidy_upkeep_issue(last_upkeep = last_upkeep_year()) } \arguments{ \item{ref}{Desired Git reference, usually the name of a tag (\code{"v2"}) or @@ -64,8 +64,10 @@ assumes that you have a hex logo using spec from \item{retina}{\code{TRUE}, the default, scales the image on the README, assuming that geometry is double the desired size.} -\item{year}{Approximate year when you last touched this package. If \code{NULL}, -the default, will give you a full set of actions to perform.} +\item{last_upkeep}{Year of last upkeep. By default, the +\code{Config/usethis/last-upkeep} field in \code{DESCRIPTION} is consulted for this, if +it's defined. If there's no information on the last upkeep, the issue will +contain the full checklist.} } \description{ These helpers follow tidyverse conventions which are generally a little @@ -119,7 +121,9 @@ document in a \verb{.github/} subdirectory. \item \code{\link[=use_tidy_github_labels]{use_tidy_github_labels()}} calls \code{use_github_labels()} to implement tidyverse conventions around GitHub issue label names and colours. \item \code{use_tidy_upkeep_issue()} creates an issue containing a checklist of -actions to bring your package up to current tidyverse standards. +actions to bring your package up to current tidyverse standards. Also +records the current date in the \code{Config/usethis/last-upkeep} field in +\code{DESCRIPTION}. \item \code{use_tidy_logo()} calls \code{use_logo()} on the appropriate hex sticker PNG file at \url{https://github.com/rstudio/hex-stickers}. } diff --git a/man/use_author.Rd b/man/use_author.Rd index ea4df4dc5..2be7571d0 100644 --- a/man/use_author.Rd +++ b/man/use_author.Rd @@ -52,8 +52,7 @@ processed to create \code{Author} and \code{Maintainer} fields, but only when th \code{\link[=use_description]{use_description()}}. This happens when \pkg{usethis} has to create a DESCRIPTION file and the user hasn't given any author information via the \code{fields} argument or the global option \code{"usethis.description"}. The -placeholder looks something like \verb{First Last [aut, cre] (YOUR-ORCID-ID)} and \code{use_author()} offers to remove it in interactive -sessions. +placeholder looks something like \verb{First Last [aut, cre]} and \code{use_author()} offers to remove it in interactive sessions. } } \examples{ diff --git a/man/use_upkeep_issue.Rd b/man/use_upkeep_issue.Rd index 704e258bf..a916dafa0 100644 --- a/man/use_upkeep_issue.Rd +++ b/man/use_upkeep_issue.Rd @@ -22,6 +22,6 @@ annual package Spring Cleaning. } \examples{ \dontrun{ -use_upkeep_issue(2023) +use_upkeep_issue() } } diff --git a/man/use_vignette.Rd b/man/use_vignette.Rd index 8c5fa70fa..9dcf81700 100644 --- a/man/use_vignette.Rd +++ b/man/use_vignette.Rd @@ -5,15 +5,20 @@ \alias{use_article} \title{Create a vignette or article} \usage{ -use_vignette(name, title = name) +use_vignette(name, title = NULL) -use_article(name, title = name) +use_article(name, title = NULL) } \arguments{ -\item{name}{Base for file name to use for new vignette. Should consist only -of numbers, letters, \verb{_} and \code{-}. Lower case is recommended.} +\item{name}{File name to use for new vignette. Should consist only of +numbers, letters, \verb{_} and \code{-}. Lower case is recommended. Can include the +\code{".Rmd"} or \code{".qmd"} file extension, which also dictates whether to place +an R Markdown or Quarto vignette. R Markdown (\code{".Rmd"}) is the current +default, but it is anticipated that Quarto (\code{".qmd"}) will become the +default in the future.} -\item{title}{The title of the vignette.} +\item{title}{The title of the vignette. If not provided, a title is generated +from \code{name}.} } \description{ Creates a new vignette or article in \verb{vignettes/}. Articles are a special @@ -28,15 +33,25 @@ automatically). \item Adds \code{inst/doc} to \code{.gitignore} so built vignettes aren't tracked. \item Adds \verb{vignettes/*.html} and \verb{vignettes/*.R} to \code{.gitignore} so you never accidentally track rendered vignettes. +\item For \verb{*.qmd}, adds Quarto-related patterns to \code{.gitignore} and +\code{.Rbuildignore}. } } \examples{ \dontrun{ use_vignette("how-to-do-stuff", "How to do stuff") +use_vignette("r-markdown-is-classic.Rmd", "R Markdown is classic") +use_vignette("quarto-is-cool.qmd", "Quarto is cool") } } \seealso{ -The \href{https://r-pkgs.org/vignettes.html}{vignettes chapter} of -\href{https://r-pkgs.org}{R Packages}. +\itemize{ +\item The \href{https://r-pkgs.org/vignettes.html}{vignettes chapter} of +\href{https://r-pkgs.org}{R Packages} +\item The pkgdown vignette on Quarto: +\code{vignette("quarto", package = "pkgdown")} +\item The quarto (as in the R package) vignette on HTML vignettes: +\code{vignette("hello", package = "quarto")} +} } diff --git a/revdep/README.md b/revdep/README.md index 23b2f2eba..52e12c714 100644 --- a/revdep/README.md +++ b/revdep/README.md @@ -1,16 +1,2 @@ # Revdeps -## Failed to check (1) - -|package |version |error |warning |note | -|:-------|:-------|:-----|:-------|:----| -|scaper |0.1.0 |1 | | | - -## New problems (3) - -|package |version |error |warning |note | -|:---------------|:-------|:--------|:-------|:------| -|[circle](problems.md#circle)|0.7.2 |1 |__+1__ | | -|[exampletestr](problems.md#exampletestr)|1.7.1 |1 __+1__ | | | -|[pharmaverseadam](problems.md#pharmaverseadam)|1.0.0 | | |__+1__ | - diff --git a/revdep/cran.md b/revdep/cran.md index 3b19c4fbf..a3d7f1c48 100644 --- a/revdep/cran.md +++ b/revdep/cran.md @@ -1,24 +1,7 @@ ## revdepcheck results -We checked 217 reverse dependencies, comparing R CMD check results across CRAN and dev versions of this package. +We checked 227 reverse dependencies, comparing R CMD check results across CRAN and dev versions of this package. - * We saw 3 new problems - * We failed to check 1 packages + * We saw 0 new problems + * We failed to check 0 packages -Issues with CRAN packages are summarised below. - -### New problems -(This reports the first line of each new failure) - -* circle - checking dependencies in R code ... WARNING - -* exampletestr - checking tests ... ERROR - -* pharmaverseadam - checking installed package size ... NOTE - -### Failed to check - -* scaper (NA) diff --git a/revdep/problems.md b/revdep/problems.md index 3051c2622..9a2073633 100644 --- a/revdep/problems.md +++ b/revdep/problems.md @@ -1,108 +1 @@ -# circle - -
- -* Version: 0.7.2 -* GitHub: https://github.com/ropensci/circle -* Source code: https://github.com/cran/circle -* Date/Publication: 2022-08-24 07:50:02 UTC -* Number of recursive dependencies: 76 - -Run `revdepcheck::cloud_details(, "circle")` for more info - -
- -## Newly broken - -* checking dependencies in R code ... WARNING - ``` - Missing or unexported object: ‘usethis::github_token’ - ``` - -## In both - -* checking running R code from vignettes ... ERROR - ``` - Errors in running code in vignettes: - when running code in ‘circle.Rmd’ - ... - - > knitr::opts_chunk$set(collapse = TRUE, comment = "#>") - - > knitr::include_graphics("../man/figures/user-key.png") - - When sourcing ‘circle.R’: - Error: Cannot find the file(s): "../man/figures/user-key.png" - Execution halted - - ‘circle.Rmd’ using ‘UTF-8’... failed - ‘tic.Rmd’ using ‘UTF-8’... OK - ``` - -# exampletestr - -
- -* Version: 1.7.1 -* GitHub: https://github.com/rorynolan/exampletestr -* Source code: https://github.com/cran/exampletestr -* Date/Publication: 2023-06-11 03:10:02 UTC -* Number of recursive dependencies: 97 - -Run `revdepcheck::cloud_details(, "exampletestr")` for more info - -
- -## Newly broken - -* checking tests ... ERROR - ``` - Running ‘spelling.R’ - Running ‘testthat.R’ - Running the tests in ‘tests/testthat.R’ failed. - Complete output: - > library(testthat) - > library(exampletestr) - > - > get_os <- function() { - + sysinf <- Sys.info() - + if (!is.null(sysinf)) { - ... - 6. └─exampletestr:::extract_examples("detect", tempdir(check = TRUE)) - 7. └─usethis::local_project(path = pkg_dir, quiet = TRUE) - 8. └─usethis::proj_set(path = path, force = force) - 9. └─usethis:::ui_abort(...) - 10. └─cli::cli_abort(...) - 11. └─rlang::abort(...) - - [ FAIL 1 | WARN 0 | SKIP 0 | PASS 27 ] - Error: Test failures - Execution halted - ``` - -## In both - -* checking running R code from vignettes ... ERROR - ``` - Errors in running code in vignettes: - when running code in ‘one-file-at-a-time.Rmd’ - ... - > knitr::opts_knit$set(root.dir = paste0(tempdir(), - + "/", "tempkg")) - - > usethis::proj_set(".") - - When sourcing ‘one-file-at-a-time.R’: - Error: ✖ Path '/tmp/RtmpGIYvQt/file132af710168/vignettes/' does not appear to - ... - - When sourcing ‘whole-package.R’: - Error: ✖ Path '/tmp/RtmpauCurR/file133f1dd70a93/vignettes/' does not appear to - be inside a project or package. - ℹ Read more in the help for `usethis::proj_get()`. - Execution halted - - ‘one-file-at-a-time.Rmd’ using ‘UTF-8’... failed - ‘one-function-at-a-time.Rmd’ using ‘UTF-8’... OK - ‘whole-package.Rmd’ using ‘UTF-8’... failed - ``` +*Wow, no problems at all. :)* \ No newline at end of file diff --git a/tests/testthat/_snaps/author.md b/tests/testthat/_snaps/author.md index 48bbed63c..b49cc9a48 100644 --- a/tests/testthat/_snaps/author.md +++ b/tests/testthat/_snaps/author.md @@ -31,5 +31,5 @@ v Adding to 'Authors@R' in DESCRIPTION: Charlie Brown [ctb] i 'Authors@R' appears to include a placeholder author: - First Last [aut, cre] (YOUR-ORCID-ID) + First Last [aut, cre] diff --git a/tests/testthat/_snaps/upkeep.md b/tests/testthat/_snaps/upkeep.md index af2df5d58..46b4fade3 100644 --- a/tests/testthat/_snaps/upkeep.md +++ b/tests/testthat/_snaps/upkeep.md @@ -5,7 +5,7 @@ Output ### To begin - * [ ] `pr_init("upkeep-2023-01")` + * [ ] `pr_init("upkeep-2025-01")` ### Pre-history @@ -58,7 +58,41 @@ * [ ] `devtools::build_readme()` * [ ] [Re-publish released site](https://pkgdown.r-lib.org/dev/articles/how-to-update-released-site.html) if needed - Created on 2023-01-01 with `usethis::use_tidy_upkeep_issue()`, using [usethis v1.1.0](https://usethis.r-lib.org) + Created on 2025-01-01 with `usethis::use_tidy_upkeep_issue()`, using [usethis v1.1.0](https://usethis.r-lib.org) + +# tidy upkeep omits bullets present in last_upkeep + + Code + writeLines(tidy_upkeep_checklist()) + Output + ### To begin + + * [ ] `pr_init("upkeep-2025-01")` + + ### 2023 + + * [ ] Update email addresses *@rstudio.com -> *@posit.co + * [ ] Update copyright holder in DESCRIPTION: `person("Posit Software, PBC", role = c("cph", "fnd"))` + * [ ] Run `devtools::document()` to re-generate package-level help topic with DESCRIPTION changes + * [ ] `usethis::use_tidy_logo(); pkgdown::build_favicons(overwrite = TRUE)` + * [ ] `usethis::use_tidy_coc()` + * [ ] Use `pak::pak("OWNER/REPO")` in README + * [ ] Consider running `usethis::use_tidy_dependencies()` and/or replace compat files with `use_standalone()` + * [ ] Use cli errors or [file an issue](new) if you don't have time to do it now + * [ ] `usethis::use_standalone("r-lib/rlang", "types-check")` instead of home grown argument checkers; + or [file an issue](new) if you don't have time to do it now + * [ ] Add alt-text to pictures, plots, etc; see https://posit.co/blog/knitr-fig-alt/ for examples + + ### To finish + + * [ ] `usethis::use_mit_license()` + * [ ] `usethis::use_package("R", "Depends", "4.0")` + * [ ] `usethis::use_tidy_description()` + * [ ] `usethis::use_tidy_github_actions()` + * [ ] `devtools::build_readme()` + * [ ] [Re-publish released site](https://pkgdown.r-lib.org/dev/articles/how-to-update-released-site.html) if needed + + Created on 2025-01-01 with `usethis::use_tidy_upkeep_issue()`, using [usethis v1.1.0](https://usethis.r-lib.org) # upkeep bullets don't change accidentally diff --git a/tests/testthat/_snaps/use_import_from.md b/tests/testthat/_snaps/use_import_from.md index 857fe0ef3..0bb4cf57d 100644 --- a/tests/testthat/_snaps/use_import_from.md +++ b/tests/testthat/_snaps/use_import_from.md @@ -3,8 +3,8 @@ Code roxygen_ns_show() Output - [1] "#' @importFrom tibble deframe" "#' @importFrom tibble enframe" - [3] "#' @importFrom tibble tibble" + [1] "#' @importFrom lifecycle deprecate_stop" + [2] "#' @importFrom lifecycle deprecate_warn" # use_import_from() generates helpful errors @@ -14,15 +14,15 @@ Error in `use_import_from()`: x `package` must be a single string. Code - use_import_from(c("tibble", "rlang")) + use_import_from(c("desc", "rlang")) Condition Error in `use_import_from()`: x `package` must be a single string. Code - use_import_from("tibble", "pool_noodle") + use_import_from("desc", "pool_noodle") Condition Error in `map2()`: i In index: 1. Caused by error in `.f()`: - x Can't find `tibble::pool_noodle()`. + x Can't find `desc::pool_noodle()`. diff --git a/tests/testthat/_snaps/vignette.md b/tests/testthat/_snaps/vignette.md index e7359ae1b..dbbd22c5f 100644 --- a/tests/testthat/_snaps/vignette.md +++ b/tests/testthat/_snaps/vignette.md @@ -13,3 +13,12 @@ i Start with a letter. i Contain only letters, numbers, '_', and '-'. +# we error informatively for bad vignette extension + + Code + check_vignette_extension("Rnw") + Condition + Error in `check_vignette_extension()`: + x Unsupported file extension: "Rnw" + i usethis can only create a vignette or article with one of these extensions: "Rmd" or "qmd". + diff --git a/tests/testthat/test-author.R b/tests/testthat/test-author.R index 987961334..f60acab86 100644 --- a/tests/testthat/test-author.R +++ b/tests/testthat/test-author.R @@ -72,9 +72,6 @@ test_that("Decline to tweak an existing author", { }) test_that("Placeholder author is challenged", { - # apparently the format method for `person` used to handle ORCIDs differently - skip_if(getRversion() < "4.0") - withr::local_options(usethis.description = NULL) create_local_package() diff --git a/tests/testthat/test-data.R b/tests/testthat/test-data.R index f2f893aee..9edde202e 100644 --- a/tests/testthat/test-data.R +++ b/tests/testthat/test-data.R @@ -95,3 +95,14 @@ test_that("use_data_raw() does setup", { expect_true(is_build_ignored("^data-raw$")) }) + +test_that("use_data() does not decrease minimum version of R itself", { + create_local_package() + + use_package("R", "depends", "4.1") + original_minimum_r_version <- pkg_minimum_r_version() + + use_data(letters) + + expect_true(pkg_minimum_r_version() >= original_minimum_r_version) +}) diff --git a/tests/testthat/test-roxygen.R b/tests/testthat/test-roxygen.R index b3161bfa9..42a26ef61 100644 --- a/tests/testthat/test-roxygen.R +++ b/tests/testthat/test-roxygen.R @@ -19,14 +19,13 @@ test_that("use_roxygen_md() adds DESCRIPTION fields to naive package", { expect_true(uses_roxygen_md()) }) -test_that("use_roxygen_md() behaves for pre-existing Roxygen field", { +test_that("use_roxygen_md() finds 'markdown = TRUE' in presence of other stuff", { skip_if_not_installed("roxygen2") pkg <- create_local_package() - desc::desc_set(Roxygen = 'list(markdown = TRUE, r6 = FALSE, load = "source")') + desc::desc_set(Roxygen = 'list(markdown = TRUE, r6 = FALSE, load = "source", roclets = c("collate", "namespace", "rd", "roxyglobals::global_roclet"))') - expect_error(use_roxygen_md(), "already has") local_check_installed() - expect_no_error(use_roxygen_md(overwrite = TRUE)) + expect_no_error(use_roxygen_md()) expect_true(uses_roxygen_md()) }) diff --git a/tests/testthat/test-tidyverse.R b/tests/testthat/test-tidyverse.R index 057480121..7a8c08665 100644 --- a/tests/testthat/test-tidyverse.R +++ b/tests/testthat/test-tidyverse.R @@ -16,7 +16,7 @@ test_that("use_tidy_dependencies() isn't overly informative", { skip_if_offline("github.com") create_local_package() - use_package_doc() + use_package_doc(open = FALSE) withr::local_options(usethis.quiet = FALSE, cli.width = Inf) expect_snapshot( diff --git a/tests/testthat/test-upkeep.R b/tests/testthat/test-upkeep.R index f0da07051..a53cbe877 100644 --- a/tests/testthat/test-upkeep.R +++ b/tests/testthat/test-upkeep.R @@ -1,9 +1,28 @@ test_that("tidy upkeep bullets don't change accidentally", { create_local_package() use_mit_license() + expect_equal(last_upkeep_year(), 2000L) local_mocked_bindings( - Sys.Date = function() as.Date("2023-01-01"), + Sys.Date = function() as.Date("2025-01-01"), + usethis_version = function() "1.1.0", + author_has_rstudio_email = function() TRUE, + is_posit_pkg = function() TRUE, + is_posit_person_canonical = function() FALSE + ) + + expect_snapshot(writeLines(tidy_upkeep_checklist())) +}) + +test_that("tidy upkeep omits bullets present in last_upkeep", { + create_local_package() + use_mit_license() + expect_equal(last_upkeep_year(), 2000L) + record_upkeep_date(as.Date("2023-04-04")) + expect_equal(last_upkeep_year(), 2023L) + + local_mocked_bindings( + Sys.Date = function() as.Date("2025-01-01"), usethis_version = function() "1.1.0", author_has_rstudio_email = function() TRUE, is_posit_pkg = function() TRUE, diff --git a/tests/testthat/test-use_import_from.R b/tests/testthat/test-use_import_from.R index 060159c3e..6a3266276 100644 --- a/tests/testthat/test-use_import_from.R +++ b/tests/testthat/test-use_import_from.R @@ -1,16 +1,16 @@ test_that("use_import_from() imports the related package & adds line to package doc", { create_local_package() use_package_doc() - use_import_from("tibble", "tibble") + use_import_from("lifecycle", "deprecated") - expect_equal(proj_desc()$get_field("Imports"), "tibble") - expect_equal(roxygen_ns_show(), "#' @importFrom tibble tibble") + expect_equal(proj_desc()$get_field("Imports"), "lifecycle") + expect_equal(roxygen_ns_show(), "#' @importFrom lifecycle deprecated") }) test_that("use_import_from() adds one line for each function", { create_local_package() use_package_doc() - use_import_from("tibble", c("tibble", "enframe", "deframe")) + use_import_from("lifecycle", c("deprecate_warn", "deprecate_stop")) expect_snapshot(roxygen_ns_show()) }) @@ -21,8 +21,8 @@ test_that("use_import_from() generates helpful errors", { expect_snapshot(error = TRUE, { use_import_from(1) - use_import_from(c("tibble", "rlang")) + use_import_from(c("desc", "rlang")) - use_import_from("tibble", "pool_noodle") + use_import_from("desc", "pool_noodle") }) }) diff --git a/tests/testthat/test-vignette.R b/tests/testthat/test-vignette.R index 82b7a4690..c23681fe7 100644 --- a/tests/testthat/test-vignette.R +++ b/tests/testthat/test-vignette.R @@ -15,7 +15,7 @@ test_that("use_vignette() gives useful errors", { }) }) -test_that("use_vignette() does the promised setup", { +test_that("use_vignette() does the promised setup, Rmd", { create_local_package() use_vignette("name", "title") @@ -32,28 +32,79 @@ test_that("use_vignette() does the promised setup", { expect_identical(proj_desc()$get_field("VignetteBuilder"), "knitr") }) -# use_article ------------------------------------------------------------- +test_that("use_vignette() does the promised setup, qmd", { + create_local_package() + local_check_installed() + + use_vignette("name.qmd", "title") + expect_proj_file("vignettes/name.qmd") + + ignores <- read_utf8(proj_path(".gitignore")) + expect_true("inst/doc" %in% ignores) + + deps <- proj_deps() + expect_true( + all(c("knitr", "quarto") %in% deps$package[deps$type == "Suggests"]) + ) + + expect_identical(proj_desc()$get_field("VignetteBuilder"), "quarto") +}) -test_that("use_article goes in article subdirectory", { +test_that("use_vignette() does the promised setup, mix of Rmd and qmd", { create_local_package() + local_check_installed() + + use_vignette("older-vignette", "older Rmd vignette") + use_vignette("newer-vignette.qmd", "newer qmd vignette") + expect_proj_file("vignettes/older-vignette.Rmd") + expect_proj_file("vignettes/newer-vignette.qmd") + + deps <- proj_deps() + expect_true( + all(c("knitr", "quarto", "rmarkdown") %in% deps$package[deps$type == "Suggests"]) + ) - use_article("test") - expect_proj_file("vignettes/articles/test.Rmd") + vignette_builder <- proj_desc()$get_field("VignetteBuilder") + expect_match(vignette_builder, "knitr", fixed = TRUE) + expect_match(vignette_builder, "quarto", fixed = TRUE) }) -test_that("use_article() adds rmarkdown to Config/Needs/website", { +# use_article ------------------------------------------------------------- +test_that("use_article() does the promised setup, Rmd", { create_local_package() local_interactive(FALSE) - proj_desc_field_update("Config/Needs/website", "somepackage", append = TRUE) + # Let's have another package already in Config/Needs/website + proj_desc_field_update("Config/Needs/website", "somepackage") use_article("name", "title") + expect_proj_file("vignettes/articles/name.Rmd") + expect_setequal( proj_desc()$get_list("Config/Needs/website"), c("rmarkdown", "somepackage") ) }) +# Note that qmd articles seem to cause problems for build_site() rn +# https://github.com/r-lib/pkgdown/issues/2821 +test_that("use_article() does the promised setup, qmd", { + create_local_package() + local_check_installed() + local_interactive(FALSE) + + # Let's have another package already in Config/Needs/website + proj_desc_field_update("Config/Needs/website", "somepackage") + use_article("name.qmd", "title") + + expect_proj_file("vignettes/articles/name.qmd") + + expect_setequal( + proj_desc()$get_list("Config/Needs/website"), + c("quarto", "somepackage") + ) +}) + # helpers ----------------------------------------------------------------- test_that("valid_vignette_name() works", { @@ -61,3 +112,10 @@ test_that("valid_vignette_name() works", { expect_false(valid_vignette_name("01-test")) expect_false(valid_vignette_name("test.1")) }) + +test_that("we error informatively for bad vignette extension", { + expect_snapshot( + error = TRUE, + check_vignette_extension("Rnw") + ) +})