Skip to content

Commit

Permalink
feat(ng-dev): delete the temporary exceptional minor NPM dist tag whe…
Browse files Browse the repository at this point in the history
…n turning stable

When an exceptional minor turns "stable" and becomes the new patch, the
temporary NPM dist tag can be deleted. We do this to avoid having
unnecessary NPM dist tags show up on NPM.

The whole tag is only needed for being able to publish and not
overriding "latest". `npm publish` always requires a tag, and falls
back to overriding "latest" if no expliit tag is provided.
  • Loading branch information
devversion committed Jan 9, 2023
1 parent 5901019 commit 156cc26
Show file tree
Hide file tree
Showing 8 changed files with 88 additions and 10 deletions.
10 changes: 10 additions & 0 deletions ng-dev/release/publish/actions/cut-stable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,16 @@ export class CutStableAction extends ReleaseAction {
this._getNpmDistTag(),
);

// If we turned an exceptional minor into the new patch, the temporary
// NPM dist tag for the exceptional minor can be deleted. For more details
// see the `CutExceptionalMinorPrereleaseAction` class.
if (this._train === this.active.exceptionalMinor) {
await ExternalCommands.invokeDeleteNpmDistTag(
this.projectDir,
'do-not-use-exceptional-minor',
);
}

// If a new major version is published and becomes the "latest" release-train, we need
// to set the LTS npm dist tag for the previous latest release-train (the current patch).
if (this._isNewMajor) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@ export class CutExceptionalMinorPrereleaseAction extends CutPrereleaseBaseAction
// should not prevent actual pre-releases for an on-going FF/RC or the next branch.
// Note that NPM always requires a dist-tag, so we explicitly have one dedicated
// for exceptional minors. This tag could be deleted in the future.
// TODO(devversion): consider automatically deleting this tag- or keep it around.
npmDistTag = 'exceptional-minor' as const;
npmDistTag = 'do-not-use-exceptional-minor' as const;

