From 1a474bc4c3f1093e89b93e8700a5f9131fac5620 Mon Sep 17 00:00:00 2001 From: Winter Date: Fri, 16 May 2025 17:17:47 -0400 Subject: [PATCH 1/7] pkgs/top-level/release-outpaths: explicitly enable unfree packages This codifies what we've been doing by setting `includeBroken` to `true`, which is evaluating unfree packages anyways. I don't see a reason to not eval them, so this makes it so that we can do it when we set `includeBroken` to false in the next commit. --- pkgs/top-level/release-outpaths.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/top-level/release-outpaths.nix b/pkgs/top-level/release-outpaths.nix index 8ca14fc950076..731c65da73e3e 100644 --- a/pkgs/top-level/release-outpaths.nix +++ b/pkgs/top-level/release-outpaths.nix @@ -27,7 +27,7 @@ let config = { allowAliases = false; allowBroken = includeBroken; - allowUnfree = false; + allowUnfree = true; allowInsecurePredicate = x: true; checkMeta = checkMeta; From 6fa8d16a1b981a87f6591e2a46d26cb995125099 Mon Sep 17 00:00:00 2001 From: Winter Date: Tue, 13 May 2025 00:02:38 -0400 Subject: [PATCH 2/7] ci/eval: don't evaluate packages marked as broken We really can't expect packages that are marked as broken to evaluate, and *especially* not on unsupported platforms. For context, we were attempting to eval them *past* the broken throw previously, which caused fun side effects like [0], but given that the next change will cause us to eval packages regardless of `meta.platforms` as a sanity check, this is required anyways (e.g. `airtame` needs `libgcc`, which is `null` on Darwin). [0]: https://github.com/NixOS/nixpkgs/issues/355847#issuecomment-2878873137 --- ci/eval/default.nix | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ci/eval/default.nix b/ci/eval/default.nix index fff771054450e..d6f94926742fe 100644 --- a/ci/eval/default.nix +++ b/ci/eval/default.nix @@ -73,7 +73,9 @@ let # The number of attributes per chunk, see ./README.md for more info. chunkSize, checkMeta ? true, - includeBroken ? true, + + # Don't try to eval packages marked as broken. + includeBroken ? false, # Whether to just evaluate a single chunk for quick testing quickTest ? false, }: From 03682f30e5441521328267773b55bfb1470f7310 Mon Sep 17 00:00:00 2001 From: Winter Date: Tue, 13 May 2025 00:02:38 -0400 Subject: [PATCH 3/7] ci/eval/release-checks: init This change reimplements `pkgs/top-level/nixpkgs-basic-release-checks.nix` using the chunked evaluator function, in order for it to be efficient enough to run in CI. --- ci/eval/default.nix | 57 ++++++++++++++-- ci/eval/release-checks.nix | 66 +++++++++++++++++++ pkgs/top-level/release-attrpaths-parallel.nix | 8 ++- pkgs/top-level/release-outpaths.nix | 5 +- pkgs/top-level/release.nix | 17 ++++- 5 files changed, 143 insertions(+), 10 deletions(-) create mode 100644 ci/eval/release-checks.nix diff --git a/ci/eval/default.nix b/ci/eval/default.nix index d6f94926742fe..63e8aaf36bd9c 100644 --- a/ci/eval/default.nix +++ b/ci/eval/default.nix @@ -35,17 +35,23 @@ let supportedSystems = builtins.fromJSON (builtins.readFile ../supportedSystems.json); + abortSource = builtins.toFile "dont-use-nix-path-in-nixpkgs.nix" '' + builtins.abort "Illegal use of in Nixpkgs" + ''; + attrpathsSuperset = { evalSystem, + nixpkgsPath ? nixpkgs, }: runCommand "attrpaths-superset.json" { - src = nixpkgs; + src = nixpkgsPath; nativeBuildInputs = [ nix time ]; + env.NIX_PATH = "nixpkgs=${abortSource}"; } '' export NIX_STATE_DIR=$(mktemp -d) @@ -69,13 +75,22 @@ let # because `--argstr system` would only be passed to the ci/default.nix file! evalSystem, # The path to the `paths.json` file from `attrpathsSuperset` - attrpathFile ? "${attrpathsSuperset { inherit evalSystem; }}/paths.json", + attrpathFile ? "${attrpathsSuperset { inherit evalSystem nixpkgsPath; }}/paths.json", + nixpkgsPath ? nixpkgs, # The number of attributes per chunk, see ./README.md for more info. chunkSize, checkMeta ? true, # Don't try to eval packages marked as broken. includeBroken ? false, + + # This is a misnomer, as we still catch and detect packages that aren't in a + # package's `meta.platforms`, but we still want to try and eval it to make + # sure that we can even get to the unsupported `throw`. (See + # https://github.com/NixOS/nixpkgs/pull/406207 as an example where the broken + # `throw` wasn't reached, therefore breaking `nixpkgs-review`.) + includeUnsupported ? true, + # Whether to just evaluate a single chunk for quick testing quickTest ? false, }: @@ -93,12 +108,13 @@ let set +e command time -o "$outputDir/timestats/$myChunk" \ -f "Chunk $myChunk on $system done [%MKB max resident, %Es elapsed] %C" \ - nix-env -f "${nixpkgs}/pkgs/top-level/release-attrpaths-parallel.nix" \ + nix-env -f "${nixpkgsPath}/pkgs/top-level/release-attrpaths-parallel.nix" \ --eval-system "$system" \ --option restrict-eval true \ --option allow-import-from-derivation false \ --query --available \ --no-name --attr-path --out-path \ + --meta --json \ --show-trace \ --arg chunkSize "$chunkSize" \ --arg myChunk "$myChunk" \ @@ -106,7 +122,8 @@ let --arg systems "[ \"$system\" ]" \ --arg checkMeta ${lib.boolToString checkMeta} \ --arg includeBroken ${lib.boolToString includeBroken} \ - -I ${nixpkgs} \ + --arg includeUnsupported ${lib.boolToString includeUnsupported} \ + -I ${nixpkgsPath} \ -I ${attrpathFile} \ > "$outputDir/result/$myChunk" \ 2> "$outputDir/stderr/$myChunk" @@ -134,6 +151,7 @@ let ]; env = { inherit evalSystem chunkSize; + NIX_PATH = "nixpkgs=${abortSource}"; }; } '' @@ -192,7 +210,22 @@ let # Make sure the glob doesn't break when there's no files shopt -s nullglob - cat "$chunkOutputDir"/result/* > $out/paths + + cat "$chunkOutputDir"/result/* | jq -r ' + to_entries[] + | select(.value.meta.unsupported | not) + | .key + " " + + .value.outputs as $outputs + | $outputs + | to_entries + | map(select(.key != "out") | .key + "=" + .value) + | join(";") + + if $outputs.out then + (if $outputs | length == 1 then "" else ";" end) + $outputs.out + else + "" + end + ' > $out/paths cat "$chunkOutputDir"/stats/* > $out/stats.jsonstream ''; @@ -278,6 +311,16 @@ let ; }; + releaseChecks = import ./release-checks.nix { + inherit + lib + runCommand + nixpkgs + singleSystem + linkFarm + ; + }; + full = { # Whether to evaluate on a specific set of systems, by default all are evaluated @@ -303,11 +346,11 @@ let in { inherit - attrpathsSuperset singleSystem combine compare - # The above three are used by separate VMs in a GitHub workflow, + releaseChecks + # The above four are used by separate VMs in a GitHub workflow, # while the below is intended for testing on a single local machine full ; diff --git a/ci/eval/release-checks.nix b/ci/eval/release-checks.nix new file mode 100644 index 0000000000000..209704c45c193 --- /dev/null +++ b/ci/eval/release-checks.nix @@ -0,0 +1,66 @@ +{ + lib, + runCommand, + nixpkgs, + singleSystem, + linkFarm, +}: + +let + nixpkgs' = builtins.path { + name = "nixpkgs-prime"; + path = nixpkgs; + }; +in +{ + evalSystem, + chunkSize, + firstEval ? singleSystem { inherit evalSystem chunkSize; }, + secondEval ? singleSystem { + inherit evalSystem chunkSize; + nixpkgsPath = nixpkgs'; + }, +}: + +let + checks = { + badFiles = runCommand "bad-files-check" { } '' + badFiles=$(find ${nixpkgs}/pkgs -type f -name '*.nix' -print | xargs grep -l '^[^#]* to refer to itself." + echo "The offending files: $badFiles" + exit 1 + fi + + touch "$out" + ''; + + conflictingPaths = runCommand "conflicting-files-check" { } '' + conflictingPaths=$(find ${nixpkgs} | awk '{ print $1 " " tolower($1) }' | sort -k2 | uniq -D -f 1 | cut -d ' ' -f 1) + if [[ -n $conflictingPaths ]]; then + echo "Files in nixpkgs must not vary only by case" + echo "The offending paths: $conflictingPaths" + exit 1 + fi + + touch "$out" + ''; + + evalPurity = runCommand "eval-purity-check" { } '' + if ! diff -u ${firstEval}/paths ${secondEval}/paths; then + echo + echo "Error: Nixpkgs evaluation depends on Nixpkgs path" + exit 1 + fi + + touch "$out" + ''; + }; +in +(linkFarm "release-checks-${evalSystem}" ( + lib.mapAttrsToList (_: check: { + inherit (check) name; + path = check; + }) checks +)) +// checks diff --git a/pkgs/top-level/release-attrpaths-parallel.nix b/pkgs/top-level/release-attrpaths-parallel.nix index 46d10c6a95041..fdc1ab03d5b03 100644 --- a/pkgs/top-level/release-attrpaths-parallel.nix +++ b/pkgs/top-level/release-attrpaths-parallel.nix @@ -9,6 +9,7 @@ myChunk, checkMeta, includeBroken, + includeUnsupported ? false, systems, }: @@ -18,7 +19,12 @@ let unfiltered = import ./release-outpaths.nix { inherit path; - inherit checkMeta includeBroken systems; + inherit + checkMeta + includeBroken + includeUnsupported + systems + ; }; # Turns the unfiltered recursive attribute set into one that is limited to myAttrpaths diff --git a/pkgs/top-level/release-outpaths.nix b/pkgs/top-level/release-outpaths.nix index 731c65da73e3e..2ac55148a97de 100644 --- a/pkgs/top-level/release-outpaths.nix +++ b/pkgs/top-level/release-outpaths.nix @@ -12,6 +12,9 @@ # used by pkgs/top-level/release-attrnames-superset.nix attrNamesOnly ? false, + # used by pkgs/top-level/release-attrpaths-parallel.nix + includeUnsupported ? false, + # Set this to `null` to build for builtins.currentSystem only systems ? builtins.fromJSON (builtins.readFile ../../ci/supportedSystems.json), }: @@ -21,7 +24,7 @@ let import (path + "/pkgs/top-level/release.nix") # Compromise: accuracy vs. resources needed for evaluation. { - inherit attrNamesOnly; + inherit attrNamesOnly includeUnsupported; supportedSystems = if systems == null then [ builtins.currentSystem ] else systems; nixpkgsArgs = { config = { diff --git a/pkgs/top-level/release.nix b/pkgs/top-level/release.nix index 7126252d79760..7ca42a17166f6 100644 --- a/pkgs/top-level/release.nix +++ b/pkgs/top-level/release.nix @@ -62,6 +62,16 @@ # pkgs/top-level/. # attrNamesOnly ? false, + + # This flag, if set to true, will inhibit the use of + # `release-lib.packagePlatforms`, instead always + # returning `supportedSystems`. This is so that + # we can properly test that unsupported platforms + # eval up to the point of being marked as unsupported. + # + # Like `attrNamesOnly`, the behavior of this flag may + # change at any time. + includeUnsupported ? false, }: let @@ -348,7 +358,12 @@ let jobs = let packagePlatforms = release-lib.recursiveMapPackages ( - if attrNamesOnly then id else release-lib.getPlatforms + if attrNamesOnly then + id + else if includeUnsupported then + drv: drv.meta.hydraPlatforms or supportedSystems + else + release-lib.getPlatforms ); packageJobs = packagePlatforms pkgs // { haskell.compiler = packagePlatforms pkgs.haskell.compiler; From c5ecf2ed1ed2654cd84619d0f0d005b358229240 Mon Sep 17 00:00:00 2001 From: Winter Date: Wed, 14 May 2025 15:57:55 -0400 Subject: [PATCH 4/7] workflows/release-checks: init --- .github/workflows/release-checks.yml | 142 +++++++++++++++++++++++++++ ci/eval/release-checks.nix | 3 + 2 files changed, 145 insertions(+) create mode 100644 .github/workflows/release-checks.yml diff --git a/.github/workflows/release-checks.yml b/.github/workflows/release-checks.yml new file mode 100644 index 0000000000000..e8e5b40ecde59 --- /dev/null +++ b/.github/workflows/release-checks.yml @@ -0,0 +1,142 @@ +name: Release checks + +on: + pull_request: + paths: + - .github/workflows/release-checks.yml + pull_request_target: + +permissions: {} + +jobs: + get-merge-commit: + uses: ./.github/workflows/get-merge-commit.yml + + outpaths: + name: Outpaths + runs-on: ubuntu-24.04-arm + needs: [ get-merge-commit ] + strategy: + fail-fast: false + matrix: + system: ${{ fromJSON(needs.get-merge-commit.outputs.systems) }} + steps: + - name: Enable swap + run: | + sudo fallocate -l 10G /swap + sudo chmod 600 /swap + sudo mkswap /swap + sudo swapon /swap + + - name: Check out the PR at the test merge commit + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + ref: ${{ needs.get-merge-commit.outputs.mergedSha }} + path: nixpkgs + + - name: Install Nix + uses: cachix/install-nix-action@526118121621777ccd86f79b04685a9319637641 # v31 + with: + extra_nix_config: sandbox = true + + - name: Evaluate the ${{ matrix.system }} output paths for all derivation attributes from a different path + env: + MATRIX_SYSTEM: ${{ matrix.system }} + run: | + nix-build nixpkgs/ci -A eval.releaseChecks.secondEval \ + --argstr evalSystem "$MATRIX_SYSTEM" \ + --arg chunkSize 10000 + # If it uses too much memory, slightly decrease chunkSize + + - name: Upload the output paths and eval stats + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: intermediate-${{ matrix.system }} + path: result + + release-checks: + name: Release checks + runs-on: ubuntu-24.04-arm + needs: [ outpaths, get-merge-commit ] + steps: + - name: Download output paths and eval stats from second eval for all systems + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 + with: + pattern: intermediate-* + path: second + + - name: Check out the PR at the test merge commit + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + ref: ${{ needs.get-merge-commit.outputs.mergedSha }} + fetch-depth: 2 + path: nixpkgs + + - name: Install Nix + uses: cachix/install-nix-action@526118121621777ccd86f79b04685a9319637641 # v31 + with: + extra_nix_config: sandbox = true + + - name: Get first eval run id + id: evalRunId + run: | + # Get the latest eval.yml workflow run for the head commit + if ! run=$(gh api --method GET /repos/"$REPOSITORY"/actions/workflows/eval.yml/runs \ + -f head_sha="$HEAD_SHA" \ + --jq '.workflow_runs | sort_by(.run_started_at) | .[-1]') \ + || [[ -z "$run" ]]; then + echo "Could not find an eval.yml workflow run for $HEAD_SHA, cannot make comparison" + exit 1 + fi + echo "First eval is $(jq .html_url <<< "$run")" + runId=$(jq .id <<< "$run") + conclusion=$(jq -r .conclusion <<< "$run") + + while [[ "$conclusion" == null || "$conclusion" == "" ]]; do + echo "Workflow not done, waiting 10 seconds before checking again" + sleep 10 + conclusion=$(gh api /repos/"$REPOSITORY"/actions/runs/"$runId" --jq '.conclusion') + done + + if [[ "$conclusion" != "success" ]]; then + echo "Workflow was not successful (conclusion: $conclusion), cannot perform release checks" + exit 1 + fi + + echo "evalRunId=$runId" >> "$GITHUB_OUTPUT" + env: + REPOSITORY: ${{ github.repository }} + HEAD_SHA: ${{ github.event.pull_request.head.sha }} + GH_TOKEN: ${{ github.token }} + + - name: Download output paths and eval stats from first eval for all systems + uses: actions/download-artifact@v4 + if: steps.evalRunId.outputs.evalRunId + with: + pattern: intermediate-* + path: first + github-token: ${{ github.token }} + run-id: ${{ steps.evalRunId.outputs.evalRunId }} + + - name: Run release checks + if: steps.evalRunId.outputs.evalRunId + run: | + failed= + for system in $(echo -n "$SYSTEMS" | jq -r ".[]"); do + echo "::group::$system" + + nix-build nixpkgs/ci -A eval.releaseChecks \ + --argstr evalSystem "$system" \ + --arg firstEval "./first/intermediate-$system" \ + --arg secondEval "./second/intermediate-$system" \ + --arg chunkSize 10000 || failed=1 + + echo "::endgroup::" + done + + if [[ $failed ]]; then + echo "Release checks failed for at least one system" + exit 1 + fi + env: + SYSTEMS: ${{ needs.get-merge-commit.outputs.systems }} diff --git a/ci/eval/release-checks.nix b/ci/eval/release-checks.nix index 209704c45c193..5dc61f942ada9 100644 --- a/ci/eval/release-checks.nix +++ b/ci/eval/release-checks.nix @@ -64,3 +64,6 @@ in }) checks )) // checks +// { + inherit secondEval; +} From 45d186d14807ecb94b283be7a626b123bcfe03de Mon Sep 17 00:00:00 2001 From: Winter Date: Tue, 13 May 2025 18:32:37 -0400 Subject: [PATCH 5/7] OWNERS: add winterqt to `.github/workflows` and `ci/` I feel like I've done enough work on this that I can effectively review any changes going forward. :) --- ci/OWNERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ci/OWNERS b/ci/OWNERS index 7ba49641ca886..0ce8e77368726 100644 --- a/ci/OWNERS +++ b/ci/OWNERS @@ -15,11 +15,11 @@ # CI /.github/*_TEMPLATE* @SigmaSquadron -/.github/workflows @NixOS/Security @Mic92 @zowoq @infinisil @azuwis @wolfgangwalther +/.github/workflows @NixOS/Security @Mic92 @zowoq @infinisil @azuwis @winterqt @wolfgangwalther /.github/workflows/check-format.yml @infinisil @wolfgangwalther /.github/workflows/codeowners-v2.yml @infinisil @wolfgangwalther /.github/workflows/nixpkgs-vet.yml @infinisil @philiptaron @wolfgangwalther -/ci @infinisil @philiptaron @NixOS/Security @wolfgangwalther +/ci @infinisil @philiptaron @NixOS/Security @winterqt @wolfgangwalther /ci/OWNERS @infinisil @philiptaron # Development support From d46ae8f6a200dd6f26ece2ad4ddcbe80218ddf9f Mon Sep 17 00:00:00 2001 From: Winter Date: Tue, 13 May 2025 21:44:28 -0400 Subject: [PATCH 6/7] ci/eval/compare: don't die if there aren't enough stats to compare Ran into this when comparing two `quickTest` evals. --- ci/eval/compare/cmp-stats.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ci/eval/compare/cmp-stats.py b/ci/eval/compare/cmp-stats.py index 0ef9c773163a9..669f13cc96b64 100644 --- a/ci/eval/compare/cmp-stats.py +++ b/ci/eval/compare/cmp-stats.py @@ -122,6 +122,10 @@ def perform_pairwise_tests(before_metrics: dict, after_metrics: dict) -> pd.Data "t_stat": t_stat }) + if len(results) == 0: + print("⚠️ Skipping comparison: we don't have enough results to compare. (Run evals without `quickTest` set to compare stats.)") + exit(0) + df = pd.DataFrame(results).sort_values("p_value") return df From be3b40fe0c2d5d1bb69b4bf3611967394e197f6d Mon Sep 17 00:00:00 2001 From: Winter Date: Sat, 17 May 2025 16:31:07 -0400 Subject: [PATCH 7/7] workflows/get-merge-commit: only grab merge commit once Currently, the `get-merge-commit` job is inherently racey, as we can't control whether these jobs will run at the same time, so it's possible that the merge/target commits will change if the target gets updated in between `get-merge-commit` runs. This is bad enough in theory (and maybe has even caused some oddities in the CI setup in the past), but it essentially makes the release checks untentable on days where lots of people are merging things. So, this change fixes it by electing the eval workflow as the "leader," and having all other jobs wait for it to determine which commits will be checked. --- .github/workflows/eval.yml | 2 + .github/workflows/get-merge-commit.yml | 63 ++++++++++++++++++++++++-- 2 files changed, 62 insertions(+), 3 deletions(-) diff --git a/.github/workflows/eval.yml b/.github/workflows/eval.yml index ce9378e62320c..fcdfdc7d60cf7 100644 --- a/.github/workflows/eval.yml +++ b/.github/workflows/eval.yml @@ -21,6 +21,8 @@ permissions: {} jobs: get-merge-commit: uses: ./.github/workflows/get-merge-commit.yml + with: + leader: true outpaths: name: Outpaths diff --git a/.github/workflows/get-merge-commit.yml b/.github/workflows/get-merge-commit.yml index edbda3e040eb5..18ffa2b251f89 100644 --- a/.github/workflows/get-merge-commit.yml +++ b/.github/workflows/get-merge-commit.yml @@ -5,6 +5,14 @@ on: paths: - .github/workflows/get-merge-commit.yml workflow_call: + inputs: + leader: + description: "Whether this job should get the merge commit, or wait for another job to do so" + type: boolean + leaderName: + description: "The name of the leader workflow" + type: string + default: "eval.yml" outputs: mergedSha: description: "The merge commit SHA" @@ -22,8 +30,8 @@ jobs: resolve-merge-commit: runs-on: ubuntu-24.04-arm outputs: - mergedSha: ${{ steps.merged.outputs.mergedSha }} - targetSha: ${{ steps.merged.outputs.targetSha }} + mergedSha: ${{ steps.getCommits.outputs.mergedSha }} + targetSha: ${{ steps.getCommits.outputs.targetSha }} systems: ${{ steps.systems.outputs.systems }} steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 @@ -32,6 +40,7 @@ jobs: sparse-checkout: ci - name: Check if the PR can be merged and get the test merge commit + if: inputs.leader == true id: merged env: GH_TOKEN: ${{ github.token }} @@ -44,7 +53,7 @@ jobs: pull_request*) if commits=$(base/ci/get-merge-commit.sh ${{ github.repository }} ${{ github.event.number }}); then echo -e "Checking the commits:\n$commits" - echo "$commits" >> "$GITHUB_OUTPUT" + echo "$commits" >> checked-commits else # Skipping so that no notifications are sent echo "Skipping the rest..." @@ -52,6 +61,54 @@ jobs: ;; esac + - name: Upload commits to check as an artifact + if: inputs.leader == true + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: checked-commits + path: checked-commits + + - name: Get leader workflow's run ID + id: getLeaderRun + timeout-minutes: 5 + if: inputs.leader == false + env: + LEADER: ${{ inputs.leaderName }} + GH_TOKEN: ${{ github.token }} + REPOSITORY: ${{ github.repository }} + HEAD_SHA: ${{ github.event.pull_request.head.sha }} + run: | + if ! run=$(gh api --method GET /repos/"$REPOSITORY"/actions/workflows/"$LEADER"/runs \ + -f head_sha="$HEAD_SHA" \ + --jq '.workflow_runs | sort_by(.run_started_at) | .[-1]') \ + || [[ -z "$run" ]]; then + echo "Could not find a leader ($LEADER) workflow run for $HEAD_SHA" + exit 1 + fi + echo "Leader is $(jq .html_url <<< "$run")" + runId=$(jq .id <<< "$run") + artifactCount=$(gh api --method GET /repos/"$REPOSITORY"/actions/runs/"$runId"/artifacts --jq '.total_count') + while (( artifactCount < 1 )); do + echo "Leader workflow didn't get merge commit yet, waiting 10 seconds before checking again" + sleep 10 + artifactCount=$(gh api --method GET /repos/"$REPOSITORY"/actions/runs/"$runId"/artifacts --jq '.total_count') + done + + echo "leaderRunId=$runId" >> "$GITHUB_OUTPUT" + + - name: Download commit hashes from leader + if: inputs.leader == false + uses: actions/download-artifact@v4 + with: + name: checked-commits + github-token: ${{ github.token }} + run-id: ${{ steps.getLeaderRun.outputs.leaderRunId }} + + - name: Output commits + id: getCommits + run: | + cat checked-commits >> "$GITHUB_OUTPUT" + - name: Load supported systems id: systems run: |