Skip to content

[eslint-miner] eslint: add require-return-after-core-setfailed rule#44697

Merged
pelikhan merged 2 commits into
mainfrom
eslint-miner/require-return-after-core-setfailed-24ecd14774ea90dc
Jul 10, 2026
Merged

[eslint-miner] eslint: add require-return-after-core-setfailed rule#44697
pelikhan merged 2 commits into
mainfrom
eslint-miner/require-return-after-core-setfailed-24ecd14774ea90dc

Conversation

@github-actions

@github-actions github-actions Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a new ESLint rule gh-aw-custom/require-return-after-core-setfailed to the eslint-factory plugin. The rule enforces that every call to core.setFailed() is immediately followed by a control-transfer statement (return, throw, break, continue, or process.exit()), preventing GitHub Actions code from continuing execution in a failed state.

Motivation

core.setFailed() only schedules the action exit code — it does not stop execution. Code that continues after core.setFailed() runs in a failed state, which is typically a bug.

Changes

New rule: require-return-after-core-setfailed

  • eslint-factory/src/rules/require-return-after-core-setfailed.ts — Rule implementation using @typescript-eslint/utils:

    • Detects core.setFailed(...) in BlockStatement, SwitchCase, and Program nodes.
    • Flags any core.setFailed() call whose immediate sibling statement is not a control-transfer.
    • Provides a hasSuggestions autofix that inserts return; before the next statement, preserving indentation for multiline cases.
    • Suggestion is only offered inside function-like scopes (not at top-level module scope where return is invalid).
  • eslint-factory/src/rules/require-return-after-core-setfailed.test.ts — Vitest + RuleTester test suite:

    • Valid cases: core.setFailed() followed by return, throw, break, continue, process.exit(); core.setFailed() as last statement in a block; non-core.setFailed() method calls.
    • Invalid cases: core.setFailed() followed by any regular statement in block, switch-case, and program scope; autofix output verified for same-line and multiline variants.
    • Edge case: core.setFailed() as last statement in an if-block where the outer block continues — not flagged (the rule only checks sibling statements in the same block).

Registration

  • eslint-factory/src/index.ts — imports and registers the new rule in the plugin.
  • eslint-factory/eslint.config.cjs — enables the rule at "warn" severity in the default config.

Commits

  • 0fcba1de6 eslint: add require-return-after-core-setfailed rule
  • 86a8b1ccf fix(eslint-factory): harden require-return-after-core-setfailed autofix and coverage

Generated by PR Description Updater for #44697 · 33.1 AIC · ⌖ 5.59 AIC · ⊞ 4.7K ·

core.setFailed() marks the action as failed but does NOT stop execution.
Calling it inside an if-branch without a following return/throw lets the
action continue in a failed state, which can mask secondary errors or
produce confusing output.

This rule flags any core.setFailed() call that is immediately followed by
a non-control-transfer statement in the same block. It provides a
'return;' autofix suggestion.

Findings in actions/setup/js (2 sites), confirming the pattern exists.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions github-actions Bot added automation cookie Issue Monster Loves Cookies! eslint labels Jul 10, 2026
@pelikhan pelikhan marked this pull request as ready for review July 10, 2026 10:33
Copilot AI review requested due to automatic review settings July 10, 2026 10:33
@github-actions

github-actions Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor Author

Test Quality Sentinel completed test quality analysis.

@github-actions

github-actions Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor Author

Design Decision Gate 🏗️ completed the design decision gate check.

No ADR enforcement needed: PR #44697 does not have the 'implementation' label and has 0 new lines of code in business logic directories (threshold: 100).

@github-actions

github-actions Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor Author

⚠️ PR Code Quality Reviewer failed to deliver outputs during code quality review.

@github-actions

github-actions Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor Author

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new ESLint rule to the eslint-factory plugin that detects core.setFailed(...) calls which are immediately followed by another statement in the same statement list, helping prevent Actions code from continuing to execute after declaring failure.

Changes:

  • Implement require-return-after-core-setfailed rule with a suggestion to insert return;.
  • Add unit tests covering valid/invalid patterns and suggestion output.
  • Register and enable the rule in the plugin index and ESLint config.
