mirror of
https://github.com/kuhyx/utils.git
synced 2026-11-11 21:34:04 +01:00
teatr-pw and teatr-pw-pytania (created ad hoc 2026-10-09) had no shim, hook or '## Commands' section: the gate was only ever rolled out by hand. The installer writes shim + pre-commit hook + CI workflow and bootstraps the Commands section and scripts/test_changed.sh, exiting 1 while <FILL IN> remains. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TjyHmRrjZssaxXDWcGuCeQ
115 lines
3.6 KiB
Python
115 lines
3.6 KiB
Python
"""The installer writes the shim, hook, workflow and Commands section once."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import stat
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from repo_contract import install as inst
|
|
from repo_contract.check import violations
|
|
|
|
from .conftest import good_repo, write
|
|
|
|
|
|
def python_repo(root: Path) -> Path:
|
|
"""A python repo with tests and no contract pieces at all."""
|
|
write(root, "pyproject.toml", "[project]\nname='x'\n")
|
|
write(root, "tests/test_a.py", "def test_a():\n pass\n")
|
|
return root
|
|
|
|
|
|
def test_plan_lists_everything_for_a_bare_repo(repo: Path) -> None:
|
|
assert inst.plan(repo) == [
|
|
"scripts/check_repo_contract.sh",
|
|
".github/workflows/repo-contract.yml",
|
|
".pre-commit-config.yaml (repo-contract hook)",
|
|
]
|
|
|
|
|
|
def test_install_writes_pieces_and_is_idempotent(repo: Path) -> None:
|
|
python_repo(repo)
|
|
done = inst.install(repo)
|
|
assert len(done) == 3
|
|
shim = repo / inst.SHIM
|
|
assert shim.stat().st_mode & stat.S_IXUSR
|
|
assert "id: repo-contract" in (repo / inst.PRECOMMIT).read_text(encoding="utf-8")
|
|
assert inst.install(repo) == []
|
|
assert inst.plan(repo) == []
|
|
|
|
|
|
def test_marker_skips_workflow(repo: Path) -> None:
|
|
write(repo, ".dep-freshness-no-workflow")
|
|
inst.install(repo)
|
|
assert not (repo / inst.WORKFLOW).exists()
|
|
|
|
|
|
def test_utils_itself_is_not_given_a_shim(repo: Path) -> None:
|
|
write(repo, "repo_contract/check.py")
|
|
assert inst.install(repo) != []
|
|
assert not (repo / inst.SHIM).exists()
|
|
|
|
|
|
def test_hook_lands_in_the_last_local_block(repo: Path) -> None:
|
|
write(
|
|
repo,
|
|
inst.PRECOMMIT.as_posix(),
|
|
"repos:\n - repo: local\n hooks:\n - id: a\n"
|
|
" - repo: https://example.com/x\n hooks:\n - id: b",
|
|
)
|
|
inst.install(repo)
|
|
lines = (repo / inst.PRECOMMIT).read_text(encoding="utf-8").splitlines()
|
|
assert lines.index(" - id: repo-contract") < lines.index(
|
|
" - repo: https://example.com/x"
|
|
)
|
|
|
|
|
|
def test_hook_needs_a_local_block(repo: Path) -> None:
|
|
write(repo, inst.PRECOMMIT.as_posix(), "repos:\n - repo: https://example.com/x\n")
|
|
with pytest.raises(ValueError, match="no ` - repo: local` block"):
|
|
inst.install(repo)
|
|
|
|
|
|
def test_bootstrap_commands_creates_section_and_script(repo: Path) -> None:
|
|
python_repo(repo)
|
|
actions = inst.bootstrap_commands(repo)
|
|
assert any("test_changed.sh" in a for a in actions)
|
|
assert "## Commands" in (repo / "CLAUDE.md").read_text(encoding="utf-8")
|
|
assert inst.bootstrap_commands(repo) == []
|
|
|
|
|
|
def test_main_check_changes_nothing(
|
|
repo: Path, capsys: pytest.CaptureFixture[str]
|
|
) -> None:
|
|
assert inst.main([str(repo), "--check"]) == 1
|
|
out = capsys.readouterr().out
|
|
assert "would write: scripts/check_repo_contract.sh" in out
|
|
assert not (repo / inst.SHIM).exists()
|
|
|
|
|
|
def test_main_installs_and_passes(
|
|
repo: Path, capsys: pytest.CaptureFixture[str]
|
|
) -> None:
|
|
good_repo(repo)
|
|
assert inst.main([str(repo)]) == 0
|
|
assert "wrote: scripts/check_repo_contract.sh" in capsys.readouterr().out
|
|
assert violations(repo)[0] == []
|
|
|
|
|
|
def test_main_no_bootstrap_leaves_violation(repo: Path) -> None:
|
|
assert inst.main([str(repo), "--no-bootstrap"]) == 1
|
|
assert not (repo / "CLAUDE.md").exists()
|
|
|
|
|
|
def test_main_rejects_non_repo(tmp_path: Path) -> None:
|
|
assert inst.main([str(tmp_path)]) == 2
|
|
|
|
|
|
def test_main_reports_bootstrap_actions(
|
|
repo: Path, capsys: pytest.CaptureFixture[str]
|
|
) -> None:
|
|
python_repo(repo)
|
|
inst.main([str(repo)])
|
|
assert "bootstrap: created scripts/test_changed.sh" in capsys.readouterr().out
|