Skip to content

Commit e47d571

Browse files
committed
Add a function to check if new version is available online
1 parent 62c0eb7 commit e47d571

File tree

9 files changed

+429
-1
lines changed

9 files changed

+429
-1
lines changed

NAMESPACE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Generated by roxygen2: do not edit by hand
22

3+
export(check_newer_version)
34
export(is_using_quarto)
45
export(new_blog_post)
56
export(quarto_add_extension)

R/aaa.R

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
11
#' Internal package state
22
#' @noRd
3-
quarto <- new.env(parent = emptyenv())
3+
the <- new.env(
4+
list(
5+
latest_stable = list(date = NULL, infos = NULL),
6+
latest_prerelease = list(date = NULL, infos = NULL)
7+
),
8+
parent = emptyenv()
9+
)

R/utils-versions.R

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
#' Check for newer version of Quarto
2+
#'
3+
#' Checks if a newer version of Quarto is available and informs the user about
4+
#' their current version status. The function compares the current Quarto version
5+
#' against the latest stable and prerelease versions available online.
6+
#'
7+
#' @param version Character string specifying the Quarto version to check.
8+
#' Defaults to the currently installed version detected by [quarto_version()].
9+
#' Use "99.9.9" to indicate a development version.
10+
#'
11+
#' @return Invisibly returns `NULL`. The function is called for its side effects
12+
#' of printing informational messages about version status.
13+
#'
14+
#' @details
15+
#' The function handles three scenarios:
16+
#' - **Development version** (99.9.9): Skips version check with informational message
17+
#' - **Prerelease version**: Compares against latest prerelease and informs about updates
18+
#' - **Stable version**: Compares against latest stable version and suggests updates if needed
19+
#'
20+
#' Version information is fetched from Quarto's download JSON endpoints and cached in current session
21+
#' for up to 24 hours to avoid repeated network requests.
22+
#'
23+
#' @section Network Requirements:
24+
#' This function requires an internet connection to fetch the latest version
25+
#' information from quarto.org. If the network request fails, an error will be thrown.
26+
#'
27+
#' @examplesIf quarto::quarto_available() && has_internet("https://www.quarto.org")
28+
#' # Check current Quarto version
29+
#' check_newer_version()
30+
#'
31+
#' # Check a specific version
32+
#' check_newer_version("1.7.30")
33+
#'
34+
#' # Check development version (will skip check)
35+
#' check_newer_version("99.9.9")
36+
#'
37+
#' @seealso
38+
#' [quarto_version()] for getting the current Quarto version,
39+
#'
40+
#' @export
41+
check_newer_version <- function(version = quarto_version()) {
42+
if (version == "99.9.9") {
43+
rlang::inform(c(
44+
"i" = "Skipping version check for development version.",
45+
">" = "Please update using development mode."
46+
))
47+
return(invisible())
48+
}
49+
stable <- latest_available_version("stable")
50+
if (version > stable) {
51+
prerelease <- latest_available_version("prerelease")
52+
if (version < prerelease) {
53+
update <- TRUE
54+
} else {
55+
update <- FALSE
56+
}
57+
cli::cli_inform(c(
58+
"i" = "You are using prerelease version of Quarto: {version}.",
59+
if (update) {
60+
">" = "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."
61+
} else {
62+
"v" = "You are using the latest prerelease version."
63+
}
64+
))
65+
} else if (version < stable) {
66+
cli::cli_inform(c(
67+
"i" = "You are using an older version of Quarto: {version}.",
68+
" " = "The latest stable version is: {stable}.",
69+
">" = "You can download new version from https://quarto.org/docs/download/ or your preferred package manager if available."
70+
))
71+
} else {
72+
cli::cli_inform(c(
73+
"i" = "You are using the latest stable version of Quarto: {version}."
74+
))
75+
}
76+
}
77+
78+
versions_urls <- list(
79+
stable = "https://quarto.org/docs/download/_download.json",
80+
prerelease = "https://quarto.org/docs/download/_prerelease.json"
81+
)
82+
83+
get_json <- function(url) {
84+
jsonlite::fromJSON(url)
85+
}
86+
87+
get_latest_info <- function(
88+
type = c("stable", "prerelease"),
89+
.call = rlang::caller_env()
90+
) {
91+
type <- match.arg(type)
92+
res <- tryCatch(
93+
get_json(versions_urls[[type]]),
94+
error = function(e) {
95+
rlang::abort(
96+
"Failed to fetch latest versions: ",
97+
parent = e,
98+
call = .call
99+
)
100+
return(NULL)
101+
}
102+
)
103+
104+
if (!is.null(res)) {
105+
return(res)
106+
}
107+
}
108+
109+
default_infos <- function(type) {
110+
list(date = Sys.Date(), infos = get_latest_info(type))
111+
}
112+
113+
latest_available_infos <- function(type = c("stable", "prerelease")) {
114+
type <- match.arg(type)
115+
type_name <- paste0("latest_", type)
116+
latest <- rlang::env_cache(
117+
the,
118+
type_name,
119+
default_infos(type)
120+
)
121+
# add a time check to invalidate the cache if the date is older than 1 day
122+
if (
123+
!is.null(latest$infos) &&
124+
!is.null(latest$date) &&
125+
latest$date > Sys.Date() - 1
126+
) {
127+
return(latest$infos)
128+
} else {
129+
rlang::env_poke(
130+
the,
131+
type_name,
132+
default_infos(type)
133+
)
134+
}
135+
}
136+
137+
latest_available_version <- function(type = c("stable", "prerelease")) {
138+
type <- match.arg(type)
139+
infos <- latest_available_infos(type)
140+
if (is.null(infos)) {
141+
return(NULL)
142+
}
143+
return(infos$version)
144+
}
145+
146+
147+
latest_available_published <- function(type = c("stable", "prerelease")) {
148+
type <- match.arg(type)
149+
infos <- latest_available_infos(type)
150+
if (is.null(infos)) {
151+
return(NULL)
152+
}
153+
return(infos$published)
154+
}

