Skip to content

Commit d6505f0

Browse files
authored
ci: run the in-repo PR mirror job instead of skipping it (#37)
2 parents c004c33 + 8656af5 commit d6505f0

1 file changed

Lines changed: 36 additions & 27 deletions

File tree

‎.github/workflows/ci.yml‎

Lines changed: 36 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -305,37 +305,37 @@ jobs:
305305
# automatically — no `pull_request` round-trip needed for non-fork
306306
# non-release PRs.
307307
required-check:
308-
# The name is conditional on purpose. On an in-repo feature PR the
309-
# `pull_request` run skips this job (the push run owns the status), and
310-
# a skipped job still posts a check run under its name. GitHub treats a
311-
# SKIPPED required check as satisfied — so if the skipped job were named
312-
# `✅ Required PR Check`, it would green-light the ruleset (and enable
313-
# auto-merge) while the push run's real mirror hadn't been created yet
314-
# (it only appears once `ci` finishes), letting a PR merge mid-test or
315-
# even override a red result. An expression name keeps the skipped job
316-
# off the required name: GitHub does not evaluate the name of a skipped
317-
# job, so it shows up as the raw expression text (still not the
318-
# required name), while every path that runs evaluates to
319-
# `✅ Required PR Check`. The condition is written out anyway so the
320-
# name stays correct if GitHub ever starts evaluating it, and must stay
321-
# identical to the `if:` below.
322-
name: ${{ (github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == true || github.event.pull_request.head.ref == 'next' || github.event.pull_request.head.ref == 'hotfixes') && '✅ Required PR Check' || '⏭️ Required PR Check (reported by the push run)' }}
323-
needs: ci
324-
# Mirror the `ci` job's gating exactly. The four cases that run:
308+
# Which name this job reports under is the whole point of it.
309+
#
310+
# The ruleset gates merges on `✅ Required PR Check`, so a check with that
311+
# name must only ever exist on a head SHA after the full test matrix for
312+
# that SHA has finished, mirroring its result. `needs: ci` guarantees the
313+
# timing: the job is only created once every Build & Test leg and the
314+
# coverage job are done.
315+
#
316+
# On an in-repo feature PR the `pull_request` run does not own the status
317+
# (the push run on the head branch does), so it must not post
318+
# `✅ Required PR Check` at all. Two traps rule out the obvious shapes:
319+
# - A job SKIPPED by `if:` still posts a check run under its name, and
320+
# GitHub treats a skipped required check as satisfied. Under the real
321+
# name that let PRs merge mid-test (CLDMV/slothlet#553).
322+
# - GitHub does not evaluate the `name:` of a skipped job, so a
323+
# conditional name on a skippable job shows up as the raw expression
324+
# text (#350).
325+
# So the job never skips: it runs on every path, the name expression is
326+
# always evaluated, and the in-repo PR path lands on a readable,
327+
# non-required name and passes as a no-op. The condition below is
328+
# repeated in the step's OWNS_STATUS and must stay identical. The paths
329+
# that own the status:
325330
# 1. push events (job needs CI run)
326331
# 2. fork PRs (push doesn't cover forks)
327332
# 3. release PRs from `next` → master/main (push covers SHA but commit-gate skips chore-bump)
328333
# 4. release PRs from `hotfixes` → master/main (same reason)
329-
# In-repo feature PRs targeting `next` / `hotfixes` skip on
330-
# pull_request — the push run on the head branch reports the status
331-
# on the SHA. See the `name:` above for why the skipped job is renamed.
332-
if: |
333-
always() && (
334-
github.event_name != 'pull_request' ||
335-
github.event.pull_request.head.repo.fork == true ||
336-
github.event.pull_request.head.ref == 'next' ||
337-
github.event.pull_request.head.ref == 'hotfixes'
338-
)
334+
name: ${{ (github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == true || github.event.pull_request.head.ref == 'next' || github.event.pull_request.head.ref == 'hotfixes') && '✅ Required PR Check' || '⏭️ Required PR Check (reported by the push run)' }}
335+
needs: ci
336+
# always(): run even when `ci` is skipped (the in-repo PR path) or failed
337+
# (so the mirror can report red).
338+
if: always()
339339
# Match the reusable's runner routing (workflow-ci.yml): private CLDMV
340340
# repos run on self-hosted cldmv-runners (GitHub-hosted Actions budget is
341341
# private-metered and exhausted), public repos use free GitHub-hosted, and
@@ -349,10 +349,19 @@ jobs:
349349
steps:
350350
- name: Mirror reusable result
351351
env:
352+
OWNS_STATUS: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == true || github.event.pull_request.head.ref == 'next' || github.event.pull_request.head.ref == 'hotfixes' }}
352353
IS_MASTER_SYNC: ${{ needs.ci.outputs.is_master_sync }}
353354
DOCS_ONLY: ${{ needs.ci.outputs.docs_only }}
354355
CI_RESULT: ${{ needs.ci.result }}
355356
run: |
357+
# In-repo feature PR: the push run on the head branch reports
358+
# `✅ Required PR Check`. This job runs under the
359+
# `⏭️ Required PR Check (reported by the push run)` name and
360+
# must not gate anything.
361+
if [ "$OWNS_STATUS" != "true" ]; then
362+
echo "In-repo PR event — the push run reports ✅ Required PR Check for this SHA."
363+
exit 0
364+
fi
356365
echo "ci.result=$CI_RESULT docs_only=$DOCS_ONLY is_master_sync=$IS_MASTER_SYNC"
357366
# next/hotfixes was force-synced to master — head SHA matches the
358367
# default branch, nothing new to test, green-light without running CI.

0 commit comments

Comments
 (0)