Auto-merge on Approval #112
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
| # ------------------------------------------------------------------------------------ | |
| # Auto-merge on Approval Workflow | |
| # | |
| # Purpose: Automatically enable auto-merge for PRs when configurable approval | |
| # and readiness conditions are met. GitHub handles the actual merge | |
| # when all status checks pass. | |
| # | |
| # Configuration: All settings are loaded from .env.base and .env.custom files for | |
| # centralized management across all workflows. | |
| # | |
| # Triggers: | |
| # - Pull request reviews (submitted) | |
| # - Pull request state changes (ready_for_review, review_request_removed) | |
| # | |
| # Auto-merge Rules (configurable via .env.base/.env.custom): | |
| # - Minimum number of approvals | |
| # - No requested reviewers remaining (if configured) | |
| # - No "Changes Requested" reviews | |
| # - PR ready for review (not draft, no WIP indicators) | |
| # - Bot PRs handled separately (if configured) | |
| # | |
| # Maintainer: @mrz1836 | |
| # | |
| # ------------------------------------------------------------------------------------ | |
| name: Auto-merge on Approval | |
| # -------------------------------------------------------------------- | |
| # Trigger Configuration | |
| # -------------------------------------------------------------------- | |
| on: | |
| pull_request_review: | |
| types: [submitted] | |
| pull_request: | |
| types: [ready_for_review, review_request_removed] | |
| # Security: Restrictive default permissions with job-level overrides for least privilege access | |
| permissions: | |
| contents: read # Default read-only access to repository contents | |
| pull-requests: read # Default read access to pull requests | |
| # -------------------------------------------------------------------- | |
| # Concurrency Control | |
| # -------------------------------------------------------------------- | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} | |
| cancel-in-progress: true | |
| # -------------------------------------------------------------------- | |
| # Environment Variables | |
| # -------------------------------------------------------------------- | |
| # Note: Configuration variables are loaded from .env.base and .env.custom files | |
| jobs: | |
| # ---------------------------------------------------------------------------------- | |
| # Load Environment Variables | |
| # ---------------------------------------------------------------------------------- | |
| load-env: | |
| name: 🌍 Load Environment Variables | |
| runs-on: ubuntu-latest | |
| outputs: | |
| env-json: ${{ steps.load-env.outputs.env-json }} | |
| steps: | |
| # -------------------------------------------------------------------- | |
| # Check out code to access env file | |
| # -------------------------------------------------------------------- | |
| - name: 📥 Checkout code (sparse) | |
| uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 | |
| with: | |
| sparse-checkout: | | |
| .github/.env.base | |
| .github/.env.custom | |
| .github/actions/load-env | |
| # -------------------------------------------------------------------- | |
| # Load and parse environment file | |
| # -------------------------------------------------------------------- | |
| - name: 🌍 Load environment variables | |
| uses: ./.github/actions/load-env | |
| id: load-env | |
| # ---------------------------------------------------------------------------------- | |
| # Process Auto-merge | |
| # ---------------------------------------------------------------------------------- | |
| process-auto-merge: | |
| name: 🤖 Process Auto-merge | |
| needs: [load-env] | |
| runs-on: ubuntu-latest | |
| permissions: | |
| pull-requests: write # Required: Update PR status and enable auto-merge | |
| issues: write # Required: Add labels and create comments | |
| outputs: | |
| action-taken: ${{ steps.process.outputs.action }} | |
| pr-number: ${{ github.event.pull_request.number }} | |
| steps: | |
| # -------------------------------------------------------------------- | |
| # Extract configuration from env-json | |
| # -------------------------------------------------------------------- | |
| - name: 🔧 Extract configuration | |
| id: config | |
| env: | |
| ENV_JSON: ${{ needs.load-env.outputs.env-json }} | |
| run: | | |
| echo "📋 Extracting auto-merge configuration from environment..." | |
| # Extract all needed variables | |
| MIN_APPROVALS=$(echo "$ENV_JSON" | jq -r '.AUTO_MERGE_MIN_APPROVALS') | |
| REQUIRE_ALL_REVIEWS=$(echo "$ENV_JSON" | jq -r '.AUTO_MERGE_REQUIRE_ALL_REQUESTED_REVIEWS') | |
| MERGE_TYPES=$(echo "$ENV_JSON" | jq -r '.AUTO_MERGE_ALLOWED_MERGE_TYPES') | |
| DELETE_BRANCH=$(echo "$ENV_JSON" | jq -r '.AUTO_MERGE_DELETE_BRANCH') | |
| SKIP_DRAFT=$(echo "$ENV_JSON" | jq -r '.AUTO_MERGE_SKIP_DRAFT') | |
| SKIP_WIP=$(echo "$ENV_JSON" | jq -r '.AUTO_MERGE_SKIP_WIP') | |
| WIP_LABELS=$(echo "$ENV_JSON" | jq -r '.AUTO_MERGE_WIP_LABELS') | |
| COMMENT_ON_ENABLE=$(echo "$ENV_JSON" | jq -r '.AUTO_MERGE_COMMENT_ON_ENABLE') | |
| COMMENT_ON_DISABLE=$(echo "$ENV_JSON" | jq -r '.AUTO_MERGE_COMMENT_ON_DISABLE') | |
| LABELS_TO_ADD=$(echo "$ENV_JSON" | jq -r '.AUTO_MERGE_LABELS_TO_ADD') | |
| SKIP_BOT_PRS=$(echo "$ENV_JSON" | jq -r '.AUTO_MERGE_SKIP_BOT_PRS') | |
| SKIP_FORK_PRS=$(echo "$ENV_JSON" | jq -r '.AUTO_MERGE_SKIP_FORK_PRS') | |
| COMMENT_ON_FORK_SKIP=$(echo "$ENV_JSON" | jq -r '.AUTO_MERGE_COMMENT_ON_FORK_SKIP') | |
| AUTO_MERGE_REQUIRE_LABEL=$(echo "$ENV_JSON" | jq -r '.AUTO_MERGE_REQUIRE_LABEL') | |
| AUTO_MERGE_LABEL=$(echo "$ENV_JSON" | jq -r '.AUTO_MERGE_LABEL') | |
| PREFERRED_TOKEN=$(echo "$ENV_JSON" | jq -r '.PREFERRED_GITHUB_TOKEN') | |
| # Validate required configuration | |
| if [[ -z "$MIN_APPROVALS" ]] || [[ "$MIN_APPROVALS" == "null" ]]; then | |
| MIN_APPROVALS="1" # Default to 1 approval | |
| fi | |
| # Set as environment variables for all subsequent steps | |
| echo "MIN_APPROVALS=$MIN_APPROVALS" >> $GITHUB_ENV | |
| echo "REQUIRE_ALL_REVIEWS=$REQUIRE_ALL_REVIEWS" >> $GITHUB_ENV | |
| echo "MERGE_TYPES=$MERGE_TYPES" >> $GITHUB_ENV | |
| echo "DELETE_BRANCH=$DELETE_BRANCH" >> $GITHUB_ENV | |
| echo "SKIP_DRAFT=$SKIP_DRAFT" >> $GITHUB_ENV | |
| echo "SKIP_WIP=$SKIP_WIP" >> $GITHUB_ENV | |
| echo "WIP_LABELS=$WIP_LABELS" >> $GITHUB_ENV | |
| echo "COMMENT_ON_ENABLE=$COMMENT_ON_ENABLE" >> $GITHUB_ENV | |
| echo "COMMENT_ON_DISABLE=$COMMENT_ON_DISABLE" >> $GITHUB_ENV | |
| echo "LABELS_TO_ADD=$LABELS_TO_ADD" >> $GITHUB_ENV | |
| echo "SKIP_BOT_PRS=$SKIP_BOT_PRS" >> $GITHUB_ENV | |
| echo "SKIP_FORK_PRS=$SKIP_FORK_PRS" >> $GITHUB_ENV | |
| echo "COMMENT_ON_FORK_SKIP=$COMMENT_ON_FORK_SKIP" >> $GITHUB_ENV | |
| echo "AUTO_MERGE_REQUIRE_LABEL=$AUTO_MERGE_REQUIRE_LABEL" >> $GITHUB_ENV | |
| echo "AUTO_MERGE_LABEL=$AUTO_MERGE_LABEL" >> $GITHUB_ENV | |
| # Determine default merge type | |
| DEFAULT_MERGE_TYPE=$(echo "$MERGE_TYPES" | cut -d',' -f1) | |
| if [[ -z "$DEFAULT_MERGE_TYPE" ]]; then | |
| DEFAULT_MERGE_TYPE="squash" | |
| fi | |
| echo "DEFAULT_MERGE_TYPE=$DEFAULT_MERGE_TYPE" >> $GITHUB_ENV | |
| # Log configuration | |
| echo "🔍 Configuration loaded:" | |
| echo " ✅ Min approvals: $MIN_APPROVALS" | |
| echo " 👥 Require all reviews: $REQUIRE_ALL_REVIEWS" | |
| echo " 🔀 Merge types: $MERGE_TYPES (default: $DEFAULT_MERGE_TYPE)" | |
| echo " 🗑️ Delete branch: $DELETE_BRANCH" | |
| echo " 📝 Skip draft: $SKIP_DRAFT" | |
| echo " 🚧 Skip WIP: $SKIP_WIP" | |
| echo " 🏷️ WIP labels: $WIP_LABELS" | |
| echo " 💬 Comment on enable: $COMMENT_ON_ENABLE" | |
| echo " 💬 Comment on disable: $COMMENT_ON_DISABLE" | |
| echo " 🏷️ Labels to add: $LABELS_TO_ADD" | |
| echo " 🤖 Skip bot PRs: $SKIP_BOT_PRS" | |
| echo " 🍴 Skip fork PRs: $SKIP_FORK_PRS" | |
| echo " 💬 Comment on fork skip: $COMMENT_ON_FORK_SKIP" | |
| echo " 🏷️ Require automerge label: $AUTO_MERGE_REQUIRE_LABEL" | |
| echo " 🏷️ Automerge label name: $AUTO_MERGE_LABEL" | |
| echo " 🔑 Token: Selected via github-script action" | |
| # -------------------------------------------------------------------- | |
| # Process the PR for auto-merge | |
| # -------------------------------------------------------------------- | |
| - name: 🔍 Check conditions and enable auto-merge | |
| id: process | |
| uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 | |
| with: | |
| github-token: ${{ secrets.GH_PAT_TOKEN || secrets.GITHUB_TOKEN }} | |
| script: | | |
| const { owner, repo } = context.repo; | |
| const prNumber = context.payload.pull_request.number; | |
| console.log(`🔍 Checking auto-merge conditions for PR #${prNumber}`); | |
| console.log('════════════════════════════════════════════════════════════════'); | |
| // Get fresh PR data | |
| const { data: pr } = await github.rest.pulls.get({ | |
| owner, | |
| repo, | |
| pull_number: prNumber, | |
| }); | |
| console.log(`📋 PR #${prNumber}: "${pr.title}"`); | |
| console.log(`👤 Author: ${pr.user.login} (${pr.user.type})`); | |
| // ———————————————————————————————————————————————————————————————— | |
| // Check if we should skip bot PRs | |
| // ———————————————————————————————————————————————————————————————— | |
| const isBot = pr.user.type === 'Bot' || pr.user.login.endsWith('[bot]'); | |
| if (isBot && process.env.SKIP_BOT_PRS === 'true') { | |
| console.log('🤖 Skipping bot PR (handled by separate workflow)'); | |
| core.setOutput('action', 'skip-bot'); | |
| return; | |
| } | |
| // ———————————————————————————————————————————————————————————————— | |
| // Check if we should skip fork PRs | |
| // ———————————————————————————————————————————————————————————————— | |
| // Handle edge case: fork repository deleted/inaccessible (pr.head.repo is null) | |
| if (!pr.head.repo) { | |
| console.log('⚠️ PR head repository is null (fork may have been deleted)'); | |
| if (process.env.SKIP_FORK_PRS === 'true') { | |
| console.log('🍴 Skipping PR with deleted fork source (security policy)'); | |
| core.setOutput('action', 'skip-deleted-fork'); | |
| return; | |
| } | |
| // If not skipping forks, log and continue (will be treated as same-repo PR) | |
| console.log('⚠️ Continuing with auto-merge processing (null repo treated as same-repo)'); | |
| } else { | |
| // Safe to access pr.head.repo.full_name now | |
| const headRepoFullName = pr.head.repo.full_name; | |
| const baseRepoFullName = `${owner}/${repo}`; | |
| const isForkPR = headRepoFullName !== baseRepoFullName; | |
| if (isForkPR && process.env.SKIP_FORK_PRS === 'true') { | |
| console.log('🍴 Skipping fork PR (security policy: fork PRs are not auto-merged)'); | |
| console.log(` Fork source: ${headRepoFullName}`); | |
| console.log(` Base repository: ${baseRepoFullName}`); | |
| console.log(' Security reason: Fork PRs require manual maintainer review before merge'); | |
| // Note: Comments are not posted to fork PRs due to read-only GITHUB_TOKEN permissions | |
| // Fork PR handling is already managed by pull-request-management-fork.yml workflow | |
| if (process.env.COMMENT_ON_FORK_SKIP === 'true') { | |
| console.log(' ℹ️ Comment posting skipped for fork PR (handled by fork PR workflow)'); | |
| } | |
| core.setOutput('action', 'skip-fork'); | |
| return; | |
| } | |
| } | |
| // ———————————————————————————————————————————————————————————————— | |
| // Check basic PR conditions | |
| // ———————————————————————————————————————————————————————————————— | |
| const isDraft = pr.draft; | |
| const title = pr.title || ''; | |
| const labels = pr.labels.map(l => l.name); | |
| if (isDraft && process.env.SKIP_DRAFT === 'true') { | |
| console.log('📝 PR is draft - skipping auto-merge'); | |
| core.setOutput('action', 'skip-draft'); | |
| return; | |
| } | |
| // Check for WIP indicators | |
| if (process.env.SKIP_WIP === 'true') { | |
| const titleHasWip = /\b(wip|work.in.progress)\b/i.test(title); | |
| const wipLabels = process.env.WIP_LABELS.split(',').map(l => l.trim()); | |
| const hasWipLabel = labels.some(label => wipLabels.includes(label)); | |
| if (titleHasWip || hasWipLabel) { | |
| console.log('🚧 PR has WIP indicators - skipping auto-merge'); | |
| core.setOutput('action', 'skip-wip'); | |
| return; | |
| } | |
| } | |
| // ———————————————————————————————————————————————————————————————— | |
| // Check for automerge label requirement | |
| // ———————————————————————————————————————————————————————————————— | |
| if (process.env.AUTO_MERGE_REQUIRE_LABEL === 'true') { | |
| const automergeLabel = process.env.AUTO_MERGE_LABEL || 'automerge'; | |
| const hasAutomergeLabel = labels.includes(automergeLabel); | |
| if (!hasAutomergeLabel) { | |
| console.log(`🏷️ Missing required label "${automergeLabel}" - skipping auto-merge`); | |
| core.setOutput('action', 'skip-missing-automerge-label'); | |
| return; | |
| } | |
| console.log(`✅ Has required automerge label: "${automergeLabel}"`); | |
| } | |
| // ———————————————————————————————————————————————————————————————— | |
| // Check review conditions | |
| // ———————————————————————————————————————————————————————————————— | |
| const { data: reviews } = await github.rest.pulls.listReviews({ | |
| owner, | |
| repo, | |
| pull_number: prNumber, | |
| }); | |
| // Get latest review per user | |
| const latestReviews = {}; | |
| reviews.forEach(review => { | |
| const userId = review.user.id; | |
| if (!latestReviews[userId] || review.submitted_at > latestReviews[userId].submitted_at) { | |
| latestReviews[userId] = review; | |
| } | |
| }); | |
| const currentReviews = Object.values(latestReviews); | |
| const approvals = currentReviews.filter(r => r.state === 'APPROVED').length; | |
| const changesRequested = currentReviews.filter(r => r.state === 'CHANGES_REQUESTED').length; | |
| const requestedReviewers = (pr.requested_reviewers || []).length; | |
| const minApprovals = parseInt(process.env.MIN_APPROVALS); | |
| console.log(`👥 Reviews: ${approvals} approvals, ${changesRequested} changes requested, ${requestedReviewers} pending`); | |
| console.log(`✅ Required approvals: ${minApprovals}`); | |
| // ———————————————————————————————————————————————————————————————— | |
| // Determine if we should enable auto-merge | |
| // ———————————————————————————————————————————————————————————————— | |
| let shouldEnableAutoMerge = approvals >= minApprovals && changesRequested === 0; | |
| if (process.env.REQUIRE_ALL_REVIEWS === 'true' && requestedReviewers > 0) { | |
| shouldEnableAutoMerge = false; | |
| } | |
| if (!shouldEnableAutoMerge) { | |
| if (approvals < minApprovals) { | |
| console.log(`⏳ Needs ${minApprovals - approvals} more approval(s)`); | |
| } | |
| if (changesRequested > 0) { | |
| console.log('🚫 Has "Changes Requested" reviews'); | |
| } | |
| if (process.env.REQUIRE_ALL_REVIEWS === 'true' && requestedReviewers > 0) { | |
| console.log(`⏳ Has ${requestedReviewers} pending reviewer request(s)`); | |
| } | |
| core.setOutput('action', 'conditions-not-met'); | |
| return; | |
| } | |
| // ———————————————————————————————————————————————————————————————— | |
| // Check if this is a disable event | |
| // ———————————————————————————————————————————————————————————————— | |
| if (context.eventName === 'pull_request_review' && | |
| context.payload.review && | |
| context.payload.review.state === 'CHANGES_REQUESTED') { | |
| // Try to disable auto-merge | |
| try { | |
| const { execSync } = require('child_process'); | |
| execSync(`gh pr merge --disable-auto "${pr.html_url}"`, { | |
| env: { | |
| ...process.env, | |
| GH_TOKEN: process.env.GITHUB_TOKEN | |
| }, | |
| stdio: 'inherit' | |
| }); | |
| console.log('🛑 Auto-merge disabled due to "Changes Requested" review'); | |
| if (process.env.COMMENT_ON_DISABLE === 'true') { | |
| await github.rest.issues.createComment({ | |
| owner, | |
| repo, | |
| issue_number: prNumber, | |
| body: `🛑 **Auto-merge disabled**\n\nChanges were requested in a review. Auto-merge will be re-enabled when conditions are met again.` | |
| }); | |
| } | |
| core.setOutput('action', 'disabled-changes-requested'); | |
| } catch (disableError) { | |
| // Differentiate between "not enabled" and actual failures | |
| if (disableError.message && ( | |
| disableError.message.includes('not enabled') || | |
| disableError.message.includes('auto-merge is not enabled') | |
| )) { | |
| console.log('ℹ️ Auto-merge was not enabled, no action needed'); | |
| } else { | |
| console.error(`❌ Failed to disable auto-merge: ${disableError.message}`); | |
| // Don't fail workflow, but log the error properly | |
| } | |
| } | |
| return; | |
| } | |
| // ———————————————————————————————————————————————————————————————— | |
| // Enable auto-merge | |
| // ———————————————————————————————————————————————————————————————— | |
| try { | |
| // Check if auto-merge is already enabled | |
| if (pr.auto_merge) { | |
| console.log('✅ Auto-merge already enabled'); | |
| core.setOutput('action', 'already-enabled'); | |
| return; | |
| } | |
| // Enable auto-merge with the configured merge type | |
| const { execSync } = require('child_process'); | |
| const mergeType = process.env.DEFAULT_MERGE_TYPE; | |
| let mergeCommand = `gh pr merge --auto`; | |
| if (mergeType === 'squash') { | |
| mergeCommand += ' --squash'; | |
| } else if (mergeType === 'merge') { | |
| mergeCommand += ' --merge'; | |
| } else if (mergeType === 'rebase') { | |
| mergeCommand += ' --rebase'; | |
| } | |
| if (process.env.DELETE_BRANCH === 'true') { | |
| mergeCommand += ' --delete-branch'; | |
| } | |
| mergeCommand += ` "${pr.html_url}"`; | |
| console.log(`🚀 Enabling auto-merge with command: ${mergeCommand}`); | |
| try { | |
| execSync(mergeCommand, { | |
| env: { | |
| ...process.env, | |
| GH_TOKEN: process.env.GITHUB_TOKEN | |
| }, | |
| stdio: 'inherit' | |
| }); | |
| console.log('✅ Auto-merge enabled! PR will merge when all status checks pass.'); | |
| } catch (enableError) { | |
| // Handle race condition: another workflow run may have enabled auto-merge | |
| if (enableError.message && ( | |
| enableError.message.includes('already enabled') || | |
| enableError.message.includes('auto-merge is already enabled') | |
| )) { | |
| console.log('ℹ️ Auto-merge already enabled by another workflow run'); | |
| core.setOutput('action', 'already-enabled'); | |
| return; | |
| } | |
| // Re-throw other errors to be caught by outer catch block | |
| throw enableError; | |
| } | |
| // Add comment if configured | |
| if (process.env.COMMENT_ON_ENABLE === 'true') { | |
| const mergeTypeText = mergeType === 'squash' ? 'squash and merge' : | |
| mergeType === 'merge' ? 'create a merge commit' : | |
| 'rebase and merge'; | |
| await github.rest.issues.createComment({ | |
| owner, | |
| repo, | |
| issue_number: prNumber, | |
| body: `🤖 **Auto-merge enabled**\n\nThis PR will automatically ${mergeTypeText} when all required status checks pass.\n\n` + | |
| `✅ Approvals: ${approvals}/${minApprovals}\n` + | |
| `🔍 Changes requested: ${changesRequested}\n` + | |
| `⏳ Pending reviews: ${requestedReviewers}` | |
| }); | |
| } | |
| // Add labels if configured | |
| if (process.env.LABELS_TO_ADD) { | |
| const labelsToAdd = process.env.LABELS_TO_ADD.split(',').map(l => l.trim()).filter(l => l); | |
| if (labelsToAdd.length > 0) { | |
| await github.rest.issues.addLabels({ | |
| owner, | |
| repo, | |
| issue_number: prNumber, | |
| labels: labelsToAdd | |
| }); | |
| console.log(`🏷️ Added labels: ${labelsToAdd.join(', ')}`); | |
| } | |
| } | |
| core.setOutput('action', 'enabled'); | |
| } catch (error) { | |
| console.error('❌ Failed to enable auto-merge:', error.message); | |
| // Comment on failure if configured | |
| if (process.env.COMMENT_ON_ENABLE === 'true') { | |
| await github.rest.issues.createComment({ | |
| owner, | |
| repo, | |
| issue_number: prNumber, | |
| body: `⚠️ **Auto-merge failed**\n\nCould not enable auto-merge: ${error.message}\n\n` + | |
| `This might be due to:\n` + | |
| `- Branch protection rules\n` + | |
| `- Missing permissions\n` + | |
| `- Repository settings` | |
| }); | |
| } | |
| core.setOutput('action', 'failed'); | |
| throw error; | |
| } | |
| # ---------------------------------------------------------------------------------- | |
| # Generate Workflow Summary Report | |
| # ---------------------------------------------------------------------------------- | |
| summary: | |
| name: 📊 Generate Summary | |
| if: always() | |
| needs: [load-env, process-auto-merge] | |
| runs-on: ubuntu-latest | |
| steps: | |
| # -------------------------------------------------------------------- | |
| # Generate a workflow summary report | |
| # -------------------------------------------------------------------- | |
| - name: 📊 Generate workflow summary | |
| env: | |
| ENV_JSON: ${{ needs.load-env.outputs.env-json }} | |
| run: | | |
| echo "📊 Generating workflow summary..." | |
| echo "# 🤖 Auto-merge on Approval Summary" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**⏰ Processed:** $(date -u '+%Y-%m-%d %H:%M:%S UTC')" >> $GITHUB_STEP_SUMMARY | |
| echo "**📋 PR:** #${{ needs.process-auto-merge.outputs.pr-number }}" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| # Determine action taken | |
| ACTION="${{ needs.process-auto-merge.outputs.action-taken }}" | |
| case "$ACTION" in | |
| "enabled") | |
| ACTION_DESC="✅ Auto-merge enabled" | |
| ;; | |
| "already-enabled") | |
| ACTION_DESC="✅ Auto-merge already enabled" | |
| ;; | |
| "disabled-changes-requested") | |
| ACTION_DESC="🛑 Auto-merge disabled (changes requested)" | |
| ;; | |
| "skip-bot") | |
| ACTION_DESC="🤖 Skipped (bot PR)" | |
| ;; | |
| "skip-fork") | |
| ACTION_DESC="🍴 Skipped (fork PR - security policy)" | |
| ;; | |
| "skip-deleted-fork") | |
| ACTION_DESC="🍴 Skipped (deleted fork PR)" | |
| ;; | |
| "skip-draft") | |
| ACTION_DESC="📝 Skipped (draft PR)" | |
| ;; | |
| "skip-wip") | |
| ACTION_DESC="🚧 Skipped (work in progress)" | |
| ;; | |
| "skip-missing-automerge-label") | |
| ACTION_DESC="🏷️ Skipped (missing automerge label)" | |
| ;; | |
| "conditions-not-met") | |
| ACTION_DESC="⏳ Conditions not met" | |
| ;; | |
| "failed") | |
| ACTION_DESC="❌ Failed to enable auto-merge" | |
| ;; | |
| *) | |
| ACTION_DESC="❓ Unknown action: $ACTION" | |
| ;; | |
| esac | |
| echo "## 🎯 Action Taken" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "$ACTION_DESC" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### 🔧 Current Configuration" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| # Extract configuration for display | |
| MIN_APPROVALS=$(echo "$ENV_JSON" | jq -r '.AUTO_MERGE_MIN_APPROVALS') | |
| REQUIRE_ALL_REVIEWS=$(echo "$ENV_JSON" | jq -r '.AUTO_MERGE_REQUIRE_ALL_REQUESTED_REVIEWS') | |
| MERGE_TYPES=$(echo "$ENV_JSON" | jq -r '.AUTO_MERGE_ALLOWED_MERGE_TYPES') | |
| SKIP_DRAFT=$(echo "$ENV_JSON" | jq -r '.AUTO_MERGE_SKIP_DRAFT') | |
| SKIP_WIP=$(echo "$ENV_JSON" | jq -r '.AUTO_MERGE_SKIP_WIP') | |
| SKIP_BOT_PRS=$(echo "$ENV_JSON" | jq -r '.AUTO_MERGE_SKIP_BOT_PRS') | |
| SKIP_FORK_PRS=$(echo "$ENV_JSON" | jq -r '.AUTO_MERGE_SKIP_FORK_PRS') | |
| echo "| Setting | Value |" >> $GITHUB_STEP_SUMMARY | |
| echo "|---------|-------|" >> $GITHUB_STEP_SUMMARY | |
| echo "| Min approvals | $MIN_APPROVALS |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Require all reviews | $REQUIRE_ALL_REVIEWS |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Allowed merge types | $MERGE_TYPES |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Skip draft PRs | $SKIP_DRAFT |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Skip WIP PRs | $SKIP_WIP |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Skip bot PRs | $SKIP_BOT_PRS |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Skip fork PRs | $SKIP_FORK_PRS |" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "---" >> $GITHUB_STEP_SUMMARY | |
| echo "🤖 _Automated by GitHub Actions_" >> $GITHUB_STEP_SUMMARY | |
| # -------------------------------------------------------------------- | |
| # Report final workflow status | |
| # -------------------------------------------------------------------- | |
| - name: 📢 Report workflow status | |
| run: | | |
| echo "=== 🤖 Auto-merge on Approval Summary ===" | |
| echo "📋 PR: #${{ needs.process-auto-merge.outputs.pr-number }}" | |
| ACTION="${{ needs.process-auto-merge.outputs.action-taken }}" | |
| case "$ACTION" in | |
| enabled) | |
| echo "✅ Action: Auto-merge enabled successfully" | |
| ;; | |
| already-enabled) | |
| echo "✅ Action: Auto-merge was already enabled" | |
| ;; | |
| disabled-changes-requested) | |
| echo "🛑 Action: Auto-merge disabled due to changes requested" | |
| ;; | |
| skip-fork) | |
| echo "🍴 Action: Skipped - Fork PR (security policy)" | |
| ;; | |
| skip-missing-automerge-label) | |
| echo "🏷️ Action: Skipped - Missing automerge label" | |
| ;; | |
| skip-*) | |
| echo "⏭️ Action: Skipped - $ACTION" | |
| ;; | |
| conditions-not-met) | |
| echo "⏳ Action: Waiting for conditions to be met" | |
| ;; | |
| failed) | |
| echo "❌ Action: Failed to enable auto-merge" | |
| ;; | |
| *) | |
| echo "❓ Action: $ACTION" | |
| ;; | |
| esac | |
| echo "🕐 Completed: $(date -u '+%Y-%m-%d %H:%M:%S UTC')" | |
| echo "✅ Workflow completed!" |