From 8ec8a3b4d9b54c3ad82f2af83065853bc3d77142 Mon Sep 17 00:00:00 2001 From: Thierry Goettelmann Date: Tue, 24 May 2022 11:01:05 +0200 Subject: [PATCH] feat(scripts/gen-deps-list.js): should now be used only during release (#6234) --- CHANGELOG.unreleased.md | 14 +--- package.json | 1 - scripts/gen-deps-list.js | 176 ++++++++++++++++----------------------- yarn.lock | 5 -- 4 files changed, 77 insertions(+), 119 deletions(-) diff --git a/CHANGELOG.unreleased.md b/CHANGELOG.unreleased.md index 90fa10a62..8d479df4f 100644 --- a/CHANGELOG.unreleased.md +++ b/CHANGELOG.unreleased.md @@ -21,23 +21,15 @@ ### Packages to release -> Packages will be released in the order they are here, therefore, they should -> be listed by inverse order of dependency. +> When modifying a package, add it here with its release type. > -> Rule of thumb: add packages on top. +> The format is the following: - `$packageName` `$releaseType` > -> The format is the following: - `$packageName` `$version` -> -> Where `$version` is +> Where `$releaseType` is > > - patch: if the change is a bug fix or a simple code improvement > - minor: if the change is a new feature > - major: if the change breaks compatibility -> -> In case of conflict, the highest (lowest in previous list) `$version` wins. -> -> The `gen-deps-list` script can be used to generate this list of dependencies -> Run `scripts/gen-deps-list.js --help` for usage diff --git a/package.json b/package.json index decdb221b..b6a62c904 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,6 @@ "@babel/register": "^7.0.0", "babel-jest": "^27.3.1", "benchmark": "^2.1.4", - "commander": "^9.2.0", "deptree": "^1.0.0", "eslint": "^8.7.0", "eslint-config-prettier": "^8.1.0", diff --git a/scripts/gen-deps-list.js b/scripts/gen-deps-list.js index aecc09fbe..b8f0e4000 100755 --- a/scripts/gen-deps-list.js +++ b/scripts/gen-deps-list.js @@ -1,7 +1,6 @@ #!/usr/bin/env node 'use strict' -const { program, Argument } = require('commander') const DepTree = require('deptree') const fs = require('fs').promises const joinPath = require('path').join @@ -9,6 +8,7 @@ const semver = require('semver') const { getPackages } = require('./utils') const escapeRegExp = require('lodash/escapeRegExp') const invert = require('lodash/invert') +const keyBy = require('lodash/keyBy') const changelogConfig = { path: joinPath(__dirname, '../CHANGELOG.unreleased.md'), @@ -16,95 +16,98 @@ const changelogConfig = { endTag: '', } -program - .argument('', 'The name of the package to release') - .addArgument(new Argument('', 'The type of release to perform').choices(['patch', 'minor', 'major'])) - .option('-r, --read-changelog', 'Import existing packages from the changelog') - .option('-w, --write-changelog', 'Write output to the changelog') - .option('--force', 'Required when using --write-changelog without --read-changelog') - .showHelpAfterError(true) - .showSuggestionAfterError(true) - .parse() - -const [rootPackageName, rootReleaseType] = program.args -const { readChangelog, writeChangelog, force } = program.opts() - -if (writeChangelog && !readChangelog && !force) { - // Stop the process to prevent unwanted changelog overwrite - program.showHelpAfterError(false).error(` - WARNING: Using --write-changelog without --read-changelog will remove existing packages list. - If you are sure you want to do this, add --force. - `) -} - const RELEASE_WEIGHT = { PATCH: 1, MINOR: 2, MAJOR: 3 } const RELEASE_TYPE = invert(RELEASE_WEIGHT) -const rootReleaseWeight = releaseTypeToWeight(rootReleaseType) - -/** @type {Map} A mapping of package names to their release weight */ -const packagesToRelease = new Map([[rootPackageName, rootReleaseWeight]]) const dependencyTree = new DepTree() +/** @type {Map} A mapping of package names to their release weight */ +const packagesToRelease = new Map() + +let allPackages async function main() { - if (readChangelog) { - await importPackagesFromChangelog() + allPackages = keyBy(await getPackages(true), 'name') + const content = await fs.readFile(changelogConfig.path) + const changelogRegex = new RegExp( + `${escapeRegExp(changelogConfig.startTag)}(.*)${escapeRegExp(changelogConfig.endTag)}`, + 's' + ) + const block = changelogRegex.exec(content)?.[1].trim() + + if (block === undefined) { + throw new Error(`Could not find changelog block in ${changelogConfig.path}`) } - const packages = await getPackages(true) - const rootPackage = packages.find(pkg => pkg.name === rootPackageName) + block.split('\n').forEach(rawLine => { + const line = rawLine.trim() - if (!rootPackage) { - program.showHelpAfterError(false).error(`error: Package ${rootPackageName} not found`) - } + if (!line) { + return + } - dependencyTree.add(rootPackage.name) + const match = line.match(/^-\s*(?\S+)\s+(?patch|minor|major)$/) - /** - * Recursively add dependencies to the dependency tree - * - * @param {string} handledPackageName The name of the package to handle - * @param {string} handledPackageNextVersion The next version of the package to handle - */ - function handlePackage(handledPackageName, handledPackageNextVersion) { - packages.forEach(({ package: { name, version, dependencies, optionalDependencies, peerDependencies } }) => { + if (!match) { + throw new Error(`Invalid line: "${rawLine}"`) + } + + const { + groups: { packageName, releaseType }, + } = match + + const rootPackage = allPackages[packageName] + + if (!rootPackage) { + throw new Error(`Package "${packageName}" does not exist`) + } + + const rootReleaseWeight = releaseTypeToWeight(releaseType) + registerPackageToRelease(packageName, rootReleaseWeight) + dependencyTree.add(rootPackage.name) + + handlePackageDependencies(rootPackage.name, getNextVersion(rootPackage.version, rootReleaseWeight)) + }) + + const commandsToExecute = ['', 'Commands to execute:', ''] + const releasedPackages = ['', '### Released packages', ''] + + dependencyTree.resolve().forEach(dependencyName => { + const releaseWeight = packagesToRelease.get(dependencyName) + const { + package: { version }, + } = allPackages[dependencyName] + commandsToExecute.push(`./scripts/bump-pkg ${dependencyName} ${RELEASE_TYPE[releaseWeight].toLocaleLowerCase()}`) + releasedPackages.push(`- ${dependencyName} ${getNextVersion(version, releaseWeight)}`) + }) + + console.log(commandsToExecute.join('\n')) + console.log(releasedPackages.join('\n')) +} + +/** + * Recursively add dependencies to the dependency tree + * + * @param {string} packageName The name of the package to handle + * @param {string} packageNextVersion The next version of the package to handle + */ +function handlePackageDependencies(packageName, packageNextVersion) { + Object.values(allPackages).forEach( + ({ package: { name, version, dependencies, optionalDependencies, peerDependencies } }) => { let releaseWeight - if ( - shouldPackageBeReleased( - handledPackageName, - { ...dependencies, ...optionalDependencies }, - handledPackageNextVersion - ) - ) { + if (shouldPackageBeReleased(packageName, { ...dependencies, ...optionalDependencies }, packageNextVersion)) { releaseWeight = RELEASE_WEIGHT.PATCH - } else if (shouldPackageBeReleased(handledPackageName, peerDependencies || {}, handledPackageNextVersion)) { + } else if (shouldPackageBeReleased(packageName, peerDependencies || {}, packageNextVersion)) { releaseWeight = versionToReleaseWeight(version) } if (releaseWeight !== undefined) { registerPackageToRelease(name, releaseWeight) - dependencyTree.add(name, handledPackageName) - handlePackage(name, getNextVersion(version, releaseWeight)) + dependencyTree.add(name, packageName) + handlePackageDependencies(name, getNextVersion(version, releaseWeight)) } - }) - } - - handlePackage(rootPackage.name, getNextVersion(rootPackage.version, rootReleaseWeight)) - - const outputLines = dependencyTree.resolve().map(dependencyName => { - const releaseTypeName = RELEASE_TYPE[packagesToRelease.get(dependencyName)].toLocaleLowerCase() - return `- ${dependencyName} ${releaseTypeName}` - }) - - const outputLog = ['', 'New packages list:', '', ...outputLines] - - if (writeChangelog) { - await updateChangelog(outputLines) - outputLog.unshift('', `File updated: ${changelogConfig.path}`) - } - - console.log(outputLog.join('\n')) + } + ) } function releaseTypeToWeight(type) { @@ -155,38 +158,7 @@ function versionToReleaseWeight(version) { * @returns {string} The incremented version */ function getNextVersion(version, releaseWeight) { - return semver.inc(version, RELEASE_TYPE[releaseWeight]) -} - -const changelogRegex = new RegExp( - `${escapeRegExp(changelogConfig.startTag)}(.*)${escapeRegExp(changelogConfig.endTag)}`, - 's' -) - -async function importPackagesFromChangelog() { - const content = await fs.readFile(changelogConfig.path) - const block = changelogRegex.exec(content)?.[1].trim() - - if (block === undefined) { - throw new Error(`Could not find changelog block in ${changelogConfig.path}`) - } - - const lines = block.matchAll(/^- (?[^ ]+) (?patch|minor|major)$/gm) - - for (const { groups: { name, type } } of lines) { - registerPackageToRelease(name, releaseTypeToWeight(type)) - dependencyTree.add(name) - } -} - -async function updateChangelog(lines) { - const content = await fs.readFile(changelogConfig.path) - await fs.writeFile( - changelogConfig.path, - content - .toString() - .replace(changelogRegex, [changelogConfig.startTag, '', ...lines, '', changelogConfig.endTag].join('\n')) - ) + return semver.inc(version, RELEASE_TYPE[releaseWeight].toLocaleLowerCase()) } main().catch(error => { diff --git a/yarn.lock b/yarn.lock index 236477990..4927b6d4e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5471,11 +5471,6 @@ commander@^8.3.0: resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== -commander@^9.2.0: - version "9.2.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-9.2.0.tgz#6e21014b2ed90d8b7c9647230d8b7a94a4a419a9" - integrity sha512-e2i4wANQiSXgnrBlIatyHtP1odfUp0BbV5Y5nEGbxtIrStkEOAAzCUirvLBNXHLr7kwLvJl6V+4V3XV9x7Wd9w== - commander@~2.19.0: version "2.19.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a"