Skip to content

Commit 4b1ff37

Browse files
committed
ci: Renovate repair PR workflow を追加
1 parent 745380c commit 4b1ff37

1 file changed

Lines changed: 207 additions & 0 deletions

File tree

Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
name: Create Renovate Repair PR
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
pr_number:
7+
description: 'Renovate PR number to create a repair PR for. If omitted, workflow_run context is used.'
8+
required: false
9+
type: string
10+
dry_run:
11+
description: 'Do not push a branch or create a PR.'
12+
required: true
13+
default: true
14+
type: boolean
15+
workflow_run:
16+
workflows:
17+
- Labeler
18+
- lint
19+
- Test Install Scripts
20+
types:
21+
- completed
22+
23+
concurrency:
24+
group: ${{ github.workflow }}-${{ github.event.workflow_run.head_branch || inputs.pr_number || github.run_id }}
25+
cancel-in-progress: false
26+
27+
jobs:
28+
create-repair-pr:
29+
runs-on: ubuntu-latest
30+
timeout-minutes: 10
31+
if: >-
32+
github.event_name == 'workflow_dispatch' ||
33+
github.event.workflow_run.conclusion == 'failure'
34+
permissions:
35+
contents: read
36+
pull-requests: read
37+
actions: read
38+
steps:
39+
- name: GitHub App トークンの生成
40+
id: app-token
41+
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3
42+
with:
43+
app-id: ${{ secrets.GHA_APP_ID }}
44+
private-key: ${{ secrets.GHA_APP_PRIVATE_KEY }}
45+
46+
- name: 対象 Renovate PR の特定
47+
id: target
48+
env:
49+
GH_TOKEN: ${{ steps.app-token.outputs.token }}
50+
EVENT_NAME: ${{ github.event_name }}
51+
INPUT_PR_NUMBER: ${{ inputs.pr_number }}
52+
WORKFLOW_HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
53+
WORKFLOW_HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }}
54+
WORKFLOW_NAME: ${{ github.event.workflow_run.name }}
55+
WORKFLOW_URL: ${{ github.event.workflow_run.html_url }}
56+
run: |
57+
set -euo pipefail
58+
59+
PR_NUMBER="${INPUT_PR_NUMBER}"
60+
if [ -z "$PR_NUMBER" ]; then
61+
if [ -z "$WORKFLOW_HEAD_SHA" ]; then
62+
echo "workflow_run head SHA is empty and pr_number was not provided"
63+
exit 0
64+
fi
65+
PR_NUMBER=$(gh api "repos/${{ github.repository }}/commits/${WORKFLOW_HEAD_SHA}/pulls" \
66+
--jq '[.[] | select(.state == "open")][0].number // empty')
67+
fi
68+
69+
if [ -z "$PR_NUMBER" ]; then
70+
echo "No open PR found for this event."
71+
exit 0
72+
fi
73+
74+
PR_JSON=$(gh pr view "$PR_NUMBER" \
75+
--repo "${{ github.repository }}" \
76+
--json number,title,url,author,headRefName,headRefOid,baseRefName,state,isDraft)
77+
78+
AUTHOR=$(jq -r '.author.login' <<<"$PR_JSON")
79+
HEAD_BRANCH=$(jq -r '.headRefName' <<<"$PR_JSON")
80+
HEAD_SHA=$(jq -r '.headRefOid' <<<"$PR_JSON")
81+
TITLE=$(jq -r '.title' <<<"$PR_JSON")
82+
URL=$(jq -r '.url' <<<"$PR_JSON")
83+
STATE=$(jq -r '.state' <<<"$PR_JSON")
84+
85+
if [ "$STATE" != "OPEN" ]; then
86+
echo "PR #${PR_NUMBER} is not open: ${STATE}"
87+
exit 0
88+
fi
89+
90+
if [ "$AUTHOR" != "app/renovate" ] && [ "$AUTHOR" != "renovate[bot]" ]; then
91+
echo "PR #${PR_NUMBER} is not a Renovate PR: author=${AUTHOR}"
92+
exit 0
93+
fi
94+
95+
if [[ "$HEAD_BRANCH" == renovate-repair/* ]]; then
96+
echo "Skip repair branch: ${HEAD_BRANCH}"
97+
exit 0
98+
fi
99+
100+
if [[ "$HEAD_BRANCH" != renovate/* ]]; then
101+
echo "PR #${PR_NUMBER} head branch is not renovate/*: ${HEAD_BRANCH}"
102+
exit 0
103+
fi
104+
105+
SAFE_BRANCH=$(printf '%s' "$HEAD_BRANCH" | sed -E 's|^renovate/||; s|[^A-Za-z0-9._-]+|-|g' | cut -c1-80)
106+
REPAIR_BRANCH="renovate-repair/pr-${PR_NUMBER}-${SAFE_BRANCH}"
107+
EXISTING_PR=$(gh pr list \
108+
--repo "${{ github.repository }}" \
109+
--state open \
110+
--head "$REPAIR_BRANCH" \
111+
--json number,url \
112+
--jq '.[0].url // empty')
113+
114+
{
115+
echo "pr_number=${PR_NUMBER}"
116+
echo "pr_title=${TITLE}"
117+
echo "pr_url=${URL}"
118+
echo "head_branch=${HEAD_BRANCH}"
119+
echo "head_sha=${HEAD_SHA}"
120+
echo "repair_branch=${REPAIR_BRANCH}"
121+
echo "existing_pr=${EXISTING_PR}"
122+
echo "workflow_name=${WORKFLOW_NAME:-manual}"
123+
echo "workflow_url=${WORKFLOW_URL:-}"
124+
} >> "$GITHUB_OUTPUT"
125+
126+
- name: repair PR 作成
127+
if: steps.target.outputs.pr_number != '' && steps.target.outputs.existing_pr == ''
128+
env:
129+
GH_TOKEN: ${{ steps.app-token.outputs.token }}
130+
DRY_RUN: ${{ inputs.dry_run || false }}
131+
PR_NUMBER: ${{ steps.target.outputs.pr_number }}
132+
PR_TITLE: ${{ steps.target.outputs.pr_title }}
133+
PR_URL: ${{ steps.target.outputs.pr_url }}
134+
HEAD_BRANCH: ${{ steps.target.outputs.head_branch }}
135+
HEAD_SHA: ${{ steps.target.outputs.head_sha }}
136+
REPAIR_BRANCH: ${{ steps.target.outputs.repair_branch }}
137+
WORKFLOW_NAME: ${{ steps.target.outputs.workflow_name }}
138+
WORKFLOW_URL: ${{ steps.target.outputs.workflow_url }}
139+
run: |
140+
set -euo pipefail
141+
142+
BODY_FILE=$(mktemp)
143+
cat > "$BODY_FILE" <<EOF
144+
## 概要
145+
146+
Renovate PR #${PR_NUMBER} の CI failure を受けて自動生成された repair PR です。
147+
148+
元 PR:
149+
- ${PR_URL}
150+
151+
この PR の base は \`${HEAD_BRANCH}\` です。\`main\` ではありません。
152+
153+
## 検知した failure
154+
155+
- Workflow: ${WORKFLOW_NAME}
156+
- Run: ${WORKFLOW_URL:-N/A}
157+
- Renovate branch: \`${HEAD_BRANCH}\`
158+
- Renovate head SHA: \`${HEAD_SHA}\`
159+
- Repair branch: \`${REPAIR_BRANCH}\`
160+
161+
## 初期版の挙動
162+
163+
現時点では安全のため、ファイルは変更せず empty commit のみで CI を再実行します。
164+
修復差分が必要な場合は、この repair PR branch に追加 commit を積んでください。
165+
166+
## レビュー観点
167+
168+
- この PR は元 Renovate PR に直接 push しないためのレビュー用 PR です。
169+
- merge すると元 Renovate branch に repair commit が入り、元 PR の CI が再実行されます。
170+
EOF
171+
172+
echo "Target PR: #${PR_NUMBER} ${PR_TITLE}"
173+
echo "Repair branch: ${REPAIR_BRANCH}"
174+
echo "Dry run: ${DRY_RUN}"
175+
176+
if [ "$DRY_RUN" = "true" ]; then
177+
echo "dry_run=true のため branch push / PR 作成は行いません。"
178+
cat "$BODY_FILE"
179+
exit 0
180+
fi
181+
182+
git config user.name "github-actions[bot]"
183+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
184+
185+
git init repair-worktree
186+
cd repair-worktree
187+
git remote add origin "https://github.com/${{ github.repository }}.git"
188+
git -c http.https://github.com/.extraheader="AUTHORIZATION: bearer ${GH_TOKEN}" \
189+
fetch --depth=1 origin "${HEAD_BRANCH}"
190+
git checkout -b "${REPAIR_BRANCH}" FETCH_HEAD
191+
git commit --allow-empty -m "chore: retrigger CI for Renovate PR #${PR_NUMBER}"
192+
git -c http.https://github.com/.extraheader="AUTHORIZATION: bearer ${GH_TOKEN}" \
193+
push origin "${REPAIR_BRANCH}"
194+
195+
gh pr create \
196+
--repo "${{ github.repository }}" \
197+
--base "${HEAD_BRANCH}" \
198+
--head "${REPAIR_BRANCH}" \
199+
--draft \
200+
--title "chore: retrigger CI for Renovate PR #${PR_NUMBER}" \
201+
--body-file "$BODY_FILE"
202+
203+
- name: 既存 repair PR の表示
204+
if: steps.target.outputs.existing_pr != ''
205+
run: |
206+
echo "既存の repair PR があるため新規作成しません。"
207+
echo "${{ steps.target.outputs.existing_pr }}"

0 commit comments

Comments
 (0)