Skip to content

🔧 修复CI状态报告和Release Notes一致性问题 #20

🔧 修复CI状态报告和Release Notes一致性问题

🔧 修复CI状态报告和Release Notes一致性问题 #20

Workflow file for this run

name: Release - Parallel Publishing
on:
release:
types: [published]
push:
tags:
- 'v*' # 支持以 v 开头的版本标签 (如 v1.0.5)
jobs:
# 🔧 构建阶段 - 创建共享的VSIX文件
build:
runs-on: ubuntu-latest
outputs:
package_name: ${{ steps.package.outputs.package_name }}
version: ${{ steps.package.outputs.version }}
tag_name: ${{ steps.tag-info.outputs.tag_name }}
is_tag_push: ${{ steps.tag-info.outputs.is_tag_push }}
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: recursive
- name: Detect trigger type and extract tag info
id: tag-info
run: |
if [ "${{ github.event_name }}" == "release" ]; then
# Release触发
echo "is_tag_push=false" >> $GITHUB_OUTPUT
echo "tag_name=${{ github.event.release.tag_name }}" >> $GITHUB_OUTPUT
echo "🎉 由 GitHub Release 触发: ${{ github.event.release.tag_name }}"
elif [ "${{ github.event_name }}" == "push" ] && [[ "${{ github.ref }}" == refs/tags/* ]]; then
# Tag推送触发
echo "is_tag_push=true" >> $GITHUB_OUTPUT
TAG_NAME=${GITHUB_REF#refs/tags/}
echo "tag_name=${TAG_NAME}" >> $GITHUB_OUTPUT
echo "🏷️ 由 Tag 推送触发: ${TAG_NAME}"
else
echo "❌ 未知的触发方式"
exit 1
fi
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build extension
run: npm run vscode:prepublish
- name: Package extension
id: package
run: |
# 从 package.json 中读取版本号
VERSION=$(node -p "require('./package.json').version")
PACKAGE_NAME="xkcoding-api-navigator-v${VERSION}.vsix"
npx @vscode/vsce package --out "${PACKAGE_NAME}"
echo "package_name=${PACKAGE_NAME}" >> $GITHUB_OUTPUT
echo "version=${VERSION}" >> $GITHUB_OUTPUT
echo "✅ 扩展打包完成: ${PACKAGE_NAME}"
- name: Upload VSIX artifact
uses: actions/upload-artifact@v4
with:
name: extension-package
path: ${{ steps.package.outputs.package_name }}
retention-days: 7
# 🚀 VSCode Marketplace 发布(并行任务1)
publish-vscode:
needs: build
runs-on: ubuntu-latest
outputs:
publish_status: ${{ steps.vscode-publish.outputs.status }}
steps:
- name: Download VSIX artifact
uses: actions/download-artifact@v4
with:
name: extension-package
- name: Publish to VSCode Marketplace
id: vscode-publish
env:
VSCE_PAT: ${{ secrets.VSCE_PAT }}
run: |
# 检查是否有发布令牌
if [ -z "$VSCE_PAT" ]; then
echo "⚠️ VSCE_PAT 未设置,跳过 VSCode Marketplace 发布"
echo "status=skipped" >> $GITHUB_OUTPUT
exit 0
fi
echo "🚀 发布到 VSCode Marketplace..."
if npx @vscode/vsce publish --packagePath ${{ needs.build.outputs.package_name }}; then
echo "✅ VSCode Marketplace 发布成功"
echo "status=success" >> $GITHUB_OUTPUT
else
echo "❌ VSCode Marketplace 发布失败"
echo "status=failed" >> $GITHUB_OUTPUT
exit 1
fi
continue-on-error: true
- name: Report VSCode publish result
if: always()
run: |
PUBLISH_STATUS="${{ steps.vscode-publish.outputs.status }}"
STEP_OUTCOME="${{ steps.vscode-publish.outcome }}"
if [ "$PUBLISH_STATUS" == "success" ]; then
echo "✅ VSCode Marketplace 发布:成功"
elif [ "$PUBLISH_STATUS" == "skipped" ]; then
echo "⏭️ VSCode Marketplace 发布:跳过 (未设置 VSCE_PAT)"
else
echo "❌ VSCode Marketplace 发布:失败 (步骤状态: $STEP_OUTCOME)"
fi
# 📦 OpenVSX Registry 发布(并行任务2)
publish-openvsx:
needs: build
runs-on: ubuntu-latest
outputs:
publish_status: ${{ steps.openvsx-publish.outputs.status }}
steps:
- name: Download VSIX artifact
uses: actions/download-artifact@v4
with:
name: extension-package
- name: Publish to OpenVSX Registry
id: openvsx-publish
env:
OVSX_PAT: ${{ secrets.OVSX_PAT }}
run: |
# 检查是否有发布令牌
if [ -z "$OVSX_PAT" ]; then
echo "⚠️ OVSX_PAT 未设置,跳过 OpenVSX Registry 发布"
echo "status=skipped" >> $GITHUB_OUTPUT
exit 0
fi
echo "🚀 发布到 OpenVSX Registry..."
if npx ovsx publish ${{ needs.build.outputs.package_name }} --pat $OVSX_PAT; then
echo "✅ OpenVSX Registry 发布成功"
echo "status=success" >> $GITHUB_OUTPUT
else
echo "❌ OpenVSX Registry 发布失败"
echo "status=failed" >> $GITHUB_OUTPUT
exit 1
fi
continue-on-error: true
- name: Report OpenVSX publish result
if: always()
run: |
PUBLISH_STATUS="${{ steps.openvsx-publish.outputs.status }}"
STEP_OUTCOME="${{ steps.openvsx-publish.outcome }}"
if [ "$PUBLISH_STATUS" == "success" ]; then
echo "✅ OpenVSX Registry 发布:成功"
elif [ "$PUBLISH_STATUS" == "skipped" ]; then
echo "⏭️ OpenVSX Registry 发布:跳过 (未设置 OVSX_PAT)"
else
echo "❌ OpenVSX Registry 发布:失败 (步骤状态: $STEP_OUTCOME)"
fi
# 📎 GitHub Release 上传(并行任务3)
upload-github-release:
needs: build
runs-on: ubuntu-latest
outputs:
upload_status: ${{ steps.github-upload.outputs.status }}
permissions:
contents: write # 允许上传文件到 Release
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0 # 获取完整的git历史,包括tags
- name: Download VSIX artifact
uses: actions/download-artifact@v4
with:
name: extension-package
- name: Upload VSIX to GitHub Release
id: github-upload
run: |
echo "🚀 处理 GitHub Release..."
TAG_NAME="${{ needs.build.outputs.tag_name }}"
PACKAGE_NAME="${{ needs.build.outputs.package_name }}"
if [ "${{ needs.build.outputs.is_tag_push }}" == "true" ]; then
# Tag推送触发:创建或更新Release
echo "📝 为 Tag ${TAG_NAME} 创建/更新 Release..."
# 检查Release是否已存在
if gh release view "${TAG_NAME}" >/dev/null 2>&1; then
echo "🔄 Release ${TAG_NAME} 已存在,上传文件..."
gh release upload "${TAG_NAME}" "${PACKAGE_NAME}" --clobber
else
echo "🆕 创建新的 Release ${TAG_NAME}..."
# 获取 Tag annotation 作为 Release Notes(使用更可靠的方法)
echo "🔍 获取 Tag ${TAG_NAME} 的 annotation..."
# 方法1: 使用 git show 获取 tag annotation
TAG_MESSAGE=$(git show "${TAG_NAME}" --format='%B' --no-patch 2>/dev/null || echo "")
# 如果方法1失败,尝试方法2: 使用 git tag -l --format
if [ -z "$TAG_MESSAGE" ] || [ "$TAG_MESSAGE" = "$TAG_NAME" ]; then
echo "🔄 尝试备用方法获取 tag annotation..."
TAG_MESSAGE=$(git tag -l --format='%(contents)' "${TAG_NAME}" 2>/dev/null || echo "")
fi
# 如果方法2也失败,尝试方法3: 使用 git cat-file
if [ -z "$TAG_MESSAGE" ] || [ "$TAG_MESSAGE" = "$TAG_NAME" ]; then
echo "🔄 尝试第三种方法获取 tag annotation..."
TAG_OBJECT=$(git rev-parse "${TAG_NAME}^{}" 2>/dev/null || echo "")
if [ -n "$TAG_OBJECT" ]; then
TAG_MESSAGE=$(git cat-file -p "${TAG_NAME}" 2>/dev/null | sed '1,/^$/d' || echo "")
fi
fi
# 检查是否成功获取到有意义的内容
if [ -n "$TAG_MESSAGE" ] && [ "$TAG_MESSAGE" != "" ] && [ "$TAG_MESSAGE" != "$TAG_NAME" ]; then
echo "📝 成功获取 Tag annotation,长度: ${#TAG_MESSAGE} 字符"
echo "📄 Release Notes 预览 (前100字符):"
echo "$TAG_MESSAGE" | head -c 100
echo ""
echo "..."
# 将 tag message 保存到临时文件,保持格式
NOTES_FILE="/tmp/release_notes.md"
echo "$TAG_MESSAGE" > "$NOTES_FILE"
echo "📝 使用 Tag annotation 作为 Release Notes"
gh release create "${TAG_NAME}" "${PACKAGE_NAME}" \
--title "API Navigator ${TAG_NAME}" \
--notes-file "$NOTES_FILE"
else
echo "⚠️ 无法获取有效的 Tag annotation,使用默认 Release Notes"
# 创建默认的 Release Notes
DEFAULT_NOTES_FILE="/tmp/default_release_notes.md"
{
echo "🚀 API Navigator ${TAG_NAME} 自动发布"
echo ""
echo "这是一个自动化发布版本。"
echo ""
echo "## 📦 安装方式"
echo ""
echo "1. **VSCode Marketplace**: 搜索 \"API Navigator\" 或访问扩展商店"
echo "2. **OpenVSX Registry**: 适用于 VSCodium 和其他兼容编辑器"
echo "3. **GitHub Release**: 下载 VSIX 文件手动安装"
echo ""
echo "## 🔗 相关链接"
echo ""
echo "- 📝 完整更新日志: [README.md](https://github.com/xkcoding/API-Navigator/blob/main/README.md)"
echo "- 🐛 问题反馈: [Issues](https://github.com/xkcoding/API-Navigator/issues)"
echo "- 📖 使用文档: [GitHub 仓库](https://github.com/xkcoding/API-Navigator)"
echo ""
echo "---"
echo "*此版本通过 GitHub Actions 自动发布到多个平台*"
} > "$DEFAULT_NOTES_FILE"
gh release create "${TAG_NAME}" "${PACKAGE_NAME}" \
--title "API Navigator ${TAG_NAME}" \
--notes-file "$DEFAULT_NOTES_FILE"
fi
fi
else
# Release触发:直接上传文件
echo "📎 上传文件到现有 Release ${TAG_NAME}..."
gh release upload "${TAG_NAME}" "${PACKAGE_NAME}" --clobber
fi
echo "✅ GitHub Release 处理成功"
echo "status=success" >> $GITHUB_OUTPUT
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
continue-on-error: true
- name: Handle GitHub upload failure
if: failure() && steps.github-upload.outcome == 'failure'
run: |
echo "❌ GitHub Release 处理失败"
echo "status=failed" >> $GITHUB_OUTPUT
- name: Report GitHub upload result
if: always()
run: |
UPLOAD_STATUS="${{ steps.github-upload.outputs.status }}"
STEP_OUTCOME="${{ steps.github-upload.outcome }}"
if [ "$UPLOAD_STATUS" == "success" ]; then
echo "✅ GitHub Release 上传:成功"
else
echo "❌ GitHub Release 上传:失败 (步骤状态: $STEP_OUTCOME)"
fi
# 📊 发布状态汇总(最终状态报告)
publish-summary:
needs: [build, publish-vscode, publish-openvsx, upload-github-release]
runs-on: ubuntu-latest
if: always() # 始终运行,即使前面的任务失败
steps:
- name: Publish Summary Report
run: |
echo "📋 发布状态汇总报告"
echo "===================="
echo "🔧 构建状态: ${{ needs.build.result }}"
# 获取各平台的详细状态
VSCODE_STATUS="${{ needs.publish-vscode.outputs.publish_status }}"
OPENVSX_STATUS="${{ needs.publish-openvsx.outputs.publish_status }}"
GITHUB_STATUS="${{ needs.upload-github-release.outputs.upload_status }}"
# 处理空状态(失败时没有输出)
[ -z "$VSCODE_STATUS" ] && VSCODE_STATUS="failed"
[ -z "$OPENVSX_STATUS" ] && OPENVSX_STATUS="failed"
[ -z "$GITHUB_STATUS" ] && GITHUB_STATUS="failed"
# 显示各平台状态
echo "🚀 VSCode Marketplace: $VSCODE_STATUS"
echo "📦 OpenVSX Registry: $OPENVSX_STATUS"
echo "📎 GitHub Release: $GITHUB_STATUS"
echo "===================="
# 统计各种状态的数量
SUCCESS_COUNT=0
SKIPPED_COUNT=0
FAILED_COUNT=0
TOTAL_COUNT=3
# VSCode Marketplace
case "$VSCODE_STATUS" in
"success") SUCCESS_COUNT=$((SUCCESS_COUNT + 1)) ;;
"skipped") SKIPPED_COUNT=$((SKIPPED_COUNT + 1)) ;;
*) FAILED_COUNT=$((FAILED_COUNT + 1)) ;;
esac
# OpenVSX Registry
case "$OPENVSX_STATUS" in
"success") SUCCESS_COUNT=$((SUCCESS_COUNT + 1)) ;;
"skipped") SKIPPED_COUNT=$((SKIPPED_COUNT + 1)) ;;
*) FAILED_COUNT=$((FAILED_COUNT + 1)) ;;
esac
# GitHub Release
case "$GITHUB_STATUS" in
"success") SUCCESS_COUNT=$((SUCCESS_COUNT + 1)) ;;
"skipped") SKIPPED_COUNT=$((SKIPPED_COUNT + 1)) ;;
*) FAILED_COUNT=$((FAILED_COUNT + 1)) ;;
esac
# 显示统计结果
echo "📊 发布统计:"
echo " ✅ 成功: ${SUCCESS_COUNT} 个平台"
echo " ⏭️ 跳过: ${SKIPPED_COUNT} 个平台"
echo " ❌ 失败: ${FAILED_COUNT} 个平台"
# 最终状态判断
if [ $SUCCESS_COUNT -eq $TOTAL_COUNT ]; then
echo "🎉 所有平台发布成功!"
elif [ $SUCCESS_COUNT -gt 0 ]; then
if [ $SKIPPED_COUNT -gt 0 ]; then
echo "⚠️ 部分平台发布成功,部分平台跳过"
else
echo "⚠️ 部分平台发布成功,请检查失败的平台"
fi
elif [ $SKIPPED_COUNT -eq $TOTAL_COUNT ]; then
echo "⏭️ 所有平台都跳过了发布"
else
echo "❌ 发布过程中出现失败"
if [ $FAILED_COUNT -eq $TOTAL_COUNT ]; then
exit 1
fi
fi