name: 需要审核的发布操作 on: workflow_dispatch: inputs: build_run_id: description: '请填写 Build CI 成功的 Run ID (例如:123456789)' required: true type: string build_flavor: description: '请选择要发布的版本风味' required: true default: 'prod' type: choice options: - prod - dev version_name: description: '请输入要发布的软件版本号 (例如: 1.0.0)' required: true type: string jobs: # Job 1: 准备和审核 prepare_review: name: 准备、预检并显示发布参数 runs-on: ubuntu-latest permissions: contents: read outputs: build_run_id_out: ${{ github.event.inputs.build_run_id }} build_flavor_out: ${{ github.event.inputs.build_flavor }} version_name_out: ${{ github.event.inputs.version_name }} artifact_id_out: ${{ steps.validate_artifact.outputs.artifact_id_out }} steps: - name: 检出代码 uses: actions/checkout@v4 with: fetch-depth: 0 - name: 关键参数展示 (请审核者核对) run: | echo "--- 待审核发布参数 ---" echo "版本号 (Version): ${{ github.event.inputs.version_name }}" echo "发布风味 (Flavor): ${{ github.event.inputs.build_flavor }}" echo "基于构建 Run ID: ${{ github.event.inputs.build_run_id }}" echo "------------------------" - name: 🔐 预检:检查目标标签是否已存在 run: | BUILD_FLAVOR=${{ github.event.inputs.build_flavor }} VERSION_NAME=${{ github.event.inputs.version_name }} # 计算目标标签名(保持与 Job 2 的标签命名规则一致) if [ "$BUILD_FLAVOR" == "prod" ]; then RELEASE_TAG="v${VERSION_NAME}" else RELEASE_TAG="v${VERSION_NAME}-${BUILD_FLAVOR}" fi echo "目标 Release 标签名: $RELEASE_TAG" # 使用 git rev-parse 检查标签是否存在 if git rev-parse --verify "refs/tags/$RELEASE_TAG" >/dev/null 2>&1; then echo "🚨 严重错误:目标 Release 标签 [$RELEASE_TAG] 已存在于 Git 仓库中。" echo "请修改版本号或手动删除旧标签后重试。" exit 1 # 强制工作流失败 fi echo "✅ 目标标签 [$RELEASE_TAG] 检查通过,可以创建。" - name: 预检:验证 Artifact 和源 Run 状态 id: validate_artifact uses: actions/github-script@v7 with: script: | const { build_run_id, build_flavor } = context.payload.inputs; const artifactName = `app-${build_flavor}-release-apk`; core.info(`执行预检:验证 Run ID ${build_run_id} 是否成功且包含 Artifact: ${artifactName}`); // 1. 检查源 Run 的状态是否为 'success' const sourceRun = await github.rest.actions.getWorkflowRun({ owner: context.repo.owner, repo: context.repo.repo, run_id: build_run_id, }); if (sourceRun.data.conclusion !== 'success') { core.setFailed(`源构建 Run ID ${build_run_id} 状态为 ${sourceRun.data.conclusion},必须是 'success' 才能发布!`); return; } core.info(`✅ 源构建 Run 状态检查通过: ${sourceRun.data.conclusion}`); // 2. 查找 Artifact 是否存在 const artifacts = await github.rest.actions.listWorkflowRunArtifacts({ owner: context.repo.owner, repo: context.repo.repo, run_id: build_run_id, }); const matchArtifact = artifacts.data.artifacts.filter(artifact => { return artifact.name === artifactName })[0]; if (!matchArtifact) { core.setFailed(`在 Run ID ${build_run_id} 中未找到 Artifact: ${artifactName}!请检查 Run ID 和风味是否正确。`); return; } core.info(`✅ Artifact 存在性检查通过。Artifact ID: ${matchArtifact.id}`); core.setOutput('artifact_id_out', matchArtifact.id); # Job 2: 审核并发布 (受环境锁限制,只有在 Job 1 成功预检并通过审核后才运行) release: name: 批准后执行发布到 GitHub Releases runs-on: ubuntu-latest needs: prepare_review environment: Production-Release permissions: contents: write steps: # 0. 检出代码 (Action 必备,用于访问 changelog-generator 和 git 历史) - name: ⬇️ 检出仓库代码 (获取完整历史) uses: actions/checkout@v4 with: fetch-depth: 0 # 必须获取全部历史,以便 git log/tag # 1. 计算 Release 名称和 Changelog 标题/标签 - name: ⚙️ 计算最终标签名和 Changelog 标题 id: compute_names run: | BUILD_FLAVOR=${{ needs.prepare_review.outputs.build_flavor_out }} VERSION_NAME=${{ needs.prepare_review.outputs.version_name_out }} # 构造标签名、Release 显示名和 Changelog 标题 FLAVOR_NAME="$BUILD_FLAVOR" case "$BUILD_FLAVOR" in "prod") RELEASE_TAG="v${VERSION_NAME}" FLAVOR_NAME="正式版" CHANGELOG_TITLE="v${VERSION_NAME}" ;; "dev") RELEASE_TAG="v${VERSION_NAME}-${BUILD_FLAVOR}" FLAVOR_NAME="开发者版" CHANGELOG_TITLE="v${VERSION_NAME}-${BUILD_FLAVOR}" ;; *) # 其他未定义风味 (防止错误) RELEASE_TAG="v${VERSION_NAME}-${BUILD_FLAVOR}" CHANGELOG_TITLE="v${VERSION_NAME}-${BUILD_FLAVOR}" ;; esac RELEASE_NAME="v${VERSION_NAME} (${FLAVOR_NAME})" echo "Release Tag: $RELEASE_TAG" echo "Release Name: $RELEASE_NAME" # 设置输出变量供后续步骤使用 echo "changelog_title=$CHANGELOG_TITLE" >> $GITHUB_OUTPUT echo "release_tag=$RELEASE_TAG" >> $GITHUB_OUTPUT echo "release_name=$RELEASE_NAME" >> $GITHUB_OUTPUT # 2. 调用 Changelog Generator 并获取内容 - name: 📄 生成并获取更新日志内容 id: generate_changelog # 假设您的 Action 路径为 ./.github/actions/changelog-generator/ uses: ./.github/actions/changelog-generator with: version_title: ${{ steps.compute_names.outputs.changelog_title }} # previous_tag 留空,让 Action 内部的逻辑自动推导出上一个版本标签 # 3. 下载指定的 Artifact ZIP 文件 - name: 下载指定的 Artifact ZIP 文件 uses: actions/github-script@v7 id: download_artifact with: script: | // 从环境变量中获取参数 const build_flavor = process.env.BUILD_FLAVOR; const version_name = process.env.VERSION_NAME; const artifactId = process.env.ARTIFACT_ID; const artifactName = `app-${build_flavor}-release-apk`; const zipFileName = `${artifactName}.zip`; core.info(`准备发布版本:${version_name},风味:${build_flavor},开始下载 Artifact ID: ${artifactId}`); const download = await github.rest.actions.downloadArtifact({ owner: context.repo.owner, repo: context.repo.repo, artifact_id: artifactId, archive_format: 'zip', }); const fs = require('fs'); fs.writeFileSync(zipFileName, Buffer.from(download.data)); core.setOutput('zip_file', zipFileName); env: BUILD_FLAVOR: ${{ needs.prepare_review.outputs.build_flavor_out }} VERSION_NAME: ${{ needs.prepare_review.outputs.version_name_out }} ARTIFACT_ID: ${{ needs.prepare_review.outputs.artifact_id_out }} # 4. 解压 Artifact - name: 解压 Artifact 并设置所有 APK 路径 id: unzip_and_set_path run: | ARTIFACT_ZIP_FILE=${{ steps.download_artifact.outputs.zip_file }} echo "开始解压文件:$ARTIFACT_ZIP_FILE" mkdir -p artifacts/ unzip -o $ARTIFACT_ZIP_FILE -d ./artifacts/ ALL_APKS_PATH='./artifacts/*.apk' echo "设置文件上传路径(通配符):$ALL_APKS_PATH" echo "artifact_path=$ALL_APKS_PATH" >> $GITHUB_OUTPUT # 5. 创建 GitHub Release - name: 创建/更新 GitHub Release uses: softprops/action-gh-release@v2 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: # 使用计算出的最终标签名 tag_name: ${{ steps.compute_names.outputs.release_tag }} # 使用计算出的 Release 显示名称 name: ${{ steps.compute_names.outputs.release_name }} # 使用 Changelog Generator 的输出作为 Release 正文 body: ${{ steps.generate_changelog.outputs.changelog_content }} # 只有非 Prod 版本才设置为 Draft draft: ${{ needs.prepare_review.outputs.build_flavor_out != 'prod' }} # 只有 Dev 版本才设置为 Prerelease prerelease: ${{ needs.prepare_review.outputs.build_flavor_out == 'dev' }} files: ${{ steps.unzip_and_set_path.outputs.artifact_path }}