feat(js): replace publish script with nx release config (#21474)
This commit is contained in:
parent
391f3ab8e6
commit
38179ad278
@ -2323,6 +2323,14 @@
|
|||||||
"isExternal": false,
|
"isExternal": false,
|
||||||
"children": [],
|
"children": [],
|
||||||
"disableCollapsible": false
|
"disableCollapsible": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Update Your Local Registry Setup to use Nx Release",
|
||||||
|
"path": "/recipes/nx-release/update-local-registry-setup",
|
||||||
|
"id": "update-local-registry-setup",
|
||||||
|
"isExternal": false,
|
||||||
|
"children": [],
|
||||||
|
"disableCollapsible": false
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"disableCollapsible": false
|
"disableCollapsible": false
|
||||||
@ -4147,6 +4155,14 @@
|
|||||||
"isExternal": false,
|
"isExternal": false,
|
||||||
"children": [],
|
"children": [],
|
||||||
"disableCollapsible": false
|
"disableCollapsible": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Update Your Local Registry Setup to use Nx Release",
|
||||||
|
"path": "/recipes/nx-release/update-local-registry-setup",
|
||||||
|
"id": "update-local-registry-setup",
|
||||||
|
"isExternal": false,
|
||||||
|
"children": [],
|
||||||
|
"disableCollapsible": false
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"disableCollapsible": false
|
"disableCollapsible": false
|
||||||
@ -4199,6 +4215,14 @@
|
|||||||
"children": [],
|
"children": [],
|
||||||
"disableCollapsible": false
|
"disableCollapsible": false
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "Update Your Local Registry Setup to use Nx Release",
|
||||||
|
"path": "/recipes/nx-release/update-local-registry-setup",
|
||||||
|
"id": "update-local-registry-setup",
|
||||||
|
"isExternal": false,
|
||||||
|
"children": [],
|
||||||
|
"disableCollapsible": false
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "Other",
|
"name": "Other",
|
||||||
"path": "/recipes/other",
|
"path": "/recipes/other",
|
||||||
|
|||||||
@ -3177,6 +3177,17 @@
|
|||||||
"isExternal": false,
|
"isExternal": false,
|
||||||
"path": "/recipes/nx-release/publish-rust-crates",
|
"path": "/recipes/nx-release/publish-rust-crates",
|
||||||
"tags": ["nx-release"]
|
"tags": ["nx-release"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "update-local-registry-setup",
|
||||||
|
"name": "Update Your Local Registry Setup to use Nx Release",
|
||||||
|
"description": "",
|
||||||
|
"mediaImage": "",
|
||||||
|
"file": "shared/recipes/nx-release/update-local-registry-setup",
|
||||||
|
"itemList": [],
|
||||||
|
"isExternal": false,
|
||||||
|
"path": "/recipes/nx-release/update-local-registry-setup",
|
||||||
|
"tags": ["nx-release"]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"isExternal": false,
|
"isExternal": false,
|
||||||
@ -5678,6 +5689,17 @@
|
|||||||
"isExternal": false,
|
"isExternal": false,
|
||||||
"path": "/recipes/nx-release/publish-rust-crates",
|
"path": "/recipes/nx-release/publish-rust-crates",
|
||||||
"tags": ["nx-release"]
|
"tags": ["nx-release"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "update-local-registry-setup",
|
||||||
|
"name": "Update Your Local Registry Setup to use Nx Release",
|
||||||
|
"description": "",
|
||||||
|
"mediaImage": "",
|
||||||
|
"file": "shared/recipes/nx-release/update-local-registry-setup",
|
||||||
|
"itemList": [],
|
||||||
|
"isExternal": false,
|
||||||
|
"path": "/recipes/nx-release/update-local-registry-setup",
|
||||||
|
"tags": ["nx-release"]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"isExternal": false,
|
"isExternal": false,
|
||||||
@ -5750,6 +5772,17 @@
|
|||||||
"path": "/recipes/nx-release/publish-rust-crates",
|
"path": "/recipes/nx-release/publish-rust-crates",
|
||||||
"tags": ["nx-release"]
|
"tags": ["nx-release"]
|
||||||
},
|
},
|
||||||
|
"/recipes/nx-release/update-local-registry-setup": {
|
||||||
|
"id": "update-local-registry-setup",
|
||||||
|
"name": "Update Your Local Registry Setup to use Nx Release",
|
||||||
|
"description": "",
|
||||||
|
"mediaImage": "",
|
||||||
|
"file": "shared/recipes/nx-release/update-local-registry-setup",
|
||||||
|
"itemList": [],
|
||||||
|
"isExternal": false,
|
||||||
|
"path": "/recipes/nx-release/update-local-registry-setup",
|
||||||
|
"tags": ["nx-release"]
|
||||||
|
},
|
||||||
"/recipes/other": {
|
"/recipes/other": {
|
||||||
"id": "other",
|
"id": "other",
|
||||||
"name": "Other",
|
"name": "Other",
|
||||||
|
|||||||
@ -1029,6 +1029,13 @@
|
|||||||
"id": "publish-rust-crates",
|
"id": "publish-rust-crates",
|
||||||
"name": "Publish Rust Crates",
|
"name": "Publish Rust Crates",
|
||||||
"path": "/recipes/nx-release/publish-rust-crates"
|
"path": "/recipes/nx-release/publish-rust-crates"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "",
|
||||||
|
"file": "shared/recipes/nx-release/update-local-registry-setup",
|
||||||
|
"id": "update-local-registry-setup",
|
||||||
|
"name": "Update Your Local Registry Setup to use Nx Release",
|
||||||
|
"path": "/recipes/nx-release/update-local-registry-setup"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"database": [
|
"database": [
|
||||||
|
|||||||
@ -89,7 +89,7 @@
|
|||||||
"publishable": {
|
"publishable": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false,
|
"default": false,
|
||||||
"description": "Generate a publishable library.",
|
"description": "Configure the library ready for use with `nx release` (https://nx.dev/core-features/manage-releases).",
|
||||||
"x-priority": "important"
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"importPath": {
|
"importPath": {
|
||||||
|
|||||||
@ -50,6 +50,18 @@
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"description": "Additional metadata to pass to the current version resolver.",
|
"description": "Additional metadata to pass to the current version resolver.",
|
||||||
"default": {}
|
"default": {}
|
||||||
|
},
|
||||||
|
"skipLockFileUpdate": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Whether to skip updating the lock file after updating the version."
|
||||||
|
},
|
||||||
|
"installArgs": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Additional arguments to pass to the package manager when updating the lock file with an install command."
|
||||||
|
},
|
||||||
|
"installIgnoreScripts": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Whether to ignore install lifecycle scripts when updating the lock file with an install command."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": ["projects", "projectGraph", "releaseGroup"],
|
"required": ["projects", "projectGraph", "releaseGroup"],
|
||||||
|
|||||||
@ -1149,6 +1149,12 @@
|
|||||||
"id": "publish-rust-crates",
|
"id": "publish-rust-crates",
|
||||||
"tags": ["nx-release"],
|
"tags": ["nx-release"],
|
||||||
"file": "shared/recipes/nx-release/publish-rust-crates"
|
"file": "shared/recipes/nx-release/publish-rust-crates"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Update Your Local Registry Setup to use Nx Release",
|
||||||
|
"id": "update-local-registry-setup",
|
||||||
|
"tags": ["nx-release"],
|
||||||
|
"file": "shared/recipes/nx-release/update-local-registry-setup"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@ -0,0 +1,79 @@
|
|||||||
|
# Update Your Local Registry Setup to use Nx Release
|
||||||
|
|
||||||
|
Nx will create a `tools/start-local-registry.ts` script for starting a local registry and publishing packages to it in preparation for running end to end tests. If you have an existing `tools/start-local-registry.ts` script from a previous version of Nx, you should update it to use Nx Release to publish packages to the local registry. This will ensure that newly generated libraries are published appropriately when running end to end tests.
|
||||||
|
|
||||||
|
## The Previous Version
|
||||||
|
|
||||||
|
The previous version of the `tools/start-local-registry.ts` script used publish targets on each project to publish the packages to the local registry. This is no longer necessary with Nx Release. You can identify the previous version by the `nx run-many` command that publishes the packages:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
/**
|
||||||
|
* This script starts a local registry for e2e testing purposes.
|
||||||
|
* It is meant to be called in jest's globalSetup.
|
||||||
|
*/
|
||||||
|
import { startLocalRegistry } from '@nx/js/plugins/jest/local-registry';
|
||||||
|
import { execFileSync } from 'child_process';
|
||||||
|
|
||||||
|
export default async () => {
|
||||||
|
// local registry target to run
|
||||||
|
const localRegistryTarget = '@demo-plugin-1800/source:local-registry';
|
||||||
|
// storage folder for the local registry
|
||||||
|
const storage = './tmp/local-registry/storage';
|
||||||
|
|
||||||
|
global.stopLocalRegistry = await startLocalRegistry({
|
||||||
|
localRegistryTarget,
|
||||||
|
storage,
|
||||||
|
verbose: false,
|
||||||
|
});
|
||||||
|
const nx = require.resolve('nx');
|
||||||
|
execFileSync(
|
||||||
|
nx,
|
||||||
|
['run-many', '--targets', 'publish', '--ver', '0.0.0-e2e', '--tag', 'e2e'],
|
||||||
|
{ env: process.env, stdio: 'inherit' }
|
||||||
|
);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
If your script looks like this, you should update it.
|
||||||
|
|
||||||
|
## The Updated Version
|
||||||
|
|
||||||
|
The updated version of the `tools/start-local-registry.ts` script uses Nx Release to publish the packages to the local registry. This is done by running `releaseVersion` and `releasePublish` functions from `nx/release`. Your updated script should look like this:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
/**
|
||||||
|
* This script starts a local registry for e2e testing purposes.
|
||||||
|
* It is meant to be called in jest's globalSetup.
|
||||||
|
*/
|
||||||
|
import { startLocalRegistry } from '@nx/js/plugins/jest/local-registry';
|
||||||
|
import { execFileSync } from 'child_process';
|
||||||
|
import { releasePublish, releaseVersion } from 'nx/release';
|
||||||
|
|
||||||
|
export default async () => {
|
||||||
|
// local registry target to run
|
||||||
|
const localRegistryTarget = '@demo-plugin-1800/source:local-registry';
|
||||||
|
// storage folder for the local registry
|
||||||
|
const storage = './tmp/local-registry/storage';
|
||||||
|
|
||||||
|
global.stopLocalRegistry = await startLocalRegistry({
|
||||||
|
localRegistryTarget,
|
||||||
|
storage,
|
||||||
|
verbose: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
await releaseVersion({
|
||||||
|
specifier: '0.0.0-e2e',
|
||||||
|
stageChanges: false,
|
||||||
|
gitCommit: false,
|
||||||
|
gitTag: false,
|
||||||
|
firstRelease: true,
|
||||||
|
generatorOptionsOverrides: {
|
||||||
|
skipLockFileUpdate: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
await releasePublish({
|
||||||
|
tag: 'e2e',
|
||||||
|
firstRelease: true,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
```
|
||||||
@ -183,6 +183,7 @@
|
|||||||
- [Publish in CI/CD](/recipes/nx-release/publish-in-ci-cd)
|
- [Publish in CI/CD](/recipes/nx-release/publish-in-ci-cd)
|
||||||
- [Automate GitHub Releases](/recipes/nx-release/automate-github-releases)
|
- [Automate GitHub Releases](/recipes/nx-release/automate-github-releases)
|
||||||
- [Publish Rust Crates](/recipes/nx-release/publish-rust-crates)
|
- [Publish Rust Crates](/recipes/nx-release/publish-rust-crates)
|
||||||
|
- [Update Your Local Registry Setup to use Nx Release](/recipes/nx-release/update-local-registry-setup)
|
||||||
- [Other](/recipes/other)
|
- [Other](/recipes/other)
|
||||||
- [Rescope Packages from @nrwl to @nx](/recipes/other/rescope)
|
- [Rescope Packages from @nrwl to @nx](/recipes/other/rescope)
|
||||||
- [Showcase](/showcase)
|
- [Showcase](/showcase)
|
||||||
|
|||||||
@ -10,12 +10,10 @@ import {
|
|||||||
readJson,
|
readJson,
|
||||||
runCLI,
|
runCLI,
|
||||||
runCommand,
|
runCommand,
|
||||||
runCommandUntil,
|
|
||||||
tmpProjPath,
|
tmpProjPath,
|
||||||
uniq,
|
uniq,
|
||||||
updateFile,
|
updateFile,
|
||||||
updateJson,
|
updateJson,
|
||||||
waitUntil,
|
|
||||||
} from '@nx/e2e/utils';
|
} from '@nx/e2e/utils';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
|
|
||||||
@ -44,6 +42,7 @@ describe('EsBuild Plugin', () => {
|
|||||||
expect(packageJson).toEqual({
|
expect(packageJson).toEqual({
|
||||||
name: `@proj/${myPkg}`,
|
name: `@proj/${myPkg}`,
|
||||||
version: '0.0.1',
|
version: '0.0.1',
|
||||||
|
private: true,
|
||||||
type: 'commonjs',
|
type: 'commonjs',
|
||||||
main: './index.cjs',
|
main: './index.cjs',
|
||||||
dependencies: {},
|
dependencies: {},
|
||||||
|
|||||||
@ -497,6 +497,7 @@ describe('Linter', () => {
|
|||||||
},
|
},
|
||||||
"main": "./src/index.js",
|
"main": "./src/index.js",
|
||||||
"name": "@proj/${mylib}",
|
"name": "@proj/${mylib}",
|
||||||
|
"private": true,
|
||||||
"type": "commonjs",
|
"type": "commonjs",
|
||||||
"typings": "./src/index.d.ts",
|
"typings": "./src/index.d.ts",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
|
|||||||
@ -16,11 +16,11 @@ import {
|
|||||||
} from '@nx/e2e/utils';
|
} from '@nx/e2e/utils';
|
||||||
import type { PackageJson } from 'nx/src/utils/package-json';
|
import type { PackageJson } from 'nx/src/utils/package-json';
|
||||||
|
|
||||||
|
import { join } from 'path';
|
||||||
import {
|
import {
|
||||||
ASYNC_GENERATOR_EXECUTOR_CONTENTS,
|
ASYNC_GENERATOR_EXECUTOR_CONTENTS,
|
||||||
NX_PLUGIN_V2_CONTENTS,
|
NX_PLUGIN_V2_CONTENTS,
|
||||||
} from './nx-plugin.fixtures';
|
} from './nx-plugin.fixtures';
|
||||||
import { join } from 'path';
|
|
||||||
|
|
||||||
describe('Nx Plugin', () => {
|
describe('Nx Plugin', () => {
|
||||||
let workspaceName: string;
|
let workspaceName: string;
|
||||||
@ -50,6 +50,7 @@ describe('Nx Plugin', () => {
|
|||||||
expect(project).toMatchObject({
|
expect(project).toMatchObject({
|
||||||
tags: [],
|
tags: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
runCLI(`e2e ${plugin}-e2e`);
|
runCLI(`e2e ${plugin}-e2e`);
|
||||||
}, 90000);
|
}, 90000);
|
||||||
|
|
||||||
|
|||||||
117
e2e/release/src/pre-version-command.test.ts
Normal file
117
e2e/release/src/pre-version-command.test.ts
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
import {
|
||||||
|
cleanupProject,
|
||||||
|
newProject,
|
||||||
|
runCLI,
|
||||||
|
uniq,
|
||||||
|
updateJson,
|
||||||
|
} from '@nx/e2e/utils';
|
||||||
|
|
||||||
|
expect.addSnapshotSerializer({
|
||||||
|
serialize(str: string) {
|
||||||
|
return (
|
||||||
|
str
|
||||||
|
// Remove all output unique to specific projects to ensure deterministic snapshots
|
||||||
|
.replaceAll(/my-pkg-\d+/g, '{project-name}')
|
||||||
|
.replaceAll(
|
||||||
|
/integrity:\s*.*/g,
|
||||||
|
'integrity: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
|
||||||
|
)
|
||||||
|
.replaceAll(/\b[0-9a-f]{40}\b/g, '{SHASUM}')
|
||||||
|
.replaceAll(/\d*B index\.js/g, 'XXB index.js')
|
||||||
|
.replaceAll(/\d*B project\.json/g, 'XXB project.json')
|
||||||
|
.replaceAll(/\d*B package\.json/g, 'XXXB package.json')
|
||||||
|
.replaceAll(/size:\s*\d*\s?B/g, 'size: XXXB')
|
||||||
|
.replaceAll(/\d*\.\d*\s?kB/g, 'XXX.XXX kb')
|
||||||
|
.replaceAll(/[a-fA-F0-9]{7}/g, '{COMMIT_SHA}')
|
||||||
|
.replaceAll(/Test @[\w\d]+/g, 'Test @{COMMIT_AUTHOR}')
|
||||||
|
// Normalize the version title date.
|
||||||
|
.replaceAll(/\(\d{4}-\d{2}-\d{2}\)/g, '(YYYY-MM-DD)')
|
||||||
|
// We trim each line to reduce the chances of snapshot flakiness
|
||||||
|
.split('\n')
|
||||||
|
.map((r) => r.trim())
|
||||||
|
.join('\n')
|
||||||
|
);
|
||||||
|
},
|
||||||
|
test(val: string) {
|
||||||
|
return val != null && typeof val === 'string';
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('nx release pre-version command', () => {
|
||||||
|
let pkg1: string;
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
newProject({
|
||||||
|
unsetProjectNameAndRootFormat: false,
|
||||||
|
packages: ['@nx/js'],
|
||||||
|
});
|
||||||
|
|
||||||
|
pkg1 = uniq('my-pkg-1');
|
||||||
|
runCLI(
|
||||||
|
`generate @nx/js:library ${pkg1} --publishable --importPath=${pkg1}`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
afterAll(() => cleanupProject());
|
||||||
|
|
||||||
|
it('should run pre-version command before versioning step', async () => {
|
||||||
|
updateJson(`nx.json`, (json) => {
|
||||||
|
delete json.release;
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
const result1 = runCLI('release patch -d --first-release', {
|
||||||
|
silenceError: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
// command should fail because @nx/js:library configures the packageRoot to be dist/{project-name}, which doesn't exist yet
|
||||||
|
expect(result1).toContain(
|
||||||
|
`NX The project "${pkg1}" does not have a package.json available at dist/${pkg1}/package.json.`
|
||||||
|
);
|
||||||
|
|
||||||
|
updateJson(`nx.json`, (json) => {
|
||||||
|
json.release = {
|
||||||
|
version: {
|
||||||
|
preVersionCommand: 'nx run-many -t build',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
|
||||||
|
// command should succeed because the pre-version command will build the package
|
||||||
|
const result2 = runCLI('release patch -d --first-release');
|
||||||
|
|
||||||
|
expect(result2).toContain('NX Executing pre-version command');
|
||||||
|
|
||||||
|
const result3 = runCLI('release patch -d --first-release --verbose');
|
||||||
|
|
||||||
|
expect(result3).toContain('NX Executing pre-version command');
|
||||||
|
expect(result3).toContain('Executing the following pre-version command:');
|
||||||
|
expect(result3).toContain('nx run-many -t build');
|
||||||
|
expect(result3).toContain(`NX Running target build for project ${pkg1}:`);
|
||||||
|
|
||||||
|
updateJson(`nx.json`, (json) => {
|
||||||
|
json.release = {
|
||||||
|
version: {
|
||||||
|
preVersionCommand: 'echo "error" && exit 1',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
|
||||||
|
// command should fail because the pre-version command will fail
|
||||||
|
const result4 = runCLI('release patch -d --first-release', {
|
||||||
|
silenceError: true,
|
||||||
|
});
|
||||||
|
expect(result4).toContain(
|
||||||
|
'NX The pre-version command failed. Retry with --verbose to see the full output of the pre-version command.'
|
||||||
|
);
|
||||||
|
expect(result4).toContain('echo "error" && exit 1');
|
||||||
|
|
||||||
|
const result5 = runCLI('release patch -d --first-release --verbose', {
|
||||||
|
silenceError: true,
|
||||||
|
});
|
||||||
|
expect(result5).toContain(
|
||||||
|
'NX The pre-version command failed. See the full output above.'
|
||||||
|
);
|
||||||
|
expect(result4).toContain('echo "error" && exit 1');
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -92,7 +92,12 @@ describe('nx release - private JS packages', () => {
|
|||||||
});
|
});
|
||||||
afterAll(() => cleanupProject());
|
afterAll(() => cleanupProject());
|
||||||
|
|
||||||
it('should skip private packages and log a warning', async () => {
|
it('should skip private packages and log a warning when private packages are explicitly configured', async () => {
|
||||||
|
updateJson('nx.json', (json) => {
|
||||||
|
json.release.projects = [publicPkg1, publicPkg2, privatePkg];
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
|
||||||
runCLI(`release version 999.9.9`);
|
runCLI(`release version 999.9.9`);
|
||||||
|
|
||||||
// This is the verdaccio instance that the e2e tests themselves are working from
|
// This is the verdaccio instance that the e2e tests themselves are working from
|
||||||
@ -222,4 +227,92 @@ describe('nx release - private JS packages', () => {
|
|||||||
/npm ERR! code E404/
|
/npm ERR! code E404/
|
||||||
);
|
);
|
||||||
}, 500000);
|
}, 500000);
|
||||||
|
|
||||||
|
it('should skip private packages and not log a warning when no projects config exists', async () => {
|
||||||
|
updateJson('nx.json', (json) => {
|
||||||
|
delete json.release.projects;
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
|
||||||
|
runCLI(`release version 999.9.10`);
|
||||||
|
|
||||||
|
// This is the verdaccio instance that the e2e tests themselves are working from
|
||||||
|
const e2eRegistryUrl = execSync('npm config get registry')
|
||||||
|
.toString()
|
||||||
|
.trim();
|
||||||
|
|
||||||
|
// Thanks to the custom serializer above, the publish output should be deterministic
|
||||||
|
const publishOutput = runCLI(`release publish`);
|
||||||
|
expect(publishOutput).toMatchInlineSnapshot(`
|
||||||
|
|
||||||
|
NX Running target nx-release-publish for 2 projects:
|
||||||
|
|
||||||
|
- {public-project-name}
|
||||||
|
- {public-project-name}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
> nx run {public-project-name}:nx-release-publish
|
||||||
|
|
||||||
|
|
||||||
|
📦 @proj/{public-project-name}@999.9.10
|
||||||
|
=== Tarball Contents ===
|
||||||
|
|
||||||
|
XXB index.js
|
||||||
|
XXXB package.json
|
||||||
|
XXB project.json
|
||||||
|
=== Tarball Details ===
|
||||||
|
name: @proj/{public-project-name}
|
||||||
|
version: 999.9.10
|
||||||
|
filename: proj-{public-project-name}-999.9.10.tgz
|
||||||
|
package size: XXXB
|
||||||
|
unpacked size: XXXB
|
||||||
|
shasum: {SHASUM}
|
||||||
|
integrity: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||||
|
total files: 3
|
||||||
|
|
||||||
|
Published to http://localhost:4873 with tag "latest"
|
||||||
|
|
||||||
|
> nx run {public-project-name}:nx-release-publish
|
||||||
|
|
||||||
|
|
||||||
|
📦 @proj/{public-project-name}@999.9.10
|
||||||
|
=== Tarball Contents ===
|
||||||
|
|
||||||
|
XXB index.js
|
||||||
|
XXXB package.json
|
||||||
|
XXB project.json
|
||||||
|
=== Tarball Details ===
|
||||||
|
name: @proj/{public-project-name}
|
||||||
|
version: 999.9.10
|
||||||
|
filename: proj-{public-project-name}-999.9.10.tgz
|
||||||
|
package size: XXXB
|
||||||
|
unpacked size: XXXB
|
||||||
|
shasum: {SHASUM}
|
||||||
|
integrity: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||||
|
total files: 3
|
||||||
|
|
||||||
|
Published to http://localhost:4873 with tag "latest"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
NX Successfully ran target nx-release-publish for 2 projects
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
`);
|
||||||
|
|
||||||
|
// The two public packages should have been published
|
||||||
|
expect(
|
||||||
|
execSync(`npm view @proj/${publicPkg1} version`).toString().trim()
|
||||||
|
).toEqual('999.9.10');
|
||||||
|
expect(
|
||||||
|
execSync(`npm view @proj/${publicPkg2} version`).toString().trim()
|
||||||
|
).toEqual('999.9.10');
|
||||||
|
|
||||||
|
// The private package should have never been published
|
||||||
|
expect(() => execSync(`npm view @proj/${privatePkg} version`)).toThrowError(
|
||||||
|
/npm ERR! code E404/
|
||||||
|
);
|
||||||
|
}, 500000);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
import {
|
import {
|
||||||
checkFilesExist,
|
checkFilesExist,
|
||||||
|
cleanupProject,
|
||||||
getSelectedPackageManager,
|
getSelectedPackageManager,
|
||||||
packageManagerLockFile,
|
packageManagerLockFile,
|
||||||
runCLI,
|
runCLI,
|
||||||
uniq,
|
|
||||||
runCreatePlugin,
|
runCreatePlugin,
|
||||||
cleanupProject,
|
uniq,
|
||||||
} from '@nx/e2e/utils';
|
} from '@nx/e2e/utils';
|
||||||
|
|
||||||
describe('create-nx-plugin', () => {
|
describe('create-nx-plugin', () => {
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
|
getPackageManagerCommand,
|
||||||
getProjects,
|
getProjects,
|
||||||
|
output,
|
||||||
readJson,
|
readJson,
|
||||||
readProjectConfiguration,
|
readProjectConfiguration,
|
||||||
Tree,
|
Tree,
|
||||||
@ -40,6 +42,7 @@ describe('lib', () => {
|
|||||||
});
|
});
|
||||||
expect(readJson(tree, '/my-lib/package.json')).toEqual({
|
expect(readJson(tree, '/my-lib/package.json')).toEqual({
|
||||||
name: '@proj/my-lib',
|
name: '@proj/my-lib',
|
||||||
|
private: true,
|
||||||
version: '0.0.1',
|
version: '0.0.1',
|
||||||
type: 'commonjs',
|
type: 'commonjs',
|
||||||
scripts: {
|
scripts: {
|
||||||
@ -1013,7 +1016,7 @@ describe('lib', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should generate the publish target', async () => {
|
it('should update the nx-release-publish target to specify dist/{projectRoot} as the package root', async () => {
|
||||||
await libraryGenerator(tree, {
|
await libraryGenerator(tree, {
|
||||||
...defaultOptions,
|
...defaultOptions,
|
||||||
name: 'my-lib',
|
name: 'my-lib',
|
||||||
@ -1024,24 +1027,356 @@ describe('lib', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const config = readProjectConfiguration(tree, 'my-lib');
|
const config = readProjectConfiguration(tree, 'my-lib');
|
||||||
expect(config.targets.publish).toEqual({
|
expect(config.targets['nx-release-publish']).toEqual({
|
||||||
command:
|
options: {
|
||||||
'node tools/scripts/publish.mjs my-lib {args.ver} {args.tag}',
|
packageRoot: 'dist/{projectRoot}',
|
||||||
dependsOn: ['build'],
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should generate publish script', async () => {
|
describe('nx release config', () => {
|
||||||
await libraryGenerator(tree, {
|
it('should not change preVersionCommand if it already exists', async () => {
|
||||||
...defaultOptions,
|
updateJson(tree, 'nx.json', (json) => {
|
||||||
name: 'my-lib',
|
json.release = {
|
||||||
publishable: true,
|
version: {
|
||||||
importPath: '@proj/my-lib',
|
preVersionCommand: 'echo "hello world"',
|
||||||
bundler: 'tsc',
|
},
|
||||||
projectNameAndRootFormat: 'as-provided',
|
};
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
|
||||||
|
await libraryGenerator(tree, {
|
||||||
|
...defaultOptions,
|
||||||
|
name: 'my-lib',
|
||||||
|
publishable: true,
|
||||||
|
importPath: '@proj/my-lib',
|
||||||
|
bundler: 'tsc',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
|
});
|
||||||
|
|
||||||
|
const nxJson = readJson(tree, 'nx.json');
|
||||||
|
expect(nxJson.release).toEqual({
|
||||||
|
version: {
|
||||||
|
preVersionCommand: 'echo "hello world"',
|
||||||
|
},
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(tree.exists('tools/scripts/publish.mjs')).toBeTruthy();
|
it('should not add projects if no release config exists', async () => {
|
||||||
|
updateJson(tree, 'nx.json', (json) => {
|
||||||
|
delete json.release;
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
|
||||||
|
await libraryGenerator(tree, {
|
||||||
|
...defaultOptions,
|
||||||
|
name: 'my-lib',
|
||||||
|
publishable: true,
|
||||||
|
importPath: '@proj/my-lib',
|
||||||
|
bundler: 'tsc',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
|
});
|
||||||
|
|
||||||
|
const nxJson = readJson(tree, 'nx.json');
|
||||||
|
expect(nxJson.release).toEqual({
|
||||||
|
version: {
|
||||||
|
preVersionCommand: `${
|
||||||
|
getPackageManagerCommand().dlx
|
||||||
|
} nx run-many -t build`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not add projects if release config exists but doesn't specify groups or projects", async () => {
|
||||||
|
const existingReleaseConfig = {
|
||||||
|
version: {
|
||||||
|
git: {},
|
||||||
|
},
|
||||||
|
changelog: {
|
||||||
|
projectChangelogs: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
updateJson(tree, 'nx.json', (json) => {
|
||||||
|
json.release = existingReleaseConfig;
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
|
||||||
|
await libraryGenerator(tree, {
|
||||||
|
...defaultOptions,
|
||||||
|
name: 'my-lib',
|
||||||
|
publishable: true,
|
||||||
|
importPath: '@proj/my-lib',
|
||||||
|
bundler: 'tsc',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
|
});
|
||||||
|
|
||||||
|
const nxJson = readJson(tree, 'nx.json');
|
||||||
|
expect(nxJson.release).toEqual({
|
||||||
|
...existingReleaseConfig,
|
||||||
|
version: {
|
||||||
|
...existingReleaseConfig.version,
|
||||||
|
preVersionCommand: `${
|
||||||
|
getPackageManagerCommand().dlx
|
||||||
|
} nx run-many -t build`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not change projects if it already exists as a string and matches the new project', async () => {
|
||||||
|
updateJson(tree, 'nx.json', (json) => {
|
||||||
|
json.release = {
|
||||||
|
projects: '*',
|
||||||
|
};
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
|
||||||
|
await libraryGenerator(tree, {
|
||||||
|
...defaultOptions,
|
||||||
|
name: 'my-lib',
|
||||||
|
publishable: true,
|
||||||
|
importPath: '@proj/my-lib',
|
||||||
|
bundler: 'tsc',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
|
});
|
||||||
|
|
||||||
|
const nxJson = readJson(tree, 'nx.json');
|
||||||
|
expect(nxJson.release).toEqual({
|
||||||
|
projects: '*',
|
||||||
|
version: {
|
||||||
|
preVersionCommand: `${
|
||||||
|
getPackageManagerCommand().dlx
|
||||||
|
} nx run-many -t build`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not change projects if it already exists as an array and matches the new project by name', async () => {
|
||||||
|
updateJson(tree, 'nx.json', (json) => {
|
||||||
|
json.release = {
|
||||||
|
projects: ['something-else', 'my-lib'],
|
||||||
|
};
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
|
||||||
|
await libraryGenerator(tree, {
|
||||||
|
...defaultOptions,
|
||||||
|
name: 'my-lib',
|
||||||
|
publishable: true,
|
||||||
|
importPath: '@proj/my-lib',
|
||||||
|
bundler: 'tsc',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
|
});
|
||||||
|
|
||||||
|
const nxJson = readJson(tree, 'nx.json');
|
||||||
|
expect(nxJson.release).toEqual({
|
||||||
|
projects: ['something-else', 'my-lib'],
|
||||||
|
version: {
|
||||||
|
preVersionCommand: `${
|
||||||
|
getPackageManagerCommand().dlx
|
||||||
|
} nx run-many -t build`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not change projects if it already exists and matches the new project by tag', async () => {
|
||||||
|
updateJson(tree, 'nx.json', (json) => {
|
||||||
|
json.release = {
|
||||||
|
projects: ['tag:one'],
|
||||||
|
};
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
|
||||||
|
await libraryGenerator(tree, {
|
||||||
|
...defaultOptions,
|
||||||
|
name: 'my-lib',
|
||||||
|
publishable: true,
|
||||||
|
importPath: '@proj/my-lib',
|
||||||
|
bundler: 'tsc',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
|
tags: 'one,two',
|
||||||
|
});
|
||||||
|
|
||||||
|
const nxJson = readJson(tree, 'nx.json');
|
||||||
|
expect(nxJson.release).toEqual({
|
||||||
|
projects: ['tag:one'],
|
||||||
|
version: {
|
||||||
|
preVersionCommand: `${
|
||||||
|
getPackageManagerCommand().dlx
|
||||||
|
} nx run-many -t build`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not change projects if it already exists and matches the new project by root directory', async () => {
|
||||||
|
updateJson(tree, 'nx.json', (json) => {
|
||||||
|
json.release = {
|
||||||
|
projects: ['packages/*'],
|
||||||
|
};
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
|
||||||
|
await libraryGenerator(tree, {
|
||||||
|
...defaultOptions,
|
||||||
|
name: 'my-lib',
|
||||||
|
publishable: true,
|
||||||
|
importPath: '@proj/my-lib',
|
||||||
|
bundler: 'tsc',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
|
directory: 'packages/my-lib',
|
||||||
|
});
|
||||||
|
|
||||||
|
const nxJson = readJson(tree, 'nx.json');
|
||||||
|
expect(nxJson.release).toEqual({
|
||||||
|
projects: ['packages/*'],
|
||||||
|
version: {
|
||||||
|
preVersionCommand: `${
|
||||||
|
getPackageManagerCommand().dlx
|
||||||
|
} nx run-many -t build`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should append project to projects if projects exists as an array, but doesn't already match the new project", async () => {
|
||||||
|
updateJson(tree, 'nx.json', (json) => {
|
||||||
|
json.release = {
|
||||||
|
projects: ['something-else'],
|
||||||
|
};
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
|
||||||
|
await libraryGenerator(tree, {
|
||||||
|
...defaultOptions,
|
||||||
|
name: 'my-lib',
|
||||||
|
publishable: true,
|
||||||
|
importPath: '@proj/my-lib',
|
||||||
|
bundler: 'tsc',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
|
});
|
||||||
|
|
||||||
|
const nxJson = readJson(tree, 'nx.json');
|
||||||
|
expect(nxJson.release).toEqual({
|
||||||
|
projects: ['something-else', 'my-lib'],
|
||||||
|
version: {
|
||||||
|
preVersionCommand: `${
|
||||||
|
getPackageManagerCommand().dlx
|
||||||
|
} nx run-many -t build`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should convert projects to an array and append the new project to it if projects exists as a string, but doesn't already match the new project", async () => {
|
||||||
|
updateJson(tree, 'nx.json', (json) => {
|
||||||
|
json.release = {
|
||||||
|
projects: 'packages',
|
||||||
|
};
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
|
||||||
|
await libraryGenerator(tree, {
|
||||||
|
...defaultOptions,
|
||||||
|
name: 'my-lib',
|
||||||
|
publishable: true,
|
||||||
|
importPath: '@proj/my-lib',
|
||||||
|
bundler: 'tsc',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
|
});
|
||||||
|
|
||||||
|
const nxJson = readJson(tree, 'nx.json');
|
||||||
|
expect(nxJson.release).toEqual({
|
||||||
|
projects: ['packages', 'my-lib'],
|
||||||
|
version: {
|
||||||
|
preVersionCommand: `${
|
||||||
|
getPackageManagerCommand().dlx
|
||||||
|
} nx run-many -t build`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not change projects if it already exists as groups config and matches the new project', async () => {
|
||||||
|
const existingReleaseConfig = {
|
||||||
|
groups: {
|
||||||
|
group1: {
|
||||||
|
projects: ['something-else'],
|
||||||
|
},
|
||||||
|
group2: {
|
||||||
|
projects: ['my-lib'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
updateJson(tree, 'nx.json', (json) => {
|
||||||
|
json.release = existingReleaseConfig;
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
|
||||||
|
await libraryGenerator(tree, {
|
||||||
|
...defaultOptions,
|
||||||
|
name: 'my-lib',
|
||||||
|
publishable: true,
|
||||||
|
importPath: '@proj/my-lib',
|
||||||
|
bundler: 'tsc',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
|
});
|
||||||
|
|
||||||
|
const nxJson = readJson(tree, 'nx.json');
|
||||||
|
expect(nxJson.release).toEqual({
|
||||||
|
groups: existingReleaseConfig.groups,
|
||||||
|
version: {
|
||||||
|
preVersionCommand: `${
|
||||||
|
getPackageManagerCommand().dlx
|
||||||
|
} nx run-many -t build`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should warn the user if their defined groups don't match the new project", async () => {
|
||||||
|
const outputSpy = jest
|
||||||
|
.spyOn(output, 'warn')
|
||||||
|
.mockImplementationOnce(() => {
|
||||||
|
return undefined as never;
|
||||||
|
});
|
||||||
|
|
||||||
|
const existingReleaseConfig = {
|
||||||
|
groups: {
|
||||||
|
group1: {
|
||||||
|
projects: ['something-else'],
|
||||||
|
},
|
||||||
|
group2: {
|
||||||
|
projects: ['other-thing'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
updateJson(tree, 'nx.json', (json) => {
|
||||||
|
json.release = existingReleaseConfig;
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
|
||||||
|
await libraryGenerator(tree, {
|
||||||
|
...defaultOptions,
|
||||||
|
name: 'my-lib',
|
||||||
|
publishable: true,
|
||||||
|
importPath: '@proj/my-lib',
|
||||||
|
bundler: 'tsc',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
|
});
|
||||||
|
|
||||||
|
const nxJson = readJson(tree, 'nx.json');
|
||||||
|
expect(nxJson.release).toEqual({
|
||||||
|
groups: existingReleaseConfig.groups,
|
||||||
|
version: {
|
||||||
|
preVersionCommand: `${
|
||||||
|
getPackageManagerCommand().dlx
|
||||||
|
} nx run-many -t build`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(outputSpy).toHaveBeenCalledWith({
|
||||||
|
title: `Could not find a release group that includes my-lib`,
|
||||||
|
bodyLines: [
|
||||||
|
`Ensure that my-lib is included in a release group's "projects" list in nx.json so it can be published with "nx release"`,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
outputSpy.mockRestore();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -5,10 +5,13 @@ import {
|
|||||||
formatFiles,
|
formatFiles,
|
||||||
generateFiles,
|
generateFiles,
|
||||||
GeneratorCallback,
|
GeneratorCallback,
|
||||||
|
getPackageManagerCommand,
|
||||||
joinPathFragments,
|
joinPathFragments,
|
||||||
names,
|
names,
|
||||||
offsetFromRoot,
|
offsetFromRoot,
|
||||||
|
output,
|
||||||
ProjectConfiguration,
|
ProjectConfiguration,
|
||||||
|
ProjectGraphProjectNode,
|
||||||
readNxJson,
|
readNxJson,
|
||||||
readProjectConfiguration,
|
readProjectConfiguration,
|
||||||
runTasksInSerial,
|
runTasksInSerial,
|
||||||
@ -22,15 +25,19 @@ import {
|
|||||||
type ProjectNameAndRootOptions,
|
type ProjectNameAndRootOptions,
|
||||||
} from '@nx/devkit/src/generators/project-name-and-root-utils';
|
} from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||||
|
|
||||||
|
import { addBuildTargetDefaults } from '@nx/devkit/src/generators/add-build-target-defaults';
|
||||||
|
import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command';
|
||||||
|
import { findMatchingProjects } from 'nx/src/utils/find-matching-projects';
|
||||||
|
import { type PackageJson } from 'nx/src/utils/package-json';
|
||||||
|
import { join } from 'path';
|
||||||
|
import { Bundler, LibraryGeneratorSchema } from '../../utils/schema';
|
||||||
|
import { addSwcConfig } from '../../utils/swc/add-swc-config';
|
||||||
|
import { addSwcDependencies } from '../../utils/swc/add-swc-dependencies';
|
||||||
|
import { tsConfigBaseOptions } from '../../utils/typescript/create-ts-config';
|
||||||
import {
|
import {
|
||||||
addTsConfigPath,
|
addTsConfigPath,
|
||||||
getRelativePathToRootTsConfig,
|
getRelativePathToRootTsConfig,
|
||||||
} from '../../utils/typescript/ts-config';
|
} from '../../utils/typescript/ts-config';
|
||||||
import { join } from 'path';
|
|
||||||
import { addMinimalPublishScript } from '../../utils/minimal-publish-script';
|
|
||||||
import { Bundler, LibraryGeneratorSchema } from '../../utils/schema';
|
|
||||||
import { addSwcConfig } from '../../utils/swc/add-swc-config';
|
|
||||||
import { addSwcDependencies } from '../../utils/swc/add-swc-dependencies';
|
|
||||||
import {
|
import {
|
||||||
esbuildVersion,
|
esbuildVersion,
|
||||||
nxVersion,
|
nxVersion,
|
||||||
@ -39,11 +46,9 @@ import {
|
|||||||
typesNodeVersion,
|
typesNodeVersion,
|
||||||
} from '../../utils/versions';
|
} from '../../utils/versions';
|
||||||
import jsInitGenerator from '../init/init';
|
import jsInitGenerator from '../init/init';
|
||||||
import { type PackageJson } from 'nx/src/utils/package-json';
|
|
||||||
import setupVerdaccio from '../setup-verdaccio/generator';
|
import setupVerdaccio from '../setup-verdaccio/generator';
|
||||||
import { tsConfigBaseOptions } from '../../utils/typescript/create-ts-config';
|
|
||||||
import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command';
|
const defaultOutputDirectory = 'dist';
|
||||||
import { addBuildTargetDefaults } from '@nx/devkit/src/generators/add-build-target-defaults';
|
|
||||||
|
|
||||||
export async function libraryGenerator(
|
export async function libraryGenerator(
|
||||||
tree: Tree,
|
tree: Tree,
|
||||||
@ -74,7 +79,7 @@ export async function libraryGeneratorInternal(
|
|||||||
|
|
||||||
createFiles(tree, options);
|
createFiles(tree, options);
|
||||||
|
|
||||||
addProject(tree, options);
|
await addProject(tree, options);
|
||||||
|
|
||||||
if (!options.skipPackageJson) {
|
if (!options.skipPackageJson) {
|
||||||
tasks.push(addProjectDependencies(tree, options));
|
tasks.push(addProjectDependencies(tree, options));
|
||||||
@ -166,6 +171,12 @@ export async function libraryGeneratorInternal(
|
|||||||
await formatFiles(tree);
|
await formatFiles(tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.publishable) {
|
||||||
|
tasks.push(() => {
|
||||||
|
logNxReleaseDocsInfo();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
tasks.push(() => {
|
tasks.push(() => {
|
||||||
logShowProjectCommand(options.name);
|
logShowProjectCommand(options.name);
|
||||||
});
|
});
|
||||||
@ -182,7 +193,7 @@ export interface NormalizedSchema extends LibraryGeneratorSchema {
|
|||||||
importPath?: string;
|
importPath?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
function addProject(tree: Tree, options: NormalizedSchema) {
|
async function addProject(tree: Tree, options: NormalizedSchema) {
|
||||||
const projectConfiguration: ProjectConfiguration = {
|
const projectConfiguration: ProjectConfiguration = {
|
||||||
root: options.projectRoot,
|
root: options.projectRoot,
|
||||||
sourceRoot: joinPathFragments(options.projectRoot, 'src'),
|
sourceRoot: joinPathFragments(options.projectRoot, 'src'),
|
||||||
@ -240,12 +251,27 @@ function addProject(tree: Tree, options: NormalizedSchema) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (options.publishable) {
|
if (options.publishable) {
|
||||||
const publishScriptPath = addMinimalPublishScript(tree);
|
const packageRoot = join(defaultOutputDirectory, '{projectRoot}');
|
||||||
|
|
||||||
projectConfiguration.targets.publish = {
|
projectConfiguration.targets ??= {};
|
||||||
command: `node ${publishScriptPath} ${options.name} {args.ver} {args.tag}`,
|
projectConfiguration.targets['nx-release-publish'] = {
|
||||||
dependsOn: ['build'],
|
options: {
|
||||||
|
packageRoot,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
projectConfiguration.release = {
|
||||||
|
version: {
|
||||||
|
generatorOptions: {
|
||||||
|
packageRoot,
|
||||||
|
// using git tags to determine the current version is required here because
|
||||||
|
// the version in the package root is overridden with every build
|
||||||
|
currentVersionResolver: 'git-tag',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
await addProjectToNxReleaseConfig(tree, options, projectConfiguration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -498,6 +524,9 @@ function createFiles(tree: Tree, options: NormalizedSchema) {
|
|||||||
if (json.private && (options.publishable || options.rootProject)) {
|
if (json.private && (options.publishable || options.rootProject)) {
|
||||||
delete json.private;
|
delete json.private;
|
||||||
}
|
}
|
||||||
|
if (!options.publishable && !options.rootProject) {
|
||||||
|
json.private = true;
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
...json,
|
...json,
|
||||||
dependencies: {
|
dependencies: {
|
||||||
@ -508,12 +537,16 @@ function createFiles(tree: Tree, options: NormalizedSchema) {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
writeJson<PackageJson>(tree, packageJsonPath, {
|
const packageJson: PackageJson = {
|
||||||
name: options.importPath,
|
name: options.importPath,
|
||||||
version: '0.0.1',
|
version: '0.0.1',
|
||||||
dependencies: determineDependencies(options),
|
dependencies: determineDependencies(options),
|
||||||
...determineEntryFields(options),
|
...determineEntryFields(options),
|
||||||
});
|
};
|
||||||
|
if (!options.publishable && !options.rootProject) {
|
||||||
|
packageJson.private = true;
|
||||||
|
}
|
||||||
|
writeJson<PackageJson>(tree, packageJsonPath, packageJson);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.config === 'npm-scripts') {
|
if (options.config === 'npm-scripts') {
|
||||||
@ -633,7 +666,7 @@ async function normalizeOptions(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is to preserve old behaviour, buildable: false
|
// This is to preserve old behavior, buildable: false
|
||||||
if (options.publishable === false && options.buildable === false) {
|
if (options.publishable === false && options.buildable === false) {
|
||||||
options.bundler = 'none';
|
options.bundler = 'none';
|
||||||
}
|
}
|
||||||
@ -761,7 +794,7 @@ function getBuildExecutor(bundler: Bundler) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getOutputPath(options: NormalizedSchema) {
|
function getOutputPath(options: NormalizedSchema) {
|
||||||
const parts = ['dist'];
|
const parts = [defaultOutputDirectory];
|
||||||
if (options.projectRoot === '.') {
|
if (options.projectRoot === '.') {
|
||||||
parts.push(options.name);
|
parts.push(options.name);
|
||||||
} else {
|
} else {
|
||||||
@ -866,4 +899,118 @@ function determineEntryFields(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function projectsConfigMatchesProject(
|
||||||
|
projectsConfig: string | string[] | undefined,
|
||||||
|
project: ProjectGraphProjectNode
|
||||||
|
): boolean {
|
||||||
|
if (!projectsConfig) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof projectsConfig === 'string') {
|
||||||
|
projectsConfig = [projectsConfig];
|
||||||
|
}
|
||||||
|
|
||||||
|
const graph: Record<string, ProjectGraphProjectNode> = {
|
||||||
|
[project.name]: project,
|
||||||
|
};
|
||||||
|
|
||||||
|
const matchingProjects = findMatchingProjects(projectsConfig, graph);
|
||||||
|
|
||||||
|
return matchingProjects.includes(project.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function addProjectToNxReleaseConfig(
|
||||||
|
tree: Tree,
|
||||||
|
options: NormalizedSchema,
|
||||||
|
projectConfiguration: ProjectConfiguration
|
||||||
|
) {
|
||||||
|
const nxJson = readNxJson(tree);
|
||||||
|
|
||||||
|
const addPreVersionCommand = () => {
|
||||||
|
const pmc = getPackageManagerCommand();
|
||||||
|
|
||||||
|
nxJson.release = {
|
||||||
|
...nxJson.release,
|
||||||
|
version: {
|
||||||
|
preVersionCommand: `${pmc.dlx} nx run-many -t build`,
|
||||||
|
...nxJson.release?.version,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!nxJson.release || (!nxJson.release.projects && !nxJson.release.groups)) {
|
||||||
|
// skip adding any projects configuration since the new project should be
|
||||||
|
// automatically included by nx release's default project detection logic
|
||||||
|
addPreVersionCommand();
|
||||||
|
writeJson(tree, 'nx.json', nxJson);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const project: ProjectGraphProjectNode = {
|
||||||
|
name: options.name,
|
||||||
|
type: 'lib' as const,
|
||||||
|
data: {
|
||||||
|
root: projectConfiguration.root,
|
||||||
|
tags: projectConfiguration.tags,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (projectsConfigMatchesProject(nxJson.release.projects, project)) {
|
||||||
|
output.log({
|
||||||
|
title: `Project already included in existing release configuration`,
|
||||||
|
});
|
||||||
|
addPreVersionCommand();
|
||||||
|
writeJson(tree, 'nx.json', nxJson);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(nxJson.release.projects)) {
|
||||||
|
nxJson.release.projects.push(options.name);
|
||||||
|
addPreVersionCommand();
|
||||||
|
writeJson(tree, 'nx.json', nxJson);
|
||||||
|
output.log({
|
||||||
|
title: `Added project to existing release configuration`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nxJson.release.groups) {
|
||||||
|
const allGroups = Object.entries(nxJson.release.groups);
|
||||||
|
|
||||||
|
for (const [name, group] of allGroups) {
|
||||||
|
if (projectsConfigMatchesProject(group.projects, project)) {
|
||||||
|
addPreVersionCommand();
|
||||||
|
writeJson(tree, 'nx.json', nxJson);
|
||||||
|
return `Project already included in existing release configuration for group ${name}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
output.warn({
|
||||||
|
title: `Could not find a release group that includes ${options.name}`,
|
||||||
|
bodyLines: [
|
||||||
|
`Ensure that ${options.name} is included in a release group's "projects" list in nx.json so it can be published with "nx release"`,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
addPreVersionCommand();
|
||||||
|
writeJson(tree, 'nx.json', nxJson);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof nxJson.release.projects === 'string') {
|
||||||
|
nxJson.release.projects = [nxJson.release.projects, options.name];
|
||||||
|
addPreVersionCommand();
|
||||||
|
writeJson(tree, 'nx.json', nxJson);
|
||||||
|
output.log({
|
||||||
|
title: `Added project to existing release configuration`,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function logNxReleaseDocsInfo() {
|
||||||
|
output.log({
|
||||||
|
title: `📦 To learn how to publish this library, see https://nx.dev/core-features/manage-releases.`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export default libraryGenerator;
|
export default libraryGenerator;
|
||||||
|
|||||||
@ -89,7 +89,7 @@
|
|||||||
"publishable": {
|
"publishable": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false,
|
"default": false,
|
||||||
"description": "Generate a publishable library.",
|
"description": "Configure the library ready for use with `nx release` (https://nx.dev/core-features/manage-releases).",
|
||||||
"x-priority": "important"
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"importPath": {
|
"importPath": {
|
||||||
|
|||||||
@ -49,6 +49,18 @@
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"description": "Additional metadata to pass to the current version resolver.",
|
"description": "Additional metadata to pass to the current version resolver.",
|
||||||
"default": {}
|
"default": {}
|
||||||
|
},
|
||||||
|
"skipLockFileUpdate": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Whether to skip updating the lock file after updating the version."
|
||||||
|
},
|
||||||
|
"installArgs": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Additional arguments to pass to the package manager when updating the lock file with an install command."
|
||||||
|
},
|
||||||
|
"installIgnoreScripts": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Whether to ignore install lifecycle scripts when updating the lock file with an install command."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": ["projects", "projectGraph", "releaseGroup"]
|
"required": ["projects", "projectGraph", "releaseGroup"]
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { ProjectConfiguration, readJson, type Tree } from '@nx/devkit';
|
import { output, ProjectConfiguration, readJson, type Tree } from '@nx/devkit';
|
||||||
|
|
||||||
const startLocalRegistryScript = (localRegistryTarget: string) => `
|
const startLocalRegistryScript = (localRegistryTarget: string) => `
|
||||||
/**
|
/**
|
||||||
@ -7,6 +7,7 @@ const startLocalRegistryScript = (localRegistryTarget: string) => `
|
|||||||
*/
|
*/
|
||||||
import { startLocalRegistry } from '@nx/js/plugins/jest/local-registry';
|
import { startLocalRegistry } from '@nx/js/plugins/jest/local-registry';
|
||||||
import { execFileSync } from 'child_process';
|
import { execFileSync } from 'child_process';
|
||||||
|
import { releasePublish, releaseVersion } from 'nx/release';
|
||||||
|
|
||||||
export default async () => {
|
export default async () => {
|
||||||
// local registry target to run
|
// local registry target to run
|
||||||
@ -19,12 +20,21 @@ export default async () => {
|
|||||||
storage,
|
storage,
|
||||||
verbose: false,
|
verbose: false,
|
||||||
});
|
});
|
||||||
const nx = require.resolve('nx');
|
|
||||||
execFileSync(
|
await releaseVersion({
|
||||||
nx,
|
specifier: '0.0.0-e2e',
|
||||||
['run-many', '--targets', 'publish', '--ver', '0.0.0-e2e', '--tag', 'e2e'],
|
stageChanges: false,
|
||||||
{ env: process.env, stdio: 'inherit' }
|
gitCommit: false,
|
||||||
);
|
gitTag: false,
|
||||||
|
firstRelease: true,
|
||||||
|
generatorOptionsOverrides: {
|
||||||
|
skipLockFileUpdate: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
await releasePublish({
|
||||||
|
tag: 'e2e',
|
||||||
|
firstRelease: true
|
||||||
|
});
|
||||||
};
|
};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@ -49,12 +59,23 @@ export function addLocalRegistryScripts(tree: Tree) {
|
|||||||
tree,
|
tree,
|
||||||
'project.json'
|
'project.json'
|
||||||
);
|
);
|
||||||
|
|
||||||
const localRegistryTarget = `${projectConfiguration.name}:local-registry`;
|
const localRegistryTarget = `${projectConfiguration.name}:local-registry`;
|
||||||
if (!tree.exists(startLocalRegistryPath)) {
|
if (!tree.exists(startLocalRegistryPath)) {
|
||||||
tree.write(
|
tree.write(
|
||||||
startLocalRegistryPath,
|
startLocalRegistryPath,
|
||||||
startLocalRegistryScript(localRegistryTarget)
|
startLocalRegistryScript(localRegistryTarget)
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
const existingStartLocalRegistryScript = tree
|
||||||
|
.read(startLocalRegistryPath)
|
||||||
|
.toString();
|
||||||
|
if (!existingStartLocalRegistryScript.includes('nx/release')) {
|
||||||
|
output.warn({
|
||||||
|
title:
|
||||||
|
'Your `start-local-registry.ts` script may be outdated. To ensure that newly generated packages are published appropriately when running end to end tests, update this script to use Nx Release. See https://nx.dev/recipes/nx-release/update-local-registry-setup for details.',
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!tree.exists(stopLocalRegistryPath)) {
|
if (!tree.exists(stopLocalRegistryPath)) {
|
||||||
tree.write(stopLocalRegistryPath, stopLocalRegistryScript);
|
tree.write(stopLocalRegistryPath, stopLocalRegistryScript);
|
||||||
|
|||||||
@ -1,75 +0,0 @@
|
|||||||
import type { Tree } from '@nx/devkit';
|
|
||||||
|
|
||||||
const publishScriptContent = `
|
|
||||||
/**
|
|
||||||
* This is a minimal script to publish your package to "npm".
|
|
||||||
* This is meant to be used as-is or customize as you see fit.
|
|
||||||
*
|
|
||||||
* This script is executed on "dist/path/to/library" as "cwd" by default.
|
|
||||||
*
|
|
||||||
* You might need to authenticate with NPM before running this script.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { execSync } from 'child_process';
|
|
||||||
import { readFileSync, writeFileSync } from 'fs';
|
|
||||||
|
|
||||||
import devkit from '@nx/devkit';
|
|
||||||
const { readCachedProjectGraph } = devkit;
|
|
||||||
|
|
||||||
function invariant(condition, message) {
|
|
||||||
if (!condition) {
|
|
||||||
console.error(message);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Executing publish script: node path/to/publish.mjs {name} --version {version} --tag {tag}
|
|
||||||
// Default "tag" to "next" so we won't publish the "latest" tag by accident.
|
|
||||||
const [, , name, version, tag = 'next'] = process.argv;
|
|
||||||
|
|
||||||
// A simple SemVer validation to validate the version
|
|
||||||
const validVersion = /^\\d+\\.\\d+\\.\\d+(-\\w+\\.\\d+)?/;
|
|
||||||
invariant(
|
|
||||||
version && validVersion.test(version),
|
|
||||||
\`No version provided or version did not match Semantic Versioning, expected: #.#.#-tag.# or #.#.#, got \${version}.\`
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
const graph = readCachedProjectGraph();
|
|
||||||
const project = graph.nodes[name];
|
|
||||||
|
|
||||||
invariant(
|
|
||||||
project,
|
|
||||||
\`Could not find project "\${name}" in the workspace. Is the project.json configured correctly?\`
|
|
||||||
);
|
|
||||||
|
|
||||||
const outputPath = project.data?.targets?.build?.options?.outputPath;
|
|
||||||
invariant(
|
|
||||||
outputPath,
|
|
||||||
\`Could not find "build.options.outputPath" of project "\${name}". Is project.json configured correctly?\`
|
|
||||||
);
|
|
||||||
|
|
||||||
process.chdir(outputPath);
|
|
||||||
|
|
||||||
// Updating the version in "package.json" before publishing
|
|
||||||
try {
|
|
||||||
const json = JSON.parse(readFileSync(\`package.json\`).toString());
|
|
||||||
json.version = version;
|
|
||||||
writeFileSync(\`package.json\`, JSON.stringify(json, null, 2));
|
|
||||||
} catch (e) {
|
|
||||||
console.error(\`Error reading package.json file from library build output.\`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Execute "npm publish" to publish
|
|
||||||
execSync(\`npm publish --access public --tag \${tag}\`);
|
|
||||||
`;
|
|
||||||
|
|
||||||
export function addMinimalPublishScript(tree: Tree) {
|
|
||||||
const publishScriptPath = 'tools/scripts/publish.mjs';
|
|
||||||
|
|
||||||
if (!tree.exists(publishScriptPath)) {
|
|
||||||
tree.write(publishScriptPath, publishScriptContent);
|
|
||||||
}
|
|
||||||
|
|
||||||
return publishScriptPath;
|
|
||||||
}
|
|
||||||
@ -157,11 +157,16 @@
|
|||||||
"$ref": "#/definitions/NxReleaseVersionConfiguration"
|
"$ref": "#/definitions/NxReleaseVersionConfiguration"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"anyOf": [
|
"allOf": [
|
||||||
{
|
{
|
||||||
"not": {
|
"not": {
|
||||||
"required": ["git"]
|
"required": ["git"]
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"not": {
|
||||||
|
"required": ["preVersionCommand"]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -576,6 +581,10 @@
|
|||||||
},
|
},
|
||||||
"git": {
|
"git": {
|
||||||
"$ref": "#/definitions/NxReleaseGitConfiguration"
|
"$ref": "#/definitions/NxReleaseGitConfiguration"
|
||||||
|
},
|
||||||
|
"preVersionCommand": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "A command to run after validation of nx release configuration, but before versioning begins. Used for preparing build artifacts. If --dry-run is passed, the command is still executed, but with the NX_DRY_RUN environment variable set to 'true'."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -127,6 +127,26 @@
|
|||||||
"items": {
|
"items": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"release": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "Configuration for the nx release commands.",
|
||||||
|
"properties": {
|
||||||
|
"version": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "Configuration for the nx release version command.",
|
||||||
|
"properties": {
|
||||||
|
"generator": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The version generator to use. Defaults to @nx/js:release-version."
|
||||||
|
},
|
||||||
|
"generatorOptions": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "Options for the version generator."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"definitions": {
|
"definitions": {
|
||||||
|
|||||||
@ -14,6 +14,7 @@ import {
|
|||||||
} from '../../config/project-graph';
|
} from '../../config/project-graph';
|
||||||
import { FsTree, Tree } from '../../generators/tree';
|
import { FsTree, Tree } from '../../generators/tree';
|
||||||
import { registerTsProject } from '../../plugins/js/utils/register';
|
import { registerTsProject } from '../../plugins/js/utils/register';
|
||||||
|
import { createProjectFileMapUsingProjectGraph } from '../../project-graph/file-map-utils';
|
||||||
import { createProjectGraphAsync } from '../../project-graph/project-graph';
|
import { createProjectGraphAsync } from '../../project-graph/project-graph';
|
||||||
import { interpolate } from '../../tasks-runner/utils';
|
import { interpolate } from '../../tasks-runner/utils';
|
||||||
import { isCI } from '../../utils/is-ci';
|
import { isCI } from '../../utils/is-ci';
|
||||||
@ -94,6 +95,7 @@ export async function releaseChangelog(
|
|||||||
// Apply default configuration to any optional user configuration
|
// Apply default configuration to any optional user configuration
|
||||||
const { error: configError, nxReleaseConfig } = await createNxReleaseConfig(
|
const { error: configError, nxReleaseConfig } = await createNxReleaseConfig(
|
||||||
projectGraph,
|
projectGraph,
|
||||||
|
await createProjectFileMapUsingProjectGraph(projectGraph),
|
||||||
nxJson.release
|
nxJson.release
|
||||||
);
|
);
|
||||||
if (configError) {
|
if (configError) {
|
||||||
|
|||||||
@ -34,6 +34,7 @@ export type VersionOptions = NxReleaseArgs &
|
|||||||
specifier?: string;
|
specifier?: string;
|
||||||
preid?: string;
|
preid?: string;
|
||||||
stageChanges?: boolean;
|
stageChanges?: boolean;
|
||||||
|
generatorOptionsOverrides?: Record<string, unknown>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ChangelogOptions = NxReleaseArgs &
|
export type ChangelogOptions = NxReleaseArgs &
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -11,9 +11,14 @@
|
|||||||
* defaults and user overrides, as well as handling common errors, up front to produce a single, consistent,
|
* defaults and user overrides, as well as handling common errors, up front to produce a single, consistent,
|
||||||
* and easy to consume config object for all the `nx release` command implementations.
|
* and easy to consume config object for all the `nx release` command implementations.
|
||||||
*/
|
*/
|
||||||
|
import { join } from 'path';
|
||||||
import { NxJsonConfiguration } from '../../../config/nx-json';
|
import { NxJsonConfiguration } from '../../../config/nx-json';
|
||||||
import { output, type ProjectGraph } from '../../../devkit-exports';
|
import { ProjectFileMap, ProjectGraph } from '../../../config/project-graph';
|
||||||
|
import { readJsonFile } from '../../../utils/fileutils';
|
||||||
import { findMatchingProjects } from '../../../utils/find-matching-projects';
|
import { findMatchingProjects } from '../../../utils/find-matching-projects';
|
||||||
|
import { output } from '../../../utils/output';
|
||||||
|
import { PackageJson } from '../../../utils/package-json';
|
||||||
|
import { workspaceRoot } from '../../../utils/workspace-root';
|
||||||
import { resolveNxJsonConfigErrorMessage } from '../utils/resolve-nx-json-error-message';
|
import { resolveNxJsonConfigErrorMessage } from '../utils/resolve-nx-json-error-message';
|
||||||
|
|
||||||
type DeepRequired<T> = Required<{
|
type DeepRequired<T> = Required<{
|
||||||
@ -80,6 +85,7 @@ export interface CreateNxReleaseConfigError {
|
|||||||
// Apply default configuration to any optional user configuration and handle known errors
|
// Apply default configuration to any optional user configuration and handle known errors
|
||||||
export async function createNxReleaseConfig(
|
export async function createNxReleaseConfig(
|
||||||
projectGraph: ProjectGraph,
|
projectGraph: ProjectGraph,
|
||||||
|
projectFileMap: ProjectFileMap,
|
||||||
userConfig: NxJsonConfiguration['release'] = {}
|
userConfig: NxJsonConfiguration['release'] = {}
|
||||||
): Promise<{
|
): Promise<{
|
||||||
error: null | CreateNxReleaseConfigError;
|
error: null | CreateNxReleaseConfigError;
|
||||||
@ -163,6 +169,7 @@ export async function createNxReleaseConfig(
|
|||||||
conventionalCommits: userConfig.version?.conventionalCommits || false,
|
conventionalCommits: userConfig.version?.conventionalCommits || false,
|
||||||
generator: '@nx/js:release-version',
|
generator: '@nx/js:release-version',
|
||||||
generatorOptions: defaultGeneratorOptions,
|
generatorOptions: defaultGeneratorOptions,
|
||||||
|
preVersionCommand: userConfig.version?.preVersionCommand || '',
|
||||||
},
|
},
|
||||||
changelog: {
|
changelog: {
|
||||||
git: changelogGitDefaults,
|
git: changelogGitDefaults,
|
||||||
@ -279,21 +286,23 @@ export async function createNxReleaseConfig(
|
|||||||
>
|
>
|
||||||
);
|
);
|
||||||
|
|
||||||
// git configuration is not supported at the group level, only the root/command level
|
// these options are not supported at the group level, only the root/command level
|
||||||
const rootVersionWithoutGit = { ...rootVersionConfig };
|
const rootVersionWithoutGlobalOptions = { ...rootVersionConfig };
|
||||||
delete rootVersionWithoutGit.git;
|
delete rootVersionWithoutGlobalOptions.git;
|
||||||
|
delete rootVersionWithoutGlobalOptions.preVersionCommand;
|
||||||
|
|
||||||
// Apply conventionalCommits shorthand to the final group defaults if explicitly configured in the original user config
|
// Apply conventionalCommits shorthand to the final group defaults if explicitly configured in the original user config
|
||||||
if (userConfig.version?.conventionalCommits === true) {
|
if (userConfig.version?.conventionalCommits === true) {
|
||||||
rootVersionWithoutGit.generatorOptions = {
|
rootVersionWithoutGlobalOptions.generatorOptions = {
|
||||||
...rootVersionWithoutGit.generatorOptions,
|
...rootVersionWithoutGlobalOptions.generatorOptions,
|
||||||
currentVersionResolver: 'git-tag',
|
currentVersionResolver: 'git-tag',
|
||||||
specifierSource: 'conventional-commits',
|
specifierSource: 'conventional-commits',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (userConfig.version?.conventionalCommits === false) {
|
if (userConfig.version?.conventionalCommits === false) {
|
||||||
delete rootVersionWithoutGit.generatorOptions.currentVersionResolver;
|
delete rootVersionWithoutGlobalOptions.generatorOptions
|
||||||
delete rootVersionWithoutGit.generatorOptions.specifierSource;
|
.currentVersionResolver;
|
||||||
|
delete rootVersionWithoutGlobalOptions.generatorOptions.specifierSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
const groups: NxReleaseConfig['groups'] =
|
const groups: NxReleaseConfig['groups'] =
|
||||||
@ -312,10 +321,8 @@ export async function createNxReleaseConfig(
|
|||||||
ensureArray(userConfig.projects),
|
ensureArray(userConfig.projects),
|
||||||
projectGraph.nodes
|
projectGraph.nodes
|
||||||
)
|
)
|
||||||
: // default to all library projects in the workspace
|
: await getDefaultProjects(projectGraph, projectFileMap),
|
||||||
findMatchingProjects(['*'], projectGraph.nodes).filter(
|
|
||||||
(project) => projectGraph.nodes[project].type === 'lib'
|
|
||||||
),
|
|
||||||
/**
|
/**
|
||||||
* For properties which are overriding config at the root, we use the root level config as the
|
* For properties which are overriding config at the root, we use the root level config as the
|
||||||
* default values to merge with so that the group that matches a specific project will always
|
* default values to merge with so that the group that matches a specific project will always
|
||||||
@ -323,7 +330,7 @@ export async function createNxReleaseConfig(
|
|||||||
*/
|
*/
|
||||||
version: deepMergeDefaults(
|
version: deepMergeDefaults(
|
||||||
[GROUP_DEFAULTS.version],
|
[GROUP_DEFAULTS.version],
|
||||||
rootVersionWithoutGit
|
rootVersionWithoutGlobalOptions
|
||||||
),
|
),
|
||||||
// If the user has set something custom for releaseTagPattern at the top level, respect it for the implicit default group
|
// If the user has set something custom for releaseTagPattern at the top level, respect it for the implicit default group
|
||||||
releaseTagPattern:
|
releaseTagPattern:
|
||||||
@ -409,7 +416,7 @@ export async function createNxReleaseConfig(
|
|||||||
projects: matchingProjects,
|
projects: matchingProjects,
|
||||||
version: deepMergeDefaults(
|
version: deepMergeDefaults(
|
||||||
// First apply any group level defaults, then apply actual root level config, then group level config
|
// First apply any group level defaults, then apply actual root level config, then group level config
|
||||||
[GROUP_DEFAULTS.version, rootVersionWithoutGit],
|
[GROUP_DEFAULTS.version, rootVersionWithoutGlobalOptions],
|
||||||
releaseGroup.version
|
releaseGroup.version
|
||||||
),
|
),
|
||||||
// If the user has set any changelog config at all, including at the root level, then use one set of defaults, otherwise default to false for the whole feature
|
// If the user has set any changelog config at all, including at the root level, then use one set of defaults, otherwise default to false for the whole feature
|
||||||
@ -694,3 +701,41 @@ function hasInvalidGitConfig(
|
|||||||
!!userConfig.git && !!(userConfig.version?.git || userConfig.changelog?.git)
|
!!userConfig.git && !!(userConfig.version?.git || userConfig.changelog?.git)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function getDefaultProjects(
|
||||||
|
projectGraph: ProjectGraph,
|
||||||
|
projectFileMap: ProjectFileMap
|
||||||
|
): Promise<string[]> {
|
||||||
|
// default to all library projects in the workspace with a package.json file
|
||||||
|
return findMatchingProjects(['*'], projectGraph.nodes).filter(
|
||||||
|
(project) =>
|
||||||
|
projectGraph.nodes[project].type === 'lib' &&
|
||||||
|
// Exclude all projects with "private": true in their package.json because this is
|
||||||
|
// a common indicator that a project is not intended for release.
|
||||||
|
// Users can override this behavior by explicitly defining the projects they want to release.
|
||||||
|
isProjectPublic(project, projectGraph, projectFileMap)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isProjectPublic(
|
||||||
|
project: string,
|
||||||
|
projectGraph: ProjectGraph,
|
||||||
|
projectFileMap: ProjectFileMap
|
||||||
|
): boolean {
|
||||||
|
const projectNode = projectGraph.nodes[project];
|
||||||
|
const packageJsonPath = join(projectNode.data.root, 'package.json');
|
||||||
|
|
||||||
|
if (!projectFileMap[project]?.find((f) => f.file === packageJsonPath)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const fullPackageJsonPath = join(workspaceRoot, packageJsonPath);
|
||||||
|
const packageJson = readJsonFile<PackageJson>(fullPackageJsonPath);
|
||||||
|
return !(packageJson.private === true);
|
||||||
|
} catch (e) {
|
||||||
|
// do nothing and assume that the project is not public if there is a parsing issue
|
||||||
|
// this will result in it being excluded from the default projects list
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -37,6 +37,7 @@ describe('filterReleaseGroups()', () => {
|
|||||||
tagMessage: '',
|
tagMessage: '',
|
||||||
tagArgs: '',
|
tagArgs: '',
|
||||||
},
|
},
|
||||||
|
preVersionCommand: '',
|
||||||
},
|
},
|
||||||
releaseTagPattern: '',
|
releaseTagPattern: '',
|
||||||
git: {
|
git: {
|
||||||
|
|||||||
@ -3,13 +3,14 @@ import {
|
|||||||
ProjectGraph,
|
ProjectGraph,
|
||||||
ProjectGraphProjectNode,
|
ProjectGraphProjectNode,
|
||||||
} from '../../config/project-graph';
|
} from '../../config/project-graph';
|
||||||
import { output } from '../../devkit-exports';
|
import { createProjectFileMapUsingProjectGraph } from '../../project-graph/file-map-utils';
|
||||||
import { createProjectGraphAsync } from '../../project-graph/project-graph';
|
import { createProjectGraphAsync } from '../../project-graph/project-graph';
|
||||||
import { runCommand } from '../../tasks-runner/run-command';
|
import { runCommand } from '../../tasks-runner/run-command';
|
||||||
import {
|
import {
|
||||||
createOverrides,
|
createOverrides,
|
||||||
readGraphFileFromGraphArg,
|
readGraphFileFromGraphArg,
|
||||||
} from '../../utils/command-line-utils';
|
} from '../../utils/command-line-utils';
|
||||||
|
import { output } from '../../utils/output';
|
||||||
import { handleErrors } from '../../utils/params';
|
import { handleErrors } from '../../utils/params';
|
||||||
import { projectHasTarget } from '../../utils/project-graph-utils';
|
import { projectHasTarget } from '../../utils/project-graph-utils';
|
||||||
import { generateGraph } from '../graph/graph';
|
import { generateGraph } from '../graph/graph';
|
||||||
@ -51,6 +52,7 @@ export async function releasePublish(
|
|||||||
// Apply default configuration to any optional user configuration
|
// Apply default configuration to any optional user configuration
|
||||||
const { error: configError, nxReleaseConfig } = await createNxReleaseConfig(
|
const { error: configError, nxReleaseConfig } = await createNxReleaseConfig(
|
||||||
projectGraph,
|
projectGraph,
|
||||||
|
await createProjectFileMapUsingProjectGraph(projectGraph),
|
||||||
nxJson.release
|
nxJson.release
|
||||||
);
|
);
|
||||||
if (configError) {
|
if (configError) {
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
import { prompt } from 'enquirer';
|
import { prompt } from 'enquirer';
|
||||||
import { readNxJson } from '../../config/nx-json';
|
import { readNxJson } from '../../config/nx-json';
|
||||||
import { output } from '../../devkit-exports';
|
import { createProjectFileMapUsingProjectGraph } from '../../project-graph/file-map-utils';
|
||||||
import { createProjectGraphAsync } from '../../project-graph/project-graph';
|
import { createProjectGraphAsync } from '../../project-graph/project-graph';
|
||||||
|
import { output } from '../../utils/output';
|
||||||
import { handleErrors } from '../../utils/params';
|
import { handleErrors } from '../../utils/params';
|
||||||
import { releaseChangelog, shouldCreateGitHubRelease } from './changelog';
|
import { releaseChangelog, shouldCreateGitHubRelease } from './changelog';
|
||||||
import { ReleaseOptions, VersionOptions } from './command-object';
|
import { ReleaseOptions, VersionOptions } from './command-object';
|
||||||
@ -55,6 +56,7 @@ export async function release(
|
|||||||
// Apply default configuration to any optional user configuration
|
// Apply default configuration to any optional user configuration
|
||||||
const { error: configError, nxReleaseConfig } = await createNxReleaseConfig(
|
const { error: configError, nxReleaseConfig } = await createNxReleaseConfig(
|
||||||
projectGraph,
|
projectGraph,
|
||||||
|
await createProjectFileMapUsingProjectGraph(projectGraph),
|
||||||
nxJson.release
|
nxJson.release
|
||||||
);
|
);
|
||||||
if (configError) {
|
if (configError) {
|
||||||
|
|||||||
@ -151,7 +151,29 @@ export async function gitAdd({
|
|||||||
logFn?: (...messages: string[]) => void;
|
logFn?: (...messages: string[]) => void;
|
||||||
}): Promise<string> {
|
}): Promise<string> {
|
||||||
logFn = logFn || console.log;
|
logFn = logFn || console.log;
|
||||||
const commandArgs = ['add', ...changedFiles];
|
|
||||||
|
let ignoredFiles: string[] = [];
|
||||||
|
let filesToAdd: string[] = [];
|
||||||
|
for (const f of changedFiles) {
|
||||||
|
const isFileIgnored = await isIgnored(f);
|
||||||
|
if (isFileIgnored) {
|
||||||
|
ignoredFiles.push(f);
|
||||||
|
} else {
|
||||||
|
filesToAdd.push(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verbose && ignoredFiles.length) {
|
||||||
|
logFn(`Will not add the following files because they are ignored by git:`);
|
||||||
|
ignoredFiles.forEach((f) => logFn(f));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!filesToAdd.length) {
|
||||||
|
logFn('\nNo files to stage. Skipping git add.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const commandArgs = ['add', ...filesToAdd];
|
||||||
const message = dryRun
|
const message = dryRun
|
||||||
? `Would stage files in git with the following command, but --dry-run was set:`
|
? `Would stage files in git with the following command, but --dry-run was set:`
|
||||||
: `Staging files in git with the following command:`;
|
: `Staging files in git with the following command:`;
|
||||||
@ -165,6 +187,16 @@ export async function gitAdd({
|
|||||||
return execCommand('git', commandArgs);
|
return execCommand('git', commandArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function isIgnored(filePath: string): Promise<boolean> {
|
||||||
|
try {
|
||||||
|
// This command will error if the file is not ignored
|
||||||
|
await execCommand('git', ['check-ignore', filePath]);
|
||||||
|
return true;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export async function gitCommit({
|
export async function gitCommit({
|
||||||
messages,
|
messages,
|
||||||
additionalArgs,
|
additionalArgs,
|
||||||
|
|||||||
@ -1,24 +1,23 @@
|
|||||||
import * as chalk from 'chalk';
|
import * as chalk from 'chalk';
|
||||||
|
import { execSync } from 'node:child_process';
|
||||||
import { readFileSync } from 'node:fs';
|
import { readFileSync } from 'node:fs';
|
||||||
import { relative } from 'node:path';
|
import { relative } from 'node:path';
|
||||||
import { Generator } from '../../config/misc-interfaces';
|
import { Generator } from '../../config/misc-interfaces';
|
||||||
import { readNxJson } from '../../config/nx-json';
|
import { NxJsonConfiguration, readNxJson } from '../../config/nx-json';
|
||||||
import {
|
import {
|
||||||
ProjectGraph,
|
ProjectGraph,
|
||||||
ProjectGraphProjectNode,
|
ProjectGraphProjectNode,
|
||||||
} from '../../config/project-graph';
|
} from '../../config/project-graph';
|
||||||
import {
|
|
||||||
NxJsonConfiguration,
|
|
||||||
joinPathFragments,
|
|
||||||
output,
|
|
||||||
workspaceRoot,
|
|
||||||
} from '../../devkit-exports';
|
|
||||||
import { FsTree, Tree, flushChanges } from '../../generators/tree';
|
import { FsTree, Tree, flushChanges } from '../../generators/tree';
|
||||||
|
import { createProjectFileMapUsingProjectGraph } from '../../project-graph/file-map-utils';
|
||||||
import {
|
import {
|
||||||
createProjectGraphAsync,
|
createProjectGraphAsync,
|
||||||
readProjectsConfigurationFromProjectGraph,
|
readProjectsConfigurationFromProjectGraph,
|
||||||
} from '../../project-graph/project-graph';
|
} from '../../project-graph/project-graph';
|
||||||
|
import { output } from '../../utils/output';
|
||||||
import { combineOptionsForGenerator, handleErrors } from '../../utils/params';
|
import { combineOptionsForGenerator, handleErrors } from '../../utils/params';
|
||||||
|
import { joinPathFragments } from '../../utils/path';
|
||||||
|
import { workspaceRoot } from '../../utils/workspace-root';
|
||||||
import { parseGeneratorString } from '../generate/generate';
|
import { parseGeneratorString } from '../generate/generate';
|
||||||
import { getGeneratorInformation } from '../generate/generator-utils';
|
import { getGeneratorInformation } from '../generate/generator-utils';
|
||||||
import { VersionOptions } from './command-object';
|
import { VersionOptions } from './command-object';
|
||||||
@ -43,6 +42,8 @@ import {
|
|||||||
handleDuplicateGitTags,
|
handleDuplicateGitTags,
|
||||||
} from './utils/shared';
|
} from './utils/shared';
|
||||||
|
|
||||||
|
const LARGE_BUFFER = 1024 * 1000000;
|
||||||
|
|
||||||
// Reexport some utils for use in plugin release-version generator implementations
|
// Reexport some utils for use in plugin release-version generator implementations
|
||||||
export { deriveNewSemverVersion } from './utils/semver';
|
export { deriveNewSemverVersion } from './utils/semver';
|
||||||
export type {
|
export type {
|
||||||
@ -67,6 +68,9 @@ export interface ReleaseVersionGeneratorSchema {
|
|||||||
firstRelease?: boolean;
|
firstRelease?: boolean;
|
||||||
// auto means the existing prefix will be preserved, and is the default behavior
|
// auto means the existing prefix will be preserved, and is the default behavior
|
||||||
versionPrefix?: typeof validReleaseVersionPrefixes[number];
|
versionPrefix?: typeof validReleaseVersionPrefixes[number];
|
||||||
|
skipLockFileUpdate?: boolean;
|
||||||
|
installArgs?: string;
|
||||||
|
installIgnoreScripts?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NxReleaseVersionResult {
|
export interface NxReleaseVersionResult {
|
||||||
@ -106,6 +110,7 @@ export async function releaseVersion(
|
|||||||
// Apply default configuration to any optional user configuration
|
// Apply default configuration to any optional user configuration
|
||||||
const { error: configError, nxReleaseConfig } = await createNxReleaseConfig(
|
const { error: configError, nxReleaseConfig } = await createNxReleaseConfig(
|
||||||
projectGraph,
|
projectGraph,
|
||||||
|
await createProjectFileMapUsingProjectGraph(projectGraph),
|
||||||
nxJson.release
|
nxJson.release
|
||||||
);
|
);
|
||||||
if (configError) {
|
if (configError) {
|
||||||
@ -148,6 +153,11 @@ export async function releaseVersion(
|
|||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
runPreVersionCommand(nxReleaseConfig.version.preVersionCommand, {
|
||||||
|
dryRun: args.dryRun,
|
||||||
|
verbose: args.verbose,
|
||||||
|
});
|
||||||
|
|
||||||
const tree = new FsTree(workspaceRoot, args.verbose);
|
const tree = new FsTree(workspaceRoot, args.verbose);
|
||||||
|
|
||||||
const versionData: VersionData = {};
|
const versionData: VersionData = {};
|
||||||
@ -197,6 +207,7 @@ export async function releaseVersion(
|
|||||||
args,
|
args,
|
||||||
tree,
|
tree,
|
||||||
generatorData,
|
generatorData,
|
||||||
|
args.generatorOptionsOverrides,
|
||||||
projectNames,
|
projectNames,
|
||||||
releaseGroup,
|
releaseGroup,
|
||||||
versionData
|
versionData
|
||||||
@ -206,7 +217,10 @@ export async function releaseVersion(
|
|||||||
const changedFiles = await generatorCallback(tree, {
|
const changedFiles = await generatorCallback(tree, {
|
||||||
dryRun: !!args.dryRun,
|
dryRun: !!args.dryRun,
|
||||||
verbose: !!args.verbose,
|
verbose: !!args.verbose,
|
||||||
generatorOptions,
|
generatorOptions: {
|
||||||
|
...generatorOptions,
|
||||||
|
...args.generatorOptionsOverrides,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
changedFiles.forEach((f) => additionalChangedFiles.add(f));
|
changedFiles.forEach((f) => additionalChangedFiles.add(f));
|
||||||
});
|
});
|
||||||
@ -324,6 +338,7 @@ export async function releaseVersion(
|
|||||||
args,
|
args,
|
||||||
tree,
|
tree,
|
||||||
generatorData,
|
generatorData,
|
||||||
|
args.generatorOptionsOverrides,
|
||||||
projectNames,
|
projectNames,
|
||||||
releaseGroup,
|
releaseGroup,
|
||||||
versionData
|
versionData
|
||||||
@ -333,7 +348,10 @@ export async function releaseVersion(
|
|||||||
const changedFiles = await generatorCallback(tree, {
|
const changedFiles = await generatorCallback(tree, {
|
||||||
dryRun: !!args.dryRun,
|
dryRun: !!args.dryRun,
|
||||||
verbose: !!args.verbose,
|
verbose: !!args.verbose,
|
||||||
generatorOptions,
|
generatorOptions: {
|
||||||
|
...generatorOptions,
|
||||||
|
...args.generatorOptionsOverrides,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
changedFiles.forEach((f) => additionalChangedFiles.add(f));
|
changedFiles.forEach((f) => additionalChangedFiles.add(f));
|
||||||
});
|
});
|
||||||
@ -445,6 +463,7 @@ async function runVersionOnProjects(
|
|||||||
args: VersionOptions,
|
args: VersionOptions,
|
||||||
tree: Tree,
|
tree: Tree,
|
||||||
generatorData: GeneratorData,
|
generatorData: GeneratorData,
|
||||||
|
generatorOverrides: Record<string, unknown> | undefined,
|
||||||
projectNames: string[],
|
projectNames: string[],
|
||||||
releaseGroup: ReleaseGroupWithName,
|
releaseGroup: ReleaseGroupWithName,
|
||||||
versionData: VersionData
|
versionData: VersionData
|
||||||
@ -454,6 +473,7 @@ async function runVersionOnProjects(
|
|||||||
specifier: args.specifier ?? '',
|
specifier: args.specifier ?? '',
|
||||||
preid: args.preid ?? '',
|
preid: args.preid ?? '',
|
||||||
...generatorData.configGeneratorOptions,
|
...generatorData.configGeneratorOptions,
|
||||||
|
...(generatorOverrides ?? {}),
|
||||||
// The following are not overridable by user config
|
// The following are not overridable by user config
|
||||||
projects: projectNames.map((p) => projectGraph.nodes[p]),
|
projects: projectNames.map((p) => projectGraph.nodes[p]),
|
||||||
projectGraph,
|
projectGraph,
|
||||||
@ -610,3 +630,43 @@ function resolveGeneratorData({
|
|||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
function runPreVersionCommand(
|
||||||
|
preVersionCommand: string,
|
||||||
|
{ dryRun, verbose }: { dryRun: boolean; verbose: boolean }
|
||||||
|
) {
|
||||||
|
if (!preVersionCommand) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
output.logSingleLine(`Executing pre-version command`);
|
||||||
|
if (verbose) {
|
||||||
|
console.log(`Executing the following pre-version command:`);
|
||||||
|
console.log(preVersionCommand);
|
||||||
|
}
|
||||||
|
|
||||||
|
let env: Record<string, string> = {
|
||||||
|
...process.env,
|
||||||
|
};
|
||||||
|
if (dryRun) {
|
||||||
|
env.NX_DRY_RUN = 'true';
|
||||||
|
}
|
||||||
|
|
||||||
|
const stdio = verbose ? 'inherit' : 'pipe';
|
||||||
|
try {
|
||||||
|
execSync(preVersionCommand, {
|
||||||
|
encoding: 'utf-8',
|
||||||
|
maxBuffer: LARGE_BUFFER,
|
||||||
|
stdio,
|
||||||
|
env,
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
const title = verbose
|
||||||
|
? `The pre-version command failed. See the full output above.`
|
||||||
|
: `The pre-version command failed. Retry with --verbose to see the full output of the pre-version command.`;
|
||||||
|
output.error({
|
||||||
|
title,
|
||||||
|
bodyLines: [preVersionCommand, e],
|
||||||
|
});
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -232,6 +232,12 @@ interface NxReleaseConfiguration {
|
|||||||
* Enable or override configuration for git operations as part of the version subcommand
|
* Enable or override configuration for git operations as part of the version subcommand
|
||||||
*/
|
*/
|
||||||
git?: NxReleaseGitConfiguration;
|
git?: NxReleaseGitConfiguration;
|
||||||
|
/**
|
||||||
|
* A command to run after validation of nx release configuration, but before versioning begins.
|
||||||
|
* Used for preparing build artifacts. If --dry-run is passed, the command is still executed, but
|
||||||
|
* with the NX_DRY_RUN environment variable set to 'true'.
|
||||||
|
*/
|
||||||
|
preVersionCommand?: string;
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* Optionally override the git/release tag pattern to use. This field is the source of truth
|
* Optionally override the git/release tag pattern to use. This field is the source of truth
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user