From c5f134865b6cf8d7c721b15e7007d4f91dd817b1 Mon Sep 17 00:00:00 2001 From: LusterSourav <282348889+LusterSourav@users.noreply.github.com> Date: Sun, 2 Aug 2026 19:29:24 +0530 Subject: [PATCH 01/11] add detection --- ci/detect-changes.py | 119 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 ci/detect-changes.py diff --git a/ci/detect-changes.py b/ci/detect-changes.py new file mode 100644 index 000000000000..1df7503a48d0 --- /dev/null +++ b/ci/detect-changes.py @@ -0,0 +1,119 @@ +#!/usr/bin/env python3 +"""decides which ci groups a pull request touches. +tier1 jobs read the result and skip platforms a diff doesnt affect""" + +import argparse +import fnmatch +import json +import os +import subprocess as sp +import sys +from pathlib import Path +from typing import List, Optional, Sequence + +# everything under these runs on all platforms +CORE_PATHS = [ + "src/lib.rs", "src/types.rs", "src/macros.rs", "src/primitives.rs", "src/unix/mod.rs", + "build.rs", "Cargo.toml", "Cargo.lock", + "ci/**", ".github/**", + "ctest/**", "ctest-test/**", "libc-test/**", "semver/**", "etc/**", +] + +#platform groups, matched against the changed files +GROUPS = { + "core": CORE_PATHS, + "apple": ["src/unix/bsd/apple/**", "src/unix/bsd/freebsdlike/**", "src/unix/bsd/mod.rs"], + "linux_gnu": ["src/unix/linux_like/**"], + "windows_msvc": ["src/windows/msvc/**", "src/windows/mod.rs"], + "windows_gnu": ["src/windows/gnu/**", "src/windows/mod.rs"], +} + +# docs and metadata files dont need a test run +DOCS_ONLY = ["README.md", "CHANGELOG.md", "CONTRIBUTING.md", "LICENSE*", "triagebot.toml"] + + +def classify(paths: Sequence[str]) -> List[str]: + if all(any(p.startswith(pat[:-3]) if pat.endswith("/**") else fnmatch.fnmatch(p, pat) for pat in DOCS_ONLY) for p in paths): + return [] + hit = set() + for p in paths: + for g, pats in GROUPS.items(): + if any(p.startswith(pat[:-3]) if pat.endswith("/**") else fnmatch.fnmatch(p, pat) for pat in pats): + hit.add(g) + # nothing matched, run all rather than skip something that matters + if not hit: + return sorted(GROUPS) + # print(hit) # debug + return sorted(hit) + + +def diff_names(base: str, head: str) -> List[str]: + try: + out = sp.run(["git", "diff", "--name-only", f"{base}...{head}"], capture_output=True, text=True, check=True) + except sp.CalledProcessError as err: + sys.exit(f"git diff failed for {base}..{head}, {err}") + return out.stdout.splitlines() + + +def changed_paths() -> Optional[List[str]]: + #local runs have no event file, nothing to classify + event_path = os.environ.get("GITHUB_EVENT_PATH") + if not event_path: + return None + try: + ev = json.loads(Path(event_path).read_text()) + except (OSError, ValueError) as err: + sys.exit(f"cannot read event file {event_path}, {err}") + pr = ev.get("pull_request") + mq = ev.get("merge_group") + if pr: + return diff_names(pr["base"]["sha"], "HEAD") + if mq: + return diff_names(mq["base_sha"], mq["head_sha"]) + #schedule and dispatch carry no diff, run everything + return None + + +def sanity() -> None: + cases = [ + (["src/unix/bsd/apple/x.rs"], ["apple"]), + (["src/unix/bsd/freebsdlike/x.rs"], ["apple"]), + (["src/unix/bsd/mod.rs"], ["apple"]), + (["src/unix/linux_like/linux/gnu/x.rs"], ["linux_gnu"]), + (["src/windows/msvc/x.rs"], ['windows_msvc']), + (["src/windows/gnu/x.rs"], ["windows_gnu"]), + (["src/windows/mod.rs"], ["windows_gnu", "windows_msvc"]), + (["Cargo.toml"], ["core"]), + (["ci/run.sh"], ["core"]), + (["src/types.rs"], ["core"]), + (["README.md"], []), + #newlib has no tier1 target, so the fail-safe runs everything + (["src/newlib/mod.rs"], sorted(GROUPS)), + (["README.md", "src/newlib/mod.rs"], sorted(GROUPS)), + ] + for paths, want in cases: + got = classify(paths) + assert got == want, f"expected {want} got {got} for {paths}" + print("all good") + + +def main() -> None: + p = argparse.ArgumentParser() + p.add_argument("--files", nargs="+", help="git paths to classify") + p.add_argument("--sanity", action="store_true") + args = p.parse_args() + if args.sanity: + sanity() + return + paths = args.files if args.files else changed_paths() + groups = list(GROUPS) if paths is None else classify(paths) + print(f"changed files {json.dumps(paths)}") + print(f"groups {json.dumps(groups)}") + out_path = os.environ.get("GITHUB_OUTPUT") + if out_path: + with open(out_path, "a") as out: + out.write(f"changes={json.dumps(groups)}\n") + + +if __name__ == "__main__": + main() From b008da67ac1f6647d5ba975eac5f9a645e0970bd Mon Sep 17 00:00:00 2001 From: LusterSourav <282348889+LusterSourav@users.noreply.github.com> Date: Sun, 2 Aug 2026 19:29:24 +0530 Subject: [PATCH 02/11] skip untouched tier1 jobs --- .github/workflows/ci.yaml | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 44dea0567271..8e5728c81da1 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -127,27 +127,55 @@ jobs: - name: Target size after job completion run: du -sh target | sort -k 2 + # which platforms a diff touches, tier1 jobs gate on this + changes: + name: Detect changed groups + runs-on: ubuntu-26.04 + timeout-minutes: 5 + outputs: + changes: ${{ steps.detect.outputs.changes }} + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + fetch-depth: 0 # full history so the base commit exists for the diff + - name: Compute affected groups + id: detect + run: python3 ci/detect-changes.py + test_tier1: name: Test tier1 + needs: changes + # run only if this target's group was touched, skipped jobs pass the gate + if: contains(fromJSON(needs.changes.outputs.changes), matrix.group) strategy: matrix: include: - target: aarch64-apple-darwin + group: apple os: macos-26 - target: aarch64-pc-windows-msvc + group: windows_msvc os: windows-11-arm - target: aarch64-unknown-linux-gnu + group: linux_gnu os: ubuntu-26.04-arm - target: i686-pc-windows-gnu + group: windows_gnu os: windows-2025 - target: i686-pc-windows-msvc + group: windows_msvc os: windows-2025 - target: i686-unknown-linux-gnu + group: linux_gnu - target: x86_64-pc-windows-gnu + group: windows_gnu os: windows-2025 - target: x86_64-pc-windows-msvc + group: windows_msvc os: windows-2025 - target: x86_64-unknown-linux-gnu + group: linux_gnu runs-on: ${{ matrix.os && matrix.os || 'ubuntu-26.04' }} timeout-minutes: 25 env: @@ -420,6 +448,7 @@ jobs: name: success runs-on: ubuntu-26.04 needs: + - changes - style_check - test_tier1 - test_tier2 @@ -438,4 +467,4 @@ jobs: steps: # Manually check the status of all dependencies. `if: failure()` does not work. - name: check if any dependency failed - run: jq --exit-status 'all(.result == "success")' <<< "$NEEDS" + run: jq --exit-status 'all(.result == "success" or .result == "skipped")' <<< "$NEEDS" From 98e5a6cf8e1e43d3d81164155803b756f0d56365 Mon Sep 17 00:00:00 2001 From: LusterSourav <282348889+LusterSourav@users.noreply.github.com> Date: Sun, 2 Aug 2026 19:58:15 +0530 Subject: [PATCH 03/11] gate tier1 steps --- .github/workflows/ci.yaml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 8e5728c81da1..86a8d43223eb 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -146,8 +146,7 @@ jobs: test_tier1: name: Test tier1 needs: changes - # run only if this target's group was touched, skipped jobs pass the gate - if: contains(fromJSON(needs.changes.outputs.changes), matrix.group) + # untouched groups skip every step, the success gate passes on skipped strategy: matrix: include: @@ -182,11 +181,14 @@ jobs: TARGET: ${{ matrix.target }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + if: contains(fromJSON(needs.changes.outputs.changes), matrix.group) with: persist-credentials: false - name: Setup Rust toolchain + if: contains(fromJSON(needs.changes.outputs.changes), matrix.group) run: ./ci/install-rust.sh - uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2 + if: contains(fromJSON(needs.changes.outputs.changes), matrix.group) with: key: ${{ matrix.target }} @@ -198,15 +200,15 @@ jobs: shell: bash - name: Run natively - if: runner.os != 'Linux' + if: contains(fromJSON(needs.changes.outputs.changes), matrix.group) && runner.os != 'Linux' run: ./ci/run.sh ${{ matrix.target }} - name: Run in Docker - if: runner.os == 'Linux' + if: contains(fromJSON(needs.changes.outputs.changes), matrix.group) && runner.os == 'Linux' run: ./ci/run-docker.sh ${{ matrix.target }} - name: Create CI artifacts id: create_artifacts - if: always() + if: always() && contains(fromJSON(needs.changes.outputs.changes), matrix.group) run: echo "step is actually running" && python3 ci/create-artifacts.py - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 if: always() && steps.create_artifacts.outcome == 'success' From a48aa5194449b5e6f5aaccc860f22e90826b146f Mon Sep 17 00:00:00 2001 From: LusterSourav <282348889+LusterSourav@users.noreply.github.com> Date: Tue, 4 Aug 2026 18:47:22 +0530 Subject: [PATCH 04/11] tidy detect-changes.py --- ci/detect-changes.py | 165 +++++++++++++++++++++---------------------- 1 file changed, 82 insertions(+), 83 deletions(-) diff --git a/ci/detect-changes.py b/ci/detect-changes.py index 1df7503a48d0..30a15a82326f 100644 --- a/ci/detect-changes.py +++ b/ci/detect-changes.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -"""decides which ci groups a pull request touches. -tier1 jobs read the result and skip platforms a diff doesnt affect""" +# tier1 tests skip platforms the diff doesnt touch, this decides which ones run import argparse import fnmatch @@ -9,111 +8,111 @@ import subprocess as sp import sys from pathlib import Path -from typing import List, Optional, Sequence - -# everything under these runs on all platforms -CORE_PATHS = [ - "src/lib.rs", "src/types.rs", "src/macros.rs", "src/primitives.rs", "src/unix/mod.rs", - "build.rs", "Cargo.toml", "Cargo.lock", - "ci/**", ".github/**", - "ctest/**", "ctest-test/**", "libc-test/**", "semver/**", "etc/**", + +#touching any of these runs everything +CORE = [ + "src/lib.rs", "src/types.rs", "src/macros.rs", "src/primitives.rs", + "src/unix/mod.rs","build.rs","Cargo.toml", "Cargo.lock" ,"ci/**", + ".github/**" , "ctest/**" , "ctest-test/**" ,"libc-test/**" ,"semver/**" , + "etc/**" , ] -#platform groups, matched against the changed files -GROUPS = { - "core": CORE_PATHS, - "apple": ["src/unix/bsd/apple/**", "src/unix/bsd/freebsdlike/**", "src/unix/bsd/mod.rs"], - "linux_gnu": ["src/unix/linux_like/**"], - "windows_msvc": ["src/windows/msvc/**", "src/windows/mod.rs"], +GROUPS={ + "core": CORE, + "apple": ["src/unix/bsd/apple/**", "src/unix/bsd/freebsdlike/**", "src/unix/bsd/mod.rs" ], + "linux_gnu":["src/unix/linux_like/**"], + "windows_msvc":["src/windows/msvc/**", "src/windows/mod.rs"] , "windows_gnu": ["src/windows/gnu/**", "src/windows/mod.rs"], } -# docs and metadata files dont need a test run -DOCS_ONLY = ["README.md", "CHANGELOG.md", "CONTRIBUTING.md", "LICENSE*", "triagebot.toml"] -def classify(paths: Sequence[str]) -> List[str]: - if all(any(p.startswith(pat[:-3]) if pat.endswith("/**") else fnmatch.fnmatch(p, pat) for pat in DOCS_ONLY) for p in paths): +# docs/metadata, nothing compiles from them +DOCS=["README.md","CHANGELOG.md", "CONTRIBUTING.md","LICENSE*", "triagebot.toml"] + + +def match (p,pat ) : + #/** is just a prefix match here + return p.startswith(pat[:-3]) if pat.endswith("/**") else fnmatch.fnmatch(p, pat) + + +def groups_for( files): + + if all (any ( match (p,pat) for pat in DOCS ) for p in files) : return [] - hit = set() - for p in paths: - for g, pats in GROUPS.items(): - if any(p.startswith(pat[:-3]) if pat.endswith("/**") else fnmatch.fnmatch(p, pat) for pat in pats): - hit.add(g) - # nothing matched, run all rather than skip something that matters - if not hit: - return sorted(GROUPS) - # print(hit) # debug - return sorted(hit) - - -def diff_names(base: str, head: str) -> List[str]: - try: - out = sp.run(["git", "diff", "--name-only", f"{base}...{head}"], capture_output=True, text=True, check=True) - except sp.CalledProcessError as err: - sys.exit(f"git diff failed for {base}..{head}, {err}") - return out.stdout.splitlines() + hit = {g for p in files for g, pats in GROUPS.items() if any(match(p, x) for x in pats)} + # no match, run everything rather than miss something + return sorted(GROUPS) if not hit else sorted(hit) + +def changed(): -def changed_paths() -> Optional[List[str]]: - #local runs have no event file, nothing to classify - event_path = os.environ.get("GITHUB_EVENT_PATH") - if not event_path: + + #no event file when run locally, nothing to classify + event = os.environ.get ( "GITHUB_EVENT_PATH" ) + if not event: return None try: - ev = json.loads(Path(event_path).read_text()) - except (OSError, ValueError) as err: - sys.exit(f"cannot read event file {event_path}, {err}") - pr = ev.get("pull_request") - mq = ev.get("merge_group") + ev=json.loads (Path (event ).read_text() ) + except ( OSError ,ValueError ) as err : + sys.exit(f"cannot read event file {event}, {err}") + + pr,mq =ev.get("pull_request" ) , ev.get( "merge_group" ) if pr: - return diff_names(pr["base"]["sha"], "HEAD") - if mq: - return diff_names(mq["base_sha"], mq["head_sha"]) - #schedule and dispatch carry no diff, run everything - return None + base, head = pr["base"]["sha"], "HEAD" + elif mq: + base, head= mq[ "base_sha" ],mq [ "head_sha" ] + else: # schedule/dispatch, run everything + return None + try: + out = sp.run(["git", "diff", "--name-only", f"{base}...{head}"], + capture_output =True,text= True , check=True) + except sp.CalledProcessError as err: + sys.exit(f"git diff failed for {base}..{head}, {err}") + + return out.stdout.splitlines() -def sanity() -> None: - cases = [ - (["src/unix/bsd/apple/x.rs"], ["apple"]), - (["src/unix/bsd/freebsdlike/x.rs"], ["apple"]), +def sanity(): + cases=[ + ( [ "src/unix/bsd/apple/x.rs"], [ "apple"]) , + ( ["src/unix/bsd/freebsdlike/x.rs" ], ["apple"] ), (["src/unix/bsd/mod.rs"], ["apple"]), - (["src/unix/linux_like/linux/gnu/x.rs"], ["linux_gnu"]), - (["src/windows/msvc/x.rs"], ['windows_msvc']), + (["src/unix/linux_like/linux/gnu/x.rs"] , [ "linux_gnu"] ) , + ( [ "src/windows/msvc/x.rs"], [ "windows_msvc"]), (["src/windows/gnu/x.rs"], ["windows_gnu"]), - (["src/windows/mod.rs"], ["windows_gnu", "windows_msvc"]), - (["Cargo.toml"], ["core"]), - (["ci/run.sh"], ["core"]), + ( [ "src/windows/mod.rs" ] ,[ "windows_gnu","windows_msvc" ]), + ( [ "Cargo.toml" ], ["core" ]), + ( ["ci/run.sh"] , [ "core" ] ), (["src/types.rs"], ["core"]), (["README.md"], []), - #newlib has no tier1 target, so the fail-safe runs everything - (["src/newlib/mod.rs"], sorted(GROUPS)), - (["README.md", "src/newlib/mod.rs"], sorted(GROUPS)), + #newlib has no tier1 target, the fail-safe kicks in + ( [ "src/newlib/mod.rs" ] ,sorted (GROUPS ) ), + ( [ "README.md","src/newlib/mod.rs" ],sorted(GROUPS)) , ] - for paths, want in cases: - got = classify(paths) - assert got == want, f"expected {want} got {got} for {paths}" - print("all good") + for files,want in cases : + got = groups_for (files ) + assert got == want, f"expected {want} got {got} for {files}" + print( "all good") -def main() -> None: +def main () : p = argparse.ArgumentParser() - p.add_argument("--files", nargs="+", help="git paths to classify") + p.add_argument( "--files",nargs= "+",help = "git paths to classify" ) p.add_argument("--sanity", action="store_true") - args = p.parse_args() + args=p.parse_args() if args.sanity: sanity() return - paths = args.files if args.files else changed_paths() - groups = list(GROUPS) if paths is None else classify(paths) - print(f"changed files {json.dumps(paths)}") - print(f"groups {json.dumps(groups)}") - out_path = os.environ.get("GITHUB_OUTPUT") - if out_path: - with open(out_path, "a") as out: - out.write(f"changes={json.dumps(groups)}\n") - - -if __name__ == "__main__": - main() + files = args.files if args.files else changed () + groups= list( GROUPS ) if files is None else groups_for ( files ) + print(json.dumps( groups ) ) + out=os.environ.get ("GITHUB_OUTPUT" ) + if out : + + with open (out,"a")as f: + f.write(f"changes={json.dumps(groups)}\n") + + +if __name__ =="__main__" : + main () From f90ab7fa016e0dbdc8c4bf564d3c64df75cc17cc Mon Sep 17 00:00:00 2001 From: LusterSourav <282348889+LusterSourav@users.noreply.github.com> Date: Tue, 4 Aug 2026 18:47:36 +0530 Subject: [PATCH 05/11] reword ci comments --- .github/workflows/ci.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 86a8d43223eb..24c7c74bb7e6 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -127,7 +127,7 @@ jobs: - name: Target size after job completion run: du -sh target | sort -k 2 - # which platforms a diff touches, tier1 jobs gate on this + # groups the diff touches, tier1 skips the rest changes: name: Detect changed groups runs-on: ubuntu-26.04 @@ -138,7 +138,7 @@ jobs: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false - fetch-depth: 0 # full history so the base commit exists for the diff + fetch-depth: 0 # need full history so the base sha exists for the diff - name: Compute affected groups id: detect run: python3 ci/detect-changes.py @@ -146,7 +146,7 @@ jobs: test_tier1: name: Test tier1 needs: changes - # untouched groups skip every step, the success gate passes on skipped + # untouched groups spawn but every step is skipped, success gate passes those strategy: matrix: include: From 1f03ab5ee158f571cb2d2d7f517a4e789d2c07d2 Mon Sep 17 00:00:00 2001 From: LusterSourav <282348889+LusterSourav@users.noreply.github.com> Date: Wed, 5 Aug 2026 00:19:37 +0530 Subject: [PATCH 06/11] generate tier matrices in python --- ci/detect-changes.py | 232 ++++++++++++++++++++++++++++--------------- 1 file changed, 154 insertions(+), 78 deletions(-) diff --git a/ci/detect-changes.py b/ci/detect-changes.py index 30a15a82326f..02ae9c4ca6ff 100644 --- a/ci/detect-changes.py +++ b/ci/detect-changes.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# tier1 tests skip platforms the diff doesnt touch, this decides which ones run +# computes the ci matrices, merge queues and schedules get every platform import argparse import fnmatch @@ -9,110 +9,186 @@ import sys from pathlib import Path -#touching any of these runs everything -CORE = [ - "src/lib.rs", "src/types.rs", "src/macros.rs", "src/primitives.rs", - "src/unix/mod.rs","build.rs","Cargo.toml", "Cargo.lock" ,"ci/**", - ".github/**" , "ctest/**" , "ctest-test/**" ,"libc-test/**" ,"semver/**" , - "etc/**" , -] - -GROUPS={ - "core": CORE, - "apple": ["src/unix/bsd/apple/**", "src/unix/bsd/freebsdlike/**", "src/unix/bsd/mod.rs" ], - "linux_gnu":["src/unix/linux_like/**"], - "windows_msvc":["src/windows/msvc/**", "src/windows/mod.rs"] , - "windows_gnu": ["src/windows/gnu/**", "src/windows/mod.rs"], +# the diff gets sorted into these, one group per platform family +PLATFORMS = { + "apple": ["src/unix/bsd/apple/**", "src/unix/bsd/freebsdlike/**", "src/unix/bsd/mod.rs"], + "bsd": ["src/unix/bsd/netbsdlike/**" ,"src/unix/bsd/freebsdlike/**","src/unix/bsd/mod.rs" ] , + "linux" :["src/unix/linux_like/**" ], + "windows_msvc": ["src/windows/msvc/**" , "src/windows/mod.rs" ], + "windows_gnu":["src/windows/gnu/**", "src/windows/mod.rs" ], + "wasm": ["src/wasi/**"], + "solarish" :["src/unix/solarish/**" ] , } +GROUPS = sorted ( PLATFORMS) # docs/metadata, nothing compiles from them -DOCS=["README.md","CHANGELOG.md", "CONTRIBUTING.md","LICENSE*", "triagebot.toml"] +DOCS= ["README.md" ,"CHANGELOG.md" ,"CONTRIBUTING.md", "LICENSE*" , "triagebot.toml" ] + +# one row per entry in the workflow matrix, group decides when it runs +# a missing os means ubuntu-26.04, except tier2_vm which runs on ubuntu-latest +TIER1 = [ + {"group" : "apple" ,"target":"aarch64-apple-darwin" ,"os":"macos-26" } , + { "group": "windows_msvc" ,"target": "aarch64-pc-windows-msvc", "os": "windows-11-arm" }, + {"group": "linux", "target": "aarch64-unknown-linux-gnu", "os": "ubuntu-26.04-arm"}, + {"group" : "windows_gnu" , "target": "i686-pc-windows-gnu","os":"windows-2025" } , + { "group":"windows_msvc","target":"i686-pc-windows-msvc","os" : "windows-2025"}, + {"group": "linux", "target": "i686-unknown-linux-gnu"}, + {"group": "windows_gnu", "target": "x86_64-pc-windows-gnu", "os": "windows-2025"}, + {"group": "windows_msvc", "target": "x86_64-pc-windows-msvc", "os": "windows-2025"}, + {"group": "linux", "target": "x86_64-unknown-linux-gnu"}, +] + +TIER2 = [ + {"group": "apple", "target": "x86_64-apple-darwin", "os": "macos-26-intel"}, + {"group": "linux", "target": "aarch64-linux-android"}, + {"group": "linux" ,"target" :"arm-linux-androideabi" }, + # Keep in sync with the Android build pinned in ci/cuttlefish-setup.sh + { "group":"linux","target" : "x86_64-linux-android" ,"artifact-tag" : "android17" } , + {"group": "linux" ,"target":"arm-unknown-linux-gnueabihf" } , + { "group" :"linux" ,"target": "loongarch64-unknown-linux-gnu"}, + { "group" : "linux", "target": "powerpc64-unknown-linux-gnu"}, + {"group": "linux", "target": "powerpc64le-unknown-linux-gnu"}, + {"group": "linux", "target": "riscv64gc-unknown-linux-gnu"}, + { "group":"linux" , "target" : "s390x-unknown-linux-gnu" }, + {"group": "linux", "target": "sparc64-unknown-linux-gnu"}, + {"group" : "linux" , "target": "wasm32-unknown-emscripten"} , + {"group": "wasm", "target": "wasm32-wasip1"}, + { "group": "wasm" ,"target": "wasm32-wasip2"}, + {"group":"linux", "target":"aarch64-unknown-linux-musl" } , + {"group": "linux", "target": "aarch64-unknown-linux-musl", "env": {"TEST_MUSL_V1_2_3": 1}, "artifact-tag": "new-musl"}, + { "group" :"linux" ,"target" :"arm-unknown-linux-musleabihf" }, + {"group": "linux", "target": "arm-unknown-linux-musleabihf", "env": {"TEST_MUSL_V1_2_3": 1}, "artifact-tag": "new-musl"}, + { "group": "linux","target": "i686-unknown-linux-musl"}, + { "group" : "linux","target":"i686-unknown-linux-musl","env" : { "TEST_MUSL_V1_2_3":1 }, "artifact-tag" : "new-musl" } , + { "group":"linux", "target" : "loongarch64-unknown-linux-musl"}, + {"group": "linux", "target": "loongarch64-unknown-linux-musl", "env": {"TEST_MUSL_V1_2_3": 1}, "artifact-tag": "new-musl"}, + { "group": "linux" , "target":"powerpc64-unknown-linux-musl"}, + {"group":"linux" ,"target" : "powerpc64-unknown-linux-musl","env" : { "RUST_LIBC_UNSTABLE_MUSL_V1_2_3":1} ,"artifact-tag" : "new-musl" } , + {"group": "linux", "target": "powerpc64le-unknown-linux-musl"}, + {"group":"linux", "target" : "powerpc64le-unknown-linux-musl", "env" : { "TEST_MUSL_V1_2_3" : 1},"artifact-tag": "new-musl" }, + {"group" : "linux", "target":"x86_64-unknown-linux-musl" } , + {"group" : "linux" ,"target": "x86_64-unknown-linux-musl","env":{ "TEST_MUSL_V1_2_3": 1} , "artifact-tag":"new-musl" } , +] + +# FIXME: disabled until they stop failing, see the linked issues +# - i686-linux-android (#4297), x86_64-unknown-linux-gnux32, x86_64-unknown-redox, powerpc-unknown-linux-gnu (#4254) + +TIER2_VM = [ + {"group": "bsd", "target": "i686-unknown-freebsd", "release": "15.0"}, + { "group": "bsd" ,"target":"x86_64-unknown-freebsd" , "release" :"14.4" } , + {"group":"bsd" , "target":"x86_64-unknown-freebsd","release" : "15.0"}, + { "group" :"solarish", "target":"x86_64-pc-solaris" }, + {"group" : "bsd" ,"target" : "x86_64-unknown-netbsd" }, + {"group": "solarish", "target": "x86_64-unknown-illumos"}, +] + + +TIERS ={"tier1" :TIER1 , "tier2":TIER2, "tier2_vm":TIER2_VM} -def match (p,pat ) : - #/** is just a prefix match here +def match(p,pat ) : + # /** is just a prefix match here return p.startswith(pat[:-3]) if pat.endswith("/**") else fnmatch.fnmatch(p, pat) -def groups_for( files): +def groups_for(files) : + code = [p for p in files if not any(match(p, d) for d in DOCS)] - if all (any ( match (p,pat) for pat in DOCS ) for p in files) : - return [] - hit = {g for p in files for g, pats in GROUPS.items() if any(match(p, x) for x in pats)} - # no match, run everything rather than miss something - return sorted(GROUPS) if not hit else sorted(hit) + if not code: + return [] + hit = set () + for p in code: + gs= { g for g , pats in PLATFORMS.items ( )if any(match (p ,x)for x in pats )} + if not gs: -def changed(): + # unknown file, run everything rather than miss something + return GROUPS + hit |= gs + return sorted (hit) - #no event file when run locally, nothing to classify - event = os.environ.get ( "GITHUB_EVENT_PATH" ) - if not event: +def changed( ): + # no event file when run locally, nothing to classify + event= os.environ.get ( "GITHUB_EVENT_PATH") + if not event : return None - try: - ev=json.loads (Path (event ).read_text() ) - except ( OSError ,ValueError ) as err : + try : + + ev =json.loads( Path (event ).read_text () ) + except ( OSError, ValueError ) as err: sys.exit(f"cannot read event file {event}, {err}") - pr,mq =ev.get("pull_request" ) , ev.get( "merge_group" ) - if pr: - base, head = pr["base"]["sha"], "HEAD" - elif mq: - base, head= mq[ "base_sha" ],mq [ "head_sha" ] - else: # schedule/dispatch, run everything + pr = ev.get("pull_request") + if not pr: + # merge queues, schedules and manual runs get everything return None + base = pr["base"]["sha"] try: - out = sp.run(["git", "diff", "--name-only", f"{base}...{head}"], - capture_output =True,text= True , check=True) - except sp.CalledProcessError as err: - sys.exit(f"git diff failed for {base}..{head}, {err}") + out = sp.run(["git", "diff", "--name-only", f"{base}...HEAD"], + capture_output=True, text=True, check=True) + except sp.CalledProcessError as err : + sys.exit(f"git diff failed for {base}..HEAD, {err}") return out.stdout.splitlines() -def sanity(): - cases=[ - ( [ "src/unix/bsd/apple/x.rs"], [ "apple"]) , - ( ["src/unix/bsd/freebsdlike/x.rs" ], ["apple"] ), - (["src/unix/bsd/mod.rs"], ["apple"]), - (["src/unix/linux_like/linux/gnu/x.rs"] , [ "linux_gnu"] ) , - ( [ "src/windows/msvc/x.rs"], [ "windows_msvc"]), - (["src/windows/gnu/x.rs"], ["windows_gnu"]), - ( [ "src/windows/mod.rs" ] ,[ "windows_gnu","windows_msvc" ]), - ( [ "Cargo.toml" ], ["core" ]), - ( ["ci/run.sh"] , [ "core" ] ), - (["src/types.rs"], ["core"]), +def matrices( groups ): + want = set(groups) + out = {} + for tier, rows in TIERS.items(): + keep = [e for e in rows if e[ "group" ]in want ] + out[tier] = [{k: v for k, v in e.items() if k != "group"} for e in keep] + return out + + +def sanity () : + cases= [ + ([ "src/unix/bsd/apple/x.rs" ],[ "apple"] ), + (["src/unix/bsd/freebsdlike/x.rs"], ["apple", "bsd"]), + (["src/unix/bsd/netbsdlike/x.rs"], ["bsd"]), + (["src/unix/bsd/mod.rs"], ["apple", "bsd"]), + ( [ "src/unix/linux_like/linux/gnu/x.rs"] ,[ "linux" ]), + ( ["src/unix/linux_like/linux/musl/x.rs"] , [ "linux" ]) , + ( [ "src/windows/msvc/x.rs"],["windows_msvc" ] ) , + (["src/windows/gnu/x.rs"], [ "windows_gnu" ]), + (["src/windows/mod.rs"], ["windows_gnu", "windows_msvc"]), + ([ "src/wasi/x.rs" ] , [ "wasm" ]), + (["src/unix/solarish/x.rs"], ["solarish"]), + (["Cargo.toml" ] , GROUPS) , + ( [ "ci/run.sh" ], GROUPS ) , (["README.md"], []), - #newlib has no tier1 target, the fail-safe kicks in - ( [ "src/newlib/mod.rs" ] ,sorted (GROUPS ) ), - ( [ "README.md","src/newlib/mod.rs" ],sorted(GROUPS)) , + ( ["README.md" , "src/unix/bsd/apple/x.rs"] ,["apple"] ) , ] - for files,want in cases : - got = groups_for (files ) - assert got == want, f"expected {want} got {got} for {files}" - print( "all good") - - -def main () : - p = argparse.ArgumentParser() - p.add_argument( "--files",nargs= "+",help = "git paths to classify" ) - p.add_argument("--sanity", action="store_true") - args=p.parse_args() - if args.sanity: + for files, want in cases: + + got =groups_for(files ) + assert got== want, f"expected {want} got {got} for {files}" + m=matrices ( ["apple"] ) + assert[e [ "target" ] for e in m[ "tier1" ] ]== ["aarch64-apple-darwin" ],m + assert m[ "tier2_vm" ] == [ ] ,m + full = matrices(GROUPS) + assert len( full["tier1" ])==9 and len( full["tier2"] )== 28 and len ( full ["tier2_vm" ] ) == 6 ,full + print ( "all good") + + +def main(): + p =argparse.ArgumentParser () + p.add_argument("--files" ,nargs ="+" ,help ="git paths to classify") + p.add_argument ( "--sanity" , action ="store_true") + args= p.parse_args() + if args.sanity : + + sanity() return - files = args.files if args.files else changed () - groups= list( GROUPS ) if files is None else groups_for ( files ) - print(json.dumps( groups ) ) - out=os.environ.get ("GITHUB_OUTPUT" ) - if out : - - with open (out,"a")as f: - f.write(f"changes={json.dumps(groups)}\n") + files=args.files if args.files else changed ( ) + groups = GROUPS if files is None else groups_for ( files ) + for tier, rows in matrices(groups).items(): + print(f"{tier}={json.dumps(rows)}") -if __name__ =="__main__" : - main () +if __name__== "__main__": + main( ) From d8efccda6df1b27d79bf1d05fdb72accdc1218d9 Mon Sep 17 00:00:00 2001 From: LusterSourav <282348889+LusterSourav@users.noreply.github.com> Date: Wed, 5 Aug 2026 00:19:43 +0530 Subject: [PATCH 07/11] use generated matrices in ci --- .github/workflows/ci.yaml | 134 +++++++------------------------------- 1 file changed, 23 insertions(+), 111 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 24c7c74bb7e6..48f602d7e5e9 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -127,68 +127,44 @@ jobs: - name: Target size after job completion run: du -sh target | sort -k 2 - # groups the diff touches, tier1 skips the rest - changes: - name: Detect changed groups + # the diff decides what each tier runs, merge queues and schedules get everything + calculate_vars: + name: Calculate CI variables runs-on: ubuntu-26.04 timeout-minutes: 5 outputs: - changes: ${{ steps.detect.outputs.changes }} + tier1: ${{ steps.vars.outputs.tier1 }} + tier2: ${{ steps.vars.outputs.tier2 }} + tier2_vm: ${{ steps.vars.outputs.tier2_vm }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false - fetch-depth: 0 # need full history so the base sha exists for the diff - - name: Compute affected groups - id: detect - run: python3 ci/detect-changes.py + fetch-depth: 0 # full history so the base sha exists for the diff + - name: Compute test matrices + id: vars + run: | + set -eo pipefail + python3 ci/detect-changes.py | tee "$GITHUB_OUTPUT" test_tier1: name: Test tier1 - needs: changes - # untouched groups spawn but every step is skipped, success gate passes those + needs: calculate_vars + # only platforms the diff touches, an empty matrix means the job is skipped strategy: matrix: - include: - - target: aarch64-apple-darwin - group: apple - os: macos-26 - - target: aarch64-pc-windows-msvc - group: windows_msvc - os: windows-11-arm - - target: aarch64-unknown-linux-gnu - group: linux_gnu - os: ubuntu-26.04-arm - - target: i686-pc-windows-gnu - group: windows_gnu - os: windows-2025 - - target: i686-pc-windows-msvc - group: windows_msvc - os: windows-2025 - - target: i686-unknown-linux-gnu - group: linux_gnu - - target: x86_64-pc-windows-gnu - group: windows_gnu - os: windows-2025 - - target: x86_64-pc-windows-msvc - group: windows_msvc - os: windows-2025 - - target: x86_64-unknown-linux-gnu - group: linux_gnu + include: ${{ fromJSON(needs.calculate_vars.outputs.tier1) }} runs-on: ${{ matrix.os && matrix.os || 'ubuntu-26.04' }} timeout-minutes: 25 env: TARGET: ${{ matrix.target }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - if: contains(fromJSON(needs.changes.outputs.changes), matrix.group) with: persist-credentials: false - name: Setup Rust toolchain - if: contains(fromJSON(needs.changes.outputs.changes), matrix.group) run: ./ci/install-rust.sh - uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2 - if: contains(fromJSON(needs.changes.outputs.changes), matrix.group) with: key: ${{ matrix.target }} @@ -200,15 +176,15 @@ jobs: shell: bash - name: Run natively - if: contains(fromJSON(needs.changes.outputs.changes), matrix.group) && runner.os != 'Linux' + if: runner.os != 'Linux' run: ./ci/run.sh ${{ matrix.target }} - name: Run in Docker - if: contains(fromJSON(needs.changes.outputs.changes), matrix.group) && runner.os == 'Linux' + if: runner.os == 'Linux' run: ./ci/run-docker.sh ${{ matrix.target }} - name: Create CI artifacts id: create_artifacts - if: always() && contains(fromJSON(needs.changes.outputs.changes), matrix.group) + if: always() run: echo "step is actually running" && python3 ci/create-artifacts.py - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 if: always() && steps.create_artifacts.outcome == 'success' @@ -219,67 +195,12 @@ jobs: test_tier2: name: Test tier2 - needs: [test_tier1, style_check] + needs: [calculate_vars, style_check] strategy: fail-fast: true max-parallel: 16 matrix: - include: - - target: aarch64-linux-android - - target: aarch64-unknown-linux-musl - - target: aarch64-unknown-linux-musl - env: { TEST_MUSL_V1_2: 1 } - artifact-tag: new-musl - - target: arm-linux-androideabi - - target: arm-unknown-linux-gnueabihf - - target: arm-unknown-linux-musleabihf - - target: arm-unknown-linux-musleabihf - env: { TEST_MUSL_V1_2: 1 } - artifact-tag: new-musl - # FIXME(#4297): Disabled due to spurious failue - # - target: i686-linux-android - - target: i686-unknown-linux-musl - - target: i686-unknown-linux-musl - env: { TEST_MUSL_V1_2: 1 } - artifact-tag: new-musl - - target: loongarch64-unknown-linux-gnu - - target: loongarch64-unknown-linux-musl - - target: loongarch64-unknown-linux-musl - env: { TEST_MUSL_V1_2: 1 } - artifact-tag: new-musl - - target: powerpc64-unknown-linux-gnu - - target: powerpc64-unknown-linux-musl - - target: powerpc64-unknown-linux-musl - env: { RUST_LIBC_UNSTABLE_MUSL_V1_2: 1 } - artifact-tag: new-musl - - target: powerpc64le-unknown-linux-gnu - - target: powerpc64le-unknown-linux-musl - - target: powerpc64le-unknown-linux-musl - env: { TEST_MUSL_V1_2: 1 } - artifact-tag: new-musl - - target: riscv64gc-unknown-linux-gnu - - target: s390x-unknown-linux-gnu - - target: sparc64-unknown-linux-gnu - - target: wasm32-unknown-emscripten - - target: wasm32-wasip1 - - target: wasm32-wasip2 - - target: x86_64-apple-darwin - os: macos-26-intel - - target: x86_64-linux-android - # Keep in sync with the Android build pinned in ci/cuttlefish-setup.sh - artifact-tag: android17 - # FIXME: Exec format error (os error 8) - # - target: x86_64-unknown-linux-gnux32 - - target: x86_64-unknown-linux-musl - - target: x86_64-unknown-linux-musl - env: { TEST_MUSL_V1_2: 1 } - artifact-tag: new-musl - # FIXME: It seems some items in `src/unix/mod.rs` aren't defined on redox actually. - # - target: x86_64-unknown-redox - - # FIXME(ppc): SIGILL running tests, see - # https://github.com/rust-lang/libc/pull/4254#issuecomment-2636288713 - # - target: powerpc-unknown-linux-gnu + include: ${{ fromJSON(needs.calculate_vars.outputs.tier2) }} runs-on: ${{ matrix.os && matrix.os || 'ubuntu-26.04' }} timeout-minutes: 25 env: @@ -321,21 +242,12 @@ jobs: test_tier2_vm: name: Test tier2 VM - needs: [test_tier1, style_check] + needs: [calculate_vars, style_check] runs-on: ubuntu-latest strategy: fail-fast: true matrix: - include: - - release: "15.0" - target: i686-unknown-freebsd - - release: "14.4" - target: x86_64-unknown-freebsd - - release: "15.0" - target: x86_64-unknown-freebsd - - target: x86_64-pc-solaris - - target: x86_64-unknown-netbsd - - target: x86_64-unknown-illumos + include: ${{ fromJSON(needs.calculate_vars.outputs.tier2_vm) }} timeout-minutes: 25 steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 @@ -450,7 +362,7 @@ jobs: name: success runs-on: ubuntu-26.04 needs: - - changes + - calculate_vars - style_check - test_tier1 - test_tier2 From 66bcd6548fd2b59a5bb69db87e6ed8b151f73680 Mon Sep 17 00:00:00 2001 From: LusterSourav <282348889+LusterSourav@users.noreply.github.com> Date: Wed, 5 Aug 2026 19:23:06 +0530 Subject: [PATCH 08/11] drop autodetection, use single TestTarget list --- .github/workflows/ci.yaml | 6 +- ci/detect-changes.py | 355 +++++++++++++++++++------------------- 2 files changed, 180 insertions(+), 181 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 48f602d7e5e9..c8ba2fd855f0 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -127,7 +127,7 @@ jobs: - name: Target size after job completion run: du -sh target | sort -k 2 - # the diff decides what each tier runs, merge queues and schedules get everything + # generates the full test matrix for each tier, same for every run calculate_vars: name: Calculate CI variables runs-on: ubuntu-26.04 @@ -140,7 +140,6 @@ jobs: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false - fetch-depth: 0 # full history so the base sha exists for the diff - name: Compute test matrices id: vars run: | @@ -150,7 +149,6 @@ jobs: test_tier1: name: Test tier1 needs: calculate_vars - # only platforms the diff touches, an empty matrix means the job is skipped strategy: matrix: include: ${{ fromJSON(needs.calculate_vars.outputs.tier1) }} @@ -381,4 +379,4 @@ jobs: steps: # Manually check the status of all dependencies. `if: failure()` does not work. - name: check if any dependency failed - run: jq --exit-status 'all(.result == "success" or .result == "skipped")' <<< "$NEEDS" + run: jq --exit-status 'all(.result == "success")' <<< "$NEEDS" diff --git a/ci/detect-changes.py b/ci/detect-changes.py index 02ae9c4ca6ff..66a73101ac0d 100644 --- a/ci/detect-changes.py +++ b/ci/detect-changes.py @@ -1,194 +1,195 @@ #!/usr/bin/env python3 -# computes the ci matrices, merge queues and schedules get every platform +"""Emit the test matrices for the CI workflow as GitHub Actions output. + +Each tier is printed on its own line as `tierN=` so the workflow can +feed it straight into a `matrix: include` block. Merge queues, schedules +and manual runs always get every target; there is no file detection yet. +""" import argparse -import fnmatch import json -import os -import subprocess as sp import sys -from pathlib import Path - -# the diff gets sorted into these, one group per platform family -PLATFORMS = { - "apple": ["src/unix/bsd/apple/**", "src/unix/bsd/freebsdlike/**", "src/unix/bsd/mod.rs"], - "bsd": ["src/unix/bsd/netbsdlike/**" ,"src/unix/bsd/freebsdlike/**","src/unix/bsd/mod.rs" ] , - "linux" :["src/unix/linux_like/**" ], - "windows_msvc": ["src/windows/msvc/**" , "src/windows/mod.rs" ], - "windows_gnu":["src/windows/gnu/**", "src/windows/mod.rs" ], - "wasm": ["src/wasi/**"], - "solarish" :["src/unix/solarish/**" ] , -} -GROUPS = sorted ( PLATFORMS) - - - -# docs/metadata, nothing compiles from them -DOCS= ["README.md" ,"CHANGELOG.md" ,"CONTRIBUTING.md", "LICENSE*" , "triagebot.toml" ] - -# one row per entry in the workflow matrix, group decides when it runs -# a missing os means ubuntu-26.04, except tier2_vm which runs on ubuntu-latest -TIER1 = [ - {"group" : "apple" ,"target":"aarch64-apple-darwin" ,"os":"macos-26" } , - { "group": "windows_msvc" ,"target": "aarch64-pc-windows-msvc", "os": "windows-11-arm" }, - {"group": "linux", "target": "aarch64-unknown-linux-gnu", "os": "ubuntu-26.04-arm"}, - {"group" : "windows_gnu" , "target": "i686-pc-windows-gnu","os":"windows-2025" } , - { "group":"windows_msvc","target":"i686-pc-windows-msvc","os" : "windows-2025"}, - {"group": "linux", "target": "i686-unknown-linux-gnu"}, - {"group": "windows_gnu", "target": "x86_64-pc-windows-gnu", "os": "windows-2025"}, - {"group": "windows_msvc", "target": "x86_64-pc-windows-msvc", "os": "windows-2025"}, - {"group": "linux", "target": "x86_64-unknown-linux-gnu"}, +from dataclasses import dataclass, field +from enum import IntEnum + + +class Tier(IntEnum): + """Roughly ordered by how much we care about the target staying green.""" + + T1 = 1 + T2 = 2 + T3 = 3 # tier 2 that only runs inside a VM + + +@dataclass(frozen=True) +class TestTarget: + """One row of the test matrix. + + The fields map straight to matrix variables in ci.yaml; a missing `os` + means the default ubuntu-26.04 runner. + """ + + name: str # rust target triple + #: runner OS, fall back to ubuntu-26.04 when unset + os: str | None = None + tier: Tier = Tier.T1 + vm: bool = False + release: str | None = None # OS version for the VM jobs + env: dict[str, str | int] = field(default_factory=dict) + artifact_tag: str | None = None + + +# the full list of matrix rows, grouped by tier for `tier_rows()` +TARGETS: list[TestTarget] = [ + # tier 1 + TestTarget("aarch64-apple-darwin", os="macos-26"), + TestTarget("aarch64-pc-windows-msvc", os="windows-11-arm"), + TestTarget("aarch64-unknown-linux-gnu", os="ubuntu-26.04-arm"), + TestTarget("i686-pc-windows-gnu", os="windows-2025"), + TestTarget("i686-pc-windows-msvc", os="windows-2025"), + TestTarget("i686-unknown-linux-gnu"), + TestTarget("x86_64-pc-windows-gnu", os="windows-2025"), + TestTarget("x86_64-pc-windows-msvc", os="windows-2025"), + TestTarget("x86_64-unknown-linux-gnu"), + # tier 2 + TestTarget("aarch64-linux-android", tier=Tier.T2), + TestTarget("aarch64-unknown-linux-musl", tier=Tier.T2), + TestTarget( + "aarch64-unknown-linux-musl", + tier=Tier.T2, + env={"TEST_MUSL_V1_2_3": 1}, + artifact_tag="new-musl", + ), + TestTarget("arm-linux-androideabi", tier=Tier.T2), + TestTarget("arm-unknown-linux-gnueabihf", tier=Tier.T2), + TestTarget("arm-unknown-linux-musleabihf", tier=Tier.T2), + TestTarget( + "arm-unknown-linux-musleabihf", + tier=Tier.T2, + env={"TEST_MUSL_V1_2_3": 1}, + artifact_tag="new-musl", + ), + # FIXME(#4297): spurious test failures, keep disabled + # TestTarget("i686-linux-android", tier=Tier.T2), + TestTarget("i686-unknown-linux-musl", tier=Tier.T2), + TestTarget( + "i686-unknown-linux-musl", + tier=Tier.T2, + env={"TEST_MUSL_V1_2_3": 1}, + artifact_tag="new-musl", + ), + TestTarget("loongarch64-unknown-linux-gnu", tier=Tier.T2), + TestTarget("loongarch64-unknown-linux-musl", tier=Tier.T2), + TestTarget( + "loongarch64-unknown-linux-musl", + tier=Tier.T2, + env={"TEST_MUSL_V1_2_3": 1}, + artifact_tag="new-musl", + ), + TestTarget("powerpc64-unknown-linux-gnu", tier=Tier.T2), + TestTarget("powerpc64-unknown-linux-musl", tier=Tier.T2), + TestTarget( + "powerpc64-unknown-linux-musl", + tier=Tier.T2, + env={"RUST_LIBC_UNSTABLE_MUSL_V1_2_3": 1}, + artifact_tag="new-musl", + ), + TestTarget("powerpc64le-unknown-linux-gnu", tier=Tier.T2), + TestTarget("powerpc64le-unknown-linux-musl", tier=Tier.T2), + TestTarget( + "powerpc64le-unknown-linux-musl", + tier=Tier.T2, + env={"TEST_MUSL_V1_2_3": 1}, + artifact_tag="new-musl", + ), + TestTarget("riscv64gc-unknown-linux-gnu", tier=Tier.T2), + TestTarget("s390x-unknown-linux-gnu", tier=Tier.T2), + TestTarget("sparc64-unknown-linux-gnu", tier=Tier.T2), + TestTarget("wasm32-unknown-emscripten", tier=Tier.T2), + TestTarget("wasm32-wasip1", tier=Tier.T2), + TestTarget("wasm32-wasip2", tier=Tier.T2), + TestTarget("x86_64-apple-darwin", os="macos-26-intel", tier=Tier.T2), + # keep in sync with the android build pinned in ci/cuttlefish-setup.sh + TestTarget("x86_64-linux-android", tier=Tier.T2, artifact_tag="android17"), + # FIXME: fails to run, exec format error (os error 8) + # TestTarget("x86_64-unknown-linux-gnux32", tier=Tier.T2), + TestTarget("x86_64-unknown-linux-musl", tier=Tier.T2), + TestTarget( + "x86_64-unknown-linux-musl", + tier=Tier.T2, + env={"TEST_MUSL_V1_2_3": 1}, + artifact_tag="new-musl", + ), + # FIXME: some items in `src/unix/mod.rs` aren't defined on redox yet + # TestTarget("x86_64-unknown-redox", tier=Tier.T2), + # FIXME(ppc): SIGILL running tests, see rust-lang/libc#4254 + # TestTarget("powerpc-unknown-linux-gnu", tier=Tier.T2), + # tier 2, VM only + TestTarget("i686-unknown-freebsd", tier=Tier.T3, vm=True, release="15.0"), + TestTarget("x86_64-unknown-freebsd", tier=Tier.T3, vm=True, release="14.4"), + TestTarget("x86_64-unknown-freebsd", tier=Tier.T3, vm=True, release="15.0"), + TestTarget("x86_64-pc-solaris", tier=Tier.T3, vm=True), + TestTarget("x86_64-unknown-netbsd", tier=Tier.T3, vm=True), + TestTarget("x86_64-unknown-illumos", tier=Tier.T3, vm=True), ] -TIER2 = [ - {"group": "apple", "target": "x86_64-apple-darwin", "os": "macos-26-intel"}, - {"group": "linux", "target": "aarch64-linux-android"}, - {"group": "linux" ,"target" :"arm-linux-androideabi" }, - # Keep in sync with the Android build pinned in ci/cuttlefish-setup.sh - { "group":"linux","target" : "x86_64-linux-android" ,"artifact-tag" : "android17" } , - {"group": "linux" ,"target":"arm-unknown-linux-gnueabihf" } , - { "group" :"linux" ,"target": "loongarch64-unknown-linux-gnu"}, - { "group" : "linux", "target": "powerpc64-unknown-linux-gnu"}, - {"group": "linux", "target": "powerpc64le-unknown-linux-gnu"}, - {"group": "linux", "target": "riscv64gc-unknown-linux-gnu"}, - { "group":"linux" , "target" : "s390x-unknown-linux-gnu" }, - {"group": "linux", "target": "sparc64-unknown-linux-gnu"}, - {"group" : "linux" , "target": "wasm32-unknown-emscripten"} , - {"group": "wasm", "target": "wasm32-wasip1"}, - { "group": "wasm" ,"target": "wasm32-wasip2"}, - {"group":"linux", "target":"aarch64-unknown-linux-musl" } , - {"group": "linux", "target": "aarch64-unknown-linux-musl", "env": {"TEST_MUSL_V1_2_3": 1}, "artifact-tag": "new-musl"}, - { "group" :"linux" ,"target" :"arm-unknown-linux-musleabihf" }, - {"group": "linux", "target": "arm-unknown-linux-musleabihf", "env": {"TEST_MUSL_V1_2_3": 1}, "artifact-tag": "new-musl"}, - { "group": "linux","target": "i686-unknown-linux-musl"}, - { "group" : "linux","target":"i686-unknown-linux-musl","env" : { "TEST_MUSL_V1_2_3":1 }, "artifact-tag" : "new-musl" } , - { "group":"linux", "target" : "loongarch64-unknown-linux-musl"}, - {"group": "linux", "target": "loongarch64-unknown-linux-musl", "env": {"TEST_MUSL_V1_2_3": 1}, "artifact-tag": "new-musl"}, - { "group": "linux" , "target":"powerpc64-unknown-linux-musl"}, - {"group":"linux" ,"target" : "powerpc64-unknown-linux-musl","env" : { "RUST_LIBC_UNSTABLE_MUSL_V1_2_3":1} ,"artifact-tag" : "new-musl" } , - {"group": "linux", "target": "powerpc64le-unknown-linux-musl"}, - {"group":"linux", "target" : "powerpc64le-unknown-linux-musl", "env" : { "TEST_MUSL_V1_2_3" : 1},"artifact-tag": "new-musl" }, - {"group" : "linux", "target":"x86_64-unknown-linux-musl" } , - {"group" : "linux" ,"target": "x86_64-unknown-linux-musl","env":{ "TEST_MUSL_V1_2_3": 1} , "artifact-tag":"new-musl" } , -] - -# FIXME: disabled until they stop failing, see the linked issues -# - i686-linux-android (#4297), x86_64-unknown-linux-gnux32, x86_64-unknown-redox, powerpc-unknown-linux-gnu (#4254) - -TIER2_VM = [ - {"group": "bsd", "target": "i686-unknown-freebsd", "release": "15.0"}, - { "group": "bsd" ,"target":"x86_64-unknown-freebsd" , "release" :"14.4" } , - {"group":"bsd" , "target":"x86_64-unknown-freebsd","release" : "15.0"}, - { "group" :"solarish", "target":"x86_64-pc-solaris" }, - {"group" : "bsd" ,"target" : "x86_64-unknown-netbsd" }, - {"group": "solarish", "target": "x86_64-unknown-illumos"}, -] - - -TIERS ={"tier1" :TIER1 , "tier2":TIER2, "tier2_vm":TIER2_VM} - - -def match(p,pat ) : - # /** is just a prefix match here - return p.startswith(pat[:-3]) if pat.endswith("/**") else fnmatch.fnmatch(p, pat) - - -def groups_for(files) : - code = [p for p in files if not any(match(p, d) for d in DOCS)] - - - if not code: - return [] - hit = set () - for p in code: - gs= { g for g , pats in PLATFORMS.items ( )if any(match (p ,x)for x in pats )} - if not gs: - - # unknown file, run everything rather than miss something - return GROUPS - hit |= gs - return sorted (hit) - - -def changed( ): - # no event file when run locally, nothing to classify - event= os.environ.get ( "GITHUB_EVENT_PATH") - if not event : - return None - try : - - ev =json.loads( Path (event ).read_text () ) - except ( OSError, ValueError ) as err: - sys.exit(f"cannot read event file {event}, {err}") - - pr = ev.get("pull_request") - if not pr: - # merge queues, schedules and manual runs get everything - return None - base = pr["base"]["sha"] - try: - out = sp.run(["git", "diff", "--name-only", f"{base}...HEAD"], - capture_output=True, text=True, check=True) - except sp.CalledProcessError as err : - sys.exit(f"git diff failed for {base}..HEAD, {err}") - - return out.stdout.splitlines() +#: tier value -> output variable name +TIER_OUTPUT_NAMES = { + Tier.T1: "tier1", + Tier.T2: "tier2", + Tier.T3: "tier2_vm", +} -def matrices( groups ): - want = set(groups) - out = {} - for tier, rows in TIERS.items(): - keep = [e for e in rows if e[ "group" ]in want ] - out[tier] = [{k: v for k, v in e.items() if k != "group"} for e in keep] +def to_matrix_row(target: TestTarget) -> dict[str, str | int]: + """Convert a target into the dict a matrix `include` row expects. + + None fields are dropped so the JSON stays identical to the old + hardcoded `include:` blocks and the workflow's `matrix.os` fallbacks + keep working. + """ + row: dict[str, str | int] = {"target": target.name} + if target.os is not None: + row["os"] = target.os + if target.env: + row["env"] = dict(target.env) + if target.artifact_tag is not None: + row["artifact-tag"] = target.artifact_tag + if target.release is not None: + row["release"] = target.release + return row + + +def tier_rows() -> dict[str, list[dict[str, str | int]]]: + """All rows, grouped by tier so the workflow gets one JSON per job.""" + out: dict[str, list[dict[str, str | int]]] = { + name: [] for name in TIER_OUTPUT_NAMES.values() + } + for target in TARGETS: + out[TIER_OUTPUT_NAMES[target.tier]].append(to_matrix_row(target)) return out -def sanity () : - cases= [ - ([ "src/unix/bsd/apple/x.rs" ],[ "apple"] ), - (["src/unix/bsd/freebsdlike/x.rs"], ["apple", "bsd"]), - (["src/unix/bsd/netbsdlike/x.rs"], ["bsd"]), - (["src/unix/bsd/mod.rs"], ["apple", "bsd"]), - ( [ "src/unix/linux_like/linux/gnu/x.rs"] ,[ "linux" ]), - ( ["src/unix/linux_like/linux/musl/x.rs"] , [ "linux" ]) , - ( [ "src/windows/msvc/x.rs"],["windows_msvc" ] ) , - (["src/windows/gnu/x.rs"], [ "windows_gnu" ]), - (["src/windows/mod.rs"], ["windows_gnu", "windows_msvc"]), - ([ "src/wasi/x.rs" ] , [ "wasm" ]), - (["src/unix/solarish/x.rs"], ["solarish"]), - (["Cargo.toml" ] , GROUPS) , - ( [ "ci/run.sh" ], GROUPS ) , - (["README.md"], []), - ( ["README.md" , "src/unix/bsd/apple/x.rs"] ,["apple"] ) , - ] - for files, want in cases: - - got =groups_for(files ) - assert got== want, f"expected {want} got {got} for {files}" - m=matrices ( ["apple"] ) - assert[e [ "target" ] for e in m[ "tier1" ] ]== ["aarch64-apple-darwin" ],m - assert m[ "tier2_vm" ] == [ ] ,m - full = matrices(GROUPS) - assert len( full["tier1" ])==9 and len( full["tier2"] )== 28 and len ( full ["tier2_vm" ] ) == 6 ,full - print ( "all good") - - -def main(): - p =argparse.ArgumentParser () - p.add_argument("--files" ,nargs ="+" ,help ="git paths to classify") - p.add_argument ( "--sanity" , action ="store_true") - args= p.parse_args() - if args.sanity : +def sanity() -> None: + """Fail loudly if the matrices drift from the full current set.""" + counts = {name: len(rows) for name, rows in tier_rows().items()} + assert counts == {"tier1": 9, "tier2": 28, "tier2_vm": 6}, counts + for target in TARGETS: + assert target.vm == (target.tier == Tier.T3) +def main() -> None: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument( + "--sanity", action="store_true", help="check the matrix is complete" + ) + args = parser.parse_args() + if args.sanity: sanity() - return - files=args.files if args.files else changed ( ) - groups = GROUPS if files is None else groups_for ( files ) - for tier, rows in matrices(groups).items(): - print(f"{tier}={json.dumps(rows)}") + sys.exit(0) + for name, rows in tier_rows().items(): + print(f"{name}={json.dumps(rows)}") -if __name__== "__main__": - main( ) +if __name__ == "__main__": + main() From 32026f67b3336c707c1fb7a6998db99c59d47a09 Mon Sep 17 00:00:00 2001 From: LusterSourav <282348889+LusterSourav@users.noreply.github.com> Date: Thu, 6 Aug 2026 16:26:55 +0530 Subject: [PATCH 09/11] address review: rename to ci-util, CiJob tiers, single emit function --- .github/workflows/ci.yaml | 48 +++++------ .gitignore | 1 + ci/{detect-changes.py => ci-util.py} | 117 +++++++++++---------------- 3 files changed, 72 insertions(+), 94 deletions(-) rename ci/{detect-changes.py => ci-util.py} (59%) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index c8ba2fd855f0..31f1c4f3034f 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -27,6 +27,25 @@ defaults: shell: bash jobs: + # generates the full test matrix for each tier, same for every run + calculate_vars: + name: Calculate CI variables + runs-on: ubuntu-26.04 + timeout-minutes: 5 + outputs: + test_tier1_matrix: ${{ steps.vars.outputs.test_tier1_matrix }} + test_tier2_matrix: ${{ steps.vars.outputs.test_tier2_matrix }} + test_tier2_vm_matrix: ${{ steps.vars.outputs.test_tier2_vm_matrix }} + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - name: Compute test matrices + id: vars + run: | + set -eo pipefail + python3 ci/ci-util.py | tee "$GITHUB_OUTPUT" + style_check: name: Style check runs-on: ubuntu-26.04 @@ -127,31 +146,12 @@ jobs: - name: Target size after job completion run: du -sh target | sort -k 2 - # generates the full test matrix for each tier, same for every run - calculate_vars: - name: Calculate CI variables - runs-on: ubuntu-26.04 - timeout-minutes: 5 - outputs: - tier1: ${{ steps.vars.outputs.tier1 }} - tier2: ${{ steps.vars.outputs.tier2 }} - tier2_vm: ${{ steps.vars.outputs.tier2_vm }} - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - persist-credentials: false - - name: Compute test matrices - id: vars - run: | - set -eo pipefail - python3 ci/detect-changes.py | tee "$GITHUB_OUTPUT" - test_tier1: name: Test tier1 needs: calculate_vars strategy: matrix: - include: ${{ fromJSON(needs.calculate_vars.outputs.tier1) }} + include: ${{ fromJSON(needs.calculate_vars.outputs.test_tier1_matrix) }} runs-on: ${{ matrix.os && matrix.os || 'ubuntu-26.04' }} timeout-minutes: 25 env: @@ -193,12 +193,12 @@ jobs: test_tier2: name: Test tier2 - needs: [calculate_vars, style_check] + needs: [test_tier1, calculate_vars, style_check] strategy: fail-fast: true max-parallel: 16 matrix: - include: ${{ fromJSON(needs.calculate_vars.outputs.tier2) }} + include: ${{ fromJSON(needs.calculate_vars.outputs.test_tier2_matrix) }} runs-on: ${{ matrix.os && matrix.os || 'ubuntu-26.04' }} timeout-minutes: 25 env: @@ -240,12 +240,12 @@ jobs: test_tier2_vm: name: Test tier2 VM - needs: [calculate_vars, style_check] + needs: [test_tier1, calculate_vars, style_check] runs-on: ubuntu-latest strategy: fail-fast: true matrix: - include: ${{ fromJSON(needs.calculate_vars.outputs.tier2_vm) }} + include: ${{ fromJSON(needs.calculate_vars.outputs.test_tier2_vm_matrix) }} timeout-minutes: 25 steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 diff --git a/.gitignore b/.gitignore index 8ee6c810f3da..787c93df98f2 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ target *~ # Used by libc-util .libc-backports +ci/__pycache__/ diff --git a/ci/detect-changes.py b/ci/ci-util.py similarity index 59% rename from ci/detect-changes.py rename to ci/ci-util.py index 66a73101ac0d..8523f4545d56 100644 --- a/ci/detect-changes.py +++ b/ci/ci-util.py @@ -1,45 +1,59 @@ #!/usr/bin/env python3 """Emit the test matrices for the CI workflow as GitHub Actions output. -Each tier is printed on its own line as `tierN=` so the workflow can -feed it straight into a `matrix: include` block. Merge queues, schedules -and manual runs always get every target; there is no file detection yet. +Each tier is printed on its own line as `test__matrix=` so the +workflow can feed it straight into a `matrix: include` block. Merge queues, +schedules and manual runs always get every target; there is no file +detection yet. """ -import argparse import json -import sys from dataclasses import dataclass, field -from enum import IntEnum +from enum import IntEnum, StrEnum class Tier(IntEnum): - """Roughly ordered by how much we care about the target staying green.""" + """Rust tier of the target, as defined in + . + """ T1 = 1 T2 = 2 - T3 = 3 # tier 2 that only runs inside a VM + + +class CiJob(StrEnum): + """Which CI job the target is tested by.""" + + T1 = "tier1" + T2 = "tier2" + T2_VM = "tier2_vm" @dataclass(frozen=True) class TestTarget: """One row of the test matrix. - The fields map straight to matrix variables in ci.yaml; a missing `os` - means the default ubuntu-26.04 runner. + The fields map straight to matrix variables in ci.yaml; `os` defaults to + the ubuntu-26.04 runner. """ name: str # rust target triple - #: runner OS, fall back to ubuntu-26.04 when unset - os: str | None = None + #: runner OS + os: str = "ubuntu-26.04" tier: Tier = Tier.T1 vm: bool = False release: str | None = None # OS version for the VM jobs env: dict[str, str | int] = field(default_factory=dict) artifact_tag: str | None = None + def ci_job(self) -> CiJob: + """The CI job this target runs in, based on its tier and VM-ness.""" + if self.tier is Tier.T1: + return CiJob.T1 + return CiJob.T2_VM if self.vm else CiJob.T2 + -# the full list of matrix rows, grouped by tier for `tier_rows()` +# the full list of matrix rows, grouped by tier for readability TARGETS: list[TestTarget] = [ # tier 1 TestTarget("aarch64-apple-darwin", os="macos-26"), @@ -125,70 +139,33 @@ class TestTarget: # FIXME(ppc): SIGILL running tests, see rust-lang/libc#4254 # TestTarget("powerpc-unknown-linux-gnu", tier=Tier.T2), # tier 2, VM only - TestTarget("i686-unknown-freebsd", tier=Tier.T3, vm=True, release="15.0"), - TestTarget("x86_64-unknown-freebsd", tier=Tier.T3, vm=True, release="14.4"), - TestTarget("x86_64-unknown-freebsd", tier=Tier.T3, vm=True, release="15.0"), - TestTarget("x86_64-pc-solaris", tier=Tier.T3, vm=True), - TestTarget("x86_64-unknown-netbsd", tier=Tier.T3, vm=True), - TestTarget("x86_64-unknown-illumos", tier=Tier.T3, vm=True), + TestTarget("i686-unknown-freebsd", tier=Tier.T2, vm=True, release="15.0"), + TestTarget("x86_64-unknown-freebsd", tier=Tier.T2, vm=True, release="14.4"), + TestTarget("x86_64-unknown-freebsd", tier=Tier.T2, vm=True, release="15.0"), + TestTarget("x86_64-pc-solaris", tier=Tier.T2, vm=True), + TestTarget("x86_64-unknown-netbsd", tier=Tier.T2, vm=True), + TestTarget("x86_64-unknown-illumos", tier=Tier.T2, vm=True), ] -#: tier value -> output variable name -TIER_OUTPUT_NAMES = { - Tier.T1: "tier1", - Tier.T2: "tier2", - Tier.T3: "tier2_vm", -} - - -def to_matrix_row(target: TestTarget) -> dict[str, str | int]: - """Convert a target into the dict a matrix `include` row expects. - - None fields are dropped so the JSON stays identical to the old - hardcoded `include:` blocks and the workflow's `matrix.os` fallbacks - keep working. - """ - row: dict[str, str | int] = {"target": target.name} - if target.os is not None: - row["os"] = target.os - if target.env: - row["env"] = dict(target.env) - if target.artifact_tag is not None: - row["artifact-tag"] = target.artifact_tag - if target.release is not None: - row["release"] = target.release - return row - - -def tier_rows() -> dict[str, list[dict[str, str | int]]]: - """All rows, grouped by tier so the workflow gets one JSON per job.""" - out: dict[str, list[dict[str, str | int]]] = { - name: [] for name in TIER_OUTPUT_NAMES.values() - } - for target in TARGETS: - out[TIER_OUTPUT_NAMES[target.tier]].append(to_matrix_row(target)) - return out - -def sanity() -> None: - """Fail loudly if the matrices drift from the full current set.""" - counts = {name: len(rows) for name, rows in tier_rows().items()} - assert counts == {"tier1": 9, "tier2": 28, "tier2_vm": 6}, counts +def emit_workflow_output() -> None: + """Print the test matrices, one `test__matrix=` line per job.""" + rows = {job: [] for job in CiJob} for target in TARGETS: - assert target.vm == (target.tier == Tier.T3) + row: dict[str, str | int] = { + "target": target.name, + "os": target.os, + "env": dict(target.env) or None, + "artifact-tag": target.artifact_tag, + "release": target.release, + } + rows[target.ci_job()].append({k: v for k, v in row.items() if v is not None}) + for job, targets in rows.items(): + print(f"test_{job.value}_matrix={json.dumps(targets)}") def main() -> None: - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument( - "--sanity", action="store_true", help="check the matrix is complete" - ) - args = parser.parse_args() - if args.sanity: - sanity() - sys.exit(0) - for name, rows in tier_rows().items(): - print(f"{name}={json.dumps(rows)}") + emit_workflow_output() if __name__ == "__main__": From b4880ec0884f9618a6fe72a8a8220fdba7d9df62 Mon Sep 17 00:00:00 2001 From: LusterSourav <282348889+LusterSourav@users.noreply.github.com> Date: Thu, 6 Aug 2026 16:30:57 +0530 Subject: [PATCH 10/11] match compiler-builtins: use generate-matrix subcommand --- .github/workflows/ci.yaml | 2 +- ci/ci-util.py | 19 +++++++++++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 31f1c4f3034f..5102040eda11 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -44,7 +44,7 @@ jobs: id: vars run: | set -eo pipefail - python3 ci/ci-util.py | tee "$GITHUB_OUTPUT" + python3 ci/ci-util.py generate-matrix | tee "$GITHUB_OUTPUT" style_check: name: Style check diff --git a/ci/ci-util.py b/ci/ci-util.py index 8523f4545d56..4b796a0b5a34 100644 --- a/ci/ci-util.py +++ b/ci/ci-util.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 -"""Emit the test matrices for the CI workflow as GitHub Actions output. +"""Utilities for CI. +Generate the test matrices for the CI workflow as GitHub Actions output. Each tier is printed on its own line as `test__matrix=` so the workflow can feed it straight into a `matrix: include` block. Merge queues, schedules and manual runs always get every target; there is no file @@ -8,6 +9,7 @@ """ import json +import sys from dataclasses import dataclass, field from enum import IntEnum, StrEnum @@ -165,7 +167,20 @@ def emit_workflow_output() -> None: def main() -> None: - emit_workflow_output() + match sys.argv[1:]: + case ["generate-matrix"]: + emit_workflow_output() + case ["--help" | "-h"] | []: + print( + """usage: ci/ci-util.py + +COMMAND: + generate-matrix + Print the test matrix for each CI job as `test__matrix=`.""" + ) + case _: + print(f"error: unknown command {sys.argv[1:]}", file=sys.stderr) + sys.exit(1) if __name__ == "__main__": From be8c7ffdb49637c7bb3a57ae42e8e7d19a75c29c Mon Sep 17 00:00:00 2001 From: LusterSourav <282348889+LusterSourav@users.noreply.github.com> Date: Tue, 11 Aug 2026 20:55:28 +0530 Subject: [PATCH 11/11] ci: use current musl env var names in generated matrices --- ci/ci-util.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ci/ci-util.py b/ci/ci-util.py index 4b796a0b5a34..0cffb76085eb 100644 --- a/ci/ci-util.py +++ b/ci/ci-util.py @@ -73,7 +73,7 @@ def ci_job(self) -> CiJob: TestTarget( "aarch64-unknown-linux-musl", tier=Tier.T2, - env={"TEST_MUSL_V1_2_3": 1}, + env={"TEST_MUSL_V1_2": 1}, artifact_tag="new-musl", ), TestTarget("arm-linux-androideabi", tier=Tier.T2), @@ -82,7 +82,7 @@ def ci_job(self) -> CiJob: TestTarget( "arm-unknown-linux-musleabihf", tier=Tier.T2, - env={"TEST_MUSL_V1_2_3": 1}, + env={"TEST_MUSL_V1_2": 1}, artifact_tag="new-musl", ), # FIXME(#4297): spurious test failures, keep disabled @@ -91,7 +91,7 @@ def ci_job(self) -> CiJob: TestTarget( "i686-unknown-linux-musl", tier=Tier.T2, - env={"TEST_MUSL_V1_2_3": 1}, + env={"TEST_MUSL_V1_2": 1}, artifact_tag="new-musl", ), TestTarget("loongarch64-unknown-linux-gnu", tier=Tier.T2), @@ -99,7 +99,7 @@ def ci_job(self) -> CiJob: TestTarget( "loongarch64-unknown-linux-musl", tier=Tier.T2, - env={"TEST_MUSL_V1_2_3": 1}, + env={"TEST_MUSL_V1_2": 1}, artifact_tag="new-musl", ), TestTarget("powerpc64-unknown-linux-gnu", tier=Tier.T2), @@ -107,7 +107,7 @@ def ci_job(self) -> CiJob: TestTarget( "powerpc64-unknown-linux-musl", tier=Tier.T2, - env={"RUST_LIBC_UNSTABLE_MUSL_V1_2_3": 1}, + env={"RUST_LIBC_UNSTABLE_MUSL_V1_2": 1}, artifact_tag="new-musl", ), TestTarget("powerpc64le-unknown-linux-gnu", tier=Tier.T2), @@ -115,7 +115,7 @@ def ci_job(self) -> CiJob: TestTarget( "powerpc64le-unknown-linux-musl", tier=Tier.T2, - env={"TEST_MUSL_V1_2_3": 1}, + env={"TEST_MUSL_V1_2": 1}, artifact_tag="new-musl", ), TestTarget("riscv64gc-unknown-linux-gnu", tier=Tier.T2), @@ -133,7 +133,7 @@ def ci_job(self) -> CiJob: TestTarget( "x86_64-unknown-linux-musl", tier=Tier.T2, - env={"TEST_MUSL_V1_2_3": 1}, + env={"TEST_MUSL_V1_2": 1}, artifact_tag="new-musl", ), # FIXME: some items in `src/unix/mod.rs` aren't defined on redox yet