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): 更新项目说明文档
---
### 2. post-commit - 提交后自动化
### 2. pre-commit - 提交前检查和 CHANGELOG 更新
**文件**`.husky/pre-commit`
**功能**
1. ESLint 代码格式检查
2. 检查调试代码(console.log、debugger)
3. 改动规模检查(提示代码审查)
4. **自动更新 CHANGELOG.md**(在提交前,包含在当前提交中)
**CHANGELOG 更新规则**
- 只对以下类型更新:`feat``fix``refactor``perf`
- 跳过:`docs(changelog)` 类型的提交(避免循环)
- CHANGELOG 变更会**包含在当前提交中**
---
### 3. post-commit - 提交后处理
**文件**`.husky/post-commit`
**功能**
1. 显示提交成功信息和改动统计
2. **自动更新 CHANGELOG.md**(通过 `scripts/changelog/update-changelog.sh`
3. 创建补充提交(如果 CHANGELOG 有变更)
2. **补充 CHANGELOG 中的 commit hash**(使用 amend)
**工作流程**
```
git commit
[pre-commit hook] 代码质量检查
[pre-commit hook] 代码检查 + 更新 CHANGELOG
[commit-msg hook] 验证 commit message 格式
创建提交(包含 CHANGELOG 变更)
[post-commit hook] ✅ 执行
├─ 显示提交信息
├─ 自动更新 CHANGELOG
└─ 如有变更,创建补充提交
└─ 补充 CHANGELOG 中的 commit hash(amend)
```
**CHANGELOG 自动更新流程**
1. 解析最新的 commit message
2. 生成对应的 CHANGELOG 条目
3. 插入到 `docs/CHANGELOG.md` 开头
4. 如果 CHANGELOG 有变更:
- 暂存 CHANGELOG 文件
- 创建补充提交:`docs(changelog): 更新 CHANGELOG - <原始提交主题>`
- 补充提交使用 `--no-verify` 跳过 hooks,避免循环
**CHANGELOG 更新流程**
1. **Pre-commit 阶段**
- 检查 commit message 类型
- 如果符合条件,调用 `scripts/changelog/update-changelog-precommit.sh`
- 生成 CHANGELOG 条目(commit hash 暂时为 "pending")
- 将 CHANGELOG 加入暂存区
2. **Post-commit 阶段**
- 检查 CHANGELOG 中是否有 "pending" hash
- 如果有,替换为真实的 commit hash
- 使用 `git commit --amend --no-edit` 更新提交
**优势**
- ✅ CHANGELOG 和功能变更在同一个提交中
- ✅ 不会产生额外的提交
- ✅ 不会触发无限循环
**输出示例**
```
✅ 提交成功!
🔍 开始 Pre-commit 检查...
📋 步骤 1/3: 代码格式检查
✅ ESLint 检查通过
📋 步骤 2/3: 检查调试代码
✅ 调试代码检查通过
📋 步骤 3/3: 改动规模检查
✅ 改动规模检查通过
📋 步骤 4/4: 更新 CHANGELOG
✅ CHANGELOG.md 已自动更新并加入暂存区
类型: 新增
范围: search
描述: 搜索 Tab 显示结果数量
✅ 所有检查通过!
🚀 开始提交...
📝 提交信息:
Hash: a6618ea
Hash: f059121
Author: huyirui
Date: 2026-02-22 15:30:45
Msg: fix(husky): 修复 CHANGELOG 自动更新功能
Date: 2026-02-28 20:07:50
Msg: refactor(search): 搜索 Tab 显示结果数量
📊 改动统计:
文件数: 3
新增行数: +45
删除行数: -12
文件数: 2
新增行数: +37
删除行数: -5
📝 更新 CHANGELOG.md...
✅ CHANGELOG.md 已自动更新
类型: 修复
范围: husky
描述: 修复 CHANGELOG 自动更新功能
✅ CHANGELOG 补充提交已创建
✅ CHANGELOG commit hash 已更新
```
---
......@@ -177,14 +214,24 @@ feat(module): 添加了新功能
### 问题:CHANGELOG 未更新
**可能原因**
1. Commit message 格式不正确
2. `scripts/changelog/update-changelog.sh` 脚本路径错误
3. `docs/CHANGELOG.md` 文件不存在
1. Commit message 类型不符合要求(只有 feat/fix/refactor/perf 会更新)
2. `scripts/changelog/update-changelog-precommit.sh` 脚本路径错误
3. `CHANGELOG.md` 文件不存在
4. Commit message 格式不正确
**解决**
1. 检查 commit message 格式
2. 运行 `pnpm changelog:check` 检查漏记
3. 手动运行脚本调试
1. 检查 commit message 类型是否为 `feat``fix``refactor``perf`
2. 确认脚本存在且可执行:`chmod +x scripts/changelog/update-changelog-precommit.sh`
3. 运行 `pnpm lint` 确保没有语法错误
### 问题:CHANGELOG 更新导致无限循环
**已解决**:新版本使用 pre-commit 阶段更新,包含在当前提交中,不会产生额外提交。
**如果仍然遇到循环**
1. 检查 post-commit hook 是否正确
2. 确认跳过了 `docs(changelog)` 类型的提交
3. 检查 pre-commit hook 中的类型判断逻辑
---
......
......@@ -5,10 +5,10 @@
#
# 功能:
# 1. 显示提交成功信息
# 2. 自动更新 CHANGELOG.md(通过补充提交)
# 2. 补充 CHANGELOG 中的 commit hash
#
# 作者:Claude Code
# 日期:2026-02-22
# 日期:2026-02-28
# ============================================
# 颜色定义
......@@ -49,53 +49,35 @@ echo " 删除行数: -$LINES_DELETED"
echo ""
# ============================================
# 自动更新 CHANGELOG.md
# 补充 CHANGELOG 中的 commit hash
# ============================================
CHANGELOG_FILE="CHANGELOG.md"
SCRIPT_PATH="scripts/changelog/update-changelog.sh"
# 检查文件和脚本是否存在
if [ ! -f "$CHANGELOG_FILE" ]; then
echo " ${YELLOW}⚠️ CHANGELOG.md 不存在,跳过自动更新${NC}"
elif [ ! -f "$SCRIPT_PATH" ]; then
echo " ${YELLOW}⚠️ CHANGELOG 更新脚本不存在: $SCRIPT_PATH${NC}"
else
echo "📝 ${BLUE}更新 CHANGELOG.md...${NC}"
if [ -f "$CHANGELOG_FILE" ]; then
# 检查 CHANGELOG 中是否有 "pending" hash 需要替换
if grep -q "\`pending\`" "$CHANGELOG_FILE"; then
# 获取当前日期时间戳
NOW_TIME=$(date +%H:%M:%S)
TODAY=$(date +%Y-%m-%d)
# 调用 CHANGELOG 更新脚本(传入 commit message 文件)
# 创建临时文件保存 commit message
TEMP_MSG_FILE=$(mktemp)
echo "$COMMIT_MSG" > "$TEMP_MSG_FILE"
# 解析 commit message
COMMIT_TYPE=$(echo "$COMMIT_MSG" | head -n 1 | sed -E 's/^([a-z]+)\(.*/\1/')
COMMIT_SCOPE=$(echo "$COMMIT_MSG" | head -n 1 | sed -E 's/^[a-z]+\(([a-z-]+)\).*/\1/')
COMMIT_SUBJECT=$(echo "$COMMIT_MSG" | head -n 1 | sed -E 's/^[a-z]+\([a-z-]+\): (.*)$/\1/')
# 执行更新脚本
bash "$SCRIPT_PATH" "$TEMP_MSG_FILE"
SCRIPT_EXIT_CODE=$?
# 替换 pending hash 为真实的 commit hash
# 使用 sed 进行替换
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 || \
sed -i.tmp "s/\`pending\` - $COMMIT_TYPE($COMMIT_SCOPE): $COMMIT_SUBJECT/\`$COMMIT_HASH\` - $COMMIT_TYPE($COMMIT_SCOPE): $COMMIT_SUBJECT/" "$CHANGELOG_FILE"
# 清理临时文件
rm -f "$TEMP_MSG_FILE"
if [ $SCRIPT_EXIT_CODE -eq 0 ]; then
# 检查 CHANGELOG 是否有变更
if git diff --quiet "$CHANGELOG_FILE" 2>/dev/null; then
echo " ${GREEN}✅ CHANGELOG 无需更新(可能已存在相同条目)${NC}"
else
# CHANGELOG 有变更,创建补充提交
echo " ${BLUE}创建 CHANGELOG 补充提交...${NC}"
# 获取原始提交的主题(第一行)
COMMIT_SUBJECT=$(echo "$COMMIT_MSG" | head -n 1)
rm -f "${CHANGELOG_FILE}.tmp"
# 暂存 CHANGELOG 更改
# 如果 CHANGELOG 有变更, amend 到当前提交
if ! git diff --quiet "$CHANGELOG_FILE" 2>/dev/null; then
git add "$CHANGELOG_FILE"
# 创建补充提交(跳过 hooks 避免循环)
git commit --no-verify -m "docs(changelog): 更新 CHANGELOG - $COMMIT_SUBJECT" 2>/dev/null
if [ $? -eq 0 ]; then
echo " ${GREEN}✅ CHANGELOG 补充提交已创建${NC}"
else
echo " ${YELLOW}⚠️ CHANGELOG 补充提交失败${NC}"
fi
git commit --amend --no-edit --no-verify >/dev/null 2>&1
echo " ${GREEN}✅ CHANGELOG commit hash 已更新${NC}"
fi
fi
fi
......
......@@ -120,10 +120,37 @@ fi
echo " ${GREEN}✅ 改动规模检查通过${NC}"
# ============================================
# 4. 自动更新 CHANGELOG.md(在提交前)
# ============================================
echo ""
echo "📋 ${BLUE}步骤 4/4: 更新 CHANGELOG${NC}"
# 获取暂存的 commit message
COMMIT_MSG_FILE=".git/COMMIT_EDITMSG"
if [ -f "$COMMIT_MSG_FILE" ]; then
COMMIT_MSG=$(cat "$COMMIT_MSG_FILE")
# 解析 commit type
COMMIT_TYPE=$(echo "$COMMIT_MSG" | head -n 1 | sed -E 's/^([a-z]+)\(.*/\1/')
# 只对特定类型更新 CHANGELOG
# 跳过: docs(changelog) 类型的提交,避免循环
if echo "$COMMIT_MSG" | head -n 1 | grep -qE "^docs\(changelog\):"; then
echo " ⏭️ 跳过 CHANGELOG 更新(docs(changelog) 类型提交)"
elif [ "$COMMIT_TYPE" = "feat" ] || [ "$COMMIT_TYPE" = "fix" ] || [ "$COMMIT_TYPE" = "refactor" ] || [ "$COMMIT_TYPE" = "perf" ]; then
# 调用 CHANGELOG 更新脚本
bash scripts/changelog/update-changelog-precommit.sh "$COMMIT_MSG_FILE"
else
echo " ⏭️ 跳过 CHANGELOG 更新(类型: $COMMIT_TYPE)"
fi
else
echo " ⚠️ 无法读取 commit message,跳过 CHANGELOG 更新"
fi
# ============================================
# 所有检查通过
# ============================================
echo ""
echo "✅ ${GREEN}所有检查通过!${NC}"
echo "🚀 ${BLUE}开始提交...${NC}"
echo "📝 ${BLUE}CHANGELOG.md 将在 commit-msg 阶段自动更新${NC}"
echo ""
......
#!/bin/bash
# ============================================
# CHANGELOG 自动更新脚本(Pre-commit 版本)
# ============================================
#
# 功能:在提交前更新 CHANGELOG.md,包含在当前提交中
# 使用:在 pre-commit hook 中调用
#
# 作者:Claude Code
# 日期:2026-02-28
# ============================================
set -e
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# 参数
COMMIT_MSG_FILE=$1
CHANGELOG_FILE="CHANGELOG.md"
# 检查文件是否存在
if [ ! -f "$CHANGELOG_FILE" ]; then
echo " ${YELLOW}⚠️ CHANGELOG.md 不存在,跳过自动更新${NC}"
exit 0
fi
# 读取 commit message
COMMIT_MSG=$(cat "$COMMIT_MSG_FILE")
# 解析 commit message
# 格式: type(scope): subject
if ! echo "$COMMIT_MSG" | grep -qE "^([a-z]+)\(([a-z-]+)\): .{1,50}"; then
echo " ${YELLOW}⚠️ Commit message 格式不匹配,跳过自动更新${NC}"
exit 0
fi
# 提取信息
COMMIT_TYPE=$(echo "$COMMIT_MSG" | head -n 1 | sed -E 's/^([a-z]+)\(.*/\1/')
COMMIT_SCOPE=$(echo "$COMMIT_MSG" | head -n 1 | sed -E 's/^[a-z]+\(([a-z-]+)\).*/\1/')
COMMIT_SUBJECT=$(echo "$COMMIT_MSG" | head -n 1 | sed -E 's/^[a-z]+\([a-z-]+\): (.*)$/\1/')
# 类型映射到中文
case "$COMMIT_TYPE" in
feat)
CHANGE_TYPE="新增"
;;
fix)
CHANGE_TYPE="修复"
;;
docs)
CHANGE_TYPE="文档"
;;
style)
CHANGE_TYPE="样式"
;;
refactor)
CHANGE_TYPE="优化"
;;
perf)
CHANGE_TYPE="性能"
;;
test)
CHANGE_TYPE="测试"
;;
chore)
CHANGE_TYPE="配置"
;;
revert)
CHANGE_TYPE="回滚"
;;
*)
CHANGE_TYPE="其他"
;;
esac
# 获取当前日期和时间
TODAY=$(date +%Y-%m-%d)
NOW_TIME=$(date +%H:%M:%S)
# 获取暂存的变更文件(使用 git diff --cached)
CHANGED_FILES=$(git diff --cached --name-only | tr '\n' '\n' | sed 's/^/- \`/;s/$/`/' | sed '$d')
if [ -z "$CHANGED_FILES" ]; then
CHANGED_FILES="- \`\`"
fi
# 在 pre-commit 阶段还没有 commit hash,使用占位符
COMMIT_HASH="pending"
# 生成 CHANGELOG 条目
CHANGELOG_ENTRY="### $NOW_TIME - $COMMIT_TYPE($COMMIT_SCOPE): $COMMIT_SUBJECT
**影响文件**:
$CHANGED_FILES
**变更摘要**:
- $COMMIT_SUBJECT
**相关提交**:
- \`$COMMIT_HASH\` - $COMMIT_TYPE($COMMIT_SCOPE): $COMMIT_SUBJECT
---
"
# 检查今天是否已有条目
if grep -q "^## $TODAY" "$CHANGELOG_FILE"; then
# 今天已有条目,找到日期行号,在日期后追加
DATE_LINE=$(grep -n "^## $TODAY" "$CHANGELOG_FILE" | head -1 | cut -d: -f1)
# 创建临时文件
TEMP_FILE=$(mktemp)
# 读取日期行之前的内容
head -n $DATE_LINE "$CHANGELOG_FILE" > "$TEMP_FILE"
# 在日期后追加新条目
echo "$CHANGELOG_ENTRY" >> "$TEMP_FILE"
# 追加日期行之后的内容(从日期行+1开始)
tail -n +$((DATE_LINE + 1)) "$CHANGELOG_FILE" >> "$TEMP_FILE"
# 替换原文件
mv "$TEMP_FILE" "$CHANGELOG_FILE"
else
# 今天没有条目,创建新的日期部分
TEMP_FILE=$(mktemp)
# 新建日期标题和条目
echo "## $TODAY" > "$TEMP_FILE"
echo "" >> "$TEMP_FILE"
echo "$CHANGELOG_ENTRY" >> "$TEMP_FILE"
echo "" >> "$TEMP_FILE"
# 追加原文件内容
cat "$CHANGELOG_FILE" >> "$TEMP_FILE"
# 替换原文件
mv "$TEMP_FILE" "$CHANGELOG_FILE"
fi
# 将 CHANGELOG.md 加入暂存区(包含在当前提交中)
git add "$CHANGELOG_FILE"
echo " ${GREEN}✅ CHANGELOG.md 已自动更新并加入暂存区${NC}"
echo " ${BLUE} 类型: $CHANGE_TYPE${NC}"
echo " ${BLUE} 范围: $COMMIT_SCOPE${NC}"
echo " ${BLUE} 描述: $COMMIT_SUBJECT${NC}"