mirror of
https://github.com/kuhyx/utils.git
synced 2026-11-10 19:07:17 +01:00
Some checks failed
dependency freshness / dependencies on newest stable (push) Waiting to run
earned_time pre-commit / pre-commit (push) Waiting to run
earned_time tests / test (push) Waiting to run
file length / file-length (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
palette drift / palette (push) Waiting to run
repo-contract / repo contract (push) Waiting to run
shared gate tests / gate unit tests (push) Waiting to run
crdt-sync pre-commit / pre-commit (push) Has been cancelled
crdt-sync tests / test (push) Has been cancelled
freedays pre-commit / pre-commit (push) Has been cancelled
freedays tests / test (push) Has been cancelled
gatelock pre-commit / pre-commit (push) Has been cancelled
gatelock tests / test (push) Has been cancelled
music_theory tests / test (push) Has been cancelled
sickdays pre-commit / pre-commit (push) Has been cancelled
sickdays tests / test (push) Has been cancelled
ts_config tests / test (push) Has been cancelled
ts_core tests / test (push) Has been cancelled
web_ui tests / test (push) Has been cancelled
In CI the gate defers to the workflow and returns 0, so the real-checker test saw 0 instead of 1. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NBScELfMUiieK9ManFbS3Y
179 lines
6.3 KiB
Python
179 lines
6.3 KiB
Python
"""The agent-ready gate: build, then run the shared AgentReady checker."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import subprocess
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from repo_contract import agent_ready_gate as gate
|
|
|
|
from .conftest import write
|
|
from .test_web import config, vite_repo
|
|
|
|
|
|
@pytest.fixture
|
|
def fake_checker(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> Path:
|
|
"""A stand-in check.sh that logs its argv and exits with $FAKE_RC."""
|
|
log = tmp_path / "checker.log"
|
|
script = write(
|
|
tmp_path,
|
|
"fake/check.sh",
|
|
f'#!/bin/bash\necho "$@" >> {log}\nexit "${{FAKE_RC:-0}}"\n',
|
|
0o755,
|
|
)
|
|
monkeypatch.setattr(gate, "CHECKER", script)
|
|
monkeypatch.delenv("GITHUB_ACTIONS", raising=False)
|
|
return log
|
|
|
|
|
|
def site(tmp_path: Path, body: str) -> Path:
|
|
root = tmp_path / "site"
|
|
root.mkdir()
|
|
config(root, body)
|
|
return root
|
|
|
|
|
|
def test_dist_builds_in_a_copy_then_checks(tmp_path: Path, fake_checker: Path) -> None:
|
|
root = site(
|
|
tmp_path,
|
|
'[agent_ready]\ndist = "out"\nbuild = "mkdir -p out && touch out/built"\n'
|
|
'install = "touch installed"\nact = true\n',
|
|
)
|
|
assert gate.main(["--repo", str(root)]) == 0
|
|
assert not (root / "out").exists()
|
|
assert not (root / "installed").exists()
|
|
mode, checked, act = fake_checker.read_text().split("\n")[0].split(" ")
|
|
assert (mode, Path(checked).name, act) == ("dist", "out", "--act")
|
|
assert root not in Path(checked).parents
|
|
assert gate.main(["--repo", str(root), "--install"]) == 0
|
|
assert (root / "installed").exists()
|
|
|
|
|
|
LIVE_BUILD = (
|
|
'[agent_ready]\ndist = "dist"\n'
|
|
'build = "rm -rf dist && mkdir dist && echo built > dist/index.html"\n'
|
|
)
|
|
|
|
|
|
def _live_site(root: Path) -> Path:
|
|
config(root, LIVE_BUILD)
|
|
write(root, "dist/live.html", "served by caddy\n")
|
|
write(root, "src/app.ts", "x\n")
|
|
write(root, "node_modules/dep/index.js", "module.exports = 1\n")
|
|
return root
|
|
|
|
|
|
def _assert_live_untouched(root: Path, log: Path) -> None:
|
|
assert (root / "dist" / "live.html").read_text() == "served by caddy\n"
|
|
assert not (root / "dist" / "index.html").exists()
|
|
assert "index.html" in log.read_text() # the copy WAS built and checked
|
|
|
|
|
|
@pytest.fixture
|
|
def listing_checker(fake_checker: Path) -> Path:
|
|
"""The fake checker also logs what the checked build dir contains."""
|
|
script = gate.CHECKER
|
|
script.write_text(script.read_text().replace('echo "$@"', 'echo "$@"; ls "$2"'))
|
|
return fake_checker
|
|
|
|
|
|
def test_live_dist_untouched_without_git(tmp_path: Path, listing_checker: Path) -> None:
|
|
root = _live_site(tmp_path / "site")
|
|
assert gate.main(["--repo", str(root)]) == 0
|
|
_assert_live_untouched(root, listing_checker)
|
|
|
|
|
|
def test_live_dist_untouched_in_git_repo(tmp_path: Path, listing_checker: Path) -> None:
|
|
root = _live_site(tmp_path / "site")
|
|
write(root, ".gitignore", "dist/\nnode_modules/\n")
|
|
subprocess.run(["git", "init", "-q", str(root)], check=True)
|
|
(root / "src" / "gone.ts").write_text("x\n")
|
|
subprocess.run(["git", "-C", str(root), "add", "-A"], check=True)
|
|
(root / "src" / "gone.ts").unlink() # tracked but deleted in the worktree
|
|
config(root, LIVE_BUILD.replace("echo built", "ls node_modules/dep src"))
|
|
assert gate.main(["--repo", str(root)]) == 0
|
|
_assert_live_untouched(root, listing_checker)
|
|
|
|
|
|
def test_failed_build_fails_without_checking(
|
|
tmp_path: Path, fake_checker: Path, capsys: pytest.CaptureFixture[str]
|
|
) -> None:
|
|
root = site(tmp_path, '[agent_ready]\ndist = "d"\nbuild = "echo boom; exit 7"\n')
|
|
assert gate.main(["--repo", str(root)]) == 1
|
|
assert "boom" in capsys.readouterr().err
|
|
assert not fake_checker.exists()
|
|
|
|
|
|
def test_failed_install_fails(tmp_path: Path, fake_checker: Path) -> None:
|
|
root = site(tmp_path, '[agent_ready]\ndist = "d"\ninstall = "exit 3"\n')
|
|
assert gate.main(["--repo", str(root), "--install"]) == 1
|
|
assert not fake_checker.exists()
|
|
|
|
|
|
def test_checker_failure_propagates(
|
|
tmp_path: Path, fake_checker: Path, monkeypatch: pytest.MonkeyPatch
|
|
) -> None:
|
|
root = site(tmp_path, '[agent_ready]\ndist = "d"\n')
|
|
monkeypatch.setenv("FAKE_RC", "1")
|
|
assert gate.main(["--repo", str(root)]) == 1
|
|
|
|
|
|
def test_url_mode_degrades_offline_unless_strict(
|
|
tmp_path: Path,
|
|
fake_checker: Path,
|
|
monkeypatch: pytest.MonkeyPatch,
|
|
capsys: pytest.CaptureFixture[str],
|
|
) -> None:
|
|
root = site(tmp_path, '[agent_ready]\nurl = "https://x.example"\n')
|
|
monkeypatch.setenv("FAKE_RC", "3")
|
|
assert gate.main(["--repo", str(root)]) == 0
|
|
assert "DEGRADED" in capsys.readouterr().err
|
|
assert gate.main(["--repo", str(root), "--strict"]) == 3
|
|
assert fake_checker.read_text().splitlines()[0] == "url https://x.example"
|
|
|
|
|
|
def test_skip_and_no_site(
|
|
tmp_path: Path, fake_checker: Path, capsys: pytest.CaptureFixture[str]
|
|
) -> None:
|
|
root = site(tmp_path, '[agent_ready]\nskip = "auth-gated"\n')
|
|
assert gate.main(["--repo", str(root)]) == 0
|
|
assert "auth-gated" in capsys.readouterr().out
|
|
assert gate.main(["--repo", str(tmp_path / "fake")]) == 0
|
|
assert not fake_checker.exists()
|
|
|
|
|
|
def test_unconfigured_web_repo_fails(tmp_path: Path, fake_checker: Path) -> None:
|
|
root = vite_repo(tmp_path / "v")
|
|
assert gate.main(["--repo", str(root)]) == 1
|
|
|
|
|
|
def test_bad_config_is_usage_error(tmp_path: Path, fake_checker: Path) -> None:
|
|
root = site(tmp_path, "[agent_ready]\n")
|
|
assert gate.main(["--repo", str(root)]) == 2
|
|
|
|
|
|
def test_pre_commit_in_ci_defers_to_the_workflow(
|
|
tmp_path: Path,
|
|
fake_checker: Path,
|
|
monkeypatch: pytest.MonkeyPatch,
|
|
capsys: pytest.CaptureFixture[str],
|
|
) -> None:
|
|
root = site(tmp_path, '[agent_ready]\ndist = "d"\nbuild = "exit 1"\n')
|
|
monkeypatch.setenv("GITHUB_ACTIONS", "true")
|
|
assert gate.main(["--repo", str(root)]) == 0
|
|
assert "agent-ready workflow" in capsys.readouterr().out
|
|
assert gate.main(["--repo", str(root), "--strict"]) == 1
|
|
|
|
|
|
@pytest.mark.skipif(not gate.CHECKER.exists(), reason="agent_ready not checked out")
|
|
def test_real_checker_fails_a_bare_build(
|
|
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
) -> None:
|
|
# In CI the gate defers to the workflow (returns 0); force the local path.
|
|
monkeypatch.delenv("GITHUB_ACTIONS", raising=False)
|
|
root = site(tmp_path, '[agent_ready]\ndist = "dist"\n')
|
|
write(root, "dist/index.html", "<!doctype html><title>x</title><p>hi</p>")
|
|
assert gate.main(["--repo", str(root)]) == 1
|