Skip to content

test(cli): port pnpm monorepo filter tests + wire --fail-if-no-match#457

Merged
jdx merged 6 commits intomainfrom
claude/ecstatic-bardeen-65b964
May 1, 2026
Merged

test(cli): port pnpm monorepo filter tests + wire --fail-if-no-match#457
jdx merged 6 commits intomainfrom
claude/ecstatic-bardeen-65b964

Conversation

@jdx
Copy link
Copy Markdown
Contributor

@jdx jdx commented May 1, 2026

Summary

Phase 3 batch 1 of the pnpm test import — the first 5 filter-semantics
tests from pnpm/test/monorepo/index.ts translated into a new
test/pnpm_monorepo_index.bats, plus the small aube-side fixes the ports surfaced.

Tests ported

pnpm source aube target
monorepo/index.ts:31 (3 sub-cases — default, --fail-if-no-match, --parseable) "no projects matched the filters" warn-and-exit-0
monorepo/index.ts:512 --filter=...<pkg> topological run order with intervening unrelated workspace pkgs
monorepo/index.ts:1662 (sub-case 2) --filter=./packages/** directory glob

Aube-side fixes

  • Wire --fail-if-no-match — the global flag was parsed at crates/aube/src/main.rs:217 but never read. Added fail_if_no_match: bool to EffectiveFilter and softened aube list's no-match path from a hard error to "No projects matched the filters in <root>" + exit 0 (suppressed under --parseable; hard-errors only with --fail-if-no-match).
  • --depth=-1 accepted as an alias for --depth=0 to match pnpm's "no transitives" spelling.
  • ./packages/** parses as a synonym for ./packages — aube's path selector is "at or under" by design, so the pnpm v9 exact-vs-recursive split (gated on legacyDirFiltering) doesn't apply. Explicitly skipped per PNPM_TEST_IMPORT.md — aube's default is the more useful one.
  • Filtered list --parseable now leads each importer block with the package directory path so consumers can find each filtered project on its own line. Non-filtered --parseable keeps the legacy 3-field tab-separated dep records (asserted by test/list.bats:171).

Documented divergences (not fixed here)

  • monorepo/index.ts:56 ("no projects found" on prepareEmpty() + list -r) — needs broader project_root() tolerance (workspace-yaml-only or no-manifest root). On the same fault line as list/run/install/query/why — touch them together when this lands.
  • monorepo/index.ts:1662 sub-case 1 (./packages matches nothing) — pnpm v9 default is exact-directory match gated on legacyDirFiltering=false; aube doesn't implement legacyDirFiltering and treats ./packages as "at or under".

Test plan

  • cargo build, cargo fmt, cargo clippy --all-targets -- -D warnings
  • cargo test --workspace --lib — all green
  • mise run test:bats test/pnpm_monorepo_index.bats — 5/5 pass
  • mise run test:bats test/filter.bats test/list.bats — 43/43 pass (regression check)

🤖 Generated with Claude Code


Note

Medium Risk
Touches workspace selector parsing and aube list output/exit-code behavior under filtering, which can affect CI scripts and machine parsers relying on prior semantics.

Overview
Aligns workspace filtering behavior with pnpm for parity and CI use by threading the global --fail-if-no-match flag through EffectiveFilter and updating aube list --filter to warn+exit 0 on no matches by default (optionally hard-failing with --fail-if-no-match) while suppressing the warning for machine formats.

Updates aube list’s --depth handling by introducing a Depth type so --depth=-1 can list project headers only (no deps) across default/JSON/parseable outputs, and adjusts filtered --parseable output to print each selected project directory before any dep records.

Extends selector parsing so pnpm’s ./packages/** directory form is accepted as a path selector synonym (without reinterpreting name globs like @scope/**), and adds new bats coverage via test/pnpm_monorepo_index.bats plus updates to test/PNPM_TEST_IMPORT.md to track the ported pnpm monorepo filter tests.

Reviewed by Cursor Bugbot for commit 10c6596. Bugbot is set up for automated code reviews on this repo. Configure here.

Phase 3 batch 1 of the pnpm test import (5 tests from
pnpm/test/monorepo/index.ts → test/pnpm_monorepo_index.bats):
no-projects-matched warn-and-exit-0 (line 31, 3 sub-cases),
topological run order under --filter=...<pkg> with intervening
unrelated workspace packages (line 512), and ./packages/** directory
glob (line 1662 sub-case 2).

Aube-side fixes that landed alongside the ports:
- wire the parsed-but-unread --fail-if-no-match global into
  EffectiveFilter; soften aube list's no-match path from hard-error
  to "No projects matched the filters in <root>" + exit 0
  (suppressed under --parseable, hard-errors with --fail-if-no-match)
- accept --depth=-1 as an alias for --depth=0 (pnpm's spelling for
  "no transitives")
- parse ./packages/** as a synonym for ./packages — aube's path
  selector is "at or under" by design, no separate legacyDirFiltering
  gate
- filtered list --parseable now leads each importer block with the
  package directory path; non-filtered --parseable keeps the legacy
  3-field tab-separated dep records

legacyDirFiltering added to the explicit-skip section in
PNPM_TEST_IMPORT.md — aube's path-selector default is the more
useful one.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 1, 2026

Greptile Summary

This PR ports 5 pnpm monorepo filter tests into test/pnpm_monorepo_index.bats and lands the aube-side fixes that the ports surface: wiring --fail-if-no-match through EffectiveFilter, introducing a Depth type so --depth=-1 lists project headers only, accepting ./packages/** as a path-selector synonym, and adding a directory-path prefix to filtered --parseable output. The refactor moves workspace discovery out of run_filtered so the no-match short-circuit fires before any lockfile I/O, while preserving the hard error for an empty workspace.

Confidence Score: 4/5

Safe to merge with minor caveats around the filtered --parseable format change and the /**-only path edge case.

No P0/P1 issues found. Two P2 observations: run_filtered redundantly re-derives format that run already computed, and the /**-only absolute path collapses to an empty PathBuf via the new strip_suffix — a behaviour change from pre-PR though an extremely unlikely input. All other changes are well-tested and the previous review concerns have been correctly addressed.

crates/aube/src/commands/list.rs and crates/aube-workspace/src/selector.rs

Important Files Changed

Filename Overview
crates/aube/src/commands/list.rs Adds early no-match handling with --fail-if-no-match wiring, introduces Depth type for -1 support, and changes filtered --parseable output to prefix each importer block with its directory path — a format change for filtered callers.
crates/aube-workspace/src/selector.rs Adds fail_if_no_match field to EffectiveFilter and strips the /** suffix from path-style selectors so ./packages/** collapses to the same ./packages path; includes unit tests for the new parse shapes.
crates/aube/src/main.rs Threads the parsed-but-previously-unread cli.fail_if_no_match into EffectiveFilter — a one-line fix that completes the flag's wiring.
test/pnpm_monorepo_index.bats New bats test file porting 5 pnpm monorepo filter tests; covers no-match warn/fail/silent cases, topological run order, and ./packages/** directory glob with --depth=-1.
aube.usage.kdl Updates --depth long-help text across list, la, and ll commands to document the new --depth=-1 behavior.
docs/cli/list.md Documentation update to --depth description to include --depth=-1 semantics.
docs/cli/commands.json Generated CLI reference updated to match the new --depth help text across all three list-family commands.
test/PNPM_TEST_IMPORT.md Tracking document updated with ported tests, aube-side fixes, and documented divergences for this batch.

Fix All in Claude Code

Reviews (4): Last reviewed commit: "[autofix.ci] apply automated fixes" | Re-trigger Greptile

Comment thread crates/aube/src/commands/list.rs Outdated
Comment thread crates/aube/src/commands/list.rs Outdated
Comment thread crates/aube-workspace/src/selector.rs Outdated
Comment thread crates/aube/src/commands/list.rs
jdx and others added 2 commits May 1, 2026 10:46
…rkspace error

Address greptile review on #457:
- Pre-compute workspace_pkgs + selected once in `run()` and thread the
  result into `run_filtered`, eliminating the duplicate
  find_workspace_packages + select_workspace_packages walk on the
  match path.
- Restore the "aube list: --filter requires a workspace root..." hard
  error when filter is set but no workspace config exists at or above
  the cwd. The previous patch silently downgraded that case to the
  soft "No projects matched" path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…o-match error

Address cursor bugbot review on #457:
- The `raw.ends_with("/**")` arm in the path-selector branch was too
  broad — it silently promoted any `<name>/**` (e.g. `@scope/**`) from
  a NameGlob to a Path selector, breaking scoped-name globs. Drop that
  arm: `./packages/**` already enters via `starts_with("./")`, and the
  `strip_suffix("/**")` step still collapses it onto the existing
  "at or under" path semantics. Add a regression test asserting
  `@scope/**` parses as `NameGlob`.
- The `--fail-if-no-match` error formatted only `filter.filters`, so
  passing only `--filter-prod` selectors produced `filter []`. Fold
  both lists into the message — and render them as a flat
  `["foo", "bar"]` list rather than dumping the EffectiveFilter
  struct.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Comment thread crates/aube/src/commands/list.rs
Comment thread crates/aube/src/commands/list.rs
…ck filtered parseable shape

Address review on #457:
- Cursor (medium): the no-match warning was suppressed only when the
  `--parseable` shortcut was set, but `--format parseable` /
  `--format json` set `args.format` instead, so those routes still
  printed the human "No projects matched..." message and corrupted
  machine-parseable stdout. Hoist the format resolution above the
  no-match check and gate the warning on `format == Default`. Cleans
  the same gap for `--json` / `--format json` (the previous
  suppression only checked `args.parseable`).
- Greptile (P1): filtered `aube list --parseable` now emits a leading
  package-directory line per importer (matches the help-text contract
  in `list.rs` and pnpm's shape). Lock the format with a bats
  regression so a future format change has to update the test.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 5888dcc. Configure here.

Comment thread crates/aube/src/commands/list.rs
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 1, 2026

Benchmark changes

Public ratios: warm installs vs Bun 5x -> 14x; warm installs vs pnpm 6x -> 17x.

Benchmark aube bun pnpm
Fresh install (warm cache) 288ms -> 181ms (-37%) 1504ms -> 2578ms (+71%) 1849ms -> 3114ms (+68%)
CI install (warm cache, GVS disabled) 416ms -> 331ms (-20%) 966ms -> 2587ms (+168%) 2237ms -> 2458ms (+10%)
CI install (cold cache, GVS disabled) 5053ms -> 4003ms (-21%) 3918ms -> 4372ms (+12%) 5491ms -> 5533ms (+1%)

d0ebf03 vs 6769405 | aube/bun/pnpm | 3 scenarios | 3 runs | 500mbit/50ms | generated by Codex.

jdx and others added 2 commits May 1, 2026 11:13
Address cursor bugbot review on #457: mapping `--depth=-1` to `0`
diverged from pnpm. In pnpm `--depth=-1` means "list project headers
only, no deps", while `--depth=0` means "direct deps only". Aube's
prior collapse silently leaked direct deps in `--parseable` output for
projects that actually had deps. The previous bats test passed only
because the fixture had zero-dep projects.

Replace `pub depth: usize` with a `Depth` struct that carries both
`include_direct: bool` and the transitive `max: usize`. Wire it
through:
- `--depth=-1`  → `Depth { include_direct: false, max: 0 }`
- `--depth=N`   → `Depth { include_direct: true,  max: N }`
- `--depth=Inf` → `Depth { include_direct: true,  max: usize::MAX }`

`render_default_for_importer` / `render_parseable_for_importer` /
`json_importer_value` early-return after the project header when
`include_direct` is false. Strengthen the directory-filtering bats
test with a real dep on `is-odd` so it would now fail under the old
collapse, plus a sanity check that `--depth=0` still surfaces direct
deps.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@jdx jdx merged commit 490dfa9 into main May 1, 2026
16 checks passed
@jdx jdx deleted the claude/ecstatic-bardeen-65b964 branch May 1, 2026 17:55
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.

1 participant