Skip to content

Commit 24ba060

Browse files
committed
fix(ci): replace hashFiles() job-level if guards with a detect gate job
rust-ci-reusable.yml and elixir-ci-reusable.yml gated their jobs with `if: ${{ hashFiles('<manifest>') != '' }}` at the JOB level. hashFiles() needs a checked-out workspace, which does not exist when a job-level `if:` is evaluated, so GitHub rejects it at the workflow-startup phase — a startup_failure that has been red on every push (confirmed: the only two workflows still failing after the YAML/secrets fixes, and the construct the rust reusable's own header comment flags as a known failure mode). Replace with the supported pattern: a tiny `detect` job that checks out, tests for the manifest (Cargo.toml / mix.exs in inputs.working_directory), and exposes `has_cargo` / `has_mix` as an output the real jobs gate on via `needs.detect.outputs.*`. Behaviour is preserved (skip the bundle when the manifest is absent) without the invalid job-level hashFiles(). Consumers pin these reusables by SHA, so existing callers are unaffected until they bump their pin.
1 parent 2880fcb commit 24ba060

2 files changed

Lines changed: 71 additions & 7 deletions

File tree

.github/workflows/elixir-ci-reusable.yml

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,11 +98,42 @@ permissions:
9898
contents: read
9999

100100
jobs:
101+
# Guard on mix.exs so the wrapper is safe to add unconditionally.
102+
#
103+
# `hashFiles()` is NOT resolvable in a job-level `if:` (it needs a
104+
# checked-out workspace, absent at job-gating time) and using it there
105+
# is a GitHub Actions startup_failure. Use a tiny `detect` job that
106+
# checks out, tests for the manifest, and exposes the result as an
107+
# output the real job gates on.
108+
detect:
109+
name: Detect mix.exs
110+
runs-on: ${{ inputs.runs-on }}
111+
permissions:
112+
contents: read
113+
outputs:
114+
has_mix: ${{ steps.detect.outputs.has_mix }}
115+
steps:
116+
- name: Checkout repository
117+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
118+
with:
119+
repository: ${{ github.repository }}
120+
ref: ${{ github.ref }}
121+
- name: Detect manifest
122+
id: detect
123+
working-directory: ${{ inputs.working_directory }}
124+
shell: bash
125+
run: |
126+
if [ -f mix.exs ]; then
127+
echo "has_mix=true" >> "$GITHUB_OUTPUT"
128+
else
129+
echo "has_mix=false" >> "$GITHUB_OUTPUT"
130+
fi
131+
101132
test:
102133
name: Compile + test
103134
runs-on: ${{ inputs.runs-on }}
104-
# Guard on mix.exs so the wrapper is safe to add unconditionally.
105-
if: ${{ hashFiles(format('{0}/mix.exs', inputs.working_directory)) != '' }}
135+
needs: detect
136+
if: ${{ needs.detect.outputs.has_mix == 'true' }}
106137
permissions:
107138
contents: read
108139
env:

.github/workflows/rust-ci-reusable.yml

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -103,10 +103,41 @@ jobs:
103103
# Skip the whole reusable when the repo has no Cargo.toml — lets
104104
# consumers add the wrapper unconditionally without worrying about
105105
# repos that don't ship Rust code at the moment.
106+
#
107+
# `hashFiles()` is NOT resolvable in a job-level `if:` (it needs a
108+
# checked-out workspace, which does not exist at job-gating time) and
109+
# using it there is a GitHub Actions startup_failure. The supported
110+
# pattern is a tiny `detect` job that checks out, tests for the
111+
# manifest, and exposes the result as an output the real jobs gate on.
112+
detect:
113+
name: Detect Cargo.toml
114+
runs-on: ${{ inputs.runs-on }}
115+
permissions:
116+
contents: read
117+
outputs:
118+
has_cargo: ${{ steps.detect.outputs.has_cargo }}
119+
steps:
120+
- name: Checkout repository
121+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
122+
with:
123+
repository: ${{ github.repository }}
124+
ref: ${{ github.ref }}
125+
- name: Detect manifest
126+
id: detect
127+
working-directory: ${{ inputs.working_directory }}
128+
shell: bash
129+
run: |
130+
if [ -f Cargo.toml ]; then
131+
echo "has_cargo=true" >> "$GITHUB_OUTPUT"
132+
else
133+
echo "has_cargo=false" >> "$GITHUB_OUTPUT"
134+
fi
135+
106136
check:
107137
name: Cargo check + clippy + fmt
108138
runs-on: ${{ inputs.runs-on }}
109-
if: ${{ hashFiles(format('{0}/Cargo.toml', inputs.working_directory)) != '' }}
139+
needs: detect
140+
if: ${{ needs.detect.outputs.has_cargo == 'true' }}
110141
permissions:
111142
contents: read
112143
defaults:
@@ -145,8 +176,8 @@ jobs:
145176
test:
146177
name: Cargo test
147178
runs-on: ${{ inputs.runs-on }}
148-
needs: check
149-
if: ${{ hashFiles(format('{0}/Cargo.toml', inputs.working_directory)) != '' }}
179+
needs: [detect, check]
180+
if: ${{ needs.detect.outputs.has_cargo == 'true' }}
150181
permissions:
151182
contents: read
152183
defaults:
@@ -184,7 +215,8 @@ jobs:
184215
audit:
185216
name: Cargo audit (security)
186217
runs-on: ${{ inputs.runs-on }}
187-
if: ${{ inputs.enable_audit && hashFiles(format('{0}/Cargo.toml', inputs.working_directory)) != '' }}
218+
needs: detect
219+
if: ${{ inputs.enable_audit && needs.detect.outputs.has_cargo == 'true' }}
188220
permissions:
189221
contents: read
190222
defaults:
@@ -212,7 +244,8 @@ jobs:
212244
coverage:
213245
name: Coverage (tarpaulin + codecov)
214246
runs-on: ${{ inputs.runs-on }}
215-
if: ${{ inputs.enable_coverage && hashFiles(format('{0}/Cargo.toml', inputs.working_directory)) != '' }}
247+
needs: detect
248+
if: ${{ inputs.enable_coverage && needs.detect.outputs.has_cargo == 'true' }}
216249
permissions:
217250
contents: read
218251
defaults:

0 commit comments

Comments
 (0)