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,7 +1,7 @@
Type: Package
Package: audit.base
Title: Base package for Posit Checks
Version: 0.7.2
Version: 0.7.3
Authors@R:
person("Jumping", "Rivers", , "info@jumpingrivers.com", role = c("aut", "cre"))
Description: Base package for sharing classes between posit audit
Expand Down
4 changes: 4 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# audit.base 0.7.3 _2026-10-15_
* fix: A release newer than the version list is reported as newer than the list, not as past EOL (#55)
* fix: Versions are compared as numbers, so Quarto 1.10 counts as newer than 1.9

# audit.base 0.7.2 _2026-10-15_
* fix: The Quarto Python test installs on Python 3.14. Its `requirements.txt` lists jupyter, matplotlib and numpy with lower bounds instead of 107 exact pins (#54)
* chore: Add Posit Workbench 2026.10.0 to the cached versions
Expand Down
31 changes: 25 additions & 6 deletions R/software-versions.R
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,12 @@ print_colour_version = function(row) {
return(invisible(NULL))
}

if (isFALSE(row$within_eol)) {
if (is.na(row$patch) && isTRUE(row$within_eol)) {
cli::cli_alert_info(
"{software_name}: v{row$installed_version} installed, which is newer than \\
audit.base's version list. Try updating audit.base."
)
} else if (isFALSE(row$within_eol)) {
cli::cli_alert_danger(
"{software_name}: v{row$installed_version} installed, \\
but EOL has past and should be removed."
Expand All @@ -67,6 +72,16 @@ print_colour_version = function(row) {
invisible(NULL)
}

# Compare X.Y versions as numbers, so that 1.10 > 1.9. NA if either side is missing.
version_compare = function(x, y, op) {
out = rep(NA, length(x))
ok = !is.na(x) & !is.na(y)
out[ok] = op(numeric_version(x[ok]), numeric_version(y[ok]))
out
}
max_version = function(x) as.character(max(numeric_version(x)))
min_version = function(x) as.character(min(numeric_version(x)))

# Returns X.Y from X.Y.Z
get_major = function(v) unlist(stringr::str_match(v, "^([0-9]*\\.[0-9]*)")[, 2])
# Returns Z - use numeric for comparisons
Expand All @@ -79,14 +94,14 @@ in_db = function(installed, remote = FALSE) {
# latest/earliest versions stored in DB
software_range = get_latest_versions(remote = remote) %>%
dplyr::group_by(.data$software) %>%
dplyr::summarise(latest = max(.data$major), earliest = min(.data$major))
dplyr::summarise(latest = max_version(.data$major), earliest = min_version(.data$major))

# Check installed packages are in software range
installed %>%
dplyr::left_join(software_range, by = c("software" = "software")) %>%
dplyr::mutate(
to_old = .data$installed_major < .data$earliest,
to_new = .data$installed_major > .data$latest
to_old = version_compare(.data$installed_major, .data$earliest, `<`),
to_new = version_compare(.data$installed_major, .data$latest, `>`)
) %>%
dplyr::select(-"latest", -"earliest")
}
Expand Down Expand Up @@ -147,10 +162,14 @@ versions_to_display = function(installed, remote = FALSE) {
) %>%
dplyr::arrange(.data$software, .data$version)

# Old versions don't appear - so just tidy up some NAs
# Versions missing from the list are past EOL, unless they're newer than the list
l = dplyr::mutate(
all,
within_eol = ifelse(is.na(.data$within_eol), FALSE, .data$within_eol),
within_eol = dplyr::case_when(
!is.na(.data$within_eol) ~ .data$within_eol,
.data$to_new %in% TRUE ~ TRUE,
.default = FALSE
),
version = ifelse(is.na(.data$version), .data$installed_version, .data$version)
)

Expand Down
29 changes: 29 additions & 0 deletions tests/testthat/test-software-versions.R
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,32 @@ test_that("get_latest_versions() falls back to cache when remote lookup fails",
versions = suppressMessages(get_latest_versions(remote = TRUE))
expect_equal(versions, suppressMessages(get_latest_versions(remote = FALSE)))
})

test_that("Versions are compared as numbers, not text", {
expect_equal(
version_compare(c("1.10", "1.9", NA), c("1.9", "1.10", "1.9"), `>`),
c(TRUE, FALSE, NA)
)
expect_equal(max_version(c("1.9", "1.10", "1.3")), "1.10")
expect_equal(min_version(c("1.9", "1.10", "1.3")), "1.3")
})

augment_quarto = function(version) {
installed = tibble::tibble(software = "quarto", installed_version = version)
augmented = augment_installed(installed, remote = FALSE, verbose = FALSE)
augmented[augmented$installed_version %in% version, ]
}

test_that("Quarto versions outside the version list", {
# Older than the list: past EOL, so upgrade
old = augment_quarto("0.0.0")
expect_false(old$within_eol)
expect_true(old$upgrade)
expect_message(print_colour_version(old), "EOL has past")

# Newer than the list: the list is out of date, not past EOL
new = augment_quarto("99.99.1")
expect_true(new$within_eol)
expect_false(new$upgrade)
expect_message(print_colour_version(new), "newer than")
})
Loading