Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions ng-dev/release/notes/changelog.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,34 @@ describe('Changelog', () => {
expect(readFileAsString(changelog.archiveFilePath)).not.toContain('version 3');
});
});

describe('removes entries for all prereleases of major or minor versions', () => {
it('only removes the prerelease entries from the matching minor versions', () => {
Changelog.prependEntryToChangelogFile(gitClient, createChangelogEntry('1.0.0-next.0'));
Changelog.prependEntryToChangelogFile(gitClient, createChangelogEntry('1.0.0'));
Changelog.prependEntryToChangelogFile(gitClient, createChangelogEntry('1.1.0-next.0'));
Changelog.prependEntryToChangelogFile(gitClient, createChangelogEntry('1.1.0-rc.0'));

Changelog.removePrereleaseEntriesForVersion(gitClient, new SemVer('1.1.0'));
expect(readFileAsString(changelog.filePath)).toContain('1.0.0-next.0');
expect(readFileAsString(changelog.filePath)).toContain('1.0.0');
expect(readFileAsString(changelog.filePath)).not.toContain('1.1.0-next.0');
expect(readFileAsString(changelog.filePath)).not.toContain('1.1.0-rc.0');
});

it('only removes the prerelease entries from the matching major versions', () => {
Changelog.prependEntryToChangelogFile(gitClient, createChangelogEntry('1.0.0-next.0'));
Changelog.prependEntryToChangelogFile(gitClient, createChangelogEntry('1.0.0'));
Changelog.prependEntryToChangelogFile(gitClient, createChangelogEntry('2.0.0-next.0'));
Changelog.prependEntryToChangelogFile(gitClient, createChangelogEntry('2.0.0-rc.0'));

Changelog.removePrereleaseEntriesForVersion(gitClient, new SemVer('2.0.0'));
expect(readFileAsString(changelog.filePath)).toContain('1.0.0-next.0');
expect(readFileAsString(changelog.filePath)).toContain('1.0.0');
expect(readFileAsString(changelog.filePath)).not.toContain('2.0.0-next.0');
expect(readFileAsString(changelog.filePath)).not.toContain('2.0.0-rc.0');
});
});
});

