Trace every CR to a test case or delivered document, drop the draft FR/NFR remark column, record lessons learned, replace the three change reports with a change-control register, add high-level diagrams and wireframes to the design, plan verification rounds with dates and hours, and base the validation result on the Customer Requirements.
97 lines
4.7 KiB
JavaScript
97 lines
4.7 KiB
JavaScript
// Regenerate every ISO/IEC 29110 work product under sdlc/ from the controlled project data.
|
|
// Usage: node scripts/sdlc-seed/build.mjs
|
|
import fs from 'node:fs/promises';
|
|
import path from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
import * as pm1 from './docs-pm1.mjs';
|
|
import * as pm2 from './docs-pm2.mjs';
|
|
import * as si from './docs-si.mjs';
|
|
import * as si2 from './docs-si2.mjs';
|
|
import * as other from './docs-other.mjs';
|
|
|
|
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');
|
|
const target = path.join(root, 'sdlc');
|
|
const figureSource = path.join(path.dirname(fileURLToPath(import.meta.url)), 'figures');
|
|
|
|
// Folders that must exist even when a work product is evidence rather than a document.
|
|
const FOLDERS = [
|
|
'1-PM Process (10 Work Product)/1.Statement of Work',
|
|
'1-PM Process (10 Work Product)/2.Project Plan/1-Work Schedule',
|
|
'1-PM Process (10 Work Product)/2.Project Plan/2-Software Project Plan',
|
|
'1-PM Process (10 Work Product)/2.Project Plan/3-Customer Requirement',
|
|
'1-PM Process (10 Work Product)/3.Progress Status Record',
|
|
'1-PM Process (10 Work Product)/4.Correction Register',
|
|
'1-PM Process (10 Work Product)/5.Acceptance Report',
|
|
'1-PM Process (10 Work Product)/6.Change Report',
|
|
'1-PM Process (10 Work Product)/7.Meeting Record',
|
|
'1-PM Process (10 Work Product)/8.Software Configuration',
|
|
'1-PM Process (10 Work Product)/9.Project Repository',
|
|
'1-PM Process (10 Work Product)/10.Project Repository (Backup)',
|
|
'2-SI Process (12 Work Product)/11.Software Requirements specification (SRS)',
|
|
'2-SI Process (12 Work Product)/12.Software design',
|
|
'2-SI Process (12 Work Product)/13.Traceability record',
|
|
'2-SI Process (12 Work Product)/14.Software Components',
|
|
'2-SI Process (12 Work Product)/15.Test Cases and Test Procedures',
|
|
'2-SI Process (12 Work Product)/16.Test Report',
|
|
'2-SI Process (12 Work Product)/17.Software',
|
|
'2-SI Process (12 Work Product)/18.Software User Documentation',
|
|
'2-SI Process (12 Work Product)/19.Product Operation Guide',
|
|
'2-SI Process (12 Work Product)/20.Maintenance Documentation',
|
|
'2-SI Process (12 Work Product)/21.Verification Result',
|
|
'2-SI Process (12 Work Product)/22.Validation Result',
|
|
'3-Other Document',
|
|
];
|
|
|
|
function collect() {
|
|
const docs = [
|
|
pm1.statementOfWork(), pm1.workSchedule(), pm1.softwareProjectPlan(), pm1.customerRequirements(),
|
|
...pm2.progressStatusRecords(), pm2.correctionRegister(), pm2.acceptanceReport(),
|
|
...pm2.changeReports(), ...pm2.meetingRecords(),
|
|
pm2.softwareConfiguration(), pm2.projectRepository(), pm2.projectRepositoryBackup(),
|
|
si.softwareRequirements(), si.softwareDesign(), si.traceabilityRecord(), si.softwareComponents(),
|
|
si.testCases(), si.testReport(), si.software(),
|
|
si2.userDocumentation(), si2.operationGuide(), si2.maintenanceDocumentation(),
|
|
...si2.verificationResults(), si2.validationResults(),
|
|
other.stakeholderRegister(), other.projectCharter(), other.traceabilityTable(), other.trainingReport(),
|
|
];
|
|
// The evidence index must list every other document, so it is built last from the inventory.
|
|
docs.push(other.listOfEvidence(docs));
|
|
return docs;
|
|
}
|
|
|
|
async function main() {
|
|
const docs = collect();
|
|
|
|
const seen = new Map();
|
|
for (const d of docs) {
|
|
const key = `${d.dir}/${d.name}`;
|
|
if (seen.has(key)) throw new Error(`Duplicate document name: ${key}`);
|
|
seen.set(key, d);
|
|
if (!FOLDERS.includes(d.dir)) throw new Error(`Unknown folder for ${d.name}: ${d.dir}`);
|
|
}
|
|
|
|
await fs.rm(target, { recursive: true, force: true });
|
|
for (const folder of FOLDERS) await fs.mkdir(path.join(target, folder), { recursive: true });
|
|
for (const d of docs) {
|
|
await fs.writeFile(path.join(target, d.dir, `${d.name}.md`), d.md, 'utf8');
|
|
// Figures referenced as  are copied next to the document.
|
|
for (const [, file] of d.md.matchAll(/^!\[[^\]]*\]\(figures\/([^)]+)\)$/gm)) {
|
|
const from = path.join(figureSource, file);
|
|
try { await fs.access(from); } catch { throw new Error(`${d.name} references missing figure ${file}; run scripts/sdlc-delivery/render-figures.mjs`); }
|
|
await fs.mkdir(path.join(target, d.dir, 'figures'), { recursive: true });
|
|
await fs.copyFile(from, path.join(target, d.dir, 'figures', file));
|
|
}
|
|
}
|
|
|
|
const empty = [];
|
|
for (const folder of FOLDERS) {
|
|
const entries = await fs.readdir(path.join(target, folder));
|
|
if (!entries.some((e) => e.endsWith('.md'))) empty.push(folder);
|
|
}
|
|
if (empty.length) throw new Error(`Folders with no work product:\n- ${empty.join('\n- ')}`);
|
|
|
|
console.log(`Generated ${docs.length} work products across ${FOLDERS.length} folders.`);
|
|
}
|
|
|
|
main().catch((error) => { console.error(error); process.exit(1); });
|