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
This commit is contained in:
Joey Perrott 2020-11-20 11:05:40 -08:00 committed by Andrew Kushnir
parent d65c2e351f
commit 5a49465ce0
3 changed files with 38 additions and 1 deletions

View File

@ -5807,6 +5807,8 @@ class ReleaseAction {
// so we cannot build and publish it. // so we cannot build and publish it.
yield invokeYarnInstallCommand(this.projectDir); yield invokeYarnInstallCommand(this.projectDir);
const builtPackages = yield invokeReleaseBuildCommand(); 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. // Create a Github release for the new version.
yield this._createGithubReleaseForVersion(newVersion, versionBumpCommitSha); yield this._createGithubReleaseForVersion(newVersion, versionBumpCommitSha);
// Walk through all built packages and publish them to NPM. // Walk through all built packages and publish them to NPM.
@ -5841,6 +5843,20 @@ class ReleaseAction {
return data.commit.message.startsWith(getCommitMessageForRelease(version)); 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();
}
}
});
}
} }
/** /**

View File

@ -503,6 +503,9 @@ export abstract class ReleaseAction {
await invokeYarnInstallCommand(this.projectDir); await invokeYarnInstallCommand(this.projectDir);
const builtPackages = await invokeReleaseBuildCommand(); 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. // Create a Github release for the new version.
await this._createGithubReleaseForVersion(newVersion, versionBumpCommitSha); await this._createGithubReleaseForVersion(newVersion, versionBumpCommitSha);
@ -537,4 +540,18 @@ export abstract class ReleaseAction {
await this.git.github.repos.getCommit({...this.git.remoteParams, ref: commitSha}); await this.git.github.repos.getCommit({...this.git.remoteParams, ref: commitSha});
return data.commit.message.startsWith(getCommitMessageForRelease(version)); 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();
}
}
}
} }

View File

@ -89,7 +89,7 @@ export function setupReleaseActionForTesting<T extends ReleaseAction>(
spyOn(console, 'promptConfirm').and.resolveTo(true); spyOn(console, 'promptConfirm').and.resolveTo(true);
// Fake all external commands for the release tool. // 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, 'invokeSetNpmDistCommand').and.resolveTo();
spyOn(externalCommands, 'invokeYarnInstallCommand').and.resolveTo(); spyOn(externalCommands, 'invokeYarnInstallCommand').and.resolveTo();
spyOn(externalCommands, 'invokeReleaseBuildCommand').and.resolveTo([ spyOn(externalCommands, 'invokeReleaseBuildCommand').and.resolveTo([
@ -97,6 +97,10 @@ export function setupReleaseActionForTesting<T extends ReleaseAction>(
{name: '@angular/pkg2', outputPath: `${testTmpDir}/dist/pkg2`} {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 // Create an empty changelog and a `package.json` file so that file system
// interactions with the project directory do not cause exceptions. // interactions with the project directory do not cause exceptions.
writeFileSync(join(testTmpDir, 'CHANGELOG.md'), 'Existing changelog'); writeFileSync(join(testTmpDir, 'CHANGELOG.md'), 'Existing changelog');