Skip to content

Topic/remove qrcode #1014

Topic/remove qrcode

Topic/remove qrcode #1014

Workflow file for this run

name: Commit Message Check
on:
push:
branches:
- master
pull_request:
jobs:
check-commit-message:
name: Validate commit messages
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Validate commit messages in range
env:
EVENT_NAME: ${{ github.event_name }}
PUSH_BEFORE: ${{ github.event.before }}
PUSH_AFTER: ${{ github.sha }}
PR_BASE_SHA: ${{ github.event.pull_request.base.sha }}
PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
python3 <<'PY'
import os
import re
import subprocess
import sys
TITLE_FORMAT = re.compile(
r'^(fix|feat|refactor|perf|style|test|docs|build|ci|chore|revert)'
r'(!\([A-Za-z0-9_-]+(,[a-z0-9_-]+)?\)|'
r'\([A-Za-z0-9_-]+(,[a-z0-9_-]+)?\)!?): [a-z0-9 ].*$'
)
TITLE_CAPITALIZATION = re.compile(r'^[^A-Z]')
TITLE_WORD_COUNT = re.compile(r'^[^ ]+([ \t]+[^ ]+){2,}$', re.S)
TITLE_LENGTH = re.compile(r'^([^\n]{1,80})(\n.*)?$', re.S)
BLANK_LINE = re.compile(r'^[^\n]+(\n\n.+)?$', re.S)
BODY_LINE_LENGTH = re.compile(r'^[^\n]+(\n[^\n]{0,80})*$', re.S)
def run(*args):
return subprocess.check_output(args, text=True).strip()
def commit_range():
event_name = os.environ["EVENT_NAME"]
if event_name == "pull_request":
head = os.environ["PR_HEAD_SHA"]
base = run("git", "merge-base", os.environ["PR_BASE_SHA"], head)
return base, head
before = os.environ["PUSH_BEFORE"]
after = os.environ["PUSH_AFTER"]
if before == "0000000000000000000000000000000000000000":
return "", after
return before, after
def list_commits(base, head):
if base:
output = run("git", "rev-list", f"{base}..{head}")
else:
output = run("git", "rev-list", head)
return [line for line in output.splitlines() if line]
def read_message(commit):
return subprocess.check_output(
["git", "show", "-s", "--format=%B", commit],
text=True,
).rstrip("\n")
def validate(commit, message):
title = message.split("\n", 1)[0]
failures = []
if not TITLE_FORMAT.match(title):
failures.append("Invalid commit title format.")
if not TITLE_CAPITALIZATION.match(title):
failures.append("Commit title must not start with an uppercase letter.")
if not TITLE_WORD_COUNT.match(title):
failures.append("Commit title must contain at least 3 words.")
if not TITLE_LENGTH.match(message):
failures.append("Commit title must be 80 characters or less.")
if title.endswith("."):
failures.append("Commit title must not end with a period.")
if not BLANK_LINE.match(message):
failures.append(
"If a commit body is present, it must be separated from the title by a blank line."
)
if not BODY_LINE_LENGTH.match(message):
failures.append("Each line in the commit body must be 80 characters or less.")
return title, failures
base, head = commit_range()
commits = list_commits(base, head)
range_label = f"{base}..{head}" if base else head
print(f"Validating commit messages in range: {range_label}")
print(f"Event: {os.environ['EVENT_NAME']}")
if not commits:
print("No commits to validate.")
sys.exit(0)
invalid = []
for commit in reversed(commits):
message = read_message(commit)
title, failures = validate(commit, message)
if failures:
invalid.append((commit, title, failures))
if invalid:
print(f"Commit message validation failed for {len(invalid)} commit(s).\n")
print("Commits outside the expected format:")
for commit, title, failures in invalid:
print(f"- {commit} {title}")
for failure in failures:
print(f" - {failure}")
print(f"::error title={commit[:10]} {title}::{failure}")
print()
sys.exit(1)
print(f"Validated {len(commits)} commit message(s).")
PY