Add support for parallel steps (background, wait, wait-all, cancel, parallel)#694
Open
devantler wants to merge 3 commits into
Open
Add support for parallel steps (background, wait, wait-all, cancel, parallel)#694devantler wants to merge 3 commits into
devantler wants to merge 3 commits into
Conversation
…arallel)
GitHub released parallel steps on 2026-06-25, introducing five new step keys:
`background`, `wait`, `wait-all`, `cancel`, and `parallel`. Until now actionlint
rejected workflows using them ("unexpected key ..." / "step must run ..."). This
adds parsing and AST support for them:
- `background: true` is parsed as a new optional `*Bool` field on a step (run or
action step), mirroring `continue-on-error`.
- `wait`/`wait-all`, `cancel`, and `parallel` are modeled as new step execution
kinds (`ExecWait`, `ExecCancel`, `ExecParallel`) so they no longer trip the
"step must run ... run/uses" check. `wait` and `cancel` accept a single ID or a
list of IDs; `parallel` parses its grouped steps recursively, and those nested
steps are visited by every rule so they keep getting linted.
Expression/context checking for the new fields is intentionally deferred: the
generated context-availability table does not describe them yet, so checking now
would produce false positives. `name`/`if` on the new step kinds are still
checked as before.
Closes rhysd#693
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The GitHub workflow-syntax docs specify that `cancel` "targets a single background step by its `id`" (unlike `wait`, which is a string or an array). Parse `cancel` as a single string instead of a string-or-list so that `cancel: [a, b]` is correctly reported as a type error, and fix the fixture accordingly. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Author
|
Thanks for flagging critical oversights @nikosavola! |
nikosavola
suggested changes
Jun 26, 2026
Address review feedback on the parallel-steps PR: - `wait-all` waits for all background steps and takes no arguments, so report an error when a value is given (e.g. `wait-all: foo`). - `wait` and `wait-all` in the same step are contradictory (one targets specific background steps, the other waits for all); flag it. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
GitHub released parallel steps on 2026-06-25, adding five new step keys. actionlint currently rejects any workflow that uses them — e.g.
unexpected key "background" for step ..., andstep must run script with "run" section or run action with "uses" sectionforwait/wait-all/cancel/parallelsteps — which blocks adoption. This teaches the parser about them.Closes #693
What the feature looks like
Changes
Modeled after the spec in
workflow-syntax.md:background(boolean) is parsed as a new optional*Boolfield on a step (run or action step), mirroringcontinue-on-error.wait/wait-all,cancelandparallelare modeled as new step execution kinds (ExecWait,ExecCancel,ExecParallel) alongsideExecRun/ExecAction, so they no longer trip the "step must run …" check.waitaccepts a single step ID or a list (wait: [a, b]);canceltargets a single step ID (a list is reported as a type error, per the spec).parallelparses its grouped steps recursively (reusingparseSteps), and the visitor inpass.gorecurses into them, so every rule still lints the nested steps.run/action steps (e.g.unexpected key "shell" for step to wait for background steps).Context checking — intentionally deferred (with reason)
actionlint generates its context-availability table (
availability.go) from GitHub'scontexts.md, and that file does not yet listbackground/wait/cancel. So there is no published context-availability to validate${{ }}expressions in those fields against, and adding guessed rules now would risk false positives. Expressions are still parsed (so e.g.background: ${{ ... }}is accepted), andname/ifon the new step kinds are checked as before. Once these keys are added tocontexts.md, regeneratingavailability.goplus a small follow-up will cover it.Test plan
testdata/ok/parallel_steps.yaml(valid usage of all five keys, incl. an expression-valuedbackground) andtestdata/err/parallel_steps.yaml+.out(unexpected keys on wait/cancel/parallel steps;cancelwith a list; and an invalid step nested inparallel, which proves the recursion lints it).background.go test ./...is green (1881 tests);gofmt/go vet/staticcheckclean.🤖 Generated with Claude Code