Skip to content

Commit a06bd69

Browse files
authored
Merge pull request #45 from carstenartur/copilot/add-rebase-workflow-actions
2 parents f96239d + 32aef9b commit a06bd69

1 file changed

Lines changed: 259 additions & 0 deletions

File tree

Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
name: Rebase on Upstream Master
2+
3+
on:
4+
pull_request:
5+
types: [opened]
6+
issue_comment:
7+
types: [created]
8+
9+
jobs:
10+
add-rebase-button:
11+
name: Add Rebase Instructions
12+
if: github.event_name == 'pull_request'
13+
runs-on: ubuntu-latest
14+
permissions:
15+
pull-requests: write
16+
steps:
17+
- name: Add comment with rebase instructions
18+
uses: actions/github-script@v7
19+
with:
20+
script: |
21+
const comment = `### 🔄 Rebase on Upstream Master
22+
23+
To rebase this PR branch onto the latest \`eclipse-jdt/eclipse.jdt.debug:master\`, comment:
24+
25+
\`\`\`
26+
/rebase-upstream
27+
\`\`\`
28+
29+
This will:
30+
1. Fetch the latest changes from \`eclipse-jdt/eclipse.jdt.debug:master\`
31+
2. Rebase your branch onto it
32+
3. Force push the rebased branch
33+
34+
[View workflow runs](${context.payload.repository.html_url}/actions/workflows/rebase-upstream.yml)`;
35+
36+
github.rest.issues.createComment({
37+
issue_number: context.issue.number,
38+
owner: context.repo.owner,
39+
repo: context.repo.repo,
40+
body: comment
41+
});
42+
43+
rebase-upstream:
44+
name: Rebase on Upstream Master
45+
if: |
46+
github.event_name == 'issue_comment' &&
47+
github.event.issue.pull_request != null &&
48+
contains(github.event.comment.body, '/rebase-upstream')
49+
runs-on: ubuntu-latest
50+
permissions:
51+
contents: write
52+
pull-requests: write
53+
steps:
54+
- name: Check if user is authorized
55+
id: check-auth
56+
uses: actions/github-script@v7
57+
with:
58+
script: |
59+
const author_association = context.payload.comment.author_association;
60+
const authorized = ['OWNER', 'MEMBER', 'COLLABORATOR'].includes(author_association);
61+
62+
if (!authorized) {
63+
await github.rest.issues.createComment({
64+
issue_number: context.issue.number,
65+
owner: context.repo.owner,
66+
repo: context.repo.repo,
67+
body: `@${context.payload.comment.user.login} ❌ Only repository owners, members, and collaborators can trigger the rebase.`
68+
});
69+
core.setFailed('User not authorized to trigger rebase');
70+
}
71+
72+
return authorized;
73+
74+
- name: Add rocket reaction to acknowledge command
75+
if: steps.check-auth.outputs.result == 'true'
76+
uses: actions/github-script@v7
77+
with:
78+
script: |
79+
github.rest.reactions.createForIssueComment({
80+
owner: context.repo.owner,
81+
repo: context.repo.repo,
82+
comment_id: context.payload.comment.id,
83+
content: 'rocket'
84+
});
85+
86+
- name: Get PR branch information
87+
if: steps.check-auth.outputs.result == 'true'
88+
id: pr-info
89+
uses: actions/github-script@v7
90+
with:
91+
script: |
92+
const { data: pr } = await github.rest.pulls.get({
93+
owner: context.repo.owner,
94+
repo: context.repo.repo,
95+
pull_number: context.issue.number
96+
});
97+
98+
if (!pr.head.repo) {
99+
await github.rest.issues.createComment({
100+
issue_number: context.issue.number,
101+
owner: context.repo.owner,
102+
repo: context.repo.repo,
103+
body: '❌ Cannot rebase: The source repository has been deleted. Please close and recreate this PR from an active fork.'
104+
});
105+
core.setFailed('Source repository has been deleted');
106+
return;
107+
}
108+
109+
core.setOutput('head_ref', pr.head.ref);
110+
core.setOutput('head_repo', pr.head.repo.full_name);
111+
core.setOutput('head_sha', pr.head.sha);
112+
113+
- name: Checkout PR branch
114+
if: steps.check-auth.outputs.result == 'true'
115+
uses: actions/checkout@v4
116+
with:
117+
# Security note: This checks out untrusted code, but is protected by:
118+
# 1. Authorization check (only OWNER/MEMBER/COLLABORATOR can trigger)
119+
# 2. No code from the PR is executed - only git operations are performed
120+
# 3. Similar security model to the existing rebase workflow in this repo
121+
repository: ${{ steps.pr-info.outputs.head_repo }}
122+
ref: ${{ steps.pr-info.outputs.head_ref }}
123+
token: ${{ secrets.GITHUB_TOKEN }}
124+
fetch-depth: 0
125+
126+
- name: Configure Git
127+
if: steps.check-auth.outputs.result == 'true'
128+
run: |
129+
git config user.name "github-actions[bot]"
130+
git config user.email "github-actions[bot]@users.noreply.github.com"
131+
132+
- name: Add upstream remote and rebase
133+
if: steps.check-auth.outputs.result == 'true'
134+
id: rebase
135+
run: |
136+
# Disable automatic exit on error to manually handle rebase failures
137+
set +e
138+
git remote add upstream https://github.com/eclipse-jdt/eclipse.jdt.debug.git
139+
git fetch upstream master
140+
141+
echo "Rebasing onto upstream/master..."
142+
git rebase upstream/master
143+
REBASE_EXIT_CODE=$?
144+
145+
if [ $REBASE_EXIT_CODE -ne 0 ]; then
146+
echo "rebase_failed=true" >> $GITHUB_OUTPUT
147+
git rebase --abort || true
148+
exit 1
149+
fi
150+
151+
echo "rebase_failed=false" >> $GITHUB_OUTPUT
152+
exit 0
153+
154+
- name: Force push with lease
155+
if: steps.check-auth.outputs.result == 'true' && steps.rebase.outputs.rebase_failed != 'true'
156+
id: push
157+
run: |
158+
# Note: GITHUB_TOKEN has write access to the fork if the PR author has enabled
159+
# "Allow edits by maintainers" (enabled by default for most PRs)
160+
# Disable automatic exit on error to manually handle push failures
161+
set +e
162+
git push --force-with-lease origin ${{ steps.pr-info.outputs.head_ref }}
163+
PUSH_EXIT_CODE=$?
164+
165+
if [ $PUSH_EXIT_CODE -ne 0 ]; then
166+
echo "push_failed=true" >> $GITHUB_OUTPUT
167+
exit 1
168+
fi
169+
170+
echo "push_failed=false" >> $GITHUB_OUTPUT
171+
exit 0
172+
173+
- name: Add success comment and reaction
174+
if: steps.check-auth.outputs.result == 'true' && steps.rebase.outputs.rebase_failed != 'true' && steps.push.outputs.push_failed != 'true'
175+
uses: actions/github-script@v7
176+
with:
177+
script: |
178+
await github.rest.reactions.createForIssueComment({
179+
owner: context.repo.owner,
180+
repo: context.repo.repo,
181+
comment_id: context.payload.comment.id,
182+
content: '+1'
183+
});
184+
185+
await github.rest.issues.createComment({
186+
issue_number: context.issue.number,
187+
owner: context.repo.owner,
188+
repo: context.repo.repo,
189+
body: '✅ Successfully rebased onto `eclipse-jdt/eclipse.jdt.debug:master`'
190+
});
191+
192+
- name: Add rebase failure comment and reaction
193+
if: steps.check-auth.outputs.result == 'true' && failure() && steps.rebase.outputs.rebase_failed == 'true'
194+
uses: actions/github-script@v7
195+
with:
196+
script: |
197+
await github.rest.reactions.createForIssueComment({
198+
owner: context.repo.owner,
199+
repo: context.repo.repo,
200+
comment_id: context.payload.comment.id,
201+
content: '-1'
202+
});
203+
204+
const comment = `❌ Rebase failed due to conflicts.
205+
206+
To rebase manually:
207+
\`\`\`bash
208+
git remote add upstream https://github.com/eclipse-jdt/eclipse.jdt.debug.git
209+
git fetch upstream master
210+
git rebase upstream/master
211+
# Resolve conflicts
212+
git rebase --continue
213+
git push --force-with-lease
214+
\`\`\``;
215+
216+
await github.rest.issues.createComment({
217+
issue_number: context.issue.number,
218+
owner: context.repo.owner,
219+
repo: context.repo.repo,
220+
body: comment
221+
});
222+
223+
- name: Add push failure comment and reaction
224+
if: steps.check-auth.outputs.result == 'true' && failure() && steps.push.outputs.push_failed == 'true'
225+
uses: actions/github-script@v7
226+
with:
227+
script: |
228+
await github.rest.reactions.createForIssueComment({
229+
owner: context.repo.owner,
230+
repo: context.repo.repo,
231+
comment_id: context.payload.comment.id,
232+
content: '-1'
233+
});
234+
235+
const comment = `❌ Rebase succeeded but push failed due to insufficient permissions.
236+
237+
**Possible causes:**
238+
- The PR author has not enabled "Allow edits by maintainers"
239+
- The fork repository has restricted push access
240+
241+
**To enable automatic rebase:**
242+
1. Go to the PR page
243+
2. Check "Allow edits by maintainers" in the sidebar
244+
3. Try the \`/rebase-upstream\` command again
245+
246+
**Or rebase manually:**
247+
\`\`\`bash
248+
git remote add upstream https://github.com/eclipse-jdt/eclipse.jdt.debug.git
249+
git fetch upstream master
250+
git rebase upstream/master
251+
git push --force-with-lease
252+
\`\`\``;
253+
254+
await github.rest.issues.createComment({
255+
issue_number: context.issue.number,
256+
owner: context.repo.owner,
257+
repo: context.repo.repo,
258+
body: comment
259+
});

0 commit comments

Comments
 (0)