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;