Show a summary per file
File Description
eslint-factory/src/rules/require-return-after-core-setfailed.ts New rule implementation, including detection logic and a return; suggestion.
eslint-factory/src/rules/require-return-after-core-setfailed.test.ts New tests validating rule behavior and the suggestion output.
eslint-factory/src/index.ts Registers the new rule in the exported plugin rules map.
eslint-factory/eslint.config.cjs Enables the new rule at warn level for .cjs files.

Review details

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 4/4 changed files
  • Comments generated: 3
  • Review effort level: Low

Comment on lines +89 to +92
messageId: "addReturn",
fix(fixer) {
return fixer.insertTextAfter(node, "\n return;");
},
Comment on lines +76 to +78
missingReturnAfterSetFailed:
"core.setFailed() does not stop execution — add a 'return' (or 'throw') immediately after to prevent the action from continuing in a failed state.",
addReturn: "Add 'return;' after core.setFailed() to stop execution.",
Comment on lines +47 to +58
it("invalid: core.setFailed followed by non-control-transfer statement", () => {
ruleTester.run("require-return-after-core-setfailed", requireReturnAfterCoreSetFailedRule, {
valid: [],
invalid: [
{
code: `function f() { core.setFailed("bad"); doMore(); }`,
errors: [{ messageId: "missingReturnAfterSetFailed", suggestions: [{ messageId: "addReturn", output: `function f() { core.setFailed("bad");\n return; doMore(); }` }] }],
},
{
code: `function f() { if (x) { core.setFailed("bad"); doMore(); } }`,
errors: [{ messageId: "missingReturnAfterSetFailed", suggestions: [{ messageId: "addReturn", output: `function f() { if (x) { core.setFailed("bad");\n return; doMore(); } }` }] }],
},
@github-actions

Copy link
Copy Markdown
Contributor Author

🧪 Test Quality Sentinel Report

Test Quality Score: 88/100 — Excellent

Analyzed 5 test(s): 5 design, 0 implementation, 0 violation(s).

📊 Metrics (5 tests)
Metric Value
Analyzed 5 (Go: 0, JS: 5)
✅ Design 5 (100%)
⚠️ Implementation 0 (0%)
Edge/error coverage 3 (60%)
Duplicate clusters 0
Inflation No (0.65:1 ratio)
🚨 Violations 0
Test File Classification Issues
uses the correct docs URL require-return-after-core-setfailed.test.ts:13–17 Design test None
valid: core.setFailed followed by return require-return-after-core-setfailed.test.ts:19–34 Design test None
valid: non-core.setFailed calls are ignored require-return-after-core-setfailed.test.ts:36–45 Design test None
invalid: core.setFailed followed by non-control-transfer statement require-return-after-core-setfailed.test.ts:47–61 Design test None
valid: core.setFailed last in if-block is not flagged require-return-after-core-setfailed.test.ts:63–71 Design test None

Verdict

Passed. 0% implementation tests (threshold: 30%). All tests verify design contracts and behavioral guarantees. Comprehensive coverage of happy path, error conditions, edge cases (scope boundaries, method/object discrimination), and autofix validation.

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • awmgmcpg

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "awmgmcpg"

See Network Configuration for more information.

🧪 Test quality analysis by Test Quality Sentinel · 9.39 AIC · ⌖ 7.27 AIC · ⊞ 6.8K ·
Comment /review to run again

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Test Quality Sentinel: 88/100. 0% implementation tests (threshold: 30%). All tests verify design contracts with comprehensive coverage of happy path, error conditions, edge cases, and autofix validation.

@github-actions github-actions Bot mentioned this pull request Jul 10, 2026

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Skills-Based Review 🧠

Applied /tdd and /codebase-design — requesting changes on three actionable issues.

📋 Key Themes & Highlights

Issues Found

  1. Hardcoded indentation in autofix — the inserted return; uses fixed 6-space indentation, which will be wrong for most real-world code.
  2. SwitchCase path is untested — the rule registers a SwitchCase visitor but no test exercises it.
  3. Program body not covered — top-level core.setFailed() calls in CommonJS scripts won't be flagged.

Positive Highlights

  • ✅ Clean helper-function design: isCoreSetFailedStatement and isControlTransfer are well-scoped and readable
  • ✅ Good block-statement test coverage, including break, throw, process.exit, and last-in-block edge cases
  • ✅ Low false-positive risk by design — only fires on explicit next-sibling statements
  • ✅ Validated against two real live findings in actions/setup/js

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · 36 AIC · ⌖ 4.68 AIC · ⊞ 6.6K
Comment /matt to run again

node,
messageId: "missingReturnAfterSetFailed",
suggest: [
{

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/tdd] The hardcoded "\n return;" indentation in the autofix suggestion will produce incorrectly-indented output for any code that isn't exactly 6 spaces deep — undermining trust in the suggestion.

💡 Use column-aware indentation

Derive indentation from the node's start column:

fix(fixer) {
  const src = context.getSourceCode();
  const token = src.getFirstToken(node)!;
  const indent = " ".repeat(token.loc.start.column);
  return fixer.insertTextAfter(node, `\\n${indent}return;`);
}

This ensures the inserted return; is aligned with the core.setFailed() call regardless of surrounding indentation.

@copilot please address this.

],
});
});

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/tdd] The test suite is missing coverage for core.setFailed() inside a switch case body — the rule explicitly handles SwitchCase nodes, but there's no test exercising that path.

