From 62bfa955262a334eca622016fec6df4619c710e1 Mon Sep 17 00:00:00 2001 From: Austin Fahsl Date: Mon, 23 Oct 2023 16:08:05 -0600 Subject: [PATCH] fix(release): validate releaseTagPattern version placeholder --- .../nx/src/command-line/release/changelog.ts | 3 -- .../release/config/config.spec.ts | 44 +++++++++++++++++++ .../src/command-line/release/config/config.ts | 44 +++++++++++++++++++ .../utils/resolve-nx-json-error-message.ts | 5 ++- 4 files changed, 92 insertions(+), 4 deletions(-) diff --git a/packages/nx/src/command-line/release/changelog.ts b/packages/nx/src/command-line/release/changelog.ts index efba396dcf46ac..e168dd7a16698e 100644 --- a/packages/nx/src/command-line/release/changelog.ts +++ b/packages/nx/src/command-line/release/changelog.ts @@ -78,9 +78,6 @@ export async function changelogHandler(args: ChangelogOptions): Promise { process.env.NX_VERBOSE_LOGGING = 'true'; } - /** - * TODO: validate releaseTagPattern contains exactly one instance of {version} - */ // Apply default configuration to any optional user configuration const { error: configError, nxReleaseConfig } = await createNxReleaseConfig( projectGraph, diff --git a/packages/nx/src/command-line/release/config/config.spec.ts b/packages/nx/src/command-line/release/config/config.spec.ts index 48dccf6c8cb74b..6b7cd9dfb51235 100644 --- a/packages/nx/src/command-line/release/config/config.spec.ts +++ b/packages/nx/src/command-line/release/config/config.spec.ts @@ -945,5 +945,49 @@ describe('createNxReleaseConfig()', () => { } `); }); + + it("should return an error if a group's releaseTagPattern has no {version} placeholder", async () => { + const res = await createNxReleaseConfig(projectGraph, { + groups: { + 'group-1': { + projects: '*', + releaseTagPattern: 'v', + }, + }, + }); + expect(res).toMatchInlineSnapshot(` + { + "error": { + "code": "RELEASE_GROUP_RELEASE_TAG_PATTERN_VERSION_PLACEHOLDER_MISSING_OR_EXCESSIVE", + "data": { + "releaseGroupName": "group-1", + }, + }, + "nxReleaseConfig": null, + } + `); + }); + + it("should return an error if a group's releaseTagPattern has more than one {version} placeholder", async () => { + const res = await createNxReleaseConfig(projectGraph, { + groups: { + 'group-1': { + projects: '*', + releaseTagPattern: '{version}v{version}', + }, + }, + }); + expect(res).toMatchInlineSnapshot(` + { + "error": { + "code": "RELEASE_GROUP_RELEASE_TAG_PATTERN_VERSION_PLACEHOLDER_MISSING_OR_EXCESSIVE", + "data": { + "releaseGroupName": "group-1", + }, + }, + "nxReleaseConfig": null, + } + `); + }); }); }); diff --git a/packages/nx/src/command-line/release/config/config.ts b/packages/nx/src/command-line/release/config/config.ts index ae86a9fb77240e..b6e452474bd700 100644 --- a/packages/nx/src/command-line/release/config/config.ts +++ b/packages/nx/src/command-line/release/config/config.ts @@ -50,6 +50,7 @@ export type NxReleaseConfig = DeepRequired< export interface CreateNxReleaseConfigError { code: | 'RELEASE_GROUP_MATCHES_NO_PROJECTS' + | 'RELEASE_GROUP_RELEASE_TAG_PATTERN_VERSION_PLACEHOLDER_MISSING_OR_EXCESSIVE' | 'PROJECT_MATCHES_MULTIPLE_GROUPS' | 'PROJECTS_MISSING_TARGET'; data: Record; @@ -194,6 +195,20 @@ export async function createNxReleaseConfig( } } + // If provided, ensure release tag pattern is valid + if (releaseGroup.releaseTagPattern) { + const error = ensureReleaseTagPatternIsValid( + releaseGroup.releaseTagPattern, + releaseGroupName + ); + if (error) { + return { + error, + nxReleaseConfig: null, + }; + } + } + for (const project of matchingProjects) { if (alreadyMatchedProjects.has(project)) { return { @@ -290,6 +305,20 @@ export async function handleNxReleaseConfigError( }); } break; + case 'RELEASE_GROUP_RELEASE_TAG_PATTERN_VERSION_PLACEHOLDER_MISSING_OR_EXCESSIVE': + { + const nxJsonMessage = await resolveNxJsonConfigErrorMessage([ + 'release', + 'groups', + error.data.releaseGroupName as string, + 'releaseTagPattern', + ]); + output.error({ + title: `Release group "${error.data.releaseGroupName}" has an invalid releaseTagPattern. Please ensure the pattern contains exactly one instance of the "{version}" placeholder`, + bodyLines: [nxJsonMessage], + }); + } + break; default: throw new Error(`Unhandled error code: ${error.code}`); } @@ -297,6 +326,21 @@ export async function handleNxReleaseConfigError( process.exit(1); } +function ensureReleaseTagPatternIsValid( + releaseTagPattern: string, + releaseGroupName: string +): null | CreateNxReleaseConfigError { + // ensure that any provided releaseTagPattern contains exactly one instance of {version} + return releaseTagPattern.split('{version}').length === 2 + ? null + : { + code: 'RELEASE_GROUP_RELEASE_TAG_PATTERN_VERSION_PLACEHOLDER_MISSING_OR_EXCESSIVE', + data: { + releaseGroupName, + }, + }; +} + function ensureProjectsConfigIsArray( groups: NxJsonConfiguration['release']['groups'] ): NxReleaseConfig['groups'] { diff --git a/packages/nx/src/command-line/release/utils/resolve-nx-json-error-message.ts b/packages/nx/src/command-line/release/utils/resolve-nx-json-error-message.ts index 85f8776b4e06d2..dd6d04bf897574 100644 --- a/packages/nx/src/command-line/release/utils/resolve-nx-json-error-message.ts +++ b/packages/nx/src/command-line/release/utils/resolve-nx-json-error-message.ts @@ -14,7 +14,10 @@ export async function resolveNxJsonConfigErrorMessage( joinPathFragments(workspaceRoot, 'nx.json') )}`; if (errorLines) { - nxJsonMessage += `, lines ${errorLines.startLine}-${errorLines.endLine}`; + nxJsonMessage += + errorLines.startLine === errorLines.endLine + ? `, line ${errorLines.startLine}` + : `, lines ${errorLines.startLine}-${errorLines.endLine}`; } return nxJsonMessage; }