prefer-actions-exec-over-child-process: flag hidden async-conversion cost in sync contexts - #56985
Merged
pelikhan merged 3 commits intoAug 29, 2026
Merged
Conversation
…ocess rule Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot
AI
changed the title
[WIP] Fix prefer-actions-exec-over-child-process to handle async conversion
prefer-actions-exec-over-child-process: flag hidden async-conversion cost in sync contexts
Aug 29, 2026
pelikhan
marked this pull request as ready for review
August 29, 2026 22:14
pelikhan
deleted the
copilot/prefer-actions-exec-over-child-process-fix
branch
August 29, 2026 22:15
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
Result-consumption detection is incomplete and promisified calls can receive an incorrect migration warning.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Adds async-migration context to the child-process ESLint rule.
Changes:
- Detects retained results in synchronous functions.
- Adds a specialized diagnostic and regression tests.
File summaries
| File | Description |
|---|---|
prefer-actions-exec-over-child-process.ts |
Adds context detection and diagnostic selection. |
prefer-actions-exec-over-child-process.test.ts |
Tests synchronous and asynchronous contexts. |
Review details
Suppressed comments (1)
eslint-factory/src/rules/prefer-actions-exec-over-child-process.ts:286
- Exclude promisified bindings from this message variant. A non-async function can already return
promisify(exec)(...)as a Promise; replacing that return withexec.getExecOutput(...)preserves its asynchronous contract and does not require converting the function or callers, but the current condition reports that it does.
messageId: requiresAsyncConversion(node) ? "preferActionsExecSyncContext" : "preferActionsExec",
- Files reviewed: 2/2 changed files
- Comments generated: 2
- Review effort level: Balanced
💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.
| */ | ||
| function requiresAsyncConversion(node: TSESTree.CallExpression): boolean { | ||
| const enclosingFunction = findEnclosingFunction(node); | ||
| return enclosingFunction !== null && !enclosingFunction.async && retainsCallResult(node); |
| preferActionsExec: | ||
| "Prefer @actions/exec's exec()/getExecOutput() over child_process.{{method}}() to spawn processes in actions/github-script scripts. child_process.{{method}}() duplicates functionality already provided by the @actions/exec toolkit available in this context.", | ||
| preferActionsExecSyncContext: | ||
| "Prefer @actions/exec's exec()/getExecOutput() over child_process.{{method}}() to spawn processes in actions/github-script scripts. child_process.{{method}}() duplicates functionality already provided by the @actions/exec toolkit available in this context. @actions/exec's API is Promise-only, so migrating this call requires converting the enclosing (currently non-async) function — and every one of its callers up the chain — to async/await.", |
Contributor
|
🎉 This pull request is included in a new release. Release: |
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.
prefer-actions-exec-over-child-processflagged everychild_processoutput-capturing call uniformly, implying a drop-in swap to@actions/exec. But@actions/execis Promise-only, so when the flagged call lives in a non-async function whose result is consumed (not just a side effect), the real fix requires converting that function — and every caller up the chain — toasync/await. The message gave no signal of this larger blast radius.findEnclosingFunction()to locate the nearest enclosing function andrequiresAsyncConversion(), which flags the call when that function is non-async and its result is consumed non-trivially (assigned, returned, or otherwise used), reusing the existingretainsCallResult()logic.preferActionsExecSyncContextextends the existing message with a note that migration requires converting the enclosing (non-async) function and its callers toasync/await. Calls in already-async functions, or bare side-effect statements, keep the originalpreferActionsExecmessage.Example:
Confirmed the new variant now fires on the real-world case cited in the issue,
actions/setup/js/get_current_branch.cjs:21.