name: Auto Merge Approved PRs on: schedule: - cron: '0 */1 * * *' # Every 1 hour workflow_dispatch: # Allow manual triggering permissions: contents: write pull-requests: write actions: read jobs: auto-merge-prs: runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v4 with: fetch-depth: 0 token: ${{ secrets.PAT_TOKEN }} - name: Configure git run: | git config --global user.email "action@github.com" git config --global user.name "GitHub Action" - name: Check for running workflows id: check_workflows run: | # Get all running workflows except this one running_workflows=$(gh run list --status in_progress --json workflowName,name --repo "$GITHUB_REPOSITORY" --jq '.[].name' | grep -v "Auto Merge Approved PRs" | wc -l) echo "running_workflows=$running_workflows" >> $GITHUB_OUTPUT if [ "$running_workflows" -gt 0 ]; then echo "Found $running_workflows running workflows. Exiting to avoid conflicts." echo "should_continue=false" >> $GITHUB_OUTPUT else echo "No other workflows running. Proceeding with auto-merge." echo "should_continue=true" >> $GITHUB_OUTPUT fi env: GH_TOKEN: ${{ secrets.PAT_TOKEN }} - name: Find and merge approved PRs if: steps.check_workflows.outputs.should_continue == 'true' run: | authorized_user="carlospolop" max_merges=2 echo "Authorized user: $authorized_user" echo "Looking for PRs with exact comment 'merge' from $authorized_user..." # Get all open PRs prs=$(gh pr list --state open --json number,title,url --repo "$GITHUB_REPOSITORY") if [ "$prs" = "[]" ]; then echo "No open PRs found." exit 0 fi # Create a temp file to track merge count echo "0" > /tmp/merged_count # Process each PR echo "$prs" | jq -r '.[] | @base64' | while IFS= read -r pr_data; do current_count=$(cat /tmp/merged_count) if [ "$current_count" -ge "$max_merges" ]; then echo "Reached maximum merge limit ($max_merges). Stopping." break fi pr_info=$(echo "$pr_data" | base64 --decode) pr_number=$(echo "$pr_info" | jq -r '.number') pr_title=$(echo "$pr_info" | jq -r '.title') pr_url=$(echo "$pr_info" | jq -r '.url') echo "Checking PR #$pr_number: $pr_title" # Get all comments for this PR comments=$(gh pr view "$pr_number" --json comments --jq '.comments[]' --repo "$GITHUB_REPOSITORY") # Print all comment authors for debugging echo "Comments in PR #$pr_number:" echo "$comments" | jq -r '" - Author: " + .author.login + " | Comment: " + (.body | split("\n")[0] | .[0:100])' # Check if any comment from carlospolop contains exactly "merge" has_merge_comment=false echo "$comments" | jq -r '.author.login + "|" + .body' | while IFS='|' read -r comment_author comment_body; do if [ "$comment_author" = "$authorized_user" ]; then if echo "$comment_body" | grep -iExq "merge"; then echo "Found exact 'merge' comment from $authorized_user in PR #$pr_number" echo "true" > /tmp/has_merge_comment_$pr_number break fi fi done if [ -f "/tmp/has_merge_comment_$pr_number" ]; then has_merge_comment=true fi if [ "$has_merge_comment" = true ]; then echo "Attempting to merge PR #$pr_number..." # Get PR details including head branch pr_details=$(gh pr view "$pr_number" --json headRefName,baseRefName --repo "$GITHUB_REPOSITORY") head_branch=$(echo "$pr_details" | jq -r '.headRefName') base_branch=$(echo "$pr_details" | jq -r '.baseRefName') # --- Polling for non-UNKNOWN mergeable status --- max_retries=10 retry=0 while true; do pr_mergeable=$(gh pr view "$pr_number" --json mergeable --jq '.mergeable' --repo "$GITHUB_REPOSITORY") if [ "$pr_mergeable" != "UNKNOWN" ]; then break fi if [ $retry -ge $max_retries ]; then echo "Timeout: mergeable status is still UNKNOWN after $max_retries retries" break fi echo "mergeable status UNKNOWN, retrying in 2s..." sleep 2 retry=$((retry + 1)) done if [ "$pr_mergeable" = "MERGEABLE" ]; then if gh pr merge "$pr_number" --merge --delete-branch --repo "$GITHUB_REPOSITORY"; then echo "Successfully merged PR #$pr_number: $pr_title" current_count=$(cat /tmp/merged_count) echo $((current_count + 1)) > /tmp/merged_count else echo "Failed to merge PR #$pr_number: $pr_title" fi elif [ "$pr_mergeable" = "CONFLICTED" ] || [ "$pr_mergeable" = "CONFLICTING" ]; then echo "PR #$pr_number has conflicts. Skipping auto-merge so it can be resolved manually." else echo "PR #$pr_number is not mergeable (status: $pr_mergeable)" fi else echo "No exact 'merge' comment found from $authorized_user in PR #$pr_number" fi rm -f "/tmp/has_merge_comment_$pr_number" done final_count=$(cat /tmp/merged_count) echo "Auto-merge process completed. Merged $final_count PRs." rm -f /tmp/merged_count env: GH_TOKEN: ${{ secrets.PAT_TOKEN }}