Skip to content

feat: add npm-style update-available notice#24

Open
alerizzo wants to merge 2 commits into
mainfrom
feat/update-available-notice
Open

feat: add npm-style update-available notice#24
alerizzo wants to merge 2 commits into
mainfrom
feat/update-available-notice

Conversation

@alerizzo

Copy link
Copy Markdown
Collaborator

Summary

  • Adds an npm-style "update available" notice via update-notifier@5: when a newer version is published, the CLI prints a one-time upgrade hint to stderr on exit. It never auto-updates.
  • The notice only shows with the default --output table in an interactive TTY. It is suppressed for --output json, when piped/non-TTY, in CI, and under npx/npm scripts — so machine-readable stdout stays byte-clean.
  • The npm lookup runs in a non-blocking detached background process (at most once/day) and never affects command timing or exit codes.
  • Opt-outs: CODACY_DISABLE_UPDATE_CHECK, NO_UPDATE_NOTIFIER, --no-update-notifier.
  • New src/version.ts (single source of name/version, read from package.json at runtime) and src/utils/update-check.ts (maybeNotifyUpdate). Wiring in src/index.ts is a thin preAction hook plus the --no-update-notifier flag on the root and every subcommand.
  • Security: update-notifier@5's transitive package-json@6got@9 is vulnerable to CVE-2022-33987. A package.json overrides entry pins package-json@^7 / got@^11.8.6 (patched, still CommonJS). npm audit --omit=dev reports 0 vulnerabilities.

This mirrors the equivalent feature in analysis-cli#70, adapted for this CLI's tsc build and --output table|json flag.

Test plan

  • npm run check-types — clean
  • npm run build — clean
  • npm test — 409 tests pass (7 new in src/utils/update-check.test.ts)
  • npm ls got package-json — resolves got@11.8.6 / package-json@7.0.0, no got@9
  • Manual: set local version below the npm latest, build, then in a TTY run node dist/index.js info (clear ~/.config/configstore/update-notifier-@codacy/codacy-cloud-cli.json first, run once, wait a few seconds, run again) → boxed notice on stderr
  • node dist/index.js info --output json | jq . → valid JSON, no banner on stdout

🤖 Generated with Claude Code

When a newer version is published, the CLI now prints a one-time upgrade
hint to stderr — it never auto-updates. The notice only shows with the
default --output table in an interactive terminal; it is suppressed for
--output json, when piped, in CI, and under npx/npm scripts, so
machine-readable stdout stays byte-clean. The npm lookup runs in a
non-blocking background process (at most once a day) and never affects
timing or exit codes. Opt out via CODACY_DISABLE_UPDATE_CHECK,
NO_UPDATE_NOTIFIER, or --no-update-notifier.

Uses update-notifier@5 (last CommonJS-compatible major). A package.json
overrides entry pins the transitive got/package-json to patched,
still-CommonJS versions (got@^11.8.6) to avoid CVE-2022-33987.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings June 30, 2026 12:47

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request introduces an npm-style "update available" notice using update-notifier that prints a non-blocking, one-time upgrade hint to stderr when a newer version is published. The notice is safely gated to only show during interactive table output, and can be disabled via several environment variables or the --no-update-notifier flag. Feedback on the changes suggests improving the unit tests in src/utils/update-check.test.ts by using Vitest's vi.stubEnv and vi.unstubAllEnvs() utilities to modify environment variables instead of mutating process.env directly, which prevents test pollution.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +25 to +32
beforeEach(() => {
delete process.env.CODACY_DISABLE_UPDATE_CHECK;
});

