Skip to content

Commit 379b7d2

Browse files
authored
chore (CI): auto-set milestone on issues closed by merged PRs (baserow#5187)
* feat: auto-set milestone on issues closed by merged PRs Uses the DATABASE_CURRENT_MILESTONE repo variable to dynamically assign a milestone to linked issues when a domain-labeled PR is merged. * address copliot feedback * fix: set the milestone on the PR if no linked issues are available
1 parent fc20aaf commit 379b7d2

1 file changed

Lines changed: 65 additions & 3 deletions

File tree

.github/workflows/database-projects-pr-workflow.yml

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ env:
1111
REVIEW_AWAITING: 'Awaiting'
1212
REVIEW_FEEDBACK: 'Feedback'
1313
REVIEW_MERGE: 'Merge'
14+
MILESTONE_NAME: ${{ vars.DATABASE_CURRENT_MILESTONE }}
1415

1516
on:
1617
pull_request:
@@ -85,7 +86,7 @@ jobs:
8586
}
8687
}
8788
closingIssuesReferences(first: 10) {
88-
nodes { id, number }
89+
nodes { id, number, repository { owner { login }, name } }
8990
}
9091
}
9192
}
@@ -271,13 +272,74 @@ jobs:
271272
// UPDATE LINKED ISSUES
272273
// ============================================================
273274
274-
const linkedIssues = pr.closingIssuesReferences.nodes;
275+
// Filter to issues in this repo only (closingIssuesReferences can include cross-repo issues)
276+
const linkedIssues = pr.closingIssuesReferences.nodes.filter(issue => {
277+
const isLocal = issue.repository.owner.login === context.repo.owner
278+
&& issue.repository.name === context.repo.repo;
279+
if (!isLocal) console.log(` Skipping cross-repo issue #${issue.number} (${issue.repository.owner.login}/${issue.repository.name})`);
280+
return isLocal;
281+
});
282+
283+
// Resolve milestone if configured and PR was merged
284+
let milestoneNumber = null;
285+
const milestoneName = process.env.MILESTONE_NAME;
286+
if (pr.merged && milestoneName) {
287+
try {
288+
const milestones = await github.paginate(github.rest.issues.listMilestones, {
289+
owner: context.repo.owner,
290+
repo: context.repo.repo,
291+
state: 'open',
292+
per_page: 100,
293+
});
294+
const milestone = milestones.find(m => m.title === milestoneName);
295+
if (milestone) {
296+
milestoneNumber = milestone.number;
297+
console.log(`Will set milestone "${milestoneName}" (${milestoneNumber}) on linked issues`);
298+
} else {
299+
console.log(`Warning: milestone "${milestoneName}" not found, skipping milestone assignment`);
300+
}
301+
} catch (e) {
302+
console.log(`Warning: failed to resolve milestone "${milestoneName}": ${e.message}`);
303+
}
304+
}
305+
275306
if (linkedIssues.length > 0) {
276307
console.log(`Updating ${linkedIssues.length} linked issue(s)...`);
277308
for (const issue of linkedIssues) {
278309
const itemId = await ensureInProject(issue.id);
279310
await updateField(itemId, fieldOptions.status.id, fieldOptions.status[status]);
280-
console.log(` Issue #${issue.number} → ${status}`);
311+
312+
if (milestoneNumber) {
313+
try {
314+
await github.rest.issues.update({
315+
owner: context.repo.owner,
316+
repo: context.repo.repo,
317+
issue_number: issue.number,
318+
milestone: milestoneNumber,
319+
});
320+
console.log(` Issue #${issue.number} → ${status}, milestone "${milestoneName}"`);
321+
} catch (e) {
322+
console.log(` Warning: failed to set milestone on #${issue.number}: ${e.message}`);
323+
console.log(` Issue #${issue.number} → ${status}`);
324+
}
325+
} else {
326+
console.log(` Issue #${issue.number} → ${status}`);
327+
}
328+
}
329+
}
330+
331+
// If no linked issues, set milestone on the PR itself
332+
if (linkedIssues.length === 0 && milestoneNumber) {
333+
try {
334+
await github.rest.issues.update({
335+
owner: context.repo.owner,
336+
repo: context.repo.repo,
337+
issue_number: prNumber,
338+
milestone: milestoneNumber,
339+
});
340+
console.log(`No linked issues — set milestone "${milestoneName}" on PR #${prNumber}`);
341+
} catch (e) {
342+
console.log(`Warning: failed to set milestone on PR #${prNumber}: ${e.message}`);
281343
}
282344
}
283345

0 commit comments

Comments
 (0)