Skip to content

fix(exec): skip deps auto-install without manifest#12301

Merged
zkochan merged 1 commit into
pnpm:mainfrom
scarab-systems:fix/deps-status-no-manifest
Jun 10, 2026
Merged

fix(exec): skip deps auto-install without manifest#12301
zkochan merged 1 commit into
pnpm:mainfrom
scarab-systems:fix/deps-status-no-manifest

Conversation

@scarab-systems

@scarab-systems scarab-systems commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Skip the dependency-status auto-install path only when dependency status was intentionally skipped outside a project manifest.
  • Preserve the existing fallback behavior for unexpected upToDate: undefined results when a project manifest exists.
  • Add regression coverage for both the no-manifest skip and unexpected-unknown fallback cases.
  • Add a changeset for @pnpm/exec.commands and pnpm.

Why

When dependency status cannot be evaluated because there is no root project manifest and the command is not recursive, checkDepsStatus() already returns upToDate: undefined after warning that the check is skipped. The consumer only returned early for true, so this intentional skip fell through to the auto-install path and could surface ERR_PNPM_NO_PKG_MANIFEST outside a project directory.

This keeps the install/error/warn/prompt path for other unknown-status results, matching the existing fallback behavior.

Closes #12240.

Checks

  • volta run --node 22.22.2 corepack pnpm install --frozen-lockfile
  • volta run --node 22.22.2 corepack pnpm run lint from exec/commands
  • NODE_OPTIONS="$NODE_OPTIONS --experimental-vm-modules --disable-warning=ExperimentalWarning --disable-warning=DEP0169" volta run --node 22.22.2 corepack pnpm exec jest test/runDepsStatusCheck.test.ts test/createInstallArgs.test.ts --runInBand from exec/commands
  • volta run --node 22.22.2 corepack pnpm exec tsgo --build --pretty false from exec/commands
  • pnpm pre-push hook completed: pnpm run compile-only && pnpm run lint --quiet; Rust checks skipped because this PR does not touch pacquet/ or pnpr/.

Written by an agent (Codex, GPT-5).

Summary by CodeRabbit

  • Bug Fixes

    • Refined dependency auto-install logic to skip installs when no project manifest is present, but still run install/verification when a manifest exists and dependency status cannot be determined.
  • Tests

    • Added tests for dependency-status unavailability covering both missing-manifest and manifest-present scenarios.
  • Chores

    • Updated release metadata to target patch releases and clarified auto-install behavior when project manifest is absent.

@scarab-systems scarab-systems requested a review from zkochan as a code owner June 9, 2026 23:37
@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Jun 9, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (0) 📎 Requirement gaps (0)

Context used

Grey Divider


Remediation recommended

1. Unknown status now skipped 🐞 Bug ☼ Reliability
Description
runDepsStatusCheck() now returns early for any upToDate value except explicit false, so
upToDate: undefined no longer triggers the install/warn/prompt/error path. This silently disables
verifyDepsBeforeRun when checkDepsStatus() returns upToDate: undefined due to unexpected
errors (where the deps-status code previously relied on a redundant install as a safe fallback).
Code

exec/commands/src/runDepsStatusCheck.ts[R20-21]

const { upToDate, issue, workspaceState } = await checkDepsStatus(opts)
-  if (upToDate) return
+  if (upToDate !== false) return
Evidence
The new guard returns early on upToDate: undefined, but deps-status uses undefined both for
intentional “skip” and for unexpected-error “unknown” cases; the latter was designed to fall back to
redundant install behavior. Returning early breaks that fallback and ignores any issue returned
for the error case.

