Merge pull request #2737 from gsd-build/fix/2726-phase-add-bullet-bold-roadmap
fix(phase-lifecycle): detect phases in bullet/bold ROADMAP formats for phase.add
This commit is contained in:
@@ -245,6 +245,100 @@ describe('phaseAdd', () => {
|
||||
expect(phaseIdx).toBeLessThan(sepIdx);
|
||||
expect(phaseIdx).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('detects max phase from bullet checklist format (regression #2726)', async () => {
|
||||
const { phaseAdd } = await import('./phase-lifecycle.js');
|
||||
|
||||
const roadmap = [
|
||||
'# Roadmap',
|
||||
'',
|
||||
'## Current Milestone: v5.0',
|
||||
'',
|
||||
'- [x] Phase 76: Data Import',
|
||||
'- [x] Phase 77: Data Transform',
|
||||
'- [ ] Phase 88: Final Cleanup',
|
||||
'',
|
||||
].join('\n');
|
||||
|
||||
await setupTestProject(tmpDir, {
|
||||
roadmap,
|
||||
state: MINIMAL_STATE,
|
||||
phases: [],
|
||||
});
|
||||
|
||||
const result = await phaseAdd(['new-feature'], tmpDir);
|
||||
const data = result.data as Record<string, unknown>;
|
||||
|
||||
expect(data.phase_number).toBe(89);
|
||||
expect(data.padded).toBe('89');
|
||||
});
|
||||
|
||||
it('detects max phase from bold inline format (regression #2726)', async () => {
|
||||
const { phaseAdd } = await import('./phase-lifecycle.js');
|
||||
|
||||
const roadmap = [
|
||||
'# Roadmap',
|
||||
'',
|
||||
'## Current Milestone: v5.0',
|
||||
'',
|
||||
'**Phase 50: Core Infrastructure**',
|
||||
'**Phase 51: API Layer**',
|
||||
'',
|
||||
].join('\n');
|
||||
|
||||
await setupTestProject(tmpDir, {
|
||||
roadmap,
|
||||
state: MINIMAL_STATE,
|
||||
phases: [],
|
||||
});
|
||||
|
||||
const result = await phaseAdd(['new-feature'], tmpDir);
|
||||
const data = result.data as Record<string, unknown>;
|
||||
|
||||
expect(data.phase_number).toBe(52);
|
||||
});
|
||||
|
||||
it('falls back to filesystem scan when no phase matches in ROADMAP (regression #2726)', async () => {
|
||||
const { phaseAdd } = await import('./phase-lifecycle.js');
|
||||
|
||||
// ROADMAP with no recognizable phase entries
|
||||
const roadmap = '# Roadmap\n\n## Current Milestone: v5.0\n\nSome content without phases\n';
|
||||
|
||||
await setupTestProject(tmpDir, {
|
||||
roadmap,
|
||||
state: MINIMAL_STATE,
|
||||
phases: ['45-legacy-phase', '46-another-phase'],
|
||||
});
|
||||
|
||||
const result = await phaseAdd(['new-feature'], tmpDir);
|
||||
const data = result.data as Record<string, unknown>;
|
||||
|
||||
// Should detect phases 45 and 46 on disk, so new phase = 47
|
||||
expect(data.phase_number).toBe(47);
|
||||
});
|
||||
|
||||
it('filesystem fallback handles project-code-prefixed phase directories (regression coderabbit)', async () => {
|
||||
const { phaseAdd } = await import('./phase-lifecycle.js');
|
||||
|
||||
const roadmap = '# Roadmap\n\n## Current Milestone: v5.0\n\nSome content\n';
|
||||
|
||||
await setupTestProject(tmpDir, {
|
||||
roadmap,
|
||||
state: MINIMAL_STATE,
|
||||
phases: [],
|
||||
});
|
||||
|
||||
// Create prefixed directories manually (project_code = "CK" scenario)
|
||||
const phasesDir = join(tmpDir, '.planning', 'phases');
|
||||
await mkdir(join(phasesDir, 'CK-45-legacy-phase'), { recursive: true });
|
||||
await mkdir(join(phasesDir, 'CK-46-another-phase'), { recursive: true });
|
||||
|
||||
const result = await phaseAdd(['new-feature'], tmpDir);
|
||||
const data = result.data as Record<string, unknown>;
|
||||
|
||||
// Should detect CK-45 and CK-46, so new phase = 47
|
||||
expect(data.phase_number).toBe(47);
|
||||
});
|
||||
});
|
||||
|
||||
// ─── phaseAddBatch ─────────────────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user