Skip to content

Commit ebb8eed

Browse files
authored
ci: Add action to creatae issue on gitflow merge conflicts (#18319)
It's often hard to notice when our Gitflow merge PRs fail due to merge conflicts and the longer they are open the harder it will be to fix these merge conflicts eventually. e.g. #18314 This is an attempt at notifying us better when these happen by creating an issue in our repo (did not actually test this yet so we might have to go through some iterations 😅). Idea by Abhi: #18317 (review)
1 parent 1df6ff9 commit ebb8eed

File tree

1 file changed

+107
-0
lines changed

1 file changed

+107
-0
lines changed
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
name: 'Gitflow: Merge Conflict Issue'
2+
3+
on:
4+
pull_request:
5+
types: [opened]
6+
branches:
7+
- develop
8+
9+
jobs:
10+
check-merge-conflicts:
11+
name: Detect merge conflicts in gitflow PRs
12+
runs-on: ubuntu-24.04
13+
if: |
14+
${{ contains(github.event.pull_request.labels.*.name, 'Dev: Gitflow') }}
15+
permissions:
16+
issues: write
17+
steps:
18+
- name: Check for merge conflicts with retry
19+
uses: actions/github-script@v8
20+
with:
21+
script: |
22+
const retryInterval = 30_000;
23+
const maxRetries = 10; // (30 seconds * 10 retries) = 5 minutes
24+
25+
async function isMergeable() {
26+
const { data: pr } = await github.rest.pulls.get({
27+
owner: context.repo.owner,
28+
repo: context.repo.repo,
29+
pull_number: context.payload.pull_request.number
30+
});
31+
32+
return pr.mergeable;
33+
}
34+
35+
async function sleep(ms) {
36+
return new Promise(resolve => setTimeout(resolve, ms));
37+
}
38+
39+
let attempt = 0;
40+
let mergeable = null;
41+
42+
while (attempt < maxRetries) {
43+
attempt++;
44+
console.log(`Attempt ${attempt}/${maxRetries}: Checking if PR is mergeable...`);
45+
46+
mergeable = await isMergeable();
47+
console.log(`Mergeable: ${mergeable}`);
48+
49+
// If mergeable is not null, GitHub has finished computing merge state
50+
if (mergeable !== null) {
51+
break;
52+
}
53+
54+
if (attempt < maxRetries) {
55+
console.log(`Waiting ${retryInterval/1000} seconds before retry...`);
56+
await sleep(retryInterval);
57+
}
58+
}
59+
60+
// Check if we have merge conflicts
61+
if (mergeable === false) {
62+
const issueTitle = '[Gitflow] Merge Conflict';
63+
64+
// Check for existing open issues with the same title
65+
const { data: existingIssues } = await github.rest.issues.listForRepo({
66+
owner: context.repo.owner,
67+
repo: context.repo.repo,
68+
state: 'open',
69+
labels: 'Dev: Gitflow'
70+
});
71+
72+
const existingOpenIssue = existingIssues.find(issue =>
73+
issue.title === issueTitle && !issue.pull_request
74+
);
75+
76+
if (!existingOpenIssue) {
77+
const issueBody = [
78+
'## Gitflow Merge Conflict Detected',
79+
'',
80+
`The automated gitflow PR #${context.payload.pull_request.number} has merge conflicts and cannot be merged automatically.`,
81+
'',
82+
'### How to resolve',
83+
'',
84+
`Follow the steps documented in [docs/gitflow.md](https://github.com/${context.repo.owner}/${context.repo.repo}/blob/develop/docs/gitflow.md#what-to-do-if-there-is-a-merge-conflict):`,
85+
'',
86+
`1. Close the automated PR #${context.payload.pull_request.number}`,
87+
'2. Create a new branch on top of `master` (e.g., `manual-develop-sync`)',
88+
'3. Merge `develop` into this branch with a **merge commit** (fix any merge conflicts)',
89+
'4. Create a PR against `develop` from your branch',
90+
'5. Merge that PR with a **merge commit**'
91+
].join('\n');
92+
93+
await github.rest.issues.create({
94+
owner: context.repo.owner,
95+
repo: context.repo.repo,
96+
title: issueTitle,
97+
body: issueBody,
98+
labels: ['Dev: Gitflow']
99+
});
100+
101+
console.log('Created new issue for merge conflict');
102+
}
103+
} else if (mergeable === null) {
104+
console.log('Could not determine mergeable state after maximum retries');
105+
} else {
106+
console.log('No merge conflicts detected - PR can be merged');
107+
}

0 commit comments

Comments
 (0)