exec/commands/src/runDepsStatusCheck.ts[14-64]
deps/status/src/checkDepsStatus.ts[79-107]
deps/status/src/checkDepsStatus.ts[98-105]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`runDepsStatusCheck()` now treats any `upToDate !== false` as “no-op”. This is correct for the “skipping check because no manifest” scenario, but it also suppresses `verifyDepsBeforeRun` behavior when `checkDepsStatus()` returns `upToDate: undefined` due to unexpected/internal errors (a case where deps-status explicitly returns `undefined` to avoid crashing and previously relied on the caller to fall back to redundant install/warn/prompt/error handling).
## Issue Context
In `checkDepsStatus()`, unexpected errors return `{ upToDate: undefined, issue: <message> }` with a comment that the redundant install fallback is acceptable. With the new early return, the `issue` is ignored and no fallback happens.
## Fix Focus Areas
- exec/commands/src/runDepsStatusCheck.ts[20-24]
### Suggested direction
Update the early-return to only skip on `undefined` when the check was intentionally skipped (e.g. no root manifest and not recursive), while keeping the fallback path for other `undefined` cases.
One pragmatic approach:
- Keep `if (upToDate === true) return`.
- Add a special-case skip for the known “no manifest + non-recursive” scenario (matching the skip condition described in deps-status): `if (upToDate === undefined && opts.allProjects == null && opts.rootProjectManifest == null) return`.
- Otherwise, treat `undefined` as “cannot verify” and proceed to the `verifyDepsBeforeRun` switch (install/warn/prompt/error) using `issue` when present.
Alternatively (more explicit contract): adjust `@pnpm/deps.status` to return a distinct flag/reason (or return `upToDate: true` for intentional skip), so callers can safely distinguish “skipped” from “unknown due to error”.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Previous review results

Review updated until commit 3757dde

Results up to commit cb68ac1


🐞 Bugs (1) 📘 Rule violations (0) 📎 Requirement gaps (0)

Context used

Remediation recommended
1. Unknown status now skipped 🐞 Bug ☼ Reliability
Description
runDepsStatusCheck() now returns early for any upToDate value except explicit false, so
upToDate: undefined no longer triggers the install/warn/prompt/error path. This silently disables
verifyDepsBeforeRun when checkDepsStatus() returns upToDate: undefined due to unexpected
errors (where the deps-status code previously relied on a redundant install as a safe fallback).
Code

exec/commands/src/runDepsStatusCheck.ts[R20-21]

const { upToDate, issue, workspaceState } = await checkDepsStatus(opts)
-  if (upToDate) return
+  if (upToDate !== false) return
Evidence
The new guard returns early on upToDate: undefined, but deps-status uses undefined both for
intentional “skip” and for unexpected-error “unknown” cases; the latter was designed to fall back to
redundant install behavior. Returning early breaks that fallback and ignores any issue returned
for the error case.

exec/commands/src/runDepsStatusCheck.ts[14-64]
deps/status/src/checkDepsStatus.ts[79-107]
deps/status/src/checkDepsStatus.ts[98-105]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`runDepsStatusCheck()` now treats any `upToDate !== false` as “no-op”. This is correct for the “skipping check because no manifest” scenario, but it also suppresses `verifyDepsBeforeRun` behavior when `checkDepsStatus()` returns `upToDate: undefined` due to unexpected/internal errors (a case where deps-status explicitly returns `undefined` to avoid crashing and previously relied on the caller to fall back to redundant install/warn/prompt/error handling).
## Issue Context
In `checkDepsStatus()`, unexpected errors return `{ upToDate: undefined, issue: <message> }` with a comment that the redundant install fallback is acceptable. With the new early return, the `issue` is ignored and no fallback happens.
## Fix Focus Areas
- exec/commands/src/runDepsStatusCheck.ts[20-24]
### Suggested direction
Update the early-return to only skip on `undefined` when the check was intentionally skipped (e.g. no root manifest and not recursive), while keeping the fallback path for other `undefined` cases.
One pragmatic approach:
- Keep `if (upToDate === true) return`.
- Add a special-case skip for the known “no manifest + non-recursive” scenario (matching the skip condition described in deps-status): `if (upToDate === undefined && opts.allProjects == null && opts.rootProjectManifest == null) return`.
- Otherwise, treat `undefined` as “cannot verify” and proceed to the `verifyDepsBeforeRun` switch (install/warn/prompt/error) using `issue` when present.
Alternatively (more explicit contract): adjust `@pnpm/deps.status` to return a distinct flag/reason (or return `upToDate: true` for intentional skip), so callers can safely distinguish “skipped” from “unknown due to error”.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Results up to commit 0238aaa


🐞 Bugs (1) 📘 Rule violations (0) 📎 Requirement gaps (0)

Context used