💡 Add a switch-case invalid test
{
  code: `switch(x) { case 'a': core.setFailed('bad'); doMore(); break; }`,
  errors: [{ messageId: "missingReturnAfterSetFailed" }],
}

And a valid counterpart:

`switch(x) { case 'a': core.setFailed('bad'); break; }`

Without this, the SwitchCase visitor in the implementation is untested.

@copilot please address this.

},
// Handle single-statement arrow functions (no braces) — rare but safe to skip
// The main case is BlockStatement above.
SwitchCase(node: TSESTree.SwitchCase) {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/codebase-design] Top-level ExpressionStatement bodies (module-level core.setFailed() followed by more statements) won't be caught — the rule only walks BlockStatement and SwitchCase, missing the Program body.

💡 Add a Program visitor
Program(node: TSESTree.Program) {
  checkStatementList(node.body as TSESTree.Statement[], report);
},

In CommonJS scripts, top-level code is common. Without this, a module-level core.setFailed() followed by more code won't be flagged.

@copilot please address this.

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot please run the pr-finisher skill, address any remaining review feedback, refresh the branch if needed, and rerun checks.

Generated by 👨‍🍳 PR Sous Chef · 4.34 AIC · ⌖ 5.93 AIC · ⊞ 7.1K ·
Comment /souschef to run again

…ix and coverage

Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>

Copilot AI commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

@copilot please run the pr-finisher skill, address any remaining review feedback, refresh the branch if needed, and rerun checks.

...

Addressed remaining in-scope review feedback in 86a8b1c. Updated the rule/fixer behavior (including Program coverage and safer suggestion behavior), expanded tests for multiline/trailing-comment/switch/program cases, and reran package-level checks (eslint-factory build/tests/lint). I also reviewed prior failed CI logs via GitHub MCP; those failures were from review-workflow submission constraints and an unrelated stale lock-file workflow, not this rule change.

Copilot AI requested a review from gh-aw-bot July 10, 2026 13:53
@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@pelikhan pelikhan merged commit b382aa7 into main Jul 10, 2026
1 of 2 checks passed
@pelikhan pelikhan deleted the eslint-miner/require-return-after-core-setfailed-24ecd14774ea90dc branch July 10, 2026 14:28
Copilot stopped work on behalf of gh-aw-bot due to an error July 10, 2026 14:28
@github-actions

Copy link
Copy Markdown
Contributor Author

🎉 This pull request is included in a new release.

Release: v0.82.8

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

automation cookie Issue Monster Loves Cookies! eslint

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants