Wire eslint-rules RuleTester suite into a runner, CI, and knip (#4409) - #4433
Conversation
The custom ESLint rule eslint-rules/no-use-client-in-server-files.cjs guards a real hazard (a 'use client' directive landing in a server-only file) and ships a RuleTester suite next to it, but nothing executed that suite: no package script, workflow, or lefthook entry referenced it, so the rule could regress silently while its "tests" rotted. knip could not flag the orphan either, because the root workspace project globs only scanned top-level files. This wires the suite in with the smallest footprint, matching the existing "Test GitHub Action helpers" precedent that runs a standalone .cjs test via plain node (ESLint's RuleTester runs standalone and exits non-zero on failure, so no test framework is needed): - package.json: add "test:eslint-rules" (plain node invocation) and chain it into the aggregate "check" script. - .github/workflows/lint-js-and-ruby.yml: add a "Test custom ESLint rules" step next to "Test GitHub Action helpers" so it runs on every PR. - knip.ts: add eslint-rules/**/*.cjs to the root project globs and eslint-rules/**/*.test.cjs to entry (the test has no importer), so the directory is analyzed and stays clean. No new dependencies. The test file itself needed no changes to be runnable. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Workflow Change AuditFile: Classification: SEMANTIC — adds a new CI step (test gate) to the existing Diff (the entire workflow change): - name: Test GitHub Action helpers
run: node .github/actions/ensure-main-docs-safety/check-previous-main.test.cjs
+ - name: Test custom ESLint rules
+ run: pnpm run test:eslint-rules
- name: Check formatting
run: pnpm start format.listDifferentBefore → After audit of security-relevant surfaces:
Command-injection review: the added Net effect: one additional lint-job step that executes the repo's own custom-ESLint-rule RuleTester suite. It runs in the existing A follow-up issue for post-merge Actions verification is linked below. |
|
Caution Review failedFailed to post review comments. GitHub was unavailable or timed out while CodeRabbit was posting the review. Please request a new review later if the pull request still needs one. Use ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
🧰 Additional context used📓 Path-based instructions (2).github/workflows/**📄 CodeRabbit inference engine (AGENTS.md)
Files:
**/package.json📄 CodeRabbit inference engine (AGENTS.md)
Files:
🧠 Learnings (3)📚 Learning: 2026-06-18T22:53:09.355ZApplied to files:
📚 Learning: 2026-06-18T22:53:16.750ZApplied to files:
📚 Learning: 2026-06-01T08:02:28.428ZApplied to files:
WalkthroughThis PR wires a previously orphaned ESLint rule test file into the project's tooling: a new ChangesTest wiring for custom ESLint rules
Estimated code review effort: 1 (Trivial) | ~5 minutes Related issues: Suggested labels: tooling, ci, testing Suggested reviewers: justin808 🐰 A rule once tested, silently, alone, 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
ESLint install failed: dependency version conflict. Check your lock file or package.json. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Greptile SummaryThis PR wires up an existing but previously unexecuted
Confidence Score: 5/5Safe to merge — all three files make minimal, targeted additions with no logic changes to the rule or test file itself. The change is purely additive CI/tooling wiring. The new workflow step follows the exact same pattern as the adjacent Test GitHub Action helpers step. The knip entries correctly separate entry (no-importer test file) from project (rule file imported by eslint.config.ts). The test:eslint-rules script explicitly targets a .cjs extension, which is evaluated as CommonJS by Node regardless of the workspace-level type:module. No runtime code is affected. No files require special attention. Important Files Changed
Reviews (1): Last reviewed commit: "Wire eslint-rules RuleTester suite into ..." | Re-trigger Greptile |
size-limit report 📦
|
…cache-4317 * origin/main: Preserve streaming LoadError during dependency failures (#4388) Wire eslint-rules RuleTester suite into a runner, CI, and knip (#4409) (#4433) Handle fire-and-forget RSCRoute retry failures (#4378) Fix visible hydration cleanup for detached roots (#4374) Avoid full locale default obsolete scans (#4398) Document RSC public-page validation and sidecar patterns (#4387) # Conflicts: # CHANGELOG.md
…derer-shutdown-restart * origin/main: Preserve streaming LoadError during dependency failures (#4388) Wire eslint-rules RuleTester suite into a runner, CI, and knip (#4409) (#4433) Handle fire-and-forget RSCRoute retry failures (#4378) Fix visible hydration cleanup for detached roots (#4374) Avoid full locale default obsolete scans (#4398)
* origin/main: Preserve streaming LoadError during dependency failures (#4388) Wire eslint-rules RuleTester suite into a runner, CI, and knip (#4409) (#4433) Handle fire-and-forget RSCRoute retry failures (#4378) Fix visible hydration cleanup for detached roots (#4374) Avoid full locale default obsolete scans (#4398) Document RSC public-page validation and sidecar patterns (#4387) Remove dead methods; prune always-false Rails<5.0 spec branches (#4418) (#4431)
…-4364 * origin/main: (24 commits) Preserve streaming LoadError during dependency failures (#4388) Wire eslint-rules RuleTester suite into a runner, CI, and knip (#4409) (#4433) Handle fire-and-forget RSCRoute retry failures (#4378) Fix visible hydration cleanup for detached roots (#4374) Avoid full locale default obsolete scans (#4398) Document RSC public-page validation and sidecar patterns (#4387) Remove dead methods; prune always-false Rails<5.0 spec branches (#4418) (#4431) Drop deprecation-tombstone config options for 17.0.0 (#4419) (#4432) Add mechanical parity guards for Ruby↔TS protocol constants (#4412) (#4427) Move Node tsconfigs from @tsconfig/node14 to @tsconfig/node18 (#4410) (#4429) [Pro] Remove unused addressable and rainbow runtime deps from gemspec (#4416) (#4422) Delete finished #3313 Prism Gemfile-rewriter spike (#4421) Extract generator scan/tracking helpers (#4405) (#4430) Extract install_dependency_group helper in JsDependencyManager (#4403) (#4424) Remove obsolete Ruby<2.6 YAML-aliases capability shim (#4417) (#4428) Remove inert config.server_render_method option (#4415) (#4423) Prune stale knip ignores and enforce binaries in CI (#4408) (#4425) Extract shared redux_store kwargs validator (#4402) (#4420) Avoid caching async props prerender streams (#4376) Release incremental render context on setup failure (#4383) ... # Conflicts: # CHANGELOG.md
…370' into codex/batch-e-loadable-stats-retry-4371 * origin/codex/batch-e-rsc-parser-flush-4370: Add cached static RSC helper and diagnostics (#4386) Fix Pro tag revalidation retry after delete failures (#4375) Fix node renderer graceful shutdown restarts (#4400) Improve release-finish dry-run fetch handling (#4441) Flush RSC payloads before incomplete HTML tails (#4379) Handle sync RSC route failures as fetch errors (#4393) Delete never-wired RenderRequest/JsCodeBuilder/RenderingStrategy layer (#4414) (#4437) Delegate deprecated base/ shims to capabilities/ instead of cloning (#4413) (#4436) Remove pre-monorepo node-renderer devDep baggage; consolidate test multipart builders (#4435) Preserve streaming LoadError during dependency failures (#4388) Wire eslint-rules RuleTester suite into a runner, CI, and knip (#4409) (#4433) Handle fire-and-forget RSCRoute retry failures (#4378)
Why
The custom ESLint rule
eslint-rules/no-use-client-in-server-files.cjsguards a real hazard — a'use client'directive landing in a server-only (.server.tsx/.server.ts) file, which forces webpack to bundle it as a client component and breaks React'sreact-serverconditional exports. ARuleTestersuite ships right next to it ineslint-rules/no-use-client-in-server-files.test.cjs, but nothing executed that suite: no package script, no workflow, no lefthook entry referenced it (grep -rn "no-use-client-in-server-files.test"→ zero hits). The rule could regress silently while its "tests" rotted — a coverage illusion. knip couldn't flag the orphan either, because the root workspace'sprojectglobs only scanned top-level files (noeslint-rules/, no.cjs).Fixes #4409What changed
Smallest-footprint wiring, matching the existing precedent in this same workflow — the
Test GitHub Action helpersstep runs a standalone.cjstest via plainnode. ESLint'sRuleTesterruns standalone and throws (exits non-zero) on failure, so no test framework is needed.package.json: add"test:eslint-rules": "node eslint-rules/no-use-client-in-server-files.test.cjs"and chain it into the aggregate"check"script (pnpm run lint && pnpm run test:eslint-rules && pnpm -r run check)..github/workflows/lint-js-and-ruby.yml: add aTest custom ESLint rulesstep immediately afterTest GitHub Action helpersin thebuildjob, so the suite runs on every PR.knip.ts(root workspace): addeslint-rules/**/*.cjstoproject(so the directory is analyzed) andeslint-rules/**/*.test.cjstoentry(the test file has no importer, so knip needs it declared as an entry point). The rule.cjsis seen as used via itsimportineslint.config.ts.No new dependencies. The test file itself needed no changes to be runnable.
Validation (real results, local; Node 22.12.0 pinned in
.tool-versions= CI Node)Core proof — the test runs and passes via the new script:
Fail-when-broken proof — the test genuinely exercises the rule (not a no-op): temporarily changed a
validfixture's filename fromComponent.tsxtoComponent.server.tsx(so a'use client'server file was asserted valid). The run failed with exit code 1:The rule correctly flagged 1 error where the (broken) test asserted 0. Reverted;
git diffon the test file is empty and it passes again.Other gates (all green):
pnpm exec knipeslint-rules/unused/unlisted linespnpm exec knip --productionorigin/main— pre-existingprop-typesfinding inreact_on_rails/spec/dummy(generated-packs artifact), byte-identical behavior with/without my change. My globs add zero new findings.pnpm run lint(eslint)pnpm start format.listDifferent(prettier)pnpm run type-checkpnpm run test(main suite)main); orthogonal totest:eslint-rules. Sanity-rancreate-react-on-rails-app: 104/104 passactionlint .github/workflows/lint-js-and-ruby.ymlyamllintQA Evidence
pnpm run test:eslint-rules) was executed locally on the pinned CI Node (22.12.0) and passes (exit 0).ERR_ASSERTION actual:1 expected:0) → reverted → passes again (emptygit diffon the test file). This is the "deliberately break an assertion, confirm the step fails, restore" evidence the issue's acceptance criteria requires.Test custom ESLint rulesCI step goes green.Codex Decision Log
codex review --base origin/mainran and returned: "No actionable correctness, CI wiring, or maintainability issues were found in the diff. The new ESLint rule test script is wired into both the lint workflow and the root check script, and the Knip entries account for the standalone test files." No findings to address.New-gate stale-base race control
Swept open PRs (
gh pr list --state open, 24 open). Only #4390 (Tighten hosted CI workflow safeguards) also toucheslint-js-and-ruby.yml, but it edits thedetect-changesjob'sif:condition (~line 26); my change adds a step in thebuildjob (~line 210) — no line-level collision, merges cleanly in either order. No PR toucheseslint-rules/,knip.ts, orpackage.jsonscripts. Coordinator should re-sweep before landing.Labels: ready-for-hosted-ci, hosted-ci-no-benchmarks — CI/tooling-only change (test wiring, knip globs, one CI step); cannot affect runtime performance, so benchmarks add no signal.
🤖 Generated with Claude Code
Summary by CodeRabbit
Tests
Chores