Remediation recommended
1. Unknown status now skipped 🐞 Bug ☼ Reliability
Description
runDepsStatusCheck() now returns early for any upToDate value except explicit false, so
upToDate: undefined no longer triggers the install/warn/prompt/error path. This silently disables
verifyDepsBeforeRun when checkDepsStatus() returns upToDate: undefined due to unexpected
errors (where the deps-status code previously relied on a redundant install as a safe fallback).
Code

exec/commands/src/runDepsStatusCheck.ts[R20-21]

 const { upToDate, issue, workspaceState } = await checkDepsStatus(opts)
-  if (upToDate) return
+  if (upToDate !== false) return
Evidence
The new guard returns early on upToDate: undefined, but deps-status uses undefined both for
intentional “skip” and for unexpected-error “unknown” cases; the latter was designed to fall back to
redundant install behavior. Returning early breaks that fallback and ignores any issue returned
for the error case.

exec/commands/src/runDepsStatusCheck.ts[14-64]
deps/status/src/checkDepsStatus.ts[79-107]
deps/status/src/checkDepsStatus.ts[98-105]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`runDepsStatusCheck()` now treats any `upToDate !== false` as “no-op”. This is correct for the “skipping check because no manifest” scenario, but it also suppresses `verifyDepsBeforeRun` behavior when `checkDepsStatus()` returns `upToDate: undefined` due to unexpected/internal errors (a case where deps-status explicitly returns `undefined` to avoid crashing and previously relied on the caller to fall back to redundant install/warn/prompt/error handling).
## Issue Context
In `checkDepsStatus()`, unexpected errors return `{ upToDate: undefined, issue: <message> }` with a comment that the redundant install fallback is acceptable. With the new early return, the `issue` is ignored and no fallback happens.
## Fix Focus Areas
- exec/commands/src/runDepsStatusCheck.ts[20-24]
### Suggested direction
Update the early-return to only skip on `undefined` when the check was intentionally skipped (e.g. no root manifest and not recursive), while keeping the fallback path for other `undefined` cases.
One pragmatic approach:
- Keep `if (upToDate === true) return`.
- Add a special-case skip for the known “no manifest + non-recursive” scenario (matching the skip condition described in deps-status): `if (upToDate === undefined && opts.allProjects == null && opts.rootProjectManifest == null) return`.
- Otherwise, treat `undefined` as “cannot verify” and proceed to the `verifyDepsBeforeRun` switch (install/warn/prompt/error) using `issue` when present.
Alternatively (more explicit contract): adjust `@pnpm/deps.status` to return a distinct flag/reason (or return `upToDate: true` for intentional skip), so callers can safely distinguish “skipped” from “unknown due to error”.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Results up to commit 0b420b0


🐞 Bugs (1) 📘 Rule violations (0) 📎 Requirement gaps (0)

Context used

Remediation recommended
1. Unknown status now skipped 🐞 Bug ☼ Reliability
Description
runDepsStatusCheck() now returns early for any upToDate value except explicit false, so
upToDate: undefined no longer triggers the install/warn/prompt/error path. This silently disables
verifyDepsBeforeRun when checkDepsStatus() returns upToDate: undefined due to unexpected
errors (where the deps-status code previously relied on a redundant install as a safe fallback).
Code

exec/commands/src/runDepsStatusCheck.ts[R20-21]

  const { upToDate, issue, workspaceState } = await checkDepsStatus(opts)
-  if (upToDate) return
+  if (upToDate !== false) return
Evidence
The new guard returns early on upToDate: undefined, but deps-status uses undefined both for
intentional “skip” and for unexpected-error “unknown” cases; the latter was designed to fall back to
redundant install behavior. Returning early breaks that fallback and ignores any issue returned
for the error case.

exec/commands/src/runDepsStatusCheck.ts[14-64]
deps/status/src/checkDepsStatus.ts[79-107]
deps/status/src/checkDepsStatus.ts[98-105]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`runDepsStatusCheck()` now treats any `upToDate !== false` as “no-op”. This is correct for the “skipping check because no manifest” scenario, but it also suppresses `verifyDepsBeforeRun` behavior when `checkDepsStatus()` returns `upToDate: undefined` due to unexpected/internal errors (a case where deps-status explicitly returns `undefined` to avoid crashing and previously relied on the caller to fall back to redundant install/warn/prompt/error handling).

