All checks were successful
ci/crow/manual/weekly-patch-proposals Pipeline was successful
ci/crow/cron/process-updates/5 Pipeline was successful
ci/crow/cron/process-updates/17 Pipeline was successful
ci/crow/cron/process-updates/1 Pipeline was successful
ci/crow/cron/process-updates/6 Pipeline was successful
ci/crow/cron/process-updates/7 Pipeline was successful
ci/crow/cron/process-updates/2 Pipeline was successful
ci/crow/cron/process-updates/8 Pipeline was successful
ci/crow/cron/process-updates/9 Pipeline was successful
ci/crow/cron/process-updates/3 Pipeline was successful
ci/crow/cron/process-updates/12 Pipeline was successful
## Problem The scheduled `--open-issue` run (issue #120) posted **800+** proposed entries, all `rcppparallel-bundled-tbb` on `ubuntu-2604`, each pre-filling `RcppParallel/disable-tbb.patch` for an unrelated package (`ACEsimFit`, `AovBay`, `AdaptGauss`, ...). Root cause: those packages fail on ubuntu-2604 only because their **RcppParallel dependency** does not build there. bincraft records RcppParallel's TBB error text against each dependent, so every one of them matches the `rcppparallel-bundled-tbb` signature. Proposing a RcppParallel source patch for `ACEsimFit` is not just noise -- it is **broken**: the diff targets RcppParallel's `Makevars.in`, so it cannot apply to a dependent's source. ## Fix Add an optional `applies_to` field that pins a package-specific fix to the package it targets: - A signature whose fix is a curated per-package source patch (`rcppparallel-bundled-tbb` -> `RcppParallel`) is only ever proposed **for that package**. - Other packages matching the signature are downstream failures, reported as **"blocked on `<dependency>`"** and never proposed a bogus entry. Fix the dependency once and the whole cascade clears. Generic levers (the `tbb-stddef-removed` makevars fix) are unaffected -- they carry no `applies_to`, so they still apply to any matching package. ## Changes - gate proposal generation in `build_triage_report()` on `applies_to`; add a `blocked_on` field to group records - surface blocked groups in both `failing-builds-report.R` and `propose-patches.R` instead of the misleading "already registered" note - document `applies_to` in the signature-table header ## Verification - New tests: RcppParallel dependents are blocked (no `proposed_entries`, `blocked_on = "RcppParallel"`), while RcppParallel *itself* is still proposed when it is the failing package. - Reproduced the avalanche end-to-end with a stubbed DB: 5 dependents now report "Blocked on RcppParallel: 5 package(s) fail because RcppParallel does not build" and **zero** candidates are emitted; a genuine `tbb-stddef` proposal in the same run is unaffected. - Full suite: 84 tests pass; all pre-commit hooks pass. Refs #120. Note: the underlying build problem (RcppParallel failing on ubuntu-2604 despite its registry entry) is real and separate -- this PR stops the classifier from spamming broken per-dependent proposals about it. Reviewed-on: #121
122 lines
4.5 KiB
R
122 lines
4.5 KiB
R
source(file.path("..", "failing-builds-classify.R"))
|
|
|
|
test_that("normalise_error collapses temp paths, versions, and package tokens", {
|
|
a <- normalise_error(
|
|
"In file /tmp/RtmpAb12/foo.c: RcppParallel 5.1.9 failed at 0xdeadbeef",
|
|
package = "RcppParallel"
|
|
)
|
|
expect_false(grepl("RtmpAb12", a))
|
|
expect_false(grepl("5\\.1\\.9", a))
|
|
expect_false(grepl("0xdeadbeef", a))
|
|
expect_true(grepl("<pkg>", a))
|
|
expect_true(grepl("<tmp>", a))
|
|
|
|
# Same root error across two versions collapses to one fingerprint.
|
|
e1 <- "StanHeaders 2.32.1: tbb/tbb_stddef.h: No such file or directory"
|
|
e2 <- "StanHeaders 2.33.0: tbb/tbb_stddef.h: No such file or directory"
|
|
expect_identical(
|
|
fingerprint_error(e1, "StanHeaders"),
|
|
fingerprint_error(e2, "StanHeaders")
|
|
)
|
|
})
|
|
|
|
test_that("normalise_error is safe on NA/empty input", {
|
|
expect_identical(normalise_error(NA_character_), "")
|
|
expect_identical(normalise_error(""), "")
|
|
expect_identical(fingerprint_error(NA_character_), "<empty>")
|
|
})
|
|
|
|
test_that("fingerprint_error picks the salient error line, not the last line", {
|
|
txt <- paste(
|
|
"* installing *source* package 'foo' ...",
|
|
"error: bar.h: No such file or directory",
|
|
"* removing '/tmp/lib/foo'",
|
|
sep = "\n"
|
|
)
|
|
fp <- fingerprint_error(txt, "foo")
|
|
expect_true(grepl("no such file", fp))
|
|
expect_false(grepl("removing", fp))
|
|
})
|
|
|
|
test_that("classify_error matches the removed TBB header signature (makevars, auto)", {
|
|
sig <- classify_error(
|
|
"fatal error: tbb/tbb_stddef.h: No such file or directory"
|
|
)
|
|
expect_identical(sig$id, "tbb-stddef-removed")
|
|
expect_identical(sig$tier, "makevars")
|
|
expect_true(sig$auto)
|
|
expect_true(sig$matched)
|
|
})
|
|
|
|
test_that("classify_error matches RcppParallel bundled-TBB failures", {
|
|
sig <- classify_error(
|
|
"Error: USE_TBB=Linux is not supported on this toolchain"
|
|
)
|
|
expect_identical(sig$id, "rcppparallel-bundled-tbb")
|
|
expect_identical(sig$tier, "patch")
|
|
expect_true(sig$auto)
|
|
})
|
|
|
|
test_that("system libuv link leak is classified but stays human-only (novel diff)", {
|
|
sig <- classify_error("cannot open shared object file: libuv.so.1")
|
|
expect_identical(sig$id, "system-libuv-link-leak")
|
|
expect_true(sig$matched)
|
|
expect_false(sig$auto)
|
|
})
|
|
|
|
test_that("unknown signatures are never guessed at", {
|
|
sig <- classify_error("segfault: memory not mapped at address")
|
|
expect_identical(sig$id, "unclassified")
|
|
expect_false(sig$matched)
|
|
expect_false(sig$auto)
|
|
expect_true(is.na(sig$tier))
|
|
})
|
|
|
|
test_that("propose_registry_entry fills a schema-valid entry for a known lever", {
|
|
sig <- classify_error("tbb/tbb_stddef.h: No such file")
|
|
json <- propose_registry_entry(sig, "StanHeaders", c("alpine", "ubuntu-2604"))
|
|
entry <- jsonlite::fromJSON(json, simplifyVector = FALSE)
|
|
expect_identical(entry$package, "StanHeaders")
|
|
expect_identical(entry$versions, "*")
|
|
expect_identical(entry$platforms, list("alpine", "ubuntu-2604"))
|
|
expect_identical(entry$makevars$CPPFLAGS, "-DTBB_INTERFACE_NEW")
|
|
expect_true(nzchar(entry$reason))
|
|
|
|
# No template -> no proposal (unclassified path).
|
|
expect_null(propose_registry_entry(classify_error("weird"), "x", "alpine"))
|
|
})
|
|
|
|
test_that("RcppParallel dependents are blocked, not proposed a per-package patch", {
|
|
# Hundreds of packages fail on ubuntu-2604 only because their RcppParallel
|
|
# dependency fails to build, so they carry RcppParallel's TBB error text.
|
|
failures <- data.frame(
|
|
name = c("ACEsimFit", "AovBay", "AdaptGauss"),
|
|
platform = "ubuntu-2604",
|
|
arch = "amd64",
|
|
error_text = "Error: USE_TBB=Linux is not supported on this toolchain",
|
|
stringsAsFactors = FALSE
|
|
)
|
|
report <- build_triage_report(failures, registered_pkgs = character(0L))
|
|
grp <- Filter(function(g) g$signature == "rcppparallel-bundled-tbb", report)[[
|
|
1L
|
|
]]
|
|
# No bogus per-dependent entries (the patch targets RcppParallel's source).
|
|
expect_null(grp$proposed_entries)
|
|
expect_identical(grp$blocked_on, "RcppParallel")
|
|
})
|
|
|
|
test_that("RcppParallel itself is still proposed when it is the failing package", {
|
|
failures <- data.frame(
|
|
name = "RcppParallel",
|
|
platform = "ubuntu-2604",
|
|
arch = "amd64",
|
|
error_text = "Error: USE_TBB=Linux is not supported on this toolchain",
|
|
stringsAsFactors = FALSE
|
|
)
|
|
report <- build_triage_report(failures, registered_pkgs = character(0L))
|
|
grp <- report[[1L]]
|
|
expect_identical(grp$signature, "rcppparallel-bundled-tbb")
|
|
expect_false(is.null(grp$proposed_entries))
|
|
expect_true("RcppParallel" %in% names(grp$proposed_entries))
|
|
expect_null(grp$blocked_on) # RcppParallel is the target, not a dependent
|
|
})
|