97 lines
4 KiB
Python
97 lines
4 KiB
Python
import importlib.util
|
|
from pathlib import Path
|
|
import subprocess
|
|
|
|
import pytest
|
|
|
|
|
|
SCRIPT = Path(__file__).parents[1] / "scripts/install_shared_generated_guard.py"
|
|
spec = importlib.util.spec_from_file_location("shared_guard", SCRIPT)
|
|
guard = importlib.util.module_from_spec(spec)
|
|
spec.loader.exec_module(guard)
|
|
|
|
|
|
def repository(tmp_path):
|
|
repo = tmp_path / "repo"
|
|
repo.mkdir()
|
|
subprocess.run(["git", "init", str(repo)], check=True, capture_output=True)
|
|
hooks = tmp_path / "shared-hooks"
|
|
hooks.mkdir()
|
|
subprocess.run(["git", "-C", str(repo), "config", "core.hooksPath", str(hooks)], check=True)
|
|
return repo, hooks
|
|
|
|
|
|
def test_real_shared_hook_rejects_generated_only_and_retains_other_hooks(tmp_path):
|
|
repo, hooks = repository(tmp_path)
|
|
other = hooks / "prepare-commit-msg"
|
|
other.write_text("# existing owner hook\n")
|
|
before = other.read_bytes()
|
|
assert guard.install(repo)["status"] == "missing"
|
|
assert not (hooks / "pre-commit").exists()
|
|
assert guard.install(repo, True)["changed"]
|
|
assert not guard.install(repo, True)["changed"]
|
|
(repo / "WORK-RECORDS.md").write_text("derived\n")
|
|
subprocess.run(["git", "-C", str(repo), "add", "WORK-RECORDS.md"], check=True)
|
|
assert subprocess.run([str(hooks / "pre-commit")], cwd=repo, capture_output=True).returncode == 1
|
|
(repo / "implementation.py").write_text("print('source')\n")
|
|
subprocess.run(["git", "-C", str(repo), "add", "implementation.py"], check=True)
|
|
assert subprocess.run([str(hooks / "pre-commit")], cwd=repo, capture_output=True).returncode == 0
|
|
assert other.read_bytes() == before
|
|
|
|
|
|
def test_foreign_or_redirected_guard_is_never_replaced(tmp_path):
|
|
repo, hooks = repository(tmp_path)
|
|
hook = hooks / "pre-commit"
|
|
hook.write_text("owner implementation\n")
|
|
with pytest.raises(ValueError):
|
|
guard.install(repo, True)
|
|
assert hook.read_text() == "owner implementation\n"
|
|
hook.unlink()
|
|
private = tmp_path / "unrelated"
|
|
private.write_text("retained\n")
|
|
hook.symlink_to(private)
|
|
with pytest.raises(ValueError):
|
|
guard.install(repo, True)
|
|
assert private.read_text() == "retained\n"
|
|
|
|
|
|
def test_reviewed_scanner_composition_is_preserved(tmp_path):
|
|
repo, hooks = repository(tmp_path)
|
|
content = (SCRIPT.parents[1] / 'docs/changes/CUST-WP-0080/secret-hooks-pre-commit').read_bytes()
|
|
hook = hooks / 'pre-commit'
|
|
hook.write_bytes(content)
|
|
hook.chmod(0o755)
|
|
assert not guard.install(repo, True)['changed']
|
|
assert hook.read_bytes() == content
|
|
hook.write_bytes(content + b'\n# unreviewed revision\n')
|
|
with pytest.raises(ValueError):
|
|
guard.install(repo, True)
|
|
|
|
|
|
@pytest.mark.parametrize("existing_local", [False, True])
|
|
def test_make_install_recognizes_existing_shared_guard(tmp_path, existing_local):
|
|
import shutil
|
|
|
|
repo, hooks = repository(tmp_path)
|
|
source = SCRIPT.parents[1]
|
|
shutil.copyfile(source / "Makefile", repo / "Makefile")
|
|
(repo / "scripts").mkdir()
|
|
for name in ("install_shared_generated_guard.py", "check_generated_only_commit.py",
|
|
"generated-pre-commit.sh"):
|
|
shutil.copyfile(source / "scripts" / name, repo / "scripts" / name)
|
|
if existing_local:
|
|
hooks = repo / ".git" / "hooks"
|
|
subprocess.run(["git", "-C", str(repo), "config", "core.hooksPath", str(hooks)], check=True)
|
|
shutil.copyfile(source / "scripts/generated-pre-commit.sh", hooks / "pre-commit")
|
|
(hooks / "pre-commit").chmod(0o755)
|
|
other = hooks / "prepare-commit-msg"
|
|
other.write_text("owner hook\n")
|
|
for _ in range(2):
|
|
result = subprocess.run(["make", "generated-commit-hook"], cwd=repo,
|
|
capture_output=True, text=True)
|
|
assert result.returncode == 0, result.stderr
|
|
assert other.read_text() == "owner hook\n"
|
|
(repo / "WORK-RECORDS.md").write_text("generated\n")
|
|
subprocess.run(["git", "-C", str(repo), "add", "WORK-RECORDS.md"], check=True)
|
|
assert subprocess.run([str(hooks / "pre-commit")], cwd=repo,
|
|
capture_output=True).returncode == 1
|