hookehuyr

feat(husky): 使用 prepare-commit-msg + amend 实现 CHANGELOG 自动更新

- 创建 prepare-commit-msg hook
- 创建 update-changelog-prepare.sh 脚本
- 修改 post-commit 检查暂存区并 amend
- 使用 --no-verify 避免 amend 触发循环

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
5 # 5 #
6 # 功能: 6 # 功能:
7 # 1. 显示提交成功信息 7 # 1. 显示提交成功信息
8 -# 2. 补充 CHANGELOG 中的 commit hash 8 +# 2. 将 CHANGELOG amend 到当前提交(如果需要)
9 # 9 #
10 # 作者:Claude Code 10 # 作者:Claude Code
11 # 日期:2026-02-28 11 # 日期:2026-02-28
...@@ -49,36 +49,23 @@ echo " 删除行数: -$LINES_DELETED" ...@@ -49,36 +49,23 @@ echo " 删除行数: -$LINES_DELETED"
49 echo "" 49 echo ""
50 50
51 # ============================================ 51 # ============================================
52 -# 补充 CHANGELOG 中的 commit hash 52 +# 将 CHANGELOG amend 到当前提交(如果在暂存区)
53 # ============================================ 53 # ============================================
54 -CHANGELOG_FILE="CHANGELOG.md" 54 +if ! git diff --cached --quiet CHANGELOG.md 2>/dev/null; then
55 + echo "📝 ${BLUE}将 CHANGELOG 加入当前提交...${NC}"
55 56
56 -if [ -f "$CHANGELOG_FILE" ]; then 57 + # 使用 amend 将 CHANGELOG 加入当前提交
57 - # 检查 CHANGELOG 中是否有 "pending" hash 需要替换 58 + # --no-edit: 不修改 commit message
58 - if grep -q "\`pending\`" "$CHANGELOG_FILE"; then 59 + # --no-verify: 跳过 hooks,避免循环
59 - # 获取当前日期时间戳
60 - NOW_TIME=$(date +%H:%M:%S)
61 - TODAY=$(date +%Y-%m-%d)
62 -
63 - # 解析 commit message
64 - COMMIT_TYPE=$(echo "$COMMIT_MSG" | head -n 1 | sed -E 's/^([a-z]+)\(.*/\1/')
65 - COMMIT_SCOPE=$(echo "$COMMIT_MSG" | head -n 1 | sed -E 's/^[a-z]+\(([a-z-]+)\).*/\1/')
66 - COMMIT_SUBJECT=$(echo "$COMMIT_MSG" | head -n 1 | sed -E 's/^[a-z]+\([a-z-]+\): (.*)$/\1/')
67 -
68 - # 替换 pending hash 为真实的 commit hash
69 - # 使用 sed 进行替换
70 - sed -i.tmp "s/\[\$NOW_TIME - $COMMIT_TYPE($COMMIT_SCOPE): $COMMIT_SUBJECT/[$NOW_TIME - $COMMIT_TYPE($COMMIT_SCOPE): $COMMIT_SUBJECT/" "$CHANGELOG_FILE" 2>/dev/null || \
71 - sed -i.tmp "s/\`pending\` - $COMMIT_TYPE($COMMIT_SCOPE): $COMMIT_SUBJECT/\`$COMMIT_HASH\` - $COMMIT_TYPE($COMMIT_SCOPE): $COMMIT_SUBJECT/" "$CHANGELOG_FILE"
72 -
73 - # 清理临时文件
74 - rm -f "${CHANGELOG_FILE}.tmp"
75 -
76 - # 如果 CHANGELOG 有变更, amend 到当前提交
77 - if ! git diff --quiet "$CHANGELOG_FILE" 2>/dev/null; then
78 - git add "$CHANGELOG_FILE"
79 git commit --amend --no-edit --no-verify >/dev/null 2>&1 60 git commit --amend --no-edit --no-verify >/dev/null 2>&1
80 - echo " ${GREEN}✅ CHANGELOG commit hash 已更新${NC}" 61 +
81 - fi 62 + if [ $? -eq 0 ]; then
63 + # 获取 amend 后的 hash
64 + NEW_HASH=$(git log -1 --pretty=%h)
65 + echo " ${GREEN}✅ CHANGELOG 已加入提交${NC}"
66 + echo " ${BLUE} 新 Hash: $NEW_HASH${NC}"
67 + else
68 + echo " ${YELLOW}⚠️ CHANGELOG amend 失败${NC}"
82 fi 69 fi
83 fi 70 fi
84 71
......
...@@ -120,37 +120,10 @@ fi ...@@ -120,37 +120,10 @@ fi
120 echo " ${GREEN}✅ 改动规模检查通过${NC}" 120 echo " ${GREEN}✅ 改动规模检查通过${NC}"
121 121
122 # ============================================ 122 # ============================================
123 -# 4. 自动更新 CHANGELOG.md(在提交前)
124 -# ============================================
125 -echo ""
126 -echo "📋 ${BLUE}步骤 4/4: 更新 CHANGELOG${NC}"
127 -
128 -# 获取暂存的 commit message
129 -COMMIT_MSG_FILE=".git/COMMIT_EDITMSG"
130 -if [ -f "$COMMIT_MSG_FILE" ]; then
131 - COMMIT_MSG=$(cat "$COMMIT_MSG_FILE")
132 -
133 - # 解析 commit type
134 - COMMIT_TYPE=$(echo "$COMMIT_MSG" | head -n 1 | sed -E 's/^([a-z]+)\(.*/\1/')
135 -
136 - # 只对特定类型更新 CHANGELOG
137 - # 跳过: docs(changelog) 类型的提交,避免循环
138 - if echo "$COMMIT_MSG" | head -n 1 | grep -qE "^docs\(changelog\):"; then
139 - echo " ⏭️ 跳过 CHANGELOG 更新(docs(changelog) 类型提交)"
140 - elif [ "$COMMIT_TYPE" = "feat" ] || [ "$COMMIT_TYPE" = "fix" ] || [ "$COMMIT_TYPE" = "refactor" ] || [ "$COMMIT_TYPE" = "perf" ]; then
141 - # 调用 CHANGELOG 更新脚本
142 - bash scripts/changelog/update-changelog-precommit.sh "$COMMIT_MSG_FILE"
143 - else
144 - echo " ⏭️ 跳过 CHANGELOG 更新(类型: $COMMIT_TYPE)"
145 - fi
146 -else
147 - echo " ⚠️ 无法读取 commit message,跳过 CHANGELOG 更新"
148 -fi
149 -
150 -# ============================================
151 # 所有检查通过 123 # 所有检查通过
152 # ============================================ 124 # ============================================
153 echo "" 125 echo ""
154 echo "✅ ${GREEN}所有检查通过!${NC}" 126 echo "✅ ${GREEN}所有检查通过!${NC}"
155 echo "🚀 ${BLUE}开始提交...${NC}" 127 echo "🚀 ${BLUE}开始提交...${NC}"
128 +echo "📝 ${BLUE}CHANGELOG.md 将在 prepare-commit-msg 阶段更新${NC}"
156 echo "" 129 echo ""
......
1 +#!/bin/sh
2 +# ============================================
3 +# Prepare-commit-msg Hook
4 +# ============================================
5 +#
6 +# 功能:
7 +# 1. 自动更新 CHANGELOG.md(包含在当前提交中)
8 +#
9 +# 关键特性:
10 +# - 只在初始提交时执行,amend 时不会触发
11 +# - 配合 post-commit 使用 amend --no-verify 完成流程
12 +#
13 +# 作者:Claude Code
14 +# 日期:2026-02-28
15 +# ============================================
16 +
17 +# 颜色定义
18 +RED='\033[0;31m'
19 +GREEN='\033[0;32m'
20 +BLUE='\033[0;34m'
21 +YELLOW='\033[1;33m'
22 +NC='\033[0m' # No Color
23 +
24 +# 获取 commit message 文件
25 +COMMIT_MSG_FILE=$1
26 +COMMIT_SOURCE=$2 # commit 来源:message/template/merge/squash等
27 +
28 +# 只在正常的 commit 时执行,跳过 merge/rebase/amend
29 +# amend 时 COMMIT_SOURCE 为空
30 +if [ "$COMMIT_SOURCE" = "message" ] || [ "$COMMIT_SOURCE" = "template" ] || [ "$COMMIT_SOURCE" = "" ]; then
31 + # 检查是否是 amend 操作(通过检查是否已有 commit)
32 + # 如果 HEAD 存在且不是初始提交,可能是 amend
33 + if git rev-parse HEAD >/dev/null 2>&1; then
34 + # 有 HEAD,检查是否是正在 amend
35 + # 简单的判断:如果已经有 commit 且当前没有在 rebase 等操作中
36 + # 这里我们允许继续,因为关键在于 post-commit 的 --no-verify
37 + :
38 + fi
39 +
40 + # 读取 commit message
41 + if [ -f "$COMMIT_MSG_FILE" ]; then
42 + COMMIT_MSG=$(cat "$COMMIT_MSG_FILE")
43 +
44 + # 只处理第一行(subject)
45 + FIRST_LINE=$(echo "$COMMIT_MSG" | head -n 1)
46 +
47 + # 解析 commit type
48 + COMMIT_TYPE=$(echo "$FIRST_LINE" | sed -E 's/^([a-z]+)\(.*/\1/')
49 +
50 + # 只对特定类型更新 CHANGELOG
51 + # 跳过: docs(changelog) 类型的提交,避免循环
52 + if echo "$FIRST_LINE" | grep -qE "^docs\(changelog\):"; then
53 + # 跳过
54 + :
55 + elif [ "$COMMIT_TYPE" = "feat" ] || [ "$COMMIT_TYPE" = "fix" ] || [ "$COMMIT_TYPE" = "refactor" ] || [ "$COMMIT_TYPE" = "perf" ]; then
56 + echo ""
57 + echo "📝 ${BLUE}更新 CHANGELOG...${NC}"
58 +
59 + # 调用 CHANGELOG 更新脚本
60 + bash scripts/changelog/update-changelog-prepare.sh "$COMMIT_MSG_FILE"
61 + fi
62 + fi
63 +fi
This diff is collapsed. Click to expand it.
1 +#!/bin/bash
2 +
3 +# ============================================
4 +# CHANGELOG 自动更新脚本(Prepare-commit-msg 版本)
5 +# ============================================
6 +#
7 +# 功能:在 prepare-commit-msg 阶段更新 CHANGELOG.md,加入暂存区
8 +# 配合 post-commit 的 amend --no-verify 完成流程
9 +#
10 +# 作者:Claude Code
11 +# 日期:2026-02-28
12 +# ============================================
13 +
14 +set -e
15 +
16 +# 颜色定义
17 +RED='\033[0;31m'
18 +GREEN='\033[0;32m'
19 +YELLOW='\033[1;33m'
20 +BLUE='\033[0;34m'
21 +NC='\033[0m' # No Color
22 +
23 +# 参数
24 +COMMIT_MSG_FILE=$1
25 +CHANGELOG_FILE="CHANGELOG.md"
26 +
27 +# 检查文件是否存在
28 +if [ ! -f "$CHANGELOG_FILE" ]; then
29 + echo " ${YELLOW}⚠️ CHANGELOG.md 不存在,跳过自动更新${NC}"
30 + exit 0
31 +fi
32 +
33 +# 读取 commit message
34 +COMMIT_MSG=$(cat "$COMMIT_MSG_FILE")
35 +
36 +# 解析 commit message
37 +# 格式: type(scope): subject
38 +if ! echo "$COMMIT_MSG" | grep -qE "^([a-z]+)\(([a-z-]+)\): .{1,50}"; then
39 + # 格式不匹配,跳过
40 + exit 0
41 +fi
42 +
43 +# 提取信息
44 +COMMIT_TYPE=$(echo "$COMMIT_MSG" | head -n 1 | sed -E 's/^([a-z]+)\(.*/\1/')
45 +COMMIT_SCOPE=$(echo "$COMMIT_MSG" | head -n 1 | sed -E 's/^[a-z]+\(([a-z-]+)\).*/\1/')
46 +COMMIT_SUBJECT=$(echo "$COMMIT_MSG" | head -n 1 | sed -E 's/^[a-z]+\([a-z-]+\): (.*)$/\1/')
47 +
48 +# 类型映射到中文
49 +case "$COMMIT_TYPE" in
50 + feat)
51 + CHANGE_TYPE="新增"
52 + ;;
53 + fix)
54 + CHANGE_TYPE="修复"
55 + ;;
56 + docs)
57 + CHANGE_TYPE="文档"
58 + ;;
59 + style)
60 + CHANGE_TYPE="样式"
61 + ;;
62 + refactor)
63 + CHANGE_TYPE="优化"
64 + ;;
65 + perf)
66 + CHANGE_TYPE="性能"
67 + ;;
68 + test)
69 + CHANGE_TYPE="测试"
70 + ;;
71 + chore)
72 + CHANGE_TYPE="配置"
73 + ;;
74 + revert)
75 + CHANGE_TYPE="回滚"
76 + ;;
77 + *)
78 + CHANGE_TYPE="其他"
79 + ;;
80 +esac
81 +
82 +# 获取当前日期和时间
83 +TODAY=$(date +%Y-%m-%d)
84 +NOW_TIME=$(date +%H:%M:%S)
85 +
86 +# 获取暂存的变更文件(使用 git diff --cached)
87 +CHANGED_FILES=$(git diff --cached --name-only | tr '\n' '\n' | sed 's/^/- \`/;s/$/`/' | sed '$d')
88 +if [ -z "$CHANGED_FILES" ]; then
89 + CHANGED_FILES="- \`\`"
90 +fi
91 +
92 +# 生成 CHANGELOG 条目
93 +CHANGELOG_ENTRY="### $NOW_TIME - $COMMIT_TYPE($COMMIT_SCOPE): $COMMIT_SUBJECT
94 +
95 +**影响文件**:
96 +$CHANGED_FILES
97 +
98 +**变更摘要**:
99 +- $COMMIT_SUBJECT
100 +
101 +---
102 +
103 +"
104 +
105 +# 检查今天是否已有条目
106 +if grep -q "^## $TODAY" "$CHANGELOG_FILE"; then
107 + # 今天已有条目,找到日期行号,在日期后追加
108 + DATE_LINE=$(grep -n "^## $TODAY" "$CHANGELOG_FILE" | head -1 | cut -d: -f1)
109 +
110 + # 创建临时文件
111 + TEMP_FILE=$(mktemp)
112 +
113 + # 读取日期行之前的内容
114 + head -n $DATE_LINE "$CHANGELOG_FILE" > "$TEMP_FILE"
115 +
116 + # 在日期后追加新条目
117 + echo "$CHANGELOG_ENTRY" >> "$TEMP_FILE"
118 +
119 + # 追加日期行之后的内容(从日期行+1开始)
120 + tail -n +$((DATE_LINE + 1)) "$CHANGELOG_FILE" >> "$TEMP_FILE"
121 +
122 + # 替换原文件
123 + mv "$TEMP_FILE" "$CHANGELOG_FILE"
124 +else
125 + # 今天没有条目,创建新的日期部分
126 + TEMP_FILE=$(mktemp)
127 +
128 + # 新建日期标题和条目
129 + echo "## $TODAY" > "$TEMP_FILE"
130 + echo "" >> "$TEMP_FILE"
131 + echo "$CHANGELOG_ENTRY" >> "$TEMP_FILE"
132 + echo "" >> "$TEMP_FILE"
133 +
134 + # 追加原文件内容
135 + cat "$CHANGELOG_FILE" >> "$TEMP_FILE"
136 +
137 + # 替换原文件
138 + mv "$TEMP_FILE" "$CHANGELOG_FILE"
139 +fi
140 +
141 +# 将 CHANGELOG.md 加入暂存区
142 +# 重要:这里只是加入暂存区,实际包含在提交中由 post-commit 的 amend 完成
143 +git add "$CHANGELOG_FILE"
144 +
145 +echo " ${GREEN}✅ CHANGELOG.md 已自动更新${NC}"
146 +echo " ${BLUE} 类型: $CHANGE_TYPE${NC}"
147 +echo " ${BLUE} 范围: $COMMIT_SCOPE${NC}"
148 +echo " ${BLUE} 描述: $COMMIT_SUBJECT${NC}"