fix(patches): validator portability, clearer docs, broader hook trigger
This commit is contained in:
parent
a826a27246
commit
f3f3bfa20d
1 changed files with 2428 additions and 8 deletions
123
.superpowers/handoff/task-A2-brief.md
Normal file
123
.superpowers/handoff/task-A2-brief.md
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
### Task A2: Platform matching and version-constraint satisfaction
|
||||
|
||||
**Files:**
|
||||
- Modify: `R/patches.R`
|
||||
- Test: `tests/testthat/test-patches.R`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: normalized entries from Task A1.
|
||||
- Produces: `build_platform_tokens(platform, arch)` → character vector; `entry_matches_platform(entry, tokens)` → logical; `match_patch_entries(registry, platform, arch)` → filtered list; `version_satisfies(version, constraint)` → logical (constraint forms: `"*"` handled by caller, `"x.y.z"` exact, `">=x"`, `"<=x"`, `">x"`, `"<x"`, `"==x"`).
|
||||
|
||||
- [ ] **Step 1: Write the failing test**
|
||||
|
||||
```r
|
||||
test_that("build_platform_tokens expands family and arch", {
|
||||
expect_setequal(
|
||||
build_platform_tokens("ubuntu-2604", "amd64"),
|
||||
c("ubuntu-2604", "ubuntu", "amd64")
|
||||
)
|
||||
expect_setequal(
|
||||
build_platform_tokens("alpine-324", "arm64"),
|
||||
c("alpine-324", "alpine", "arm64")
|
||||
)
|
||||
})
|
||||
|
||||
test_that("match_patch_entries matches family, codename, arch, and wildcard", {
|
||||
reg <- list(
|
||||
list(package = "A", versions = "*", platforms = "alpine", reason = "r"),
|
||||
list(package = "B", versions = "*", platforms = "ubuntu-2604", reason = "r"),
|
||||
list(package = "C", versions = "*", platforms = "*", reason = "r"),
|
||||
list(package = "D", versions = "*", platforms = "redhat", reason = "r")
|
||||
)
|
||||
got <- vapply(
|
||||
match_patch_entries(reg, "ubuntu-2604", "amd64"),
|
||||
function(e) e$package, character(1L)
|
||||
)
|
||||
expect_setequal(got, c("B", "C"))
|
||||
})
|
||||
|
||||
test_that("version_satisfies handles operators and hyphenated versions", {
|
||||
expect_true(version_satisfies("5.1.11-2", "5.1.11-2"))
|
||||
expect_true(version_satisfies("5.1.11-2", "==5.1.11-2"))
|
||||
expect_true(version_satisfies("5.1.12", ">=5.1.0"))
|
||||
expect_false(version_satisfies("5.0.0", ">=5.1.0"))
|
||||
expect_true(version_satisfies("5.1.11-2", "<=5.1.11-2"))
|
||||
expect_false(version_satisfies("5.1.12", "<=5.1.11-2"))
|
||||
})
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run test to verify it fails**
|
||||
|
||||
Run: `Rscript -e 'devtools::load_all("."); testthat::test_file("tests/testthat/test-patches.R")'`
|
||||
Expected: FAIL with "could not find function build_platform_tokens".
|
||||
|
||||
- [ ] **Step 3: Write minimal implementation (append to `R/patches.R`)**
|
||||
|
||||
```r
|
||||
#' Build platform tokens for patch matching
|
||||
#' @keywords internal
|
||||
build_platform_tokens <- function(platform, arch) {
|
||||
family <- sub("-.*$", "", platform)
|
||||
unique(c(platform, family, arch))
|
||||
}
|
||||
|
||||
#' Does a patch entry apply to the current platform tokens?
|
||||
#' @keywords internal
|
||||
entry_matches_platform <- function(entry, tokens) {
|
||||
any(entry$platforms == "*") ||
|
||||
length(intersect(entry$platforms, tokens)) > 0L
|
||||
}
|
||||
|
||||
#' Filter registry entries applicable to the current build
|
||||
#' @keywords internal
|
||||
match_patch_entries <- function(registry, platform, arch) {
|
||||
if (length(registry) == 0L) {
|
||||
return(list())
|
||||
}
|
||||
tokens <- build_platform_tokens(platform, arch)
|
||||
Filter(function(e) entry_matches_platform(e, tokens), registry)
|
||||
}
|
||||
|
||||
#' Test whether a version satisfies a single constraint
|
||||
#'
|
||||
#' @param version A version string (CRAN style, may contain `-`).
|
||||
#' @param constraint One of `"x.y.z"`, `"==x"`, `">=x"`, `"<=x"`, `">x"`, `"<x"`.
|
||||
#' @keywords internal
|
||||
version_satisfies <- function(version, constraint) {
|
||||
constraint <- trimws(constraint)
|
||||
parts <- regmatches(
|
||||
constraint,
|
||||
regexec("^(>=|<=|==|>|<)?\\s*(.+)$", constraint)
|
||||
)[[1L]]
|
||||
op <- parts[2L]
|
||||
target <- parts[3L]
|
||||
v <- package_version(version)
|
||||
t <- package_version(target)
|
||||
if (op == "" || op == "==") {
|
||||
return(v == t)
|
||||
}
|
||||
switch(
|
||||
op,
|
||||
">=" = v >= t,
|
||||
"<=" = v <= t,
|
||||
">" = v > t,
|
||||
"<" = v < t,
|
||||
FALSE
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Run test to verify it passes**
|
||||
|
||||
Run: `Rscript -e 'devtools::load_all("."); testthat::test_file("tests/testthat/test-patches.R")'`
|
||||
Expected: PASS.
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add R/patches.R tests/testthat/test-patches.R
|
||||
git commit -m "feat(patches): platform matching and version-constraint checks"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Loading…
Reference in a new issue