Skip to content

pacquet: promote --filter/--filter-prod to recursive mode (CLI-wide, prerequisite for driving release.yml) #12723

Description

@KSXGitHub

What this issue is (and isn't)

This tracks one shared CLI-argument behavior that pacquet is missing: passing --filter (or --filter-prod) on its own must put the command into recursive mode, even without -r/--recursive. It is not about publish logic, and not about applying the filter once recursive (that was #12711, already done). Like #12711, this belongs outside the publish PR (#12691) because it governs every recursive-capable command, not just publish.

Why

pnpm's own deployment CI (.github/workflows/release.yml) drives publishing entirely through --filter, without -r:

pn --filter=@pnpm/exe publish --tag=next-11 --access=public --provenance
pn publish --filter=!pnpm --filter=!@pnpm/exe --access=public --provenance
pn publish --filter=pnpm --tag=next-11 --access=public --provenance

For pacquet to be a drop-in pn in this workflow, pn publish --filter=pnpm must behave as a recursive publish over the filtered set. Today it does not — it falls through to the single-package path and would try to publish the current directory.

Upstream behavior to match

pnpm promotes recursive in cli/parse-cli-args, for all commands, when a filter is present:

// pnpm11/cli/parse-cli-args/src/index.ts (around line 219)
if (options['recursive'] !== true && (options['filter'] || options['filter-prod'] || recursiveCommandUsed)) {
  options['recursive'] = true
  // ...
}

pnpm/src/main.ts then builds the filter set from config.filter/config.filterProd, and — when every selector is an exclusion (!pnpm, !@pnpm/exe) and the command is not run at the workspace root — additionally pushes !{.} so the root project is excluded too.

Current pacquet state

  • recursive is taken straight from the -r/--recursive flag and threaded through RunCtx.recursive; there is no promotion from --filter.
  • The only place --filter affects routing is the install fast-path bail in pacquet/crates/cli/src/cli_args/dispatch.rs (if self.recursive || !self.filter.is_empty() || !self.filter_prod.is_empty()), which merely disables a fast path — it does not enter the recursive command dispatch.
  • Consequence: run, exec, pack, and publish all require an explicit -r to go recursive, diverging from pnpm whenever only --filter is passed.

(Permalinks pinned at a70a996e88: dispatch routing in pacquet/crates/cli/src/cli_args/dispatch.rs, publish entry in pacquet/crates/cli/src/cli_args/publish.rs where if recursive || self.recursive selects the recursive path.)

Proposed change

Promote recursive to true when filter or filter_prod is non-empty, at the same single point where the raw -r flag is read (so it applies CLI-wide, matching parse-cli-args rather than being special-cased per command). Two sub-points to port faithfully:

  1. The all-exclusion augmentation (!{.}) from main.ts so --filter=!pnpm --filter=!@pnpm/exe also excludes the workspace root. Note: in this repo the root manifest is private: true, so recursive publish's existing eligibility check already drops it; the augmentation still matters for non-private-root workspaces and for non-publish commands.
  2. Confirm no already-ported run/exec/pack test asserts the current (non-promoting) behavior; update any that encode the divergence.

Acceptance

  • pn <recursive-capable-cmd> --filter=<sel> (no -r) enters recursive mode and operates on the filtered set.
  • pn publish --filter=pnpm and pn publish --filter=!pnpm --filter=!@pnpm/exe select the intended projects, matching release.yml.
  • Behavior parity verified for run/exec/pack/publish.

Not part of this issue

  • Building @pnpm/exe artifacts and the root release scripts (copy-artifacts, make-release-description) — TS/Node-specific release steps, tracked under the Rust Roadmap (#11633).
  • --batch publishing — intentionally unported; not used by release.yml.

Written by an agent (Claude Code, claude-opus-4-8).

Metadata

Metadata

Assignees

Labels

rustPull requests that update rust code

Type

Fields

No fields configured for Task.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions