fix(release): add overall nx release command (#20535)

Co-authored-by: James Henry <james@henry.sc>
Co-authored-by: Isaac Mann <isaacplmann@gmail.com>
This commit is contained in:
Austin Fahsl 2023-12-20 03:42:20 -10:00 committed by GitHub
parent 72898896a7
commit 82fb2da5d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 758 additions and 34 deletions

View File

@ -15,9 +15,9 @@ nx release
Install `nx` globally to invoke the command directly using `nx`, or use `npx nx`, `yarn nx`, or `pnpm nx`.
## Options
## Shared Options
### dryRun
### dry-run
Type: `boolean`
@ -57,6 +57,46 @@ Show version number
## Subcommands
### Base Command Options
Create a version and release for the workspace, generate a changelog, and optionally publish the packages
```shell
nx release [specifier]
```
#### Options
##### help
Type: `boolean`
Show help
##### skip-publish
Type: `boolean`
Skip publishing by automatically answering no to the confirmation prompt for publishing
##### specifier
Type: `string`
Exact version or semver keyword to apply to the selected release group.
##### version
Type: `boolean`
Show version number
##### yes
Type: `boolean`
Automatically answer yes to the confirmation prompt for publishing
### version
Create a version and release for one or more applications and libraries
@ -169,6 +209,14 @@ Type: `string`
Custom git commit message to use when committing the changes made by this command. {version} will be dynamically interpolated when performing fixed releases, interpolated tags will be appended to the commit body when performing independent releases.
##### git-remote
Type: `string`
Default: `origin`
Alternate git remote in the form {user}/{repo} on which to create the Github release (useful for testing)
##### git-tag
Type: `boolean`
@ -187,14 +235,6 @@ Type: `string`
Custom git tag message to use when tagging the changes made by this command. This defaults to be the same value as the tag itself.
##### gitRemote
Type: `string`
Default: `origin`
Alternate git remote in the form {user}/{repo} on which to create the Github release (useful for testing)
##### help
Type: `boolean`

View File

@ -65,7 +65,7 @@ Show information about "my-app" in a human readable format.:
nx show project my-app --json false
```
## Options
## Shared Options
### help

View File

@ -638,6 +638,14 @@
"children": [],
"disableCollapsible": false
},
{
"name": "Manage Releases",
"path": "/core-features/manage-releases",
"id": "manage-releases",
"isExternal": false,
"children": [],
"disableCollapsible": false
},
{
"name": "Plugin Features",
"path": "/core-features/plugin-features",
@ -730,6 +738,14 @@
"children": [],
"disableCollapsible": false
},
{
"name": "Manage Releases",
"path": "/core-features/manage-releases",
"id": "manage-releases",
"isExternal": false,
"children": [],
"disableCollapsible": false
},
{
"name": "Plugin Features",
"path": "/core-features/plugin-features",

View File

@ -870,6 +870,17 @@
"path": "/core-features/integrate-with-editors",
"tags": ["integrate-with-editors"]
},
{
"id": "manage-releases",
"name": "Manage Releases",
"description": "Learn how Nx provides tools to help you manage releasing your projects.",
"mediaImage": "",
"file": "shared/core-features/manage-releases",
"itemList": [],
"isExternal": false,
"path": "/core-features/manage-releases",
"tags": ["manage-releases"]
},
{
"id": "plugin-features",
"name": "Plugin Features",
@ -997,6 +1008,17 @@
"path": "/core-features/integrate-with-editors",
"tags": ["integrate-with-editors"]
},
"/core-features/manage-releases": {
"id": "manage-releases",
"name": "Manage Releases",
"description": "Learn how Nx provides tools to help you manage releasing your projects.",
"mediaImage": "",
"file": "shared/core-features/manage-releases",
"itemList": [],
"isExternal": false,
"path": "/core-features/manage-releases",
"tags": ["manage-releases"]
},
"/core-features/plugin-features": {
"id": "plugin-features",
"name": "Plugin Features",

View File

@ -396,6 +396,15 @@
"path": "/recipes/nx-console/console-troubleshooting"
}
],
"manage-releases": [
{
"description": "Learn how Nx provides tools to help you manage releasing your projects.",
"file": "shared/core-features/manage-releases",
"id": "manage-releases",
"name": "Manage Releases",
"path": "/core-features/manage-releases"
}
],
"use-task-executors": [
{
"description": "",

View File

@ -15,9 +15,9 @@ nx release
Install `nx` globally to invoke the command directly using `nx`, or use `npx nx`, `yarn nx`, or `pnpm nx`.
## Options
## Shared Options
### dryRun
### dry-run
Type: `boolean`
@ -57,6 +57,46 @@ Show version number
## Subcommands
### Base Command Options
Create a version and release for the workspace, generate a changelog, and optionally publish the packages
```shell
nx release [specifier]
```
#### Options
##### help
Type: `boolean`
Show help
##### skip-publish
Type: `boolean`
Skip publishing by automatically answering no to the confirmation prompt for publishing
##### specifier
Type: `string`
Exact version or semver keyword to apply to the selected release group.
##### version
Type: `boolean`
Show version number
##### yes
Type: `boolean`
Automatically answer yes to the confirmation prompt for publishing
### version
Create a version and release for one or more applications and libraries
@ -169,6 +209,14 @@ Type: `string`
Custom git commit message to use when committing the changes made by this command. {version} will be dynamically interpolated when performing fixed releases, interpolated tags will be appended to the commit body when performing independent releases.
##### git-remote
Type: `string`
Default: `origin`
Alternate git remote in the form {user}/{repo} on which to create the Github release (useful for testing)
##### git-tag
Type: `boolean`
@ -187,14 +235,6 @@ Type: `string`
Custom git tag message to use when tagging the changes made by this command. This defaults to be the same value as the tag itself.
##### gitRemote
Type: `string`
Default: `origin`
Alternate git remote in the form {user}/{repo} on which to create the Github release (useful for testing)
##### help
Type: `boolean`

View File

@ -65,7 +65,7 @@ Show information about "my-app" in a human readable format.:
nx show project my-app --json false
```
## Options
## Shared Options
### help

View File

@ -244,6 +244,13 @@
"tags": ["integrate-with-editors"],
"file": "shared/core-features/integrate-with-editors"
},
{
"name": "Manage Releases",
"description": "Learn how Nx provides tools to help you manage releasing your projects.",
"id": "manage-releases",
"tags": ["manage-releases"],
"file": "shared/core-features/manage-releases"
},
{
"name": "Plugin Features",
"id": "plugin-features",

View File

@ -0,0 +1,128 @@
# Manage Releases - `nx release`
Once you have leveraged Nx's powerful code generation and task running capabilities to build your libraries and applications, you will want to share them with your users.
Nx provides a set of tools to help you manage your releases called `nx release`.
> We recommend always starting with --dry-run, because publishing is difficult to undo
```shell
nx release --dry-run
```
## What makes up a release?
A release can be thought about in three main phases:
1. **Versioning** - The process of determining the next version of your projects, and updating any projects that depend on them to use the new version.
2. **Changelog** - The process of deriving a changelog from your commit messages, which can be used to communicate the changes to your users.
3. **Publishing** - The process of publishing your projects to a registry, such as npm for TypeScript/JavaScript libraries.
## Running releases
The `nx release` command is used to run the release process from end to end. It is a wrapper around the three main phases of a release to provide maximum convenience and ease of use.
By default if you just run `nx release` it will prompt you for a semver-compatible version number, or semver keyword (such as major, minor, patch, etc.) and then run the three phases of the release process, including publishing.
As with most Nx commands, when trying it out for the first time, it is strongly recommended to use the `--dry-run` flag to see what changes will be made before actually making them.
```shell
nx release --dry-run
```
{% callout type="note" title="Establishing the previous release" %}
If you are working with a brand new workspace, or one that has never been released before, you will need to establish the previous release before running `nx release`. This is because Nx needs to know what the previous version of your projects was in order to know what to use as the start of the new release's changelog commit range. To do this, run `git tag` with an appropriate initial version. For example, if you have a brand new workspace, you might run `git tag 0.0.0` to establish the initial version.
{% /callout %}
## Customizing releases
The `nx release` command is highly customizable. You can customize the versioning, changelog, and publishing phases of the release process independently through a mixture of configuration and CLI arguments.
The configuration lives in your `nx.json` file under the `"release"` section.
```jsonc {% fileName="nx.json" %}
{
// ... more nx.json config
"release": {
// For example, configures nx release to target all projects
// except the one called "ignore-me"
"projects": ["*", "!ignore-me"]
// ... nx release config
}
}
```
## Using nx release subcommands independently
As explained above, `nx release` is a wrapper around the three main phases of a release.
If you need more advanced or granular control over your release process you can also run these phases independently using the `nx release version`, `nx release changelog`, and `nx release publish` subcommands.
Each of these subcommands has their own CLI arguments which you can explore using the `--help` flag.
```shell
nx release version --help
nx release changelog --help
nx release publish --help
```
## Using the programmatic API for nx release
For the maximum control and power over your release process, it is recommended to use the programmatic API for `nx release` in your own custom scripts.
Here is a full working example of creating a custom script which processes its own CLI arguments (with `--dry-run` true by default) and then calls the `nx release` programmatic API.
```ts {% fileName="tools/scripts/release.ts" %}
import {
releaseChangelog,
releasePublish,
releaseVersion,
} from 'nx/src/command-line/release';
import * as yargs from 'yargs';
(async () => {
const options = await yargs
.version(false) // don't use the default meaning of version in yargs
.option('version', {
description:
'Explicit version specifier to use, if overriding conventional commits',
type: 'string',
})
.option('dryRun', {
alias: 'd',
description:
'Whether or not to perform a dry-run of the release process, defaults to true',
type: 'boolean',
default: true,
})
.option('verbose', {
description:
'Whether or not to enable verbose logging, defaults to false',
type: 'boolean',
default: false,
})
.parseAsync();
const { workspaceVersion, projectsVersionData } = await releaseVersion({
specifier: options.version,
// stage package.json updates to be committed later by the changelog command
stageChanges: true,
dryRun: options.dryRun,
verbose: options.verbose,
});
await releaseChangelog({
versionData: projectsVersionData,
version: workspaceVersion,
dryRun: options.dryRun,
verbose: options.verbose,
});
await releasePublish({
dryRun: options.dryRun,
verbose: options.verbose,
});
process.exit(0);
})();
```

View File

@ -31,7 +31,25 @@ The following is an expanded example showing all options. Your `nx.json` will li
}
},
"parallel": 4,
"cacheDirectory": "tmp/my-nx-cache"
"cacheDirectory": "tmp/my-nx-cache",
"release": {
"version": {
"generatorOptions": {
"currentVersionResolver": "git-tag",
"specifierSource": "conventional-commits"
}
},
"changelog": {
"git": {
"commit": true,
"tag": true
},
"workspaceChangelog": {
"createRelease": "github"
},
"projectChangelogs": true
}
}
}
```
@ -259,3 +277,181 @@ As of Nx 17, if you only use one tasks runner, you can specify these properties
You can configure `parallel` in `nx.json`, but you can also pass them in the
terminal `nx run-many -t test --parallel=5`.
### Release
The `release` property in `nx.json` configures the `nx release` command. It is an optional property, as `nx release` is capable of working with zero config, but when present it is used to configure the versioning, changelog, and publishing phases of the release process.
For more information on how `nx release` works, see [manage releases](/core-features/manage-releases).
The full list of configuration options available for `"release"` can be found here: [https://github.com/nrwl/nx/blob/master/packages/nx/src/config/nx-json.ts](https://github.com/nrwl/nx/blob/master/packages/nx/src/config/nx-json.ts) under `NxReleaseConfiguration`.
#### Projects
If you want to limit the projects that `nx release` targets, you can use the `projects` property in `nx.json` to do so. This property is either a string, or an array of strings. The strings can be project names, glob patterns, directories, tag references or anything else that is supported by the `--projects` filter you may know from other commands such as `nx run`.
```jsonc {% fileName="nx.json" %}
{
"release": {
// Here we are configuring nx release to target all projects
// except the one called "ignore-me"
"projects": ["*", "!ignore-me"]
}
}
```
#### Projects Relationship
The `projectsRelationship` property tells Nx whether to release projects independently or together. By default Nx will release all your projects together in lock step, which is an equivalent of `"projectRelationships": "fixed"`. If you want to release projects independently, you can set `"projectsRelationship": "independent"`.
```jsonc {% fileName="nx.json" %}
{
"release": {
// Here we are configuring nx release to release projects
// independently, as opposed to the default of "fixed"
"projectsRelationship": "independent"
}
}
```
#### Release Tag Pattern
Optionally override the git/release tag pattern to use. This field is the source of truth for changelog generation and release tagging, as well as for conventional commits parsing.
It supports interpolating the version as `{version}` and (if releasing independently or forcing project level version control system releases) the project name as `{projectName}` within the string.
The default `"releaseTagPattern"` for fixed/unified releases is: `v{version}`
The default `"releaseTagPattern"` for independent releases at the project level is: `{projectName}@v{version}`
```jsonc {% fileName="nx.json" %}
{
"release": {
// Here we are configuring nx release to use a custom release
// tag pattern (we have dropped the v prefix from the default)
"releaseTagPattern": "{version}"
}
}
```
#### Version
The `version` property configures the versioning phase of the release process. It is used to determine the next version of your projects, and update any projects that depend on them to use the new version.
Behind the scenes, the `version` logic is powered by an Nx generator. Out of the box Nx wires up the most widely applicable generator implementation for you, which is `@nx/js:release-version` provided by the `@nx/js` plugin.
It is therefore a common requirement to be able to tweak the options given to that generator. This can be done by configuring the `release.version.generatorOptions` property in `nx.json`:
```jsonc {% fileName="nx.json" %}
{
"release": {
"version": {
"generatorOptions": {
// Here we are configuring the generator to use git tags as the
// source of truth for a project's current version
"currentVersionResolver": "git-tag",
// Here we are configuring the generator to use conventional
// commits as the source of truth for how to determine the
// relevant version bump for the next version
"specifierSource": "conventional-commits"
}
}
}
}
```
For a full reference of the available options for the `@nx/js:release-version` generator, see the [release version generator reference](/nx-api/js/generators/release-version).
#### Changelog
The `changelog` property configures the changelog phase of the release process. It is used to generate a changelog for your projects, and commit it to your repository.
There are two types of possible changelog that can be generated:
- **Workspace Changelog**: A changelog that contains all changes across all projects in your workspace. This is not applicable when releasing projects independently.
- **Project Changelogs**: A changelog that contains all changes for a given project.
The `changelog` property is used to configure both of these changelogs.
##### Workspace Changelog
The `changelog.workspaceChangelog` property configures the workspace changelog. It is used to determine if and how the workspace changelog is generated.
```jsonc {% fileName="nx.json" %}
{
"release": {
"changelog": {
// This disables the workspace changelog
"workspaceChangelog": false
}
}
}
```
```jsonc {% fileName="nx.json" %}
{
"release": {
"changelog": {
"workspaceChangelog": {
// This will create a GitHub release containing the workspace
// changelog contents
"createRelease": "github",
// This will disable creating a workspace CHANGELOG.md file
"file": false
}
}
}
}
```
##### Project Changelogs
The `changelog.projectChangelogs` property configures the project changelogs. It is used to determine if and how the project changelogs are generated.
```jsonc {% fileName="nx.json" %}
{
"release": {
"changelog": {
// This enables project changelogs with the default options
"projectChangelogs": true
}
}
}
```
```jsonc {% fileName="nx.json" %}
{
"release": {
"changelog": {
"projectChangelogs": {
// This will create one GitHub release per project containing
// the project changelog contents
"createRelease": "github",
// This will disable creating any project level CHANGELOG.md
// files
"file": false
}
}
}
}
```
#### Git
The `git` property configures the automated git operations that take place as part of the release process.
```jsonc {% fileName="nx.json" %}
{
"release": {
"git": {
// This will enable committing any changes (e.g. package.json
// updates, CHANGELOG.md files) to git
"commit": true,
// This will enable create a git for the overall release, or
// one tag per project for independent project releases
"tag": false
}
}
}
```

View File

@ -40,6 +40,7 @@
- [Automate Updating Dependencies](/core-features/automate-updating-dependencies)
- [Enforce Module Boundaries](/core-features/enforce-module-boundaries)
- [Integrate with Editors](/core-features/integrate-with-editors)
- [Manage Releases](/core-features/manage-releases)
- [Plugin Features](/core-features/plugin-features)
- [Use Task Executors](/core-features/plugin-features/use-task-executors)
- [Use Code Generators](/core-features/plugin-features/use-code-generators)

View File

@ -649,4 +649,61 @@ describe('nx release - independent projects', () => {
`);
});
});
describe('release command', () => {
beforeEach(() => {
updateJson('nx.json', () => {
return {
release: {
projectsRelationship: 'independent',
releaseTagPattern: '{projectName}@v{version}',
version: {
generatorOptions: {
currentVersionResolver: 'git-tag',
},
},
changelog: {
projectChangelogs: {},
},
},
};
});
});
it('should allow versioning projects independently', async () => {
runCommand(`git tag ${pkg1}@v1.2.0`);
runCommand(`git tag ${pkg2}@v1.4.0`);
runCommand(`git tag ${pkg3}@v1.6.0`);
const releaseOutput = runCLI(`release patch -y`);
expect(
releaseOutput.match(new RegExp(`New version 1\.2\.1 written`, 'g'))
.length
).toEqual(1);
expect(
releaseOutput.match(new RegExp(`New version 1\.4\.1 written`, 'g'))
.length
).toEqual(1);
expect(
releaseOutput.match(new RegExp(`New version 1\.6\.1 written`, 'g'))
.length
).toEqual(1);
expect(
releaseOutput.match(new RegExp(`Generating an entry in `, 'g')).length
).toEqual(3);
expect(
releaseOutput.match(
new RegExp(
`Successfully ran target nx-release-publish for 3 projects`,
'g'
)
).length
).toEqual(1);
});
});
});

