Bare make lists targets. make install-cli installs the activity tool via uv. Named activity-core backends live in ~/.config/activity/services.json with list/add/use/default/which; -s/--service selects one call without changing the default; --activity-url is a one-shot override.
193 lines
5.3 KiB
Python
193 lines
5.3 KiB
Python
"""Tests for activity review CLI (ACTIVITY-WP-0028)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
from datetime import datetime, timezone
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from activity_core.review_cli.checkpoint import ack, load_checkpoint, save_checkpoint
|
|
from activity_core.review_cli.defs import load_local_automations
|
|
from activity_core.review_cli.main import main
|
|
from activity_core.review_cli.merge import classify_row
|
|
from activity_core.review_cli.repo import resolve_repo, _slug_from_remote_url
|
|
from activity_core.review_cli.timewin import parse_since
|
|
|
|
|
|
def test_slug_from_remote() -> None:
|
|
assert (
|
|
_slug_from_remote_url("forgejo-remote:coulomb/freedom-intelligence.git")
|
|
== "freedom-intelligence"
|
|
)
|
|
assert (
|
|
_slug_from_remote_url("https://forgejo.example/coulomb/binky-control.git")
|
|
== "binky-control"
|
|
)
|
|
|
|
|
|
def test_resolve_repo_explicit(tmp_path: Path) -> None:
|
|
r = resolve_repo(cwd=tmp_path, explicit="freedom-intelligence")
|
|
assert r["slug"] == "freedom-intelligence"
|
|
assert r["source"] == "flag"
|
|
|
|
|
|
def test_parse_since_today() -> None:
|
|
now = datetime(2026, 8, 6, 15, 0, tzinfo=timezone.utc)
|
|
s = parse_since("today", now=now, tz_name="UTC")
|
|
assert s is not None
|
|
assert s.day == 6
|
|
assert s.hour == 0
|
|
|
|
|
|
def test_parse_since_checkpoint() -> None:
|
|
cp = {"reviewed_at": "2026-08-05T14:00:00+00:00"}
|
|
s = parse_since("checkpoint", checkpoint=cp)
|
|
assert s is not None
|
|
assert s.day == 5
|
|
|
|
|
|
def test_classify_trust_matrix() -> None:
|
|
assert classify_row(git_present=True, hub_present=True) == "ok"
|
|
assert classify_row(git_present=True, hub_present=False) == "partial"
|
|
assert classify_row(git_present=False, hub_present=True) == "lag"
|
|
assert classify_row(git_present=False, hub_present=False) == "missing"
|
|
assert classify_row(git_present=None, hub_present=None, ops_failed=True) == "failed"
|
|
|
|
|
|
def test_checkpoint_ack_roundtrip(tmp_path: Path) -> None:
|
|
save_checkpoint("freedom-intelligence", {"reviewed_paths": []}, tmp_path)
|
|
ack(
|
|
"freedom-intelligence",
|
|
paths=["briefs/2026/08/2026-08-06.md"],
|
|
state_dir=tmp_path,
|
|
)
|
|
cp = load_checkpoint("freedom-intelligence", tmp_path)
|
|
assert "briefs/2026/08/2026-08-06.md" in cp["reviewed_paths"]
|
|
assert cp["reviewed_at"]
|
|
|
|
|
|
def test_load_local_fi_definition(tmp_path: Path) -> None:
|
|
defs = tmp_path / "activity-definitions"
|
|
defs.mkdir()
|
|
(defs / "fi-daily-research-brief.md").write_text(
|
|
"""---
|
|
id: fi-daily-research-brief
|
|
name: Freedom Intelligence Daily Research Brief
|
|
enabled: true
|
|
trigger:
|
|
type: cron
|
|
cron_expression: "30 7 * * 1-5"
|
|
timezone: Europe/Berlin
|
|
---
|
|
|
|
```rule
|
|
id: emit
|
|
action:
|
|
target_repo: freedom-intelligence
|
|
labels: ["freedom-intelligence"]
|
|
```
|
|
""",
|
|
encoding="utf-8",
|
|
)
|
|
items, warnings = load_local_automations(tmp_path, "freedom-intelligence")
|
|
assert not warnings
|
|
assert len(items) == 1
|
|
assert items[0]["id"] == "fi-daily-research-brief"
|
|
assert "briefs/**/*.md" in items[0]["review"]["deliverable_globs"]
|
|
|
|
|
|
def test_cli_list_json(tmp_path: Path, capsys: pytest.CaptureFixture[str]) -> None:
|
|
defs = tmp_path / "activity-definitions"
|
|
defs.mkdir()
|
|
(defs / "fi-daily-research-brief.md").write_text(
|
|
"""---
|
|
id: fi-daily-research-brief
|
|
name: Freedom Intelligence Daily Research Brief
|
|
enabled: true
|
|
trigger:
|
|
type: cron
|
|
cron_expression: "30 7 * * 1-5"
|
|
timezone: Europe/Berlin
|
|
---
|
|
|
|
```rule
|
|
id: emit
|
|
action:
|
|
target_repo: freedom-intelligence
|
|
```
|
|
""",
|
|
encoding="utf-8",
|
|
)
|
|
code = main(
|
|
[
|
|
"list",
|
|
"--cwd",
|
|
str(tmp_path),
|
|
"--repo",
|
|
"freedom-intelligence",
|
|
"--format",
|
|
"json",
|
|
]
|
|
)
|
|
assert code in (0, 2)
|
|
out = capsys.readouterr().out
|
|
data = json.loads(out)
|
|
assert data["repo"] == "freedom-intelligence"
|
|
assert data["count"] == 1
|
|
|
|
|
|
def test_cli_status_offline(tmp_path: Path, capsys: pytest.CaptureFixture[str]) -> None:
|
|
defs = tmp_path / "activity-definitions"
|
|
defs.mkdir()
|
|
briefs = tmp_path / "briefs" / "2026" / "08"
|
|
briefs.mkdir(parents=True)
|
|
(briefs / "2026-08-06.md").write_text("# brief\n", encoding="utf-8")
|
|
(defs / "fi-daily-research-brief.md").write_text(
|
|
"""---
|
|
id: fi-daily-research-brief
|
|
name: Freedom Intelligence Daily Research Brief
|
|
enabled: true
|
|
trigger:
|
|
type: cron
|
|
cron_expression: "30 7 * * 1-5"
|
|
timezone: Europe/Berlin
|
|
---
|
|
|
|
```rule
|
|
id: emit
|
|
action:
|
|
target_repo: freedom-intelligence
|
|
```
|
|
""",
|
|
encoding="utf-8",
|
|
)
|
|
# init git for deliverables
|
|
import subprocess
|
|
|
|
subprocess.run(["git", "init"], cwd=tmp_path, check=True, capture_output=True)
|
|
subprocess.run(["git", "add", "."], cwd=tmp_path, check=True, capture_output=True)
|
|
subprocess.run(
|
|
["git", "-c", "user.email=t@t", "-c", "user.name=t", "commit", "-m", "init"],
|
|
cwd=tmp_path,
|
|
check=True,
|
|
capture_output=True,
|
|
)
|
|
code = main(
|
|
[
|
|
"status",
|
|
"--cwd",
|
|
str(tmp_path),
|
|
"--repo",
|
|
"freedom-intelligence",
|
|
"--state-dir",
|
|
str(tmp_path / "state"),
|
|
"--since",
|
|
"week",
|
|
]
|
|
)
|
|
assert code in (0, 2)
|
|
out = capsys.readouterr().out
|
|
assert "freedom-intelligence" in out
|
|
assert "Automations:" in out
|