function readFileAsString(file: string) {
Expand Down
25 changes: 25 additions & 0 deletions ng-dev/release/notes/changelog.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {existsSync, readFileSync, writeFileSync} from 'fs';
import {join} from 'path';
import * as semver from 'semver';
import {AuthenticatedGitClient} from '../../utils/git/authenticated-git-client';
import {GitClient} from '../../utils/git/git-client';

/** Project-relative path for the changelog file. */
Expand Down Expand Up @@ -57,6 +58,17 @@ export class Changelog {
changelog.moveEntriesPriorToVersionToArchive(version);
}

/**
* Remove all changelog entries from the CHANGELOG.md file for versions which are prereleases
* for the provided version. This is expected to be done on each major and minor release to remove
* the changelog entries which will be made redundant by the first major/minor changelog for a
* version.
*/
static removePrereleaseEntriesForVersion(git: GitClient, version: semver.SemVer) {
const changelog = new this(git);
changelog.removePrereleaseEntriesForVersion(version);
}

// TODO(josephperrott): Remove this after it is unused.
/** Retrieve the file paths for the changelog files. */
static getChangelogFilePaths(git: GitClient) {
Expand Down Expand Up @@ -98,6 +110,19 @@ export class Changelog {
this.writeToChangelogFile();
}

/**
* Remove all changelog entries from the CHANGELOG.md file for versions which are prereleases
* for the provided version. This is expected to be done on each major and minor release to remove
* the changelog entries which will be made redundant by the first major/minor changelog for a
* version.
*/
private removePrereleaseEntriesForVersion(version: semver.SemVer) {
this._entries = this.entries.filter((entry: ChangelogEntry) => {
return semver.diff(entry.version, version) !== 'prerelease';
});
this.writeToChangelogFile();
}

/**
* Move all changelog entries from the CHANGELOG.md file for versions prior to the provided
* version to the changelog archive.
Expand Down
7 changes: 6 additions & 1 deletion ng-dev/release/notes/release-notes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,14 @@ export class ReleaseNotes {

/**
* Prepend generated release note to the CHANGELOG.md file in the base directory of the repository
* provided by the GitClient.
* provided by the GitClient. Removes entries for related prerelease entries as appropriate.
*/
async prependEntryToChangelogFile() {
// When the version for the entry is a non-prelease (i.e. 1.0.0 rather than 1.0.0-next.1), the
// pre-release entries for the version should be removed from the changelog.
if (semver.prerelease(this.version) === null) {
Changelog.removePrereleaseEntriesForVersion(this.git, this.version);
}
Comment thread
josephperrott marked this conversation as resolved.
Changelog.prependEntryToChangelogFile(this.git, await this.getChangelogEntry());

// TODO(josephperrott): Remove file formatting calls.
Expand Down
73 changes: 73 additions & 0 deletions ng-dev/release/publish/test/cut-stable.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
import {testTmpDir} from '../../../utils/testing';
import {SandboxGitRepo} from '../../../utils/testing';
import {ActiveReleaseTrains} from '../../versioning';
import {ReleaseNotes} from '../../notes/release-notes';

describe('cut stable action', () => {
it('should not activate if a feature-freeze release-train is active', async () => {
Expand Down Expand Up @@ -181,4 +182,76 @@ describe('cut stable action', () => {
`);
},
);

it(
'removes prerelease changelog entries for the new stable release when creating the stable ' +
'release changelog entry',
async () => {
const action = setupReleaseActionForTesting(
CutStableAction,
new ActiveReleaseTrains({
releaseCandidate: new ReleaseTrain('10.1.x', parse('10.1.0-rc.0')),
next: new ReleaseTrain('master', parse('10.2.0-next.0')),
latest: new ReleaseTrain('10.0.x', parse('10.0.3')),
}),
true,
{useSandboxGitClient: true},
);

SandboxGitRepo.withInitialCommit(action.githubConfig)
.commit('fix(pkg1): landed in all release trains *1')
.branchOff('10.0.x')
.commit('fix(pkg1): released in patch, cherry-picked *1', 1)
.commit('fix(pkg1): released in patch, cherry-picked *2', 2)
.createTagForHead('10.0.3')
.commit('fix(pkg1): landed in patch, not released but cherry-picked *1', 3)
.switchToBranch('master')
.cherryPick(1)
.cherryPick(2)
.cherryPick(3)
.commit('fix(pkg1): released first next pre-release *1')
.commit('fix(pkg1): released first next pre-release *2')
.createTagForHead('10.1.0-next.0')
.commit('fix(pkg1): released feature-freeze pre-release *1')
.commit('fix(pkg1): released feature-freeze pre-release *2')
.branchOff('10.1.x')
.createTagForHead('10.1.0-next.1')
.commit('fix(pkg1): released release-candidate *1')
.commit('fix(pkg1): released release-candidate *2')
.createTagForHead('10.1.0-rc.0')
.commit('fix(pkg1): not yet released *1')
.commit('fix(pkg1): not yet released *2');

const entriesBeforeStableReleaseAction: [startingRef: string, endingRef: string][] = [
['10.0.3~2', '10.0.3'],
['10.0.3', '10.1.0-next.0'],
['10.1.0-next.0', '10.1.0-next.1'],
['10.1.0-next.1', '10.1.0-rc.0'],
];
for (const [start, end] of entriesBeforeStableReleaseAction) {
const releaseNotes = await ReleaseNotes.forRange(action.gitClient, parse(end), start, end);
await releaseNotes.prependEntryToChangelogFile();
}

// Assert the existence of the expected versions in the changelog.
const changelogBeforeAction = readFileSync(`${testTmpDir}/CHANGELOG.md`, 'utf8');
expect(changelogBeforeAction).toContain('<a name="10.0.3"></a>');
expect(changelogBeforeAction).toContain('<a name="10.1.0-next.0"></a>');
expect(changelogBeforeAction).toContain('<a name="10.1.0-next.1"></a>');
expect(changelogBeforeAction).toContain('<a name="10.1.0-rc.0"></a>');
expect(changelogBeforeAction).not.toContain('<a name="10.1.0"></a>');

await expectGithubApiRequestsForStaging(action, '10.1.x', '10.1.0', true);
await action.instance.perform();

// Assert the removal of changelog entries for the prerelease versions expected to be removed
// and now has the new stable entry.
const changelogAfterAction = readFileSync(`${testTmpDir}/CHANGELOG.md`, 'utf8');
expect(changelogAfterAction).not.toContain('<a name="10.0.3"></a>');
expect(changelogAfterAction).not.toContain('<a name="10.1.0-next.0"></a>');
expect(changelogAfterAction).not.toContain('<a name="10.1.0-next.1"></a>');
expect(changelogAfterAction).not.toContain('<a name="10.1.0-rc.0"></a>');
expect(changelogAfterAction).toContain('<a name="10.1.0"></a>');
},
);
});
16 changes: 15 additions & 1 deletion tools/local-actions/changelog/main.js

Large diffs are not rendered by default.