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>
This commit is contained in:
Anders Kaseorg 2021-06-14 13:36:30 -07:00
parent 9ce7c52a10
commit d1b3ac8d94

View file

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