🎨 代码格式化
Hello from ImmortalWrt / say-hello (push) Successful in 0s Details

:fix: 修复识别`CHANGELOG`标题问题
This commit is contained in:
csh 2025-11-02 23:13:48 +08:00
parent 84e2751668
commit ec5785cc6a
2 changed files with 116 additions and 88 deletions

View File

@ -80,11 +80,11 @@ env:
# 需要忽略的提交模式(支持正则表达式)
# 这些提交不会被添加到 CHANGELOG 中
# 使用 | 分隔多个模式
#
#
# ⚠️ 重要说明:
# - 使用 ^ 表示行首匹配,$ 表示行尾匹配
# - [skip ci] 和 [ci skip] 仅匹配行尾,避免误过滤其他提交
# - 如果要完全匹配某个字符串,使用 ^...$
# - 如果要完全匹配某个字符串,使用 ^...$
IGNORE_PATTERNS: >-
^Merge |
^:memo: Auto update CHANGELOG|
@ -226,21 +226,21 @@ jobs:
# 检查仓库状态
if [ -d "$REPO_DIR" ]; then
echo "📂 目录已存在,检查 Git 仓库状态..."
if [ -d "$REPO_DIR/.git" ]; then
# 目录存在且是有效的 Git 仓库
echo "✓ 发现有效的 Git 仓库,执行增量更新..."
cd "$REPO_DIR"
# 清理工作区
git clean -fdx
git reset --hard
# 获取最新代码和标签,同时清理远程已删除的 tag
echo "📥 拉取最新代码和标签..."
git fetch --all --tags --force --prune --prune-tags
echo "✓ 已同步远程状态(包括已删除的 tag"
echo "✓ 仓库已更新"
else
# 目录存在但不是 Git 仓库(可能之前运行失败)
@ -248,20 +248,20 @@ jobs:
echo "🧹 清理损坏的目录..."
rm -rf "$REPO_DIR"
echo "✓ 已清理"
# 重新克隆
echo "📥 克隆仓库..."
mkdir -p "${{ env.WORKSPACE_DIR }}"
git clone \
https://oauth2:${{ env.ACCESS_TOKEN }}@${GITHUB_SERVER_URL#https://}/${{ github.repository }}.git \
"$REPO_DIR"
if [ $? -ne 0 ]; then
echo "❌ 克隆失败"
exit 1
fi
cd "$REPO_DIR"
echo "✓ 仓库已克隆"
fi
@ -269,11 +269,11 @@ jobs:
# 目录不存在,首次克隆
echo "📥 克隆仓库(首次)..."
mkdir -p "${{ env.WORKSPACE_DIR }}"
git clone \
https://oauth2:${{ env.ACCESS_TOKEN }}@${GITHUB_SERVER_URL#https://}/${{ github.repository }}.git \
"$REPO_DIR"
if [ $? -eq 0 ]; then
cd "$REPO_DIR"
echo "✓ 仓库已克隆"
@ -362,7 +362,7 @@ jobs:
else
CHANGELOG_VERSION="${{ env.CHANGELOG_VERSION }}"
echo "📝 检查版本: $CHANGELOG_VERSION"
if grep -q "## :bookmark: $CHANGELOG_VERSION" CHANGELOG.md; then
echo "⚠️ 版本 $CHANGELOG_VERSION 已存在于 CHANGELOG.md"
echo "version_exists=true" >> $GITHUB_OUTPUT
@ -395,23 +395,23 @@ jobs:
# 查找前一个 tag
# 排除所有属于当前 CHANGELOG 版本的 tag例如 0.0.2-rc1, 0.0.2-rc2 都属于 0.0.2
echo "🔍 查找前一个版本的 tag..."
# 获取所有 tag
ALL_TAGS=$(git tag --sort=-version:refname)
# 遍历查找第一个不属于当前 CHANGELOG 版本的 tag
PREVIOUS_TAG=""
while IFS= read -r tag; do
# 跳过空行
[ -z "$tag" ] && continue
# 对每个 tag 执行 strip 操作(去除 pre-release 后缀)
if [[ "${{ env.CHANGELOG_VERSION_MODE }}" == "strip" ]]; then
tag_stripped=$(echo "$tag" | sed -E 's/-(alpha|beta|rc|pre|preview|dev|test)[0-9]*$//')
else
tag_stripped="$tag"
fi
# 如果这个 tag 的 CHANGELOG 版本不等于当前版本,就是我们要找的
if [ "$tag_stripped" != "$CHANGELOG_VERSION" ]; then
PREVIOUS_TAG="$tag"
@ -424,13 +424,13 @@ jobs:
COMMIT_RANGE=""
else
echo "📍 Previous tag: $PREVIOUS_TAG"
# 对 previous tag 也执行 strip显示对应的 CHANGELOG 版本
if [[ "${{ env.CHANGELOG_VERSION_MODE }}" == "strip" ]]; then
PREV_CHANGELOG_VERSION=$(echo "$PREVIOUS_TAG" | sed -E 's/-(alpha|beta|rc|pre|preview|dev|test)[0-9]*$//')
echo " (对应 CHANGELOG 版本: $PREV_CHANGELOG_VERSION)"
fi
COMMIT_RANGE="${PREVIOUS_TAG}..${VERSION}"
fi
@ -477,9 +477,9 @@ jobs:
line = line.strip()
if not line or '|' not in line:
continue
commit_hash, message = line.split('|', 1)
# 检查是否应该忽略
should_ignore = False
matched_pattern = None
@ -488,7 +488,7 @@ jobs:
should_ignore = True
matched_pattern = pattern
break
if should_ignore:
skipped_commits.append((message, matched_pattern))
else:
@ -549,11 +549,11 @@ jobs:
# 找到版本区块,在其中追加新的提交
pattern = rf'(## :bookmark: {re.escape(changelog_version)}.*?\n{re.escape(section_title)}\n\n)(.*?)(\n---|\n## :bookmark: |\Z)'
match = re.search(pattern, existing_content, re.DOTALL)
if match:
existing_commits = match.group(2).strip()
new_commits = changelog_content.split(f"{section_title}\n\n")[1].split("\n---")[0].strip()
# 合并提交,去重
all_commits_text = existing_commits + "\n" + new_commits
# 简单去重(基于完整行)
@ -563,36 +563,64 @@ jobs:
if line.strip() and line not in seen:
unique_lines.append(line)
seen.add(line)
merged_commits = '\n'.join(unique_lines)
# 重新组装版本区块
updated_section = match.group(1) + merged_commits + "\n\n---\n"
new_content = existing_content[:match.start()] + updated_section + existing_content[match.end():]
else:
print("⚠️ Could not find version section, prepending new content")
new_content = existing_content.replace(
"# :memo: CHANGELOG\n\n",
f"# :memo: CHANGELOG\n\n{changelog_content}"
)
# 尝试匹配各种可能的 CHANGELOG 标题格式
header_pattern = r'^#\s*(?::[\w_]+:)?\s*CHANGELOG\s*\n'
match = re.search(header_pattern, existing_content, re.IGNORECASE | re.MULTILINE)
if match:
insert_pos = match.end()
if not existing_content[insert_pos:insert_pos+1] == '\n':
new_content = existing_content[:insert_pos] + '\n' + changelog_content + existing_content[insert_pos:]
else:
new_content = existing_content[:insert_pos] + '\n' + changelog_content + existing_content[insert_pos+1:]
else:
# 没有找到标题,在开头插入
new_content = f"# :memo: CHANGELOG\n\n{changelog_content}{existing_content}"
else:
# 插入新版本
new_content = existing_content.replace(
"# :memo: CHANGELOG\n\n",
f"# :memo: CHANGELOG\n\n{changelog_content}"
)
# 尝试匹配各种可能的 CHANGELOG 标题格式
# 支持: # CHANGELOG, # :memo: CHANGELOG, # Changelog 等
# 尝试找到 CHANGELOG 标题(不区分大小写,可选 emoji
header_pattern = r'^#\s*(?::[\w_]+:)?\s*CHANGELOG\s*\n'
match = re.search(header_pattern, existing_content, re.IGNORECASE | re.MULTILINE)
if match:
# 找到了 CHANGELOG 标题,在其后插入
insert_pos = match.end()
# 确保标题后有空行
if not existing_content[insert_pos:insert_pos+1] == '\n':
new_content = existing_content[:insert_pos] + '\n' + changelog_content + existing_content[insert_pos:]
else:
new_content = existing_content[:insert_pos] + '\n' + changelog_content + existing_content[insert_pos+1:]
else:
# 没有找到 CHANGELOG 标题,在文件开头插入标题和内容
if existing_content.strip():
# 文件有内容但没有 CHANGELOG 标题
new_content = f"# :memo: CHANGELOG\n\n{changelog_content}{existing_content}"
else:
# 文件为空
new_content = f"# :memo: CHANGELOG\n\n{changelog_content}"
# 检查内容是否真的改变
content_changed = (new_content != existing_content)
version_exists = f"## :bookmark: {changelog_version}" in existing_content
if content_changed:
with open(changelog_file, 'w', encoding='utf-8') as f:
f.write(new_content)
print(f"✅ CHANGELOG updated successfully")
print(f" Added {len(commits)} commits to version {changelog_version}")
with open('/tmp/changelog_updated.txt', 'w') as f:
f.write('true')
with open('/tmp/content_changed.txt', 'w') as f:
@ -605,7 +633,7 @@ jobs:
print(f" Version {changelog_version} already contains all {len(commits)} commits")
print(f" This usually happens when recreating a deleted tag")
print(f" Will still create Release from existing CHANGELOG content")
with open('/tmp/changelog_updated.txt', 'w') as f:
f.write('true') # 返回 true 以触发 Release 创建
with open('/tmp/content_changed.txt', 'w') as f:
@ -613,7 +641,7 @@ jobs:
else:
# 既没有新内容,版本也不存在(不应该发生)
print(f"⚠️ Unexpected state: no content change and version doesn't exist")
with open('/tmp/changelog_updated.txt', 'w') as f:
f.write('false')
with open('/tmp/content_changed.txt', 'w') as f:
@ -622,7 +650,7 @@ jobs:
UPDATED=$(cat /tmp/changelog_updated.txt)
CONTENT_CHANGED=$(cat /tmp/content_changed.txt 2>/dev/null || echo "false")
echo "changelog_updated=$UPDATED" >> $GITHUB_OUTPUT
echo "content_changed=$CONTENT_CHANGED" >> $GITHUB_OUTPUT
@ -660,10 +688,10 @@ jobs:
else
echo "📝 提交 CHANGELOG 更新..."
git commit -m "${{ env.COMMIT_MSG }}"
echo "📤 推送到远程 ${{ env.MAIN_BRANCH }} 分支..."
git push https://oauth2:${{ env.ACCESS_TOKEN }}@${GITHUB_SERVER_URL#https://}/${{ github.repository }}.git ${{ env.MAIN_BRANCH }}
if [ $? -eq 0 ]; then
echo "✅ 推送成功"
else
@ -944,7 +972,7 @@ jobs:
- CHANGELOG.md 无需更新(内容已存在)
- ✅ Release 已创建
- ✅ CHANGELOG.md 已作为附件上传
💡 **说明**: 检测到这是重建已删除的 tagCHANGELOG 中已包含所有提交内容,因此直接从现有内容创建 Release。
EOFREBUILD
fi
@ -963,7 +991,7 @@ jobs:
可能的原因:
- 在标签之间未找到有效的提交记录
- 或者版本 \`${{ env.CHANGELOG_VERSION }}\` 已包含所有相关提交(常见于重新创建已删除的 tag
💡 如果你删除了 tag 后重新创建CHANGELOG 中的内容已经存在,无需重复添加。
EOFNOCOMMIT
fi
@ -1017,7 +1045,7 @@ jobs:
echo " - Release 标题: ${{ env.RELEASE_TITLE_PROCESSED }}"
echo " - Pre-release: ${{ env.RELEASE_IS_PRERELEASE }}"
echo ""
if [ "${{ steps.changelog.outputs.content_changed }}" = "true" ]; then
echo "✅ 已完成的操作:"
echo " - CHANGELOG.md 已更新并推送到 ${{ env.MAIN_BRANCH }} 分支"
@ -1054,4 +1082,4 @@ jobs:
run: |
echo "🧹 清理临时文件..."
rm -rf /tmp/commits.txt /tmp/changelog_updated.txt /tmp/content_changed.txt /tmp/release-body.txt /tmp/payload.json /tmp/release_response.json /tmp/upload_response_*.json
echo "✅ 清理完成"
echo "✅ 清理完成"

View File

@ -142,7 +142,7 @@ jobs:
if [ ${#MISSING_TOOLS[@]} -gt 0 ]; then
echo ""
echo "📦 安装缺失的工具: ${MISSING_TOOLS[*]}"
# 🔧 智能判断是否需要 sudo
# Docker 环境通常以 root 运行,不需要 sudo
if [ "$EUID" -eq 0 ] || [ "$(id -u)" -eq 0 ]; then
@ -166,7 +166,7 @@ jobs:
echo " RUN apt-get update && apt-get install -y bc jq"
exit 1
fi
echo "installed=true" >> $GITHUB_OUTPUT
echo "✅ 工具安装完成"
else
@ -196,20 +196,20 @@ jobs:
# 检查仓库状态
if [ -d "$REPO_DIR" ]; then
echo "📂 目录已存在,检查 Git 仓库状态..."
if [ -d "$REPO_DIR/.git" ]; then
# 目录存在且是有效的 Git 仓库
echo "✓ 发现有效的 Git 仓库,执行增量更新..."
cd "$REPO_DIR"
# 清理工作区
git clean -fdx
git reset --hard
# 获取最新代码
echo "📥 拉取最新代码..."
git fetch --all --tags --force
echo "✓ 仓库已更新"
else
# 目录存在但不是 Git 仓库(可能之前运行失败)
@ -217,20 +217,20 @@ jobs:
echo "🧹 清理损坏的目录..."
rm -rf "$REPO_DIR"
echo "✓ 已清理"
# 重新克隆
echo "📥 克隆仓库..."
mkdir -p "${{ env.WORKSPACE_DIR }}"
git clone \
https://oauth2:${{ env.ACCESS_TOKEN }}@${GITHUB_SERVER_URL#https://}/${{ github.repository }}.git \
"$REPO_DIR"
if [ $? -ne 0 ]; then
echo "❌ 克隆失败"
exit 1
fi
cd "$REPO_DIR"
echo "✓ 仓库已克隆"
fi
@ -238,16 +238,16 @@ jobs:
# 目录不存在,首次克隆
echo "📥 克隆仓库(首次)..."
mkdir -p "${{ env.WORKSPACE_DIR }}"
git clone \
https://oauth2:${{ env.ACCESS_TOKEN }}@${GITHUB_SERVER_URL#https://}/${{ github.repository }}.git \
"$REPO_DIR"
if [ $? -ne 0 ]; then
echo "❌ 克隆失败"
exit 1
fi
cd "$REPO_DIR"
echo "✓ 仓库已克隆"
fi
@ -294,17 +294,17 @@ jobs:
# 检查统计分支是否存在
if git ls-remote --heads origin ${{ env.BADGE_BRANCH }} | grep -q ${{ env.BADGE_BRANCH }}; then
echo "✅ 统计分支 '${{ env.BADGE_BRANCH }}' 已存在"
# 检出统计分支
git fetch origin ${{ env.BADGE_BRANCH }}:${{ env.BADGE_BRANCH }}
git checkout ${{ env.BADGE_BRANCH }}
echo "📂 当前分支内容:"
ls -la
# 返回主分支
git checkout ${{ github.ref_name }}
echo "branch_exists=true" >> $GITHUB_OUTPUT
else
echo "🆕 统计分支 '${{ env.BADGE_BRANCH }}' 不存在,将创建"
@ -348,7 +348,7 @@ jobs:
# - stats 分支是独立的数据存储分支,不需要主分支的代码文件
# - 只需要存储徽章 JSON 文件和统计报告
# - 保持分支干净,避免混淆
#
#
# ✅ 能否复用仓库?
# - 可以!.git 目录包含所有分支的完整信息
# - 切换到主分支时,主分支的文件会恢复
@ -381,7 +381,7 @@ jobs:
# 📊 代码统计徽章数据
> 此分支由 GitHub Actions 自动生成和维护
>
>
> ⚠️ **请勿手动修改此分支的内容!**
## 📁 目录结构
@ -517,12 +517,12 @@ jobs:
# 读取语言配置并统计
echo "${{ env.LANGUAGE_GROUPS }}" | while IFS= read -r line; do
[ -z "$line" ] && continue
# 解析配置行: 组名:后缀列表:显示名称:颜色:图标
IFS=':' read -r lang_id extensions display_name color icon <<< "$line"
echo "🔍 统计 $display_name..."
# 构建扩展名查找条件
FIND_CONDITIONS=""
IFS=',' read -ra EXTS <<< "$extensions"
@ -533,21 +533,21 @@ jobs:
FIND_CONDITIONS="$FIND_CONDITIONS -o -name '*.$ext'"
fi
done
# 统计文件数
FILE_COUNT=$(eval "find . -type f \( $FIND_CONDITIONS \) $EXCLUDE_PARAMS" | wc -l)
if [ "$FILE_COUNT" -gt 0 ]; then
# 统计代码行数
CODE_LINES=$(eval "find . -type f \( $FIND_CONDITIONS \) $EXCLUDE_PARAMS -exec grep -cHv '^[[:space:]]*$' {} + 2>/dev/null" | awk -F: '{sum+=$2} END {print sum+0}')
# 只保存超过阈值的语言
if [ "$CODE_LINES" -ge "${{ env.MIN_LINES_THRESHOLD }}" ]; then
FORMATTED_LINES=$(printf "%'d" $CODE_LINES)
echo " - 文件数: $FILE_COUNT"
echo " - 代码行: $FORMATTED_LINES"
# 保存到临时文件
echo "$lang_id|$display_name|$CODE_LINES|$FORMATTED_LINES|$FILE_COUNT|$color|$icon" >> /tmp/lang_stats/${lang_id}.txt
LANGUAGE_COUNT=$((LANGUAGE_COUNT + 1))
@ -619,12 +619,12 @@ jobs:
if [ -f /tmp/lang_summary.txt ] && [ -s /tmp/lang_summary.txt ]; then
echo ""
echo "🌐 生成语言徽章..."
while IFS='|' read -r lang_id display_name code_lines formatted_lines file_count color icon; do
[ -z "$lang_id" ] && continue
echo " - $display_name"
# 生成代码行数徽章(使用 heredoc
if [ -n "$icon" ]; then
# 带图标的徽章
@ -651,7 +651,7 @@ jobs:
EOFJSON
fi
GENERATED_COUNT=$((GENERATED_COUNT + 1))
# 生成文件数徽章
cat > ${{ env.BADGE_DIR }}/${lang_id}-files.json << EOFJSON
{
@ -689,7 +689,7 @@ jobs:
# 📊 代码统计详细报告
> 🤖 由 GitHub Actions 自动生成
>
>
> 📅 更新时间: TIMESTAMP_PLACEHOLDER
## 📈 总体统计
@ -720,17 +720,17 @@ jobs:
| 语言 | 代码行数 | 文件数 | 占比 | 徽章 |
|------|----------|--------|------|------|
EOFTABLE
TOTAL_CODE=${{ steps.total.outputs.total_code }}
while IFS='|' read -r lang_id display_name code_lines formatted_lines file_count color icon; do
[ -z "$lang_id" ] && continue
if [ "$TOTAL_CODE" -gt 0 ]; then
PERCENT=$(echo "scale=1; $code_lines * 100 / $TOTAL_CODE" | bc)
else
PERCENT="0.0"
fi
cat >> ${{ env.BADGE_DIR }}/README.md << EOFLANG
| **${display_name}** | ${formatted_lines} | ${file_count} | ${PERCENT}% | ![${display_name}](https://img.shields.io/endpoint?url=${{ env.RAW_URL_BASE }}/${{ env.BADGE_BRANCH }}/${{ env.BADGE_DIR }}/${lang_id}-lines.json) |
EOFLANG
@ -807,7 +807,7 @@ jobs:
echo ""
else
echo "📝 准备提交..."
# 生成提交信息
COMMIT_MSG="chore: 更新代码统计 [$(date '+%Y-%m-%d %H:%M')]
@ -821,12 +821,12 @@ jobs:
🤖 由 GitHub Actions 自动生成"
git commit -m "$COMMIT_MSG"
echo "📤 推送到远程 ${{ env.BADGE_BRANCH }} 分支..."
# 推送到远程(使用 TOKEN
git push https://oauth2:${{ env.ACCESS_TOKEN }}@${GITHUB_SERVER_URL#https://}/${{ github.repository }}.git ${{ env.BADGE_BRANCH }}
if [ $? -eq 0 ]; then
echo "✅ 推送成功"
echo "changed=true" >> $GITHUB_OUTPUT
@ -873,17 +873,17 @@ jobs:
| 语言 | 代码行数 | 文件数 | 占比 |
|------|----------|--------|------|
EOFTABLE
TOTAL_CODE=${{ steps.total.outputs.total_code }}
sort -t'|' -k3 -nr /tmp/lang_summary.txt | head -10 | while IFS='|' read -r lang_id display_name code_lines formatted_lines file_count color icon; do
[ -z "$lang_id" ] && continue
if [ "$TOTAL_CODE" -gt 0 ]; then
PERCENT=$(echo "scale=1; $code_lines * 100 / $TOTAL_CODE" | bc)
else
PERCENT="0.0"
fi
echo "| **${display_name}** | ${formatted_lines} | ${file_count} | ${PERCENT}% |" >> $GITHUB_STEP_SUMMARY
done
else