From 282e86ad710647bf6516f5ee7bff5cc5d8a9144d Mon Sep 17 00:00:00 2001 From: Joey Perrott Date: Thu, 15 Jul 2021 17:06:15 -0700 Subject: [PATCH] fix(dev-infra): use the version from package.json rather than tags (#42872) Use the version value from the primary package.json file rather than checking the branch for the latest semver tag. This allows for us to explictly create changelogs from the previous version to the new version. PR Close #42872 --- dev-infra/build-worker.js | 10 ++++++++ dev-infra/ng-dev.js | 25 ++++++++++++++++++- dev-infra/release/publish/actions.ts | 16 ++++++++++-- dev-infra/release/publish/test/test-utils.ts | 2 +- dev-infra/utils/git/git-client.ts | 13 ++++++++++ dev-infra/utils/testing/virtual-git-client.ts | 8 ++++++ 6 files changed, 70 insertions(+), 4 deletions(-) diff --git a/dev-infra/build-worker.js b/dev-infra/build-worker.js index 2939ff9538..aad3843510 100644 --- a/dev-infra/build-worker.js +++ b/dev-infra/build-worker.js @@ -262,6 +262,16 @@ var GitClient = /** @class */ (function () { } return new semver.SemVer(latestTag, semVerOptions); }; + /** Retrieves the git tag matching the provided SemVer, if it exists. */ + GitClient.prototype.getMatchingTagForSemver = function (semver$1) { + var semVerOptions = { loose: true }; + var tags = this.runGraceful(['tag', '--sort=-committerdate', '--merged']).stdout.split('\n'); + var matchingTag = tags.find(function (tag) { var _a; return ((_a = semver.parse(tag, semVerOptions)) === null || _a === void 0 ? void 0 : _a.compare(semver$1)) === 0; }); + if (matchingTag === undefined) { + throw new Error("Unable to find a tag for the version: \"" + semver$1.format() + "\""); + } + return matchingTag; + }; /** Retrieve a list of all files in the repository changed since the provided shaOrRef. */ GitClient.prototype.allChangesFilesSince = function (shaOrRef) { if (shaOrRef === void 0) { shaOrRef = 'HEAD'; } diff --git a/dev-infra/ng-dev.js b/dev-infra/ng-dev.js index b849312806..7b7c2fb3d8 100755 --- a/dev-infra/ng-dev.js +++ b/dev-infra/ng-dev.js @@ -434,6 +434,16 @@ var GitClient = /** @class */ (function () { } return new semver.SemVer(latestTag, semVerOptions); }; + /** Retrieves the git tag matching the provided SemVer, if it exists. */ + GitClient.prototype.getMatchingTagForSemver = function (semver$1) { + var semVerOptions = { loose: true }; + var tags = this.runGraceful(['tag', '--sort=-committerdate', '--merged']).stdout.split('\n'); + var matchingTag = tags.find(function (tag) { var _a; return ((_a = semver.parse(tag, semVerOptions)) === null || _a === void 0 ? void 0 : _a.compare(semver$1)) === 0; }); + if (matchingTag === undefined) { + throw new Error("Unable to find a tag for the version: \"" + semver$1.format() + "\""); + } + return matchingTag; + }; /** Retrieve a list of all files in the repository changed since the provided shaOrRef. */ GitClient.prototype.allChangesFilesSince = function (shaOrRef) { if (shaOrRef === void 0) { shaOrRef = 'HEAD'; } @@ -6423,6 +6433,14 @@ class ReleaseAction { static isActive(_trains, _config) { throw Error('Not implemented.'); } + /** Retrieves the version in the project top-level `package.json` file. */ + getProjectVersion() { + return tslib.__awaiter(this, void 0, void 0, function* () { + const pkgJsonPath = path.join(this.projectDir, packageJsonPath); + const pkgJson = JSON.parse(yield fs.promises.readFile(pkgJsonPath, 'utf8')); + return new semver.SemVer(pkgJson.version); + }); + } /** Updates the version in the project top-level `package.json` file. */ updateProjectVersion(newVersion) { return tslib.__awaiter(this, void 0, void 0, function* () { @@ -6676,7 +6694,12 @@ class ReleaseAction { */ stageVersionForBranchAndCreatePullRequest(newVersion, pullRequestBaseBranch) { return tslib.__awaiter(this, void 0, void 0, function* () { - const releaseNotes = yield ReleaseNotes.fromRange(newVersion, this.git.getLatestSemverTag().format(), 'HEAD'); + /** + * The current version of the project for the branch from the root package.json. This must be + * retrieved prior to updating the project version. + */ + const currentVersion = this.git.getMatchingTagForSemver(yield this.getProjectVersion()); + const releaseNotes = yield ReleaseNotes.fromRange(newVersion, currentVersion, 'HEAD'); yield this.updateProjectVersion(newVersion); yield this.prependReleaseNotesToChangelog(releaseNotes); yield this.waitForEditsAndCreateReleaseCommit(newVersion); diff --git a/dev-infra/release/publish/actions.ts b/dev-infra/release/publish/actions.ts index e040ef4c2a..aa312a9a96 100644 --- a/dev-infra/release/publish/actions.ts +++ b/dev-infra/release/publish/actions.ts @@ -80,6 +80,14 @@ export abstract class ReleaseAction { protected active: ActiveReleaseTrains, protected git: AuthenticatedGitClient, protected config: ReleaseConfig, protected projectDir: string) {} + /** Retrieves the version in the project top-level `package.json` file. */ + private async getProjectVersion() { + const pkgJsonPath = join(this.projectDir, packageJsonPath); + const pkgJson = + JSON.parse(await fs.readFile(pkgJsonPath, 'utf8')) as {version: string, [key: string]: any}; + return new semver.SemVer(pkgJson.version); + } + /** Updates the version in the project top-level `package.json` file. */ protected async updateProjectVersion(newVersion: semver.SemVer) { const pkgJsonPath = join(this.projectDir, packageJsonPath); @@ -351,8 +359,12 @@ export abstract class ReleaseAction { protected async stageVersionForBranchAndCreatePullRequest( newVersion: semver.SemVer, pullRequestBaseBranch: string): Promise<{releaseNotes: ReleaseNotes, pullRequest: PullRequest}> { - const releaseNotes = - await ReleaseNotes.fromRange(newVersion, this.git.getLatestSemverTag().format(), 'HEAD'); + /** + * The current version of the project for the branch from the root package.json. This must be + * retrieved prior to updating the project version. + */ + const currentVersion = this.git.getMatchingTagForSemver(await this.getProjectVersion()); + const releaseNotes = await ReleaseNotes.fromRange(newVersion, currentVersion, 'HEAD'); await this.updateProjectVersion(newVersion); await this.prependReleaseNotesToChangelog(releaseNotes); await this.waitForEditsAndCreateReleaseCommit(newVersion); diff --git a/dev-infra/release/publish/test/test-utils.ts b/dev-infra/release/publish/test/test-utils.ts index ddbc36e847..3681e3c2c0 100644 --- a/dev-infra/release/publish/test/test-utils.ts +++ b/dev-infra/release/publish/test/test-utils.ts @@ -108,7 +108,7 @@ export function setupReleaseActionForTesting( // 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'); - writeFileSync(join(testTmpDir, 'package.json'), JSON.stringify({version: 'unknown'})); + writeFileSync(join(testTmpDir, 'package.json'), JSON.stringify({version: '0.0.0'})); // Override the default pull request wait interval to a number of milliseconds that can be // awaited in Jasmine tests. The default interval of 10sec is too large and causes a timeout. diff --git a/dev-infra/utils/git/git-client.ts b/dev-infra/utils/git/git-client.ts index 2faef84805..eab11db987 100644 --- a/dev-infra/utils/git/git-client.ts +++ b/dev-infra/utils/git/git-client.ts @@ -162,6 +162,19 @@ export class GitClient { return new SemVer(latestTag, semVerOptions); } + /** Retrieves the git tag matching the provided SemVer, if it exists. */ + getMatchingTagForSemver(semver: SemVer): string { + const semVerOptions: SemVerOptions = {loose: true}; + const tags = this.runGraceful(['tag', '--sort=-committerdate', '--merged']).stdout.split('\n'); + const matchingTag = + tags.find((tag: string) => parse(tag, semVerOptions)?.compare(semver) === 0); + + if (matchingTag === undefined) { + throw new Error(`Unable to find a tag for the version: "${semver.format()}"`); + } + return matchingTag; + } + /** Retrieve a list of all files in the repository changed since the provided shaOrRef. */ allChangesFilesSince(shaOrRef = 'HEAD'): string[] { return Array.from(new Set([ diff --git a/dev-infra/utils/testing/virtual-git-client.ts b/dev-infra/utils/testing/virtual-git-client.ts index 0042d6e409..17202127c2 100644 --- a/dev-infra/utils/testing/virtual-git-client.ts +++ b/dev-infra/utils/testing/virtual-git-client.ts @@ -82,6 +82,14 @@ export class VirtualGitClient extends AuthenticatedGitClient { return new SemVer('0.0.0'); } + /** + * Override the actual GitClient getLatestSemverTag, as an actual tags cannot be checked during + * testing, return back the SemVer version as the tag. + */ + override getMatchingTagForSemver(semver: SemVer) { + return semver.format(); + } + /** Override for the actual Git client command execution. */ override runGraceful(args: string[], options: SpawnSyncOptions = {}): SpawnSyncReturns { const [command, ...rawArgs] = args;