diff --git a/.forgejo/workflows/skip-status-probe.yml b/.forgejo/workflows/skip-status-probe.yml new file mode 100644 index 0000000..d1b828e --- /dev/null +++ b/.forgejo/workflows/skip-status-probe.yml @@ -0,0 +1,92 @@ +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"