mirror of
https://github.com/kuhyx/steam-backlog-enforcer.git
synced 2026-11-10 19:07:05 +01:00
Vendors ~/utils/file_length into scripts/file_length so the gate is reachable in CI: pre-commit's `entry:` is not shell-expanded and GitHub runners have no ~/utils, so an external reference would pass locally and silently skip on push. The existing pre-commit/action all-files job picks the hook up with no workflow change. The vendored copy is excluded from ruff/ruff-format/mypy/pylint and must stay byte-identical to upstream -- ruff --unsafe-fixes otherwise rewrites its print() calls to `pass` (T201/F841), which leaves the gate exiting 1 while reporting nothing. Also: - name-tests-test now exempts tests/_*.py, so the 35 test-file splits have a landing zone for shared helpers (it rejects any non-test_*.py module under tests/). - pylint max-module-lines 1000 -> 250, so both limits agree. Note: .git/hooks/pre-commit was never installed in this repo (only pre-push), so no commit-stage hook had ever run. Installed via `pre-commit install`. 55 files are currently over the cap; they are split in following commits. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PPpmMpTSkp8UziRc5u8B7P
83 lines
2.8 KiB
Python
83 lines
2.8 KiB
Python
"""Predicates deciding whether a file is exempt from the 250-line cap.
|
|
|
|
Split from :mod:`file_length.config`, which holds the tables these read.
|
|
Keeping the rules separate from the data they consult means a new exemption
|
|
is a table entry, not a new branch, and the gate and the survey keep sharing
|
|
one definition of "exempt".
|
|
|
|
Re-exported from :mod:`file_length.config`, so existing
|
|
``from file_length.config import is_generated`` imports keep working.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import TYPE_CHECKING
|
|
|
|
from file_length._tables import (
|
|
DATA_TXT_MAX_MEAN_LINE,
|
|
EXCLUDED_DIRS,
|
|
GENERATED_MARKERS,
|
|
GENERATED_PATTERN,
|
|
SESSION_ARTIFACTS_ANYWHERE,
|
|
THIRD_PARTY_REPOS,
|
|
VENDORED_ANYWHERE,
|
|
VENDORED_SUBPATHS,
|
|
)
|
|
|
|
if TYPE_CHECKING:
|
|
from pathlib import Path
|
|
|
|
|
|
def is_generated(path: Path) -> bool:
|
|
"""True if the file is tool-generated and must not be split by hand."""
|
|
if GENERATED_PATTERN.search(path.as_posix()):
|
|
return True
|
|
try:
|
|
with path.open("r", encoding="utf-8", errors="replace") as handle:
|
|
head = "".join(next(handle, "") for _ in range(5))
|
|
except OSError:
|
|
return False
|
|
return any(marker in head for marker in GENERATED_MARKERS)
|
|
|
|
|
|
def is_data_text(path: Path, lines: int, size: int) -> bool:
|
|
"""True for wordlist-style .txt: many lines, very short ones."""
|
|
if path.suffix.lower() != ".txt" or lines <= 0:
|
|
return False
|
|
return (size / lines) < DATA_TXT_MAX_MEAN_LINE
|
|
|
|
|
|
def is_vendored(path: Path) -> bool:
|
|
"""True if the path sits under a known vendored subtree or excluded dir.
|
|
|
|
Callers must pass an absolute path (see `check.absolutize`). Every rule
|
|
below needs the repo-name context that a repo-relative path has already
|
|
thrown away: '/.claude/skills/' cannot match 'skills/x.md', so a relative
|
|
path would quietly skip the exemption instead of applying it.
|
|
"""
|
|
parts = path.parts
|
|
if any(part in EXCLUDED_DIRS for part in parts):
|
|
return True
|
|
posix = path.as_posix()
|
|
if any(marker in posix for marker in VENDORED_ANYWHERE):
|
|
return True
|
|
for repo, subs in VENDORED_SUBPATHS.items():
|
|
for sub in subs:
|
|
if f"/{repo}/{sub}/" in posix:
|
|
return True
|
|
return any(f"/{repo}/" in posix for repo in THIRD_PARTY_REPOS)
|
|
|
|
|
|
def is_session_artifact(path: Path) -> bool:
|
|
"""True for a frozen agent-session record (a plan or a session log).
|
|
|
|
Kept separate from `is_vendored` so the gate reports why a file is exempt:
|
|
these are kuhy's own files, not third-party code.
|
|
|
|
Callers must pass an absolute path (see `check.absolutize`), for the same
|
|
reason `is_vendored` does -- a repo-relative path has already dropped the
|
|
leading directory these markers match on.
|
|
"""
|
|
posix = path.as_posix()
|
|
return any(marker in posix for marker in SESSION_ARTIFACTS_ANYWHERE)
|