♻️ 重构`changelog_and_release.yml`
Hello from ImmortalWrt / say-hello (push) Successful in 0s
Details
Hello from ImmortalWrt / say-hello (push) Successful in 0s
Details
This commit is contained in:
parent
9961226704
commit
1f535e0675
|
|
@ -5,6 +5,10 @@ on:
|
|||
tags:
|
||||
- "[0-9]*"
|
||||
|
||||
concurrency:
|
||||
group: release-${{ github.repository }}
|
||||
cancel-in-progress: false
|
||||
|
||||
# ==========================================
|
||||
# 🔧 配置区域 - 根据你的项目修改
|
||||
# ==========================================
|
||||
|
|
@ -33,7 +37,7 @@ env:
|
|||
# ===== 分支配置 =====
|
||||
# 主分支名称(用于推送 CHANGELOG 更新)
|
||||
# 如果留空,会自动检测(main 或 master)
|
||||
MAIN_BRANCH: ""
|
||||
MAIN_BRANCH: "main"
|
||||
|
||||
# ===== 服务器配置 =====
|
||||
# Gitea 服务器地址(用于生成头像链接和 API 调用)
|
||||
|
|
@ -63,6 +67,8 @@ env:
|
|||
# - "true": 创建为草稿,不会立即发布
|
||||
# - "false": 立即发布 Release
|
||||
RELEASE_IS_DRAFT: "false"
|
||||
# 统一管理 pre-release 关键词
|
||||
PRERELEASE_KEYWORDS: "alpha|beta|rc|pre|preview|dev|test"
|
||||
# 额外要上传到 Release 的文件(空格分隔)
|
||||
# 例如: "README.md LICENSE docs/guide.pdf"
|
||||
ADDITIONAL_RELEASE_FILES: ""
|
||||
|
|
@ -137,10 +143,14 @@ jobs:
|
|||
# 从环境变量读取配置
|
||||
VERSION="${{ github.ref_name }}"
|
||||
|
||||
KEYWORDS="${{ env.PRERELEASE_KEYWORDS }}"
|
||||
STRIP_REGEX="-($KEYWORDS)[0-9]*$" # 用于 sed 删除后缀
|
||||
MATCH_REGEX="($KEYWORDS)" # 用于 bash =~ 匹配
|
||||
|
||||
# 处理 CHANGELOG 版本号
|
||||
if [[ "${{ env.CHANGELOG_VERSION_MODE }}" == "strip" ]]; then
|
||||
# 去除 pre-release 后缀(-beta, -rc1, -alpha 等)
|
||||
CHANGELOG_VERSION=$(echo "$VERSION" | sed -E 's/-(alpha|beta|rc|pre|preview|dev|test)[0-9]*$//')
|
||||
CHANGELOG_VERSION=$(echo "$VERSION" | sed -E "s/${STRIP_REGEX}//")
|
||||
echo "📝 CHANGELOG version mode: strip"
|
||||
echo " Tag: $VERSION → CHANGELOG: $CHANGELOG_VERSION"
|
||||
else
|
||||
|
|
@ -160,7 +170,7 @@ jobs:
|
|||
|
||||
# 智能判断 pre-release
|
||||
if [[ "${{ env.RELEASE_PRERELEASE_MODE }}" == "auto" ]]; then
|
||||
if [[ "$VERSION" =~ (alpha|beta|rc|pre|preview|dev|test) ]]; then
|
||||
if [[ "$VERSION" =~ $MATCH_REGEX ]]; then
|
||||
RELEASE_IS_PRERELEASE="true"
|
||||
PRERELEASE_DETECTED="yes (auto-detected: $VERSION contains pre-release keyword)"
|
||||
else
|
||||
|
|
@ -172,12 +182,6 @@ jobs:
|
|||
PRERELEASE_DETECTED="${{ env.RELEASE_PRERELEASE_MODE }} (manually configured)"
|
||||
fi
|
||||
|
||||
# 导出处理后的配置到 GitHub 环境变量
|
||||
echo "CHANGELOG_VERSION=$CHANGELOG_VERSION" >> $GITHUB_ENV
|
||||
echo "RELEASE_TITLE_PROCESSED=$RELEASE_TITLE_PROCESSED" >> $GITHUB_ENV
|
||||
echo "RELEASE_IS_PRERELEASE=$RELEASE_IS_PRERELEASE" >> $GITHUB_ENV
|
||||
echo "COMMIT_MSG=$COMMIT_MSG" >> $GITHUB_ENV
|
||||
|
||||
# 处理忽略模式(转换为数组)
|
||||
IFS='|' read -ra PATTERNS_ARRAY <<< "${{ env.IGNORE_PATTERNS }}"
|
||||
IGNORE_JSON="["
|
||||
|
|
@ -189,6 +193,16 @@ jobs:
|
|||
fi
|
||||
done
|
||||
IGNORE_JSON="${IGNORE_JSON%,}]"
|
||||
|
||||
# 导出处理后的配置到 GitHub 环境变量
|
||||
echo "CHANGELOG_VERSION=$CHANGELOG_VERSION" >> $GITHUB_ENV
|
||||
echo "RELEASE_TITLE_PROCESSED=$RELEASE_TITLE_PROCESSED" >> $GITHUB_ENV
|
||||
echo "RELEASE_IS_PRERELEASE=$RELEASE_IS_PRERELEASE" >> $GITHUB_ENV
|
||||
echo "COMMIT_MSG=$COMMIT_MSG" >> $GITHUB_ENV
|
||||
|
||||
echo "PRERELEASE_STRIP_REGEX=$STRIP_REGEX" >> $GITHUB_ENV
|
||||
echo "PRERELEASE_MATCH_REGEX=$MATCH_REGEX" >> $GITHUB_ENV
|
||||
|
||||
echo "IGNORE_PATTERNS_JSON=$IGNORE_JSON" >> $GITHUB_ENV
|
||||
|
||||
# 显示配置摘要
|
||||
|
|
@ -259,6 +273,13 @@ jobs:
|
|||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "❌ 克隆失败"
|
||||
cat /tmp/git_clone.log
|
||||
|
||||
# 清理残留
|
||||
if [ -d "$REPO_DIR" ]; then
|
||||
rm -rf "$REPO_DIR"
|
||||
fi
|
||||
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
|
@ -283,26 +304,37 @@ jobs:
|
|||
fi
|
||||
fi
|
||||
|
||||
# 检测主分支名称
|
||||
echo ""
|
||||
echo "🔍 检测主分支名称..."
|
||||
if [ -n "${{ env.MAIN_BRANCH }}" ]; then
|
||||
MAIN_BRANCH="${{ env.MAIN_BRANCH }}"
|
||||
echo "✓ 使用配置的主分支: $MAIN_BRANCH"
|
||||
else
|
||||
# 自动检测 main 或 master
|
||||
if git show-ref --verify --quiet refs/remotes/origin/main; then
|
||||
MAIN_BRANCH="main"
|
||||
echo "✓ 自动检测到主分支: main"
|
||||
elif git show-ref --verify --quiet refs/remotes/origin/master; then
|
||||
MAIN_BRANCH="master"
|
||||
echo "✓ 自动检测到主分支: master"
|
||||
else
|
||||
echo "❌ 错误: 无法检测主分支(main 或 master)"
|
||||
echo "🔍 验证主分支配置..."
|
||||
|
||||
# 检查是否配置了主分支
|
||||
if [ -z "${{ env.MAIN_BRANCH }}" ]; then
|
||||
echo "❌ 错误: 未配置主分支"
|
||||
echo ""
|
||||
echo "请在 workflow 配置文件的 env 区域设置 MAIN_BRANCH:"
|
||||
echo ""
|
||||
echo "env:"
|
||||
echo " MAIN_BRANCH: \"main\" # 或 \"master\""
|
||||
echo ""
|
||||
exit 1
|
||||
fi
|
||||
|
||||
MAIN_BRANCH="${{ env.MAIN_BRANCH }}"
|
||||
echo "✓ 使用配置的主分支: $MAIN_BRANCH"
|
||||
|
||||
# 验证分支是否存在
|
||||
if ! git show-ref --verify --quiet refs/remotes/origin/$MAIN_BRANCH; then
|
||||
echo "❌ 错误: 配置的分支 '$MAIN_BRANCH' 不存在"
|
||||
echo ""
|
||||
echo "可用的远程分支:"
|
||||
git branch -r | grep -v HEAD
|
||||
echo ""
|
||||
echo "请在 workflow 配置文件中修改 MAIN_BRANCH 为正确的分支名"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✓ 分支 '$MAIN_BRANCH' 已验证存在"
|
||||
|
||||
# 切换到主分支
|
||||
echo ""
|
||||
echo "🌿 切换到主分支: $MAIN_BRANCH"
|
||||
|
|
@ -346,38 +378,9 @@ jobs:
|
|||
echo "======================================"
|
||||
echo ""
|
||||
|
||||
- name: 🔍 检查版本是否已存在
|
||||
id: check_version
|
||||
if: steps.check_bot.outputs.is_bot_commit != 'true'
|
||||
run: |
|
||||
echo "======================================"
|
||||
echo "🔍 检查 CHANGELOG 版本"
|
||||
echo "======================================"
|
||||
|
||||
cd ${{ env.REPO_DIR }}
|
||||
|
||||
if [ ! -f "CHANGELOG.md" ]; then
|
||||
echo "📝 CHANGELOG.md 不存在,将创建新文件"
|
||||
echo "version_exists=false" >> $GITHUB_OUTPUT
|
||||
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
|
||||
else
|
||||
echo "✅ 版本 $CHANGELOG_VERSION 不存在,可以继续"
|
||||
echo "version_exists=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "======================================"
|
||||
echo ""
|
||||
|
||||
- name: 📝 生成 CHANGELOG
|
||||
id: changelog
|
||||
if: steps.check_bot.outputs.is_bot_commit != 'true' && steps.check_version.outputs.version_exists != 'true'
|
||||
if: steps.check_bot.outputs.is_bot_commit != 'true'
|
||||
run: |
|
||||
echo "======================================"
|
||||
echo "📝 生成 CHANGELOG"
|
||||
|
|
@ -407,7 +410,7 @@ jobs:
|
|||
|
||||
# 对每个 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]*$//')
|
||||
tag_stripped=$(echo "$tag" | sed -E "s/${{ env.PRERELEASE_STRIP_REGEX }}//")
|
||||
else
|
||||
tag_stripped="$tag"
|
||||
fi
|
||||
|
|
@ -420,248 +423,353 @@ jobs:
|
|||
done <<< "$ALL_TAGS"
|
||||
|
||||
if [ -z "$PREVIOUS_TAG" ]; then
|
||||
echo "ℹ️ No previous tag found, using all commits"
|
||||
COMMIT_RANGE=""
|
||||
echo "ℹ️ 未找到前一个tag,将使用所有提交"
|
||||
COMMIT_RANGE="HEAD"
|
||||
else
|
||||
echo "📍 Previous tag: $PREVIOUS_TAG"
|
||||
echo "📍 前一个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]*$//')
|
||||
PREV_CHANGELOG_VERSION=$(echo "$PREVIOUS_TAG" | sed -E "s/${{ env.PRERELEASE_STRIP_REGEX }}//")
|
||||
echo " (对应 CHANGELOG 版本: $PREV_CHANGELOG_VERSION)"
|
||||
fi
|
||||
|
||||
COMMIT_RANGE="${PREVIOUS_TAG}..${VERSION}"
|
||||
fi
|
||||
|
||||
# 获取提交记录
|
||||
echo ""
|
||||
echo "📋 获取提交记录..."
|
||||
if [ -z "$COMMIT_RANGE" ]; then
|
||||
git log --pretty=format:'%H|%s' > /tmp/commits.txt
|
||||
echo "🔍 扫描提交记录..."
|
||||
|
||||
# ============================================
|
||||
# 使用 NULL 分隔符读取 git log (最安全可靠的方式)
|
||||
# ============================================
|
||||
declare -a COMMITS_HASH
|
||||
declare -a COMMITS_AUTHOR
|
||||
declare -a COMMITS_MESSAGE
|
||||
declare -a COMMITS_BODY
|
||||
|
||||
# 从环境变量加载忽略模式 (转换为 bash 数组)
|
||||
IFS='|' read -ra IGNORE_PATTERNS <<< "${{ env.IGNORE_PATTERNS }}"
|
||||
|
||||
# 去除每个模式的首尾空格
|
||||
for i in "${!IGNORE_PATTERNS[@]}"; do
|
||||
IGNORE_PATTERNS[$i]=$(echo "${IGNORE_PATTERNS[$i]}" | xargs)
|
||||
done
|
||||
|
||||
echo "📋 已加载 ${#IGNORE_PATTERNS[@]} 个忽略模式"
|
||||
|
||||
VALID_COUNT=0
|
||||
SKIPPED_COUNT=0
|
||||
|
||||
# 使用 NULL 分隔符读取 commits
|
||||
# -z: 使用 NULL 字符分隔输出
|
||||
# %x00: 在格式中插入 NULL 字符
|
||||
# 格式: 完整hash \0 作者 \0 主题 \0 正文 \0
|
||||
while IFS= read -r -d '' hash && \
|
||||
IFS= read -r -d '' author && \
|
||||
IFS= read -r -d '' subject && \
|
||||
IFS= read -r -d '' body; do
|
||||
|
||||
# 检查是否应该忽略此提交
|
||||
SHOULD_SKIP=false
|
||||
MATCHED_PATTERN=""
|
||||
|
||||
for pattern in "${IGNORE_PATTERNS[@]}"; do
|
||||
# 跳过空模式
|
||||
[ -z "$pattern" ] && continue
|
||||
|
||||
if [[ "$subject" =~ $pattern ]]; then
|
||||
SHOULD_SKIP=true
|
||||
MATCHED_PATTERN="$pattern"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$SHOULD_SKIP" = true ]; then
|
||||
echo " ⏭️ 跳过: ${subject:0:70}... (匹配: ${MATCHED_PATTERN})"
|
||||
SKIPPED_COUNT=$((SKIPPED_COUNT + 1))
|
||||
else
|
||||
git log --pretty=format:'%H|%s' "$COMMIT_RANGE" > /tmp/commits.txt
|
||||
COMMITS_HASH+=("$hash")
|
||||
COMMITS_AUTHOR+=("$author")
|
||||
COMMITS_MESSAGE+=("$subject")
|
||||
COMMITS_BODY+=("$body")
|
||||
VALID_COUNT=$((VALID_COUNT + 1))
|
||||
fi
|
||||
done < <(git log $COMMIT_RANGE --no-merges --reverse -z --format="%H%x00%an%x00%s%x00%b%x00")
|
||||
|
||||
echo ""
|
||||
echo "📊 提交统计:"
|
||||
echo " ✓ 有效提交: $VALID_COUNT"
|
||||
echo " ⏭️ 已跳过: $SKIPPED_COUNT"
|
||||
echo " 📝 总计: $((VALID_COUNT + SKIPPED_COUNT))"
|
||||
echo ""
|
||||
|
||||
if [ $VALID_COUNT -eq 0 ]; then
|
||||
echo "⚠️ 未找到有效的提交"
|
||||
echo "changelog_updated=false" >> $GITHUB_OUTPUT
|
||||
echo "content_changed=false" >> $GITHUB_OUTPUT
|
||||
exit 0
|
||||
fi
|
||||
|
||||
TOTAL_COMMITS=$(wc -l < /tmp/commits.txt)
|
||||
echo "✓ 找到 $TOTAL_COMMITS 个提交"
|
||||
# ============================================
|
||||
# 构建 CHANGELOG 条目
|
||||
# ============================================
|
||||
echo "📄 构建 CHANGELOG 条目..."
|
||||
|
||||
# Python 脚本生成 CHANGELOG
|
||||
python3 << 'PYSCRIPT'
|
||||
import re
|
||||
import json
|
||||
import sys
|
||||
from datetime import datetime
|
||||
REPO_URL="${{ github.server_url }}/${{ github.repository }}"
|
||||
|
||||
# 读取配置
|
||||
changelog_version = "${{ env.CHANGELOG_VERSION }}"
|
||||
gitea_server = "${{ env.GITEA_SERVER }}"
|
||||
repo = "${{ github.repository }}"
|
||||
section_title = "${{ env.CHANGELOG_SECTION_TITLE }}"
|
||||
contributors_title = "${{ env.CHANGELOG_CONTRIBUTORS_TITLE }}"
|
||||
# 初始化条目内容
|
||||
NEW_ENTRY="## :bookmark: ${CHANGELOG_VERSION}\n\n"
|
||||
NEW_ENTRY="${NEW_ENTRY}${CHANGELOG_SECTION_TITLE}\n\n"
|
||||
|
||||
# 读取忽略模式
|
||||
ignore_patterns = json.loads('${{ env.IGNORE_PATTERNS_JSON }}')
|
||||
print(f"🔍 Loaded {len(ignore_patterns)} ignore patterns:")
|
||||
for pattern in ignore_patterns:
|
||||
print(f" - {pattern}")
|
||||
print()
|
||||
# 处理每个提交
|
||||
for ((i=0; i<$VALID_COUNT; i++)); do
|
||||
hash="${COMMITS_HASH[$i]}"
|
||||
author="${COMMITS_AUTHOR[$i]}"
|
||||
message="${COMMITS_MESSAGE[$i]}"
|
||||
body="${COMMITS_BODY[$i]}"
|
||||
|
||||
# 读取提交
|
||||
with open('/tmp/commits.txt', 'r', encoding='utf-8') as f:
|
||||
lines = f.readlines()
|
||||
echo " [$((i+1))/$VALID_COUNT] ${hash:0:7}: ${message:0:60}..."
|
||||
|
||||
commits = []
|
||||
skipped_commits = []
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
if not line or '|' not in line:
|
||||
continue
|
||||
# 构建提交链接
|
||||
short_hash="${hash:0:7}"
|
||||
COMMIT_LINK="([${short_hash}](${REPO_URL}/commit/${hash}))"
|
||||
|
||||
commit_hash, message = line.split('|', 1)
|
||||
# 处理 body (如果存在)
|
||||
if [ -n "$body" ]; then
|
||||
# 移除首尾空行,保留中间的空行
|
||||
cleaned_body=$(echo "$body" | sed -e :a -e '/^\s*$/d;')
|
||||
|
||||
# 检查是否应该忽略
|
||||
should_ignore = False
|
||||
matched_pattern = None
|
||||
for pattern in ignore_patterns:
|
||||
if re.search(pattern, message):
|
||||
should_ignore = True
|
||||
matched_pattern = pattern
|
||||
break
|
||||
if [ -n "$cleaned_body" ]; then
|
||||
# 有 body: 主题换行后接 body,然后是链接和作者
|
||||
# Markdown 需要两个空格来实现换行
|
||||
NEW_ENTRY="${NEW_ENTRY}- ${message} \n"
|
||||
|
||||
if should_ignore:
|
||||
skipped_commits.append((message, matched_pattern))
|
||||
else:
|
||||
commits.append({'hash': commit_hash, 'message': message})
|
||||
# 将 body 按行添加,每行缩进两个空格
|
||||
while IFS= read -r line; do
|
||||
NEW_ENTRY="${NEW_ENTRY} ${line} \n"
|
||||
done <<< "$cleaned_body"
|
||||
|
||||
# 输出统计
|
||||
print(f"📊 Commit Statistics:")
|
||||
print(f" Total: {len(lines)}")
|
||||
print(f" Valid: {len(commits)}")
|
||||
print(f" Skipped: {len(skipped_commits)}")
|
||||
print()
|
||||
# 在最后一行添加链接和作者
|
||||
NEW_ENTRY="${NEW_ENTRY} ${COMMIT_LINK}"
|
||||
if [ -n "$author" ]; then
|
||||
NEW_ENTRY="${NEW_ENTRY} by @${author}"
|
||||
fi
|
||||
NEW_ENTRY="${NEW_ENTRY}\n"
|
||||
else
|
||||
# body 为空 (只有空白): 主题 + 链接 + 作者
|
||||
NEW_ENTRY="${NEW_ENTRY}- ${message} ${COMMIT_LINK}"
|
||||
if [ -n "$author" ]; then
|
||||
NEW_ENTRY="${NEW_ENTRY} by @${author}"
|
||||
fi
|
||||
NEW_ENTRY="${NEW_ENTRY}\n"
|
||||
fi
|
||||
else
|
||||
# 没有 body: 主题 + 链接 + 作者
|
||||
NEW_ENTRY="${NEW_ENTRY}- ${message} ${COMMIT_LINK}"
|
||||
if [ -n "$author" ]; then
|
||||
NEW_ENTRY="${NEW_ENTRY} by @${author}"
|
||||
fi
|
||||
NEW_ENTRY="${NEW_ENTRY}\n"
|
||||
fi
|
||||
done
|
||||
|
||||
if skipped_commits:
|
||||
print("⏭️ Skipped Commits:")
|
||||
for msg, pattern in skipped_commits:
|
||||
print(f" ⏭️ Skipping: {msg[:80]}... (matched: {pattern})")
|
||||
print()
|
||||
echo ""
|
||||
echo "👥 收集贡献者..."
|
||||
|
||||
if not commits:
|
||||
print("⚠️ No valid commits found")
|
||||
with open('/tmp/changelog_updated.txt', 'w') as f:
|
||||
f.write('false')
|
||||
sys.exit(0)
|
||||
# 收集贡献者 (去除 bot)
|
||||
if [ "$COMMIT_RANGE" = "HEAD" ]; then
|
||||
CONTRIBUTORS=$(git log --pretty=format:"%an" --no-merges | \
|
||||
grep -v "github-actions\[bot\]" | \
|
||||
grep -v "dependabot\[bot\]" | \
|
||||
grep -v "renovate\[bot\]" | \
|
||||
sort -u)
|
||||
else
|
||||
CONTRIBUTORS=$(git log $COMMIT_RANGE --pretty=format:"%an" --no-merges | \
|
||||
grep -v "github-actions\[bot\]" | \
|
||||
grep -v "dependabot\[bot\]" | \
|
||||
grep -v "renovate\[bot\]" | \
|
||||
sort -u)
|
||||
fi
|
||||
|
||||
# 收集贡献者
|
||||
contributors = set()
|
||||
for commit in commits:
|
||||
# 从提交消息中提取可能的用户名(如果使用了 @username 格式)
|
||||
# 这里简化处理,实际可以通过 git log --format='%an|%ae' 获取
|
||||
pass
|
||||
if [ -n "$CONTRIBUTORS" ]; then
|
||||
CONTRIBUTOR_COUNT=$(echo "$CONTRIBUTORS" | wc -l)
|
||||
echo "✓ 找到 ${CONTRIBUTOR_COUNT} 个贡献者"
|
||||
|
||||
# 生成 CHANGELOG 内容
|
||||
changelog_content = f"## :bookmark: {changelog_version}\n\n"
|
||||
changelog_content += f"*Released on {datetime.now().strftime('%Y-%m-%d')}*\n\n"
|
||||
changelog_content += f"{section_title}\n\n"
|
||||
NEW_ENTRY="${NEW_ENTRY}\n${{ env.CHANGELOG_CONTRIBUTORS_TITLE }}\n\n"
|
||||
|
||||
for commit in commits:
|
||||
short_hash = commit['hash'][:7]
|
||||
message = commit['message']
|
||||
changelog_content += f"- {message} ([`{short_hash}`](https://github.com/{repo}/commit/{commit['hash']}))\n"
|
||||
while IFS= read -r name; do
|
||||
[ -z "$name" ] && continue
|
||||
NEW_ENTRY="${NEW_ENTRY}<a href=\"${{ env.GITEA_SERVER }}/${name}\">\n"
|
||||
NEW_ENTRY="${NEW_ENTRY} <img src=\"${{ env.GITEA_SERVER }}/${name}.png\" alt=\"${name}\" width=\"35\" height=\"35\" style=\"border-radius: 50%;\" onerror=\"this.src='${{ env.GITEA_SERVER }}/assets/img/avatar_default.png'\" />\n"
|
||||
NEW_ENTRY="${NEW_ENTRY}</a>\n"
|
||||
done <<< "$CONTRIBUTORS"
|
||||
fi
|
||||
|
||||
# 如果有贡献者信息,可以在这里添加
|
||||
# changelog_content += f"\n{contributors_title}\n\n"
|
||||
NEW_ENTRY="${NEW_ENTRY}\n---\n"
|
||||
|
||||
changelog_content += "\n---\n\n"
|
||||
echo ""
|
||||
echo "💾 写入 CHANGELOG.md..."
|
||||
|
||||
# 切换到主分支
|
||||
git checkout ${{ env.MAIN_BRANCH }}
|
||||
|
||||
# ============================================
|
||||
# 更新或创建 CHANGELOG.md
|
||||
changelog_file = 'CHANGELOG.md'
|
||||
try:
|
||||
with open(changelog_file, 'r', encoding='utf-8') as f:
|
||||
existing_content = f.read()
|
||||
except FileNotFoundError:
|
||||
existing_content = "# :memo: CHANGELOG\n\n"
|
||||
# ============================================
|
||||
|
||||
# 检查版本是否已存在
|
||||
if f"## :bookmark: {changelog_version}" in existing_content:
|
||||
print(f"ℹ️ Version {changelog_version} already exists, appending commits")
|
||||
# 找到版本区块,在其中追加新的提交
|
||||
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 [ -f CHANGELOG.md ]; then
|
||||
# CHANGELOG 文件已存在
|
||||
if grep -q "^## :bookmark: ${CHANGELOG_VERSION}$" CHANGELOG.md; then
|
||||
# 版本已存在 - 内容叠加模式
|
||||
echo "🔄 版本 ${CHANGELOG_VERSION} 已存在,执行内容叠加..."
|
||||
|
||||
if match:
|
||||
existing_commits = match.group(2).strip()
|
||||
new_commits = changelog_content.split(f"{section_title}\n\n")[1].split("\n---")[0].strip()
|
||||
# 提取现有版本区域中的 commit hashes (用于去重)
|
||||
EXISTING_HASHES=$(awk '
|
||||
BEGIN { in_version=0 }
|
||||
/^## :bookmark: '"${CHANGELOG_VERSION}"'$/ { in_version=1; next }
|
||||
/^## :bookmark: / && in_version { in_version=0 }
|
||||
in_version && /\(\[([0-9a-f]{7})\]/ {
|
||||
match($0, /\(\[([0-9a-f]{7})\]/, arr)
|
||||
print arr[1]
|
||||
}
|
||||
' CHANGELOG.md | sort -u)
|
||||
|
||||
# 合并提交,去重
|
||||
all_commits_text = existing_commits + "\n" + new_commits
|
||||
# 简单去重(基于完整行)
|
||||
unique_lines = []
|
||||
seen = set()
|
||||
for line in all_commits_text.split('\n'):
|
||||
if line.strip() and line not in seen:
|
||||
unique_lines.append(line)
|
||||
seen.add(line)
|
||||
# 找出真正的新 commits (基于 hash 去重)
|
||||
NEW_COMMIT_ENTRIES=""
|
||||
NEW_COMMIT_COUNT=0
|
||||
|
||||
merged_commits = '\n'.join(unique_lines)
|
||||
for ((i=0; i<$VALID_COUNT; i++)); do
|
||||
hash="${COMMITS_HASH[$i]}"
|
||||
short_hash="${hash:0:7}"
|
||||
|
||||
# 重新组装版本区块
|
||||
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")
|
||||
# 尝试匹配各种可能的 CHANGELOG 标题格式
|
||||
header_pattern = r'^#\s*(?::[\w_]+:)?\s*CHANGELOG\s*\n'
|
||||
match = re.search(header_pattern, existing_content, re.IGNORECASE | re.MULTILINE)
|
||||
# 检查这个 commit 是否已存在
|
||||
if echo "$EXISTING_HASHES" | grep -q "^${short_hash}$"; then
|
||||
echo " ℹ️ 跳过已存在: ${short_hash} ${COMMITS_MESSAGE[$i]:0:50}..."
|
||||
continue
|
||||
fi
|
||||
|
||||
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:
|
||||
# 插入新版本
|
||||
# 尝试匹配各种可能的 CHANGELOG 标题格式
|
||||
# 支持: # CHANGELOG, # :memo: CHANGELOG, # Changelog 等
|
||||
# 这是一个新的 commit,添加它
|
||||
author="${COMMITS_AUTHOR[$i]}"
|
||||
message="${COMMITS_MESSAGE[$i]}"
|
||||
body="${COMMITS_BODY[$i]}"
|
||||
|
||||
# 尝试找到 CHANGELOG 标题(不区分大小写,可选 emoji)
|
||||
header_pattern = r'^#\s*(?::[\w_]+:)?\s*CHANGELOG\s*\n'
|
||||
match = re.search(header_pattern, existing_content, re.IGNORECASE | re.MULTILINE)
|
||||
COMMIT_LINK="([${short_hash}](${REPO_URL}/commit/${hash}))"
|
||||
|
||||
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}"
|
||||
if [ -n "$body" ]; then
|
||||
cleaned_body=$(echo "$body" | sed -e :a -e '/^\s*$/d;')
|
||||
if [ -n "$cleaned_body" ]; then
|
||||
NEW_COMMIT_ENTRIES="${NEW_COMMIT_ENTRIES}- ${message} \n"
|
||||
while IFS= read -r line; do
|
||||
NEW_COMMIT_ENTRIES="${NEW_COMMIT_ENTRIES} ${line} \n"
|
||||
done <<< "$cleaned_body"
|
||||
NEW_COMMIT_ENTRIES="${NEW_COMMIT_ENTRIES} ${COMMIT_LINK}"
|
||||
else
|
||||
NEW_COMMIT_ENTRIES="${NEW_COMMIT_ENTRIES}- ${message} ${COMMIT_LINK}"
|
||||
fi
|
||||
else
|
||||
NEW_COMMIT_ENTRIES="${NEW_COMMIT_ENTRIES}- ${message} ${COMMIT_LINK}"
|
||||
fi
|
||||
|
||||
# 检查内容是否真的改变
|
||||
content_changed = (new_content != existing_content)
|
||||
version_exists = f"## :bookmark: {changelog_version}" in existing_content
|
||||
if [ -n "$author" ]; then
|
||||
NEW_COMMIT_ENTRIES="${NEW_COMMIT_ENTRIES} by @${author}"
|
||||
fi
|
||||
|
||||
if content_changed:
|
||||
with open(changelog_file, 'w', encoding='utf-8') as f:
|
||||
f.write(new_content)
|
||||
NEW_COMMIT_ENTRIES="${NEW_COMMIT_ENTRIES}\n"
|
||||
NEW_COMMIT_COUNT=$((NEW_COMMIT_COUNT + 1))
|
||||
done
|
||||
|
||||
print(f"✅ CHANGELOG updated successfully")
|
||||
print(f" Added {len(commits)} commits to version {changelog_version}")
|
||||
if [ $NEW_COMMIT_COUNT -gt 0 ]; then
|
||||
echo "✓ 发现 ${NEW_COMMIT_COUNT} 个新的commits需要添加"
|
||||
|
||||
with open('/tmp/changelog_updated.txt', 'w') as f:
|
||||
f.write('true')
|
||||
with open('/tmp/content_changed.txt', 'w') as f:
|
||||
f.write('true')
|
||||
elif version_exists:
|
||||
# 内容没有变化,但版本已存在
|
||||
# 这通常发生在重建已删除的 tag
|
||||
# 我们仍然应该创建 Release(从现有 CHANGELOG 提取内容)
|
||||
print(f"ℹ️ No new content to add")
|
||||
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")
|
||||
# 在 Contributors 部分之前插入新的 commits
|
||||
TEMP_FILE=$(mktemp)
|
||||
IN_VERSION=false
|
||||
ADDED=false
|
||||
|
||||
with open('/tmp/changelog_updated.txt', 'w') as f:
|
||||
f.write('true') # 返回 true 以触发 Release 创建
|
||||
with open('/tmp/content_changed.txt', 'w') as f:
|
||||
f.write('false') # 但文件没有变化,不需要提交
|
||||
else:
|
||||
# 既没有新内容,版本也不存在(不应该发生)
|
||||
print(f"⚠️ Unexpected state: no content change and version doesn't exist")
|
||||
while IFS= read -r line; do
|
||||
# 检测版本标题
|
||||
if [[ "$line" =~ ^##[[:space:]]:bookmark:[[:space:]]${CHANGELOG_VERSION}$ ]]; then
|
||||
echo "$line" >> "$TEMP_FILE"
|
||||
IN_VERSION=true
|
||||
# 检测到 Contributors 标题,在它之前插入新 commits
|
||||
elif [[ "$line" =~ ^###[[:space:]]:busts_in_silhouette: ]] && [ "$IN_VERSION" = true ] && [ "$ADDED" = false ]; then
|
||||
echo "" >> "$TEMP_FILE"
|
||||
echo -e "${NEW_COMMIT_ENTRIES}" >> "$TEMP_FILE"
|
||||
echo "$line" >> "$TEMP_FILE"
|
||||
ADDED=true
|
||||
# 遇到下一个版本标题
|
||||
elif [[ "$line" =~ ^##[[:space:]]:bookmark: ]] && [ "$IN_VERSION" = true ]; then
|
||||
# 如果还没添加(可能没有 Contributors 部分)
|
||||
if [ "$ADDED" = false ]; then
|
||||
echo "" >> "$TEMP_FILE"
|
||||
echo -e "${NEW_COMMIT_ENTRIES}" >> "$TEMP_FILE"
|
||||
ADDED=true
|
||||
fi
|
||||
echo "$line" >> "$TEMP_FILE"
|
||||
IN_VERSION=false
|
||||
else
|
||||
echo "$line" >> "$TEMP_FILE"
|
||||
fi
|
||||
done < CHANGELOG.md
|
||||
|
||||
with open('/tmp/changelog_updated.txt', 'w') as f:
|
||||
f.write('false')
|
||||
with open('/tmp/content_changed.txt', 'w') as f:
|
||||
f.write('false')
|
||||
PYSCRIPT
|
||||
# 如果到文件末尾还没添加(版本在最后且没有 Contributors)
|
||||
if [ "$IN_VERSION" = true ] && [ "$ADDED" = false ]; then
|
||||
echo "" >> "$TEMP_FILE"
|
||||
echo -e "${NEW_COMMIT_ENTRIES}" >> "$TEMP_FILE"
|
||||
fi
|
||||
|
||||
UPDATED=$(cat /tmp/changelog_updated.txt)
|
||||
CONTENT_CHANGED=$(cat /tmp/content_changed.txt 2>/dev/null || echo "false")
|
||||
mv "$TEMP_FILE" CHANGELOG.md
|
||||
echo "✅ 已追加 ${NEW_COMMIT_COUNT} 个新commits到现有版本"
|
||||
|
||||
echo "changelog_updated=$UPDATED" >> $GITHUB_OUTPUT
|
||||
echo "content_changed=$CONTENT_CHANGED" >> $GITHUB_OUTPUT
|
||||
echo "changelog_updated=true" >> $GITHUB_OUTPUT
|
||||
echo "content_changed=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "ℹ️ 所有commits都已存在于CHANGELOG中"
|
||||
echo " (通常发生在重建已删除的 tag)"
|
||||
echo " 将从现有内容创建 Release"
|
||||
|
||||
echo "changelog_updated=true" >> $GITHUB_OUTPUT
|
||||
echo "content_changed=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
else
|
||||
# 版本不存在 - 添加新版本条目
|
||||
echo "➕ 添加新版本条目: ${CHANGELOG_VERSION}"
|
||||
|
||||
TEMP_FILE=$(mktemp)
|
||||
|
||||
# 读取第一行 (CHANGELOG 标题)
|
||||
head -n 1 CHANGELOG.md > "$TEMP_FILE"
|
||||
echo "" >> "$TEMP_FILE"
|
||||
|
||||
# 插入新条目
|
||||
echo -e "${NEW_ENTRY}" >> "$TEMP_FILE"
|
||||
|
||||
# 追加剩余内容 (从第3行开始,跳过标题后的空行)
|
||||
tail -n +3 CHANGELOG.md >> "$TEMP_FILE"
|
||||
|
||||
mv "$TEMP_FILE" CHANGELOG.md
|
||||
echo "✅ 已添加新的CHANGELOG条目"
|
||||
|
||||
echo "changelog_updated=true" >> $GITHUB_OUTPUT
|
||||
echo "content_changed=true" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
else
|
||||
# CHANGELOG 文件不存在 - 创建新文件
|
||||
echo "📄 创建新的 CHANGELOG.md"
|
||||
|
||||
echo "# :memo: CHANGELOG" > CHANGELOG.md
|
||||
echo "" >> CHANGELOG.md
|
||||
echo -e "${NEW_ENTRY}" >> CHANGELOG.md
|
||||
|
||||
echo "✅ 已创建新的CHANGELOG.md"
|
||||
|
||||
echo "changelog_updated=true" >> $GITHUB_OUTPUT
|
||||
echo "content_changed=true" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
if [ "$UPDATED" = "true" ]; then
|
||||
echo ""
|
||||
echo "✅ CHANGELOG 生成完成"
|
||||
else
|
||||
echo ""
|
||||
echo "ℹ️ 没有有效的提交,跳过 CHANGELOG 更新"
|
||||
fi
|
||||
|
||||
echo "======================================"
|
||||
echo ""
|
||||
|
||||
|
|
@ -828,10 +936,6 @@ jobs:
|
|||
id: upload_assets
|
||||
if: steps.changelog.outputs.changelog_updated == 'true'
|
||||
run: |
|
||||
echo "======================================"
|
||||
echo "📎 上传 Release 附件"
|
||||
echo "======================================"
|
||||
|
||||
cd ${{ env.REPO_DIR }}
|
||||
|
||||
echo "🔍 提取 Release ID..."
|
||||
|
|
|
|||
Loading…
Reference in New Issue