From 2ba0fdeaf5357599ec97dd59f2e6e84852dac273 Mon Sep 17 00:00:00 2001 From: Zach Vorhies Date: Mon, 26 Oct 2026 06:28:24 -0700 Subject: [PATCH] ci(dylint): report the required Dylint check on merge_group (GEN-022) Branch protection requires the Dylint check from dylint.yml, which had no merge_group trigger, so a merge queue would stall waiting for it. Add the trigger (all jobs run unconditionally), allow it in ci.toml, end the queue run with the GEN-022 cache janitor, and pin the shape in tests. --- .github/workflows/dylint.yml | 36 +++++++++++++++++++++++++++++++++ ci.toml | 2 +- ci/test_fractional_workflows.py | 9 +++++++++ 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/.github/workflows/dylint.yml b/.github/workflows/dylint.yml index 18b115696..ef44b6a82 100644 --- a/.github/workflows/dylint.yml +++ b/.github/workflows/dylint.yml @@ -17,6 +17,9 @@ on: # Dylint compile cache that subsequent PRs are allowed to restore. push: branches: [main] + # GEN-022: branch protection requires the `Dylint` check, so a merge-queue + # run must report it too or the queue stalls. Every job runs unconditionally. + merge_group: # Auto-cancel superseded PR runs: pushing again to a feature branch # supersedes the in-flight run instead of queueing behind it. Non-PR @@ -274,3 +277,36 @@ jobs: run: | test "$POLICY" = success test "$FULL_DYLINT" = success + + # GEN-022 (forge-ci/ci.yml#405): a merge-queue run ends with the cache + # janitor, which needs every other job and never cancels a sweep. + queue-cache-janitor: + name: End-of-queue cache janitor + needs: [policy, dylint, gate] + if: always() && github.event_name == 'merge_group' + runs-on: ubuntu-24.04 + timeout-minutes: 5 + concurrency: + group: cache-janitor + cancel-in-progress: false + permissions: + contents: read + actions: write + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + sparse-checkout: ci.toml + sparse-checkout-cone-mode: false + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + repository: zackees/ci.yml + ref: b93b8c4a20ce3cd476c75a278ad01a31bde2438b + path: .ci-lint + persist-credentials: false + sparse-checkout: ci_lint + - name: Sweep caches + env: + GITHUB_TOKEN: ${{ github.token }} + PYTHONPATH: .ci-lint + run: python3 -P -m ci_lint cache janitor --repo . --default-branch main diff --git a/ci.toml b/ci.toml index a1a19ed3f..5f2ad3abc 100644 --- a/ci.toml +++ b/ci.toml @@ -135,7 +135,7 @@ cache-actions = { only-in = ".github/actions/setup" } "ci-test.yml" = ["workflow_call", "workflow_dispatch"] "ci-workflow-drift.yml" = ["workflow_dispatch", "push:main", "pull_request"] "crate-gate.yml" = ["push:main", "pull_request", "workflow_dispatch", "workflow_call"] -"dylint.yml" = ["workflow_dispatch", "workflow_call", "pull_request", "push:main"] +"dylint.yml" = ["workflow_dispatch", "workflow_call", "pull_request", "push:main", "merge_group"] "fmt.yml" = ["workflow_dispatch", "workflow_call", "push:main", "pull_request"] "lint-subprocess.yml" = ["workflow_dispatch", "push:main", "pull_request"] "loc-gate.yml" = ["push:main", "pull_request", "workflow_dispatch"] diff --git a/ci/test_fractional_workflows.py b/ci/test_fractional_workflows.py index 176e67300..17b09e85f 100644 --- a/ci/test_fractional_workflows.py +++ b/ci/test_fractional_workflows.py @@ -174,6 +174,15 @@ def test_full_matrix_matches_every_supported_board(self): self.assertNotIn("run_full", full["jobs"]["dylint"]["with"]) dylint = self.load("dylint.yml") self.assertEqual(["main"], dylint[True]["push"]["branches"]) + # GEN-022: the required `Dylint` check must report on merge-queue runs, + # and none of its jobs may be skipped there. + self.assertIn("merge_group", dylint[True]) + self.assertEqual("Dylint", dylint["jobs"]["gate"]["name"]) + self.assertEqual("always()", dylint["jobs"]["gate"]["if"]) + self.assertNotIn("if", dylint["jobs"]["policy"]) + dylint_janitor = dylint["jobs"]["queue-cache-janitor"] + self.assertEqual(set(dylint["jobs"]) - {"queue-cache-janitor"}, set(dylint_janitor["needs"])) + self.assertEqual("always() && github.event_name == 'merge_group'", dylint_janitor["if"]) setup = next( step for step in dylint["jobs"]["dylint"]["steps"] if step.get("uses", "").startswith("zackees/setup-soldr@")