Skip to content

Commit

Permalink
Refactor the recording of package version/check issues
Browse files Browse the repository at this point in the history
  • Loading branch information
wlandau committed Mar 28, 2024
1 parent bd85d00 commit a95d837
Show file tree
Hide file tree
Showing 10 changed files with 218 additions and 50 deletions.
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ Package: multiverse.internals
Title: Internal Infrastructure for R-multiverse
Description: R-multiverse requires this internal internal infrastructure
package to automate contribution reviews and populate universes.
Version: 0.1.3
Version: 0.1.4
License: MIT + file LICENSE
URL: https://github.com/r-multiverse/multiverse.internals
BugReports: https://github.com/r-multiverse/multiverse.internals/issues
Expand Down
2 changes: 2 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export(assert_cran_url)
export(assert_package)
export(assert_release_exists)
export(get_current_versions)
export(record_issues)
export(record_versions)
export(review_pull_request)
export(review_pull_requests)
Expand All @@ -22,3 +23,4 @@ importFrom(utils,available.packages)
importFrom(utils,compareVersion)
importFrom(utils,contrib.url)
importFrom(vctrs,vec_rbind)
importFrom(vctrs,vec_slice)
5 changes: 5 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# multiverse.internals 0.1.4

* Do not write `version_issues.json` from `record_versions()`.
* Record version issues in separate JSON files in a new `record_issues()` function. Going forward, this function will also write R-universe check results in those individual package-specific files.

# multiverse.internals 0.1.3

* In `record_versions()`, left-join old versions into new versions to avoid spamming `versions.json` with an unbounded list of renamed or abandoned packages.
Expand Down
2 changes: 1 addition & 1 deletion R/package.R
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@
#' @importFrom nanonext ncurl parse_url status_code
#' @importFrom pkgsearch cran_package
#' @importFrom utils available.packages compareVersion contrib.url
#' @importFrom vctrs vec_rbind
#' @importFrom vctrs vec_rbind vec_slice
NULL
40 changes: 40 additions & 0 deletions R/record_issues.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#' @title Record package issues.
#' @export
#' @description Record package check and version issues in individual JSON
#' files.
#' @return `NULL` (invisibly).
#' @param manifest Character of length 1, file path to a JSON manifest
#' tracking release versions of packages.
#' @param output Character of length 1, file path to the folder to record
#' new package issues. Each call to `record_issues()` overwrites the
#' contents of the repo.
record_issues <- function(
manifest = "versions.json",
output = "issues"
) {
issues_version <- version_issues(manifest)
issues <- issues_version # Will include check issues too later.
overwrite_issues(issues, output)
invisible()
}

overwrite_issues <- function(issues, output) {
unlink(output, recursive = TRUE)
dir.create(output)
for (index in seq_len(nrow(issues))) {
row <- vctrs::vec_slice(x = issues, i = index)
jsonlite::write_json(row, file.path(output, row$package))
}
}

