Add parallel-steps rule: check wait/cancel references and steps allowed inside parallel#695
Open
devantler wants to merge 9 commits into
Open
Add parallel-steps rule: check wait/cancel references and steps allowed inside parallel#695devantler wants to merge 9 commits into
parallel-steps rule: check wait/cancel references and steps allowed inside parallel#695devantler wants to merge 9 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>
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>
`wait` and `cancel` steps refer to the IDs of background steps, much like `needs:` refers to job IDs. This adds a rule that flags a `wait`/`cancel` target that doesn't match the ID of a preceding `background: true` step, catching typos such as `cancel: typo`. A single in-order walk (recursing into `parallel:` groups) validates existence, that the target is a background step, and that it precedes the reference. `wait-all` and expression-valued IDs are skipped. Addresses review feedback on the parallel-steps PR. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The visitor already recurses into 'parallel:' groups, visiting every step in order, so the rule can accumulate background step IDs in VisitStep (resetting per job in VisitJobPre) instead of re-walking the step tree itself. This matches the RuleID pattern and removes the manual recursion. No behaviour change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Author
|
Still working on this a bit more. I want to be sure that we catch this error scenario: on: push
jobs:
test:
runs-on: ubuntu-latest
steps:
- parallel:
- parallel: # not allowed. Should fail with actionable feedback.
- run: echo "not good"Done ✅ The code lints for this scenario as well now. |
A `parallel` group is shorthand for backgrounding each of its steps with an implicit wait at the end, so a `parallel` step cannot itself appear inside another `parallel` group. Flag it in the parallel-steps rule. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds an ok fixture covering the defensive paths: a step whose `background` is an expression is treated as a possible background step (so a `wait`/`cancel` to it isn't flagged), and an expression-valued `wait`/`cancel` reference is skipped because it can't be resolved statically. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Author
|
Now I am investigating whether EDIT: They are not. I am working on adding linting for this now. Done ✅ |
GitHub's workflow parser (actions/languageservices) only allows `run` and `uses` steps inside a `parallel` group; `background`, `wait`, `wait-all`, `cancel`, and nested `parallel` steps are rejected at parse time. Extend the parallel-steps rule to flag each of them so actionlint matches the runtime's validation instead of only catching nested `parallel`. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…scade A `wait`/`cancel` step inside a `parallel` group is already reported as not allowed there, but its target was still validated, producing a second, redundant "unknown reference" error for the same step. Track the steps that are direct children of a `parallel` group and skip the reference check for them, so each such step yields a single, root-cause error — matching GitHub's parser, which reports only the structural violation. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
parallel-steps rule: check wait/cancel step referencesparallel-steps rule: check wait/cancel references and steps allowed inside parallel
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
Adds a
parallel-stepslint rule for the new parallel steps feature, catching two classes of mistake the parser alone doesn't:wait/cancelreferences — await: <id>/cancel: <id>must refer to the ID of a precedingbackground: truestep (analogous to howneeds:refers to job IDs), so a typo likecancel: typois flagged.parallelgroup — aparallelgroup may contain onlyrun/usessteps;background,wait,wait-all,cancel, and a nestedparallelare all rejected.The first addresses the remaining review point on #694; the second extends the rule to the structural constraints GitHub enforces.
wait/cancelreferencesRuleParallelStepswalks each job's steps in document order (recursing intoparallel:groups), tracking the IDs ofbackground: truesteps seen so far. Await/canceltarget that isn't among them is reported:A single in-order pass checks three things at once: the target exists, is a background step, and precedes the reference.
wait-alland expression-valued IDs (${{ }}) are skipped to avoid false positives.Steps inside a
parallelgroupA
parallelgroup only allowsrun/usessteps — verified againstactions/languageservices'workflow-parser(shared by the backend and the VS Code extension), which rejects the rest at parse time. Each is reported:A step that's forbidden here is reported once — its
wait/cancelreference isn't separately re-validated, so there's no cascading "unknown reference" error from the same step.Tests / docs
rule_parallel_steps.go, registered afterRuleJobNeedsinlinter.go.testdata/err/parallel_step_refs.{yaml,out}— unknown / non-background / forward references, plus every disallowed step insideparallel.testdata/ok/parallel_step_refs.yaml— dynamicbackground: ${{ … }}treated as a possible background step and expression-valued references skipped;testdata/ok/parallel_steps.yamlcovers validrun+usesinsideparallel.docs/checks.mdsection + TOC entry; SARIF golden updated.go test ./...green;gofmt/go vet/staticcheckclean.🤖 Generated with Claude Code