gitlint-rules: Remove convoluted binary search for imperative forms.
This also fixes the suggestions for the following words: disabled,
disables, disabling, implemented, implementing, implements, kept,
made, took, using.
(Copied from zulip/zulip@91f048c056a66eb78a102c095e714eff5f28e36e.)
MODIFY
tools/gitlint-rules.py
tools/gitlint-rules.py
@@ -10,276 +10,70 @@ from gitlint.rules import CommitMessageTitle, LineRule, RuleViolation
# Copyright (c) 2015 Mike Foley
# License: MIT
# Ref: fit_commit/validators/tense.rb
-WORD_SET = {
- "adds",
- "adding",
- "added",
- "allows",
- "allowing",
- "allowed",
- "amends",
- "amending",
- "amended",
- "bumps",
- "bumping",
- "bumped",
- "calculates",
- "calculating",
- "calculated",
- "changes",
- "changing",
- "changed",
- "cleans",
- "cleaning",
- "cleaned",
- "commits",
- "committing",
- "committed",
- "corrects",
- "correcting",
- "corrected",
- "creates",
- "creating",
- "created",
- "darkens",
- "darkening",
- "darkened",
- "disables",
- "disabling",
- "disabled",
- "displays",
- "displaying",
- "displayed",
- "documents",
- "documenting",
- "documented",
- "drys",
- "drying",
- "dryed",
- "ends",
- "ending",
- "ended",
- "enforces",
- "enforcing",
- "enforced",
- "enqueues",
- "enqueuing",
- "enqueued",
- "extracts",
- "extracting",
- "extracted",
- "finishes",
- "finishing",
- "finished",
- "fixes",
- "fixing",
- "fixed",
- "formats",
- "formatting",
- "formatted",
- "guards",
- "guarding",
- "guarded",
- "handles",
- "handling",
- "handled",
- "hides",
- "hiding",
- "hid",
- "increases",
- "increasing",
- "increased",
- "ignores",
- "ignoring",
- "ignored",
- "implements",
- "implementing",
- "implemented",
- "improves",
- "improving",
- "improved",
- "keeps",
- "keeping",
- "kept",
- "kills",
- "killing",
- "killed",
- "makes",
- "making",
- "made",
- "merges",
- "merging",
- "merged",
- "moves",
- "moving",
- "moved",
- "permits",
- "permitting",
- "permitted",
- "prevents",
- "preventing",
- "prevented",
- "pushes",
- "pushing",
- "pushed",
- "rebases",
- "rebasing",
- "rebased",
- "refactors",
- "refactoring",
- "refactored",
- "removes",
- "removing",
- "removed",
- "renames",
- "renaming",
- "renamed",
- "reorders",
- "reordering",
- "reordered",
- "replaces",
- "replacing",
- "replaced",
- "requires",
- "requiring",
- "required",
- "restores",
- "restoring",
- "restored",
- "sends",
- "sending",
- "sent",
- "sets",
- "setting",
- "separates",
- "separating",
- "separated",
- "shows",
- "showing",
- "showed",
- "simplifies",
- "simplifying",
- "simplified",
- "skips",
- "skipping",
- "skipped",
- "sorts",
- "sorting",
- "speeds",
- "speeding",
- "sped",
- "starts",
- "starting",
- "started",
- "supports",
- "supporting",
- "supported",
- "takes",
- "taking",
- "took",
- "testing",
- "tested", # 'tests' excluded to reduce false negative
- "truncates",
- "truncating",
- "truncated",
- "updates",
- "updating",
- "updated",
- "uses",
- "using",
- "used",
-}
-
-imperative_forms = [
- "add",
- "allow",
- "amend",
- "bump",
- "calculate",
- "change",
- "clean",
- "commit",
- "correct",
- "create",
- "darken",
- "disable",
- "display",
- "document",
- "dry",
- "end",
- "enforce",
- "enqueue",
- "extract",
- "finish",
- "fix",
- "format",
- "guard",
- "handle",
- "hide",
- "ignore",
- "implement",
- "improve",
- "increase",
- "keep",
- "kill",
- "make",
- "merge",
- "move",
- "permit",
- "prevent",
- "push",
- "rebase",
- "refactor",
- "remove",
- "rename",
- "reorder",
- "replace",
- "require",
- "restore",
- "send",
- "separate",
- "set",
- "show",
- "simplify",
- "skip",
- "sort",
- "speed",
- "start",
- "support",
- "take",
- "test",
- "truncate",
- "update",
- "use",
+TENSE_DATA = [
+ (["adds", "adding", "added"], "add"),
+ (["allows", "allowing", "allowed"], "allow"),
+ (["amends", "amending", "amended"], "amend"),
+ (["bumps", "bumping", "bumped"], "bump"),
+ (["calculates", "calculating", "calculated"], "calculate"),
+ (["changes", "changing", "changed"], "change"),
+ (["cleans", "cleaning", "cleaned"], "clean"),
+ (["commits", "committing", "committed"], "commit"),
+ (["corrects", "correcting", "corrected"], "correct"),
+ (["creates", "creating", "created"], "create"),
+ (["darkens", "darkening", "darkened"], "darken"),
+ (["disables", "disabling", "disabled"], "disable"),
+ (["displays", "displaying", "displayed"], "display"),
+ (["documents", "documenting", "documented"], "document"),
+ (["drys", "drying", "dryed"], "dry"),
+ (["ends", "ending", "ended"], "end"),
+ (["enforces", "enforcing", "enforced"], "enforce"),
+ (["enqueues", "enqueuing", "enqueued"], "enqueue"),
+ (["extracts", "extracting", "extracted"], "extract"),
+ (["finishes", "finishing", "finished"], "finish"),
+ (["fixes", "fixing", "fixed"], "fix"),
+ (["formats", "formatting", "formatted"], "format"),
+ (["guards", "guarding", "guarded"], "guard"),
+ (["handles", "handling", "handled"], "handle"),
+ (["hides", "hiding", "hid"], "hide"),
+ (["increases", "increasing", "increased"], "increase"),
+ (["ignores", "ignoring", "ignored"], "ignore"),
+ (["implements", "implementing", "implemented"], "implement"),
+ (["improves", "improving", "improved"], "improve"),
+ (["keeps", "keeping", "kept"], "keep"),
+ (["kills", "killing", "killed"], "kill"),
+ (["makes", "making", "made"], "make"),
+ (["merges", "merging", "merged"], "merge"),
+ (["moves", "moving", "moved"], "move"),
+ (["permits", "permitting", "permitted"], "permit"),
+ (["prevents", "preventing", "prevented"], "prevent"),
+ (["pushes", "pushing", "pushed"], "push"),
+ (["rebases", "rebasing", "rebased"], "rebase"),
+ (["refactors", "refactoring", "refactored"], "refactor"),
+ (["removes", "removing", "removed"], "remove"),
+ (["renames", "renaming", "renamed"], "rename"),
+ (["reorders", "reordering", "reordered"], "reorder"),
+ (["replaces", "replacing", "replaced"], "replace"),
+ (["requires", "requiring", "required"], "require"),
+ (["restores", "restoring", "restored"], "restore"),
+ (["sends", "sending", "sent"], "send"),
+ (["sets", "setting"], "set"),
+ (["separates", "separating", "separated"], "separate"),
+ (["shows", "showing", "showed"], "show"),
+ (["simplifies", "simplifying", "simplified"], "simplify"),
+ (["skips", "skipping", "skipped"], "skip"),
+ (["sorts", "sorting"], "sort"),
+ (["speeds", "speeding", "sped"], "speed"),
+ (["starts", "starting", "started"], "start"),
+ (["supports", "supporting", "supported"], "support"),
+ (["takes", "taking", "took"], "take"),
+ (["testing", "tested"], "test"), # "tests" excluded to reduce false negatives
+ (["truncates", "truncating", "truncated"], "truncate"),
+ (["updates", "updating", "updated"], "update"),
+ (["uses", "using", "used"], "use"),
]
-imperative_forms.sort()
-
-
-def head_binary_search(key: str, words: List[str]) -> str:
- """Find the imperative mood version of `word` by looking at the first
- 3 characters."""
-
- # Edge case: 'disable' and 'display' have the same 3 starting letters.
- if key in ["displays", "displaying", "displayed"]:
- return "display"
-
- lower = 0
- upper = len(words) - 1
-
- while True:
- if lower > upper:
- # Should not happen
- raise Exception(f"Cannot find imperative mood of {key}")
-
- mid = (lower + upper) // 2
- imperative_form = words[mid]
- if key[:3] == imperative_form[:3]:
- return imperative_form
- elif key < imperative_form:
- upper = mid - 1
- elif key > imperative_form:
- lower = mid + 1
+TENSE_CORRECTIONS = {word: imperative for words, imperative in TENSE_DATA for word in words}
class ImperativeMood(LineRule):
@@ -303,8 +97,8 @@ class ImperativeMood(LineRule):
words = line.split(": ", 1)[-1].split()
first_word = words[0].lower()
- if first_word in WORD_SET:
- imperative = head_binary_search(first_word, imperative_forms)
+ if first_word in TENSE_CORRECTIONS:
+ imperative = TENSE_CORRECTIONS[first_word]
violation = RuleViolation(
self.id,
self.error_msg.format(

gitlint-rules: Remove convoluted binary search for imperative forms.

This also fixes the suggestions for the following words: disabled,
disables, disabling, implemented, implementing, implements, kept,
made, took, using.

(Copied from zulip/zulip@91f048c056a66eb78a102c095e714eff5f28e36e.)

Signed-off-by: Anders Kaseorg <anders@zulip.com>