diff --git a/DESCRIPTION b/DESCRIPTION index ab34b5f..ad94618 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -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 diff --git a/NEWS.md b/NEWS.md index 4dc5641..908906d 100644 --- a/NEWS.md +++ b/NEWS.md @@ -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 diff --git a/R/software-versions.R b/R/software-versions.R index ef62dda..7039ef4 100644 --- a/R/software-versions.R +++ b/R/software-versions.R @@ -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." @@ -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 @@ -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") } @@ -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) ) diff --git a/tests/testthat/test-software-versions.R b/tests/testthat/test-software-versions.R index 5e06158..8fd0f3a 100644 --- a/tests/testthat/test-software-versions.R +++ b/tests/testthat/test-software-versions.R @@ -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") +})