hookehuyr

refactor(husky): 将 CHANGELOG 更新移至 pre-commit 阶段

- 修改 pre-commit hook,在提交前更新 CHANGELOG
- 创建 update-changelog-precommit.sh 脚本
- 修改 post-commit hook,移除 CHANGELOG 更新逻辑
- 更新文档说明新的工作机制
- 解决 post-commit 无限循环问题

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
...@@ -61,60 +61,97 @@ docs(readme): 更新项目说明文档 ...@@ -61,60 +61,97 @@ docs(readme): 更新项目说明文档
61 61
62 --- 62 ---
63 63
64 -### 2. post-commit - 提交后自动化 64 +### 2. pre-commit - 提交前检查和 CHANGELOG 更新
65 +
66 +**文件**`.husky/pre-commit`
67 +
68 +**功能**
69 +1. ESLint 代码格式检查
70 +2. 检查调试代码(console.log、debugger)
71 +3. 改动规模检查(提示代码审查)
72 +4. **自动更新 CHANGELOG.md**(在提交前,包含在当前提交中)
73 +
74 +**CHANGELOG 更新规则**
75 +- 只对以下类型更新:`feat``fix``refactor``perf`
76 +- 跳过:`docs(changelog)` 类型的提交(避免循环)
77 +- CHANGELOG 变更会**包含在当前提交中**
78 +
79 +---
80 +
81 +### 3. post-commit - 提交后处理
65 82
66 **文件**`.husky/post-commit` 83 **文件**`.husky/post-commit`
67 84
68 **功能** 85 **功能**
69 1. 显示提交成功信息和改动统计 86 1. 显示提交成功信息和改动统计
70 -2. **自动更新 CHANGELOG.md**(通过 `scripts/changelog/update-changelog.sh` 87 +2. **补充 CHANGELOG 中的 commit hash**(使用 amend)
71 -3. 创建补充提交(如果 CHANGELOG 有变更)
72 88
73 **工作流程** 89 **工作流程**
74 ``` 90 ```
75 git commit 91 git commit
76 92
77 -[pre-commit hook] 代码质量检查 93 +[pre-commit hook] 代码检查 + 更新 CHANGELOG
78 94
79 [commit-msg hook] 验证 commit message 格式 95 [commit-msg hook] 验证 commit message 格式
80 96
97 +创建提交(包含 CHANGELOG 变更)
98 +
81 [post-commit hook] ✅ 执行 99 [post-commit hook] ✅ 执行
82 ├─ 显示提交信息 100 ├─ 显示提交信息
83 - ├─ 自动更新 CHANGELOG 101 + └─ 补充 CHANGELOG 中的 commit hash(amend)
84 - └─ 如有变更,创建补充提交
85 ``` 102 ```
86 103
87 -**CHANGELOG 自动更新流程** 104 +**CHANGELOG 更新流程**
88 -1. 解析最新的 commit message 105 +1. **Pre-commit 阶段**
89 -2. 生成对应的 CHANGELOG 条目 106 + - 检查 commit message 类型
90 -3. 插入到 `docs/CHANGELOG.md` 开头 107 + - 如果符合条件,调用 `scripts/changelog/update-changelog-precommit.sh`
91 -4. 如果 CHANGELOG 有变更: 108 + - 生成 CHANGELOG 条目(commit hash 暂时为 "pending")
92 - - 暂存 CHANGELOG 文件 109 + - 将 CHANGELOG 加入暂存区
93 - - 创建补充提交:`docs(changelog): 更新 CHANGELOG - <原始提交主题>` 110 +
94 - - 补充提交使用 `--no-verify` 跳过 hooks,避免循环 111 +2. **Post-commit 阶段**
112 + - 检查 CHANGELOG 中是否有 "pending" hash
113 + - 如果有,替换为真实的 commit hash
114 + - 使用 `git commit --amend --no-edit` 更新提交
115 +
116 +**优势**
117 +- ✅ CHANGELOG 和功能变更在同一个提交中
118 +- ✅ 不会产生额外的提交
119 +- ✅ 不会触发无限循环
95 120
96 **输出示例** 121 **输出示例**
97 ``` 122 ```
98 -✅ 提交成功! 123 +🔍 开始 Pre-commit 检查...
124 +
125 +📋 步骤 1/3: 代码格式检查
126 + ✅ ESLint 检查通过
127 +
128 +📋 步骤 2/3: 检查调试代码
129 + ✅ 调试代码检查通过
130 +
131 +📋 步骤 3/3: 改动规模检查
132 + ✅ 改动规模检查通过
133 +
134 +📋 步骤 4/4: 更新 CHANGELOG
135 + ✅ CHANGELOG.md 已自动更新并加入暂存区
136 + 类型: 新增
137 + 范围: search
138 + 描述: 搜索 Tab 显示结果数量
139 +
140 +✅ 所有检查通过!
141 +🚀 开始提交...
99 142
100 📝 提交信息: 143 📝 提交信息:
101 - Hash: a6618ea 144 + Hash: f059121
102 Author: huyirui 145 Author: huyirui
103 - Date: 2026-02-22 15:30:45 146 + Date: 2026-02-28 20:07:50
104 - Msg: fix(husky): 修复 CHANGELOG 自动更新功能 147 + Msg: refactor(search): 搜索 Tab 显示结果数量
105 148
106 📊 改动统计: 149 📊 改动统计:
107 - 文件数: 3 150 + 文件数: 2
108 - 新增行数: +45 151 + 新增行数: +37
109 - 删除行数: -12 152 + 删除行数: -5
110 153
111 -📝 更新 CHANGELOG.md... 154 + ✅ CHANGELOG commit hash 已更新
112 - ✅ CHANGELOG.md 已自动更新
113 - 类型: 修复
114 - 范围: husky
115 - 描述: 修复 CHANGELOG 自动更新功能
116 -
117 - ✅ CHANGELOG 补充提交已创建
118 ``` 155 ```
119 156
120 --- 157 ---
...@@ -177,14 +214,24 @@ feat(module): 添加了新功能 ...@@ -177,14 +214,24 @@ feat(module): 添加了新功能
177 ### 问题:CHANGELOG 未更新 214 ### 问题:CHANGELOG 未更新
178 215
179 **可能原因** 216 **可能原因**
180 -1. Commit message 格式不正确 217 +1. Commit message 类型不符合要求(只有 feat/fix/refactor/perf 会更新)
181 -2. `scripts/changelog/update-changelog.sh` 脚本路径错误 218 +2. `scripts/changelog/update-changelog-precommit.sh` 脚本路径错误
182 -3. `docs/CHANGELOG.md` 文件不存在 219 +3. `CHANGELOG.md` 文件不存在
220 +4. Commit message 格式不正确
183 221
184 **解决** 222 **解决**
185 -1. 检查 commit message 格式 223 +1. 检查 commit message 类型是否为 `feat``fix``refactor``perf`
186 -2. 运行 `pnpm changelog:check` 检查漏记 224 +2. 确认脚本存在且可执行:`chmod +x scripts/changelog/update-changelog-precommit.sh`
187 -3. 手动运行脚本调试 225 +3. 运行 `pnpm lint` 确保没有语法错误
226 +
227 +### 问题:CHANGELOG 更新导致无限循环
228 +
229 +**已解决**:新版本使用 pre-commit 阶段更新,包含在当前提交中,不会产生额外提交。
230 +
231 +**如果仍然遇到循环**
232 +1. 检查 post-commit hook 是否正确
233 +2. 确认跳过了 `docs(changelog)` 类型的提交
234 +3. 检查 pre-commit hook 中的类型判断逻辑
188 235
189 --- 236 ---
190 237
......
...@@ -5,10 +5,10 @@ ...@@ -5,10 +5,10 @@
5 # 5 #
6 # 功能: 6 # 功能:
7 # 1. 显示提交成功信息 7 # 1. 显示提交成功信息
8 -# 2. 自动更新 CHANGELOG.md(通过补充提交) 8 +# 2. 补充 CHANGELOG 中的 commit hash
9 # 9 #
10 # 作者:Claude Code 10 # 作者:Claude Code
11 -# 日期:2026-02-22 11 +# 日期:2026-02-28
12 # ============================================ 12 # ============================================
13 13
14 # 颜色定义 14 # 颜色定义
...@@ -49,53 +49,35 @@ echo " 删除行数: -$LINES_DELETED" ...@@ -49,53 +49,35 @@ echo " 删除行数: -$LINES_DELETED"
49 echo "" 49 echo ""
50 50
51 # ============================================ 51 # ============================================
52 -# 自动更新 CHANGELOG.md 52 +# 补充 CHANGELOG 中的 commit hash
53 # ============================================ 53 # ============================================
54 CHANGELOG_FILE="CHANGELOG.md" 54 CHANGELOG_FILE="CHANGELOG.md"
55 -SCRIPT_PATH="scripts/changelog/update-changelog.sh"
56 55
57 -# 检查文件和脚本是否存在 56 +if [ -f "$CHANGELOG_FILE" ]; then
58 -if [ ! -f "$CHANGELOG_FILE" ]; then 57 + # 检查 CHANGELOG 中是否有 "pending" hash 需要替换
59 - echo " ${YELLOW}⚠️ CHANGELOG.md 不存在,跳过自动更新${NC}" 58 + if grep -q "\`pending\`" "$CHANGELOG_FILE"; then
60 -elif [ ! -f "$SCRIPT_PATH" ]; then 59 + # 获取当前日期时间戳
61 - echo " ${YELLOW}⚠️ CHANGELOG 更新脚本不存在: $SCRIPT_PATH${NC}" 60 + NOW_TIME=$(date +%H:%M:%S)
62 -else 61 + TODAY=$(date +%Y-%m-%d)
63 - echo "📝 ${BLUE}更新 CHANGELOG.md...${NC}"
64 -
65 - # 调用 CHANGELOG 更新脚本(传入 commit message 文件)
66 - # 创建临时文件保存 commit message
67 - TEMP_MSG_FILE=$(mktemp)
68 - echo "$COMMIT_MSG" > "$TEMP_MSG_FILE"
69 -
70 - # 执行更新脚本
71 - bash "$SCRIPT_PATH" "$TEMP_MSG_FILE"
72 - SCRIPT_EXIT_CODE=$?
73 62
74 - # 清理临时文件 63 + # 解析 commit message
75 - rm -f "$TEMP_MSG_FILE" 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/')
76 67
77 - if [ $SCRIPT_EXIT_CODE -eq 0 ]; then 68 + # 替换 pending hash 为真实的 commit hash
78 - # 检查 CHANGELOG 是否有变更 69 + # 使用 sed 进行替换
79 - if git diff --quiet "$CHANGELOG_FILE" 2>/dev/null; then 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 || \
80 - echo " ${GREEN}✅ CHANGELOG 无需更新(可能已存在相同条目)${NC}" 71 + sed -i.tmp "s/\`pending\` - $COMMIT_TYPE($COMMIT_SCOPE): $COMMIT_SUBJECT/\`$COMMIT_HASH\` - $COMMIT_TYPE($COMMIT_SCOPE): $COMMIT_SUBJECT/" "$CHANGELOG_FILE"
81 - else
82 - # CHANGELOG 有变更,创建补充提交
83 - echo " ${BLUE}创建 CHANGELOG 补充提交...${NC}"
84 72
85 - # 获取原始提交的主题(第一行) 73 + # 清理临时文件
86 - COMMIT_SUBJECT=$(echo "$COMMIT_MSG" | head -n 1) 74 + rm -f "${CHANGELOG_FILE}.tmp"
87 75
88 - # 暂存 CHANGELOG 更改 76 + # 如果 CHANGELOG 有变更, amend 到当前提交
77 + if ! git diff --quiet "$CHANGELOG_FILE" 2>/dev/null; then
89 git add "$CHANGELOG_FILE" 78 git add "$CHANGELOG_FILE"
90 - 79 + git commit --amend --no-edit --no-verify >/dev/null 2>&1
91 - # 创建补充提交(跳过 hooks 避免循环) 80 + echo " ${GREEN}✅ CHANGELOG commit hash 已更新${NC}"
92 - git commit --no-verify -m "docs(changelog): 更新 CHANGELOG - $COMMIT_SUBJECT" 2>/dev/null
93 -
94 - if [ $? -eq 0 ]; then
95 - echo " ${GREEN}✅ CHANGELOG 补充提交已创建${NC}"
96 - else
97 - echo " ${YELLOW}⚠️ CHANGELOG 补充提交失败${NC}"
98 - fi
99 fi 81 fi
100 fi 82 fi
101 fi 83 fi
......
...@@ -120,10 +120,37 @@ fi ...@@ -120,10 +120,37 @@ 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 +# ============================================
123 # 所有检查通过 151 # 所有检查通过
124 # ============================================ 152 # ============================================
125 echo "" 153 echo ""
126 echo "✅ ${GREEN}所有检查通过!${NC}" 154 echo "✅ ${GREEN}所有检查通过!${NC}"
127 echo "🚀 ${BLUE}开始提交...${NC}" 155 echo "🚀 ${BLUE}开始提交...${NC}"
128 -echo "📝 ${BLUE}CHANGELOG.md 将在 commit-msg 阶段自动更新${NC}"
129 echo "" 156 echo ""
......
1 +#!/bin/bash
2 +
3 +# ============================================
4 +# CHANGELOG 自动更新脚本(Pre-commit 版本)
5 +# ============================================
6 +#
7 +# 功能:在提交前更新 CHANGELOG.md,包含在当前提交中
8 +# 使用:在 pre-commit hook 中调用
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 + echo " ${YELLOW}⚠️ Commit message 格式不匹配,跳过自动更新${NC}"
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 +# 在 pre-commit 阶段还没有 commit hash,使用占位符
93 +COMMIT_HASH="pending"
94 +
95 +# 生成 CHANGELOG 条目
96 +CHANGELOG_ENTRY="### $NOW_TIME - $COMMIT_TYPE($COMMIT_SCOPE): $COMMIT_SUBJECT
97 +
98 +**影响文件**:
99 +$CHANGED_FILES
100 +
101 +**变更摘要**:
102 +- $COMMIT_SUBJECT
103 +
104 +**相关提交**:
105 +- \`$COMMIT_HASH\` - $COMMIT_TYPE($COMMIT_SCOPE): $COMMIT_SUBJECT
106 +
107 +---
108 +
109 +"
110 +
111 +# 检查今天是否已有条目
112 +if grep -q "^## $TODAY" "$CHANGELOG_FILE"; then
113 + # 今天已有条目,找到日期行号,在日期后追加
114 + DATE_LINE=$(grep -n "^## $TODAY" "$CHANGELOG_FILE" | head -1 | cut -d: -f1)
115 +
116 + # 创建临时文件
117 + TEMP_FILE=$(mktemp)
118 +
119 + # 读取日期行之前的内容
120 + head -n $DATE_LINE "$CHANGELOG_FILE" > "$TEMP_FILE"
121 +
122 + # 在日期后追加新条目
123 + echo "$CHANGELOG_ENTRY" >> "$TEMP_FILE"
124 +
125 + # 追加日期行之后的内容(从日期行+1开始)
126 + tail -n +$((DATE_LINE + 1)) "$CHANGELOG_FILE" >> "$TEMP_FILE"
127 +
128 + # 替换原文件
129 + mv "$TEMP_FILE" "$CHANGELOG_FILE"
130 +else
131 + # 今天没有条目,创建新的日期部分
132 + TEMP_FILE=$(mktemp)
133 +
134 + # 新建日期标题和条目
135 + echo "## $TODAY" > "$TEMP_FILE"
136 + echo "" >> "$TEMP_FILE"
137 + echo "$CHANGELOG_ENTRY" >> "$TEMP_FILE"
138 + echo "" >> "$TEMP_FILE"
139 +
140 + # 追加原文件内容
141 + cat "$CHANGELOG_FILE" >> "$TEMP_FILE"
142 +
143 + # 替换原文件
144 + mv "$TEMP_FILE" "$CHANGELOG_FILE"
145 +fi
146 +
147 +# 将 CHANGELOG.md 加入暂存区(包含在当前提交中)
148 +git add "$CHANGELOG_FILE"
149 +
150 +echo " ${GREEN}✅ CHANGELOG.md 已自动更新并加入暂存区${NC}"
151 +echo " ${BLUE} 类型: $CHANGE_TYPE${NC}"
152 +echo " ${BLUE} 范围: $COMMIT_SCOPE${NC}"
153 +echo " ${BLUE} 描述: $COMMIT_SUBJECT${NC}"