-
Notifications
You must be signed in to change notification settings - Fork 168
Expand file tree
/
Copy pathScheduled-Dependabot-PRs-Auto-Merge.yml
More file actions
152 lines (146 loc) · 6.21 KB
/
Scheduled-Dependabot-PRs-Auto-Merge.yml
File metadata and controls
152 lines (146 loc) · 6.21 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# ------------------------------------------------------------------------------
# Scheduled Dependabot PRs Auto-Merge Workflow
#
# Purpose:
# - Automatically detect, rebase (if needed), and merge Dependabot PRs targeting
# the `dependabotchanges` branch, supporting different merge strategies.
#
# Features:
# ✅ Filters PRs authored by Dependabot and targets the specific base branch
# ✅ Rebases PRs with conflicts and auto-resolves using "prefer-theirs" strategy
# ✅ Attempts all three merge strategies: merge, squash, rebase (first success wins)
# ✅ Handles errors gracefully, logs clearly
#
# Triggers:
# - Scheduled daily run (midnight UTC)
# - Manual trigger (via GitHub UI)
#
# Required Permissions:
# - contents: write
# - pull-requests: write
# ------------------------------------------------------------------------------
name: Scheduled Dependabot PRs Auto-Merge
on:
schedule:
- cron: '0 0 * * *' # Runs once a day at midnight UTC
workflow_dispatch:
permissions:
contents: write
pull-requests: write
jobs:
merge-dependabot:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install GitHub CLI
run: |
sudo apt update
sudo apt install -y gh
- name: Fetch & Filter Dependabot PRs
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo "🔍 Fetching all Dependabot PRs targeting 'dependabotchanges'..."
> matched_prs.txt
pr_batch=$(gh pr list --state open --json number,title,author,baseRefName,url \
--jq '.[] | "\(.number)|\(.title)|\(.author.login)|\(.baseRefName)|\(.url)"')
while IFS='|' read -r number title author base url; do
author=$(echo "$author" | xargs)
base=$(echo "$base" | xargs)
if [[ "$author" == "app/dependabot" && "$base" == "dependabotchanges" ]]; then
echo "$url" >> matched_prs.txt
echo "✅ Matched PR #$number - $title"
else
echo "❌ Skipped PR #$number - $title (Author: $author, Base: $base)"
fi
done <<< "$pr_batch"
echo "👉 Matched PRs:"
cat matched_prs.txt || echo "None"
- name: Rebase PR if Conflicts Exist
if: success()
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
if [[ ! -s matched_prs.txt ]]; then
echo "⚠️ No matching PRs to process."
exit 0
fi
while IFS= read -r pr_url; do
pr_number=$(basename "$pr_url")
echo "🔁 Checking PR #$pr_number for conflicts..."
mergeable=$(gh pr view "$pr_number" --json mergeable --jq '.mergeable')
if [[ "$mergeable" == "CONFLICTING" ]]; then
echo "⚠️ Merge conflicts detected. Performing manual rebase for PR #$pr_number..."
head_branch=$(gh pr view "$pr_number" --json headRefName --jq '.headRefName')
base_branch=$(gh pr view "$pr_number" --json baseRefName --jq '.baseRefName')
git fetch origin "$base_branch":"$base_branch"
git fetch origin "$head_branch":"$head_branch"
git checkout "$head_branch"
git config user.name "github-actions"
git config user.email "action@github.com"
# Attempt rebase with 'theirs' strategy
if git rebase --strategy=recursive -X theirs "$base_branch"; then
echo "✅ Rebase successful. Pushing..."
git push origin "$head_branch" --force
else
echo "❌ Rebase failed. Aborting..."
git rebase --abort || true
fi
else
echo "✅ PR #$pr_number is mergeable. Skipping rebase."
fi
done < matched_prs.txt
- name: Auto-Merge PRs using available strategy
if: success()
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
if [[ ! -s matched_prs.txt ]]; then
echo "⚠️ No matching PRs to process."
exit 0
fi
while IFS= read -r pr_url; do
pr_number=$(basename "$pr_url")
echo "🔍 Checking mergeability for PR #$pr_number"
attempt=0
max_attempts=8
mergeable=""
sleep 5 # Let GitHub calculate mergeable status
while [[ $attempt -lt $max_attempts ]]; do
mergeable=$(gh pr view "$pr_number" --json mergeable --jq '.mergeable' 2>/dev/null || echo "UNKNOWN")
echo "🔁 Attempt $((attempt+1))/$max_attempts: mergeable=$mergeable"
if [[ "$mergeable" == "MERGEABLE" ]]; then
success=0
for strategy in rebase squash merge; do
echo "🚀 Trying to auto-merge PR #$pr_number using '$strategy' strategy..."
set -x
merge_output=$(gh pr merge --auto --"$strategy" "$pr_url" 2>&1)
merge_status=$?
set +x
echo "$merge_output"
if [[ $merge_status -eq 0 ]]; then
echo "✅ Auto-merge succeeded using '$strategy'."
success=1
break
else
echo "❌ Auto-merge failed using '$strategy'. Trying next strategy..."
fi
done
if [[ $success -eq 0 ]]; then
echo "❌ All merge strategies failed for PR #$pr_number"
fi
break
elif [[ "$mergeable" == "CONFLICTING" ]]; then
echo "❌ Cannot merge due to conflicts. Skipping PR #$pr_number"
break
else
echo "🕒 Waiting for GitHub to determine mergeable status..."
sleep 15
fi
((attempt++))
done
if [[ "$mergeable" != "MERGEABLE" && "$mergeable" != "CONFLICTING" ]]; then
echo "❌ Mergeability undetermined after $max_attempts attempts. Skipping PR #$pr_number"
fi
done < matched_prs.txt || echo "⚠️ Completed loop with some errors, but continuing gracefully."