Skip to content

fix: use single quotes in a workflow expression, and lint for it - #67

Merged
coretl merged 2 commits into
mainfrom
fix/workflow-expression-syntax
Aug 21, 2026
Merged

coretl merged 2 commits into
mainfrom
fix/workflow-expression-syntax

Conversation

@coretl

@coretl coretl commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

The first deploy after #66 failed before any job started — no logs, no annotations, no failing step, because GitHub rejected the workflow file itself:

publish-gh-pages.yml:146: got unexpected character '"' while lexing expression …
only single quotes are available for string delimiter

${{ github.event.workflow_run.html_url || "manual dispatch" }}, in the context-logging step I added in #66. Expressions take single-quoted string literals only — and a single-quoted literal can't be nested inside the single-quoted shell word it was written in.

Fixed by taking every context value through env: rather than interpolating into the script, which is the right shape regardless: it keeps arbitrary values out of the shell too.

The gap matters more than the bug

Workflow expressions are validated only by GitHub. This passed:

  • YAML parsing (it's a valid string)
  • bash -n on every embedded script
  • the workflow harness — which substitutes ${{ }} away before running anything

…and the failure mode hands you nothing to read. gh run view --log returns log not found; the jobs array is empty. I only isolated it by dispatching the workflow manually, where the error surfaced on stderr.

So _lint.yml now runs actionlint, which reports this exact error with the column. Verified against a copy with the bug reintroduced.

It was previously rejected for false-flagging job.workflow_repository / job.workflow_sha — its job context schema is stale, while those properties are real and publish-gh-pages.yml depends on them to version-match assemble.mjs. Those two are suppressed with an -ignore pattern narrow enough not to hide anything else; with them suppressed the repo lints clean.

State

main's deploy is currently broken — this restores it. The v0.25.0 tag waits until a deploy from main is verified green.

🤖 Generated with Claude Code

coretl and others added 2 commits August 21, 2026 14:52
The first deploy after the workflow_run migration failed before any job started — no
logs, no annotations, no failing step, because GitHub rejected the workflow file itself:

  publish-gh-pages.yml:146: got unexpected character '"' while lexing expression ...
  only single quotes are available for string delimiter

`${{ github.event.workflow_run.html_url || "manual dispatch" }}`, in the context-logging
step. Expressions take single-quoted string literals only, and a single-quoted literal
cannot be nested inside the single-quoted shell word it was written in.

Fixed by taking every context value through `env:` instead of interpolating it into the
script — which is the right shape anyway, since it also keeps arbitrary values out of
the shell.

The reason this reached main is worth more than the fix. Workflow expressions are
validated only by GitHub: this passed YAML parsing, passed `bash -n` on every embedded
script, and passed the workflow harness (which substitutes `${{ }}` away before running
anything). Nothing local could see it, and the failure mode gives you no logs to read.

So _lint.yml now runs actionlint, which reports this exact error and pinpoints the
column. It was previously rejected for false-flagging job.workflow_repository /
job.workflow_sha — its `job` context schema is stale, while those properties are real and
publish-gh-pages.yml depends on them. Those two are suppressed by an -ignore pattern
narrow enough to not hide anything else; with them suppressed the repo lints clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The CI runner has shellcheck installed, so actionlint runs it over every embedded
script — which my local run had disabled, so I missed both.

SC2002: `$(cat file | head -1)` is a pointless subprocess; `head -1 file`.

SC2015: `[ -n "$stable_src" ] && ln -s … || true` is not if-then-else. It swallows a
FAILED symlink as well as the intended empty-stable_src case, and a missing stable/
alias is silent damage — the root redirect targets that constant URL, and cross-project
intersphinx points at it. Now an explicit `if`, so a real `ln` failure fails the deploy.
This one predates the migration; actionlint found it on its first run.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@coretl
coretl merged commit 73ad598 into main Aug 21, 2026
4 checks passed
@coretl
coretl deleted the fix/workflow-expression-syntax branch August 21, 2026 14:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant