-
Notifications
You must be signed in to change notification settings - Fork 2
164 lines (152 loc) · 6.88 KB
/
Copy pathrebase-dependabot.yml
File metadata and controls
164 lines (152 loc) · 6.88 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
160
161
162
163
164
name: Rebase Dependabot
# After a merge, strict required checks leave other Dependabot PRs BEHIND.
# Dependabot rebase-strategy: auto is slow, so auto-merge sits armed forever.
# Replay each behind branch onto origin/main. Do not comment
# @dependabot rebase: github-actions[bot] and the auto-approve App are
# both rejected ("only users with push access", #1508 / #1509).
#
# Push the rebase with GITHUB_TOKEN (not the App). require_last_push_approval
# dismisses the last pusher's review. If the App pushed, it could not approve
# (#1520). That GITHUB_TOKEN push leaves CI/Security/Auto-approve at
# action_required with zero jobs (#1516 / #1522). The following step uses
# the App token to approve those stubs and re-approve the PR.
on:
push:
branches: [main]
schedule:
- cron: "17 * * * *"
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}
cancel-in-progress: true
permissions:
contents: read
jobs:
rebase:
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: write
pull-requests: write
steps:
- name: Harden runner
uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
with:
egress-policy: audit
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
fetch-depth: 0
persist-credentials: false
# App is not last pusher (rebase uses GITHUB_TOKEN). That is required
# so this token can approve the PR under require_last_push_approval
# and start action_required stub runs (#1516 / #1522).
- uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
id: app-token
continue-on-error: true
with:
client-id: ${{ vars.AUTO_APPROVE_CLIENT_ID }}
private-key: ${{ secrets.AUTO_APPROVE_PRIVATE_KEY }}
permission-contents: write
permission-pull-requests: write
permission-workflows: write
- name: Rebase Dependabot PRs that are behind main
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REPO: ${{ github.repository }}
run: |
set -euo pipefail
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
nums=$(gh pr list --repo "${REPO}" --author "app/dependabot" --state open \
--json number,mergeStateStatus \
--jq '[.[] | select(.mergeStateStatus == "BEHIND") | .number] | .[]')
if [ -z "${nums}" ]; then
echo "No Dependabot PRs behind main."
exit 0
fi
git fetch origin main
remote_url="https://x-access-token:${GH_TOKEN}@github.com/${REPO}.git"
for n in ${nums}; do
branch=$(gh pr view "${n}" --repo "${REPO}" --json headRefName --jq .headRefName)
echo "Rebasing #${n} (${branch}) onto origin/main"
# Named-remote lease needs a tracking SHA. Pushing to a URL has none,
# so bare --force-with-lease reports stale info and aborts (#1513).
git fetch origin "refs/heads/${branch}:refs/remotes/origin/${branch}"
expected=$(git rev-parse "origin/${branch}")
git checkout -B "${branch}" "origin/${branch}"
if ! git rebase origin/main; then
echo "Conflict on #${n}; leaving it for a human."
git rebase --abort
continue
fi
if ! git push --force-with-lease="refs/heads/${branch}:${expected}" \
"${remote_url}" "HEAD:refs/heads/${branch}"; then
echo "Lease rejected on #${n}; refetch and retry once."
git fetch origin "refs/heads/${branch}:refs/remotes/origin/${branch}"
expected=$(git rev-parse "origin/${branch}")
git checkout -B "${branch}" "origin/${branch}"
if ! git rebase origin/main; then
echo "Conflict on #${n} after retry; leaving it for a human."
git rebase --abort
continue
fi
if ! git push --force-with-lease="refs/heads/${branch}:${expected}" \
"${remote_url}" "HEAD:refs/heads/${branch}"; then
echo "Lease rejected again on #${n}; leaving it for a later run."
continue
fi
fi
done
- name: Require App token to unstick CI
if: steps.app-token.outputs.token == ''
run: |
echo "FAIL: App token is empty after rebase; cannot unstick Dependabot CI."
echo "Set AUTO_APPROVE_CLIENT_ID and AUTO_APPROVE_PRIVATE_KEY."
exit 1
- name: Start CI and re-approve after GITHUB_TOKEN rebase
if: steps.app-token.outputs.token != ''
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
REPO: ${{ github.repository }}
run: |
set -euo pipefail
# GITHUB_TOKEN rebase leaves pull_request runs at action_required
# with zero jobs. User tokens 404 on run-approve; App token works
# (start-cleanup-pr-ci.sh). App is not last pusher, so it can also
# satisfy require_last_push_approval. Only touch PRs that already
# have auto-merge armed (skip unreviewed majors).
echo "PLAN: unstick Dependabot PRs with action_required stubs"
for _try in 1 2 3 4 5; do
found=0
nums=$(gh pr list --repo "${REPO}" --author "app/dependabot" \
--state open --json number,autoMergeRequest \
--jq '.[] | select(.autoMergeRequest != null) | .number')
for n in ${nums}; do
branch=$(gh pr view "${n}" --repo "${REPO}" --json headRefName \
--jq .headRefName)
ids=$(gh run list --repo "${REPO}" --branch "${branch}" --limit 15 \
--json databaseId,conclusion \
--jq '.[] | select(.conclusion == "action_required") | .databaseId')
if [ -z "${ids}" ]; then
continue
fi
found=1
echo "DO: approve stubs on #${n}"
while read -r id; do
[ -z "${id}" ] && continue
gh api -X POST "repos/${REPO}/actions/runs/${id}/approve" \
>/dev/null && echo "OK: approved run ${id}" \
|| echo "FAIL: approve ${id} (continuing)"
done <<<"${ids}"
gh pr review --approve "${n}" --repo "${REPO}" \
|| echo "Approve #${n} failed or already approved"
gh pr merge --auto --squash "${n}" --repo "${REPO}" \
|| echo "auto-merge already armed or blocked on #${n}"
done
if [ "${found}" -eq 0 ]; then
echo "OK: no action_required Dependabot stubs"
break
fi
sleep 4
done
echo "DONE: Dependabot unstick pass"