Skip to content

Commit b7c32bb

Browse files
authored
Correctly show quarto error when it fails (#238)
* correctly add quarto-cli error message when reporting error in quarto_run * Add tests, and update all snapshot transformation * Add NEWS and update version
1 parent 18db58d commit b7c32bb

File tree

8 files changed

+150
-15
lines changed

8 files changed

+150
-15
lines changed

DESCRIPTION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Package: quarto
22
Title: R Interface to 'Quarto' Markdown Publishing System
3-
Version: 1.4.4.9004
3+
Version: 1.4.4.9005
44
Authors@R: c(
55
person("JJ", "Allaire", , "[email protected]", role = "aut",
66
comment = c(ORCID = "0000-0003-0174-9868")),

NEWS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212

1313
- `QUARTO_R_QUIET` environment variable can be used to set `quarto.quiet` option, which overrides any `quiet = TRUE` argument passed to `quarto_*` functions. This can be useful to debug Quarto rendering inside other packages, like **pkgdown**. Overrides will also now happens for [GHA debug logging](https://docs.github.com/en/actions/monitoring-and-troubleshooting-workflows/troubleshooting-workflows/enabling-debug-logging).
1414

15+
- Correctly report Quarto CLI error when background process call to `quarto` fails (thanks, @salim-b, [#235](https://github.com/quarto-dev/quarto-r/issues/235))
16+
1517
# quarto 1.4.4
1618

1719
- `quarto_preview()` now looks at `quarto preview` log to browse to the correct url when inside RStudio viewer (thanks, @aronatkins, #167).

R/quarto.R

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,22 @@
33
#' Determine the path to the quarto binary. Uses `QUARTO_PATH` environment
44
#' variable if defined, otherwise uses `Sys.which()`.
55
#'
6+
#' @param normalize If `TRUE` (default), normalize the path using [base::normalizePath()].
7+
#'
68
#' @return Path to quarto binary (or `NULL` if not found)
79
#'
810
#' @export
9-
quarto_path <- function() {
11+
quarto_path <- function(normalize = TRUE) {
1012
path_env <- get_quarto_path_env()
1113
quarto_path <- if (is.na(path_env)) {
1214
path <- unname(Sys.which("quarto"))
1315
if (nzchar(path)) path else return(NULL)
1416
} else {
1517
path_env
1618
}
19+
if (!normalize) {
20+
return(quarto_path)
21+
}
1722
normalizePath(quarto_path, winslash = "/", mustWork = FALSE)
1823
}
1924

@@ -69,11 +74,25 @@ quarto_run <- function(
6974
},
7075
error = function(e) {
7176
msg <- c(x = "Error running quarto cli.")
77+
# if there is an error message from quarto CLI, add it to the message
78+
if (e$stderr != "") {
79+
quarto_error_msg <- xfun::split_lines(e$stderr)
80+
names(quarto_error_msg) <- rep(" ", length(quarto_error_msg))
81+
msg <- c(
82+
msg,
83+
" " = paste0(rep("-", nchar(msg)), collapse = ""),
84+
quarto_error_msg
85+
)
86+
}
87+
88+
# if `--quiet` has been set, quarto CLI won't report any error (e$stderr will be empty)
89+
# So remind user to run without `--quiet` to see the full error message
7290
if (cli_arg_quiet() %in% args)
7391
msg <- c(
7492
msg,
7593
"i" = "Rerun with `quiet = FALSE` to see the full error message."
7694
)
95+
7796
cli::cli_abort(msg, call = .call, parent = e)
7897
}
7998
)

man/quarto_path.Rd

Lines changed: 4 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/testthat/_snaps/quarto.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,31 @@
99
Caused by error:
1010
! System command 'quarto' failed
1111

12+
# quarto_run report full quarto cli error message
13+
14+
Code
15+
quarto_inspect()
16+
Condition
17+
Error in `quarto_inspect()`:
18+
x Error running quarto cli.
19+
-------------------------
20+
ERROR: Book chapter 'intro.qmd' not found
21+
22+
Stack trace:
23+
at throwInputNotFound (<quarto.js full path with location>)
24+
at findInputs (<quarto.js full path with location>)
25+
at eventLoopTick (ext:core/01_core.js:175:7)
26+
at async findChapters (<quarto.js full path with location>)
27+
at async bookRenderItems (<quarto.js full path with location>)
28+
at async Object.bookProjectConfig [as config] (<quarto.js full path with location>)
29+
at async projectContext (<quarto.js full path with location>)
30+
at async inspectConfig (<quarto.js full path with location>)
31+
at async Command.actionHandler (<quarto.js full path with location>)
32+
at async Command.execute (<quarto.js full path with location>)
33+
34+
Caused by error:
35+
! System command 'quarto' failed
36+
1237
# is_using_quarto correctly check directory
1338

1439
Code

tests/testthat/helper.R

Lines changed: 75 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,34 @@ local_qmd_file <- function(..., .env = parent.frame()) {
6363
path
6464
}
6565

66+
local_quarto_project <- function(
67+
name = "test-project",
68+
type,
69+
...,
70+
.env = parent.frame()
71+
) {
72+
skip_if_no_quarto()
73+
path_tmp <- withr::local_tempdir(
74+
pattern = "quarto-tests-project-",
75+
.local_envir = .env
76+
)
77+
tryCatch(
78+
quarto_create_project(
79+
name = name,
80+
type = type,
81+
dir = path_tmp,
82+
no_prompt = TRUE,
83+
quiet = TRUE,
84+
...
85+
),
86+
error = function(e) {
87+
stop("Creating temp project for tests failed", call. = FALSE)
88+
}
89+
)
90+
# return the path to the created project
91+
return(file.path(path_tmp, name))
92+
}
93+
6694
.render <- function(input, output_file = NULL, ..., .env = parent.frame()) {
6795
skip_if_no_quarto()
6896
skip_if_not_installed("withr")
@@ -105,28 +133,66 @@ expect_snapshot_qmd_output <- function(name, input, output_file = NULL, ...) {
105133

106134
transform_quarto_cli_in_output <- function(
107135
full_path = FALSE,
108-
normalize_path = FALSE,
109-
version = FALSE
136+
version = FALSE,
137+
dir_only = FALSE
110138
) {
139+
hide_path <- function(lines, real_path) {
140+
gsub(
141+
real_path,
142+
"<quarto full path>",
143+
lines,
144+
fixed = TRUE
145+
)
146+
}
147+
111148
return(
112149
function(lines) {
113150
if (full_path) {
114151
quarto_found <- find_quarto()
115-
if (normalize_path) {
116-
quarto_found <- normalizePath(quarto_found, mustWork = FALSE)
152+
if (dir_only) {
153+
quarto_found <- dirname(quarto_found)
117154
}
118-
lines <- gsub(quarto_found, "<quarto full path>", lines, fixed = TRUE)
155+
quarto_found_normalized <- normalizePath(quarto_found, mustWork = FALSE)
156+
# look for non-normalized path
157+
lines <- hide_path(lines, quarto_found)
158+
# look for normalized path
159+
lines <- hide_path(lines, quarto_found_normalized)
160+
161+
non_normalized_path <- quarto_path(normalize = FALSE)
162+
non_normalized_path_slash <- gsub("\\\\", "/", non_normalized_path)
163+
lines <- hide_path(lines, non_normalized_path)
164+
lines <- hide_path(lines, non_normalized_path_slash)
165+
119166
# seems like there are quotes around path in CI windows
120167
lines <- gsub(
121-
"\"<quarto full path>\"",
122-
"<quarto full path>",
123-
lines,
124-
fixed = TRUE
168+
"\"<quarto full path>([^\"]*)\"",
169+
"<quarto full path>\\1",
170+
lines
125171
)
172+
173+
# Handle quarto.js in stackstrace outputs
174+
lines <- gsub(
175+
"file:[/]{2,3}<quarto full path>[/\\]quarto.js:\\d+:\\d+",
176+
"<quarto.js full path with location>",
177+
lines
178+
)
179+
# fixup binary name difference it exists in the output
180+
# windows is quarto.exe while quarto on other OS
181+
lines <- gsub("quarto.exe", "quarto", lines, fixed = TRUE)
126182
} else {
127183
# it will be quarto.exe only on windows
128184
lines <- gsub("quarto\\.(exe|cmd)", "quarto", lines)
129185
}
186+
187+
# fallback: Above can fail on some windows situation, so try a regex match
188+
# it should only match windows path with Drive letters
189+
lines <- gsub(
190+
"file:[/]{2,3}[A-Za-z]:[\\\\/](?:[^:\\n]+[\\\\/])*bin[\\\\/]quarto\\.js:\\d+:\\d+",
191+
"<quarto.js full path with location>",
192+
lines,
193+
perl = TRUE
194+
)
195+
130196
if (version) {
131197
lines <- gsub(quarto_version(), "<quarto version>", lines, fixed = TRUE)
132198
}

tests/testthat/project/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/.quarto

tests/testthat/test-quarto.R

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,26 @@ test_that("quarto_run gives guidance in error", {
1414
)
1515
})
1616

17+
test_that("quarto_run report full quarto cli error message", {
18+
skip_if_no_quarto()
19+
local_reproducible_output(width = 1000)
20+
# Ensure we don't have colors in the output for quarto-cli error
21+
withr::local_envvar(list(NO_COLOR = 1L))
22+
# https://github.com/quarto-dev/quarto-r/issues/235
23+
tmp_proj <- local_quarto_project(type = "book")
24+
withr::local_dir(tmp_proj)
25+
# simulate an error by renaming the intro.qmd
26+
file.rename(from = "intro.qmd", to = "no_intro.qmd")
27+
expect_snapshot(
28+
error = TRUE,
29+
quarto_inspect(),
30+
transform = transform_quarto_cli_in_output(
31+
full_path = TRUE,
32+
dir_only = TRUE
33+
)
34+
)
35+
})
36+
1737
test_that("is_using_quarto correctly check directory", {
1838
qmd <- local_qmd_file(c("content"))
1939
# Only qmd
@@ -63,7 +83,7 @@ test_that("quarto CLI sitrep", {
6383
lines,
6484
fixed = TRUE
6585
)
66-
transform_quarto_cli_in_output(full_path = TRUE, normalize_path = TRUE)(
86+
transform_quarto_cli_in_output(full_path = TRUE)(
6787
lines
6888
)
6989
}
@@ -75,8 +95,7 @@ test_that("quarto CLI sitrep", {
7595
expect_snapshot(
7696
quarto_binary_sitrep(debug = TRUE),
7797
transform = transform_quarto_cli_in_output(
78-
full_path = TRUE,
79-
normalize_path = TRUE
98+
full_path = TRUE
8099
)
81100
)
82101
)

0 commit comments

Comments
 (0)