Skip to content

Commit 5e333db

Browse files
MrSidimsjsji
authored andcommitted
Add actions job to create backports (#3156)
Example use: /backport llvm_release_190 Expected behaviour: IF user input != /backport llvm_release<digits> THEN out << Invalid backport command. Expected /backport llvm_release_<digits> STOP out << Attempting to create PR to <target>... IF merge_conflict THEN out << Backport to <target> failed due to conflicts on commit <sha>. Please backport manually. STOP ELSE create_pr AND out << Success. Backport PR created: <PR_URL> SUCCESS Signed-off-by: Sidorov, Dmitry <[email protected]> Original commit: KhronosGroup/SPIRV-LLVM-Translator@5cf776c1fb980d7
1 parent 6495e45 commit 5e333db

File tree

1 file changed

+175
-0
lines changed

1 file changed

+175
-0
lines changed
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
name: Backport on Comment
2+
3+
# Example use: /backport llvm_release_190
4+
on:
5+
issue_comment:
6+
types: [created]
7+
8+
permissions:
9+
contents: write
10+
pull-requests: write
11+
issues: read
12+
13+
jobs:
14+
backport:
15+
if: >
16+
github.event.issue.pull_request != null &&
17+
startsWith(github.event.comment.body, '/backport ')
18+
runs-on: ubuntu-latest
19+
20+
steps:
21+
- name: Checkout repository
22+
uses: actions/checkout@v4
23+
with:
24+
fetch-depth: 0
25+
26+
- name: Configure Git
27+
run: |
28+
git config user.name "${{ github.actor }}"
29+
git config user.email "${{ github.actor }}@users.noreply.github.com"
30+
31+
- name: Ensure PR is merged
32+
uses: actions/github-script@v7
33+
with:
34+
script: |
35+
const pr = await github.rest.pulls.get({
36+
owner: context.repo.owner,
37+
repo: context.repo.repo,
38+
pull_number: context.issue.number
39+
});
40+
if (!pr.data.merged) {
41+
core.setFailed('PR #' + context.issue.number + ' is not merged.');
42+
}
43+
44+
- name: Parse backport command
45+
uses: actions/github-script@v7
46+
with:
47+
github-token: ${{ secrets.GITHUB_TOKEN }}
48+
result-encoding: string
49+
script: |
50+
const body = context.payload.comment.body.trim();
51+
const msg = body.match(/^\/backport\s+(llvm_release_[0-9]+)$/);
52+
if (!msg) {
53+
await github.rest.issues.createComment({
54+
owner: context.repo.owner,
55+
repo: context.repo.repo,
56+
issue_number: context.issue.number,
57+
body: 'Invalid backport command. Expected `/backport llvm_release_<digits>`'
58+
});
59+
throw new Error('Invalid backport command.');
60+
}
61+
core.exportVariable('TARGET', msg[1]);
62+
63+
- name: Notify attempt
64+
uses: actions/github-script@v7
65+
with:
66+
script: |
67+
const target = process.env.TARGET;
68+
await github.rest.issues.createComment({
69+
owner: context.repo.owner,
70+
repo: context.repo.repo,
71+
issue_number: context.issue.number,
72+
body: `Attempting to create backport to \`${target}\`...`
73+
});
74+
75+
- name: Create backport branch
76+
run: |
77+
git fetch origin ${{ env.TARGET }}:${{ env.TARGET }}
78+
git checkout -b backport/pr-${{ github.event.issue.number }}-to-${{ env.TARGET }} origin/${{ env.TARGET }}
79+
80+
- name: Get list of PR commits
81+
id: commits
82+
uses: actions/github-script@v7
83+
with:
84+
result-encoding: string
85+
script: |
86+
const { data } = await github.rest.pulls.listCommits({
87+
owner: context.repo.owner,
88+
repo: context.repo.repo,
89+
pull_number: context.issue.number
90+
});
91+
return data.map(c => c.sha).join(' ');
92+
93+
- name: Cherry-pick commits
94+
id: cherry
95+
run: |
96+
conflict=false
97+
for sha in ${{ steps.commits.outputs.result }}; do
98+
echo "Cherry-picking $sha"
99+
if git cherry-pick "$sha"; then
100+
echo "$sha"
101+
else
102+
echo "Conflict on $sha"
103+
conflict=true
104+
echo "CONFLICT_SHA=$sha" >> $GITHUB_ENV
105+
break
106+
fi
107+
done
108+
echo "CONFLICT=$conflict" >> $GITHUB_ENV
109+
110+
- name: Notify conflict
111+
if: env.CONFLICT == 'true'
112+
uses: actions/github-script@v7
113+
with:
114+
github-token: ${{ secrets.GITHUB_TOKEN }}
115+
script: |
116+
const sha = process.env.CONFLICT_SHA;
117+
const target = process.env.TARGET;
118+
await github.rest.issues.createComment({
119+
owner: context.repo.owner,
120+
repo: context.repo.repo,
121+
issue_number: context.issue.number,
122+
body: `Backport to \`${target}\` failed due to conflicts on commit \`${sha}\`. Please backport manually.`
123+
});
124+
125+
- name: Stop on conflict
126+
if: env.CONFLICT == 'true'
127+
run: exit 0
128+
129+
- name: Push backport branch
130+
if: env.CONFLICT == 'false'
131+
run: git push --set-upstream origin HEAD
132+
133+
- name: Prepare PR
134+
if: env.CONFLICT == 'false'
135+
id: prinfo
136+
run: |
137+
echo "BODY<<EOF" >> $GITHUB_ENV
138+
echo "Backport of PR #${{ github.event.issue.number }} into \`${{ env.TARGET }}\`." >> $GITHUB_ENV
139+
echo "" >> $GITHUB_ENV
140+
echo "All commits applied cleanly." >> $GITHUB_ENV
141+
echo "EOF" >> $GITHUB_ENV
142+
echo "LABELS=backport" >> $GITHUB_ENV
143+
144+
- name: Create Pull Request
145+
if: env.CONFLICT == 'false'
146+
id: create_pr
147+
uses: actions/github-script@v7
148+
with:
149+
github-token: ${{ secrets.GITHUB_TOKEN }}
150+
result-encoding: string
151+
script: |
152+
const {data: pr} = await github.rest.pulls.create({
153+
owner: context.repo.owner,
154+
repo: context.repo.repo,
155+
head: `backport/pr-${context.issue.number}-to-${process.env.TARGET}`,
156+
base: process.env.TARGET,
157+
title: `[Backport to ${process.env.TARGET}] ${context.payload.issue.title}`,
158+
body: process.env.BODY
159+
});
160+
return pr.html_url;
161+
162+
- name: Notify success
163+
if: env.CONFLICT == 'false'
164+
uses: actions/github-script@v7
165+
env:
166+
PR_URL: ${{ steps.create_pr.outputs.result }}
167+
with:
168+
script: |
169+
const target = process.env.TARGET;
170+
await github.rest.issues.createComment({
171+
owner: context.repo.owner,
172+
repo: context.repo.repo,
173+
issue_number: context.issue.number,
174+
body: `Success. Backport PR created: ${process.env.PR_URL}`
175+
});

0 commit comments

Comments
 (0)