From c1fde8038674899dfd1cd86dac2d2f3f9812db64 Mon Sep 17 00:00:00 2001 From: mpadge Date: Wed, 13 Nov 2024 12:16:12 +0100 Subject: [PATCH] add 'cran_downloads' for #11 --- DESCRIPTION | 2 ++ R/chaoss-metrics-external.R | 27 +++++++++++++++++ R/utils.R | 7 +++++ codemeta.json | 30 +++++++++++++++++-- inst/httptest2/redact.R | 20 +++++++++++++ tests/testthat.R | 1 + .../cran_dl/cranlogs/goodpractice.json | 8 +++++ tests/testthat/test-chaoss-metrics-external.R | 11 +++++++ 8 files changed, 103 insertions(+), 3 deletions(-) create mode 100644 R/chaoss-metrics-external.R create mode 100644 inst/httptest2/redact.R create mode 100644 tests/testthat/cran_dl/cranlogs/goodpractice.json create mode 100644 tests/testthat/test-chaoss-metrics-external.R diff --git a/DESCRIPTION b/DESCRIPTION index 09526d8..3620594 100755 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -15,11 +15,13 @@ Imports: dplyr, fs, gert, + httr2, memoise, pbapply, pkgstats Suggests: brio, + httptest2, lubridate, quarto, testthat (>= 3.0.0), diff --git a/R/chaoss-metrics-external.R b/R/chaoss-metrics-external.R new file mode 100644 index 0000000..b6da335 --- /dev/null +++ b/R/chaoss-metrics-external.R @@ -0,0 +1,27 @@ +#' Extract total CRAN downloads for nominated package over period defined by +#' `options("githist_period")`. +#' +#' @param pkg_name Name of package. For packages not on CRAN, the 'cranlogs' +#' API returns download counts of 0. +#' @param end_date The date up to which download counts are to be aggregated. +#' @return A single integer counting the number of downloads. +#' @noRd +cran_downloads <- function (pkg_name, end_date = Sys.Date ()) { + + checkmate::assert_character (pkg_name, len = 1L) + checkmate::assert_date (end_date) + period <- get_githist_period () + start_date <- as.Date (end_date - period) + interval <- paste (start_date, sep = ":", end_date) + + base_url <- "http://cranlogs.r-pkg.org/" + daily_url <- paste0 (base_url, "downloads/total/") + req_url <- paste0 (daily_url, interval, "/", pkg_name) + + req <- httr2::request (req_url) + resp <- httr2::req_perform (req) + httr2::resp_check_status (resp) + + body <- httr2::resp_body_json (resp) + return (body [[1]]$downloads) +} diff --git a/R/utils.R b/R/utils.R index 55293da..bc79413 100644 --- a/R/utils.R +++ b/R/utils.R @@ -28,6 +28,13 @@ set_num_cores <- function (num_cores) { return (num_cores) } +pkg_name_from_path <- function (path) { + desc <- fs::dir_ls (path, type = "file", regexp = "DESCRIPTION$") + checkmate::assert_file_exists (desc) + + unname (read.dcf (desc) [, "Package"]) +} + filter_git_hist <- function (h, n, step_days) { if (!is.null (n)) { h <- h [seq_len (n), ] diff --git a/codemeta.json b/codemeta.json index e8fb676..05a10de 100644 --- a/codemeta.json +++ b/codemeta.json @@ -46,6 +46,18 @@ }, "sameAs": "https://CRAN.R-project.org/package=brio" }, + { + "@type": "SoftwareApplication", + "identifier": "httptest2", + "name": "httptest2", + "provider": { + "@id": "https://cran.r-project.org", + "@type": "Organization", + "name": "Comprehensive R Archive Network (CRAN)", + "url": "https://cran.r-project.org" + }, + "sameAs": "https://CRAN.R-project.org/package=httptest2" + }, { "@type": "SoftwareApplication", "identifier": "lubridate", @@ -170,6 +182,18 @@ "sameAs": "https://CRAN.R-project.org/package=gert" }, "6": { + "@type": "SoftwareApplication", + "identifier": "httr2", + "name": "httr2", + "provider": { + "@id": "https://cran.r-project.org", + "@type": "Organization", + "name": "Comprehensive R Archive Network (CRAN)", + "url": "https://cran.r-project.org" + }, + "sameAs": "https://CRAN.R-project.org/package=httr2" + }, + "7": { "@type": "SoftwareApplication", "identifier": "memoise", "name": "memoise", @@ -181,7 +205,7 @@ }, "sameAs": "https://CRAN.R-project.org/package=memoise" }, - "7": { + "8": { "@type": "SoftwareApplication", "identifier": "pbapply", "name": "pbapply", @@ -193,7 +217,7 @@ }, "sameAs": "https://CRAN.R-project.org/package=pbapply" }, - "8": { + "9": { "@type": "SoftwareApplication", "identifier": "pkgstats", "name": "pkgstats", @@ -201,7 +225,7 @@ }, "SystemRequirements": null }, - "fileSize": "88.964KB", + "fileSize": "90.739KB", "readme": "https://github.com/ropensci-review-tools/githist/blob/main/README.md", "contIntegration": ["https://github.com/ropensci-review-tools/githist/actions?query=workflow%3AR-CMD-check", "https://app.codecov.io/gh/ropensci-review-tools/githist"], "developmentStatus": "https://www.repostatus.org/#active" diff --git a/inst/httptest2/redact.R b/inst/httptest2/redact.R new file mode 100644 index 0000000..b83552b --- /dev/null +++ b/inst/httptest2/redact.R @@ -0,0 +1,20 @@ +function (resp) { + + resp <- httptest2::gsub_response ( + resp, + "http://cranlogs.r-pkg.org/downloads/total/", + "cranlogs/", + fixed = TRUE + ) + + # Timestamp pattern, where replacing with "" removes sub-dir: + ptn <- "[0-9]{4}\\-[0-9]{2}\\-[0-9]{2}" + resp <- httptest2::gsub_response ( + resp, + paste0 (ptn, "\\:", ptn), + "", + fixed = FALSE + ) + + return (resp) +} diff --git a/tests/testthat.R b/tests/testthat.R index 1e86f56..5beee00 100644 --- a/tests/testthat.R +++ b/tests/testthat.R @@ -7,6 +7,7 @@ # * https://testthat.r-lib.org/articles/special-files.html library (testthat) +library (httptest2) library (githist) test_check ("githist") diff --git a/tests/testthat/cran_dl/cranlogs/goodpractice.json b/tests/testthat/cran_dl/cranlogs/goodpractice.json new file mode 100644 index 0000000..5879939 --- /dev/null +++ b/tests/testthat/cran_dl/cranlogs/goodpractice.json @@ -0,0 +1,8 @@ +[ + { + "start": "2023-10-03", + "end": "2024-01-01", + "downloads": 2308, + "package": "goodpractice" + } +] diff --git a/tests/testthat/test-chaoss-metrics-external.R b/tests/testthat/test-chaoss-metrics-external.R new file mode 100644 index 0000000..3489b35 --- /dev/null +++ b/tests/testthat/test-chaoss-metrics-external.R @@ -0,0 +1,11 @@ +test_that ("chaoss external cran_downloads", { + + pkg_name <- "goodpractice" + end_date <- as.Date ("2024-01-01") + dl <- with_mock_dir ("cran_dl", { + cran_downloads (pkg_name = pkg_name, end_date = end_date) + }) + expect_type (dl, "integer") + expect_length (dl, 1L) + expect_equal (dl, 2308) +})