/** * This script updates the CHANGELOG when a new minor version is created. * * @author n1474335 [n1474335@gmail.com] * @copyright Crown Copyright 2022 * @license Apache-2.0 */ /* eslint no-console: ["off"] */ import prompt from "prompt"; import colors from "colors"; import path from "path"; import fs from "fs"; import process from "process"; const dir = path.join(process.cwd() + "/src/core/config/"); if (!fs.existsSync(dir)) { console.log("\nCWD: " + process.cwd()); console.log("Error: newMinorVersion.mjs should be run from the project root"); console.log("Example> node --experimental-modules src/core/config/scripts/newMinorVersion.mjs"); process.exit(1); } let changelogData = fs.readFileSync(path.join(process.cwd(), "CHANGELOG.md"), "utf8"); const lastVersion = changelogData.match(/## Details\s+### \[(\d+)\.(\d+)\.(\d+)\]/); const newVersion = [ parseInt(lastVersion[1], 10), parseInt(lastVersion[2], 10) + 1, 0 ]; let knownContributors = changelogData.match(/^\[@([^\]]+)\]/gm); knownContributors = knownContributors.map(c => c.slice(2, -1)); const date = (new Date()).toISOString().split("T")[0]; const schema = { properties: { message: { description: "A short but descriptive summary of a feature in this version", example: "Added 'Op name' operation", prompt: "Feature description", type: "string", required: true, }, author: { description: "The author of the feature (only one supported, edit manually to add more)", example: "n1474335", prompt: "Author", type: "string", default: "n1474335" }, id: { description: "The PR number or full commit hash for this feature.", example: "1200", prompt: "Pull request or commit ID", type: "string" }, another: { description: "y/n", example: "y", prompt: "Add another feature?", type: "string", pattern: /^[yn]$/, } } }; // Build schema for (const prop in schema.properties) { const p = schema.properties[prop]; p.description = "\n" + colors.white(p.description) + colors.cyan("\nExample: " + p.example) + "\n" + colors.green(p.prompt); } prompt.message = ""; prompt.delimiter = ":".green; const features = []; const authors = []; const prIDs = []; const commitIDs = []; prompt.start(); const getFeature = function() { prompt.get(schema, (err, result) => { if (err) { console.log("\nExiting script."); process.exit(0); } features.push(result); if (result.another === "y") { getFeature(); } else { let message = `### [${newVersion[0]}.${newVersion[1]}.${newVersion[2]}] - ${date}\n`; features.forEach(feature => { const id = feature.id.length > 10 ? feature.id.slice(0, 7) : "#" + feature.id; message += `- ${feature.message} [@${feature.author}] | [${id}]\n`; if (!knownContributors.includes(feature.author)) { authors.push(`[@${feature.author}]: https://github.com/${feature.author}`); } if (feature.id.length > 10) { commitIDs.push(`[${id}]: https://github.com/gchq/CyberChef/commit/${feature.id}`); } else { prIDs.push(`[#${feature.id}]: https://github.com/gchq/CyberChef/pull/${feature.id}`); } }); // Message changelogData = changelogData.replace(/## Details\n\n/, "## Details\n\n" + message + "\n"); // Tag const newTag = `[${newVersion[0]}.${newVersion[1]}.${newVersion[2]}]: https://github.com/gchq/CyberChef/releases/tag/v${newVersion[0]}.${newVersion[1]}.${newVersion[2]}\n`; changelogData = changelogData.replace(/\n\n(\[\d+\.\d+\.\d+\]: https)/, "\n\n" + newTag + "$1"); // Author authors.forEach(author => { changelogData = changelogData.replace(/(\n\[@[^\]]+\]: https:\/\/github\.com\/[^\n]+\n)\n/, "$1" + author + "\n\n"); }); // Commit IDs commitIDs.forEach(commitID => { changelogData = changelogData.replace(/(\n\[[^\].]+\]: https:\/\/github.com\/gchq\/CyberChef\/commit\/[^\n]+\n)\n/, "$1" + commitID + "\n\n"); }); // PR IDs prIDs.forEach(prID => { changelogData = changelogData.replace(/(\n\[#[^\]]+\]: https:\/\/github.com\/gchq\/CyberChef\/pull\/[^\n]+\n)\n*$/, "$1" + prID + "\n\n"); }); fs.writeFileSync(path.join(process.cwd(), "CHANGELOG.md"), changelogData); console.log("Written CHANGELOG.md"); } }); }; getFeature();