From 8633fa702436cceeafa52ec39a7fabb5b2650c38 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Mon, 18 Jun 2018 16:55:59 +0200 Subject: Add more prepublish checks --- packages/monorepo-scripts/src/prepublish_checks.ts | 96 +++++++++++++++++++++- 1 file changed, 95 insertions(+), 1 deletion(-) (limited to 'packages/monorepo-scripts/src/prepublish_checks.ts') diff --git a/packages/monorepo-scripts/src/prepublish_checks.ts b/packages/monorepo-scripts/src/prepublish_checks.ts index 2c096d8f6..64de56ece 100644 --- a/packages/monorepo-scripts/src/prepublish_checks.ts +++ b/packages/monorepo-scripts/src/prepublish_checks.ts @@ -1,9 +1,103 @@ +import * as fs from 'fs'; import * as _ from 'lodash'; +import * as path from 'path'; import { exec as execAsync } from 'promisify-child-process'; import { constants } from './constants'; +import { Changelog, PackageRegistryJson } from './types'; +import { changelogUtils } from './utils/changelog_utils'; +import { npmUtils } from './utils/npm_utils'; +import { semverUtils } from './utils/semver_utils'; import { utils } from './utils/utils'; +async function prepublishChecksAsync(): Promise { + const shouldIncludePrivate = false; + const updatedPublicLernaPackages = await utils.getUpdatedLernaPackagesAsync(shouldIncludePrivate); + + await checkCurrentVersionMatchesLatestPublishedNPMPackageAsync(updatedPublicLernaPackages); + await checkChangelogFormatAsync(updatedPublicLernaPackages); + await checkGitTagsForNextVersionAndDeleteIfExistAsync(updatedPublicLernaPackages); + await checkPublishRequiredSetupAsync(); +} + +async function checkGitTagsForNextVersionAndDeleteIfExistAsync( + updatedPublicLernaPackages: LernaPackage[], +): Promise { + const packageNames = _.map(updatedPublicLernaPackages, lernaPackage => lernaPackage.package.name); + const localGitTags = await utils.getLocalGitTagsAsync(); + const localTagVersionsByPackageName = await utils.getGitTagsByPackageNameAsync(packageNames, localGitTags); + + const remoteGitTags = await utils.getRemoteGitTagsAsync(); + const remoteTagVersionsByPackageName = await utils.getGitTagsByPackageNameAsync(packageNames, remoteGitTags); + + for (const lernaPackage of updatedPublicLernaPackages) { + const currentVersion = lernaPackage.package.version; + const packageName = lernaPackage.package.name; + const packageLocation = lernaPackage.location; + const nextVersion = await utils.getNextPackageVersionAsync(currentVersion, packageName, packageLocation); + + const localTagVersions = localTagVersionsByPackageName[packageName]; + if (_.includes(localTagVersions, nextVersion)) { + const tagName = `${packageName}@${nextVersion}`; + await utils.removeLocalTagAsync(tagName); + } + + const remoteTagVersions = remoteTagVersionsByPackageName[packageName]; + if (_.includes(remoteTagVersions, nextVersion)) { + const tagName = `:refs/tags/${packageName}@${nextVersion}`; + await utils.removeRemoteTagAsync(tagName); + } + } +} + +async function checkCurrentVersionMatchesLatestPublishedNPMPackageAsync( + updatedPublicLernaPackages: LernaPackage[], +): Promise { + for (const lernaPackage of updatedPublicLernaPackages) { + const packageName = lernaPackage.package.name; + const packageVersion = lernaPackage.package.version; + const packageRegistryJsonIfExists = await npmUtils.getPackageRegistryJsonIfExistsAsync(packageName); + if (_.isUndefined(packageRegistryJsonIfExists)) { + continue; // noop for packages not yet published to NPM + } + const allVersionsIncludingUnpublished = npmUtils.getPreviouslyPublishedVersions(packageRegistryJsonIfExists); + const latestNPMVersion = semverUtils.getLatestVersion(allVersionsIncludingUnpublished); + if (packageVersion !== latestNPMVersion) { + throw new Error( + `Found verson ${packageVersion} in package.json but version ${latestNPMVersion} + on NPM (could be unpublished version) for ${packageName}. These versions must match. If you update + the package.json version, make sure to also update the internal dependency versions too.`, + ); + } + } +} + +async function checkChangelogFormatAsync(updatedPublicLernaPackages: LernaPackage[]): Promise { + for (const lernaPackage of updatedPublicLernaPackages) { + const packageName = lernaPackage.package.name; + const changelog = changelogUtils.getChangelogOrCreateIfMissing(packageName, lernaPackage.location); + + const currentVersion = lernaPackage.package.version; + if (!_.isEmpty(changelog)) { + const lastEntry = changelog[0]; + const doesLastEntryHaveTimestamp = !_.isUndefined(lastEntry.timestamp); + if (semverUtils.lessThan(lastEntry.version, currentVersion)) { + throw new Error( + `CHANGELOG version cannot be below current package version. + Update ${packageName}'s CHANGELOG. It's current version is ${currentVersion} + but the latest CHANGELOG entry is: ${lastEntry.version}`, + ); + } else if (semverUtils.greaterThan(lastEntry.version, currentVersion) && doesLastEntryHaveTimestamp) { + // Remove incorrectly added timestamp + delete changelog[0].timestamp; + // Save updated CHANGELOG.json + await changelogUtils.writeChangelogJsonFileAsync(lernaPackage.location, changelog); + utils.log(`${packageName}: Removed timestamp from latest CHANGELOG.json entry.`); + } + } + } +} + async function checkPublishRequiredSetupAsync(): Promise { // check to see if logged into npm before publishing try { @@ -65,7 +159,7 @@ async function checkPublishRequiredSetupAsync(): Promise { } } -checkPublishRequiredSetupAsync().catch(err => { +prepublishChecksAsync().catch(err => { utils.log(err.message); process.exit(1); }); -- cgit v1.2.3 From 53eae14763b9c2b7ff26a832b5ea9d8b4511969e Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Mon, 18 Jun 2018 17:41:03 +0200 Subject: Show all errors of a given kind at once rather then throwing after the first instance is encountered --- packages/monorepo-scripts/src/prepublish_checks.ts | 46 +++++++++++++++++----- 1 file changed, 36 insertions(+), 10 deletions(-) (limited to 'packages/monorepo-scripts/src/prepublish_checks.ts') diff --git a/packages/monorepo-scripts/src/prepublish_checks.ts b/packages/monorepo-scripts/src/prepublish_checks.ts index 64de56ece..17227d13f 100644 --- a/packages/monorepo-scripts/src/prepublish_checks.ts +++ b/packages/monorepo-scripts/src/prepublish_checks.ts @@ -18,6 +18,7 @@ async function prepublishChecksAsync(): Promise { await checkChangelogFormatAsync(updatedPublicLernaPackages); await checkGitTagsForNextVersionAndDeleteIfExistAsync(updatedPublicLernaPackages); await checkPublishRequiredSetupAsync(); + throw new Error('Intentional stop!'); } async function checkGitTagsForNextVersionAndDeleteIfExistAsync( @@ -53,6 +54,8 @@ async function checkGitTagsForNextVersionAndDeleteIfExistAsync( async function checkCurrentVersionMatchesLatestPublishedNPMPackageAsync( updatedPublicLernaPackages: LernaPackage[], ): Promise { + utils.log('Check package versions against npmjs.org...'); + const versionMismatches = []; for (const lernaPackage of updatedPublicLernaPackages) { const packageName = lernaPackage.package.name; const packageVersion = lernaPackage.package.version; @@ -63,16 +66,28 @@ async function checkCurrentVersionMatchesLatestPublishedNPMPackageAsync( const allVersionsIncludingUnpublished = npmUtils.getPreviouslyPublishedVersions(packageRegistryJsonIfExists); const latestNPMVersion = semverUtils.getLatestVersion(allVersionsIncludingUnpublished); if (packageVersion !== latestNPMVersion) { - throw new Error( - `Found verson ${packageVersion} in package.json but version ${latestNPMVersion} - on NPM (could be unpublished version) for ${packageName}. These versions must match. If you update - the package.json version, make sure to also update the internal dependency versions too.`, - ); + versionMismatches.push({ + packageJsonVersion: packageVersion, + npmVersion: latestNPMVersion, + packageName, + }); } } + if (!_.isEmpty(versionMismatches)) { + utils.log(`Found version mismatches between package.json and NPM published versions (might be unpublished).`); + _.each(versionMismatches, versionMismatch => { + utils.log( + `${versionMismatch.packageName}: ${versionMismatch.packageJsonVersion} package.json, ${ + versionMismatch.npmVersion + } on NPM`, + ); + }); + throw new Error(`Please fix the above package.json/NPM inconsistencies.`); + } } async function checkChangelogFormatAsync(updatedPublicLernaPackages: LernaPackage[]): Promise { + const changeLogInconsistencies = []; for (const lernaPackage of updatedPublicLernaPackages) { const packageName = lernaPackage.package.name; const changelog = changelogUtils.getChangelogOrCreateIfMissing(packageName, lernaPackage.location); @@ -82,11 +97,11 @@ async function checkChangelogFormatAsync(updatedPublicLernaPackages: LernaPackag const lastEntry = changelog[0]; const doesLastEntryHaveTimestamp = !_.isUndefined(lastEntry.timestamp); if (semverUtils.lessThan(lastEntry.version, currentVersion)) { - throw new Error( - `CHANGELOG version cannot be below current package version. - Update ${packageName}'s CHANGELOG. It's current version is ${currentVersion} - but the latest CHANGELOG entry is: ${lastEntry.version}`, - ); + changeLogInconsistencies.push({ + packageJsonVersion: currentVersion, + changelogVersion: lastEntry.version, + packageName, + }); } else if (semverUtils.greaterThan(lastEntry.version, currentVersion) && doesLastEntryHaveTimestamp) { // Remove incorrectly added timestamp delete changelog[0].timestamp; @@ -96,6 +111,17 @@ async function checkChangelogFormatAsync(updatedPublicLernaPackages: LernaPackag } } } + if (!_.isEmpty(changeLogInconsistencies)) { + utils.log(`CHANGELOG versions cannot below package.json versions:`); + _.each(changeLogInconsistencies, inconsistency => { + utils.log( + `${inconsistency.packageName}: ${inconsistency.packageJsonVersion} package.json, ${ + inconsistency.changelogVersion + } CHANGELOG.json`, + ); + }); + } + throw new Error('Fix the above inconsistencies to continue.'); } async function checkPublishRequiredSetupAsync(): Promise { -- cgit v1.2.3 From 9a748c8bf1dfd1a090e3d44a4cbebb59bcedd5e6 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Mon, 18 Jun 2018 17:58:17 +0200 Subject: small fixes --- packages/monorepo-scripts/src/prepublish_checks.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'packages/monorepo-scripts/src/prepublish_checks.ts') diff --git a/packages/monorepo-scripts/src/prepublish_checks.ts b/packages/monorepo-scripts/src/prepublish_checks.ts index 17227d13f..0bd3bb0c1 100644 --- a/packages/monorepo-scripts/src/prepublish_checks.ts +++ b/packages/monorepo-scripts/src/prepublish_checks.ts @@ -18,7 +18,6 @@ async function prepublishChecksAsync(): Promise { await checkChangelogFormatAsync(updatedPublicLernaPackages); await checkGitTagsForNextVersionAndDeleteIfExistAsync(updatedPublicLernaPackages); await checkPublishRequiredSetupAsync(); - throw new Error('Intentional stop!'); } async function checkGitTagsForNextVersionAndDeleteIfExistAsync( @@ -87,6 +86,7 @@ async function checkCurrentVersionMatchesLatestPublishedNPMPackageAsync( } async function checkChangelogFormatAsync(updatedPublicLernaPackages: LernaPackage[]): Promise { + utils.log('Check CHANGELOGs for inconsistencies...'); const changeLogInconsistencies = []; for (const lernaPackage of updatedPublicLernaPackages) { const packageName = lernaPackage.package.name; @@ -120,8 +120,8 @@ async function checkChangelogFormatAsync(updatedPublicLernaPackages: LernaPackag } CHANGELOG.json`, ); }); + throw new Error('Fix the above inconsistencies to continue.'); } - throw new Error('Fix the above inconsistencies to continue.'); } async function checkPublishRequiredSetupAsync(): Promise { -- cgit v1.2.3 From 3e64b3da398a90e6ddfc287ebf28ec780b64b56f Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Mon, 18 Jun 2018 19:00:39 +0200 Subject: Use semver library instead of semverUtils --- packages/monorepo-scripts/src/prepublish_checks.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'packages/monorepo-scripts/src/prepublish_checks.ts') diff --git a/packages/monorepo-scripts/src/prepublish_checks.ts b/packages/monorepo-scripts/src/prepublish_checks.ts index 0bd3bb0c1..5848cea8d 100644 --- a/packages/monorepo-scripts/src/prepublish_checks.ts +++ b/packages/monorepo-scripts/src/prepublish_checks.ts @@ -2,12 +2,13 @@ import * as fs from 'fs'; import * as _ from 'lodash'; import * as path from 'path'; import { exec as execAsync } from 'promisify-child-process'; +import semver = require('semver'); +import semverSort = require('semver-sort'); import { constants } from './constants'; import { Changelog, PackageRegistryJson } from './types'; import { changelogUtils } from './utils/changelog_utils'; import { npmUtils } from './utils/npm_utils'; -import { semverUtils } from './utils/semver_utils'; import { utils } from './utils/utils'; async function prepublishChecksAsync(): Promise { @@ -63,7 +64,8 @@ async function checkCurrentVersionMatchesLatestPublishedNPMPackageAsync( continue; // noop for packages not yet published to NPM } const allVersionsIncludingUnpublished = npmUtils.getPreviouslyPublishedVersions(packageRegistryJsonIfExists); - const latestNPMVersion = semverUtils.getLatestVersion(allVersionsIncludingUnpublished); + const sortedVersions = semverSort.desc(allVersionsIncludingUnpublished); + const latestNPMVersion = sortedVersions[0]; if (packageVersion !== latestNPMVersion) { versionMismatches.push({ packageJsonVersion: packageVersion, @@ -96,13 +98,13 @@ async function checkChangelogFormatAsync(updatedPublicLernaPackages: LernaPackag if (!_.isEmpty(changelog)) { const lastEntry = changelog[0]; const doesLastEntryHaveTimestamp = !_.isUndefined(lastEntry.timestamp); - if (semverUtils.lessThan(lastEntry.version, currentVersion)) { + if (semver.lt(lastEntry.version, currentVersion)) { changeLogInconsistencies.push({ packageJsonVersion: currentVersion, changelogVersion: lastEntry.version, packageName, }); - } else if (semverUtils.greaterThan(lastEntry.version, currentVersion) && doesLastEntryHaveTimestamp) { + } else if (semver.gt(lastEntry.version, currentVersion) && doesLastEntryHaveTimestamp) { // Remove incorrectly added timestamp delete changelog[0].timestamp; // Save updated CHANGELOG.json -- cgit v1.2.3 From 880cbd88c2416c9a3281542c68affb862bd90575 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Mon, 18 Jun 2018 23:15:52 +0200 Subject: Small fixes --- packages/monorepo-scripts/src/prepublish_checks.ts | 3 --- 1 file changed, 3 deletions(-) (limited to 'packages/monorepo-scripts/src/prepublish_checks.ts') diff --git a/packages/monorepo-scripts/src/prepublish_checks.ts b/packages/monorepo-scripts/src/prepublish_checks.ts index 5848cea8d..1c4ee1fc6 100644 --- a/packages/monorepo-scripts/src/prepublish_checks.ts +++ b/packages/monorepo-scripts/src/prepublish_checks.ts @@ -1,12 +1,9 @@ -import * as fs from 'fs'; import * as _ from 'lodash'; -import * as path from 'path'; import { exec as execAsync } from 'promisify-child-process'; import semver = require('semver'); import semverSort = require('semver-sort'); import { constants } from './constants'; -import { Changelog, PackageRegistryJson } from './types'; import { changelogUtils } from './utils/changelog_utils'; import { npmUtils } from './utils/npm_utils'; import { utils } from './utils/utils'; -- cgit v1.2.3