From 3e5a9bde4228de6b09e52ce3014e7c21c2293799 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Tue, 4 Aug 2026 10:54:15 -0400 Subject: [PATCH 1/3] ci: Dynamically re-gate heavy tests on PRs when no merge queue is active Our CI jobs were wired to the merge queue semantics, I broke this when dropping the merge queue requirement. xref #2177 Change the logic to detect a merge queue dynamically, then if we decide to flip back on the queue things should work the same as before. But here we need to run the tests. Also while we're here make use of the (new-ish) `ubuntu-slim` for jobs that are just computing state as that's cheaper and should be quicker to schedule. Assisted-by: AI Signed-off-by: Colin Walters --- .github/workflows/ci.yml | 72 ++++++++++++++++++++++++++++++++-------- 1 file changed, 59 insertions(+), 13 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9fa42e5f8..a9fc8d037 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,22 +43,58 @@ jobs: # Determine the OS matrix for CI jobs based on context: # - merge_group / workflow_dispatch / ci/merge label: all OSes # - ci/tier-1 label: centos-10 only (fast feedback on the primary target) - # - plain PR: no heavy jobs + # - PR with no merge queue configured: all OSes (the PR is the only gate, + # so it must run the full suite; see the merge-queue check below) + # - plain PR (merge queue active): no heavy jobs + # - push to main: no heavy jobs (already verified pre-merge; a push here + # is a record of what merged, not something new to gate) compute-ci-level: - runs-on: ubuntu-24.04 + # Cheap metadata check (gh api + jq) — no need for a full VM. + runs-on: ubuntu-slim outputs: package_os_matrix: ${{ steps.matrix.outputs.package_os_matrix }} integration_os_matrix: ${{ steps.matrix.outputs.integration_os_matrix }} upgrade_os_matrix: ${{ steps.matrix.outputs.upgrade_os_matrix }} run_heavy: ${{ steps.matrix.outputs.run_heavy }} + merge_queue_enabled: ${{ steps.merge-queue.outputs.enabled }} steps: + # Detect at runtime whether `main` is currently protected by a GitHub + # merge queue (see https://github.com/bootc-dev/bootc/issues/2177). + # The tiered CI below only makes sense with a queue: it lets heavy jobs + # run for feedback on PRs without gating merges, because the queue + # re-verifies everything before landing. Without a queue, a PR is the + # *only* gate, so the heavy suite must be required directly on PRs + # again. Checking this dynamically means re-enabling the queue later + # doesn't require another manual flip of this workflow to go back to + # the tiered behavior. + # + # A branch's effective rules (aggregated across org- and repo-level + # rulesets) are public, unauthenticated info; a `merge_queue` rule is + # present only while a queue is actually configured for the branch. + - name: Check for a merge_queue rule on main + id: merge-queue + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + # Let this fail outright if the API call fails, rather than + # guessing: required-checks-heavy (below) needs this job, so we + # never silently skip testing on a transient API hiccup. + rules=$(gh api "repos/${{ github.repository }}/rules/branches/main") + if echo "$rules" | jq -e 'any(.[]; .type == "merge_queue")' > /dev/null; then + echo "enabled=true" >> "$GITHUB_OUTPUT" + else + echo "enabled=false" >> "$GITHUB_OUTPUT" + fi + - name: Compute OS matrices id: matrix run: | LABELS='${{ toJson(github.event.pull_request.labels.*.name) }}' EVENT='${{ github.event_name }}' + MERGE_QUEUE_ENABLED='${{ steps.merge-queue.outputs.enabled }}' if [[ "$EVENT" == "merge_group" || "$EVENT" == "workflow_dispatch" ]] \ + || [[ "$EVENT" == "pull_request" && "$MERGE_QUEUE_ENABLED" != "true" ]] \ || echo "$LABELS" | jq -e 'index("ci/merge")' > /dev/null; then # Full suite: all OSes echo 'package_os_matrix=["fedora-43","fedora-44","fedora-45","centos-9","centos-10"]' >> "$GITHUB_OUTPUT" @@ -572,14 +608,20 @@ jobs: name: container-export-test-${{ env.ARCH }} path: target/anaconda-test/*.log - # Runs only in merge_group / workflow_dispatch and gates the full heavy suite. - # Skipped on PRs, so required-checks (below) sees it as 'skipped' == success there. + # Gates the full heavy suite. Runs in merge_group / workflow_dispatch, and + # also directly on PRs whenever compute-ci-level found no merge queue + # active (see the merge-queue check in that job) — in that case a PR is + # the only gate, so this must actually require the heavy jobs rather than + # being skipped. + # (Deliberately not extended to plain `push`: a push to main is a record of + # what already merged, not something new to gate.) # Uses always() so it still reports a failure when an upstream heavy job failed, # rather than being skipped along with it. - required-checks-merge: - if: ${{ always() && (github.event_name == 'merge_group' || github.event_name == 'workflow_dispatch') }} + required-checks-heavy: + if: ${{ always() && (github.event_name == 'merge_group' || github.event_name == 'workflow_dispatch' || (github.event_name == 'pull_request' && needs.compute-ci-level.outputs.merge_queue_enabled != 'true')) }} needs: [compute-ci-level, cargo-deny, validate, install-tests, docs, package, test-integration, test-upgrade, test-baseconfigs, test-container-export] - runs-on: ubuntu-latest + # Cheap aggregation (jq only) — no need for a full VM. + runs-on: ubuntu-slim steps: - name: Check all jobs env: @@ -592,14 +634,18 @@ jobs: fi # Sentinel job — configure this single name in repo required-status-checks settings. - # On PRs: gates only the light always-run jobs; required-checks-merge is skipped - # (treated as success) so ci/merge heavy jobs run for feedback but don't block - # merge-queue entry — those jobs run again in the queue anyway with fresh artifacts. - # In merge_group: required-checks-merge has already verified the full suite above. + # With a merge queue active: gates only the light always-run jobs on PRs; + # required-checks-heavy is skipped there (treated as success) so ci/merge + # heavy jobs run for feedback but don't block merge-queue entry — those jobs + # run again in the queue anyway with fresh artifacts. In merge_group, + # required-checks-heavy has already verified the full suite above. + # Without a merge queue: required-checks-heavy runs and gates directly on + # PRs too, since there's no queue left to re-verify anything afterwards. required-checks: if: always() - needs: [compute-ci-level, validate, cargo-deny, docs, required-checks-merge] - runs-on: ubuntu-latest + needs: [compute-ci-level, validate, cargo-deny, docs, required-checks-heavy] + # Cheap aggregation (jq only) — no need for a full VM. + runs-on: ubuntu-slim steps: - name: Check required jobs env: From a92d62a6dea72aea1c48f5dfa2d59909f4fd73fe Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Wed, 5 Aug 2026 15:56:34 -0400 Subject: [PATCH 2/3] tmt: Fix broken ./bootc invocation in UKI dumpfile test Assisted-by: AI Signed-off-by: Colin Walters --- tmt/tests/booted/test-composefs-uki-dumpfile.nu | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmt/tests/booted/test-composefs-uki-dumpfile.nu b/tmt/tests/booted/test-composefs-uki-dumpfile.nu index c46b06902..fc5e4e612 100644 --- a/tmt/tests/booted/test-composefs-uki-dumpfile.nu +++ b/tmt/tests/booted/test-composefs-uki-dumpfile.nu @@ -38,7 +38,7 @@ def first_boot [] { let result = do { bootc switch --transport containers-storage localhost/dump-diff } | complete - let actual_digest = ./bootc internals cfs oci compute-id $"@(podman images --no-trunc | grep dump-diff | awk '{print $3}')" + let actual_digest = bootc internals cfs oci compute-id $"@(podman images --no-trunc | grep dump-diff | awk '{print $3}')" assert ($result.exit_code != 0) "bootc switch should fail" From 72428d1d9735b5e942e06afb28d4d14cb6de94d0 Mon Sep 17 00:00:00 2001 From: Pragyan Poudyal Date: Thu, 6 Aug 2026 14:23:12 +0530 Subject: [PATCH 3/3] tmt: disable composefs-uki-dumpfile test This test has some issues currently, especially in the upgrade path. Since this does not affect the install/update flows, disable this test Signed-off-by: Pragyan Poudyal --- tmt/tests/booted/test-composefs-uki-dumpfile.nu | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tmt/tests/booted/test-composefs-uki-dumpfile.nu b/tmt/tests/booted/test-composefs-uki-dumpfile.nu index fc5e4e612..8ba286364 100644 --- a/tmt/tests/booted/test-composefs-uki-dumpfile.nu +++ b/tmt/tests/booted/test-composefs-uki-dumpfile.nu @@ -6,9 +6,8 @@ use std assert use tap.nu -if not (tap is_composefs) { - exit 0 -} +# FIXME(Johan-Liebert1): This job is disabled for now +exit 0 # bootc status let st = bootc status --json | from json