version_issues <- function(manifest) {
manifest <- jsonlite::read_json(path = manifest, simplifyVector = TRUE)
aligned <- (manifest$version_current == manifest$version_highest) &
(manifest$hash_current == manifest$hash_highest)
aligned[is.na(aligned)] <- TRUE
out <- manifest[!aligned,, drop = FALSE] # nolint
if (nrow(out)) {
out$version_okay <- FALSE
}
out
}
12 changes: 1 addition & 11 deletions R/record_versions.R
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,11 @@
#' @return `NULL` (invisibly). Writes a package version manifest
#' and a manifest of version issues as JSON files.
#' @param manifest Character of length 1, file path to the JSON manifest.
#' @param issues Character of length 1, file path to a JSON file
#' which records packages with version issues.
#' @param repo Character string of package repositories to track.
#' @param current A data frame of current versions and hashes of packages
#' in `repo`. This argument is exposed for testing only.
record_versions <- function(
manifest = "versions.json",
issues = "version_issues.json",
repo = "https://r-multiverse.r-universe.dev",
current = multiverse.internals::get_current_versions(repo = repo)
) {
Expand All @@ -28,11 +25,6 @@ record_versions <- function(
previous <- read_versions_previous(manifest = manifest)
new <- update_version_manifest(current = current, previous = previous)
jsonlite::write_json(x = new, path = manifest, pretty = TRUE)
aligned <- (new$version_current == new$version_highest) &
(new$hash_current == new$hash_highest)
aligned[is.na(aligned)] <- TRUE
new_issues <- new[!aligned,, drop = FALSE] # nolint
jsonlite::write_json(x = new_issues, path = issues, pretty = TRUE)
invisible()
}

Expand Down Expand Up @@ -63,9 +55,7 @@ get_current_versions <- function(
}

read_versions_previous <- function(manifest) {
out <- jsonlite::read_json(path = manifest)
out <- do.call(what = vctrs::vec_rbind, args = out)
out <- lapply(out, as.character)
out <- jsonlite::read_json(path = manifest, simplifyVector = TRUE)
if (is.null(out$version_highest)) {
out$version_highest <- out$version_current
}
Expand Down
23 changes: 23 additions & 0 deletions man/record_issues.Rd

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

4 changes: 0 additions & 4 deletions man/record_versions.Rd

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

142 changes: 142 additions & 0 deletions tests/testthat/test-record_issues.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
test_that("version_issues() in a mock repo", {
# Temporary files used in the mock test.
manifest <- tempfile()
# First update to the manifest.
contents <- data.frame(
package = c(
"package_unmodified",
"version_decremented",
"version_incremented",
"version_unmodified"
),
version_current = rep("1.0.0", 4L),
hash_current = rep("hash_1.0.0", 4L)
)
record_versions(manifest = manifest, current = contents)
expect_equal(
version_issues(manifest),
data.frame(
package = character(0L),
version_current = character(0L),
hash_current = character(0L)
)
)
# Update the manifest after no changes to packages or versions.
suppressMessages(
record_versions(manifest = manifest, current = contents)
)
expect_equal(
version_issues(manifest),
data.frame(
package = character(0L),
version_current = character(0L),
hash_current = character(0L),
version_highest = character(0L),
hash_highest = character(0L)
)
)
# Update the packages in all the ways indicated above.
index <- contents$package == "version_decremented"
contents$version_current[index] <- "0.0.1"
contents$hash_current[index] <- "hash_0.0.1"
index <- contents$package == "version_incremented"
contents$version_current[index] <- "2.0.0"
contents$hash_current[index] <- "hash_2.0.0"
index <- contents$package == "version_unmodified"
contents$version_current[index] <- "1.0.0"
contents$hash_current[index] <- "hash_1.0.0-modified"
for (index in seq_len(2L)) {
record_versions(
manifest = manifest,
current = contents
)
out <- version_issues(manifest)
rownames(out) <- NULL
expect_equal(
out,
data.frame(
package = c("version_decremented", "version_unmodified"),
version_current = c("0.0.1", "1.0.0"),
hash_current = c("hash_0.0.1", "hash_1.0.0-modified"),
version_highest = c("1.0.0", "1.0.0"),
hash_highest = c("hash_1.0.0", "hash_1.0.0"),
version_okay = c(FALSE, FALSE)
)
)
}
# Remove temporary files
unlink(manifest)
})

test_that("record_issues() in a mock repo", {
# Temporary files used in the mock test.
manifest <- tempfile()
output <- tempfile()
# First update to the manifest.
contents <- data.frame(
package = c(
"package_unmodified",
"version_decremented",
"version_incremented",
"version_unmodified"
),
version_current = rep("1.0.0", 4L),
hash_current = rep("hash_1.0.0", 4L)
)
record_versions(manifest = manifest, current = contents)
record_issues(manifest = manifest, output = output)
expect_equal(list.files(output), character(0L))
# Update the manifest after no changes to packages or versions.
suppressMessages(
record_versions(manifest = manifest, current = contents)
)
record_issues(manifest = manifest, output = output)
expect_equal(list.files(output), character(0L))
# Update the packages in all the ways indicated above.
index <- contents$package == "version_decremented"
contents$version_current[index] <- "0.0.1"
contents$hash_current[index] <- "hash_0.0.1"
index <- contents$package == "version_incremented"
contents$version_current[index] <- "2.0.0"
contents$hash_current[index] <- "hash_2.0.0"
index <- contents$package == "version_unmodified"
contents$version_current[index] <- "1.0.0"
contents$hash_current[index] <- "hash_1.0.0-modified"
for (index in seq_len(2L)) {
record_versions(
manifest = manifest,
current = contents
)
record_issues(manifest = manifest, output = output)
expect_equal(
sort(list.files(output)),
sort(c("version_decremented", "version_unmodified"))
)
out <- jsonlite::read_json(file.path(output, "version_decremented"))
expect_equal(
unlist(out, recursive = TRUE),
c(
package = "version_decremented",
version_current = "0.0.1",
hash_current = "hash_0.0.1",
version_highest = "1.0.0",
hash_highest = "hash_1.0.0",
version_okay = FALSE
)
)
out <- jsonlite::read_json(file.path(output, "version_unmodified"))
expect_equal(
unlist(out, recursive = TRUE),
c(
package = "version_unmodified",
version_current = "1.0.0",
hash_current = "hash_1.0.0-modified",
version_highest = "1.0.0",
hash_highest = "hash_1.0.0",
version_okay = FALSE
)
)
}
# Remove temporary files
unlink(manifest)
})
Loading

0 comments on commit a95d837

Please sign in to comment.