R/utils.R

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,16 @@ hide_path <- function(path) {
5252
gsub(fs::path_real(path), "<project directory>", x, fixed = TRUE)
5353
}
5454
}
55+
56+
has_internet <- function(host = "https://www.google.com") {
57+
tryCatch(
58+
{
59+
headers <- curlGetHeaders(host)
60+
# If we get headers back, we have internet
61+
!is.null(headers) && length(headers) > 0
62+
},
63+
error = function(e) {
64+
FALSE
65+
}
66+
)
67+
}

_pkgdown.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ reference:
4747
- quarto_available
4848
- is_using_quarto
4949
- quarto_binary_sitrep
50+
- check_newer_version
5051

5152
- title: "Theme Helpers"
5253
desc: >

man/check_newer_version.Rd

Lines changed: 54 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# check_newer_version handles stable version scenarios
2+
3+
Code
4+
check_newer_version("1.0.0")
5+
Message
6+
i You are using an older version of Quarto: 1.0.0.
7+
The latest stable version is: 1.5.3.
8+
> You can download new version from https://quarto.org/docs/download/ or your preferred package manager if available.
9+
10+
---
11+
12+
Code
13+
check_newer_version("1.5.3")
14+
Message
15+
i You are using the latest stable version of Quarto: 1.5.3.
16+
17+
# check_newer_version handles prerelease version scenarios
18+
19+
Code
20+
check_newer_version("1.6.3")
21+
Message
22+
i You are using prerelease version of Quarto: 1.6.3.
23+
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.
24+
25+
---
26+
27+
Code
28+
check_newer_version("1.6.5")
29+
Message
30+
i You are using prerelease version of Quarto: 1.6.5.
31+
You are using the latest prerelease version.
32+

0 commit comments

Comments
 (0)