mirror of
https://github.com/kuhyx/utils.git
synced 2026-11-10 21:27:14 +01:00
Some checks are pending
dependency freshness / dependencies on newest stable (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
Flutter repos now fail the repo contract when a launcher icon's ink is not on the shared 340px circle (png_ink), the launcher label breaks the naming rule (capital, ASCII letters, <= 10 chars, <= 522 wide in GoogleSansFlex), or an applicationIdSuffix variant still carries the LAUNCHER category. hook_sync rewrites a repo's stale repo-contract `files:` line to the widened template. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017k9j5dbjenpfZj7dh2faPN
119 lines
3.6 KiB
Python
119 lines
3.6 KiB
Python
"""The widened repo-contract hook `files:` and the sync that rolls it out."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import re
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
import yaml
|
|
|
|
from repo_contract import hook_sync
|
|
from repo_contract.bootstrap import TEMPLATES
|
|
|
|
from .conftest import write
|
|
|
|
OLD = r" files: ^(CLAUDE\.md|AGENTS\.md|scripts/test_changed\.sh)$"
|
|
CONFIG = """repos:
|
|
- repo: local
|
|
hooks:
|
|
- id: repo-contract
|
|
name: repo contract
|
|
entry: scripts/check_repo_contract.sh
|
|
language: system
|
|
pass_filenames: false
|
|
{files}
|
|
- id: other
|
|
entry: x
|
|
"""
|
|
|
|
|
|
def template_regex() -> re.Pattern[str]:
|
|
hooks = yaml.safe_load((TEMPLATES / "pre-commit-snippet.yaml").read_text())
|
|
return re.compile(hooks[0]["files"])
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"path",
|
|
[
|
|
"CLAUDE.md",
|
|
"AGENTS.md",
|
|
"scripts/test_changed.sh",
|
|
"android/app/src/main/AndroidManifest.xml",
|
|
"app/android/app/src/sandbox/AndroidManifest.xml",
|
|
"android/app/build.gradle",
|
|
"android/app/build.gradle.kts",
|
|
"android/app/src/main/res/values/strings.xml",
|
|
"linux/todo.desktop",
|
|
"todo.desktop",
|
|
"assets/icon/icon_foreground.png",
|
|
"app/assets/icon/icon.png",
|
|
"repo-contract.toml",
|
|
"focus-owner/repo-contract.toml",
|
|
"pubspec.yaml",
|
|
],
|
|
)
|
|
def test_template_fires_on_launcher_files(path: str) -> None:
|
|
assert template_regex().search(path)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"path",
|
|
["lib/main.dart", "docs/CLAUDE.md", "assets/icon/sub/x.png", "x.desktop.bak"],
|
|
)
|
|
def test_template_ignores_other_files(path: str) -> None:
|
|
assert not template_regex().search(path)
|
|
|
|
|
|
def config(repo: Path, files: str = OLD) -> Path:
|
|
return write(repo, ".pre-commit-config.yaml", CONFIG.format(files=files))
|
|
|
|
|
|
def test_status(tmp_path: Path) -> None:
|
|
assert hook_sync.status(tmp_path) == "no hook"
|
|
config(tmp_path)
|
|
assert hook_sync.status(tmp_path) == "stale"
|
|
config(tmp_path, hook_sync.template_line())
|
|
assert hook_sync.status(tmp_path) == "current"
|
|
|
|
|
|
def test_dry_run_changes_nothing(
|
|
tmp_path: Path, capsys: pytest.CaptureFixture[str]
|
|
) -> None:
|
|
before = config(tmp_path).read_text()
|
|
assert hook_sync.main([str(tmp_path)]) == 1
|
|
assert (tmp_path / ".pre-commit-config.yaml").read_text() == before
|
|
out = capsys.readouterr().out
|
|
assert f"would update: {tmp_path}" in out
|
|
assert "1 stale, 0 updated, 0 current, 0 without the hook" in out
|
|
|
|
|
|
def test_apply_rewrites_only_the_files_line(
|
|
tmp_path: Path, capsys: pytest.CaptureFixture[str]
|
|
) -> None:
|
|
path = config(tmp_path)
|
|
assert hook_sync.main(["--apply", str(tmp_path)]) == 0
|
|
assert path.read_text() == CONFIG.format(files=hook_sync.template_line())
|
|
assert f"updated: {tmp_path}" in capsys.readouterr().out
|
|
assert hook_sync.main(["--apply", str(tmp_path)]) == 0
|
|
assert "0 stale, 0 updated, 1 current" in capsys.readouterr().out
|
|
|
|
|
|
def test_hook_without_files_line_gets_one(tmp_path: Path) -> None:
|
|
config(tmp_path, " always_run: false")
|
|
assert hook_sync.status(tmp_path) == "stale"
|
|
hook_sync.main(["--apply", str(tmp_path)])
|
|
assert hook_sync.status(tmp_path) == "current"
|
|
|
|
|
|
def test_default_roots_are_the_sweep_roots(
|
|
tmp_path: Path, capsys: pytest.CaptureFixture[str]
|
|
) -> None:
|
|
(tmp_path / "a" / ".git").mkdir(parents=True)
|
|
(tmp_path / "b" / ".git").mkdir(parents=True)
|
|
config(tmp_path / "a", hook_sync.template_line())
|
|
assert hook_sync.main([], roots=[tmp_path]) == 0
|
|
out = capsys.readouterr().out
|
|
assert f"current: {tmp_path / 'a'}" in out
|
|
assert f"no hook: {tmp_path / 'b'}" in out
|