fix: getMilestoneInfo() returns wrong version after milestone completion (#768)
Strip <details> blocks (shipped milestones) before matching, and extract both version and name from the same ## heading for consistency.
This commit is contained in:
@@ -379,11 +379,21 @@ function generateSlugInternal(text) {
|
||||
function getMilestoneInfo(cwd) {
|
||||
try {
|
||||
const roadmap = fs.readFileSync(path.join(cwd, '.planning', 'ROADMAP.md'), 'utf-8');
|
||||
const versionMatch = roadmap.match(/v(\d+\.\d+)/);
|
||||
const nameMatch = roadmap.match(/## .*v\d+\.\d+[:\s]+([^\n(]+)/);
|
||||
// Strip <details>...</details> blocks so shipped milestones don't interfere
|
||||
const cleaned = roadmap.replace(/<details>[\s\S]*?<\/details>/gi, '');
|
||||
// Extract version and name from the same ## heading for consistency
|
||||
const headingMatch = cleaned.match(/## .*v(\d+\.\d+)[:\s]+([^\n(]+)/);
|
||||
if (headingMatch) {
|
||||
return {
|
||||
version: 'v' + headingMatch[1],
|
||||
name: headingMatch[2].trim(),
|
||||
};
|
||||
}
|
||||
// Fallback: try bare version match
|
||||
const versionMatch = cleaned.match(/v(\d+\.\d+)/);
|
||||
return {
|
||||
version: versionMatch ? versionMatch[0] : 'v1.0',
|
||||
name: nameMatch ? nameMatch[1].trim() : 'milestone',
|
||||
name: 'milestone',
|
||||
};
|
||||
} catch {
|
||||
return { version: 'v1.0', name: 'milestone' };
|
||||
|
||||
@@ -398,6 +398,80 @@ describe('getMilestoneInfo', () => {
|
||||
assert.strictEqual(info.version, 'v1.0');
|
||||
assert.strictEqual(info.name, 'milestone');
|
||||
});
|
||||
|
||||
test('returns active milestone when shipped milestone is collapsed in details block', () => {
|
||||
const roadmap = [
|
||||
'# Milestones',
|
||||
'',
|
||||
'| Version | Status |',
|
||||
'|---------|--------|',
|
||||
'| v0.1 | Shipped |',
|
||||
'| v0.2 | Active |',
|
||||
'',
|
||||
'<details>',
|
||||
'<summary>v0.1 — Legacy Feature Parity (Shipped)</summary>',
|
||||
'',
|
||||
'## Roadmap v0.1: Legacy Feature Parity',
|
||||
'',
|
||||
'### Phase 1: Core Setup',
|
||||
'Some content about phase 1',
|
||||
'',
|
||||
'</details>',
|
||||
'',
|
||||
'## Roadmap v0.2: Dashboard Overhaul',
|
||||
'',
|
||||
'### Phase 8: New Dashboard Layout',
|
||||
'Some content about phase 8',
|
||||
].join('\n');
|
||||
fs.writeFileSync(path.join(tmpDir, '.planning', 'ROADMAP.md'), roadmap);
|
||||
const info = getMilestoneInfo(tmpDir);
|
||||
assert.strictEqual(info.version, 'v0.2');
|
||||
assert.strictEqual(info.name, 'Dashboard Overhaul');
|
||||
});
|
||||
|
||||
test('returns active milestone when multiple shipped milestones exist in details blocks', () => {
|
||||
const roadmap = [
|
||||
'# Milestones',
|
||||
'',
|
||||
'| Version | Status |',
|
||||
'|---------|--------|',
|
||||
'| v0.1 | Shipped |',
|
||||
'| v0.2 | Shipped |',
|
||||
'| v0.3 | Active |',
|
||||
'',
|
||||
'<details>',
|
||||
'<summary>v0.1 — Initial Release (Shipped)</summary>',
|
||||
'',
|
||||
'## Roadmap v0.1: Initial Release',
|
||||
'',
|
||||
'</details>',
|
||||
'',
|
||||
'<details>',
|
||||
'<summary>v0.2 — Feature Expansion (Shipped)</summary>',
|
||||
'',
|
||||
'## Roadmap v0.2: Feature Expansion',
|
||||
'',
|
||||
'</details>',
|
||||
'',
|
||||
'## Roadmap v0.3: Performance Tuning',
|
||||
'',
|
||||
'### Phase 12: Optimize Queries',
|
||||
].join('\n');
|
||||
fs.writeFileSync(path.join(tmpDir, '.planning', 'ROADMAP.md'), roadmap);
|
||||
const info = getMilestoneInfo(tmpDir);
|
||||
assert.strictEqual(info.version, 'v0.3');
|
||||
assert.strictEqual(info.name, 'Performance Tuning');
|
||||
});
|
||||
|
||||
test('returns defaults when roadmap has no heading matches', () => {
|
||||
fs.writeFileSync(
|
||||
path.join(tmpDir, '.planning', 'ROADMAP.md'),
|
||||
'# Roadmap\n\nSome content without version headings'
|
||||
);
|
||||
const info = getMilestoneInfo(tmpDir);
|
||||
assert.strictEqual(info.version, 'v1.0');
|
||||
assert.strictEqual(info.name, 'milestone');
|
||||
});
|
||||
});
|
||||
|
||||
// ─── searchPhaseInDir ──────────────────────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user