From 5a49465ce0670097f088a6b57085aec4d5ceee1d Mon Sep 17 00:00:00 2001 From: Joey Perrott Date: Fri, 20 Nov 2020 11:05:40 -0800 Subject: [PATCH] fix(dev-infra): verify the version of generated build artifacts (#39789) Verify the version of the generated build artifacts to ensure that the version published to NPM is the version we expect. PR Close #39789 --- dev-infra/ng-dev.js | 16 ++++++++++++++++ dev-infra/release/publish/actions.ts | 17 +++++++++++++++++ dev-infra/release/publish/test/test-utils.ts | 6 +++++- 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/dev-infra/ng-dev.js b/dev-infra/ng-dev.js index a86d2d3ac3..39e9f71014 100755 --- a/dev-infra/ng-dev.js +++ b/dev-infra/ng-dev.js @@ -5807,6 +5807,8 @@ class ReleaseAction { // so we cannot build and publish it. yield invokeYarnInstallCommand(this.projectDir); const builtPackages = yield invokeReleaseBuildCommand(); + // Verify the packages built are the correct version. + yield this._verifyPackageVersions(newVersion, builtPackages); // Create a Github release for the new version. yield this._createGithubReleaseForVersion(newVersion, versionBumpCommitSha); // Walk through all built packages and publish them to NPM. @@ -5841,6 +5843,20 @@ class ReleaseAction { return data.commit.message.startsWith(getCommitMessageForRelease(version)); }); } + /** Verify the version of each generated package exact matches the specified version. */ + _verifyPackageVersions(version, packages) { + return tslib.__awaiter(this, void 0, void 0, function* () { + for (const pkg of packages) { + const { version: packageJsonVersion } = JSON.parse(yield fs.promises.readFile(path.join(pkg.outputPath, 'package.json'), 'utf8')); + if (version.compare(packageJsonVersion) !== 0) { + error(red('The built package version does not match the version being released.')); + error(` Release Version: ${version.version}`); + error(` Generated Version: ${packageJsonVersion}`); + throw new FatalReleaseActionError(); + } + } + }); + } } /** diff --git a/dev-infra/release/publish/actions.ts b/dev-infra/release/publish/actions.ts index b2e4e5edc8..3b22e81feb 100644 --- a/dev-infra/release/publish/actions.ts +++ b/dev-infra/release/publish/actions.ts @@ -503,6 +503,9 @@ export abstract class ReleaseAction { await invokeYarnInstallCommand(this.projectDir); const builtPackages = await invokeReleaseBuildCommand(); + // Verify the packages built are the correct version. + await this._verifyPackageVersions(newVersion, builtPackages); + // Create a Github release for the new version. await this._createGithubReleaseForVersion(newVersion, versionBumpCommitSha); @@ -537,4 +540,18 @@ export abstract class ReleaseAction { await this.git.github.repos.getCommit({...this.git.remoteParams, ref: commitSha}); return data.commit.message.startsWith(getCommitMessageForRelease(version)); } + + /** Verify the version of each generated package exact matches the specified version. */ + private async _verifyPackageVersions(version: semver.SemVer, packages: BuiltPackage[]) { + for (const pkg of packages) { + const {version: packageJsonVersion} = + JSON.parse(await fs.readFile(join(pkg.outputPath, 'package.json'), 'utf8')); + if (version.compare(packageJsonVersion) !== 0) { + error(red('The built package version does not match the version being released.')); + error(` Release Version: ${version.version}`); + error(` Generated Version: ${packageJsonVersion}`); + throw new FatalReleaseActionError(); + } + } + } } diff --git a/dev-infra/release/publish/test/test-utils.ts b/dev-infra/release/publish/test/test-utils.ts index 0f4ac54445..8225a30980 100644 --- a/dev-infra/release/publish/test/test-utils.ts +++ b/dev-infra/release/publish/test/test-utils.ts @@ -89,7 +89,7 @@ export function setupReleaseActionForTesting( spyOn(console, 'promptConfirm').and.resolveTo(true); // Fake all external commands for the release tool. - spyOn(npm, 'runNpmPublish').and.resolveTo(true); + spyOn(npm, 'runNpmPublish').and.resolveTo(); spyOn(externalCommands, 'invokeSetNpmDistCommand').and.resolveTo(); spyOn(externalCommands, 'invokeYarnInstallCommand').and.resolveTo(); spyOn(externalCommands, 'invokeReleaseBuildCommand').and.resolveTo([ @@ -97,6 +97,10 @@ export function setupReleaseActionForTesting( {name: '@angular/pkg2', outputPath: `${testTmpDir}/dist/pkg2`} ]); + // Fake checking the package versions since we don't actually create packages to check against in + // the publish tests. + spyOn(ReleaseAction.prototype, '_verifyPackageVersions' as any).and.resolveTo(); + // Create an empty changelog and a `package.json` file so that file system // interactions with the project directory do not cause exceptions. writeFileSync(join(testTmpDir, 'CHANGELOG.md'), 'Existing changelog');