Skip to content

Commit ba3311b

Browse files
committed
cli/sync(fix[sync]) Emit summary when all sync patterns are unmatched
why: When every pattern is unmatched (total_repos == 0, unmatched_count > 0), the early return skipped summary emission. JSON/NDJSON consumers got no machine-readable output; humans saw no summary line. what: - Emit summary event and human-readable summary before early return - Add test for all-patterns-unmatched scenario
1 parent c7308fb commit ba3311b

2 files changed

Lines changed: 66 additions & 1 deletion

File tree

src/vcspull/cli/sync.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -697,7 +697,26 @@ def sync(
697697
return
698698

699699
if total_repos == 0:
700-
formatter.emit_text(colors.warning("No repositories matched the criteria."))
700+
if unmatched_count > 0:
701+
summary = {
702+
"total": unmatched_count,
703+
"synced": 0,
704+
"previewed": 0,
705+
"failed": unmatched_count,
706+
}
707+
formatter.emit({"reason": "summary", **summary})
708+
if formatter.mode == OutputMode.HUMAN:
709+
formatter.emit_text(
710+
f"\n{colors.info('Summary:')} "
711+
f"{summary['total']} repos, "
712+
f"{colors.success(str(summary['synced']))} synced, "
713+
f"{colors.warning(str(summary['previewed']))} previewed, "
714+
f"{colors.error(str(summary['failed']))} failed",
715+
)
716+
else:
717+
formatter.emit_text(
718+
colors.warning("No repositories matched the criteria."),
719+
)
701720
formatter.finalize()
702721
return
703722

tests/test_cli.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2052,6 +2052,52 @@ def test_sync_unmatched_pattern_counts_in_summary(
20522052
assert "1 synced" in output
20532053

20542054

2055+
def test_sync_all_patterns_unmatched_emits_summary(
2056+
tmp_path: pathlib.Path,
2057+
capsys: pytest.CaptureFixture[str],
2058+
caplog: pytest.LogCaptureFixture,
2059+
monkeypatch: pytest.MonkeyPatch,
2060+
user_path: pathlib.Path,
2061+
config_path: pathlib.Path,
2062+
git_repo: GitSync,
2063+
) -> None:
2064+
"""Summary should be emitted even when ALL patterns are unmatched.
2065+
2066+
When every pattern fails to match a repo (``total_repos == 0``), the early
2067+
return must still emit a summary event with the correct failure count so
2068+
both human-readable and machine-readable consumers see a summary.
2069+
"""
2070+
config = {
2071+
"~/github_projects/": {
2072+
"my_git_project": {
2073+
"url": f"git+file://{git_repo.path}",
2074+
"remotes": {"test_remote": f"git+file://{git_repo.path}"},
2075+
},
2076+
},
2077+
}
2078+
yaml_config = config_path / ".vcspull.yaml"
2079+
yaml_config.write_text(
2080+
yaml.dump(config, default_flow_style=False), encoding="utf-8"
2081+
)
2082+
2083+
monkeypatch.chdir(tmp_path)
2084+
caplog.set_level(logging.INFO)
2085+
2086+
with contextlib.suppress(SystemExit):
2087+
cli(["sync", "not_in_config1", "not_in_config2"])
2088+
2089+
captured = capsys.readouterr()
2090+
output = "".join([*caplog.messages, captured.out, captured.err])
2091+
2092+
# Both unmatched patterns should appear in the output
2093+
assert "not_in_config1" in output
2094+
assert "not_in_config2" in output
2095+
2096+
# Summary should reflect both unmatched patterns as failures
2097+
assert "2 failed" in output
2098+
assert "0 synced" in output
2099+
2100+
20552101
def test_sync_unmatched_pattern_no_duplicate_log(
20562102
tmp_path: pathlib.Path,
20572103
capsys: pytest.CaptureFixture[str],

0 commit comments

Comments
 (0)