Skip to content

Commit 3c16c20

Browse files
committed
## What
Fix a required-status-check deadlock by converting the path-filtered required job to a **pass-through shim** (same pattern as echidna#256). ## Why This job is a **required** status check but its workflow is path-filtered on `pull_request`, so it never runs (never reports) on PRs that don't touch those paths — branch protection then waits forever and the PR can't merge via normal flow. ## Fix - Drop the `pull_request` paths-filter so the job **always runs** (the required check always reports). - A `Detect relevant changes` step reads the PR's changed files via the GitHub API and gates the heavy steps — real work runs only when the relevant sources change; otherwise it passes through in seconds. - `push` stays scoped to the default branch + paths (post-merge behaviour unchanged); job names preserved so the required contexts still match. Identified by the 2026-06-14 estate required-check deadlock audit (`dev-notes/audits/`). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
1 parent 58071eb commit 3c16c20

1 file changed

Lines changed: 52 additions & 3 deletions

File tree

.github/workflows/elixir-ci.yml

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@ on:
66
paths:
77
- 'elixir-mcp/**'
88
- '.github/workflows/elixir-ci.yml'
9+
# No pull_request paths-filter: Dialyzer is a REQUIRED status check, so it must
10+
# report on every PR (a path-filtered required check deadlocks PRs that don't
11+
# touch its paths). The "Detect relevant changes" step gates the heavy work; the
12+
# non-required test matrix is gated the same way so it doesn't run on every PR.
913
pull_request:
1014
branches: [main]
11-
paths:
12-
- 'elixir-mcp/**'
13-
- '.github/workflows/elixir-ci.yml'
1415
permissions:
1516
contents: read
1617
jobs:
@@ -20,6 +21,7 @@ jobs:
2021
timeout-minutes: 15
2122
permissions:
2223
contents: read
24+
pull-requests: read # change-detector reads the PR's file list
2325
defaults:
2426
run:
2527
working-directory: elixir-mcp
@@ -29,12 +31,32 @@ jobs:
2931
otp: ['26']
3032
steps:
3133
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
34+
- name: Detect relevant changes
35+
id: detect
36+
working-directory: ${{ github.workspace }}
37+
env:
38+
GH_TOKEN: ${{ github.token }}
39+
run: |
40+
set -euo pipefail
41+
PATTERN='^elixir-mcp/'
42+
if [ "${{ github.event_name }}" = "pull_request" ]; then
43+
FILES=$(gh api "repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/files" --paginate --jq '.[].filename')
44+
if printf '%s\n' "$FILES" | grep -qE "$PATTERN"; then
45+
echo "relevant=true" >> "$GITHUB_OUTPUT"
46+
else
47+
echo "relevant=false" >> "$GITHUB_OUTPUT"; echo "No elixir-mcp changes — pass-through (required-check shim)."
48+
fi
49+
else
50+
echo "relevant=true" >> "$GITHUB_OUTPUT"
51+
fi
3252
- name: Set up Elixir
53+
if: steps.detect.outputs.relevant == 'true'
3354
uses: erlef/setup-beam@fc68ffb90438ef2936bbb3251622353b3dcb2f93 # v1.24.0
3455
with:
3556
elixir-version: ${{ matrix.elixir }}
3657
otp-version: ${{ matrix.otp }}
3758
- name: Cache deps
59+
if: steps.detect.outputs.relevant == 'true'
3860
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
3961
with:
4062
path: |
@@ -44,30 +66,55 @@ jobs:
4466
restore-keys: |
4567
mix-${{ matrix.elixir }}-${{ matrix.otp }}-
4668
- name: Install dependencies
69+
if: steps.detect.outputs.relevant == 'true'
4770
run: mix deps.get
4871
- name: Compile (warnings as errors)
72+
if: steps.detect.outputs.relevant == 'true'
4973
run: mix compile --warnings-as-errors
5074
- name: Check formatting
75+
if: steps.detect.outputs.relevant == 'true'
5176
run: mix format --check-formatted
5277
- name: Run tests
78+
if: steps.detect.outputs.relevant == 'true'
5379
run: mix test --trace
5480
dialyzer:
5581
name: Dialyzer
5682
runs-on: ubuntu-latest
5783
timeout-minutes: 15
5884
permissions:
5985
contents: read
86+
pull-requests: read # change-detector reads the PR's file list
6087
defaults:
6188
run:
6289
working-directory: elixir-mcp
6390
steps:
6491
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
92+
- name: Detect relevant changes
93+
id: detect
94+
working-directory: ${{ github.workspace }}
95+
env:
96+
GH_TOKEN: ${{ github.token }}
97+
run: |
98+
set -euo pipefail
99+
PATTERN='^elixir-mcp/'
100+
if [ "${{ github.event_name }}" = "pull_request" ]; then
101+
FILES=$(gh api "repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/files" --paginate --jq '.[].filename')
102+
if printf '%s\n' "$FILES" | grep -qE "$PATTERN"; then
103+
echo "relevant=true" >> "$GITHUB_OUTPUT"
104+
else
105+
echo "relevant=false" >> "$GITHUB_OUTPUT"; echo "No elixir-mcp changes — pass-through (required-check shim)."
106+
fi
107+
else
108+
echo "relevant=true" >> "$GITHUB_OUTPUT"
109+
fi
65110
- name: Set up Elixir
111+
if: steps.detect.outputs.relevant == 'true'
66112
uses: erlef/setup-beam@fc68ffb90438ef2936bbb3251622353b3dcb2f93 # v1.24.0
67113
with:
68114
elixir-version: '1.17'
69115
otp-version: '26'
70116
- name: Cache deps
117+
if: steps.detect.outputs.relevant == 'true'
71118
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
72119
with:
73120
path: |
@@ -77,7 +124,9 @@ jobs:
77124
restore-keys: |
78125
dialyzer-
79126
- name: Install dependencies
127+
if: steps.detect.outputs.relevant == 'true'
80128
run: mix deps.get
81129
- name: Run Dialyzer
130+
if: steps.detect.outputs.relevant == 'true'
82131
run: mix dialyzer
83132
continue-on-error: true

0 commit comments

Comments
 (0)