Release GitHub Tasks #27
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
| # Release GitHub Tasks Workflow | |
| # | |
| # This workflow handles GitHub-specific release tasks: | |
| # 1. Creates a Git tag for the release | |
| # 2. Creates a GitHub Release with release notes | |
| # 3. Creates a PR to merge release branch back to main | |
| # 4. Creates a PR to update PackageValidationBaselineVersion | |
| # | |
| # Designed for idempotency - safe to re-run after partial failures. | |
| # | |
| # Invocation paths: | |
| # - Manual: triggered by a release manager via the Actions UI. The `authorize` | |
| # job gates on admin/maintain permission for the dispatching user. | |
| # - Chained: dispatched automatically by the AzDO release-publish-nuget | |
| # pipeline running as the aspire-repo-bot GitHub App. The authorize job | |
| # recognizes this actor and bypasses the human permission check because | |
| # the AzDO pipeline itself gates on AzDO release-publish permissions. | |
| # | |
| # For full documentation, see: docs/release-process.md | |
| name: Release GitHub Tasks | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| release_version: | |
| description: 'Release version (e.g., 13.2.0)' | |
| required: true | |
| type: string | |
| commit_sha: | |
| description: 'Commit SHA to tag (from the signed build)' | |
| required: true | |
| type: string | |
| release_branch: | |
| description: 'Release branch name (e.g., release/9.2)' | |
| required: true | |
| type: string | |
| is_prerelease: | |
| description: 'Is this a preview/prerelease?' | |
| required: false | |
| type: boolean | |
| default: false | |
| dry_run: | |
| description: 'Dry run mode - validate and log actions without making changes' | |
| required: false | |
| type: boolean | |
| default: false | |
| # Idempotency flags for re-running after partial failures | |
| skip_tagging: | |
| description: 'Skip tag creation (set true if already completed)' | |
| required: false | |
| type: boolean | |
| default: false | |
| skip_github_release: | |
| description: 'Skip GitHub Release creation (set true if already completed)' | |
| required: false | |
| type: boolean | |
| default: false | |
| skip_merge_pr: | |
| description: 'Skip merge-back PR creation (set true if already completed)' | |
| required: false | |
| type: boolean | |
| default: false | |
| skip_baseline_pr: | |
| description: 'Skip baseline version PR creation (set true if already completed)' | |
| required: false | |
| type: boolean | |
| default: false | |
| # Limit to one release at a time | |
| concurrency: | |
| group: release-github-tasks | |
| cancel-in-progress: false | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| jobs: | |
| # Three-job layout: | |
| # - `release` does the linear, must-be-sequential work (authorize, tag, | |
| # GitHub release). Splitting these would buy nothing because they | |
| # strictly depend on each other. | |
| # - `merge-pr` and `baseline-pr` run in parallel after `release`. They are | |
| # independent (a failure in one must NOT block the other — that was the | |
| # pre-consolidation behavior we want to preserve), so they each pay | |
| # their own runner-provision tax but run concurrently. | |
| # - `summary` joins on all three with `if: always()` and prints the final | |
| # status. | |
| # | |
| # Each step preserves the previous per-job `if:` gating against the | |
| # `skip_*` inputs so partial-failure re-runs still behave the same way. | |
| release: | |
| name: Release Tasks | |
| runs-on: ubuntu-latest | |
| steps: | |
| # --- Authorize --------------------------------------------------------- | |
| - name: Authorize | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| ACTOR="${{ github.actor }}" | |
| ACTOR_ID="${{ github.actor_id }}" | |
| echo "Checking if $ACTOR (id=$ACTOR_ID) is authorized to run releases..." | |
| # The AzDO release pipeline dispatches this workflow as the | |
| # aspire-repo-bot GitHub App. That path is already gated on AzDO | |
| # release-publish permissions, so we skip the human admin/maintain | |
| # check for the bot after verifying the actor identity. | |
| if [[ "$ACTOR" == "aspire-repo-bot[bot]" ]]; then | |
| ACTOR_INFO=$(gh api "users/$ACTOR" 2>/dev/null || echo '') | |
| ACTOR_TYPE=$(echo "$ACTOR_INFO" | jq -r '.type // empty') | |
| ACTOR_API_ID=$(echo "$ACTOR_INFO" | jq -r '.id // empty') | |
| if [[ "$ACTOR_TYPE" != "Bot" ]]; then | |
| echo "❌ ERROR: $ACTOR resolves to account type '$ACTOR_TYPE', expected 'Bot'." | |
| exit 1 | |
| fi | |
| if [[ -z "$ACTOR_ID" || -z "$ACTOR_API_ID" || "$ACTOR_ID" != "$ACTOR_API_ID" ]]; then | |
| echo "❌ ERROR: actor_id mismatch (context=$ACTOR_ID, api=$ACTOR_API_ID)." | |
| exit 1 | |
| fi | |
| echo "✓ Verified dispatcher is aspire-repo-bot GitHub App (type=Bot, id=$ACTOR_API_ID) — skipping human permission check." | |
| exit 0 | |
| fi | |
| # Get the user's permission level for this repo | |
| PERMISSION=$(gh api repos/${{ github.repository }}/collaborators/$ACTOR/permission --jq '.permission') | |
| echo "User permission level: $PERMISSION" | |
| # Only allow admin or maintain permission levels | |
| if [[ "$PERMISSION" != "admin" && "$PERMISSION" != "maintain" ]]; then | |
| echo "❌ ERROR: User $ACTOR does not have sufficient permissions." | |
| echo "Required: 'admin' or 'maintain' permission level." | |
| echo "Current: '$PERMISSION'" | |
| exit 1 | |
| fi | |
| echo "✓ User $ACTOR is authorized (permission: $PERMISSION)" | |
| # --- Validate ---------------------------------------------------------- | |
| - name: Print Parameters | |
| run: | | |
| echo "=== Release Workflow Parameters ===" | |
| echo "Release Version: ${{ inputs.release_version }}" | |
| echo "Commit SHA: ${{ inputs.commit_sha }}" | |
| echo "Release Branch: ${{ inputs.release_branch }}" | |
| echo "Is Prerelease: ${{ inputs.is_prerelease }}" | |
| echo "Dry Run: ${{ inputs.dry_run }}" | |
| echo "Skip Tagging: ${{ inputs.skip_tagging }}" | |
| echo "Skip GitHub Release: ${{ inputs.skip_github_release }}" | |
| echo "Skip Merge PR: ${{ inputs.skip_merge_pr }}" | |
| echo "Skip Baseline PR: ${{ inputs.skip_baseline_pr }}" | |
| echo "===================================" | |
| if [ "${{ inputs.dry_run }}" == "true" ]; then | |
| echo "" | |
| echo "⚠️ DRY RUN MODE ENABLED" | |
| echo " All operations will be simulated - no actual changes will be made." | |
| echo "" | |
| fi | |
| - name: Validate Version Format | |
| run: | | |
| VERSION="${{ inputs.release_version }}" | |
| if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9\.]+)?$ ]]; then | |
| echo "❌ Invalid version format: $VERSION" | |
| echo "Expected format: major.minor.patch[-prerelease]" | |
| exit 1 | |
| fi | |
| echo "✓ Version format is valid: $VERSION" | |
| - name: Validate Commit SHA | |
| run: | | |
| SHA="${{ inputs.commit_sha }}" | |
| if [[ ! "$SHA" =~ ^[a-f0-9]{40}$ ]]; then | |
| echo "❌ Invalid commit SHA format: $SHA" | |
| echo "Expected a 40-character hex string" | |
| exit 1 | |
| fi | |
| echo "✓ Commit SHA format is valid: $SHA" | |
| # --- App token and checkout (shared by all subsequent steps) ---------- | |
| # Mint the aspire-repo-bot App installation token. Used by every step | |
| # that needs to fire a downstream event (release create, PR create, | |
| # branch push). Using the App token instead of the default GITHUB_TOKEN | |
| # causes the `release: released` event to actually trigger | |
| # release-notes-generate.lock.yml (events fired by GITHUB_TOKEN do not | |
| # cascade into other workflow runs). | |
| - name: Generate GitHub App Token | |
| id: app-token | |
| uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1 | |
| with: | |
| app-id: ${{ secrets.ASPIRE_BOT_APP_ID }} | |
| private-key: ${{ secrets.ASPIRE_BOT_PRIVATE_KEY }} | |
| # Single checkout with full history. The tag-creation step needs all | |
| # branches/tags reachable (fetch-depth: 0). The baseline-pr step | |
| # explicitly switches to main before modifying files. | |
| - name: Checkout Repository | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| fetch-depth: 0 | |
| token: ${{ steps.app-token.outputs.token }} | |
| # --- Create Tag -------------------------------------------------------- | |
| - name: Check if Tag Exists | |
| id: check-tag | |
| if: inputs.skip_tagging != true | |
| run: | | |
| TAG_NAME="v${{ inputs.release_version }}" | |
| if git rev-parse "$TAG_NAME" >/dev/null 2>&1; then | |
| EXISTING_SHA=$(git rev-parse "$TAG_NAME") | |
| if [ "$EXISTING_SHA" == "${{ inputs.commit_sha }}" ]; then | |
| echo "✓ Tag $TAG_NAME already exists and points to the correct commit" | |
| echo "tag_exists=true" >> $GITHUB_OUTPUT | |
| echo "tag_matches=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "⚠️ Tag $TAG_NAME exists but points to different commit!" | |
| echo " Existing: $EXISTING_SHA" | |
| echo " Expected: ${{ inputs.commit_sha }}" | |
| echo "tag_exists=true" >> $GITHUB_OUTPUT | |
| echo "tag_matches=false" >> $GITHUB_OUTPUT | |
| fi | |
| else | |
| echo "Tag $TAG_NAME does not exist yet" | |
| echo "tag_exists=false" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Fail if Tag Exists with Different SHA | |
| if: inputs.skip_tagging != true && steps.check-tag.outputs.tag_exists == 'true' && steps.check-tag.outputs.tag_matches == 'false' | |
| run: | | |
| echo "❌ Tag already exists but points to a different commit!" | |
| echo "This requires manual resolution." | |
| exit 1 | |
| - name: Create and Push Tag | |
| if: inputs.skip_tagging != true && steps.check-tag.outputs.tag_exists != 'true' | |
| run: | | |
| TAG_NAME="v${{ inputs.release_version }}" | |
| DRY_RUN="${{ inputs.dry_run }}" | |
| if [ "$DRY_RUN" == "true" ]; then | |
| echo "🔍 [DRY RUN] Would create and push tag:" | |
| echo " Tag name: $TAG_NAME" | |
| echo " Target commit: ${{ inputs.commit_sha }}" | |
| echo " Command: git tag \"$TAG_NAME\" \"${{ inputs.commit_sha }}\"" | |
| echo " Command: git push origin \"$TAG_NAME\"" | |
| else | |
| git tag "$TAG_NAME" "${{ inputs.commit_sha }}" | |
| git push origin "$TAG_NAME" | |
| echo "✓ Created and pushed tag: $TAG_NAME" | |
| fi | |
| # --- Create GitHub Release -------------------------------------------- | |
| - name: Check if Release Exists | |
| id: check-release | |
| if: inputs.skip_github_release != true | |
| env: | |
| # Read-only check, no event fired — github.token is fine. | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| TAG_NAME="v${{ inputs.release_version }}" | |
| if gh release view "$TAG_NAME" >/dev/null 2>&1; then | |
| echo "✓ Release $TAG_NAME already exists" | |
| echo "release_exists=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "Release $TAG_NAME does not exist yet" | |
| echo "release_exists=false" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Generate Release Notes | |
| if: inputs.skip_github_release != true && steps.check-release.outputs.release_exists != 'true' | |
| id: release-notes | |
| run: | | |
| # Write a short placeholder. The real release notes are generated | |
| # asynchronously by the release-notes-generate agentic workflow, | |
| # which fires on the `release: [released]` event once `gh release | |
| # create` below publishes the release, and edits this body in | |
| # place. | |
| cat << EOF > release_notes.md | |
| *Release notes are being generated automatically and will be added to this release shortly. If they haven't appeared within a few hours, ping the Aspire team.* | |
| --- | |
| *Full commit: [${{ inputs.commit_sha }}](https://github.com/${{ github.repository }}/commit/${{ inputs.commit_sha }})* | |
| EOF | |
| echo "Placeholder release notes generated" | |
| - name: Create GitHub Release | |
| if: inputs.skip_github_release != true && steps.check-release.outputs.release_exists != 'true' | |
| env: | |
| # Use the App token here so the `release: released` event is | |
| # authored by aspire-repo-bot and downstream workflows | |
| # (release-notes-generate.lock.yml) get triggered. Events fired by | |
| # GITHUB_TOKEN intentionally do NOT trigger other workflows. | |
| GH_TOKEN: ${{ steps.app-token.outputs.token }} | |
| run: | | |
| TAG_NAME="v${{ inputs.release_version }}" | |
| DRY_RUN="${{ inputs.dry_run }}" | |
| PRERELEASE_FLAG="" | |
| if [ "${{ inputs.is_prerelease }}" == "true" ]; then | |
| PRERELEASE_FLAG="--prerelease" | |
| fi | |
| if [ "$DRY_RUN" == "true" ]; then | |
| echo "🔍 [DRY RUN] Would create GitHub Release:" | |
| echo " Tag: $TAG_NAME" | |
| echo " Title: Aspire ${{ inputs.release_version }}" | |
| echo " Target: ${{ inputs.commit_sha }}" | |
| echo " Prerelease: ${{ inputs.is_prerelease }}" | |
| echo "" | |
| echo " Release notes content:" | |
| echo " ─────────────────────────────────────" | |
| cat release_notes.md | |
| echo " ─────────────────────────────────────" | |
| else | |
| gh release create "$TAG_NAME" \ | |
| --title "Aspire ${{ inputs.release_version }}" \ | |
| --notes-file release_notes.md \ | |
| --target "${{ inputs.commit_sha }}" \ | |
| $PRERELEASE_FLAG | |
| echo "✓ Created GitHub Release: $TAG_NAME" | |
| fi | |
| # ---------------------------------------------------------------------------- | |
| # merge-pr: runs in parallel with baseline-pr after the release job. A | |
| # failure here must NOT block baseline-pr (and vice versa) — that matches | |
| # the pre-consolidation per-job design. | |
| # ---------------------------------------------------------------------------- | |
| merge-pr: | |
| name: Create Merge-Back PR | |
| needs: release | |
| if: inputs.skip_merge_pr != true | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| steps: | |
| - name: Generate GitHub App Token | |
| id: app-token | |
| uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1 | |
| with: | |
| app-id: ${{ secrets.ASPIRE_BOT_APP_ID }} | |
| private-key: ${{ secrets.ASPIRE_BOT_PRIVATE_KEY }} | |
| - name: Checkout Repository | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| fetch-depth: 0 | |
| token: ${{ steps.app-token.outputs.token }} | |
| - name: Check for Existing Merge PR | |
| id: check-merge-pr | |
| env: | |
| GH_TOKEN: ${{ steps.app-token.outputs.token }} | |
| run: | | |
| RELEASE_BRANCH="${{ inputs.release_branch }}" | |
| EXISTING_PR=$(gh pr list --head "$RELEASE_BRANCH" --base main --json number --jq '.[0].number // empty') | |
| if [ -n "$EXISTING_PR" ]; then | |
| echo "✓ Merge PR already exists: #$EXISTING_PR" | |
| echo "pr_exists=true" >> $GITHUB_OUTPUT | |
| echo "pr_number=$EXISTING_PR" >> $GITHUB_OUTPUT | |
| else | |
| echo "No existing merge PR found" | |
| echo "pr_exists=false" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Dry Run - Show Merge PR Details | |
| if: steps.check-merge-pr.outputs.pr_exists != 'true' && inputs.dry_run == true | |
| run: | | |
| echo "🔍 [DRY RUN] Would create merge PR:" | |
| echo " Title: Merge ${{ inputs.release_branch }} to main after v${{ inputs.release_version }} release" | |
| echo " Head branch: ${{ inputs.release_branch }}" | |
| echo " Base branch: main" | |
| echo " Labels: area-engineering-systems" | |
| echo "" | |
| echo " PR body:" | |
| echo " ─────────────────────────────────────" | |
| echo " This PR merges the \`${{ inputs.release_branch }}\` branch back to \`main\` after the v${{ inputs.release_version }} release." | |
| echo "" | |
| echo " ## Checklist" | |
| echo " - [ ] Verify all release-specific changes are appropriate for main" | |
| echo " - [ ] Resolve any merge conflicts" | |
| echo " - [ ] Ensure CI passes" | |
| echo " ─────────────────────────────────────" | |
| - name: Create Merge PR | |
| if: steps.check-merge-pr.outputs.pr_exists != 'true' && inputs.dry_run != true | |
| uses: ./.github/actions/create-pull-request | |
| with: | |
| token: ${{ steps.app-token.outputs.token }} | |
| title: "Merge ${{ inputs.release_branch }} to main after v${{ inputs.release_version }} release" | |
| body: | | |
| This PR merges the `${{ inputs.release_branch }}` branch back to `main` after the v${{ inputs.release_version }} release. | |
| ## Checklist | |
| - [ ] Verify all release-specific changes are appropriate for main | |
| - [ ] Resolve any merge conflicts | |
| - [ ] Ensure CI passes | |
| --- | |
| *Created automatically by the release workflow.* | |
| branch: ${{ inputs.release_branch }} | |
| base: main | |
| branch-already-exists: 'true' | |
| labels: | | |
| area-engineering-systems | |
| # ---------------------------------------------------------------------------- | |
| # baseline-pr: runs in parallel with merge-pr after the release job. | |
| # ---------------------------------------------------------------------------- | |
| baseline-pr: | |
| name: Create Baseline Version PR | |
| needs: release | |
| if: inputs.skip_baseline_pr != true && inputs.is_prerelease != true | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| steps: | |
| - name: Generate GitHub App Token | |
| id: app-token | |
| uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1 | |
| with: | |
| app-id: ${{ secrets.ASPIRE_BOT_APP_ID }} | |
| private-key: ${{ secrets.ASPIRE_BOT_PRIVATE_KEY }} | |
| # Checkout main directly — the baseline-update branch is meant to be | |
| # branched off main, not off the release branch the workflow was | |
| # dispatched from. | |
| - name: Checkout main | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| ref: main | |
| fetch-depth: 0 | |
| token: ${{ steps.app-token.outputs.token }} | |
| - name: Check for Existing Baseline PR | |
| id: check-baseline-pr | |
| env: | |
| GH_TOKEN: ${{ steps.app-token.outputs.token }} | |
| run: | | |
| BRANCH_NAME="update-baseline-${{ inputs.release_version }}" | |
| EXISTING_PR=$(gh pr list --head "$BRANCH_NAME" --json number --jq '.[0].number // empty') | |
| if [ -n "$EXISTING_PR" ]; then | |
| echo "✓ Baseline update PR already exists: #$EXISTING_PR" | |
| echo "pr_exists=true" >> $GITHUB_OUTPUT | |
| echo "pr_number=$EXISTING_PR" >> $GITHUB_OUTPUT | |
| else | |
| echo "No existing baseline update PR found" | |
| echo "pr_exists=false" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Update PackageValidationBaselineVersion | |
| if: steps.check-baseline-pr.outputs.pr_exists != 'true' | |
| run: | | |
| VERSION="${{ inputs.release_version }}" | |
| FILE="src/Directory.Build.props" | |
| echo "Updating PackageValidationBaselineVersion to $VERSION in $FILE" | |
| # Use sed to update the version - pattern matches the actual format in Directory.Build.props | |
| # Format: <PackageValidationBaselineVersion Condition="'$(EnablePackageValidation)' == 'true' and '$(PackageValidationBaselineVersion)' == ''">VERSION</PackageValidationBaselineVersion> | |
| sed -i -E "s#(<PackageValidationBaselineVersion[^>]*>)[^<]*(</PackageValidationBaselineVersion>)#\1$VERSION\2#" "$FILE" | |
| echo "✓ Updated $FILE" | |
| echo "" | |
| echo "Changes made:" | |
| if git diff --quiet "$FILE"; then | |
| echo "::error::No changes detected in $FILE - PackageValidationBaselineVersion element may be missing or pattern did not match" | |
| exit 1 | |
| fi | |
| git diff "$FILE" | |
| - name: Dry Run - Show Baseline PR Details | |
| if: steps.check-baseline-pr.outputs.pr_exists != 'true' && inputs.dry_run == true | |
| run: | | |
| VERSION="${{ inputs.release_version }}" | |
| BRANCH_NAME="update-baseline-$VERSION" | |
| echo "🔍 [DRY RUN] Would create baseline version PR:" | |
| echo " Title: Update PackageValidationBaselineVersion to $VERSION" | |
| echo " Branch: $BRANCH_NAME" | |
| echo " Base: main" | |
| echo " Labels: area-engineering-systems" | |
| echo "" | |
| echo " File changes (src/Directory.Build.props):" | |
| echo " ─────────────────────────────────────" | |
| git diff src/Directory.Build.props || echo " (diff shown above)" | |
| echo " ─────────────────────────────────────" | |
| echo "" | |
| echo " Commit message: Update PackageValidationBaselineVersion to $VERSION" | |
| - name: Create Branch and Commit for Baseline PR | |
| if: steps.check-baseline-pr.outputs.pr_exists != 'true' && inputs.dry_run != true | |
| run: | | |
| BRANCH_NAME="update-baseline-${{ inputs.release_version }}" | |
| VERSION="${{ inputs.release_version }}" | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| git checkout -b "$BRANCH_NAME" | |
| git add src/Directory.Build.props | |
| git commit -m "Update PackageValidationBaselineVersion to $VERSION" | |
| git push origin "$BRANCH_NAME" | |
| echo "✓ Created branch: $BRANCH_NAME" | |
| - name: Create Baseline PR | |
| if: steps.check-baseline-pr.outputs.pr_exists != 'true' && inputs.dry_run != true | |
| uses: ./.github/actions/create-pull-request | |
| with: | |
| token: ${{ steps.app-token.outputs.token }} | |
| title: "Update PackageValidationBaselineVersion to ${{ inputs.release_version }}" | |
| body: | | |
| This PR updates the `PackageValidationBaselineVersion` to `${{ inputs.release_version }}` after the release. | |
| This ensures that future builds validate API compatibility against this release. | |
| ## Changes | |
| - Updated `src/Directory.Build.props` with new baseline version | |
| --- | |
| *Created automatically by the release workflow.* | |
| branch: update-baseline-${{ inputs.release_version }} | |
| base: main | |
| branch-already-exists: 'true' | |
| labels: | | |
| area-engineering-systems | |
| # ---------------------------------------------------------------------------- | |
| # summary: joins all upstream jobs with `if: always()` and reports the | |
| # final outcome. Uses `needs.*.result` to surface per-job status because | |
| # the work is no longer in a single job. | |
| # ---------------------------------------------------------------------------- | |
| summary: | |
| name: Summary | |
| needs: [release, merge-pr, baseline-pr] | |
| if: always() | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Print Summary | |
| run: | | |
| echo "" | |
| if [ "${{ inputs.dry_run }}" == "true" ]; then | |
| echo "╔═══════════════════════════════════════════════════════════════╗" | |
| echo "║ 🔍 DRY RUN - NO CHANGES WERE MADE 🔍 ║" | |
| echo "╠═══════════════════════════════════════════════════════════════╣" | |
| else | |
| echo "╔═══════════════════════════════════════════════════════════════╗" | |
| echo "║ GITHUB RELEASE SUMMARY ║" | |
| echo "╠═══════════════════════════════════════════════════════════════╣" | |
| fi | |
| echo "║ Version: ${{ inputs.release_version }}" | |
| echo "║ Commit SHA: ${{ inputs.commit_sha }}" | |
| echo "║ Release Branch: ${{ inputs.release_branch }}" | |
| echo "║ Is Prerelease: ${{ inputs.is_prerelease }}" | |
| echo "║ Dry Run: ${{ inputs.dry_run }}" | |
| echo "║ Skip Tagging: ${{ inputs.skip_tagging }}" | |
| echo "║ Skip GitHub Release: ${{ inputs.skip_github_release }}" | |
| echo "║ Skip Merge PR: ${{ inputs.skip_merge_pr }}" | |
| echo "║ Skip Baseline PR: ${{ inputs.skip_baseline_pr }}" | |
| echo "╠═══════════════════════════════════════════════════════════════╣" | |
| echo "║ Release job: ${{ needs.release.result }}" | |
| echo "║ Merge PR job: ${{ needs.merge-pr.result }}" | |
| echo "║ Baseline PR job: ${{ needs.baseline-pr.result }}" | |
| echo "╚═══════════════════════════════════════════════════════════════╝" | |
| echo "" | |
| - name: Create Job Summary | |
| run: | | |
| DRY_RUN_BANNER="" | |
| if [ "${{ inputs.dry_run }}" == "true" ]; then | |
| DRY_RUN_BANNER="## 🔍 DRY RUN MODE - No changes were made | |
| This was a dry run execution. All validations and checks were performed, but no tags, releases, or PRs were created. | |
| --- | |
| " | |
| fi | |
| # Map a needs.*.result string to an icon for the summary table. | |
| render_status() { | |
| case "$1" in | |
| success) echo "✅ \`success\`" ;; | |
| failure) echo "❌ \`failure\`" ;; | |
| cancelled) echo "⏹️ \`cancelled\`" ;; | |
| skipped) echo "⏭️ \`skipped\`" ;; | |
| *) echo "❔ \`$1\`" ;; | |
| esac | |
| } | |
| RELEASE_STATUS=$(render_status "${{ needs.release.result }}") | |
| MERGE_STATUS=$(render_status "${{ needs.merge-pr.result }}") | |
| BASELINE_STATUS=$(render_status "${{ needs.baseline-pr.result }}") | |
| cat << EOF >> $GITHUB_STEP_SUMMARY | |
| # Release Summary: v${{ inputs.release_version }} | |
| ${DRY_RUN_BANNER}## Job results | |
| | Job | Result | | |
| |-----|--------| | |
| | Release Tasks (tag + GitHub release) | ${RELEASE_STATUS} | | |
| | Create Merge-Back PR | ${MERGE_STATUS} | | |
| | Create Baseline Version PR | ${BASELINE_STATUS} | | |
| ## Details | |
| - **Tag**: v${{ inputs.release_version }} | |
| - **Commit**: \`${{ inputs.commit_sha }}\` | |
| - **Branch**: ${{ inputs.release_branch }} | |
| - **Prerelease**: ${{ inputs.is_prerelease }} | |
| - **Dry Run**: ${{ inputs.dry_run }} | |
| - **Skip Tagging**: ${{ inputs.skip_tagging }} | |
| - **Skip GitHub Release**: ${{ inputs.skip_github_release }} | |
| - **Skip Merge PR**: ${{ inputs.skip_merge_pr }} | |
| - **Skip Baseline PR**: ${{ inputs.skip_baseline_pr }} | |
| ## Links | |
| - [Release](https://github.com/${{ github.repository }}/releases/tag/v${{ inputs.release_version }}) | |
| - [Tag](https://github.com/${{ github.repository }}/tree/v${{ inputs.release_version }}) | |
| EOF |