From b9b60767d12ceee22b8b747a55c99ac1c605e64b Mon Sep 17 00:00:00 2001 From: ChrisRackauckas-Claude Date: Tue, 23 Jun 2026 09:09:30 -0400 Subject: [PATCH 1/2] grouped-tests: QA group defaults to Julia v1 only MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QA (Aqua/JET/ExplicitImports) is version-agnostic, so running it once per declared version just multiplies the job count with no added signal — and the lts half is exactly where the <1.11 [sources]-backport QA failures bite. Clamp the QA group to ["1"] centrally in the matrix generator (root-matrix + sublibrary modes) so every grouped-tests@v1 consumer gets it without trimming [QA] versions in each test_groups.toml. For a 56-sublib monorepo like OrdinaryDiffEq this drops ~50 redundant QA jobs. Verified locally: a fixture with [QA] versions=["lts","1"] now emits QA only on version 1 in both --root-matrix and --projects-matrix, while Core (["lts","1","pre"]) and GPU are unchanged. Co-Authored-By: Chris Rackauckas Co-Authored-By: Claude Opus 4.8 (1M context) --- scripts/compute_affected_sublibraries.jl | 25 ++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/scripts/compute_affected_sublibraries.jl b/scripts/compute_affected_sublibraries.jl index 7fb18dc..90a00b1 100644 --- a/scripts/compute_affected_sublibraries.jl +++ b/scripts/compute_affected_sublibraries.jl @@ -14,7 +14,10 @@ # versions = ["lts", "1", "pre"] # # [QA] -# versions = ["lts", "1"] +# versions = ["lts", "1"] # NOTE: ignored — QA always runs once on "1". +# # Aqua/JET/ExplicitImports are version-agnostic, so +# # the QA group is centrally clamped to ["1"] (see +# # QA_VERSIONS); no need to trim this per repo. # # [GPU] # versions = ["1"] @@ -39,7 +42,7 @@ # # If no test/test_groups.toml exists, the default is: # Core on ["lts", "1", "pre"] -# QA on ["lts", "1"] +# QA on ["1"] # # A group that needs test-only deps beyond the sublibrary's [targets].test list should # carry an isolated environment at test//Project.toml that runtests.jl activates @@ -76,7 +79,7 @@ using TOML const DEFAULT_TEST_GROUPS = Dict( "Core" => ["lts", "1", "pre"], - "QA" => ["lts", "1"], + "QA" => ["1"], ) function build_dependency_graph(lib_dir::String) @@ -241,6 +244,13 @@ const EXCLUDES = Set( const DOWNSTREAM_VERSION = "1" +# QA (Aqua/JET/ExplicitImports) is version-agnostic, so running it per declared +# version just doubles the job count with no added signal — and the lts half is +# where the <1.11 [sources]-backport QA failures bite. Central policy: the QA +# group always runs once, on the latest stable, regardless of the per-repo +# [QA] versions. Repos therefore needn't trim [QA] versions in test_groups.toml. +const QA_VERSIONS = ["1"] + function build_matrix( direct::Set{String}, transitive::Set{String}, lib_dir::String ) @@ -255,7 +265,8 @@ function build_matrix( is_downstream && config.local_only && continue ci_group = group_name == "Core" ? pkg : "$(pkg)_$(group_name)" # Downstream (transitive) deps only run on latest stable. - versions = is_downstream ? [DOWNSTREAM_VERSION] : config.versions + versions = group_name == "QA" ? QA_VERSIONS : + is_downstream ? [DOWNSTREAM_VERSION] : config.versions for ver in versions (ci_group, ver) in EXCLUDES && continue push!( @@ -313,7 +324,8 @@ function build_projects_matrix( config = groups[group_name] is_downstream && config.local_only && continue ci_group = group_name == "Core" ? pkg : "$(pkg)_$(group_name)" - versions = is_downstream ? [DOWNSTREAM_VERSION] : config.versions + versions = group_name == "QA" ? QA_VERSIONS : + is_downstream ? [DOWNSTREAM_VERSION] : config.versions for ver in versions (ci_group, ver) in EXCLUDES && continue push!( @@ -370,7 +382,8 @@ function build_root_matrix(repo_root::String) for group_name in sort!(collect(keys(groups))) config = groups[group_name] runners = isempty(config.os) ? Any[config.runner] : Any[o for o in config.os] - for ver in config.versions + vers = group_name == "QA" ? QA_VERSIONS : config.versions + for ver in vers for runner in runners push!( entries, From aeee3286d46bdc79bb055aeccffd9f7ca60acd15 Mon Sep 17 00:00:00 2001 From: ChrisRackauckas-Claude Date: Wed, 24 Jun 2026 08:25:11 -0400 Subject: [PATCH 2/2] =?UTF-8?q?test:=20update=20matrix=20assertions=20for?= =?UTF-8?q?=20QA=E2=86=92v1=20default?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QA now defaults to Julia v1 only (clamped centrally in the matrix generator), so the .github test suite's expected matrices drop the (QA, lts) cells: projects-matrix default groups, the build_root_matrix excludes test, and the OrdinaryDiffEq-reproduction test (now 45 cells, not 46). Co-Authored-By: Chris Rackauckas Co-Authored-By: Claude Opus 4.8 (1M context) --- test/runtests.jl | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index 444566f..586cfe6 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -82,10 +82,10 @@ end @testset "projects-matrix: default groups + downstream→v1" begin direct, trans = compute_affected(["lib/A/src/A.jl"], graph, rev) m = build_projects_matrix(direct, trans, lib) - # A is directly changed: default Core on lts,1,pre + QA on lts,1 + # A is directly changed: default Core on lts,1,pre + QA on 1 (QA defaults to v1 only) a = filter(e -> e.project == "lib/A", m) @test Set((e.group, e.version) for e in a) == - Set([("Core", "lts"), ("Core", "1"), ("Core", "pre"), ("QA", "lts"), ("QA", "1")]) + Set([("Core", "lts"), ("Core", "1"), ("Core", "pre"), ("QA", "1")]) # B and C are downstream: version "1" only for p in ("lib/B", "lib/C") ds = filter(e -> e.project == p, m) @@ -210,7 +210,8 @@ end m = build_root_matrix(d) cells = Set((e.group, e.version) for e in m) @test ("AD", "1") ∉ cells && ("AD", "pre") ∉ cells && ("AD", "lts") in cells - @test ("QA", "pre") ∉ cells && ("QA", "lts") in cells && ("QA", "1") in cells + # QA is centrally clamped to v1 only, regardless of the per-group `versions`. + @test ("QA", "pre") ∉ cells && ("QA", "lts") ∉ cells && ("QA", "1") in cells # continue_on_error rides only on the Downstream group. @test all(e -> e.continue_on_error, filter(e -> e.group == "Downstream", m)) @test all(e -> !e.continue_on_error, filter(e -> e.group != "Downstream", m)) @@ -252,8 +253,8 @@ end @testset "root matrix faithfully reproduces OrdinaryDiffEq's embedded matrix" begin # ODE's root CI.yml is 17 groups × [lts,1,pre] minus excludes (AD->lts only, - # QA->lts/1, ODEInterfaceRegression->lts only). Per-group `versions` - # expresses the same 46 cells, which is the migration this enables. + # ODEInterfaceRegression->lts only). QA is centrally clamped to v1 only (see + # QA_VERSIONS), so it intentionally diverges from ODE's old QA-on-lts/1: 45 cells. base = [ "InterfaceI", "InterfaceII", "InterfaceIII", "InterfaceIV", "InterfaceV", "Integrators_I", "Integrators_II", "AlgConvergence_I", "AlgConvergence_II", @@ -273,11 +274,11 @@ end cells = Set((e.group, e.version) for e in build_root_matrix(d)) groups17 = vcat(base, ["AD", "QA", "ODEInterfaceRegression"]) expected = Set((g, v) for g in groups17 for v in ["lts", "1", "pre"]) - for ex in [("AD", "1"), ("AD", "pre"), ("QA", "pre"), ("ODEInterfaceRegression", "1"), ("ODEInterfaceRegression", "pre")] + for ex in [("AD", "1"), ("AD", "pre"), ("QA", "pre"), ("QA", "lts"), ("ODEInterfaceRegression", "1"), ("ODEInterfaceRegression", "pre")] delete!(expected, ex) end @test cells == expected - @test length(cells) == 46 + @test length(cells) == 45 end @testset "--root-matrix CLI (no lib/ required) + JSON shape" begin