Merge pull request #3699 from Tibsfox/fix/import-done-milestones-as-complete

fix(gsd): import all-done milestones as complete during DB migration
This commit is contained in:
Jeremy McSpadden 2026-04-07 06:56:27 -05:00 committed by GitHub
commit bf1d7cfd4d
2 changed files with 52 additions and 5 deletions

View file

@ -530,11 +530,6 @@ export function migrateHierarchyToDb(basePath: string): {
// Ghost milestone: no CONTEXT, ROADMAP, or SUMMARY → skip
if (!hasRoadmap && !hasContext && !hasSummary) continue;
// Determine milestone status
let milestoneStatus = 'active';
if (hasSummary) milestoneStatus = 'complete';
else if (hasParked) milestoneStatus = 'parked';
// Determine milestone title from roadmap H1 or CONTEXT heading
let milestoneTitle = '';
let roadmapContent: string | null = null;
@ -544,6 +539,16 @@ export function migrateHierarchyToDb(basePath: string): {
roadmap = parseRoadmap(roadmapContent);
milestoneTitle = roadmap.title;
}
// Determine milestone status
let milestoneStatus = 'active';
if (hasSummary) milestoneStatus = 'complete';
else if (hasParked) milestoneStatus = 'parked';
// Import milestones with all-done roadmap slices as complete (#3390, #3379)
// even when SUMMARY.md is missing — the roadmap checkboxes are authoritative.
else if (roadmap && roadmap.slices.length > 0 && roadmap.slices.every(s => s.done)) {
milestoneStatus = 'complete';
}
if (!milestoneTitle && hasContext) {
const contextContent = readFileSync(contextPath!, 'utf-8');
const h1Match = contextContent.match(/^#\s+(.+)/m);

View file

@ -0,0 +1,42 @@
/**
* Regression test for #3699 import milestones with all-done slices as complete
*
* During DB migration, milestones whose roadmap slices are all marked done
* should be imported with status "complete" instead of "active".
*/
import { describe, test } from 'node:test';
import assert from 'node:assert/strict';
import { readFileSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const importerSrc = readFileSync(
join(__dirname, '..', 'md-importer.ts'),
'utf-8',
);
describe('import done milestones as complete (#3699)', () => {
test('all-slices-done check sets milestoneStatus to complete', () => {
// The importer should check if all roadmap slices are done
assert.match(importerSrc, /roadmap\.slices\.every\(s\s*=>\s*s\.done\)/,
'should check roadmap.slices.every(s => s.done)');
});
test('milestoneStatus is set to complete when all slices done', () => {
// Find the all-done guard and verify it sets 'complete'
const everyIdx = importerSrc.indexOf('roadmap.slices.every(s => s.done)');
assert.ok(everyIdx > -1, 'all-slices-done check should exist');
const afterCheck = importerSrc.slice(everyIdx, everyIdx + 200);
assert.match(afterCheck, /milestoneStatus\s*=\s*'complete'/,
'should set milestoneStatus to complete when all slices are done');
});
test('roadmap.slices.length > 0 guard prevents false positives', () => {
assert.match(importerSrc, /roadmap\.slices\.length\s*>\s*0/,
'should guard against empty slices array');
});
});