Skip to content

feat(cli): warn that the next major will require Node 20+ - #2411

Merged
aryanku-dev merged 1 commit into
masterfrom
feat/cli-node-20-deprecation-warning
Sep 1, 2026
Merged

aryanku-dev merged 1 commit into
masterfrom
feat/cli-node-20-deprecation-warning

Conversation

@aryanku-dev

@aryanku-dev aryanku-dev commented Aug 31, 2026 •

Copy link
Copy Markdown
Contributor

What

Tells every user that the next major version of @percy/cli will require Node 20+, so they can pin or get their setup ready before it lands.

$ percy exec -- echo
Heads up! The next major version of @percy/cli will require Node 20+. Either pin
@percy/cli to its current major version, or make sure your setup runs on Node 20+,
before the next major release.

Why

Nothing currently announces the upcoming minimum-version bump. Without a heads up, the first signal users get is a broken pipeline the day the major lands.

How

Five lines in packages/cli/bin/run.cjs, after the existing Node < 14 gate (which is untouched):

// heads up ahead of the next major release, which raises the minimum to Node 20
console.warn('Heads up! The next major version of @percy/cli will require Node 20+. ' + (
  'Either pin @percy/cli to its current major version, or make sure your setup runs ' +
  'on Node 20+, before the next major release.'));

Shown to everyone, not just users below Node 20 — the announcement matters to anyone who might upgrade across the major, whatever Node they are on today.

Notes

  • Warning only, nothing breaks. The current major still supports Node 14+, so engines stays ">=14" — that bump belongs to the major release itself.
  • Printed before the dist/index.js import, so it fires for every command and never on programmatic use of the package.
  • Intentionally has no mute switch. It should be removed when the major ships.

Testing

Verified by hand on Node v18.20.8 — the warning prints ahead of the command. Lint passes. No unit test: bin/run.cjs is the pre-dist bootstrap and isn't covered by the jasmine suite, same as the existing < 14 gate.

🤖 Generated with Claude Code

@aryanku-dev
aryanku-dev requested a review from a team as a code owner August 31, 2026 09:12
@aryanku-dev aryanku-dev changed the title feat(cli): warn that the next major will require Node >= 20 feat(cli): warn that the next major will require Node 20+ Aug 31, 2026
Nothing currently tells users the next major release raises the minimum to
Node 20. Print a heads up on every run, naming both ways out: pin @percy/cli
to its current major, or get the setup onto Node 20+.

Warning only. The current major still supports Node 14+, so `engines` stays at
">=14" — that bump belongs to the major release itself.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@aryanku-dev
aryanku-dev force-pushed the feat/cli-node-20-deprecation-warning branch from 4ef410f to f15541e Compare August 31, 2026 09:30

@aryanku-dev aryanku-dev 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.

Claude Code Review (automated) — 2 inline finding(s). Full report in the PR comment below. Verdict: Passed.

Comment thread packages/cli/bin/run.cjs
}

