|
| 1 | +name: Scheduled Dependabot PRs Auto-Merge |
| 2 | + |
| 3 | +on: |
| 4 | + schedule: |
| 5 | + - cron: '0 0 * * *' # Runs once a day at midnight UTC |
| 6 | + workflow_dispatch: |
| 7 | + |
| 8 | +permissions: |
| 9 | + contents: write |
| 10 | + pull-requests: write |
| 11 | + |
| 12 | +jobs: |
| 13 | + merge-dependabot: |
| 14 | + runs-on: ubuntu-latest |
| 15 | + steps: |
| 16 | + - name: Checkout repository |
| 17 | + uses: actions/checkout@v4 |
| 18 | + |
| 19 | + - name: Install GitHub CLI |
| 20 | + run: | |
| 21 | + sudo apt update |
| 22 | + sudo apt install -y gh |
| 23 | +
|
| 24 | + - name: Fetch & Filter Dependabot PRs |
| 25 | + env: |
| 26 | + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
| 27 | + run: | |
| 28 | + echo "🔍 Fetching all Dependabot PRs targeting 'dependabotchanges'..." |
| 29 | + > matched_prs.txt |
| 30 | + pr_batch=$(gh pr list --state open --json number,title,author,baseRefName,url \ |
| 31 | + --jq '.[] | "\(.number)|\(.title)|\(.author.login)|\(.baseRefName)|\(.url)"') |
| 32 | + while IFS='|' read -r number title author base url; do |
| 33 | + author=$(echo "$author" | xargs) |
| 34 | + base=$(echo "$base" | xargs) |
| 35 | + if [[ "$author" == "app/dependabot" && "$base" == "dependabotchanges" ]]; then |
| 36 | + echo "$url" >> matched_prs.txt |
| 37 | + echo "✅ Matched PR #$number - $title" |
| 38 | + else |
| 39 | + echo "❌ Skipped PR #$number - $title (Author: $author, Base: $base)" |
| 40 | + fi |
| 41 | + done <<< "$pr_batch" |
| 42 | + echo "👉 Matched PRs:" |
| 43 | + cat matched_prs.txt || echo "None" |
| 44 | +
|
| 45 | + - name: Rebase PR if Conflicts Exist |
| 46 | + if: success() |
| 47 | + env: |
| 48 | + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
| 49 | + run: | |
| 50 | + if [[ ! -s matched_prs.txt ]]; then |
| 51 | + echo "⚠️ No matching PRs to process." |
| 52 | + exit 0 |
| 53 | + fi |
| 54 | + while IFS= read -r pr_url; do |
| 55 | + pr_number=$(basename "$pr_url") |
| 56 | + echo "🔁 Rebasing PR #$pr_number if conflicts exist" |
| 57 | + mergeable=$(gh pr view "$pr_number" --json mergeable --jq '.mergeable') |
| 58 | + if [[ "$mergeable" == "CONFLICTING" ]]; then |
| 59 | + echo "❌ Merge conflicts detected. Rebasing PR #$pr_number" |
| 60 | + gh pr rebase "$pr_url" || echo "❗ Rebase failed." |
| 61 | + fi |
| 62 | + done < matched_prs.txt |
| 63 | +
|
| 64 | + - name: Approve and Auto-Merge if Mergeable |
| 65 | + if: success() |
| 66 | + env: |
| 67 | + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
| 68 | + run: | |
| 69 | + if [[ ! -s matched_prs.txt ]]; then |
| 70 | + echo "⚠️ No matching PRs to process." |
| 71 | + exit 0 |
| 72 | + fi |
| 73 | + while IFS= read -r pr_url; do |
| 74 | + echo "🔍 Checking mergeability for $pr_url" |
| 75 | + pr_number=$(basename "$pr_url") |
| 76 | + attempt=0 |
| 77 | + max_attempts=8 |
| 78 | + mergeable="" |
| 79 | + sleep 5 # Initial delay to allow GitHub to compute mergeability |
| 80 | + while [[ $attempt -lt $max_attempts ]]; do |
| 81 | + mergeable=$(gh pr view "$pr_number" --json mergeable --jq '.mergeable' 2>/dev/null || echo "UNKNOWN") |
| 82 | + echo "🔁 Attempt $((attempt+1))/$max_attempts: mergeable=$mergeable" |
| 83 | + if [[ "$mergeable" == "MERGEABLE" ]]; then |
| 84 | + echo "✅ PR is mergeable. Approving..." |
| 85 | + gh pr review --approve "$pr_url" || echo "❗ Approval failed." |
| 86 | + echo "🚀 Enabling auto-merge..." |
| 87 | + set -x |
| 88 | + merge_output=$(gh pr merge --auto --merge "$pr_url" 2>&1) |
| 89 | + merge_status=$? |
| 90 | + set +x |
| 91 | + echo "$merge_output" |
| 92 | + if [[ $merge_status -ne 0 ]]; then |
| 93 | + echo "❗ Auto-merge failed. Output: $merge_output" |
| 94 | + else |
| 95 | + echo "✅ Auto-merge succeeded!" |
| 96 | + fi |
| 97 | + break |
| 98 | + elif [[ "$mergeable" == "CONFLICTING" ]]; then |
| 99 | + echo "❌ Cannot merge due to conflicts. Skipping." |
| 100 | + break |
| 101 | + else |
| 102 | + echo "🕒 Waiting for GitHub to determine mergeable status..." |
| 103 | + sleep 15 |
| 104 | + fi |
| 105 | + ((attempt++)) |
| 106 | + done |
| 107 | + if [[ "$mergeable" != "MERGEABLE" && "$mergeable" != "CONFLICTING" ]]; then |
| 108 | + echo "❌ Mergeability undetermined after $max_attempts attempts. Skipping PR #$pr_number" |
| 109 | + fi |
| 110 | + done < matched_prs.txt || echo "⚠️ Completed loop with some errors, but continuing gracefully." |
0 commit comments