Skip to content

feat(sync[dry-run]): auto-show all matched repos when filtering explicitly#540

Draft
tony wants to merge 3 commits intosync-edgecasesfrom
sync-implicit-show-unchanged
Draft

feat(sync[dry-run]): auto-show all matched repos when filtering explicitly#540
tony wants to merge 3 commits intosync-edgecasesfrom
sync-implicit-show-unchanged

Conversation

@tony
Copy link
Copy Markdown
Member

@tony tony commented Apr 5, 2026

Summary

  • Fix a confusing DX gap: vcspull sync tanstack-* --dry-run matched 5 repos but only displayed the 1 needing action — the 4 unchanged repos were hidden unless --show-unchanged was passed, even though the user had already scoped the command to specific repos.
  • Add has_explicit_patterns to PlanRenderOptions: computed as not sync_all and bool(repo_patterns) in sync(), propagated to both the human and JSON/NDJSON render paths.
  • Improve tip message: suppress the --show-unchanged hint when unchanged rows are already visible due to explicit filtering; show a shorter "run without --dry-run to apply" tip instead.
  • Add xfail field and request.applymarker support to DryRunPlanFixture / test_sync_dry_run_plan_human for per-fixture conditional xfail without stopping test execution.

Design decisions

OR semantics at the call site: show_unchanged or has_explicit_patterns is passed to _filter_entries_for_display() rather than changing the function's own signature — the helper stays minimal and doesn't need to know about the concept of "explicit patterns".

--all unaffected: has_explicit_patterns is only True when repo_patterns is non-empty and sync_all is False. Bulk --all dry-runs retain the hide-unchanged default.

request.applymarker over pytest.xfail(): imperative pytest.xfail() short-circuits execution and can never become XPASS. request.applymarker applies the marker but still runs the test body, so the fixture transitions XFAIL → XPASS → PASS cleanly across the three-commit workflow.

Before / After

Before:

Progress: 5/5 +:0 ~:1 ✓:4 ⚠:0 ✗:0
Plan: 0 to clone (+), 1 to update (~), 4 unchanged (✓), 0 blocked (⚠), 0 errors (✗)

~/study/typescript/
  ~ tanstack-router  ~/study/typescript/tanstack-router  remote state unknown; use --fetch
Tip: run without --dry-run to apply. Use --show-unchanged to include ✓ rows.

After:

Progress: 5/5 +:0 ~:1 ✓:4 ⚠:0 ✗:0
Plan: 0 to clone (+), 1 to update (~), 4 unchanged (✓), 0 blocked (⚠), 0 errors (✗)

~/study/typescript/
  ~ tanstack-router  ~/study/typescript/tanstack-router  remote state unknown; use --fetch
  ✓ tanstack-devtools  ~/study/typescript/tanstack-devtools
  ✓ tanstack-store     ~/study/typescript/tanstack-store
  ✓ tanstack-table     ~/study/typescript/tanstack-table
  ✓ tanstack-virtual   ~/study/typescript/tanstack-virtual
Tip: run without --dry-run to apply.

Test plan

  • unchanged-implicit-filter--dry-run with explicit name pattern and pre-synced repo shows row without --show-unchanged
  • unchanged-show — existing --show-unchanged flag still works
  • uv run ruff check . --fix --show-fixes — no lint errors
  • uv run ruff format . — no formatting changes
  • uv run mypy — no type errors
  • uv run py.test --reruns 0 — full suite passes

tony added 3 commits April 5, 2026 09:34
…atterns

why: when filtering to specific repos, the user expects all matched repos to
appear — needing --show-unchanged to see the 4 unchanged out of 5 matched is
unintuitive. Regression test documents the desired behavior before the fix.
what:
- add xfail field to DryRunPlanFixture (defaults False, zero churn on existing fixtures)
- add pytest.xfail() guard in test_sync_dry_run_plan_human when xfail=True
- add unchanged-implicit-filter fixture: --dry-run with explicit name pattern,
  pre-synced repo, expects ✓ row without --show-unchanged flag
…itly

why: vcspull sync tanstack-* shows 5 matched repos but only the 1 needing
action — the user has already scoped the command to specific repos and
shouldn't need --show-unchanged to confirm the filter worked.
what:
- add has_explicit_patterns field to PlanRenderOptions
- set it true in sync() when repo_patterns passed without --all
- fold it into the show_unchanged OR at both _filter_entries_for_display
  call sites (human and JSON/NDJSON paths)
- add PLAN_TIP_MESSAGE_FILTERED: suppress --show-unchanged hint when
  unchanged rows are already visible due to explicit filtering
- wire request.applymarker into test_sync_dry_run_plan_human to support
  per-fixture xfail without stopping test execution
…ed fixed

why: unchanged-implicit-filter now passes unconditionally.
what:
- remove xfail=True from unchanged-implicit-filter fixture
@codecov
Copy link
Copy Markdown

codecov bot commented Apr 5, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 84.29%. Comparing base (617c05e) to head (d22bd28).

Additional details and impacted files
@@               Coverage Diff               @@
##           sync-edgecases     #540   +/-   ##
===============================================
  Coverage           84.29%   84.29%           
===============================================
  Files                  29       29           
  Lines                3813     3815    +2     
  Branches              759      759           
===============================================
+ Hits                 3214     3216    +2     
  Misses                377      377           
  Partials              222      222           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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