Skip to content
Merged
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
37 changes: 37 additions & 0 deletions scripts/lint_commits.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,24 @@
# below 50 characters, with occasional outliers.
COMMIT_MSG_MAX_SUMMARY_LEN = 100

# Conventional commit types (https://www.conventionalcommits.org/)
CONVENTIONAL_COMMIT_TYPES = {
"feat",
"fix",
"docs",
"style",
"refactor",
"perf",
"test",
"chore",
"ci",
"build",
"revert",
}

# Matches: <type>[(<scope>)][!]: <description>
CONVENTIONAL_COMMIT_RE = re.compile(r"^(?P<type>[a-z]+)(\([^)]+\))?!?: .+")


def error(msg: str, commit: str | None = None) -> None:
"""Log error."""
Expand Down Expand Up @@ -84,6 +102,25 @@ def lint_commit_message(commit: str) -> bool:
)
success = False

# Check conventional commit format.
cc_match = CONVENTIONAL_COMMIT_RE.match(lines[0])
if cc_match is None:
error(
f"The summary line {lines[0]!r} does not follow the conventional "
"commit format. Expected: <type>[(<scope>)][!]: <description>. "
f"Valid types are: {', '.join(sorted(CONVENTIONAL_COMMIT_TYPES))}. "
"See https://www.conventionalcommits.org/ for details.",
commit,
)
success = False
elif cc_match.group("type") not in CONVENTIONAL_COMMIT_TYPES:
error(
f"The commit type {cc_match.group('type')!r} is not recognised. "
f"Valid types are: {', '.join(sorted(CONVENTIONAL_COMMIT_TYPES))}.",
commit,
)
success = False

# Check for an empty line separating the summary line from the long
# description.
if len(lines) > 1 and lines[1] != "":
Expand Down
Loading