View File

@ -878,5 +878,42 @@ ${JSON.stringify(
/New version 1101.0.0 written to my-pkg-\d*\/package.json/g
).length
).toEqual(3);
// Reset the nx release config to something basic for testing the release command
updateJson<NxJsonConfiguration>('nx.json', (nxJson) => {
nxJson.release = {
groups: {
default: {
// @proj/source will be added as a project by the verdaccio setup, but we aren't versioning or publishing it, so we exclude it here
projects: ['*', '!@proj/source'],
releaseTagPattern: 'xx{version}',
},
},
};
return nxJson;
});
const releaseOutput = runCLI(`release 1200.0.0 -y`);
expect(
releaseOutput.match(
new RegExp(`Running release version for project: `, 'g')
).length
).toEqual(3);
expect(
releaseOutput.match(
new RegExp(`Generating an entry in CHANGELOG\.md for v1200\.0\.0`, 'g')
).length
).toEqual(1);
expect(
releaseOutput.match(
new RegExp(
`Successfully ran target nx-release-publish for 3 projects`,
'g'
)
).length
).toEqual(1);
}, 500000);
});

View File

@ -423,8 +423,9 @@ async function generateChangelogForWorkspace(
postGitTasks: PostGitTask[]
) {
const config = nxReleaseConfig.changelog.workspaceChangelog;
const isEnabled = args.workspaceChangelog ?? config;
// The entire feature is disabled at the workspace level, exit early
if (config === false) {
if (isEnabled === false) {
return;
}
@ -433,7 +434,14 @@ async function generateChangelogForWorkspace(
return;
}
if (!workspaceChangelogVersion) {
// The user explicitly passed workspaceChangelog=true but does not have a workspace changelog config in nx.json
if (!config) {
throw new Error(
`Workspace changelog is enabled but no configuration was provided. Please provide a workspaceChangelog object in your nx.json`
);
}
if (!workspaceChangelogVersion && args.workspaceChangelog) {
throw new Error(
`Workspace changelog is enabled but no overall version was provided. Please provide an explicit version using --version`
);

View File

@ -42,6 +42,7 @@ export type ChangelogOptions = NxReleaseArgs &
from?: string;
interactive?: string;
gitRemote?: string;
workspaceChangelog?: boolean;
};
export type PublishOptions = NxReleaseArgs &
@ -51,6 +52,11 @@ export type PublishOptions = NxReleaseArgs &
otp?: number;
};
export type ReleaseOptions = NxReleaseArgs & {
yes?: boolean;
skipPublish?: boolean;
};
export const yargsReleaseCommand: CommandModule<
Record<string, unknown>,
NxReleaseArgs
@ -60,6 +66,7 @@ export const yargsReleaseCommand: CommandModule<
'**ALPHA**: Orchestrate versioning and publishing of applications and libraries',
builder: (yargs) =>
yargs
.command(releaseCommand)
.command(versionCommand)
.command(changelogCommand)
.command(publishCommand)
@ -80,7 +87,7 @@ export const yargsReleaseCommand: CommandModule<
describe:
'Projects to run. (comma/space delimited project names and/or patterns)',
})
.option('dryRun', {
.option('dry-run', {
describe:
'Preview the changes without updating files/creating releases',
alias: 'd',
@ -116,6 +123,47 @@ export const yargsReleaseCommand: CommandModule<
},
};
const releaseCommand: CommandModule<NxReleaseArgs, ReleaseOptions> = {
command: '$0 [specifier]',
describe:
'Create a version and release for the workspace, generate a changelog, and optionally publish the packages',
builder: (yargs) =>
yargs
.positional('specifier', {
type: 'string',
describe:
'Exact version or semver keyword to apply to the selected release group.',
})
.option('yes', {
type: 'boolean',
alias: 'y',
description:
'Automatically answer yes to the confirmation prompt for publishing',
})
.option('skip-publish', {
type: 'boolean',
description:
'Skip publishing by automatically answering no to the confirmation prompt for publishing',
})
.check((argv) => {
if (argv.yes !== undefined && argv.skipPublish !== undefined) {
throw new Error(
'The --yes and --skip-publish options are mutually exclusive, please use one or the other.'
);
}
return true;
}),
handler: (args) =>
import('./release')
.then((m) => m.releaseCLIHandler(args))
.then((versionDataOrExitCode) => {
if (typeof versionDataOrExitCode === 'number') {
return process.exit(versionDataOrExitCode);
}
process.exit(0);
}),
};
const versionCommand: CommandModule<NxReleaseArgs, VersionOptions> = {
command: 'version [specifier]',
aliases: ['v'],
@ -185,7 +233,7 @@ const changelogCommand: CommandModule<NxReleaseArgs, ChangelogOptions> = {
'Interactively modify changelog markdown contents in your code editor before applying the changes. You can set it to be interactive for all changelogs, or only the workspace level, or only the project level',
choices: ['all', 'workspace', 'projects'],
})
.option('gitRemote', {
.option('git-remote', {
type: 'string',
description:
'Alternate git remote in the form {user}/{repo} on which to create the Github release (useful for testing)',

View File

@ -10,3 +10,7 @@ export { releasePublish } from './publish';
* @public
*/
export { releaseVersion } from './version';
/**
* @public
*/
export { release } from './release';

View File

@ -0,0 +1,103 @@
import { prompt } from 'enquirer';
import { readNxJson } from '../../config/nx-json';
import { output } from '../../devkit-exports';
import { createProjectGraphAsync } from '../../project-graph/project-graph';
import { handleErrors } from '../../utils/params';
import { releaseChangelog } from './changelog';
import { ReleaseOptions, VersionOptions } from './command-object';
import {
createNxReleaseConfig,
handleNxReleaseConfigError,
} from './config/config';
import { releasePublish } from './publish';
import { resolveNxJsonConfigErrorMessage } from './utils/resolve-nx-json-error-message';
import { NxReleaseVersionResult, releaseVersion } from './version';
export const releaseCLIHandler = (args: VersionOptions) =>
handleErrors(args.verbose, () => release(args));
export async function release(
args: ReleaseOptions
): Promise<NxReleaseVersionResult | number> {
const projectGraph = await createProjectGraphAsync({ exitOnError: true });
const nxJson = readNxJson();
if (args.verbose) {
process.env.NX_VERBOSE_LOGGING = 'true';
}
const hasVersionGitConfig =
Object.keys(nxJson.release?.version?.git ?? {}).length > 0;
const hasChangelogGitConfig =
Object.keys(nxJson.release?.changelog?.git ?? {}).length > 0;
if (hasVersionGitConfig || hasChangelogGitConfig) {
const jsonConfigErrorPath = hasVersionGitConfig
? ['release', 'version', 'git']
: ['release', 'changelog', 'git'];
const nxJsonMessage = await resolveNxJsonConfigErrorMessage(
jsonConfigErrorPath
);
output.error({
title: `The 'release' top level command cannot be used with granular git configuration. Instead, configure git options in the 'release.git' property in nx.json.`,
bodyLines: [nxJsonMessage],
});
process.exit(1);
}
// Apply default configuration to any optional user configuration
const { error: configError, nxReleaseConfig } = await createNxReleaseConfig(
projectGraph,
nxJson.release,
'nx-release-publish'
);
if (configError) {
return await handleNxReleaseConfigError(configError);
}
const versionResult: NxReleaseVersionResult = await releaseVersion({
...args,
// if enabled, committing and tagging will be handled by the changelog
// command, so we should only stage the changes in the version command
stageChanges: nxReleaseConfig.git?.commit,
gitCommit: false,
gitTag: false,
});
await releaseChangelog({
...args,
versionData: versionResult.projectsVersionData,
version: versionResult.workspaceVersion,
workspaceChangelog: versionResult.workspaceVersion !== undefined,
});
let shouldPublish = !!args.yes && !args.skipPublish;
const shouldPromptPublishing = !args.yes && !args.skipPublish && !args.dryRun;
if (shouldPromptPublishing) {
shouldPublish = await promptForPublish();
}
if (shouldPublish) {
await releasePublish(args);
} else {
console.log('Skipped publishing packages.');
}
return versionResult;
}
async function promptForPublish(): Promise<boolean> {
console.log('\n');
const reply = await prompt<{ confirmation: boolean }>([
{
name: 'confirmation',
message: 'Do you want to publish these versions?',
type: 'confirm',
},
]);
console.log('\n');
return reply.confirmation;
}

View File

@ -58,7 +58,7 @@ export interface ReleaseVersionGeneratorSchema {
currentVersionResolverMetadata?: Record<string, unknown>;
}
interface NxReleaseVersionResult {
export interface NxReleaseVersionResult {
/**
* In one specific (and very common) case, an overall workspace version is relevant, for example when there is
* only a single release group in which all projects have a fixed relationship to each other. In this case, the

View File

@ -223,13 +223,13 @@ interface NxReleaseConfiguration {
};
/**
* Optionally override the git/release tag pattern to use. This field is the source of truth
* for changelog generation and release tagging, as well as for conventional-commits parsing.
* for changelog generation and release tagging, as well as for conventional commits parsing.
*
* It supports interpolating the version as {version} and (if releasing independently or forcing
* project level version control system releases) the project name as {projectName} within the string.
*
* The default releaseTagPattern for unified releases is: "v{version}"
* The default releaseTagPattern for releases at the project level is: "{projectName}@v{version}"
* The default releaseTagPattern for fixed/unified releases is: "v{version}"
* The default releaseTagPattern for independent releases at the project level is: "{projectName}@v{version}"
*/
releaseTagPattern?: string;
/**

View File

@ -70,10 +70,13 @@ description: "${command.description}"
templateLines.push(h2('Subcommands'));
for (const subcommand of command.subcommands) {
templateLines.push(
h3(subcommand.name),
h3(subcommand.name.replace('$0', 'Base Command Options')),
formatDescription(subcommand.description, subcommand.deprecated),
codeBlock(
`nx ${command.commandString} ${subcommand.commandString}`,
`nx ${command.commandString} ${subcommand.commandString.replace(
'$0 ',
''
)}`,
'shell'
),
generateOptionsMarkdown(subcommand, 2)

View File

@ -231,7 +231,12 @@ export function generateOptionsMarkdown(
): string {
const lines: string[] = [];
if (Array.isArray(command.options) && !!command.options.length) {
lines.push(h(2 + extraHeadingLevels, 'Options'));
lines.push(
h(
2 + extraHeadingLevels,
command.subcommands?.length ? 'Shared Options' : 'Options'
)
);
command.options
.sort((a, b) => sortAlphabeticallyFunction(a.name, b.name))