🚧 Add export feature and refined exclusion info

This commit is contained in:
Jonas Bengtsson
2026-09-13 12:04:42 +02:00
parent 1d67330f27
commit 3bbfd6c161
10 changed files with 637 additions and 16 deletions
+82
View File
@@ -295,6 +295,88 @@ class TestExtraction:
assert before == after
class TestExportHistory:
"""export subcommand: collected history becomes analysis-ready rows."""
def _collect_two_cycles(self, git_repo: Path, config: dict, tmp_path: Path) -> None:
# Cycle 1: one addition with sidecar attribution
(git_repo / "config.xml").write_text("<c/>", encoding="utf-8")
(git_repo / "config.xml.metadata").write_text(
"last_modified_by=DOMAIN\\jsmith\n", encoding="utf-8"
)
_run(config, tmp_path)
# Cycle 2: one deletion (bare D line in the history)
(git_repo / "config.xml").unlink()
_run(config, tmp_path)
def test_export_csv_round_trip(
self, git_repo: Path, tracker_config: dict, tmp_path: Path
) -> None:
import csv
from git_auto_tracker.config import AppConfig
from git_auto_tracker.exporting.history import export_history
self._collect_two_cycles(git_repo, tracker_config, tmp_path)
app_config = AppConfig.from_dict(tracker_config, config_dir=tmp_path)
output = tmp_path / "history.csv"
count = export_history(app_config, output)
# 3 rows: A config.xml + A config.xml.metadata, then D config.xml
assert count == 3
with output.open(encoding="utf-8", newline="") as handle:
rows = list(csv.DictReader(handle))
assert rows[0]["letter"] == "D" # newest collection first
assert rows[0]["path"] == "config.xml"
assert rows[1]["letter"] == "A"
assert rows[1]["path"] == "config.xml"
assert rows[1]["author"] == "DOMAIN\\jsmith"
assert rows[1]["run_id"] # trailer parsed
def test_export_jsonl_and_since_filter(
self, git_repo: Path, tracker_config: dict, tmp_path: Path
) -> None:
import json
from git_auto_tracker.config import AppConfig
from git_auto_tracker.exporting.history import export_history
self._collect_two_cycles(git_repo, tracker_config, tmp_path)
app_config = AppConfig.from_dict(tracker_config, config_dir=tmp_path)
output = tmp_path / "history.jsonl"
# Future-dated --since excludes everything (2099, not 2999: Git's
# approxidate parser mishandles far-future years and returns all)
assert export_history(app_config, output, since="2099-01-01") == 0
assert output.read_text(encoding="utf-8") == ""
# No filter: both collections' rows present, newest first
assert export_history(app_config, output) == 3
lines = output.read_text(encoding="utf-8").splitlines()
parsed = [json.loads(line) for line in lines]
assert parsed[0]["letter"] == "D"
assert parsed[1]["letter"] == "A"
assert parsed[0]["collected_at"] >= parsed[-1]["collected_at"]
def test_cli_export_command(
self, git_repo: Path, tracker_config: dict, tmp_path: Path, capsys
) -> None:
from git_auto_tracker.cli import main
self._collect_two_cycles(git_repo, tracker_config, tmp_path)
import yaml
config_path = tmp_path / "cfg.yaml"
config_path.write_text(yaml.safe_dump(tracker_config), encoding="utf-8")
output = tmp_path / "out.csv"
exit_code = main(["--config", str(config_path), "export", "-o", str(output)])
assert exit_code == 0
assert output.is_file()
captured = capsys.readouterr().out
assert "3 file-change record(s)" in captured
class TestSafetyAborts:
def test_pre_existing_staged_changes_abort(
self, git_repo: Path, tracker_config: dict, tmp_path: Path