## Issue Context
In `checkDepsStatus()`, unexpected errors return `{ upToDate: undefined, issue: <message> }` with a comment that the redundant install fallback is acceptable. With the new early return, the `issue` is ignored and no fallback happens.

## Fix Focus Areas
- exec/commands/src/runDepsStatusCheck.ts[20-24]

### Suggested direction
Update the early-return to only skip on `undefined` when the check was intentionally skipped (e.g. no root manifest and not recursive), while keeping the fallback path for other `undefined` cases.

One pragmatic approach:
- Keep `if (upToDate === true) return`.
- Add a special-case skip for the known “no manifest + non-recursive” scenario (matching the skip condition described in deps-status): `if (upToDate === undefined && opts.allProjects == null && opts.rootProjectManifest == null) return`.
- Otherwise, treat `undefined` as “cannot verify” and proceed to the `verifyDepsBeforeRun` switch (install/warn/prompt/error) using `issue` when present.

Alternatively (more explicit contract): adjust `@pnpm/deps.status` to return a distinct flag/reason (or return `upToDate: true` for intentional skip), so callers can safely distinguish “skipped” from “unknown due to error”.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Qodo Logo

@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 19ab01c0-abcf-414a-a6a3-ee44003c6e18

📥 Commits

Reviewing files that changed from the base of the PR and between cb68ac1 and 3757dde.

📒 Files selected for processing (3)
  • .changeset/deps-status-no-manifest.md
  • exec/commands/src/runDepsStatusCheck.ts
  • exec/commands/test/runDepsStatusCheck.test.ts
✅ Files skipped from review due to trivial changes (1)
  • .changeset/deps-status-no-manifest.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • exec/commands/src/runDepsStatusCheck.ts
  • exec/commands/test/runDepsStatusCheck.test.ts

📝 Walkthrough

Walkthrough

This PR tightens runDepsStatusCheck's early-exit: it only skips work when deps are explicitly up-to-date or when status is undefined and there's no manifest/allProjects context. It adds tests for undefined-status branches and updates a changeset to target patch releases and document the no-manifest behavior.

Changes

Dependency Status Check Fix

Layer / File(s) Summary
Early-exit on unavailable dependency status
exec/commands/src/runDepsStatusCheck.ts, exec/commands/test/runDepsStatusCheck.test.ts, .changeset/deps-status-no-manifest.md
runDepsStatusCheck now returns early only for upToDate === true or for upToDate === undefined when both allProjects and rootProjectManifest are absent. New Jest tests cover the missing-manifest no-install path and the manifest-present install path; the changeset records patch version bumps and the behavior note.

Sequence Diagram(s)

sequenceDiagram
  participant runDepsStatusCheck
  participant checkDepsStatus
  participant runPnpmCli
  runDepsStatusCheck->>checkDepsStatus: checkDepsStatus(opts) => { upToDate, issues }
  alt upToDate === true
    runDepsStatusCheck-->>runDepsStatusCheck: return early
  else upToDate === undefined and no rootProjectManifest & not allProjects
    runDepsStatusCheck-->>runDepsStatusCheck: return early (skip install)
  else
    runDepsStatusCheck->>runPnpmCli: runPnpmCli(['install'], { cwd, reporter })
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested reviewers

  • zkochan

Poem

🐇 I checked the burrow, no manifest in sight,
So I skipped the install and hopped on light.
If clues remain and context is there,
I call the install with careful care.
Patch noted, carrot in paw — tidy and bright.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: skipping dependency auto-install when no project manifest exists.
Linked Issues check ✅ Passed The changes directly address issue #12240 by preventing auto-install when dependency status is unavailable due to missing manifest.
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing the dependency-status auto-install behavior and adding corresponding test coverage.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration.


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

fix(exec): avoid deps auto-install when dependency status is unknown
🐞 Bug fix 🧪 Tests ⚙️ Configuration changes 🕐 10-20 Minutes

Grey Divider

Walkthroughs

