🔧 修复CI状态报告和Release Notes一致性问题 #20
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |