From 77259dc73edaa8e19c785f0b15891c6d8382ae3e Mon Sep 17 00:00:00 2001 From: Edouard Bozon Date: Thu, 14 Dec 2023 15:55:41 +0100 Subject: [PATCH 01/22] wip: setup initial nx release migration --- .../native-nx-release/index.spec.ts | 35 +++++++++++++++++++ .../src/migrations/native-nx-release/index.ts | 16 +++++++++ 2 files changed, 51 insertions(+) create mode 100644 packages/semver/src/migrations/native-nx-release/index.spec.ts create mode 100644 packages/semver/src/migrations/native-nx-release/index.ts diff --git a/packages/semver/src/migrations/native-nx-release/index.spec.ts b/packages/semver/src/migrations/native-nx-release/index.spec.ts new file mode 100644 index 000000000..f6c17f109 --- /dev/null +++ b/packages/semver/src/migrations/native-nx-release/index.spec.ts @@ -0,0 +1,35 @@ +import type { Tree } from '@nx/devkit'; +import { addProjectConfiguration, getProjects } from '@nx/devkit'; +import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; + +import migrate from '.'; + +describe('native nx release migration', () => { + let tree: Tree; + + beforeEach(async () => { + tree = createTreeWithEmptyWorkspace(); + + addProjectConfiguration(tree, 'a', { + root: 'libs/a', + targets: { + version: { + executor: '@jscutlery/semver:version', + }, + }, + }); + + migrate(tree); + }); + + it('should remove version target', () => { + const projectConfig = getProjects(tree).get('a'); + expect(projectConfig).toBeDefined(); + expect(projectConfig?.targets?.version).toBeUndefined(); + }); + + it.todo('should remove @jscutlery/semver from package.json'); + it.todo('should remove post targets'); + it.todo('should setup release config in nx.json'); + it.todo('should inform about detected ci setup and suggest how to update it'); +}); diff --git a/packages/semver/src/migrations/native-nx-release/index.ts b/packages/semver/src/migrations/native-nx-release/index.ts new file mode 100644 index 000000000..87c92c60b --- /dev/null +++ b/packages/semver/src/migrations/native-nx-release/index.ts @@ -0,0 +1,16 @@ +import { getProjects, updateProjectConfiguration, type Tree, logger } from '@nx/devkit'; + +export default function migrate(tree: Tree) { + Array.from(getProjects(tree)).filter(([, projectConfig]) => { + return projectConfig.targets?.version?.executor === '@jscutlery/semver:version' + }).forEach(([projectName, projectConfig]) => { + logger.info(`Updating project "${projectName}", removing version target.`); + // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-non-null-assertion + const { version, ...targets } = projectConfig.targets!; + const newProjectConfig = { + ...projectConfig, + targets, + }; + updateProjectConfiguration(tree, projectName, newProjectConfig); + }); +} From d852ac4f800d0cbe1a85d7b7ba1a2e1f06e8ec21 Mon Sep 17 00:00:00 2001 From: Edouard Bozon Date: Thu, 14 Dec 2023 16:24:31 +0100 Subject: [PATCH 02/22] wip: add post targets removal --- .../native-nx-release/index.spec.ts | 50 +++++++++++++++++-- .../src/migrations/native-nx-release/index.ts | 48 ++++++++++++++++-- 2 files changed, 90 insertions(+), 8 deletions(-) diff --git a/packages/semver/src/migrations/native-nx-release/index.spec.ts b/packages/semver/src/migrations/native-nx-release/index.spec.ts index f6c17f109..0bb4dbb2a 100644 --- a/packages/semver/src/migrations/native-nx-release/index.spec.ts +++ b/packages/semver/src/migrations/native-nx-release/index.spec.ts @@ -9,7 +9,9 @@ describe('native nx release migration', () => { beforeEach(async () => { tree = createTreeWithEmptyWorkspace(); + }); + it('should remove version target', () => { addProjectConfiguration(tree, 'a', { root: 'libs/a', targets: { @@ -20,14 +22,56 @@ describe('native nx release migration', () => { }); migrate(tree); - }); - it('should remove version target', () => { const projectConfig = getProjects(tree).get('a'); - expect(projectConfig).toBeDefined(); expect(projectConfig?.targets?.version).toBeUndefined(); }); + it('should remove post targets', () => { + addProjectConfiguration(tree, 'a', { + root: 'libs/a', + targets: { + version: { + executor: '@jscutlery/semver:version', + options: { + postTargets: ['npm', 'github'], + }, + }, + npm: { + command: 'exit 0', + }, + github: { + command: 'exit 0', + }, + }, + }); + + migrate(tree); + + const projectConfig = getProjects(tree).get('a'); + expect(projectConfig?.targets?.npm).toBeUndefined(); + expect(projectConfig?.targets?.github).toBeUndefined(); + }); + + it('should bail out if sync mode is detected', () => { + addProjectConfiguration(tree, 'a', { + root: '.', + targets: { + version: { + executor: '@jscutlery/semver:version', + options: { + syncVersions: true, + }, + }, + }, + }); + + migrate(tree); + + const projectConfig = getProjects(tree).get('a'); + expect(projectConfig?.targets?.version).toBeDefined(); + }); + it.todo('should remove @jscutlery/semver from package.json'); it.todo('should remove post targets'); it.todo('should setup release config in nx.json'); diff --git a/packages/semver/src/migrations/native-nx-release/index.ts b/packages/semver/src/migrations/native-nx-release/index.ts index 87c92c60b..cb64287e2 100644 --- a/packages/semver/src/migrations/native-nx-release/index.ts +++ b/packages/semver/src/migrations/native-nx-release/index.ts @@ -1,16 +1,54 @@ -import { getProjects, updateProjectConfiguration, type Tree, logger } from '@nx/devkit'; +import { + getProjects, + updateProjectConfiguration, + type Tree, + logger, +} from '@nx/devkit'; export default function migrate(tree: Tree) { - Array.from(getProjects(tree)).filter(([, projectConfig]) => { - return projectConfig.targets?.version?.executor === '@jscutlery/semver:version' - }).forEach(([projectName, projectConfig]) => { - logger.info(`Updating project "${projectName}", removing version target.`); + const projects = Array.from(getProjects(tree)); + const syncModeDetected = projects.some(([, projectConfig]) => { + return projectConfig.targets?.version?.options?.syncVersions === true; + }); + + if (syncModeDetected) { + logger.info( + 'Sync mode detected, skipping migration. Please migrate your workspace manually.', + ); + return; + } + + const semverProjects = projects.filter(([, projectConfig]) => { + return ( + projectConfig.targets?.version?.executor === '@jscutlery/semver:version' + ); + }); + + semverProjects.forEach(([projectName, projectConfig]) => { + logger.info( + `Updating project "${projectName}", removing "version" target.`, + ); // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-non-null-assertion const { version, ...targets } = projectConfig.targets!; + const postTargets = (version?.options?.postTargets as string[]) ?? []; + + if (postTargets.length > 0) { + logger.info( + `Updating project "${projectName}", removing post targets: "${postTargets.join( + '", "', + )}"`, + ); + } + + postTargets.forEach((postTarget) => { + delete targets[postTarget]; + }); + const newProjectConfig = { ...projectConfig, targets, }; + updateProjectConfiguration(tree, projectName, newProjectConfig); }); } From 29058dc0de144a349b5cabfc59c4a828c8cd411c Mon Sep 17 00:00:00 2001 From: Edouard Bozon Date: Thu, 21 Dec 2023 10:52:19 +0100 Subject: [PATCH 03/22] wip: configure Nx Release --- .../native-nx-release/index.spec.ts | 146 ++++++++++++++++++ .../src/generators/native-nx-release/index.ts | 145 +++++++++++++++++ .../native-nx-release/index.spec.ts | 79 ---------- .../src/migrations/native-nx-release/index.ts | 54 ------- 4 files changed, 291 insertions(+), 133 deletions(-) create mode 100644 packages/semver/src/generators/native-nx-release/index.spec.ts create mode 100644 packages/semver/src/generators/native-nx-release/index.ts delete mode 100644 packages/semver/src/migrations/native-nx-release/index.spec.ts delete mode 100644 packages/semver/src/migrations/native-nx-release/index.ts diff --git a/packages/semver/src/generators/native-nx-release/index.spec.ts b/packages/semver/src/generators/native-nx-release/index.spec.ts new file mode 100644 index 000000000..ec7fc2c15 --- /dev/null +++ b/packages/semver/src/generators/native-nx-release/index.spec.ts @@ -0,0 +1,146 @@ +import type { NxJsonConfiguration, Tree } from '@nx/devkit'; +import { + addProjectConfiguration, + getProjects, + logger, + readNxJson, +} from '@nx/devkit'; +import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; + +import migrate from '.'; + +/* eslint-disable @typescript-eslint/no-non-null-assertion */ + +describe('Native Nx Release Migration', () => { + let tree: Tree; + let loggerInfoSpy: jest.SpyInstance; + + beforeEach(() => { + tree = createTreeWithEmptyWorkspace(); + loggerInfoSpy = jest.spyOn(logger, 'info').mockImplementation(); + }); + + it('should bail out if sync mode is detected', () => { + addProjectConfiguration(tree, 'a', { + root: '.', + targets: { + version: { + executor: '@jscutlery/semver:version', + options: { + syncVersions: true, + }, + }, + }, + }); + + migrate(tree); + + const projectConfig = getProjects(tree).get('a'); + expect(projectConfig?.targets?.version).toBeDefined(); + expect(loggerInfoSpy).toHaveBeenCalledWith( + 'Sync mode detected, skipping migration. Please migrate your workspace manually.', + ); + }); + + it('should bail out if no semver config is detected', () => { + addProjectConfiguration(tree, 'a', { + root: '.', + targets: { + build: { + executor: 'version', + }, + }, + }); + + migrate(tree); + + expect(loggerInfoSpy).toHaveBeenCalledWith( + 'No @jscutlery/semver config detected, skipping migration.', + ); + }); + + describe('Nx Release Configuration', () => { + let release: NxJsonConfiguration['release']; + + beforeEach(() => { + addProjectConfiguration(tree, 'a', { + root: 'libs/a', + targets: { + version: { + executor: '@jscutlery/semver:version', + }, + }, + }); + + migrate(tree); + + release = readNxJson(tree)!.release; + }); + + it('should configure releaseTagPattern', () => { + expect(release!.releaseTagPattern).toBe(`{projectName}-{version}`); + }); + + it('should configure changelog', () => { + expect(release!.changelog).toEqual({ + git: { + commit: true, + tag: true, + }, + workspaceChangelog: { + createRelease: 'github', + file: false, + }, + projectChangelogs: true, + }); + }); + }); + + describe('Cleanup @jscutlery/semver', () => { + it('should remove version target', () => { + addProjectConfiguration(tree, 'a', { + root: 'libs/a', + targets: { + version: { + executor: '@jscutlery/semver:version', + }, + }, + }); + + migrate(tree); + + const projectConfig = getProjects(tree).get('a'); + expect(projectConfig?.targets?.version).toBeUndefined(); + }); + + it('should remove post targets', () => { + addProjectConfiguration(tree, 'a', { + root: 'libs/a', + targets: { + version: { + executor: '@jscutlery/semver:version', + options: { + postTargets: ['npm', 'github'], + }, + }, + npm: { + command: 'exit 0', + }, + github: { + command: 'exit 0', + }, + }, + }); + + migrate(tree); + + const projectConfig = getProjects(tree).get('a'); + expect(projectConfig?.targets?.npm).toBeUndefined(); + expect(projectConfig?.targets?.github).toBeUndefined(); + }); + + it.todo('should remove @jscutlery/semver from package.json'); + }); + + it.todo('should inform about detected ci setup and suggest how to update it'); +}); diff --git a/packages/semver/src/generators/native-nx-release/index.ts b/packages/semver/src/generators/native-nx-release/index.ts new file mode 100644 index 000000000..7a2398df7 --- /dev/null +++ b/packages/semver/src/generators/native-nx-release/index.ts @@ -0,0 +1,145 @@ +import { + getProjects, + updateProjectConfiguration, + type Tree, + logger, + ProjectConfiguration, + readNxJson, + formatFiles, + writeJson, +} from '@nx/devkit'; +import { VersionBuilderSchema } from '../../executors/version/schema'; + +export default function migrate(tree: Tree) { + const projects = Array.from(getProjects(tree)); + const syncModeDetected = projects.some(([, projectConfig]) => { + return getSemverOptions(projectConfig).syncVersions === true; + }); + + if (syncModeDetected) { + logger.info( + 'Sync mode detected, skipping migration. Please migrate your workspace manually.', + ); + return; + } + + const semverProjects = projects.filter(([, projectConfig]) => { + return ( + projectConfig.targets?.version?.executor === '@jscutlery/semver:version' + ); + }); + + if (semverProjects.length === 0) { + logger.info('No @jscutlery/semver config detected, skipping migration.'); + return; + } + + configureNxRelease(tree, semverProjects); + + semverProjects.forEach(([projectName, projectConfig]) => { + removeSemverTargets(projectName, projectConfig, tree); + }); + + return () => formatFiles(tree); +} + +function removeSemverTargets( + projectName: string, + projectConfig: ProjectConfiguration, + tree: Tree, +): void { + logger.info( + `[${projectName}] @jscutlery/semver config detected, removing it.`, + ); + // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-non-null-assertion + const { version, ...targets } = projectConfig.targets!; + const postTargets = (version?.options?.postTargets as string[]) ?? []; + + if (postTargets.length > 0) { + logger.info( + `[${projectName}] Post-targets detected, removing: "${postTargets.join( + '", "', + )}".`, + ); + } + + postTargets.forEach((postTarget) => { + delete targets[postTarget]; + }); + + const newProjectConfig = { + ...projectConfig, + targets, + }; + + updateProjectConfiguration(tree, projectName, newProjectConfig); +} + +function configureNxRelease( + tree: Tree, + semverProjects: [string, ProjectConfiguration][], +): void { + const nxJson = readNxJson(tree); + + if (nxJson == null) { + logger.info('No nx.json detected, skipping Nx Release configuration.'); + return; + } + + logger.info('Configuring Nx Release.'); + + // We assume that all projects have the same configuration, so we only take the first one. + const [, projectConfig] = semverProjects[0]; + const options = getSemverOptions(projectConfig); + const tagPrefix = options.tagPrefix ?? '{projectName}-'; + const skipProjectChangelog = options.skipProjectChangelog ?? false; + + nxJson.release ??= { + releaseTagPattern: `${tagPrefix}{version}`, + changelog: { + git: { + commit: true, + tag: true, + }, + workspaceChangelog: { + createRelease: 'github', + file: false, + }, + projectChangelogs: !skipProjectChangelog, + }, + }; + + writeJson(tree, 'nx.json', nxJson); +} + +function getSemverOptions( + projectConfig: ProjectConfiguration, +): VersionBuilderSchema { + return projectConfig.targets?.version?.options ?? {}; +} + +// "release": { +// "releaseTagPattern": "{version}", +// "changelog": { +// "git": { +// "commit": true, +// "tag": true +// }, +// "workspaceChangelog": { +// "createRelease": "github", +// "file": false +// }, +// "projectChangelogs": true +// }, +// "groups": { +// "npm": { +// "projects": ["rxjs"], +// "version": { +// "generatorOptions": { +// "currentVersionResolver": "git-tag", +// "specifierSource": "conventional-commits" +// } +// } +// } +// } +// } diff --git a/packages/semver/src/migrations/native-nx-release/index.spec.ts b/packages/semver/src/migrations/native-nx-release/index.spec.ts deleted file mode 100644 index 0bb4dbb2a..000000000 --- a/packages/semver/src/migrations/native-nx-release/index.spec.ts +++ /dev/null @@ -1,79 +0,0 @@ -import type { Tree } from '@nx/devkit'; -import { addProjectConfiguration, getProjects } from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; - -import migrate from '.'; - -describe('native nx release migration', () => { - let tree: Tree; - - beforeEach(async () => { - tree = createTreeWithEmptyWorkspace(); - }); - - it('should remove version target', () => { - addProjectConfiguration(tree, 'a', { - root: 'libs/a', - targets: { - version: { - executor: '@jscutlery/semver:version', - }, - }, - }); - - migrate(tree); - - const projectConfig = getProjects(tree).get('a'); - expect(projectConfig?.targets?.version).toBeUndefined(); - }); - - it('should remove post targets', () => { - addProjectConfiguration(tree, 'a', { - root: 'libs/a', - targets: { - version: { - executor: '@jscutlery/semver:version', - options: { - postTargets: ['npm', 'github'], - }, - }, - npm: { - command: 'exit 0', - }, - github: { - command: 'exit 0', - }, - }, - }); - - migrate(tree); - - const projectConfig = getProjects(tree).get('a'); - expect(projectConfig?.targets?.npm).toBeUndefined(); - expect(projectConfig?.targets?.github).toBeUndefined(); - }); - - it('should bail out if sync mode is detected', () => { - addProjectConfiguration(tree, 'a', { - root: '.', - targets: { - version: { - executor: '@jscutlery/semver:version', - options: { - syncVersions: true, - }, - }, - }, - }); - - migrate(tree); - - const projectConfig = getProjects(tree).get('a'); - expect(projectConfig?.targets?.version).toBeDefined(); - }); - - it.todo('should remove @jscutlery/semver from package.json'); - it.todo('should remove post targets'); - it.todo('should setup release config in nx.json'); - it.todo('should inform about detected ci setup and suggest how to update it'); -}); diff --git a/packages/semver/src/migrations/native-nx-release/index.ts b/packages/semver/src/migrations/native-nx-release/index.ts deleted file mode 100644 index cb64287e2..000000000 --- a/packages/semver/src/migrations/native-nx-release/index.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { - getProjects, - updateProjectConfiguration, - type Tree, - logger, -} from '@nx/devkit'; - -export default function migrate(tree: Tree) { - const projects = Array.from(getProjects(tree)); - const syncModeDetected = projects.some(([, projectConfig]) => { - return projectConfig.targets?.version?.options?.syncVersions === true; - }); - - if (syncModeDetected) { - logger.info( - 'Sync mode detected, skipping migration. Please migrate your workspace manually.', - ); - return; - } - - const semverProjects = projects.filter(([, projectConfig]) => { - return ( - projectConfig.targets?.version?.executor === '@jscutlery/semver:version' - ); - }); - - semverProjects.forEach(([projectName, projectConfig]) => { - logger.info( - `Updating project "${projectName}", removing "version" target.`, - ); - // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-non-null-assertion - const { version, ...targets } = projectConfig.targets!; - const postTargets = (version?.options?.postTargets as string[]) ?? []; - - if (postTargets.length > 0) { - logger.info( - `Updating project "${projectName}", removing post targets: "${postTargets.join( - '", "', - )}"`, - ); - } - - postTargets.forEach((postTarget) => { - delete targets[postTarget]; - }); - - const newProjectConfig = { - ...projectConfig, - targets, - }; - - updateProjectConfiguration(tree, projectName, newProjectConfig); - }); -} From 1a8cbb45fc288b9970e1b9c7638ec09a131de798 Mon Sep 17 00:00:00 2001 From: Edouard Bozon Date: Thu, 21 Dec 2023 11:15:55 +0100 Subject: [PATCH 04/22] wip: configure GitHub release --- .../native-nx-release/index.spec.ts | 34 ++++++++++++++++--- .../src/generators/native-nx-release/index.ts | 5 ++- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/packages/semver/src/generators/native-nx-release/index.spec.ts b/packages/semver/src/generators/native-nx-release/index.spec.ts index ec7fc2c15..fcfa84425 100644 --- a/packages/semver/src/generators/native-nx-release/index.spec.ts +++ b/packages/semver/src/generators/native-nx-release/index.spec.ts @@ -1,4 +1,8 @@ -import type { NxJsonConfiguration, Tree } from '@nx/devkit'; +import type { + NxJsonConfiguration, + ProjectConfiguration, + Tree, +} from '@nx/devkit'; import { addProjectConfiguration, getProjects, @@ -8,6 +12,7 @@ import { import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import migrate from '.'; +import { VersionBuilderSchema } from '../../executors/version/schema'; /* eslint-disable @typescript-eslint/no-non-null-assertion */ @@ -62,38 +67,59 @@ describe('Native Nx Release Migration', () => { describe('Nx Release Configuration', () => { let release: NxJsonConfiguration['release']; - beforeEach(() => { + function setupSemver( + options: Partial = {}, + targets: ProjectConfiguration['targets'] = {}, + ) { addProjectConfiguration(tree, 'a', { root: 'libs/a', targets: { version: { executor: '@jscutlery/semver:version', + options, }, + ...targets, }, }); migrate(tree); release = readNxJson(tree)!.release; - }); + } it('should configure releaseTagPattern', () => { + setupSemver(); + expect(release!.releaseTagPattern).toBe(`{projectName}-{version}`); }); it('should configure changelog', () => { + setupSemver(); + expect(release!.changelog).toEqual({ git: { commit: true, tag: true, }, workspaceChangelog: { - createRelease: 'github', + createRelease: false, file: false, }, projectChangelogs: true, }); }); + + it('should configure github release', () => { + setupSemver( + { postTargets: ['github'] }, + { github: { executor: '@jscutlery/semver:github' } }, + ); + + expect(release!.changelog!.workspaceChangelog).toEqual({ + createRelease: 'github', + file: false, + }); + }); }); describe('Cleanup @jscutlery/semver', () => { diff --git a/packages/semver/src/generators/native-nx-release/index.ts b/packages/semver/src/generators/native-nx-release/index.ts index 7a2398df7..56be1289f 100644 --- a/packages/semver/src/generators/native-nx-release/index.ts +++ b/packages/semver/src/generators/native-nx-release/index.ts @@ -93,6 +93,9 @@ function configureNxRelease( const options = getSemverOptions(projectConfig); const tagPrefix = options.tagPrefix ?? '{projectName}-'; const skipProjectChangelog = options.skipProjectChangelog ?? false; + const githubRelease = Object.values(projectConfig.targets!).some( + (target) => target.executor === '@jscutlery/semver:github', + ); nxJson.release ??= { releaseTagPattern: `${tagPrefix}{version}`, @@ -102,7 +105,7 @@ function configureNxRelease( tag: true, }, workspaceChangelog: { - createRelease: 'github', + createRelease: githubRelease ? 'github' : false, file: false, }, projectChangelogs: !skipProjectChangelog, From db8ec6bc4c975b3f57d8408465bf89dc1dcb1169 Mon Sep 17 00:00:00 2001 From: Edouard Bozon Date: Thu, 21 Dec 2023 16:38:25 +0100 Subject: [PATCH 05/22] wip: configure release groups --- .../native-nx-release/index.spec.ts | 19 ++++++++ .../src/generators/native-nx-release/index.ts | 43 ++++++------------- 2 files changed, 33 insertions(+), 29 deletions(-) diff --git a/packages/semver/src/generators/native-nx-release/index.spec.ts b/packages/semver/src/generators/native-nx-release/index.spec.ts index fcfa84425..17e9216e2 100644 --- a/packages/semver/src/generators/native-nx-release/index.spec.ts +++ b/packages/semver/src/generators/native-nx-release/index.spec.ts @@ -120,6 +120,25 @@ describe('Native Nx Release Migration', () => { file: false, }); }); + + it('should configure groups', () => { + setupSemver( + { postTargets: ['npm'] }, + { npm: { executor: '@jscutlery/semver:npm' } }, + ); + + expect(release!.groups).toEqual({ + npm: { + projects: ['a'], + version: { + generatorOptions: { + currentVersionResolver: 'git-tag', + specifierSource: 'conventional-commits', + }, + }, + }, + }); + }); }); describe('Cleanup @jscutlery/semver', () => { diff --git a/packages/semver/src/generators/native-nx-release/index.ts b/packages/semver/src/generators/native-nx-release/index.ts index 56be1289f..f39cd99f2 100644 --- a/packages/semver/src/generators/native-nx-release/index.ts +++ b/packages/semver/src/generators/native-nx-release/index.ts @@ -37,16 +37,16 @@ export default function migrate(tree: Tree) { configureNxRelease(tree, semverProjects); semverProjects.forEach(([projectName, projectConfig]) => { - removeSemverTargets(projectName, projectConfig, tree); + removeSemverTargets(tree, projectName, projectConfig); }); return () => formatFiles(tree); } function removeSemverTargets( + tree: Tree, projectName: string, projectConfig: ProjectConfiguration, - tree: Tree, ): void { logger.info( `[${projectName}] @jscutlery/semver config detected, removing it.`, @@ -110,6 +110,17 @@ function configureNxRelease( }, projectChangelogs: !skipProjectChangelog, }, + groups: { + npm: { + projects: semverProjects.map(([projectName]) => projectName), + version: { + generatorOptions: { + currentVersionResolver: 'git-tag', + specifierSource: 'conventional-commits', + }, + }, + }, + } }; writeJson(tree, 'nx.json', nxJson); @@ -117,32 +128,6 @@ function configureNxRelease( function getSemverOptions( projectConfig: ProjectConfiguration, -): VersionBuilderSchema { +): Partial { return projectConfig.targets?.version?.options ?? {}; } - -// "release": { -// "releaseTagPattern": "{version}", -// "changelog": { -// "git": { -// "commit": true, -// "tag": true -// }, -// "workspaceChangelog": { -// "createRelease": "github", -// "file": false -// }, -// "projectChangelogs": true -// }, -// "groups": { -// "npm": { -// "projects": ["rxjs"], -// "version": { -// "generatorOptions": { -// "currentVersionResolver": "git-tag", -// "specifierSource": "conventional-commits" -// } -// } -// } -// } -// } From 21f96dbd3b7c886c124cf88401ff02c12a44f167 Mon Sep 17 00:00:00 2001 From: Edouard Bozon Date: Thu, 21 Dec 2023 16:59:03 +0100 Subject: [PATCH 06/22] wip: find version target --- .../src/generators/native-nx-release/index.ts | 36 ++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/packages/semver/src/generators/native-nx-release/index.ts b/packages/semver/src/generators/native-nx-release/index.ts index f39cd99f2..363b3e2ac 100644 --- a/packages/semver/src/generators/native-nx-release/index.ts +++ b/packages/semver/src/generators/native-nx-release/index.ts @@ -7,6 +7,7 @@ import { readNxJson, formatFiles, writeJson, + TargetConfiguration, } from '@nx/devkit'; import { VersionBuilderSchema } from '../../executors/version/schema'; @@ -23,11 +24,9 @@ export default function migrate(tree: Tree) { return; } - const semverProjects = projects.filter(([, projectConfig]) => { - return ( - projectConfig.targets?.version?.executor === '@jscutlery/semver:version' - ); - }); + const semverProjects = projects.filter( + ([, projectConfig]) => findVersionTarget(projectConfig) !== undefined, + ); if (semverProjects.length === 0) { logger.info('No @jscutlery/semver config detected, skipping migration.'); @@ -51,9 +50,8 @@ function removeSemverTargets( logger.info( `[${projectName}] @jscutlery/semver config detected, removing it.`, ); - // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-non-null-assertion - const { version, ...targets } = projectConfig.targets!; - const postTargets = (version?.options?.postTargets as string[]) ?? []; + const [versionTarget, targetConfig] = findVersionTarget(projectConfig)!; + const postTargets = targetConfig.options?.postTargets ?? []; if (postTargets.length > 0) { logger.info( @@ -63,16 +61,11 @@ function removeSemverTargets( ); } - postTargets.forEach((postTarget) => { - delete targets[postTarget]; + [versionTarget, ...postTargets].forEach((target) => { + delete projectConfig.targets![target]; }); - const newProjectConfig = { - ...projectConfig, - targets, - }; - - updateProjectConfiguration(tree, projectName, newProjectConfig); + updateProjectConfiguration(tree, projectName, projectConfig); } function configureNxRelease( @@ -120,12 +113,21 @@ function configureNxRelease( }, }, }, - } + }, }; writeJson(tree, 'nx.json', nxJson); } +function findVersionTarget( + projectConfig: ProjectConfiguration, +): [string, TargetConfiguration] | undefined { + return Object.entries(projectConfig.targets ?? {}).find( + ([, targetOptions]) => + targetOptions.executor === '@jscutlery/semver:version', + ); +} + function getSemverOptions( projectConfig: ProjectConfiguration, ): Partial { From cc64a92020f04c85d69824d8c474b27aad64f63c Mon Sep 17 00:00:00 2001 From: Edouard Bozon Date: Thu, 21 Dec 2023 17:39:07 +0100 Subject: [PATCH 07/22] wip: commit message + independent --- .../native-nx-release/index.spec.ts | 39 ++++++++++++++++--- .../src/generators/native-nx-release/index.ts | 14 ++++--- 2 files changed, 42 insertions(+), 11 deletions(-) diff --git a/packages/semver/src/generators/native-nx-release/index.spec.ts b/packages/semver/src/generators/native-nx-release/index.spec.ts index 17e9216e2..1c718aab7 100644 --- a/packages/semver/src/generators/native-nx-release/index.spec.ts +++ b/packages/semver/src/generators/native-nx-release/index.spec.ts @@ -41,7 +41,7 @@ describe('Native Nx Release Migration', () => { migrate(tree); const projectConfig = getProjects(tree).get('a'); - expect(projectConfig?.targets?.version).toBeDefined(); + expect(projectConfig!.targets!.version).toBeDefined(); expect(loggerInfoSpy).toHaveBeenCalledWith( 'Sync mode detected, skipping migration. Please migrate your workspace manually.', ); @@ -87,7 +87,7 @@ describe('Native Nx Release Migration', () => { release = readNxJson(tree)!.release; } - it('should configure releaseTagPattern', () => { + it('should configure release.releaseTagPattern', () => { setupSemver(); expect(release!.releaseTagPattern).toBe(`{projectName}-{version}`); @@ -109,6 +109,32 @@ describe('Native Nx Release Migration', () => { }); }); + it('should configure git with --skipCommit', () => { + setupSemver({ skipCommit: true }); + + expect(release!.changelog).toEqual( + expect.objectContaining({ + git: expect.objectContaining({ + commit: false, + }), + }), + ); + }); + + it('should configure commitMessage with --commitMessageFormat', () => { + setupSemver({ + commitMessageFormat: 'chore(release): release v{version}', + }); + + expect(release!.changelog).toEqual( + expect.objectContaining({ + git: expect.objectContaining({ + commitMessage: 'chore(release): release v{version}', + }), + }), + ); + }); + it('should configure github release', () => { setupSemver( { postTargets: ['github'] }, @@ -121,7 +147,7 @@ describe('Native Nx Release Migration', () => { }); }); - it('should configure groups', () => { + it('should configure release groups', () => { setupSemver( { postTargets: ['npm'] }, { npm: { executor: '@jscutlery/semver:npm' } }, @@ -130,6 +156,7 @@ describe('Native Nx Release Migration', () => { expect(release!.groups).toEqual({ npm: { projects: ['a'], + projectsRelationship: 'independent', version: { generatorOptions: { currentVersionResolver: 'git-tag', @@ -155,7 +182,7 @@ describe('Native Nx Release Migration', () => { migrate(tree); const projectConfig = getProjects(tree).get('a'); - expect(projectConfig?.targets?.version).toBeUndefined(); + expect(projectConfig!.targets!.version).toBeUndefined(); }); it('should remove post targets', () => { @@ -180,8 +207,8 @@ describe('Native Nx Release Migration', () => { migrate(tree); const projectConfig = getProjects(tree).get('a'); - expect(projectConfig?.targets?.npm).toBeUndefined(); - expect(projectConfig?.targets?.github).toBeUndefined(); + expect(projectConfig!.targets!.npm).toBeUndefined(); + expect(projectConfig!.targets!.github).toBeUndefined(); }); it.todo('should remove @jscutlery/semver from package.json'); diff --git a/packages/semver/src/generators/native-nx-release/index.ts b/packages/semver/src/generators/native-nx-release/index.ts index 363b3e2ac..ccd38da32 100644 --- a/packages/semver/src/generators/native-nx-release/index.ts +++ b/packages/semver/src/generators/native-nx-release/index.ts @@ -82,11 +82,11 @@ function configureNxRelease( logger.info('Configuring Nx Release.'); // We assume that all projects have the same configuration, so we only take the first one. - const [, projectConfig] = semverProjects[0]; - const options = getSemverOptions(projectConfig); + const [, semverConfig] = semverProjects[0]; + const options = getSemverOptions(semverConfig); const tagPrefix = options.tagPrefix ?? '{projectName}-'; const skipProjectChangelog = options.skipProjectChangelog ?? false; - const githubRelease = Object.values(projectConfig.targets!).some( + const githubRelease = Object.values(semverConfig.targets!).some( (target) => target.executor === '@jscutlery/semver:github', ); @@ -94,7 +94,10 @@ function configureNxRelease( releaseTagPattern: `${tagPrefix}{version}`, changelog: { git: { - commit: true, + commit: !options.skipCommit ?? true, + ...(options.commitMessageFormat + ? { commitMessage: options.commitMessageFormat } + : {}), tag: true, }, workspaceChangelog: { @@ -106,6 +109,7 @@ function configureNxRelease( groups: { npm: { projects: semverProjects.map(([projectName]) => projectName), + projectsRelationship: 'independent', version: { generatorOptions: { currentVersionResolver: 'git-tag', @@ -131,5 +135,5 @@ function findVersionTarget( function getSemverOptions( projectConfig: ProjectConfiguration, ): Partial { - return projectConfig.targets?.version?.options ?? {}; + return findVersionTarget(projectConfig)?.[1].options ?? {}; } From 7b491cc45bff2c0f13c7408eac9e5d54675318e0 Mon Sep 17 00:00:00 2001 From: Edouard Bozon Date: Mon, 25 Dec 2023 09:38:18 +0100 Subject: [PATCH 08/22] build: add `wip` commit type --- commitlint.config.js | 1 + 1 file changed, 1 insertion(+) diff --git a/commitlint.config.js b/commitlint.config.js index b35c249f8..0318898aa 100644 --- a/commitlint.config.js +++ b/commitlint.config.js @@ -17,6 +17,7 @@ module.exports = { 'style', 'test', 'release', + 'wip', ], ], }, From 188bd4ebbdc80469e3d046341007895bf78ac982 Mon Sep 17 00:00:00 2001 From: Edouard Bozon Date: Sun, 11 Feb 2024 10:21:51 +0100 Subject: [PATCH 09/22] wip: update config --- .../native-nx-release/index.spec.ts | 46 ++++--------------- .../src/generators/native-nx-release/index.ts | 38 +++++++-------- 2 files changed, 25 insertions(+), 59 deletions(-) diff --git a/packages/semver/src/generators/native-nx-release/index.spec.ts b/packages/semver/src/generators/native-nx-release/index.spec.ts index 1c718aab7..864b71ce4 100644 --- a/packages/semver/src/generators/native-nx-release/index.spec.ts +++ b/packages/semver/src/generators/native-nx-release/index.spec.ts @@ -93,26 +93,18 @@ describe('Native Nx Release Migration', () => { expect(release!.releaseTagPattern).toBe(`{projectName}-{version}`); }); - it('should configure changelog', () => { + it('should configure projects', () => { setupSemver(); - expect(release!.changelog).toEqual({ - git: { - commit: true, - tag: true, - }, - workspaceChangelog: { - createRelease: false, - file: false, - }, - projectChangelogs: true, - }); + expect(release!.projects).toEqual(['a']); + expect(release!.version!.conventionalCommits).toEqual(true); + expect(release!.projectsRelationship).toEqual('independent'); }); it('should configure git with --skipCommit', () => { setupSemver({ skipCommit: true }); - expect(release!.changelog).toEqual( + expect(release).toEqual( expect.objectContaining({ git: expect.objectContaining({ commit: false, @@ -126,7 +118,7 @@ describe('Native Nx Release Migration', () => { commitMessageFormat: 'chore(release): release v{version}', }); - expect(release!.changelog).toEqual( + expect(release).toEqual( expect.objectContaining({ git: expect.objectContaining({ commitMessage: 'chore(release): release v{version}', @@ -141,29 +133,9 @@ describe('Native Nx Release Migration', () => { { github: { executor: '@jscutlery/semver:github' } }, ); - expect(release!.changelog!.workspaceChangelog).toEqual({ - createRelease: 'github', - file: false, - }); - }); - - it('should configure release groups', () => { - setupSemver( - { postTargets: ['npm'] }, - { npm: { executor: '@jscutlery/semver:npm' } }, - ); - - expect(release!.groups).toEqual({ - npm: { - projects: ['a'], - projectsRelationship: 'independent', - version: { - generatorOptions: { - currentVersionResolver: 'git-tag', - specifierSource: 'conventional-commits', - }, - }, - }, + expect(release!.changelog).toEqual({ + automaticFromRef: true, + projectChangelogs: { createRelease: 'github' }, }); }); }); diff --git a/packages/semver/src/generators/native-nx-release/index.ts b/packages/semver/src/generators/native-nx-release/index.ts index ccd38da32..7850005aa 100644 --- a/packages/semver/src/generators/native-nx-release/index.ts +++ b/packages/semver/src/generators/native-nx-release/index.ts @@ -11,6 +11,8 @@ import { } from '@nx/devkit'; import { VersionBuilderSchema } from '../../executors/version/schema'; +/* eslint-disable @typescript-eslint/no-non-null-assertion */ + export default function migrate(tree: Tree) { const projects = Array.from(getProjects(tree)); const syncModeDetected = projects.some(([, projectConfig]) => { @@ -92,30 +94,22 @@ function configureNxRelease( nxJson.release ??= { releaseTagPattern: `${tagPrefix}{version}`, + projects: semverProjects.map(([projectName]) => projectName), + projectsRelationship: 'independent', + version: { + conventionalCommits: true, + }, + git: { + commit: !options.skipCommit ?? true, + commitMessage: + options.commitMessageFormat ?? + 'chore({projectName}): release version {version}', + }, changelog: { - git: { - commit: !options.skipCommit ?? true, - ...(options.commitMessageFormat - ? { commitMessage: options.commitMessageFormat } - : {}), - tag: true, - }, - workspaceChangelog: { + automaticFromRef: true, + projectChangelogs: { createRelease: githubRelease ? 'github' : false, - file: false, - }, - projectChangelogs: !skipProjectChangelog, - }, - groups: { - npm: { - projects: semverProjects.map(([projectName]) => projectName), - projectsRelationship: 'independent', - version: { - generatorOptions: { - currentVersionResolver: 'git-tag', - specifierSource: 'conventional-commits', - }, - }, + ...(skipProjectChangelog ? { file: false } : {}), }, }, }; From 42d5bc3f85156c408763e194aab0c480f895dd7f Mon Sep 17 00:00:00 2001 From: Edouard Bozon Date: Sun, 11 Feb 2024 10:35:56 +0100 Subject: [PATCH 10/22] wip: expose generator --- packages/semver/generators.json | 5 +++++ .../index.spec.ts | 0 .../{native-nx-release => migrate-nx-release}/index.ts | 0 .../semver/src/generators/migrate-nx-release/schema.json | 8 ++++++++ 4 files changed, 13 insertions(+) rename packages/semver/src/generators/{native-nx-release => migrate-nx-release}/index.spec.ts (100%) rename packages/semver/src/generators/{native-nx-release => migrate-nx-release}/index.ts (100%) create mode 100644 packages/semver/src/generators/migrate-nx-release/schema.json diff --git a/packages/semver/generators.json b/packages/semver/generators.json index 99d2bfc7d..a0dca1e18 100644 --- a/packages/semver/generators.json +++ b/packages/semver/generators.json @@ -5,6 +5,11 @@ "schema": "./src/generators/install/schema.json", "factory": "./src/generators/install", "description": "Add @jscutlery/semver to the workspace." + }, + "migrate-nx-release": { + "schema": "./src/generators/migrate-nx-release/schema.json", + "factory": "./src/generators/migrate-nx-release/index", + "description": "Migrate @jscutlery/semver to Nx release." } }, "required": [], diff --git a/packages/semver/src/generators/native-nx-release/index.spec.ts b/packages/semver/src/generators/migrate-nx-release/index.spec.ts similarity index 100% rename from packages/semver/src/generators/native-nx-release/index.spec.ts rename to packages/semver/src/generators/migrate-nx-release/index.spec.ts diff --git a/packages/semver/src/generators/native-nx-release/index.ts b/packages/semver/src/generators/migrate-nx-release/index.ts similarity index 100% rename from packages/semver/src/generators/native-nx-release/index.ts rename to packages/semver/src/generators/migrate-nx-release/index.ts diff --git a/packages/semver/src/generators/migrate-nx-release/schema.json b/packages/semver/src/generators/migrate-nx-release/schema.json new file mode 100644 index 000000000..3e4d7d26a --- /dev/null +++ b/packages/semver/src/generators/migrate-nx-release/schema.json @@ -0,0 +1,8 @@ +{ + "$schema": "http://json-schema.org/schema", + "$id": "migrate-nx-release", + "title": "Migrate to Nx release generator.", + "type": "object", + "properties": {}, + "required": [] +} From 980efa40b0f82d508513535cfaef8b098545922b Mon Sep 17 00:00:00 2001 From: Edouard Bozon Date: Sun, 11 Feb 2024 11:03:59 +0100 Subject: [PATCH 11/22] wip: exclude not semver related targets to be removed --- .../generators/migrate-nx-release/index.ts | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/packages/semver/src/generators/migrate-nx-release/index.ts b/packages/semver/src/generators/migrate-nx-release/index.ts index 7850005aa..b5ad97697 100644 --- a/packages/semver/src/generators/migrate-nx-release/index.ts +++ b/packages/semver/src/generators/migrate-nx-release/index.ts @@ -31,7 +31,7 @@ export default function migrate(tree: Tree) { ); if (semverProjects.length === 0) { - logger.info('No @jscutlery/semver config detected, skipping migration.'); + logger.info('No config detected, skipping migration.'); return; } @@ -49,11 +49,18 @@ function removeSemverTargets( projectName: string, projectConfig: ProjectConfiguration, ): void { - logger.info( - `[${projectName}] @jscutlery/semver config detected, removing it.`, - ); + logger.info(`[${projectName}] config detected, removing it.`); const [versionTarget, targetConfig] = findVersionTarget(projectConfig)!; - const postTargets = targetConfig.options?.postTargets ?? []; + const postTargets = (targetConfig.options?.postTargets ?? []).filter( + (target) => { + const executor = projectConfig.targets?.[target].executor; + return ( + executor?.includes('semver') || + executor?.includes('ngx-deploy-npm') || + false + ); + }, + ); if (postTargets.length > 0) { logger.info( @@ -89,7 +96,7 @@ function configureNxRelease( const tagPrefix = options.tagPrefix ?? '{projectName}-'; const skipProjectChangelog = options.skipProjectChangelog ?? false; const githubRelease = Object.values(semverConfig.targets!).some( - (target) => target.executor === '@jscutlery/semver:github', + ({ executor }) => executor?.includes('semver:github') ?? false, ); nxJson.release ??= { @@ -121,8 +128,7 @@ function findVersionTarget( projectConfig: ProjectConfiguration, ): [string, TargetConfiguration] | undefined { return Object.entries(projectConfig.targets ?? {}).find( - ([, targetOptions]) => - targetOptions.executor === '@jscutlery/semver:version', + ([, { executor }]) => executor?.includes('semver:version') ?? false, ); } From b02462197b6938b75f9f1936f24b1b61aade6517 Mon Sep 17 00:00:00 2001 From: Edouard Bozon Date: Sun, 11 Feb 2024 11:14:25 +0100 Subject: [PATCH 12/22] wip: drop custom publish --- packages/semver/src/generators/migrate-nx-release/index.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/semver/src/generators/migrate-nx-release/index.ts b/packages/semver/src/generators/migrate-nx-release/index.ts index b5ad97697..504ea68b1 100644 --- a/packages/semver/src/generators/migrate-nx-release/index.ts +++ b/packages/semver/src/generators/migrate-nx-release/index.ts @@ -57,6 +57,10 @@ function removeSemverTargets( return ( executor?.includes('semver') || executor?.includes('ngx-deploy-npm') || + // Drop targets defined with both format: + // { command: "npm publish" } + // { executor: "nx:run-commands", options: { commands: "npm publish" } } + /npm publish/.test(JSON.stringify(projectConfig.targets?.[target])) || false ); }, From ef1bfc347210d335255e9754470449c5e4278462 Mon Sep 17 00:00:00 2001 From: Edouard Bozon Date: Sun, 11 Feb 2024 11:16:13 +0100 Subject: [PATCH 13/22] wip: fix could not format nx.json --- packages/semver/src/generators/migrate-nx-release/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/semver/src/generators/migrate-nx-release/index.ts b/packages/semver/src/generators/migrate-nx-release/index.ts index 504ea68b1..9d7011a6d 100644 --- a/packages/semver/src/generators/migrate-nx-release/index.ts +++ b/packages/semver/src/generators/migrate-nx-release/index.ts @@ -41,7 +41,7 @@ export default function migrate(tree: Tree) { removeSemverTargets(tree, projectName, projectConfig); }); - return () => formatFiles(tree); + return formatFiles(tree); } function removeSemverTargets( From ef6d53f69b7eb3ebc58ba1dbe712ad4f99112185 Mon Sep 17 00:00:00 2001 From: Edouard Bozon Date: Sun, 11 Feb 2024 11:34:22 +0100 Subject: [PATCH 14/22] wip: update specs --- .../migrate-nx-release/index.spec.ts | 93 +++++++++++++++++-- .../generators/migrate-nx-release/index.ts | 4 +- .../generators/migrate-nx-release/schema.json | 8 +- 3 files changed, 92 insertions(+), 13 deletions(-) diff --git a/packages/semver/src/generators/migrate-nx-release/index.spec.ts b/packages/semver/src/generators/migrate-nx-release/index.spec.ts index 864b71ce4..184ecd385 100644 --- a/packages/semver/src/generators/migrate-nx-release/index.spec.ts +++ b/packages/semver/src/generators/migrate-nx-release/index.spec.ts @@ -38,7 +38,7 @@ describe('Native Nx Release Migration', () => { }, }); - migrate(tree); + migrate(tree, { skipFormat: true }); const projectConfig = getProjects(tree).get('a'); expect(projectConfig!.targets!.version).toBeDefined(); @@ -57,10 +57,10 @@ describe('Native Nx Release Migration', () => { }, }); - migrate(tree); + migrate(tree, { skipFormat: true }); expect(loggerInfoSpy).toHaveBeenCalledWith( - 'No @jscutlery/semver config detected, skipping migration.', + 'No config detected, skipping migration.', ); }); @@ -82,7 +82,7 @@ describe('Native Nx Release Migration', () => { }, }); - migrate(tree); + migrate(tree, { skipFormat: true }); release = readNxJson(tree)!.release; } @@ -151,36 +151,109 @@ describe('Native Nx Release Migration', () => { }, }); - migrate(tree); + migrate(tree, { skipFormat: true }); const projectConfig = getProjects(tree).get('a'); expect(projectConfig!.targets!.version).toBeUndefined(); }); - it('should remove post targets', () => { + it('should remove github post-target', () => { addProjectConfiguration(tree, 'a', { root: 'libs/a', targets: { version: { executor: '@jscutlery/semver:version', options: { - postTargets: ['npm', 'github'], + postTargets: ['build', 'github'], + }, + }, + github: { + executor: '@jscutlery/semver:github', + }, + build: { + command: 'exit 0', + }, + }, + }); + + migrate(tree, { skipFormat: true }); + + const projectConfig = getProjects(tree).get('a'); + expect(projectConfig!.targets!.github).toBeUndefined(); + }); + + it('should remove npm post-target (ngx-deploy-npm)', () => { + addProjectConfiguration(tree, 'a', { + root: 'libs/a', + targets: { + version: { + executor: '@jscutlery/semver:version', + options: { + postTargets: ['build', 'npm'], }, }, npm: { + executor: 'ngx-deploy-npm:deploy', + }, + build: { command: 'exit 0', }, - github: { + }, + }); + + migrate(tree, { skipFormat: true }); + + const projectConfig = getProjects(tree).get('a'); + expect(projectConfig!.targets!.npm).toBeUndefined(); + expect(projectConfig!.targets!.build).toBeDefined(); + }); + + it('should remove npm post-target (custom npm publish command)', () => { + addProjectConfiguration(tree, 'a', { + root: 'libs/a', + targets: { + version: { + executor: '@jscutlery/semver:version', + options: { + postTargets: ['build', 'npm'], + }, + }, + npm: { + command: 'npm publish dist/libs/a', + }, + build: { command: 'exit 0', }, }, }); - migrate(tree); + migrate(tree, { skipFormat: true }); const projectConfig = getProjects(tree).get('a'); expect(projectConfig!.targets!.npm).toBeUndefined(); - expect(projectConfig!.targets!.github).toBeUndefined(); + expect(projectConfig!.targets!.build).toBeDefined(); + }); + + it('should keep build post-target', () => { + addProjectConfiguration(tree, 'a', { + root: 'libs/a', + targets: { + version: { + executor: '@jscutlery/semver:version', + options: { + postTargets: ['build'], + }, + }, + build: { + command: 'exit 0', + }, + }, + }); + + migrate(tree, { skipFormat: true }); + + const projectConfig = getProjects(tree).get('a'); + expect(projectConfig!.targets!.build).toBeDefined(); }); it.todo('should remove @jscutlery/semver from package.json'); diff --git a/packages/semver/src/generators/migrate-nx-release/index.ts b/packages/semver/src/generators/migrate-nx-release/index.ts index 9d7011a6d..1ec0d4a65 100644 --- a/packages/semver/src/generators/migrate-nx-release/index.ts +++ b/packages/semver/src/generators/migrate-nx-release/index.ts @@ -13,7 +13,7 @@ import { VersionBuilderSchema } from '../../executors/version/schema'; /* eslint-disable @typescript-eslint/no-non-null-assertion */ -export default function migrate(tree: Tree) { +export default function migrate(tree: Tree, options: { skipFormat: boolean }) { const projects = Array.from(getProjects(tree)); const syncModeDetected = projects.some(([, projectConfig]) => { return getSemverOptions(projectConfig).syncVersions === true; @@ -41,7 +41,7 @@ export default function migrate(tree: Tree) { removeSemverTargets(tree, projectName, projectConfig); }); - return formatFiles(tree); + return !options.skipFormat && formatFiles(tree); } function removeSemverTargets( diff --git a/packages/semver/src/generators/migrate-nx-release/schema.json b/packages/semver/src/generators/migrate-nx-release/schema.json index 3e4d7d26a..459e23309 100644 --- a/packages/semver/src/generators/migrate-nx-release/schema.json +++ b/packages/semver/src/generators/migrate-nx-release/schema.json @@ -3,6 +3,12 @@ "$id": "migrate-nx-release", "title": "Migrate to Nx release generator.", "type": "object", - "properties": {}, + "properties": { + "skipFormat": { + "description": "Skip formatting files", + "type": "boolean", + "default": false + } + }, "required": [] } From 6bdc332548b9ed59ab0b266df3679ffcdf38c22c Mon Sep 17 00:00:00 2001 From: Edouard Bozon Date: Sun, 11 Feb 2024 12:20:25 +0100 Subject: [PATCH 15/22] wip: add e2e spec --- .../__snapshots__/index.e2e.spec.ts.snap | 38 ++++++++++++++ .../src/executors/version/index.e2e.spec.ts | 52 +++++++++++++++++++ .../migrate-nx-release/index.spec.ts | 14 ----- .../generators/migrate-nx-release/index.ts | 4 +- 4 files changed, 91 insertions(+), 17 deletions(-) diff --git a/packages/semver/src/executors/version/__snapshots__/index.e2e.spec.ts.snap b/packages/semver/src/executors/version/__snapshots__/index.e2e.spec.ts.snap index fcef6d626..24d8b5bd4 100644 --- a/packages/semver/src/executors/version/__snapshots__/index.e2e.spec.ts.snap +++ b/packages/semver/src/executors/version/__snapshots__/index.e2e.spec.ts.snap @@ -1,5 +1,43 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`@jscutlery/semver @jscutlery/semver:migrate-nx-release should generate CHANGELOG.md: b-0.3.0 1`] = ` +"## 0.3.0 (yyyy-mm-dd) + + +### 🚀 Features + +- **b:** 🚀 new feature + + +### ❤️ Thank You + +- Test Bot + +# Changelog + +This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver). + +## [0.2.0](///compare/b-0.1.0...b-0.2.0) (yyyy-mm-dd) + + +### Features + +* **b:** 🚀 new feature xxxxxxx + +## 0.1.0 (yyyy-mm-dd) + + +### Features + +* **b:** 🚀 new feature xxxxxxx + + +### Bug Fixes + +* **b:** 🐞 fix bug xxxxxxx +" +`; + exports[`@jscutlery/semver @jscutlery/semver:version when libs/a changed (breaking change) should generate CHANGELOG.md: a-1.0.0 1`] = ` "# Changelog diff --git a/packages/semver/src/executors/version/index.e2e.spec.ts b/packages/semver/src/executors/version/index.e2e.spec.ts index 11c105ed1..5a385bc0e 100644 --- a/packages/semver/src/executors/version/index.e2e.spec.ts +++ b/packages/semver/src/executors/version/index.e2e.spec.ts @@ -400,6 +400,58 @@ describe('@jscutlery/semver', () => { }); }); }); + + describe('@jscutlery/semver:migrate-nx-release', () => { + beforeAll(() => { + testingWorkspace.runNx(`g @jscutlery/semver:migrate-nx-release`); + testingWorkspace.exec( + ` + git add . + git commit -m "build: 🛠️ migrate to nx release" + `, + ); + testingWorkspace.exec( + ` + echo feat > libs/b/b.txt + git add . + git commit -m "feat(b): 🚀 new feature" + `, + ); + testingWorkspace.runNx(`release --skip-publish`); + }); + + it('should commit with description', () => { + expect(getLastCommitDescription(testingWorkspace.root)).toBe( + `chore(release): publish + +- project: b 0.3.0`, + ); + }); + + it('should tag with version', () => { + expect(getLastTag(testingWorkspace.root)).toBe('b-0.3.0'); + }); + + it('should bump package version', () => { + expect(readFile(`${testingWorkspace.root}/libs/b/package.json`)).toMatch( + /"version": "0.3.0"/, + ); + }); + + it('should generate CHANGELOG.md', () => { + expect( + deterministicChangelog( + readFile(`${testingWorkspace.root}/libs/b/CHANGELOG.md`), + ), + ).toMatchSnapshot('b-0.3.0'); + }); + + it('should version projects independently', () => { + expect(getTags(testingWorkspace.root)).toEqual( + expect.arrayContaining(['a-1.2.0-alpha.0', 'b-0.3.0', 'd-0.1.0']), + ); + }); + }); }); function getLastTag(dir: string) { diff --git a/packages/semver/src/generators/migrate-nx-release/index.spec.ts b/packages/semver/src/generators/migrate-nx-release/index.spec.ts index 184ecd385..d95001633 100644 --- a/packages/semver/src/generators/migrate-nx-release/index.spec.ts +++ b/packages/semver/src/generators/migrate-nx-release/index.spec.ts @@ -113,20 +113,6 @@ describe('Native Nx Release Migration', () => { ); }); - it('should configure commitMessage with --commitMessageFormat', () => { - setupSemver({ - commitMessageFormat: 'chore(release): release v{version}', - }); - - expect(release).toEqual( - expect.objectContaining({ - git: expect.objectContaining({ - commitMessage: 'chore(release): release v{version}', - }), - }), - ); - }); - it('should configure github release', () => { setupSemver( { postTargets: ['github'] }, diff --git a/packages/semver/src/generators/migrate-nx-release/index.ts b/packages/semver/src/generators/migrate-nx-release/index.ts index 1ec0d4a65..61a215aee 100644 --- a/packages/semver/src/generators/migrate-nx-release/index.ts +++ b/packages/semver/src/generators/migrate-nx-release/index.ts @@ -112,9 +112,7 @@ function configureNxRelease( }, git: { commit: !options.skipCommit ?? true, - commitMessage: - options.commitMessageFormat ?? - 'chore({projectName}): release version {version}', + commitArgs: '--no-verify', }, changelog: { automaticFromRef: true, From 2ec4c90d2e714daf0b9c89b694db2e3fb0ada9cc Mon Sep 17 00:00:00 2001 From: Edouard Bozon Date: Sun, 11 Feb 2024 13:46:33 +0100 Subject: [PATCH 16/22] wip: bail out if multiple semver configs detected --- .../migrate-nx-release/index.spec.ts | 35 ++++++++++++++++++- .../generators/migrate-nx-release/index.ts | 21 +++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/packages/semver/src/generators/migrate-nx-release/index.spec.ts b/packages/semver/src/generators/migrate-nx-release/index.spec.ts index d95001633..dda55f89b 100644 --- a/packages/semver/src/generators/migrate-nx-release/index.spec.ts +++ b/packages/semver/src/generators/migrate-nx-release/index.spec.ts @@ -52,7 +52,7 @@ describe('Native Nx Release Migration', () => { root: '.', targets: { build: { - executor: 'version', + executor: 'build', }, }, }); @@ -62,6 +62,39 @@ describe('Native Nx Release Migration', () => { expect(loggerInfoSpy).toHaveBeenCalledWith( 'No config detected, skipping migration.', ); + expect(readNxJson(tree)!.release).toBeUndefined(); + }); + + it('should bail out if multiple incompatible semver configs are detected', () => { + addProjectConfiguration(tree, 'a', { + root: 'libs/a', + targets: { + version: { + executor: '@jscutlery/semver:version', + options: { + commitMessageFormat: 'chore(release): {version}', + }, + }, + }, + }); + addProjectConfiguration(tree, 'b', { + root: 'libs/b', + targets: { + version: { + executor: '@jscutlery/semver:version', + options: { + commitMessageFormat: 'release: {version}', + }, + }, + }, + }); + + migrate(tree, { skipFormat: true }); + + expect(loggerInfoSpy).toHaveBeenCalledWith( + 'Multiple semver configs detected, skipping migration. Please migrate your workspace manually.', + ); + expect(readNxJson(tree)!.release).toBeUndefined(); }); describe('Nx Release Configuration', () => { diff --git a/packages/semver/src/generators/migrate-nx-release/index.ts b/packages/semver/src/generators/migrate-nx-release/index.ts index 61a215aee..b7be5c2a2 100644 --- a/packages/semver/src/generators/migrate-nx-release/index.ts +++ b/packages/semver/src/generators/migrate-nx-release/index.ts @@ -35,6 +35,27 @@ export default function migrate(tree: Tree, options: { skipFormat: boolean }) { return; } + const multipleSemverConfigsDetected = + semverProjects + .map( + ([, projectConfig]) => + findVersionTarget(projectConfig) as [ + string, + TargetConfiguration, + ], + ) + .every( + ([, { options }], _, [[, { options: baseOptions }]]) => + JSON.stringify(options) === JSON.stringify(baseOptions), + ) === false; + + if (multipleSemverConfigsDetected) { + logger.info( + 'Multiple semver configs detected, skipping migration. Please migrate your workspace manually.', + ); + return; + } + configureNxRelease(tree, semverProjects); semverProjects.forEach(([projectName, projectConfig]) => { From 45674faab143ea61c1410c832e8ba356ad14f82c Mon Sep 17 00:00:00 2001 From: Edouard Bozon Date: Sun, 11 Feb 2024 14:23:47 +0100 Subject: [PATCH 17/22] wip: continue exec if multiple semver config detected --- .../semver/src/generators/migrate-nx-release/index.spec.ts | 5 ++--- packages/semver/src/generators/migrate-nx-release/index.ts | 3 +-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/semver/src/generators/migrate-nx-release/index.spec.ts b/packages/semver/src/generators/migrate-nx-release/index.spec.ts index dda55f89b..840290b96 100644 --- a/packages/semver/src/generators/migrate-nx-release/index.spec.ts +++ b/packages/semver/src/generators/migrate-nx-release/index.spec.ts @@ -65,7 +65,7 @@ describe('Native Nx Release Migration', () => { expect(readNxJson(tree)!.release).toBeUndefined(); }); - it('should bail out if multiple incompatible semver configs are detected', () => { + it('should log if multiple semver configs are detected', () => { addProjectConfiguration(tree, 'a', { root: 'libs/a', targets: { @@ -92,9 +92,8 @@ describe('Native Nx Release Migration', () => { migrate(tree, { skipFormat: true }); expect(loggerInfoSpy).toHaveBeenCalledWith( - 'Multiple semver configs detected, skipping migration. Please migrate your workspace manually.', + 'Multiple semver configs detected, the migration can eventually break your workspace. Please verify the changes.', ); - expect(readNxJson(tree)!.release).toBeUndefined(); }); describe('Nx Release Configuration', () => { diff --git a/packages/semver/src/generators/migrate-nx-release/index.ts b/packages/semver/src/generators/migrate-nx-release/index.ts index b7be5c2a2..23b52b510 100644 --- a/packages/semver/src/generators/migrate-nx-release/index.ts +++ b/packages/semver/src/generators/migrate-nx-release/index.ts @@ -51,9 +51,8 @@ export default function migrate(tree: Tree, options: { skipFormat: boolean }) { if (multipleSemverConfigsDetected) { logger.info( - 'Multiple semver configs detected, skipping migration. Please migrate your workspace manually.', + 'Multiple semver configs detected, the migration can eventually break your workspace. Please verify the changes.', ); - return; } configureNxRelease(tree, semverProjects); From d0b77c5ba663930fae055fa0b022e33f82f370e0 Mon Sep 17 00:00:00 2001 From: Edouard Bozon Date: Sun, 11 Feb 2024 15:27:42 +0100 Subject: [PATCH 18/22] wip: remove header --- .../__snapshots__/index.e2e.spec.ts.snap | 13 +++---------- .../generators/migrate-nx-release/index.ts | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/packages/semver/src/executors/version/__snapshots__/index.e2e.spec.ts.snap b/packages/semver/src/executors/version/__snapshots__/index.e2e.spec.ts.snap index 24d8b5bd4..d55955133 100644 --- a/packages/semver/src/executors/version/__snapshots__/index.e2e.spec.ts.snap +++ b/packages/semver/src/executors/version/__snapshots__/index.e2e.spec.ts.snap @@ -13,28 +13,21 @@ exports[`@jscutlery/semver @jscutlery/semver:migrate-nx-release should generate - Test Bot -# Changelog - -This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver). - ## [0.2.0](///compare/b-0.1.0...b-0.2.0) (yyyy-mm-dd) - ### Features -* **b:** 🚀 new feature xxxxxxx +- **b:** 🚀 new feature xxxxxxx ## 0.1.0 (yyyy-mm-dd) - ### Features -* **b:** 🚀 new feature xxxxxxx - +- **b:** 🚀 new feature xxxxxxx ### Bug Fixes -* **b:** 🐞 fix bug xxxxxxx +- **b:** 🐞 fix bug xxxxxxx " `; diff --git a/packages/semver/src/generators/migrate-nx-release/index.ts b/packages/semver/src/generators/migrate-nx-release/index.ts index 23b52b510..15f5ec86b 100644 --- a/packages/semver/src/generators/migrate-nx-release/index.ts +++ b/packages/semver/src/generators/migrate-nx-release/index.ts @@ -10,6 +10,7 @@ import { TargetConfiguration, } from '@nx/devkit'; import { VersionBuilderSchema } from '../../executors/version/schema'; +import { defaultHeader } from '../../executors/version/utils/changelog'; /* eslint-disable @typescript-eslint/no-non-null-assertion */ @@ -59,6 +60,7 @@ export default function migrate(tree: Tree, options: { skipFormat: boolean }) { semverProjects.forEach(([projectName, projectConfig]) => { removeSemverTargets(tree, projectName, projectConfig); + removeSemverChangelogHeader(tree, projectConfig); }); return !options.skipFormat && formatFiles(tree); @@ -159,3 +161,20 @@ function getSemverOptions( ): Partial { return findVersionTarget(projectConfig)?.[1].options ?? {}; } + +function removeSemverChangelogHeader( + tree: Tree, + projectConfig: ProjectConfiguration, +) { + const changelog = projectConfig.root + '/CHANGELOG.md'; + if (tree.exists(changelog)) { + const content = tree.read(changelog)!.toString('utf-8'); + tree.write( + changelog, + content.replace( + getSemverOptions(projectConfig).changelogHeader ?? defaultHeader, + '', + ), + ); + } +} From b6896a53ce54df99c5a4a08e3bbec274adfdb754 Mon Sep 17 00:00:00 2001 From: Edouard Bozon Date: Sun, 11 Feb 2024 16:51:10 +0100 Subject: [PATCH 19/22] wip: remove dependencies --- .../migrate-nx-release/index.spec.ts | 90 +++++++++++++------ .../generators/migrate-nx-release/index.ts | 23 ++++- .../generators/migrate-nx-release/schema.json | 5 ++ 3 files changed, 87 insertions(+), 31 deletions(-) diff --git a/packages/semver/src/generators/migrate-nx-release/index.spec.ts b/packages/semver/src/generators/migrate-nx-release/index.spec.ts index 840290b96..3efedfad6 100644 --- a/packages/semver/src/generators/migrate-nx-release/index.spec.ts +++ b/packages/semver/src/generators/migrate-nx-release/index.spec.ts @@ -7,6 +7,7 @@ import { addProjectConfiguration, getProjects, logger, + readJson, readNxJson, } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; @@ -20,12 +21,14 @@ describe('Native Nx Release Migration', () => { let tree: Tree; let loggerInfoSpy: jest.SpyInstance; + const options = { skipFormat: true, skipInstall: false }; + beforeEach(() => { tree = createTreeWithEmptyWorkspace(); loggerInfoSpy = jest.spyOn(logger, 'info').mockImplementation(); }); - it('should bail out if sync mode is detected', () => { + it('should bail out if sync mode is detected', async () => { addProjectConfiguration(tree, 'a', { root: '.', targets: { @@ -38,7 +41,7 @@ describe('Native Nx Release Migration', () => { }, }); - migrate(tree, { skipFormat: true }); + await migrate(tree, options); const projectConfig = getProjects(tree).get('a'); expect(projectConfig!.targets!.version).toBeDefined(); @@ -47,7 +50,7 @@ describe('Native Nx Release Migration', () => { ); }); - it('should bail out if no semver config is detected', () => { + it('should bail out if no semver config is detected', async () => { addProjectConfiguration(tree, 'a', { root: '.', targets: { @@ -57,7 +60,7 @@ describe('Native Nx Release Migration', () => { }, }); - migrate(tree, { skipFormat: true }); + await migrate(tree, options); expect(loggerInfoSpy).toHaveBeenCalledWith( 'No config detected, skipping migration.', @@ -65,7 +68,7 @@ describe('Native Nx Release Migration', () => { expect(readNxJson(tree)!.release).toBeUndefined(); }); - it('should log if multiple semver configs are detected', () => { + it('should log if multiple semver configs are detected', async () => { addProjectConfiguration(tree, 'a', { root: 'libs/a', targets: { @@ -89,7 +92,7 @@ describe('Native Nx Release Migration', () => { }, }); - migrate(tree, { skipFormat: true }); + await migrate(tree, options); expect(loggerInfoSpy).toHaveBeenCalledWith( 'Multiple semver configs detected, the migration can eventually break your workspace. Please verify the changes.', @@ -99,8 +102,8 @@ describe('Native Nx Release Migration', () => { describe('Nx Release Configuration', () => { let release: NxJsonConfiguration['release']; - function setupSemver( - options: Partial = {}, + async function setupSemver( + versionOpts: Partial = {}, targets: ProjectConfiguration['targets'] = {}, ) { addProjectConfiguration(tree, 'a', { @@ -108,33 +111,33 @@ describe('Native Nx Release Migration', () => { targets: { version: { executor: '@jscutlery/semver:version', - options, + options: versionOpts, }, ...targets, }, }); - migrate(tree, { skipFormat: true }); + await migrate(tree, options); release = readNxJson(tree)!.release; } - it('should configure release.releaseTagPattern', () => { - setupSemver(); + it('should configure release.releaseTagPattern', async () => { + await setupSemver(); expect(release!.releaseTagPattern).toBe(`{projectName}-{version}`); }); - it('should configure projects', () => { - setupSemver(); + it('should configure projects', async () => { + await setupSemver(); expect(release!.projects).toEqual(['a']); expect(release!.version!.conventionalCommits).toEqual(true); expect(release!.projectsRelationship).toEqual('independent'); }); - it('should configure git with --skipCommit', () => { - setupSemver({ skipCommit: true }); + it('should configure git with --skipCommit', async () => { + await setupSemver({ skipCommit: true }); expect(release).toEqual( expect.objectContaining({ @@ -145,8 +148,8 @@ describe('Native Nx Release Migration', () => { ); }); - it('should configure github release', () => { - setupSemver( + it('should configure github release', async () => { + await setupSemver( { postTargets: ['github'] }, { github: { executor: '@jscutlery/semver:github' } }, ); @@ -159,7 +162,7 @@ describe('Native Nx Release Migration', () => { }); describe('Cleanup @jscutlery/semver', () => { - it('should remove version target', () => { + it('should remove version target', async () => { addProjectConfiguration(tree, 'a', { root: 'libs/a', targets: { @@ -169,13 +172,13 @@ describe('Native Nx Release Migration', () => { }, }); - migrate(tree, { skipFormat: true }); + await migrate(tree, options); const projectConfig = getProjects(tree).get('a'); expect(projectConfig!.targets!.version).toBeUndefined(); }); - it('should remove github post-target', () => { + it('should remove github post-target', async () => { addProjectConfiguration(tree, 'a', { root: 'libs/a', targets: { @@ -194,13 +197,13 @@ describe('Native Nx Release Migration', () => { }, }); - migrate(tree, { skipFormat: true }); + await migrate(tree, options); const projectConfig = getProjects(tree).get('a'); expect(projectConfig!.targets!.github).toBeUndefined(); }); - it('should remove npm post-target (ngx-deploy-npm)', () => { + it('should remove npm post-target (ngx-deploy-npm)', async () => { addProjectConfiguration(tree, 'a', { root: 'libs/a', targets: { @@ -219,14 +222,14 @@ describe('Native Nx Release Migration', () => { }, }); - migrate(tree, { skipFormat: true }); + await migrate(tree, options); const projectConfig = getProjects(tree).get('a'); expect(projectConfig!.targets!.npm).toBeUndefined(); expect(projectConfig!.targets!.build).toBeDefined(); }); - it('should remove npm post-target (custom npm publish command)', () => { + it('should remove npm post-target (custom npm publish command)', async () => { addProjectConfiguration(tree, 'a', { root: 'libs/a', targets: { @@ -245,14 +248,14 @@ describe('Native Nx Release Migration', () => { }, }); - migrate(tree, { skipFormat: true }); + await migrate(tree, options); const projectConfig = getProjects(tree).get('a'); expect(projectConfig!.targets!.npm).toBeUndefined(); expect(projectConfig!.targets!.build).toBeDefined(); }); - it('should keep build post-target', () => { + it('should keep build post-target', async () => { addProjectConfiguration(tree, 'a', { root: 'libs/a', targets: { @@ -268,13 +271,42 @@ describe('Native Nx Release Migration', () => { }, }); - migrate(tree, { skipFormat: true }); + await migrate(tree, options); const projectConfig = getProjects(tree).get('a'); expect(projectConfig!.targets!.build).toBeDefined(); }); - it.todo('should remove @jscutlery/semver from package.json'); + it('should remove dependencies from package.json', async () => { + tree.write( + 'package.json', + JSON.stringify( + { + devDependencies: { + '@jscutlery/semver': '0.0.0', + 'ngx-deploy-npm': '0.0.0', + }, + }, + null, + 2, + ), + ); + + addProjectConfiguration(tree, 'a', { + root: 'libs/a', + targets: { + version: { + executor: '@jscutlery/semver:version', + }, + }, + }); + + await migrate(tree, options); + + const packageJson = readJson(tree, 'package.json'); + expect(packageJson.devDependencies['@jscutlery/semver']).toBeUndefined(); + expect(packageJson.devDependencies['ngx-deploy-npm']).toBeUndefined(); + }); }); it.todo('should inform about detected ci setup and suggest how to update it'); diff --git a/packages/semver/src/generators/migrate-nx-release/index.ts b/packages/semver/src/generators/migrate-nx-release/index.ts index 15f5ec86b..8e75c86ad 100644 --- a/packages/semver/src/generators/migrate-nx-release/index.ts +++ b/packages/semver/src/generators/migrate-nx-release/index.ts @@ -8,13 +8,18 @@ import { formatFiles, writeJson, TargetConfiguration, + installPackagesTask, + updateJson, } from '@nx/devkit'; import { VersionBuilderSchema } from '../../executors/version/schema'; import { defaultHeader } from '../../executors/version/utils/changelog'; /* eslint-disable @typescript-eslint/no-non-null-assertion */ -export default function migrate(tree: Tree, options: { skipFormat: boolean }) { +export default async function migrate( + tree: Tree, + options: { skipFormat: boolean; skipInstall: boolean }, +) { const projects = Array.from(getProjects(tree)); const syncModeDetected = projects.some(([, projectConfig]) => { return getSemverOptions(projectConfig).syncVersions === true; @@ -63,7 +68,21 @@ export default function migrate(tree: Tree, options: { skipFormat: boolean }) { removeSemverChangelogHeader(tree, projectConfig); }); - return !options.skipFormat && formatFiles(tree); + updateJson(tree, 'package.json', (packageJson) => { + ['@jscutlery/semver', 'ngx-deploy-npm'].forEach((dep) => { + delete packageJson?.dependencies?.[dep]; + delete packageJson?.devDependencies?.[dep]; + }); + return packageJson; + }); + + if (!options.skipFormat) { + await formatFiles(tree); + } + + return () => { + !options.skipInstall && installPackagesTask(tree); + }; } function removeSemverTargets( diff --git a/packages/semver/src/generators/migrate-nx-release/schema.json b/packages/semver/src/generators/migrate-nx-release/schema.json index 459e23309..5ff793faf 100644 --- a/packages/semver/src/generators/migrate-nx-release/schema.json +++ b/packages/semver/src/generators/migrate-nx-release/schema.json @@ -8,6 +8,11 @@ "description": "Skip formatting files", "type": "boolean", "default": false + }, + "skipInstall": { + "description": "Skip install dependencies", + "type": "boolean", + "default": false } }, "required": [] From 3677bf31fe5da776f488703ba86e1f5ec7d87bdb Mon Sep 17 00:00:00 2001 From: Edouard Bozon Date: Sun, 11 Feb 2024 17:26:11 +0100 Subject: [PATCH 20/22] wip: log manual CI setup required --- .../src/generators/migrate-nx-release/index.spec.ts | 2 -- .../semver/src/generators/migrate-nx-release/index.ts | 11 +++++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/packages/semver/src/generators/migrate-nx-release/index.spec.ts b/packages/semver/src/generators/migrate-nx-release/index.spec.ts index 3efedfad6..27d2c9799 100644 --- a/packages/semver/src/generators/migrate-nx-release/index.spec.ts +++ b/packages/semver/src/generators/migrate-nx-release/index.spec.ts @@ -308,6 +308,4 @@ describe('Native Nx Release Migration', () => { expect(packageJson.devDependencies['ngx-deploy-npm']).toBeUndefined(); }); }); - - it.todo('should inform about detected ci setup and suggest how to update it'); }); diff --git a/packages/semver/src/generators/migrate-nx-release/index.ts b/packages/semver/src/generators/migrate-nx-release/index.ts index 8e75c86ad..76e34e0e7 100644 --- a/packages/semver/src/generators/migrate-nx-release/index.ts +++ b/packages/semver/src/generators/migrate-nx-release/index.ts @@ -76,6 +76,17 @@ export default async function migrate( return packageJson; }); + if ( + tree.exists('.github') || + tree.exists('.gitlab-ci.yml') || + tree.exists('.circleci') || + tree.exists('.travis.yml') + ) { + logger.info( + 'CI setup detected, please update your CI configuration to use Nx Release.', + ); + } + if (!options.skipFormat) { await formatFiles(tree); } From 6051bd18c15341f21c7747701f77e9e98fa96e7a Mon Sep 17 00:00:00 2001 From: Edouard Bozon Date: Sun, 11 Feb 2024 17:35:17 +0100 Subject: [PATCH 21/22] wip: add --no-verify only if husky config present --- packages/semver/src/generators/migrate-nx-release/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/semver/src/generators/migrate-nx-release/index.ts b/packages/semver/src/generators/migrate-nx-release/index.ts index 76e34e0e7..aae0be213 100644 --- a/packages/semver/src/generators/migrate-nx-release/index.ts +++ b/packages/semver/src/generators/migrate-nx-release/index.ts @@ -164,7 +164,7 @@ function configureNxRelease( }, git: { commit: !options.skipCommit ?? true, - commitArgs: '--no-verify', + ...(tree.exists('.husky') ? { commitArgs: '--no-verify' } : {}), }, changelog: { automaticFromRef: true, From 597270a54a2b039094e34da952a1dbdd6feef216 Mon Sep 17 00:00:00 2001 From: Edouard Bozon Date: Mon, 12 Feb 2024 09:36:17 +0100 Subject: [PATCH 22/22] wip: drop semver targetDefaults --- .../migrate-nx-release/index.spec.ts | 63 +++++++++++++++++++ .../generators/migrate-nx-release/index.ts | 17 +++++ 2 files changed, 80 insertions(+) diff --git a/packages/semver/src/generators/migrate-nx-release/index.spec.ts b/packages/semver/src/generators/migrate-nx-release/index.spec.ts index 27d2c9799..bc47ae0c2 100644 --- a/packages/semver/src/generators/migrate-nx-release/index.spec.ts +++ b/packages/semver/src/generators/migrate-nx-release/index.spec.ts @@ -26,6 +26,7 @@ describe('Native Nx Release Migration', () => { beforeEach(() => { tree = createTreeWithEmptyWorkspace(); loggerInfoSpy = jest.spyOn(logger, 'info').mockImplementation(); + loggerInfoSpy.mockReset(); }); it('should bail out if sync mode is detected', async () => { @@ -307,5 +308,67 @@ describe('Native Nx Release Migration', () => { expect(packageJson.devDependencies['@jscutlery/semver']).toBeUndefined(); expect(packageJson.devDependencies['ngx-deploy-npm']).toBeUndefined(); }); + + it('should inform about CI setup if config detected', async () => { + addProjectConfiguration(tree, 'a', { + root: 'libs/a', + targets: { + version: { + executor: '@jscutlery/semver:version', + }, + }, + }); + tree.write('.gitlab-ci.yml', ''); + + await migrate(tree, options); + + expect(loggerInfoSpy).toHaveBeenCalledWith( + 'CI setup detected, please update your CI configuration to use Nx Release.', + ); + }); + + it('should remove targetDefaults', async () => { + addProjectConfiguration(tree, 'a', { + root: 'libs/a', + targets: { + version: { + executor: '@jscutlery/semver:version', + }, + }, + }); + + tree.write( + 'nx.json', + JSON.stringify( + { + targetDefaults: { + version: { + cache: false, + }, + '@jscutlery/semver:version': { + cache: false, + options: { + commitMessageFormat: 'chore(release): {version}', + }, + }, + npm: { + command: 'npm publish dist/lib/a', + }, + }, + }, + null, + 2, + ), + ); + + await migrate(tree, options); + + const nxJson = readJson(tree, 'nx.json'); + expect( + nxJson.targetDefaults['@jscutlery/semver:version'], + ).toBeUndefined(); + expect(nxJson.targetDefaults.version).toBeUndefined(); + expect(nxJson.targetDefaults.npm).toBeUndefined(); + }); }); }); diff --git a/packages/semver/src/generators/migrate-nx-release/index.ts b/packages/semver/src/generators/migrate-nx-release/index.ts index aae0be213..787418479 100644 --- a/packages/semver/src/generators/migrate-nx-release/index.ts +++ b/packages/semver/src/generators/migrate-nx-release/index.ts @@ -10,6 +10,7 @@ import { TargetConfiguration, installPackagesTask, updateJson, + NxJsonConfiguration, } from '@nx/devkit'; import { VersionBuilderSchema } from '../../executors/version/schema'; import { defaultHeader } from '../../executors/version/utils/changelog'; @@ -68,6 +69,22 @@ export default async function migrate( removeSemverChangelogHeader(tree, projectConfig); }); + updateJson(tree, 'nx.json', (nxJson) => { + Object.entries(nxJson?.targetDefaults ?? {}).forEach( + ([targetKey, target]) => { + if ( + targetKey === 'version' || + targetKey.includes('semver') || + targetKey.includes('ngx-deploy-npm') || + /npm publish/.test(JSON.stringify(target)) + ) { + delete nxJson!.targetDefaults![targetKey]; + } + }, + ); + return nxJson; + }); + updateJson(tree, 'package.json', (packageJson) => { ['@jscutlery/semver', 'ngx-deploy-npm'].forEach((dep) => { delete packageJson?.dependencies?.[dep];