Description
• Treat undefined deps-status as “skip check” to prevent unintended auto-install.
• Only trigger install/prompt/error paths when deps status is explicitly false.
• Add regression test for no-manifest deps-status result and ship patch changeset.
Diagram
graph TD
  A["pnpm exec" caller] --> B["runDepsStatusCheck"] --> C["checkDepsStatus"] --> D{"upToDate === false?"}
  D -- "No (true/undefined)" --> E["Return (no-op)"]
  D -- "Yes" --> F["createInstallArgs"] --> G["runPnpmCli install"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Make deps-status return an explicit enum
  • ➕ Eliminates tri-state ambiguity (true/false/undefined) at call sites
  • ➕ Forces callers to handle “skipped/unknown” explicitly via typing
  • ➖ Broader API change across packages; higher coordination cost
  • ➖ May require semver considerations and more downstream updates
2. Throw a dedicated “no manifest / skipped” error from checkDepsStatus
  • ➕ Control-flow becomes explicit and harder to mishandle
  • ➕ Can attach structured metadata (reason, missing manifest path)
  • ➖ Exceptions for non-exceptional flow can be noisy
  • ➖ Requires try/catch plumbing in callers and tests

Recommendation: The PR’s approach (treating anything other than explicit false as a no-op) is the best minimal-risk fix for the reported bug and matches the existing “skipped check” semantics. Consider an explicit enum return in a follow-up if more call sites emerge, but it’s likely overkill for this targeted regression.

Grey Divider

File Changes

Bug fix (1)
runDepsStatusCheck.ts Gate auto-install on explicit out-of-date deps status +1/-1

Gate auto-install on explicit out-of-date deps status

• Changes the early-return condition so the install path runs only when upToDate is explicitly false. This prevents falling through to auto-install when checkDepsStatus returns upToDate: undefined (e.g., no package manifest).

exec/commands/src/runDepsStatusCheck.ts


Tests (1)
runDepsStatusCheck.test.ts Add regression test for undefined upToDate (no manifest) case +44/-0

Add regression test for undefined upToDate (no manifest) case

• Adds a Jest test that mocks checkDepsStatus to return upToDate: undefined and asserts runPnpmCli is not invoked. Uses ESM module mocking to isolate runDepsStatusCheck behavior.

exec/commands/test/runDepsStatusCheck.test.ts


Other (1)
deps-status-no-manifest.md Add changeset for skipping auto-install when deps status is unavailable +6/-0

Add changeset for skipping auto-install when deps status is unavailable

• Introduces a patch changeset for @pnpm/exec.commands and pnpm documenting the behavioral fix. Ensures the release notes capture that auto-install is avoided when dependency status cannot be computed without a manifest.

.changeset/deps-status-no-manifest.md


Grey Divider

Qodo Logo

@scarab-systems scarab-systems force-pushed the fix/deps-status-no-manifest branch from 0b420b0 to 0238aaa Compare June 9, 2026 23:50
@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Jun 9, 2026

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit 0238aaa

@scarab-systems scarab-systems changed the title fix(exec): skip deps auto-install when status is unknown fix(exec): skip deps auto-install without manifest Jun 9, 2026
@scarab-systems scarab-systems force-pushed the fix/deps-status-no-manifest branch from 0238aaa to cb68ac1 Compare June 9, 2026 23:58
@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Jun 9, 2026

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit cb68ac1

@zkochan zkochan force-pushed the fix/deps-status-no-manifest branch from cb68ac1 to 3757dde Compare June 10, 2026 06:28
@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Jun 10, 2026

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit 3757dde

@zkochan zkochan merged commit 2c0b91d into pnpm:main Jun 10, 2026
10 checks passed
@welcome

welcome Bot commented Jun 10, 2026

Copy link
Copy Markdown

Congrats on merging your first pull request! 🎉🎉🎉

@scarab-systems scarab-systems deleted the fix/deps-status-no-manifest branch June 10, 2026 12:44
KSXGitHub pushed a commit that referenced this pull request Jun 10, 2026
Integrate the 9 commits main gained (#12271, #12294, #12301, #12303,
#12305, #12312, #12315, #12316, and the release/version bumps).

Conflict resolution: all four conflicts (record_lockfile_verified,
build_modules, hoisted_dep_graph, install) were between this branch's
lint edits and main's feature changes — took main's authoritative
versions; lint compliance is re-derived by re-running clippy in the
follow-up commit.
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.

pnpm self-upgrade fails with ERR_PNPM_NO_PKG_MANIFEST when run outside a project directory

2 participants