ci-test/.forgejo/workflows/skip-status-probe.yml
David Charlot 6f5193da95
All checks were successful
skip-status-probe / probe · skipped by its own literal false (expect SKIP) (push) Has been skipped
skip-status-probe / probe · a gate that itself skips (push) Has been skipped
skip-status-probe / probe · dependent of a skipped gate (expect SKIP, no runner) (push) Has been skipped
skip-status-probe / probe · skipped-gate matrix leg one (expect SKIP, no runner) (push) Has been skipped
skip-status-probe / probe · skipped-gate matrix leg three (expect SKIP, no runner) (push) Has been skipped
skip-status-probe / probe · skipped-gate matrix leg two (expect SKIP, no runner) (push) Has been skipped
skip-status-probe / probe · gate emitting false (push) Successful in 1s
skip-status-probe / probe · dependent of a false gate (expect SKIP) (push) Has been skipped
skip-status-probe / probe · skipped matrix leg alpha (expect SKIP) (push) Has been skipped
skip-status-probe / probe · skipped matrix leg beta (expect SKIP) (push) Has been skipped
skip-status-probe / probe · skipped matrix leg gamma (expect SKIP) (push) Has been skipped
skip-status-probe / probe · gate emitting true (push) Successful in 0s
skip-status-probe / probe · dependent of a true gate (expect RUN) (push) Successful in 0s
ci-smoke / smoke (push) Successful in 5s
ci: answer the needs-gated skip without waiting on a runner
The first pair needs the gate to RUN to produce its output, and this fleet's
`linux` runner is hours deep, so it has not answered in 27 minutes. This pair
skips the gate on its own literal false, which the forge resolves without
scheduling anything, and a dependent of a skipped job skips in turn. Same
question, no runner.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-09 04:10:48 -04:00

129 lines
4.4 KiB
YAML

name: skip-status-probe
# Does a SKIPPED job report a commit status on this forge?
#
# open-standards gates expensive path-filtered workflows behind a `relevant`
# job: the dependent jobs carry `needs: relevant` + an `if:` on its output, so
# they skip when the change does not touch that standard. If a skipped job
# reports no status at all, every one of those contexts stays permanently
# pending and a branch-protection rule that requires them can never be
# satisfied — the PR becomes unmergeable. That is the question this answers,
# before the pattern is rolled out past the one workflow that has it.
#
# Four jobs, and the pairing is the point:
# gate-false -> dep-of-false expected SKIP
# gate-true -> dep-of-true expected RUN
# The second pair is the control. Without it, a skip proves nothing: if
# `needs.*.outputs.*` were simply broken here and always read empty, EVERY
# dependent would skip and the result would look identical. dep-of-true
# running is what makes dep-of-false's skip mean "the output said false".
#
# dep-literal isolates a job skipped by its own `if: false`, with no `needs`
# edge, to tell the two skip causes apart.
#
# dep-matrix mirrors the real shape under test: wai-pack's dependent jobs are
# a three-platform matrix, so the required contexts are per-leg. Whether each
# leg reports its own status, or the matrix collapses to one row, decides how
# many contexts go missing.
on:
push:
paths:
- ".forgejo/workflows/skip-status-probe.yml"
pull_request:
paths:
- ".forgejo/workflows/skip-status-probe.yml"
concurrency:
group: skip-status-probe-${{ github.ref }}
cancel-in-progress: true
jobs:
gate-false:
name: probe · gate emitting false
runs-on: linux
outputs:
touched: ${{ steps.decide.outputs.touched }}
steps:
- id: decide
run: echo "touched=false" >> "$GITHUB_OUTPUT"
gate-true:
name: probe · gate emitting true
runs-on: linux
outputs:
touched: ${{ steps.decide.outputs.touched }}
steps:
- id: decide
run: echo "touched=true" >> "$GITHUB_OUTPUT"
dep-of-false:
name: probe · dependent of a false gate (expect SKIP)
needs: gate-false
if: needs.gate-false.outputs.touched == 'true'
runs-on: linux
steps:
- run: echo "FAIL - this job should not have run"
dep-of-true:
name: probe · dependent of a true gate (expect RUN)
needs: gate-true
if: needs.gate-true.outputs.touched == 'true'
runs-on: linux
steps:
- run: echo "control - outputs propagate, so a skip above means false"
dep-literal:
name: probe · skipped by its own literal false (expect SKIP)
runs-on: linux
if: false
steps:
- run: echo "FAIL - this job should not have run"
dep-matrix:
name: probe · skipped matrix leg ${{ matrix.leg }} (expect SKIP)
needs: gate-false
if: needs.gate-false.outputs.touched == 'true'
runs-on: linux
strategy:
matrix:
leg: [alpha, beta, gamma]
steps:
- run: echo "FAIL - this job should not have run"
# The pair above still needs a runner to answer, because a gate must RUN to
# produce the output its dependents are gated on, and this fleet's `linux`
# runner is hours deep. This pair needs no runner at all: the gate skips on
# its own literal false, which the forge resolves without scheduling
# anything, and a dependent of a skipped job skips in turn. It isolates the
# one thing still unknown — whether a job skipped through a `needs` edge
# reports a commit status, or silently reports nothing and leaves its
# context pending forever.
gate-skipped:
name: probe · a gate that itself skips
runs-on: linux
if: false
outputs:
run: ${{ steps.d.outputs.run }}
steps:
- id: d
run: echo "run=true" >> "$GITHUB_OUTPUT"
dep-of-skipped-gate:
name: probe · dependent of a skipped gate (expect SKIP, no runner)
needs: gate-skipped
if: needs.gate-skipped.outputs.run == 'true'
runs-on: linux
steps:
- run: echo "FAIL - this job should not have run"
dep-matrix-of-skipped-gate:
name: probe · skipped-gate matrix leg ${{ matrix.leg }} (expect SKIP, no runner)
needs: gate-skipped
if: needs.gate-skipped.outputs.run == 'true'
runs-on: linux
strategy:
matrix:
leg: [one, two, three]
steps:
- run: echo "FAIL - this job should not have run"