name: Auto-Merge on: pull_request_review: types: [submitted] status: {} check_run: types: [completed] pull_request: types: [labeled] permissions: contents: write pull-requests: write jobs: auto-merge: runs-on: ubuntu-latest if: | github.event.pull_request.state == 'open' && (contains(github.event.pull_request.labels.*.name, 'auto-merge') || contains(github.event.pull_request.labels.*.name, 'claude-auto') || contains(github.event.pull_request.labels.*.name, 'atlas-auto') || contains(github.event.pull_request.labels.*.name, 'codex-auto') || contains(github.event.pull_request.labels.*.name, 'docs-only') || contains(github.event.pull_request.labels.*.name, 'merge-ready')) && !contains(github.event.pull_request.labels.*.name, 'do-not-merge') && !contains(github.event.pull_request.labels.*.name, 'wip') && !contains(github.event.pull_request.labels.*.name, 'breaking-change') && !contains(github.event.pull_request.labels.*.name, 'security') && !contains(github.event.pull_request.labels.*.name, 'needs-review') steps: - name: Check all required checks passed uses: actions/github-script@v7 id: check-status with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | const { data: checks } = await github.rest.checks.listForRef({ owner: context.repo.owner, repo: context.repo.repo, ref: context.payload.pull_request.head.sha }); const allPassed = checks.check_runs.every(check => check.conclusion === 'success' || check.conclusion === 'skipped' || check.conclusion === 'neutral' ); console.log(`All checks passed: ${allPassed}`); return allPassed; - name: Check PR is approved id: check-approval run: | APPROVED=$(gh pr view ${{ github.event.pull_request.number }} --json reviewDecision --jq '.reviewDecision') if [ "$APPROVED" != "APPROVED" ]; then echo "PR not yet approved, skipping auto-merge" exit 1 fi echo "approved=true" >> $GITHUB_OUTPUT env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Determine soak time id: soak-time run: | SOAK_SECONDS=0 # AI-generated PRs: 5 minutes if [[ "${{ contains(github.event.pull_request.labels.*.name, 'claude-auto') }}" == "true" ]] || [[ "${{ contains(github.event.pull_request.labels.*.name, 'atlas-auto') }}" == "true" ]] || [[ "${{ contains(github.event.pull_request.labels.*.name, 'codex-auto') }}" == "true" ]]; then SOAK_SECONDS=300 fi # Dependency updates: 30 minutes if [[ "${{ github.actor }}" == "dependabot[bot]" ]]; then SOAK_SECONDS=1800 fi echo "soak_seconds=$SOAK_SECONDS" >> $GITHUB_OUTPUT echo "Soak time: $SOAK_SECONDS seconds" - name: Wait soak time if: steps.soak-time.outputs.soak_seconds != '0' run: | echo "Waiting ${{ steps.soak-time.outputs.soak_seconds }} seconds for soak period..." sleep ${{ steps.soak-time.outputs.soak_seconds }} - name: Merge PR if: | steps.check-status.outputs.result == 'true' && steps.check-approval.outputs.approved == 'true' uses: pascalgn/automerge-action@v0.16.2 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} MERGE_LABELS: auto-merge,claude-auto,atlas-auto,codex-auto,docs-only,tests-only,merge-ready MERGE_METHOD: squash MERGE_COMMIT_MESSAGE: pull-request-title MERGE_DELETE_BRANCH: true MERGE_RETRIES: 3 MERGE_RETRY_SLEEP: 60000 MERGE_REQUIRED_APPROVALS: 1 - name: Post merge comment if: success() run: | MERGE_TIME=$(date -u +"%Y-%m-%d %H:%M:%S UTC") gh pr comment ${{ github.event.pull_request.number }} --body "✅ **Auto-Merged Successfully** **Merged At**: $MERGE_TIME **Merge Method**: squash **Soak Time**: ${{ steps.soak-time.outputs.soak_seconds }} seconds **Approvals**: ${{ steps.check-approval.outputs.approved }} **All Checks**: ✅ Passed **Automation Rule**: AUTO_MERGE_POLICY.md **Audit Trail**: Logged to database Thank you for your contribution! 🚀" env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Notify on failure if: failure() run: | gh pr comment ${{ github.event.pull_request.number }} --body "⚠️ **Auto-Merge Failed** Auto-merge could not complete. Possible reasons: - Some checks are still failing - Merge conflicts with main branch - GitHub API error **Action Required**: Please review the PR and merge manually, or fix issues and retry. Check GitHub Actions logs for details." env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}