shouldUseExistingVersion = (async () => {
// If an exceptional minor branch has just been created, the actual version
Expand Down
34 changes: 34 additions & 0 deletions ng-dev/release/publish/external-commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,40 @@ export abstract class ExternalCommands {
}
}

/**
* Invokes the `ng-dev release npm-dist-tag delete` command in order to delete the
* NPM dist tag for all packages in the checked-out version branch.
*/
static async invokeDeleteNpmDistTag(projectDir: string, npmDistTag: NpmDistTag) {
// Note: We cannot use `yarn` directly as command because we might operate in
// a different publish branch and the current `PATH` will point to the Yarn version
// that invoked the release tool. More details in the function description.
const yarnCommand = await resolveYarnScriptForProject(projectDir);

try {
// Note: No progress indicator needed as that is the responsibility of the command.
// TODO: detect yarn berry and handle flag differences properly.
await ChildProcess.spawn(
yarnCommand.binary,
[
...yarnCommand.args,
'--silent',
'ng-dev',
'release',
'npm-dist-tag',
'delete',
npmDistTag,
],
{cwd: projectDir},
);
Log.info(green(` ✓ Deleted "${npmDistTag}" NPM dist tag for all packages.`));
} catch (e) {
Log.error(e);
Log.error(` ✘ An error occurred while deleting the NPM dist tag: "${npmDistTag}".`);
throw new FatalReleaseActionError();
}
}

/**
* Invokes the `ng-dev release build` command in order to build the release
* packages for the currently checked out branch.
Expand Down
33 changes: 33 additions & 0 deletions ng-dev/release/publish/test/cut-stable.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,23 @@ describe('cut stable action', () => {
},
);

it('should not attempting deleting temporary exceptional-minor NPM dist tags', async () => {
const action = setupReleaseActionForTesting(
CutStableAction,
new ActiveReleaseTrains({
exceptionalMinor: null,
// No longer in feature-freeze but in release-candidate phase.
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')),
}),
);

await expectStagingAndPublishWithCherryPick(action, '10.1.x', '10.1.0', 'latest');

expect(ExternalCommands.invokeDeleteNpmDistTag).toHaveBeenCalledTimes(0);
});

describe('exceptional minor is in-progress', () => {
it('should create a proper new version and select correct branch', async () => {
const action = setupReleaseActionForTesting(
Expand Down Expand Up @@ -345,6 +362,22 @@ describe('cut stable action', () => {
expect(pkgJson[exceptionalMinorPackageIndicator]).toBe(undefined);
});

it('should delete the temporary exceptional-minor NPM dist tag', async () => {
const action = setupReleaseActionForTesting(
CutStableAction,
new ActiveReleaseTrains({
latest: new ReleaseTrain('10.0.x', parse('10.0.3')),
exceptionalMinor: new ReleaseTrain('10.1.x', parse('10.1.0-rc.0')),
releaseCandidate: null,
next: new ReleaseTrain('master', parse('11.0.0-next.0')),
}),
);

await expectStagingAndPublishWithCherryPick(action, '10.1.x', '10.1.0', 'latest');

expect(ExternalCommands.invokeDeleteNpmDistTag).toHaveBeenCalledTimes(1);
});

it(
'should generate release notes capturing all associated RC, next releases while ' +
'deduping commits that have been cherry-picked from patch and are already released',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ describe('cut exceptional minor pre-release action', () => {
action,
'10.2.x',
'10.2.0-next.0',
'exceptional-minor',
'do-not-use-exceptional-minor',
);

const pkgJsonContents = readFileSync(
Expand Down Expand Up @@ -131,7 +131,7 @@ describe('cut exceptional minor pre-release action', () => {
action,
'10.1.x',
'10.1.0-next.1',
'exceptional-minor',
'do-not-use-exceptional-minor',
);
});

Expand Down Expand Up @@ -188,7 +188,7 @@ describe('cut exceptional minor pre-release action', () => {
action,
'10.1.x',
'10.1.0-rc.1',
'exceptional-minor',
'do-not-use-exceptional-minor',
);
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ describe('cut exceptional minor next release candidate action', () => {
action,
'10.1.x',
'10.1.0-rc.0',
'exceptional-minor',
'do-not-use-exceptional-minor',
);
});

Expand Down
1 change: 1 addition & 0 deletions ng-dev/release/publish/test/test-utils/action-mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ export function setupMocksForReleaseAction<T extends boolean>(
// Fake all external commands for the release tool.
spyOn(NpmCommand, 'publish').and.resolveTo();
spyOn(ExternalCommands, 'invokeSetNpmDist').and.resolveTo();
spyOn(ExternalCommands, 'invokeDeleteNpmDistTag').and.resolveTo();
spyOn(ExternalCommands, 'invokeYarnInstall').and.resolveTo();
spyOn(ExternalCommands, 'invokeReleaseInfo').and.resolveTo(releaseConfig);
spyOn(ExternalCommands, 'invokeReleaseBuild').and.resolveTo(builtPackages);
Expand Down
9 changes: 5 additions & 4 deletions ng-dev/release/versioning/npm-registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@ import {LtsNpmDistTag} from './long-term-support.js';
* Type describing the possible NPM dist tags used by Angular packages:
* - latest: Stable versions. These are releases from the "latest" train.
* - next: Next versions. These are releases from the FF/RC or "next" train.
* - exceptional-minor: Exceptional minors have their own NPM dist tag since we
* would not want to override `latest`, nor would we want to revert `@next` if
* the version is already ahead.
* - do-not-use-exceptional-minor: Exceptional minors have their own NPM dist tag since
* we would not want to override `latest`, nor would we want to revert `@next` if
* the version is already ahead. The tags are expected to be deleted after the minor
* becomes stable.
*/
export type NpmDistTag = 'latest' | 'next' | 'exceptional-minor' | LtsNpmDistTag;
export type NpmDistTag = 'latest' | 'next' | 'do-not-use-exceptional-minor' | LtsNpmDistTag;

/** Type describing an NPM package fetched from the registry. */
export interface NpmPackageInfo {
Expand Down

0 comments on commit 156cc26

Please sign in to comment.