From e050bfe80ec8fca52b11b72c615ddf1108e0a676 Mon Sep 17 00:00:00 2001 From: Stefan Steiner Date: Tue, 26 May 2026 23:49:43 -0700 Subject: [PATCH] fix(ci): defer fromJson(release.outputs.pr) into a run block MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The follow-up steps added in PR #50 reference `fromJson(steps.release.outputs.pr).headBranchName` directly in `ref:` (checkout) and `env:` (push) blocks. GitHub Actions evaluates every `${{ }}` expression in the workflow at job-load time, BEFORE per-step `if:` gates short-circuit. When release-please runs on a push that doesn't produce a release PR (e.g. a PR merge whose conventional- commit was already covered by an earlier release), `pr` is the empty string, `fromJson('')` errors out, and the entire job fails with: ##[error]The template is not valid. .../release-please.yml (Line: 203, Col: 19): Error reading JToken from JsonReader. Path '', line 0, position 0. This blocks release-please from ever opening the next release PR. Observed in run 26494686197 on the merge of PR #50 itself. Fix: extract the branch name in a new "Resolve release-please branch name" step (id=`branch`) that does the parse via `jq` inside a `run:` block — that block only runs when the step's `if:` gate passes, so the parse is never attempted on empty input. The downstream `actions/checkout` `ref:` and the final `git push` `env: BRANCH:` both reference `steps.branch.outputs.name`, which evaluates safely to the empty string when the step was skipped. Add a doc comment explaining the GHA expression-evaluation timing trap so the next person reading the workflow doesn't accidentally re-introduce the same pattern. --- .github/workflows/release-please.yml | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index cbf280d..8f0488a 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -79,11 +79,35 @@ jobs: # exclusion is the safety net that protects the released # binary even if a maintainer merges in a tiny window between # release-please's force-push and our follow-up step landing. + # Extract the release-please branch name into its own step + # output. We can't reference `fromJson(steps.release.outputs.pr)` + # directly in `ref:` / `env:` further down, because GitHub + # Actions evaluates every `${{ }}` expression in the workflow + # at job-load time — even on steps gated by `if:` that won't + # run. When `pr` is empty (no release PR this run), + # `fromJson('')` errors with "Error reading JToken from + # JsonReader." Wrapping the parse in a `run:` block keeps it + # inside the `if`-gate. + - name: Resolve release-please branch name + id: branch + if: ${{ steps.release.outputs.pr != '' }} + env: + PR_JSON: ${{ steps.release.outputs.pr }} + run: | + set -euo pipefail + BRANCH=$(printf '%s' "$PR_JSON" | jq -r '.headBranchName') + if [ -z "$BRANCH" ] || [ "$BRANCH" = "null" ]; then + echo "::error::Could not extract headBranchName from release-please output" + printf '%s\n' "$PR_JSON" | head -5 + exit 1 + fi + echo "name=$BRANCH" >> "$GITHUB_OUTPUT" + - name: Checkout release-please branch if: ${{ steps.release.outputs.pr != '' }} uses: actions/checkout@v6 with: - ref: ${{ fromJson(steps.release.outputs.pr).headBranchName }} + ref: ${{ steps.branch.outputs.name }} token: ${{ secrets.RELEASE_PLEASE_TOKEN }} - uses: actions-rust-lang/setup-rust-toolchain@v1 @@ -200,4 +224,4 @@ jobs: # tracking branch staying the default in future versions. git push origin "HEAD:${BRANCH}" env: - BRANCH: ${{ fromJson(steps.release.outputs.pr).headBranchName }} + BRANCH: ${{ steps.branch.outputs.name }}