Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions src/git_commit_guard/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,15 @@
)

_NON_IMPERATIVE_SUFFIX_RE = re.compile(r"(?:ing|ed)$")
_VERB_FORMING_PREFIXES = frozenset(
{
"re",
"pre",
"auto",
"co",
"under",
}
)
_TRAILER_RE = re.compile(r"^[\w-]+:\s+\S")
_GITHUB_REMOTE_RE = re.compile(
r"github\.com[:/](?P<owner>[^/]+)/(?P<repo>[^/\s]+?)(?:\.git)?$"
Expand Down Expand Up @@ -235,6 +244,13 @@ def check_imperative(desc, result):
if tagged[1][1] != "VB":
if wordnet.morphy(first, wordnet.VERB) == first:
return
if "-" in first:
hyphen_prefix, hyphen_base = first.split("-", 1)
if (
hyphen_prefix in _VERB_FORMING_PREFIXES
and wordnet.morphy(hyphen_base, wordnet.VERB) == hyphen_base
):
return
result.error(
f"expected imperative verb, got '{tagged[1][0]}' (POS={tagged[1][1]})",
check=Check.IMPERATIVE,
Expand Down
33 changes: 33 additions & 0 deletions tests/test_git_commit_guard.py
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,39 @@ def test_pos_fallback_unknown_word_fails(self):
assert not r.ok
assert "POS=NN" in r.errors[0][2]

def test_hyphen_re_prefix_verb_passes(self):
r = Result()
check_imperative("re-enable signature check", r)
assert r.ok

def test_hyphen_auto_prefix_verb_passes(self):
r = Result()
check_imperative("auto-detect format from header", r)
assert r.ok

def test_hyphen_pre_prefix_verb_passes(self):
r = Result()
check_imperative("pre-process input lines", r)
assert r.ok

def test_hyphen_unknown_prefix_fails(self):
# 'high' is not in the verb-forming prefix allowlist
r = Result()
check_imperative("high-level overview of foo", r)
assert not r.ok

def test_hyphen_non_verb_base_fails(self):
# 'in' is not a verb, so even though split shape matches, base check rejects
r = Result()
check_imperative("built-in helper function", r)
assert not r.ok

def test_hyphen_inflected_suffix_still_fails(self):
# Suffix check runs before hyphen escape — 're-running' caught by ing$
r = Result()
check_imperative("re-running the tests", r)
assert not r.ok


class TestDownloadIfMissing:
def test_skips_download_when_present(self):
Expand Down
Loading