From c0c9f70f160218391b386387d97a5caf750d8d61 Mon Sep 17 00:00:00 2001 From: Lane0218 Date: Tue, 30 Dec 2025 09:46:02 +0800 Subject: [PATCH] =?UTF-8?q?chore(dev):=20=E6=96=B0=E5=A2=9Ecommit=20messag?= =?UTF-8?q?e=E6=A3=80=E9=AA=8C=E9=92=A9=E5=AD=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .githooks/commit-msg | 126 +++++++++++++++++++++++++++++++ doc/Git Commit Message 规范.md | 3 +- scripts/setup-git-hooks.sh | 30 ++++++++ 3 files changed, 158 insertions(+), 1 deletion(-) create mode 100755 .githooks/commit-msg create mode 100755 scripts/setup-git-hooks.sh diff --git a/.githooks/commit-msg b/.githooks/commit-msg new file mode 100755 index 0000000..f54edfc --- /dev/null +++ b/.githooks/commit-msg @@ -0,0 +1,126 @@ +#!/usr/bin/env bash +set -euo pipefail + +msg_file="${1:-}" + +if [[ -z "${msg_file}" || ! -f "${msg_file}" ]]; then + echo "错误:未找到提交信息文件(commit-msg hook 未收到有效参数)。" >&2 + exit 1 +fi + +# 读取第一条“有效提交信息”(跳过空行与注释行),并兼容 CRLF。 +first_line="$( + awk ' + { + sub(/\r$/, "") + if ($0 ~ /^[[:space:]]*#/) next + if ($0 ~ /^[[:space:]]*$/) next + print + exit + } + ' "${msg_file}" +)" + +allowed_types=( + feat fix docs style refactor perf test build ci chore revert +) + +allowed_scopes=( + frontend ast sema ir irgen mir backend antlr build test doc dev +) + +print_allowed() { + local IFS="|" + echo "允许的 type:${allowed_types[*]}" >&2 + echo "允许的 scope:${allowed_scopes[*]}" >&2 +} + +fail() { + local reason="$1" + local extra="${2:-}" + + echo "错误:提交信息不符合规范:${reason}" >&2 + echo "" >&2 + echo "当前提交信息:" >&2 + echo " ${first_line}" >&2 + echo "" >&2 + echo "规范格式:" >&2 + echo " (): " >&2 + echo "" >&2 + echo "注意:" >&2 + echo " 1) 冒号必须是英文 ':'(不是中文 ':')。" >&2 + echo " 2) 冒号后必须严格跟 1 个空格(': ')。" >&2 + echo "" >&2 + print_allowed + echo "" >&2 + echo "示例:" >&2 + echo " feat(irgen): add constant folding" >&2 + echo " fix(sema): handle null symbol" >&2 + echo " docs(doc): update build instructions" >&2 + if [[ -n "${extra}" ]]; then + echo "" >&2 + echo "${extra}" >&2 + fi + echo "" >&2 + echo "参考文档:doc/Git Commit Message 规范.md" >&2 + exit 1 +} + +if [[ -z "${first_line}" ]]; then + fail "提交信息为空(第一行不能为空)。" +fi + +# 允许 merge 提交信息(如:git merge 默认生成的 message)。 +if [[ "${first_line}" == "Merge "* ]]; then + exit 0 +fi + +# 允许 fixup!/squash!(用于 rebase --autosquash 等流程)。 +if [[ "${first_line}" == "fixup!"* || "${first_line}" == "squash!"* ]]; then + exit 0 +fi + +# 先做一些常见错误的定向提示。 +if [[ "${first_line}" == *":"* ]]; then + fail "检测到中文冒号 ':'。" "请把中文冒号替换为英文冒号 ':',并确保冒号后有且仅有 1 个空格。" +fi + +if [[ "${first_line}" =~ ^[A-Za-z]+\([A-Za-z]+\):[^[:space:]].*$ ]]; then + fail "冒号后缺少空格。" "正确写法应为 ': '(英文冒号 + 1 个空格)。" +fi + +if [[ "${first_line}" =~ ^[A-Za-z]+\([A-Za-z]+\):[[:space:]]{2,}.*$ ]]; then + fail "冒号后空格数量不正确(多于 1 个空格)。" "请确保冒号后严格是 1 个空格(': ')。" +fi + +type="" +scope="" +subject="" + +if [[ "${first_line}" =~ ^([A-Za-z]+)\(([A-Za-z]+)\):\ (.+)$ ]]; then + type="${BASH_REMATCH[1]}" + scope="${BASH_REMATCH[2]}" + subject="${BASH_REMATCH[3]}" +else + fail "格式不正确。" "请按 '(): ' 格式填写。" +fi + +if [[ "${subject}" =~ ^[[:space:]] ]]; then + fail "冒号后的空格数量不正确(多于 1 个空格)。" "请确保冒号后严格是 1 个空格(': ')。" +fi + +case "${type}" in + feat | fix | docs | style | refactor | perf | test | build | ci | chore | revert) ;; + *) + fail "type 不合法:${type}" "请使用允许的 type(小写)。" + ;; +esac + +case "${scope}" in + frontend | ast | sema | ir | irgen | mir | backend | antlr | build | test | doc | dev) ;; + *) + fail "scope 不合法:${scope}" "请使用允许的 scope(严格限制)。" + ;; +esac + +exit 0 diff --git a/doc/Git Commit Message 规范.md b/doc/Git Commit Message 规范.md index 88e4b11..92f6366 100644 --- a/doc/Git Commit Message 规范.md +++ b/doc/Git Commit Message 规范.md @@ -10,7 +10,7 @@ - ``:提交类型(必填) - ``:影响范围/模块(必填) -- ``:一句话说明“做了什么”(必填) +- ``:用一句中文说明“做了什么”(必填) --- @@ -51,3 +51,4 @@ | `build` | 构建配置 | | `test` | 测试 | | `doc` | 文档 | +| `dev` | 开发流程/工具(hooks、脚本、规范等) | diff --git a/scripts/setup-git-hooks.sh b/scripts/setup-git-hooks.sh new file mode 100755 index 0000000..86503d3 --- /dev/null +++ b/scripts/setup-git-hooks.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +set -euo pipefail + +repo_root="$(git rev-parse --show-toplevel 2>/dev/null || true)" +if [[ -z "${repo_root}" ]]; then + echo "错误:当前目录不是 Git 仓库,无法配置 hooks。" >&2 + exit 1 +fi + +cd "${repo_root}" + +hooks_dir=".githooks" +if [[ ! -d "${hooks_dir}" ]]; then + echo "错误:未找到 ${hooks_dir} 目录,请确认仓库已包含 hooks 文件。" >&2 + exit 1 +fi + +git config core.hooksPath "${hooks_dir}" + +echo "已启用本仓库 Git hooks:" >&2 +echo " core.hooksPath=${hooks_dir}" >&2 +echo "" >&2 +echo "现在执行 git commit 时会校验提交信息是否符合:" >&2 +echo " doc/Git Commit Message 规范.md" >&2 +echo "" >&2 +echo "查看当前配置:" >&2 +echo " git config --get core.hooksPath" >&2 +echo "" >&2 +echo "如需取消(恢复默认 .git/hooks): " >&2 +echo " git config --unset core.hooksPath" >&2