✨ feat(ci): Release Notes 改为增量展示,正式版覆盖整个版本周期
CHANGELOG.md 仍保持整个版本累积(strip 模式),但 Release Notes 改为: - 预发布(rc):只展示相对紧邻上一个 tag 的增量(如 rc1→rc2 新提交), 避免同版本各 rc 之间大量重复。 - 正式版:跳过同版本 rc,基准落到上一个不同版本 tag, 覆盖整个版本开发周期的全量提交。 基准 tag 按 RELEASE_IS_PRERELEASE 区分,Release Notes 独立用 git log 重新生成。
This commit is contained in:
@@ -490,6 +490,38 @@ jobs:
|
|||||||
COMMIT_RANGE="${PREVIOUS_TAG}..${VERSION}"
|
COMMIT_RANGE="${PREVIOUS_TAG}..${VERSION}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# 计算 Release Notes 的增量基准 tag,规则按当前发布是否为预发布(rc)区分:
|
||||||
|
# - 预发布(rc):基准 = 紧邻的上一个 tag(不跳过同版本 rc)
|
||||||
|
# 例如 0.0.5-rc2 的基准是 0.0.5-rc1,Release Notes 只展示 rc1→rc2 的新提交,
|
||||||
|
# 避免同一版本各 rc 之间大量重复。
|
||||||
|
# - 正式版:基准 = 上一个"不同 CHANGELOG 版本"的 tag(即上面的 PREVIOUS_TAG)
|
||||||
|
# 例如 0.0.5 正式版会跳过 0.0.5-rc1/rc2,基准落到 0.0.4-rc2,
|
||||||
|
# Release Notes 覆盖整个 0.0.5 开发周期的全量提交。
|
||||||
|
# 注意:CHANGELOG.md 始终是整个版本的累积(strip 模式),与此处无关。
|
||||||
|
if [[ "${RELEASE_IS_PRERELEASE}" == "true" ]]; then
|
||||||
|
NOTES_BASE_TAG=""
|
||||||
|
while IFS= read -r tag; do
|
||||||
|
[ -z "$tag" ] && continue
|
||||||
|
if [ "$tag" != "$VERSION" ]; then
|
||||||
|
NOTES_BASE_TAG="$tag"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done <<< "$ALL_TAGS"
|
||||||
|
echo "🏷️ 预发布:Release Notes 基准 = 紧邻上一个 tag"
|
||||||
|
else
|
||||||
|
NOTES_BASE_TAG="$PREVIOUS_TAG"
|
||||||
|
echo "🏷️ 正式版:Release Notes 基准 = 上一个不同版本 tag(覆盖整个版本周期)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$NOTES_BASE_TAG" ]; then
|
||||||
|
echo "ℹ️ 未找到基准 tag,Release Notes 将包含全部提交"
|
||||||
|
RELEASE_NOTES_RANGE="HEAD"
|
||||||
|
else
|
||||||
|
echo "📍 Release Notes 增量基准: $NOTES_BASE_TAG"
|
||||||
|
RELEASE_NOTES_RANGE="${NOTES_BASE_TAG}..${VERSION}"
|
||||||
|
fi
|
||||||
|
echo "RELEASE_NOTES_RANGE=$RELEASE_NOTES_RANGE" >> $GITHUB_ENV
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "🔍 扫描提交记录..."
|
echo "🔍 扫描提交记录..."
|
||||||
|
|
||||||
@@ -918,40 +950,139 @@ jobs:
|
|||||||
if: steps.changelog.outputs.changelog_updated == 'true'
|
if: steps.changelog.outputs.changelog_updated == 'true'
|
||||||
run: |
|
run: |
|
||||||
echo "======================================"
|
echo "======================================"
|
||||||
echo "📄 提取 Release Notes"
|
echo "📄 生成增量 Release Notes"
|
||||||
echo "======================================"
|
echo "======================================"
|
||||||
|
|
||||||
cd ${{ env.REPO_DIR }}
|
cd ${{ env.REPO_DIR }}
|
||||||
|
|
||||||
python3 << 'PYSCRIPT'
|
# Release Notes 只展示本次 rc 相对上一个 tag 的增量提交
|
||||||
import re
|
# (CHANGELOG.md 仍是整个版本的累积,二者用途不同)
|
||||||
|
RELEASE_NOTES_RANGE="${{ env.RELEASE_NOTES_RANGE }}"
|
||||||
|
REPO_URL="${{ github.server_url }}/${{ github.repository }}"
|
||||||
|
echo "📊 增量范围: $RELEASE_NOTES_RANGE"
|
||||||
|
|
||||||
changelog_version = "${{ env.CHANGELOG_VERSION }}"
|
TEMP_COMMITS=$(mktemp)
|
||||||
|
git log $RELEASE_NOTES_RANGE --no-merges --reverse \
|
||||||
|
--format="COMMIT_START%n%H%n%an%n%s%nBODY_START%n%b%nBODY_END" > "$TEMP_COMMITS"
|
||||||
|
|
||||||
with open('CHANGELOG.md', 'r', encoding='utf-8') as f:
|
declare -a COMMITS_HASH
|
||||||
content = f.read()
|
declare -a COMMITS_AUTHOR
|
||||||
|
declare -a COMMITS_MESSAGE
|
||||||
|
declare -a COMMITS_BODY
|
||||||
|
|
||||||
# 匹配版本区块
|
IFS='|' read -ra IGNORE_PATTERNS <<< "${{ env.IGNORE_PATTERNS_PROCESSED }}"
|
||||||
pattern = rf'## :bookmark: {re.escape(changelog_version)}\s*\n(.*?)(?=\n---\n|\n## :bookmark: |\Z)'
|
|
||||||
match = re.search(pattern, content, re.DOTALL)
|
|
||||||
|
|
||||||
if match:
|
COMMIT_INDEX=0
|
||||||
version_content = match.group(1).strip()
|
CURRENT_HASH=""
|
||||||
# 清理多余的空行
|
CURRENT_AUTHOR=""
|
||||||
version_content = re.sub(r'\n\s*\n\s*\n+', '\n\n', version_content).strip()
|
CURRENT_MESSAGE=""
|
||||||
# 移除可能的分隔线
|
CURRENT_BODY=""
|
||||||
version_content = re.sub(r'^-{3,}\s*\n', '', version_content)
|
IN_BODY=false
|
||||||
print(f"✓ Found changelog for version {changelog_version}")
|
|
||||||
print(f"📊 Content length: {len(version_content)} characters")
|
|
||||||
else:
|
|
||||||
version_content = "⚠️ No changelog found for this version"
|
|
||||||
print(f"⚠️ WARNING: Version {changelog_version} not found in CHANGELOG")
|
|
||||||
|
|
||||||
with open('/tmp/release-body.txt', 'w', encoding='utf-8') as f:
|
flush_commit() {
|
||||||
f.write(version_content)
|
[ -z "$CURRENT_HASH" ] && return
|
||||||
|
for pattern in "${IGNORE_PATTERNS[@]}"; do
|
||||||
|
[ -z "$pattern" ] && continue
|
||||||
|
if echo "$CURRENT_MESSAGE" | grep -qiE "$pattern"; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
COMMITS_HASH[$COMMIT_INDEX]="$CURRENT_HASH"
|
||||||
|
COMMITS_AUTHOR[$COMMIT_INDEX]="$CURRENT_AUTHOR"
|
||||||
|
COMMITS_MESSAGE[$COMMIT_INDEX]="$CURRENT_MESSAGE"
|
||||||
|
COMMITS_BODY[$COMMIT_INDEX]="$CURRENT_BODY"
|
||||||
|
COMMIT_INDEX=$((COMMIT_INDEX + 1))
|
||||||
|
}
|
||||||
|
|
||||||
print("✅ Release notes generated successfully")
|
while IFS= read -r line; do
|
||||||
PYSCRIPT
|
if [[ "$line" == "COMMIT_START" ]]; then
|
||||||
|
flush_commit
|
||||||
|
CURRENT_HASH=""
|
||||||
|
CURRENT_AUTHOR=""
|
||||||
|
CURRENT_MESSAGE=""
|
||||||
|
CURRENT_BODY=""
|
||||||
|
IN_BODY=false
|
||||||
|
elif [[ "$line" == "BODY_START" ]]; then
|
||||||
|
IN_BODY=true
|
||||||
|
CURRENT_BODY=""
|
||||||
|
elif [[ "$line" == "BODY_END" ]]; then
|
||||||
|
IN_BODY=false
|
||||||
|
elif [ "$IN_BODY" = true ]; then
|
||||||
|
if [ -n "$CURRENT_BODY" ]; then
|
||||||
|
CURRENT_BODY="${CURRENT_BODY}"$'\n'"${line}"
|
||||||
|
else
|
||||||
|
CURRENT_BODY="$line"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if [ -z "$CURRENT_HASH" ]; then
|
||||||
|
CURRENT_HASH="$line"
|
||||||
|
elif [ -z "$CURRENT_AUTHOR" ]; then
|
||||||
|
CURRENT_AUTHOR="$line"
|
||||||
|
elif [ -z "$CURRENT_MESSAGE" ]; then
|
||||||
|
CURRENT_MESSAGE="$line"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done < "$TEMP_COMMITS"
|
||||||
|
flush_commit
|
||||||
|
rm -f "$TEMP_COMMITS"
|
||||||
|
|
||||||
|
VALID_COUNT=$COMMIT_INDEX
|
||||||
|
echo "✅ 增量有效提交: $VALID_COUNT"
|
||||||
|
|
||||||
|
NOTES="${CHANGELOG_SECTION_TITLE}\n\n"
|
||||||
|
for ((i=0; i<$VALID_COUNT; i++)); do
|
||||||
|
hash="${COMMITS_HASH[$i]}"
|
||||||
|
author="${COMMITS_AUTHOR[$i]}"
|
||||||
|
message="${COMMITS_MESSAGE[$i]}"
|
||||||
|
body="${COMMITS_BODY[$i]}"
|
||||||
|
short_hash="${hash:0:7}"
|
||||||
|
COMMIT_LINK="([${short_hash}](${REPO_URL}/commit/${hash}))"
|
||||||
|
AUTHOR_INFO=""
|
||||||
|
[ -n "$author" ] && AUTHOR_INFO=" by @${author}"
|
||||||
|
|
||||||
|
if [ -n "$body" ]; then
|
||||||
|
cleaned_body=$(echo "$body" | sed -e :a -e '/^\s*$/d;')
|
||||||
|
else
|
||||||
|
cleaned_body=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$cleaned_body" ]; then
|
||||||
|
NOTES="${NOTES}- ${message} \n"
|
||||||
|
while IFS= read -r bline; do
|
||||||
|
[ -z "$bline" ] && continue
|
||||||
|
NOTES="${NOTES} ${bline} \n"
|
||||||
|
done <<< "$cleaned_body"
|
||||||
|
NOTES="${NOTES} ${COMMIT_LINK}${AUTHOR_INFO}\n"
|
||||||
|
else
|
||||||
|
NOTES="${NOTES}- ${message} ${COMMIT_LINK}${AUTHOR_INFO}\n"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# 增量贡献者(同样过滤 bot)
|
||||||
|
if [ "$RELEASE_NOTES_RANGE" = "HEAD" ]; then
|
||||||
|
CONTRIBUTORS=$(git log --pretty=format:"%an" --no-merges)
|
||||||
|
else
|
||||||
|
CONTRIBUTORS=$(git log $RELEASE_NOTES_RANGE --pretty=format:"%an" --no-merges)
|
||||||
|
fi
|
||||||
|
CONTRIBUTORS=$(echo "$CONTRIBUTORS" | \
|
||||||
|
grep -v "github-actions\[bot\]" | \
|
||||||
|
grep -v "dependabot\[bot\]" | \
|
||||||
|
grep -v "renovate\[bot\]" | \
|
||||||
|
grep -vxF "${{ env.GIT_USER_NAME }}" | \
|
||||||
|
sort -u)
|
||||||
|
|
||||||
|
if [ -n "$CONTRIBUTORS" ]; then
|
||||||
|
NOTES="${NOTES}\n${{ env.CHANGELOG_CONTRIBUTORS_TITLE }}\n\n"
|
||||||
|
while IFS= read -r name; do
|
||||||
|
[ -z "$name" ] && continue
|
||||||
|
NOTES="${NOTES}<a href=\"${{ env.GITEA_SERVER }}/${name}\">\n"
|
||||||
|
NOTES="${NOTES} <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"
|
||||||
|
NOTES="${NOTES}</a>\n"
|
||||||
|
done <<< "$CONTRIBUTORS"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "$NOTES" > /tmp/release-body.txt
|
||||||
|
echo "✅ Release notes 生成完成 ($(wc -c < /tmp/release-body.txt) 字节)"
|
||||||
|
|
||||||
echo "======================================"
|
echo "======================================"
|
||||||
echo ""
|
echo ""
|
||||||
|
|||||||
Reference in New Issue
Block a user