afterEach(() => {
vi.clearAllMocks(); // clears call history but keeps the default mock impl
delete process.env.CODACY_DISABLE_UPDATE_CHECK;
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

To prevent environment mutations from leaking across tests, use Vitest's vi.stubEnv and vi.unstubAllEnvs() in afterEach instead of manually deleting properties from process.env.

Suggested change
beforeEach(() => {
delete process.env.CODACY_DISABLE_UPDATE_CHECK;
});
afterEach(() => {
vi.clearAllMocks(); // clears call history but keeps the default mock impl
delete process.env.CODACY_DISABLE_UPDATE_CHECK;
});
afterEach(() => {
vi.clearAllMocks(); // clears call history but keeps the default mock impl
vi.unstubAllEnvs();
});
References
  1. Use Vitest's vi.stubEnv and vi.unstubAllEnvs() in afterEach to modify environment variables in tests, ensuring that environment mutations do not leak across tests.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Keeping direct process.env mutation to match this repo's established test convention — every existing test that touches env (auth.test.ts, info.test.ts, issues.test.ts, and ~7 others) does the same, and none use vi.stubEnv. beforeEach/afterEach already delete the var on both sides, so there's no cross-test leak. Favoring consistency here over the (otherwise reasonable) switch.

🤖 Generated by /pr-fixup command

});

