Skip to content

Commit 82a0525

Browse files
committed
Expanded readme builder to support Quarto. Extended tests for qmds. Deprecated build_rmd.
1 parent 635341b commit 82a0525

10 files changed

Lines changed: 190 additions & 62 deletions

File tree

DESCRIPTION

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ Suggests:
5757
MASS,
5858
mockery (>= 0.4.3),
5959
pingr (>= 2.0.1),
60+
quarto (>= 1.5.1),
6061
rhub (>= 1.1.1),
6162
rmarkdown (>= 2.14),
6263
rstudioapi (>= 0.13),

NAMESPACE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export(as.package)
66
export(bash)
77
export(build)
88
export(build_manual)
9+
export(build_md)
910
export(build_readme)
1011
export(build_rmd)
1112
export(build_site)

NEWS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# devtools (development version)
2+
* `build_rmd()` is deprecated in favor of `build_md()` which also handles Quarto.
23

34
# devtools 2.4.6
45

R/build-readme.R

Lines changed: 92 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,31 @@
1-
#' Build a Rmarkdown files package
1+
#' Build a qmd or Rmarkdown files package
22
#'
3-
#' `build_rmd()` is a wrapper around [rmarkdown::render()] that first installs
4-
#' a temporary copy of the package, and then renders each `.Rmd` in a clean R
5-
#' session. `build_readme()` locates your `README.Rmd` and builds it into a
6-
#' `README.md`
3+
#' `build_md()` is a wrapper around [rmarkdown::render()] and
4+
#' [quarto::quarto_render()] that first installs a temporary copy of the
5+
#' package, and then renders each `.Rmd` or `.qmd` in a clean R session.
6+
#' `build_readme()` locates your `README.Rmd` or `README.qmd` and builds it into
7+
#' a `README.md`.
78
#'
8-
#' @param files The Rmarkdown files to be rendered.
9+
#' @param files The R Markdown or Quarto files to be rendered.
910
#' @param path path to the package to build the readme.
10-
#' @param ... additional arguments passed to [rmarkdown::render()]
11+
#' @param output_options A list of options passed to [rmarkdown::render()] for
12+
#' `.Rmd` inputs. Ignored for Quarto `.qmd` inputs.
13+
#' @param ... additional arguments passed to [rmarkdown::render()] for `.Rmd`
14+
#' inputs or to [quarto::quarto_render()] for `.qmd` inputs. Arguments are shared.
1115
#' @inheritParams install
1216
#' @inheritParams rmarkdown::render
1317
#' @export
14-
build_rmd <- function(files, path = ".", output_options = list(), ..., quiet = TRUE) {
18+
build_md <- function(
19+
files,
20+
path = ".",
21+
output_options = list(),
22+
...,
23+
quiet = TRUE
24+
) {
1525
check_dots_used(action = getOption("devtools.ellipsis_action", rlang::warn))
1626

1727
pkg <- as.package(path)
1828

19-
rlang::check_installed("rmarkdown")
2029
save_all()
2130

2231
paths <- files
@@ -28,40 +37,98 @@ build_rmd <- function(files, path = ".", output_options = list(), ..., quiet = T
2837
cli::cli_abort("Can't find file{?s}: {.path {files[!ok]}}.")
2938
}
3039

31-
local_install(pkg, quiet = TRUE)
40+
is_rmd <- grepl("\\.[Rr]md$", paths)
41+
is_qmd <- grepl("\\.[Qq]md$", paths)
42+
43+
if (!all(is_rmd | is_qmd)) {
44+
cli::cli_abort("Can only build {.file .Rmd} or {.file .qmd} files.")
45+
}
3246

33-
# Ensure rendering github_document() doesn't generate HTML file
34-
output_options$html_preview <- FALSE
47+
if (any(is_rmd)) {
48+
rlang::check_installed("rmarkdown")
49+
# Ensure rendering github_document() doesn't generate HTML file
50+
output_options$html_preview <- FALSE
51+
}
3552

53+
if (any(is_qmd)) {
54+
rlang::check_installed("quarto")
55+
}
56+
57+
local_install(pkg, quiet = TRUE)
3658

3759
for (path in paths) {
3860
cli::cli_inform(c(i = "Building {.path {path}}"))
39-
callr::r_safe(
40-
function(...) rmarkdown::render(...),
41-
args = list(input = path, ..., output_options = output_options, quiet = quiet),
42-
show = TRUE,
43-
spinner = FALSE,
44-
stderr = "2>&1"
45-
)
61+
if (grepl("\\.[Qq]md$", path)) {
62+
callr::r_safe(
63+
function(...) quarto::quarto_render(...),
64+
args = list(
65+
input = path,
66+
...,
67+
quiet = quiet
68+
),
69+
show = TRUE,
70+
spinner = FALSE,
71+
stderr = "2>&1"
72+
)
73+
} else {
74+
callr::r_safe(
75+
function(...) rmarkdown::render(...),
76+
args = list(
77+
input = path,
78+
...,
79+
output_options = output_options,
80+
quiet = quiet
81+
),
82+
show = TRUE,
83+
spinner = FALSE,
84+
stderr = "2>&1"
85+
)
86+
}
4687
}
4788

4889
invisible(TRUE)
4990
}
5091

51-
#' @rdname build_rmd
92+
#' @rdname build_md
93+
#' @export
94+
build_rmd <- function(...) {
95+
cli::cli_warn(
96+
c(
97+
"!" = "{.fn build_rmd} is deprecated.",
98+
"i" = "Please use {.fn build_md} instead."
99+
),
100+
.frequency = "regularly",
101+
.frequency_id = "build_rmd"
102+
)
103+
build_md(...)
104+
}
105+
106+
#' @rdname build_md
52107
#' @export
53108
build_readme <- function(path = ".", quiet = TRUE, ...) {
54109
pkg <- as.package(path)
55110

56-
regexp <- paste0(path_file(pkg$path), "/(inst/)?readme[.]rmd")
57-
readme_path <- path_abs(dir_ls(pkg$path, ignore.case = TRUE, regexp = regexp, recurse = 1, type = "file"))
111+
regexp <- paste0(path_file(pkg$path), "/(inst/)?readme[.](r|q)md")
112+
readme_path <- path_abs(
113+
dir_ls(
114+
pkg$path,
115+
ignore.case = TRUE,
116+
regexp = regexp,
117+
recurse = 1,
118+
type = "file"
119+
)
120+
)
58121

59122
if (length(readme_path) == 0) {
60-
cli::cli_abort("Can't find {.file README.Rmd} or {.file inst/README.Rmd}.")
123+
cli::cli_abort(
124+
"Can't find {.file README.Rmd}, {.file inst/README.Rmd}, {.file README.qmd}, or {.file inst/README.qmd}."
125+
)
61126
}
62127
if (length(readme_path) > 1) {
63-
cli::cli_abort("Can't have both {.file README.Rmd} and {.file inst/README.Rmd}.")
128+
cli::cli_abort(
129+
"Can't have multiple README sources: {.file README.Rmd}, {.file inst/README.Rmd}, {.file README.qmd}, or {.file inst/README.qmd}."
130+
)
64131
}
65132

66-
build_rmd(readme_path, path = path, quiet = quiet, ...)
133+
build_md(readme_path, path = path, quiet = quiet, ...)
67134
}

inst/WORDLIST

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ pre
128128
processx
129129
profvis
130130
pryr
131+
qmd
131132
rOpenSci
132133
randomises
133134
rcmdcheck

man/build_md.Rd

Lines changed: 34 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/build_rmd.Rd

Lines changed: 0 additions & 32 deletions
This file was deleted.

man/check.Rd

Lines changed: 7 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/testthat/_snaps/build-readme.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@
44
build_readme(pkg)
55
Condition
66
Error in `build_readme()`:
7-
! Can't find 'README.Rmd' or 'inst/README.Rmd'.
7+
! Can't find 'README.Rmd', 'inst/README.Rmd', 'README.qmd', or 'inst/README.qmd'.
88

99
---
1010

1111
Code
1212
build_readme(pkg)
1313
Condition
1414
Error in `build_readme()`:
15-
! Can't have both 'README.Rmd' and 'inst/README.Rmd'.
15+
! Can't have multiple README sources: 'README.Rmd', 'inst/README.Rmd', 'README.qmd', or 'inst/README.qmd'.
1616

tests/testthat/test-build-readme.R

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,35 @@ test_that("can build README in inst/", {
2727
expect_false(file_exists(path(pkg, "inst", "README.html")))
2828
})
2929

30+
test_that("can build Quarto README in root directory", {
31+
skip_on_cran()
32+
33+
pkg <- local_package_create()
34+
suppressMessages(usethis::with_project(pkg, use_readme_qmd()))
35+
36+
suppressMessages(build_readme(pkg))
37+
expect_true(file_exists(path(pkg, "README.md")))
38+
expect_false(file_exists(path(pkg, "README.html")))
39+
})
40+
41+
test_that("can build Quarto README in inst/", {
42+
skip_on_cran()
43+
44+
pkg <- local_package_create()
45+
suppressMessages(usethis::with_project(pkg, use_readme_qmd()))
46+
dir_create(pkg, "inst")
47+
file_move(
48+
path(pkg, "README.qmd"),
49+
path(pkg, "inst", "README.qmd")
50+
)
51+
52+
suppressMessages(build_readme(pkg))
53+
expect_true(file_exists(path(pkg, "inst", "README.md")))
54+
expect_false(file_exists(path(pkg, "README.Rmd")))
55+
expect_false(file_exists(path(pkg, "README.md")))
56+
expect_false(file_exists(path(pkg, "inst", "README.html")))
57+
})
58+
3059
test_that("useful errors if too few or too many", {
3160
pkg <- local_package_create()
3261
expect_snapshot(build_readme(pkg), error = TRUE)
@@ -35,6 +64,17 @@ test_that("useful errors if too few or too many", {
3564
dir_create(pkg, "inst")
3665
file_copy(path(pkg, "README.Rmd"), path(pkg, "inst", "README.Rmd"))
3766
expect_snapshot(build_readme(pkg), error = TRUE)
67+
68+
suppressMessages(usethis::with_project(pkg, use_readme_qmd()))
69+
dir_create(pkg, "inst")
70+
file_copy(path(pkg, "README.qmd"), path(pkg, "inst", "README.qmd"))
71+
expect_snapshot(build_readme(pkg), error = TRUE)
72+
})
73+
74+
test_that("useful errors if too many--mixed Quarto and Rmd", {
75+
suppressMessages(usethis::with_project(pkg, use_readme_rmd()))
76+
suppressMessages(usethis::with_project(pkg, use_readme_qmd()))
77+
expect_snapshot(build_readme(pkg), error = TRUE)
3878
})
3979

4080
test_that("don't error for README in another directory", {
@@ -47,3 +87,14 @@ test_that("don't error for README in another directory", {
4787

4888
expect_no_error(suppressMessages(build_readme(pkg)))
4989
})
90+
91+
test_that("don't error for Quarto README in another directory", {
92+
skip_on_cran()
93+
94+
pkg <- local_package_create()
95+
suppressMessages(usethis::with_project(pkg, use_readme_qmd(open = FALSE)))
96+
dir_create(pkg, "data-raw")
97+
file_create(pkg, "data-raw", "README.md")
98+
99+
expect_no_error(suppressMessages(build_readme(pkg)))
100+
})

0 commit comments

Comments
 (0)