From 6493517c9d678175a471ed4635b9fedab0df4893 Mon Sep 17 00:00:00 2001 From: Phillip Cloud <417981+cpcloud@users.noreply.github.com> Date: Fri, 17 Apr 2026 10:18:06 -0400 Subject: [PATCH] ci: guard fromJSON in detect-changes against empty pr-info output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The detect-changes job's `Detect changed paths` step gates on `startsWith(github.ref_name, 'pull-request/')`, but GitHub Actions evaluates step-level `env:` expressions eagerly — the `if:` gate does not short-circuit them. On push to main, tag, or schedule events the preceding `Resolve PR base branch` step is skipped and its outputs are empty strings, so `fromJSON(steps.pr-info.outputs.pr-info)` raises a template error and fails the step even though its `if:` would otherwise skip it. That failure cascades into the final "Check job status" aggregation, turning every push-to-main CI run red (see run 24566662170). Guard the `fromJSON` call with a short-circuit so the expression resolves to an empty string when pr-info did not run. On PR events the expression still evaluates to the PR's actual base ref. --- .github/workflows/ci.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 525c210889..f575d2f851 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -121,7 +121,15 @@ jobs: id: filter if: ${{ startsWith(github.ref_name, 'pull-request/') }} env: - BASE_REF: ${{ fromJSON(steps.pr-info.outputs.pr-info).base.ref }} + # GitHub Actions evaluates step-level `env:` expressions eagerly — + # the step's `if:` gate does NOT short-circuit them. On non-PR + # events (push/tag/schedule), `pr-info` is skipped and its outputs + # are empty strings, so `fromJSON('')` would raise a template error + # and fail the step despite `if:` being false. Guard the + # `fromJSON` call with a short-circuit so the expression resolves + # to an empty string on non-PR events; the step is still gated + # off by `if:`, so `BASE_REF` is never consumed there. + BASE_REF: ${{ steps.pr-info.outputs.pr-info && fromJSON(steps.pr-info.outputs.pr-info).base.ref || '' }} run: | # Diff against the merge base with the PR's actual target branch. # Uses merge-base so diverged branches only show files changed on