it("honors the CODACY_DISABLE_UPDATE_CHECK opt-out", () => {
process.env.CODACY_DISABLE_UPDATE_CHECK = "1";

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Use vi.stubEnv to set the environment variable instead of mutating process.env directly.

Suggested change
process.env.CODACY_DISABLE_UPDATE_CHECK = "1";
vi.stubEnv("CODACY_DISABLE_UPDATE_CHECK", "1");
References
  1. Use Vitest's vi.stubEnv and vi.unstubAllEnvs() in afterEach to modify environment variables in tests, ensuring that environment mutations do not leak across tests.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Same as above — direct process.env assignment matches the repo-wide test convention, and the var is cleared in both beforeEach and afterEach. Keeping it consistent with the existing suite.

🤖 Generated by /pr-fixup command

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

This PR adds an npm-style “update available” notice to the Codacy Cloud CLI using update-notifier, aiming to keep stdout byte-clean for machine-readable --output json while showing a one-time upgrade hint on stderr for interactive/table usage.

Changes:

  • Introduces runtime CLI name/version resolution (src/version.ts) and an update-notifier wrapper (maybeNotifyUpdate).
  • Wires update checks into the CLI lifecycle via a Commander preAction hook and adds --no-update-notifier support.
  • Adds dependency overrides to avoid a vulnerable transitive got version, plus unit tests and a changeset.

Reviewed changes

Copilot reviewed 7 out of 8 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/version.ts Adds a runtime single source of truth for CLI package name/version from package.json.
src/utils/update-check.ts Implements maybeNotifyUpdate wrapper around update-notifier with format gating and opt-out env var.
src/utils/update-check.test.ts Adds unit tests for the update-check gating/opt-out behavior with update-notifier mocked.
src/index.ts Wires update-check scheduling via preAction hook; registers --no-update-notifier on root and subcommands.
SPECS/README.md Adds a changelog entry describing the new update notice feature.
package.json Adds update-notifier, adds overrides for patched transitive deps, and adds typings.
package-lock.json Updates lockfile for new dependencies and version bump.
.changeset/update-available-notice.md Declares a minor release changeset describing the new behavior and opt-outs.

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

Comment thread src/utils/update-check.ts Outdated
Comment on lines +44 to +47
// Full opt-out: bail before constructing the notifier so no background
// network/disk lookup is even scheduled. (update-notifier also honors
// NO_UPDATE_NOTIFIER and --no-update-notifier on its own.)
if (process.env[DISABLE_ENV_VAR]) return;

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Good catch on the wording. The behavior is actually safe: updateNotifier() runs .check() on construction, and check() returns early when the instance is disabled — which covers NO_UPDATE_NOTIFIER, --no-update-notifier, CI and NODE_ENV=test — before any disk read or network spawn (see update-notifier index.js lines 43-46, 77). So those opt-outs cost one cheap object construction and no background work. Reworded the comment to state this precisely instead of implying the early CODACY_DISABLE_UPDATE_CHECK return is the only safeguard.

🤖 Generated by /pr-fixup command

Comment thread package.json
@codacy-production

codacy-production Bot commented Jun 30, 2026

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 20 complexity · 0 duplication

Metric Results
Complexity 20
Duplication 0

View in Codacy

AI Reviewer: first review requested successfully. AI can make mistakes. Always validate suggestions.

Run reviewer

TIP This summary will be updated as you push new changes.

@codacy-production codacy-production Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull Request Overview

The PR successfully implements the update-available notice system but contains a significant divergence from the requirements regarding the output stream. The implementation currently defaults to stdout, whereas the specification and internal comments indicate stderr should be used to prevent polluting machine-readable output. Additionally, the project is currently 'not up to standards' due to missing coverage requirements for the newly introduced complexity in the update-check logic.

Two security-related findings in the package.json recommend pinning dependency versions to exact values. This is particularly relevant given the PR's intent to address CVE-2022-33987. Ensuring exact versions are used will prevent accidental upgrades to unverified or potentially compromised minor/patch versions in the future.

About this PR

  • There is a systemic discrepancy between the PR description and the implementation: the notification system should target stderr to avoid interfering with stdout-based data processing, but the current configuration uses stdout.

Test suggestions

  • Display notice when output format is 'table' (human-readable)
  • Suppress notice when output format is 'json' (machine-readable)
  • Initialize notifier even in JSON mode to warm the background cache for future calls
  • Fully disable update check when CODACY_DISABLE_UPDATE_CHECK env var is set
  • Verify that background check interval is configured for 24 hours
  • Ensure errors during update check (e.g., registry issues) do not crash the CLI

TIP Improve review quality by adding custom instructions
TIP How was this review? Give us feedback

Comment thread package.json Outdated
"ora": "7.0.1",
"pluralize": "8.0.0"
"pluralize": "8.0.0",
"update-notifier": "^5.1.0"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔴 HIGH RISK

Pin the 'update-notifier' version to ensure consistent behavior and prevent potential dependency confusion or hijacking attacks. This aligns with your current strategy of pinning critical transitive dependencies.

Suggested change
"update-notifier": "^5.1.0"
"update-notifier": "5.1.0"

See Issue in Codacy

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Fixed — pinned update-notifier to exact 5.1.0, and the package-json/got overrides to 7.0.0/11.8.6. Matches the repo's exact-pin convention and resolves this finding.

🤖 Generated by /pr-fixup command

Comment thread src/utils/update-check.ts
// `defer` (default) prints the notice to stderr on process exit, which fires
// even though commands may call process.exit() explicitly. `isGlobal` makes
// the suggested command an `npm i -g …`, matching how this CLI is installed.
notifier.notify({ isGlobal: true });

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 MEDIUM RISK

The PR description and internal comments state the notice is printed to stderr, but 'update-notifier' defaults to stdout. To ensure compatibility with users piping stdout for JSON processing, explicitly configure the output stream to stderr or verify if stdout is acceptable given the TTY/format gating.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

False positive: update-notifier@5 writes the notice via console.error (stderr), not stdout — see node_modules/update-notifier/index.js lines 67/166/169. It also self-suppresses entirely when process.stdout.isTTY is false (line 118), so piping stdout for JSON is doubly safe; we additionally gate on --output table. stdout stays byte-clean.

🤖 Generated by /pr-fixup command

- Pin update-notifier (5.1.0), @types/update-notifier (5.1.0), and the
  got/package-json overrides to exact versions, matching the repo's
  exact-pin convention and resolving the Codacy "variant versions"
  security finding (dependency-confusion risk).
- Reword the opt-out comment in update-check.ts to state precisely that
  NO_UPDATE_NOTIFIER/--no-update-notifier/CI/NODE_ENV=test are handled by
  update-notifier's own disabled check (which returns before any disk or
  network work), rather than implying the early CODACY_DISABLE_UPDATE_CHECK
  return is the only safeguard.
- Add .gemini/styleguide.md capturing project review conventions (direct
  process.env mutation in tests, stderr-only diagnostics, exact dep pins,
  generated-file false positives) to reduce future AI-review false positives.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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