forked from hyperlight-dev/hyperagent
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathauto-approve-dependabot.sh
More file actions
159 lines (132 loc) · 7.32 KB
/
auto-approve-dependabot.sh
File metadata and controls
159 lines (132 loc) · 7.32 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
153
154
155
156
157
158
159
#!/bin/bash
set -e
set -o pipefail
# This script checks for open PRs from dependabot that have all checks passing and have not been
# modified by another user, and approves+merges them automatically.
# To be run as a GitHub action.
# Check if repository argument is provided
if [ -z "$1" ]; then
echo "Error: Repository name not provided."
echo "Usage: $0 <owner/repo>"
echo "Example: $0 hyperlight-dev/hyperlight"
exit 1
fi
REPO="$1"
echo "Checking for open Dependabot PRs to approve and merge in $REPO..."
# Get all open PRs from dependabot
# We filter so that only PRs that are not from forks and are in branches starting with "dependabot/cargo" or "dependabot/npm_and_yarn" are included.
dependabot_prs=$(gh pr list -R "$REPO" --author "dependabot[bot]" --state open --json number,title,reviews,headRepositoryOwner,headRefName | jq --arg repo_owner "$(echo "$REPO" | cut -d'/' -f1)" '[.[] | select(.headRepositoryOwner.login == $repo_owner and ((.headRefName | startswith("dependabot/cargo")) or (.headRefName | startswith("dependabot/npm_and_yarn"))))]')
# Exit early if no PRs found
if [ -z "$dependabot_prs" ] || [ "$dependabot_prs" = "[]" ]; then
echo "No open Dependabot PRs found in $REPO"
exit 0
fi
# Count how many PRs we found
pr_count=$(echo "$dependabot_prs" | jq 'length')
echo "Found $pr_count open Dependabot PRs in $REPO"
# Process each PR
echo "$dependabot_prs" | jq -c '.[]' | while read -r pr; do
pr_number=$(echo "$pr" | jq -r '.number')
pr_title=$(echo "$pr" | jq -r '.title')
echo "Processing PR #$pr_number: $pr_title"
# Check if PR only modifies allowed files
pr_files=$(gh pr view "$pr_number" -R "$REPO" --json files)
invalid_files=$(echo "$pr_files" | jq -r '.files[].path' | grep -v -E '(^|/)(Cargo\.toml|Cargo\.lock|package\.json|package-lock\.json)$' || true)
if [ -n "$invalid_files" ]; then
echo " ❌ PR #$pr_number modifies files that are not allowed for auto-merge:"
printf '%s\n' "$invalid_files" | sed 's/^/ - /'
echo " ℹ️ Only changes to Cargo.toml, Cargo.lock, package.json, and package-lock.json are allowed"
continue
fi
echo " ✅ PR #$pr_number only modifies allowed files (Cargo.toml, Cargo.lock, package.json, package-lock.json)"
# First, get detailed PR information including all checks
pr_details=$(gh pr view "$pr_number" -R "$REPO" --json statusCheckRollup,state)
# Check if all status checks have passed (regardless of required or not)
all_checks_pass=true
has_pending_checks=false
failed_checks=""
# First identify checks that are still in progress
pending_checks=$(echo "$pr_details" | jq -r '.statusCheckRollup[] | select(.status == "IN_PROGRESS" or .status == "QUEUED" or .status == "PENDING") | .name')
# Check for permission-required checks
permission_required_checks=$(echo "$pr_details" | jq -r '.statusCheckRollup[] | select(.status == "WAITING" or .status == "ACTION_REQUIRED" or (.status == "QUEUED" and .conclusion == null and .detailsUrl != null and (.detailsUrl | contains("waiting-for-approval")))) | .name')
# Don't approve if there are checks required that need permission to run
if [ -n "$permission_required_checks" ]; then
echo " 🔐 PR #$pr_number has checks waiting for permission:"
echo "$permission_required_checks" | sed 's/^/ - /'
echo " ❌ Skipping auto-approval due to permission-required checks"
continue
fi
if [ -n "$pending_checks" ]; then
echo " ⏳ PR #$pr_number has pending checks:"
echo "$pending_checks" | sed 's/^/ - /'
echo " ℹ️ We will still approve the PR so it can merge automatically once all checks pass"
has_pending_checks=true
fi
# Check for failed checks - only include checks that have a conclusion and are not still running
# Explicitly exclude checks with status IN_PROGRESS, QUEUED, or PENDING
failed_checks=$(echo "$pr_details" | jq -r '.statusCheckRollup[] |
select(.conclusion != null and
.conclusion != "SUCCESS" and
.conclusion != "NEUTRAL" and
.conclusion != "SKIPPED" and
.status != "IN_PROGRESS" and
.status != "QUEUED" and
.status != "PENDING") | .name')
if [ -n "$failed_checks" ]; then
echo " ❌ PR #$pr_number has failed checks:"
echo "$failed_checks" | sed 's/^/ - /'
all_checks_pass=false
continue
fi
# If we've reached here, either all checks have passed or some are pending
if [ "$has_pending_checks" = false ]; then
echo " ✅ All status checks passed for PR #$pr_number"
fi
# Check if PR has been modified by someone other than dependabot
pr_commits=$(gh pr view "$pr_number" -R "$REPO" --json commits)
non_dependabot_authors=$(echo "$pr_commits" | jq -r '.commits[].authors[].login' | grep -v -e "dependabot\[bot\]" -e "^$" || true)
if [ -n "$non_dependabot_authors" ]; then
echo " ❌ PR #$pr_number has been modified by users other than dependabot: $non_dependabot_authors"
continue
fi
# Check if PR needs approval (i.e., hasn't been approved already)
already_approved=$(echo "$pr" | jq -r '.reviews[] | select(.state == "APPROVED") | .state' | grep -c "APPROVED" || true)
if [ "$already_approved" -eq 0 ]; then
echo " ✅ Approving PR #$pr_number"
gh pr review "$pr_number" -R "$REPO" --approve -b "Automatically approved by dependabot auto-approve workflow"
else
echo " ℹ️ PR #$pr_number is already approved"
fi
if [ "$has_pending_checks" = true ]; then
echo " ⏳ PR #$pr_number still has pending checks"
echo " ✅ Enabling auto-merge (squash strategy) for PR #$pr_number"
gh pr merge "$pr_number" -R "$REPO" --auto --squash
echo " ✅ Auto-merge enabled for PR #$pr_number"
elif [ "$all_checks_pass" = true ]; then
# Check if PR is up-to-date with base branch
merge_status=$(gh pr view "$pr_number" -R "$REPO" --json mergeStateStatus -q '.mergeStateStatus')
case "$merge_status" in
CLEAN)
echo " ✅ PR #$pr_number is up to date with base branch"
# PR is already clean/mergeable - merge directly instead of enabling auto-merge
echo " ✅ Merging PR #$pr_number directly (squash strategy)"
gh pr merge "$pr_number" -R "$REPO" --squash
echo " ✅ PR #$pr_number merged successfully"
;;
BEHIND)
echo " ⚠️ PR #$pr_number is behind the base branch"
# Enable auto-merge to merge once the branch is updated and checks pass
echo " ✅ Enabling auto-merge (squash strategy) for PR #$pr_number"
gh pr merge "$pr_number" -R "$REPO" --auto --squash
echo " ✅ Auto-merge enabled for PR #$pr_number"
;;
DIRTY|BLOCKED)
echo " ⚠️ Skipping PR #$pr_number because it cannot be auto-merged (status: $merge_status)"
;;
*)
echo " ⚠️ Skipping PR #$pr_number due to unsupported merge status: $merge_status"
;;
esac
fi
done
echo "Finished processing Dependabot PRs for $REPO"