Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package: quarto
Title: R Interface to 'Quarto' Markdown Publishing System
Version: 1.4.4.9016
Version: 1.4.4.9017
Authors@R: c(
person("JJ", "Allaire", , "jj@posit.co", role = "aut",
comment = c(ORCID = "0000-0003-0174-9868")),
Expand Down
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Generated by roxygen2: do not edit by hand

export(check_newer_version)
export(is_using_quarto)
export(new_blog_post)
export(quarto_add_extension)
Expand Down
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# quarto (development version)

- Added `check_newer_version()` function to check if a newer version of Quarto is available. The function compares the current Quarto version against the latest stable and prerelease versions. It is aimed for verbosity by default (`verbose = TRUE`), but `verbose = FALSE` can also be set for just checking update availability with TRUE or FALSE return values. Version information is cached per session for up to 24 hours to minimize network requests.

- Added `write_yaml_metadata_block()` function to dynamically set YAML metadata in Quarto documents from R code chunks. This addresses the limitation where Quarto metadata must be static and defined in the document header. The function enables conditional content and metadata-driven document behavior based on R computations (thanks, @kmasiello, #137, #160).

- Added debugging logic for quarto vignette engine to help diagnose issues with Quarto vignettes in **pkgdown** and other context (thanks, @hadley, #185).
Expand Down
8 changes: 7 additions & 1 deletion R/aaa.R
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
#' Internal package state
#' @noRd
quarto <- new.env(parent = emptyenv())
the <- new.env(
list(
latest_stable = list(date = NULL, infos = NULL),
latest_prerelease = list(date = NULL, infos = NULL)
),
parent = emptyenv()
)
181 changes: 181 additions & 0 deletions R/utils-versions.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
#' Check for newer version of Quarto
#'
#' Checks if a newer version of Quarto is available and informs the user about
#' their current version status. The function compares the current Quarto version
#' against the latest stable and prerelease versions available online.
#'
#' @param version Character string specifying the Quarto version to check.
#' Defaults to the currently installed version detected by [quarto_version()].
#' Use "99.9.9" to indicate a development version.
#' @param verbose Logical indicating whether to print informational messages.
#' Defaults to `TRUE`. When `FALSE`, the function runs silently and only
#' returns the logical result.
#'
#' @return Invisibly returns a logical value:
#' - `TRUE` if an update is available
#' - `FALSE` if no update is needed or when using development version
#' The function is primarily called for its side effects of printing
#' informational messages (when `verbose = TRUE`).
#'
#' @details
#' The function handles three scenarios:
#' - **Development version** (99.9.9): Skips version check with informational message
#' - **Prerelease version**: Compares against latest prerelease and informs about updates
#' - **Stable version**: Compares against latest stable version and suggests updates if needed
#'
#' Version information is fetched from Quarto's download JSON endpoints and cached in current session
#' for up to 24 hours to avoid repeated network requests.
#'
#' @section Network Requirements:
#' This function requires an internet connection to fetch the latest version
#' information from quarto.org. If the network request fails, an error will be thrown.
#'
#' @examplesIf quarto::quarto_available() && quarto:::has_internet("https://www.quarto.org")
#' # Check current Quarto version
#' check_newer_version()
#'
#' # Check a specific version
#' check_newer_version("1.7.30")
#'
#' # Check development version (will skip check)
#' check_newer_version("99.9.9")
#'
#' # Check silently without messages
#' result <- check_newer_version(verbose = FALSE)
#' if (result) {
#' message("Update available!")
#' }
#'
#' @seealso
#' [quarto_version()] for getting the current Quarto version,
#'
#' @export
check_newer_version <- function(version = quarto_version(), verbose = TRUE) {
inform_if_verbose <- function(...) {
void <- function(...) invisible(NULL)
if (verbose) {
return(cli::cli_inform(...))
} else {
return(void(...))
}
}

if (version == "99.9.9") {
inform_if_verbose(c(
"i" = "Skipping version check for development version.",
">" = "Please update using development mode."
))
return(invisible(FALSE))
}
stable <- latest_available_version("stable")
if (version > stable) {
prerelease <- latest_available_version("prerelease")
if (version < prerelease) {
update <- TRUE
} else {
update <- FALSE
}
inform_if_verbose(
c(
"i" = "You are using prerelease version of Quarto: {version}.",
if (update) {
">" = "A newer version is available: {prerelease}. You can download it from {.url https://quarto.org/docs/download/prerelease.html} or your preferred package manager if available."
} else {
"v" = "You are using the latest prerelease version."
}
)
)
return(invisible(update))
} else if (version < stable) {
inform_if_verbose(c(
"i" = "You are using an older version of Quarto: {version}.",
" " = "The latest stable version is: {stable}.",
">" = "You can download new version from https://quarto.org/docs/download/ or your preferred package manager if available."
))
return(invisible(TRUE))
} else {
inform_if_verbose(c(
"i" = "You are using the latest stable version of Quarto: {version}."
))
return(invisible(FALSE))
}
}


versions_urls <- list(
stable = "https://quarto.org/docs/download/_download.json",
prerelease = "https://quarto.org/docs/download/_prerelease.json"
)

get_json <- function(url) {
jsonlite::fromJSON(url)
}

get_latest_info <- function(
type = c("stable", "prerelease"),
.call = rlang::caller_env()
) {
type <- match.arg(type)
res <- tryCatch(
get_json(versions_urls[[type]]),
error = function(e) {
rlang::abort(
"Failed to fetch latest versions: ",
parent = e,
call = .call
)
return(NULL)

Check warning on line 127 in R/utils-versions.R

View check run for this annotation

Codecov / codecov/patch

R/utils-versions.R#L127

Added line #L127 was not covered by tests
}
)

if (!is.null(res)) {
return(res)
}
}

default_infos <- function(type) {
list(date = Sys.Date(), infos = get_latest_info(type))
}

latest_available_infos <- function(type = c("stable", "prerelease")) {
type <- match.arg(type)
type_name <- paste0("latest_", type)
latest <- rlang::env_cache(
the,
type_name,
default_infos(type)
)
# add a time check to invalidate the cache if the date is older than 1 day
if (
!is.null(latest$infos) &&
!is.null(latest$date) &&
latest$date > Sys.Date() - 1
) {
return(latest$infos)
} else {
rlang::env_poke(
the,
type_name,
default_infos(type)
)

Check warning on line 160 in R/utils-versions.R

View check run for this annotation

Codecov / codecov/patch

R/utils-versions.R#L156-L160

Added lines #L156 - L160 were not covered by tests
}
}

latest_available_version <- function(type = c("stable", "prerelease")) {
type <- match.arg(type)
infos <- latest_available_infos(type)
if (is.null(infos)) {
return(NULL)

Check warning on line 168 in R/utils-versions.R

View check run for this annotation

Codecov / codecov/patch

R/utils-versions.R#L168

Added line #L168 was not covered by tests
}
return(infos$version)
}


latest_available_published <- function(type = c("stable", "prerelease")) {
type <- match.arg(type)
infos <- latest_available_infos(type)
if (is.null(infos)) {
return(NULL)

Check warning on line 178 in R/utils-versions.R

View check run for this annotation

Codecov / codecov/patch

R/utils-versions.R#L178

Added line #L178 was not covered by tests
}
return(infos$published)
}
13 changes: 13 additions & 0 deletions R/utils.R
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,16 @@ hide_path <- function(path) {
gsub(fs::path_real(path), "<project directory>", x, fixed = TRUE)
}
}

has_internet <- function(host = "https://www.google.com") {
tryCatch(
{
headers <- curlGetHeaders(host)
# If we get headers back, we have internet
!is.null(headers) && length(headers) > 0
},
error = function(e) {
FALSE
}
)
}
1 change: 1 addition & 0 deletions _pkgdown.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ reference:
- quarto_available
- is_using_quarto
- quarto_binary_sitrep
- check_newer_version

- title: "Theme Helpers"
desc: >
Expand Down
69 changes: 69 additions & 0 deletions man/check_newer_version.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

32 changes: 32 additions & 0 deletions tests/testthat/_snaps/utils-versions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# check_newer_version handles stable version scenarios

Code
expect_invisible(expect_true(check_newer_version("1.0.0")))
Message
i You are using an older version of Quarto: 1.0.0.
The latest stable version is: 1.5.3.
> You can download new version from https://quarto.org/docs/download/ or your preferred package manager if available.

---

Code
expect_invisible(expect_false(check_newer_version("1.5.3")))
Message
i You are using the latest stable version of Quarto: 1.5.3.

# check_newer_version handles prerelease version scenarios

Code
expect_invisible(expect_true(check_newer_version("1.6.3")))
Message
i You are using prerelease version of Quarto: 1.6.3.
A newer version is available: 1.6.4. You can download it from <https://quarto.org/docs/download/prerelease.html> or your preferred package manager if available.

---

Code
expect_invisible(expect_false(check_newer_version("1.6.5")))
Message
i You are using prerelease version of Quarto: 1.6.5.
You are using the latest prerelease version.

Loading