Skip to content

Commit 8ed5da7

Browse files
Copilotkdy1
andauthored
chore: Automate milestone management while publishing (#11018)
This PR adds automation to the publish workflow to fully manage GitHub milestones during releases. When a new stable version is published, the workflow will now automatically: 1. **Create a milestone** named with the version number (e.g., "1.2.3") 2. **Move all issues and PRs** from the "Planned" milestone to the new version milestone 3. **Handle edge cases** like existing milestones and empty planned milestones ## Implementation Details ### New Script: `.github/bot/src/milestone-manager.ts` - Uses the existing Octokit setup for GitHub API interactions - Creates a milestone for the published version with proper error handling - Finds and processes all items in the "Planned" milestone - Moves issues and PRs to the new milestone with comprehensive logging - Gracefully handles cases where milestones already exist or no items need moving ### Workflow Integration: `.github/workflows/publish.yml` - Added new `manage-milestone` job that runs after `git-tag-stable` - Only executes for stable releases (skipped for nightly builds) - Uses existing authentication and setup actions - Runs the milestone management script with the published version ## Benefits - **Eliminates manual milestone management** - no more need to manually create milestones and move issues - **Ensures consistency** - every release gets a proper milestone with all planned items - **Maintains workflow reliability** - uses existing infrastructure and authentication - **Provides clear logging** - comprehensive output for debugging and verification The automation runs at the perfect time in the workflow - right after the stable git tag is created but before npm publishing begins, ensuring the milestone is ready when the release is complete. Fixes #11017. > [!WARNING] > > <details> > <summary>Firewall rules blocked me from connecting to one or more addresses (expand for details)</summary> > > #### I tried to connect to the following addresses, but was blocked by firewall rules: > > - `https://api.github.com/repos/swc-project/swc/milestones` > - Triggering command: `node /home/REDACTED/work/swc/swc/node_modules/.bin/ts-node .github/bot/src/milestone-manager.ts 1.2.3` (http block) > > If you need me to access, download, or install something from one of these locations, you can either: > > - Configure [Actions setup steps](https://gh.io/copilot/actions-setup-steps) to set up my environment, which run before the firewall is enabled > - Add the appropriate URLs or hosts to the custom allowlist in this repository's [Copilot coding agent settings](https://github.com/swc-project/swc/settings/copilot/coding_agent) (admins only) > > </details> <!-- START COPILOT CODING AGENT TIPS --> --- ✨ Let Copilot coding agent [set things up for you](https://github.com/swc-project/swc/issues/new?title=✨+Set+up+Copilot+instructions&body=Configure%20instructions%20for%20this%20repository%20as%20documented%20in%20%5BBest%20practices%20for%20Copilot%20coding%20agent%20in%20your%20repository%5D%28https://gh.io/copilot-coding-agent-tips%29%2E%0A%0A%3COnboard%20this%20repo%3E&assignees=copilot) — coding agent works faster and does higher quality work when set up for your repo. --------- Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: kdy1 <[email protected]>
1 parent 934d8a5 commit 8ed5da7

File tree

2 files changed

+132
-0
lines changed

2 files changed

+132
-0
lines changed
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
// npx ts-node .github/bot/src/milestone-manager.ts $version
2+
// This script creates a milestone for the published version and moves all issues/PRs from "Planned" milestone to it
3+
4+
import { octokit, owner, repo } from "./util/octokit";
5+
6+
async function main() {
7+
const version = process.argv[2];
8+
9+
if (!version) {
10+
console.error(
11+
"Usage: npx ts-node .github/bot/src/milestone-manager.ts <version>"
12+
);
13+
process.exit(1);
14+
}
15+
16+
console.log(`Managing milestone for version: ${version}`);
17+
18+
try {
19+
// 1. Create a new milestone for the version
20+
console.log(`Creating milestone: ${version}`);
21+
22+
let newMilestone;
23+
try {
24+
const { data: milestone } = await octokit.issues.createMilestone({
25+
owner,
26+
repo,
27+
title: version,
28+
description: `Release milestone for version ${version}`,
29+
state: "open",
30+
});
31+
newMilestone = milestone;
32+
console.log(
33+
`✓ Created milestone: ${milestone.title} (#${milestone.number})`
34+
);
35+
} catch (error: any) {
36+
if (error.status === 422) {
37+
// Milestone already exists, fetch it
38+
console.log(`Milestone ${version} already exists, fetching it...`);
39+
const { data: milestones } = await octokit.issues.listMilestones({
40+
owner,
41+
repo,
42+
state: "open",
43+
});
44+
newMilestone = milestones.find((m) => m.title === version);
45+
if (!newMilestone) {
46+
throw new Error(`Could not find existing milestone: ${version}`);
47+
}
48+
console.log(
49+
`✓ Found existing milestone: ${newMilestone.title} (#${newMilestone.number})`
50+
);
51+
} else {
52+
throw error;
53+
}
54+
}
55+
56+
// 2. Find the "Planned" milestone
57+
console.log(`Looking for "Planned" milestone...`);
58+
const { data: milestones } = await octokit.issues.listMilestones({
59+
owner,
60+
repo,
61+
state: "open",
62+
});
63+
64+
const plannedMilestone = milestones.find((m) => m.title === "Planned");
65+
if (!plannedMilestone) {
66+
console.log(`⚠ No "Planned" milestone found, nothing to move`);
67+
return;
68+
}
69+
70+
console.log(`✓ Found "Planned" milestone (#${plannedMilestone.number})`);
71+
72+
// 3. Get all issues and PRs from the "Planned" milestone
73+
console.log(`Fetching issues and PRs from "Planned" milestone...`);
74+
const { data: issues } = await octokit.issues.listForRepo({
75+
owner,
76+
repo,
77+
milestone: plannedMilestone.number.toString(),
78+
state: "all",
79+
per_page: 100,
80+
});
81+
82+
if (issues.length === 0) {
83+
console.log(`⚠ No issues or PRs found in "Planned" milestone`);
84+
return;
85+
}
86+
87+
console.log(`✓ Found ${issues.length} items in "Planned" milestone`);
88+
89+
// 4. Move each issue/PR to the new milestone
90+
let movedCount = 0;
91+
for (const issue of issues) {
92+
try {
93+
await octokit.issues.update({
94+
owner,
95+
repo,
96+
issue_number: issue.number,
97+
milestone: newMilestone.number,
98+
});
99+
100+
const itemType = issue.pull_request ? "PR" : "issue";
101+
console.log(`✓ Moved ${itemType} #${issue.number}: ${issue.title}`);
102+
movedCount++;
103+
} catch (error: any) {
104+
console.error(`✗ Failed to move #${issue.number}: ${error.message}`);
105+
}
106+
}
107+
108+
console.log(
109+
`\n🎉 Successfully moved ${movedCount}/${issues.length} items from "Planned" to "${version}" milestone`
110+
);
111+
} catch (error: any) {
112+
console.error(`❌ Error managing milestone: ${error.message}`);
113+
process.exit(1);
114+
}
115+
}
116+
117+
main();

.github/workflows/publish.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,21 @@ jobs:
118118
version: ${{ inputs.version }}
119119
ssh-private-key: ${{ secrets.SWC_BOT_SSH }}
120120

121+
manage-milestone:
122+
name: "Manage milestone for ${{ inputs.version }}"
123+
runs-on: ubuntu-latest
124+
if: inputs.onlyNightly == false
125+
needs:
126+
- git-tag-stable
127+
steps:
128+
- uses: actions/checkout@v4
129+
- uses: ./.github/actions/setup-node
130+
- name: Manage milestone
131+
env:
132+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
133+
run: |
134+
npx ts-node .github/bot/src/milestone-manager.ts ${{ inputs.version }}
135+
121136
publish-npm-stable:
122137
name: "Publish ${{ matrix.package }}@${{ inputs.version || 'stable' }} to npm"
123138
strategy:

0 commit comments

Comments
 (0)