// heads up ahead of the next major release, which raises the minimum to Node 20
console.warn('Heads up! The next major version of @percy/cli will require Node 20+. ' + (

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.

[Medium] Warning has no mute switch and prints on every invocation

Every other user-facing warning in this codebase can be silenced — checkForUpdate() honours PERCY_SKIP_UPDATE_CHECK, and logger output honours PERCY_LOGLEVEL. This one runs before @percy/logger is loaded and has no env gate, so it prints on every command (percy --version, percy --help, every subcommand, every CI matrix job) for the whole life of the current major. The blast radius is every Percy SDK's CI logs.

Suggestion: Called out as intentional in the PR description, so not blocking — but it is a product decision with wide reach and deserves an explicit second sign-off. If the noise proves excessive, update.js's CACHE_FILE / CACHE_MAX_AGE pattern is a ready-made template for "print at most once per N days" without adding an opt-out flag.

Reviewer: stack-code-reviewer

Comment thread packages/cli/bin/run.cjs
process.exit(1);
}

// heads up ahead of the next major release, which raises the minimum to Node 20

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.

[Low] No tracking reference for removal, and no note on why console.warn

Two small things this comment could carry:

  1. Nothing guarantees this block is deleted when the next major bumps engines.node to >=20. If forgotten it becomes permanently wrong — telling Node 20+ users that "the next major" will require Node 20+, which they are already past.
  2. The raw console.warn is correct here (@percy/logger only exists after the dynamic import('../dist/index.js') resolves), but nothing says so — a future contributor "cleaning this up" into logger.warn(...) would introduce a load-order bug.

Suggestion: // TODO(PER-XXXX): remove once vX ships with engines.node >=20. Uses console.warn because @percy/logger is not loaded until the import below.

Reviewer: stack-code-reviewer

@aryanku-dev

Copy link
Copy Markdown
Contributor Author

Claude Code PR Review

PR: #2411 • Head: f15541e • Reviewers: stack-code-reviewer

Summary

Adds an unconditional console.warn to the CLI's CJS entrypoint announcing that the next major version of @percy/cli will require Node 20+, telling users to either pin @percy/cli to its current major or move their setup to Node 20+. One file, +5/−0. engines.node deliberately stays at ">=14"; the existing Node < 14 hard exit is untouched.

Review Table

Priority Category Check Status Notes
High Security No hardcoded secrets or credentials Pass Static string literal only.
High Security Authentication/authorization checks present N/A No auth surface in a bin bootstrap.
High Security Input validation and sanitization N/A No input consumed by the new code.
High Security No IDOR — resource ownership validated N/A No resource access.
High Security No SQL injection (parameterized queries) N/A No data layer.
High Correctness Logic is correct, handles edge cases Pass Unconditional by design; placed after the Node < 14 hard exit so unsupported versions still get only the fatal error, no double messaging.
High Correctness Error handling is explicit, no swallowed exceptions N/A No error paths introduced.
High Correctness No race conditions or concurrency issues Pass Synchronous, runs before the dynamic import().
Medium Testing New code has corresponding tests N/A bin/run.cjs is the pre-dist bootstrap and has no existing coverage — the sibling Node < 14 gate is untested too, so this is not a regression. Verified by hand on Node v18.20.8.
Medium Testing Error paths and edge cases tested N/A No error paths.
Medium Testing Existing tests still pass (no regressions) Pass No src/ or dist/ code touched; the jasmine suite does not load bin/run.cjs.
Medium Performance No N+1 queries or unbounded data fetching N/A No I/O added.
Medium Performance Long-running tasks use background jobs N/A Single synchronous write to stderr.
Medium Quality Follows existing codebase patterns Pass Mirrors the adjacent console.error gate: same string-concatenation style, same stream family, same pre-dist placement.
Medium Quality Changes are focused (single concern) Pass One file, one concern.
Low Quality Meaningful names, no dead code Pass No new identifiers; no dead code.
Low Quality Comments explain why, not what Fail The comment states what the warning is for but not why raw console.warn is used instead of @percy/logger, and carries no tracking reference for its removal. See findings 2 and 4.
Low Quality No unnecessary dependencies added Pass No dependencies added.

Findings

1. Warning has no mute switch and prints on every invocation

  • File: packages/cli/bin/run.cjs:12
  • Severity: Medium
  • Reviewer: stack-code-reviewer
  • Issue: Every other user-facing warning in this codebase can be silenced — checkForUpdate() honours PERCY_SKIP_UPDATE_CHECK (packages/cli/src/update.js), and logger output honours PERCY_LOGLEVEL. This one runs before @percy/logger is loaded and has no env gate, so it prints on every command (percy --version, percy --help, every subcommand, every CI matrix job) for the whole life of the current major, with no way for a consumer to turn it off. The blast radius is every Percy SDK's CI logs, not just this repo.
  • Suggestion: This is called out as intentional in the PR description, so it is not blocking — but it is a product decision with wide reach and deserves an explicit second sign-off rather than passing as an implementation detail. If the noise proves excessive, update.js's existing CACHE_FILE / CACHE_MAX_AGE pattern is a ready-made template for "print at most once per N days" without introducing an opt-out flag.

2. No tracking reference for removing the warning when the major ships

  • File: packages/cli/bin/run.cjs:11
  • Severity: Low
  • Reviewer: stack-code-reviewer
  • Issue: Nothing guarantees this block is deleted when the next major actually bumps engines.node to >=20. If it is forgotten it becomes permanently wrong on the new major's line — telling Node 20+ users that "the next major" will require Node 20+, which they are already past.
  • Suggestion: Add a // TODO(PER-XXXX): remove once vX ships with engines.node >=20 reference, or add the removal to the major-bump PR checklist.

3. "Heads up!" lead-in duplicates the update-check warnings

  • File: packages/cli/bin/run.cjs:12
  • Severity: Low
  • Reviewer: stack-code-reviewer
  • Issue: checkForUpdate() already opens with Heads up! The current version of @percy/cli is more than 10 releases behind!. Both fire on the same run for anyone behind on both Node and the CLI — a likely overlap — producing two back-to-back paragraphs that both start with "Heads up!".
  • Suggestion: Use a distinct lead-in for one of the two.

4. Comment does not explain why console.warn is used instead of @percy/logger

  • File: packages/cli/bin/run.cjs:11
  • Severity: Low
  • Reviewer: stack-code-reviewer
  • Issue: The raw console.warn is correct here — @percy/logger only exists after the dynamic import('../dist/index.js') resolves — but nothing in the comment says so. A future contributor "cleaning this up" into logger.warn(...) would introduce a load-order bug.
  • Suggestion: Extend the comment to note that the logger is not loaded yet at this point, mirroring the reason the Node < 14 gate above uses console.error.

Confirmed as correct

  • Stream choice. console.warn writes to stderr, matching @percy/logger's warn level, so it cannot pollute stdout that SDKs or scripts parse for machine-readable output.
  • Placement. Sitting after the Node < 14 hard exit means unsupported versions still get only the existing fatal error.
  • engines untouched. Leaving ">=14" in place means npm install does not newly fail for current-major users on Node 14/16/18, consistent with the warning-only intent.

Verdict: PASS — no High or Critical findings. One Medium worth an explicit product sign-off (unconditional, unmutable output on every invocation across every consumer's CI) and three Low polish items.

@aryanku-dev
aryanku-dev merged commit 8ff7f1e into master Sep 1, 2026
48 checks passed
@aryanku-dev
aryanku-dev deleted the feat/cli-node-20-deprecation-warning branch September 1, 2026 14:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants