feat(cli): add clean analysis export with markdown/json output
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import json
|
||||
from pathlib import Path
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import AsyncMock, MagicMock
|
||||
@@ -444,3 +445,105 @@ def test_interactive_history_without_store_shows_hint(monkeypatch) -> None: # t
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert "Session memory is disabled" in result.stdout
|
||||
|
||||
|
||||
def test_run_analyze_writes_output_file(monkeypatch, tmp_path: Path) -> None: # type: ignore[no-untyped-def]
|
||||
_mock_session(monkeypatch)
|
||||
|
||||
async def fake_collect_from_plan(_session, _plan) -> CollectionReport: # type: ignore[no-untyped-def]
|
||||
return CollectionReport(
|
||||
host="ssh.archflux.net",
|
||||
items=[
|
||||
CollectedItem(
|
||||
name="kernel",
|
||||
result=SSHCommandResult(
|
||||
command="uname -a",
|
||||
exit_code=0,
|
||||
stdout="Linux test",
|
||||
stderr="",
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
monkeypatch.setattr("tai.cli.collect_from_plan", fake_collect_from_plan)
|
||||
monkeypatch.setattr(
|
||||
"tai.cli.AIClient.complete",
|
||||
lambda *_args, **_kwargs: SimpleNamespace(content="Root Cause\n\nEvidence\n\nRecommended Actions"),
|
||||
)
|
||||
|
||||
output_path = tmp_path / "analysis.md"
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(
|
||||
app,
|
||||
[
|
||||
"run", "apache failed",
|
||||
"--host",
|
||||
"ssh.archflux.net",
|
||||
"--port",
|
||||
"5566",
|
||||
"--no-probe",
|
||||
"--analyze",
|
||||
"--output-file",
|
||||
str(output_path),
|
||||
],
|
||||
)
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert "Wrote analysis output" in result.stdout
|
||||
assert output_path.exists()
|
||||
assert "Root Cause" in output_path.read_text(encoding="utf-8")
|
||||
|
||||
|
||||
def test_run_analyze_writes_json_output_and_strips_ansi(monkeypatch, tmp_path: Path) -> None: # type: ignore[no-untyped-def]
|
||||
_mock_session(monkeypatch)
|
||||
|
||||
async def fake_collect_from_plan(_session, _plan) -> CollectionReport: # type: ignore[no-untyped-def]
|
||||
return CollectionReport(
|
||||
host="ssh.archflux.net",
|
||||
items=[
|
||||
CollectedItem(
|
||||
name="kernel",
|
||||
result=SSHCommandResult(
|
||||
command="uname -a",
|
||||
exit_code=0,
|
||||
stdout="Linux test",
|
||||
stderr="",
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
monkeypatch.setattr("tai.cli.collect_from_plan", fake_collect_from_plan)
|
||||
monkeypatch.setattr(
|
||||
"tai.cli.AIClient.complete",
|
||||
lambda *_args, **_kwargs: SimpleNamespace(
|
||||
content="\x1b[31mRoot Cause\x1b[0m\n\nEvidence\n\nRecommended Actions"
|
||||
),
|
||||
)
|
||||
|
||||
output_path = tmp_path / "analysis.json"
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(
|
||||
app,
|
||||
[
|
||||
"run", "apache failed",
|
||||
"--host",
|
||||
"ssh.archflux.net",
|
||||
"--port",
|
||||
"5566",
|
||||
"--no-probe",
|
||||
"--analyze",
|
||||
"--output-file",
|
||||
str(output_path),
|
||||
"--output-format",
|
||||
"json",
|
||||
],
|
||||
)
|
||||
|
||||
assert result.exit_code == 0
|
||||
payload = json.loads(output_path.read_text(encoding="utf-8"))
|
||||
assert payload["issue"] == "apache failed"
|
||||
assert payload["host"] == "ssh.archflux.net"
|
||||
assert "Root Cause" in payload["analysis"]
|
||||
assert "\u001b" not in payload["analysis"]
|
||||
|
||||
Reference in New Issue
Block a user