feat(release)!: useLegacyVersioning is false by default, migrate config (#30838)
This PR updates `nx release` to use the revamped versioning
implementation by default. It also updates and adds relevant
documentation, and provides an automated migration for the new
configuration structure.
For anyone exclusively versioning TS/JS packages, there should be no
real difference to your experience (although a number of bugs have been
fixed and new features around updating multiple `package.json` files at
once are now available to you with this change).
For the lifecycle of Nx v21, `release.version.useLegacyVersioning` will
remain as a option that can be set to `true` to revert to the old
behavior and configuration structure.
NOTE: This should only be a temporary solution, for example if one of
the plugins you use does provide a `VersionActions` based versioning
implementation yet. The option and legacy implementation will be removed
entirely in Nx v22 (in ~6 months).
BREAKING CHANGE:
**⚠️ For any early adopters of `VersionActions` in Nx 20.8 when it was
opt-in, there are breaking changes to the abstract class here as well.**
`manifestRootsToUpdate` has gone from `string[]` to `manifestsToUpdate:
{ manifestPath: string; preserveLocalDependencyProtocols: boolean; }[]`
to support controlling the local dependency updates per manifest in
order to support advanced source vs dist scenarios, and correspondingly
`isLocalDependencyProtocol` has been removed from the abstract class and
the method will no longer be called from the core logic. It should be
thought of as an implementation detail of `updateProjectDependencies`
instead.
This commit is contained in:
parent
053fc67e90
commit
ee097a8e10
@ -99,8 +99,8 @@ Project specific configuration for `nx release`
|
||||
#### Type declaration
|
||||
|
||||
| Name | Type |
|
||||
| :--------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `version?` | `Pick`\<`NxReleaseVersionConfiguration`, `"generator"` \| `"generatorOptions"`\> \| `Pick`\<`NxReleaseVersionV2Configuration`, `"versionActions"` \| `"versionActionsOptions"` \| `"manifestRootsToUpdate"` \| `"currentVersionResolver"` \| `"currentVersionResolverMetadata"` \| `"fallbackCurrentVersionResolver"` \| `"versionPrefix"` \| `"preserveLocalDependencyProtocols"`\> |
|
||||
| :--------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `version?` | `Pick`\<`LegacyNxReleaseVersionConfiguration`, `"generator"` \| `"generatorOptions"`\> \| `Pick`\<`NxReleaseVersionConfiguration`, `"versionActions"` \| `"versionActionsOptions"` \| `"manifestRootsToUpdate"` \| `"currentVersionResolver"` \| `"currentVersionResolverMetadata"` \| `"fallbackCurrentVersionResolver"` \| `"versionPrefix"` \| `"preserveLocalDependencyProtocols"`\> |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@ -3724,6 +3724,16 @@
|
||||
}
|
||||
},
|
||||
"migrations": {
|
||||
"/nx-api/nx/migrations/release-version-config-changes": {
|
||||
"description": "Updates release version config based on the breaking changes in Nx v21",
|
||||
"file": "generated/packages/nx/migrations/release-version-config-changes.json",
|
||||
"hidden": false,
|
||||
"name": "release-version-config-changes",
|
||||
"version": "21.0.0-beta.1",
|
||||
"originalFilePath": "/packages/nx",
|
||||
"path": "/nx-api/nx/migrations/release-version-config-changes",
|
||||
"type": "migration"
|
||||
},
|
||||
"/nx-api/nx/migrations/use-legacy-cache": {
|
||||
"description": "Set `useLegacyCache` to true for migrating workspaces",
|
||||
"file": "generated/packages/nx/migrations/use-legacy-cache.json",
|
||||
|
||||
@ -3700,6 +3700,16 @@
|
||||
}
|
||||
],
|
||||
"migrations": [
|
||||
{
|
||||
"description": "Updates release version config based on the breaking changes in Nx v21",
|
||||
"file": "generated/packages/nx/migrations/release-version-config-changes.json",
|
||||
"hidden": false,
|
||||
"name": "release-version-config-changes",
|
||||
"version": "21.0.0-beta.1",
|
||||
"originalFilePath": "/packages/nx",
|
||||
"path": "nx/migrations/release-version-config-changes",
|
||||
"type": "migration"
|
||||
},
|
||||
{
|
||||
"description": "Set `useLegacyCache` to true for migrating workspaces",
|
||||
"file": "generated/packages/nx/migrations/use-legacy-cache.json",
|
||||
|
||||
@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "release-version-config-changes",
|
||||
"version": "21.0.0-beta.1",
|
||||
"description": "Updates release version config based on the breaking changes in Nx v21",
|
||||
"implementation": "/packages/nx/src/migrations/update-21-0-0/release-version-config-changes.ts",
|
||||
"aliases": [],
|
||||
"hidden": false,
|
||||
"path": "/packages/nx",
|
||||
"schema": null,
|
||||
"type": "migration",
|
||||
"examplesFile": "#### Nx Release Version Config Changes\n\nIn Nx v21, the implementation details of versioning were rewritten to massively enhance flexibility and lay the groundwork for future features.\n\nAs part of this, some elements of the release configuration were updated. During the lifecycle of Nx v21, you can still opt into the old versioning by setting `release.version.useLegacyVersioning` to `true`, in which case the release configuration should remain unchanged.\n\nIn Nx v22, the legacy versioning implementation will be removed entirely and the configuration will have to be updated to match what this migration does for you.\n\n#### Sample Code Changes\n\n\"generatorOptions\" is longer exists and most non-ecosystem specific options have moved to the top level of \"version\" and are therefore fully documented on the JSON schema as a core option.\n\n\"packageRoot: string\" has been replaced by the more flexible concept of \"manifestRootsToUpdate: string[]\", allowing for multiple manifest files (such as `package.json` in the JS/TS ecosystem)\nto be updated in a single versioning run.\n\nEcosystem specific options, such as \"skipLockFileUpdate\", which is specific to the JS/TS ecosystem, are available via the new \"versionActionsOptions\" object, which is so named because of the new `VersionActions` abstraction introduced in Nx v21,\nwhich allows for different ecosystems and use-cases to be supported via very minimal implementation effort.\n\n\"preserveLocalDependencyProtocols\" changed from `false` by default to `true` by default in Nx v21, so it can simply be removed from the configuration when set to true.\n\nThe migration will also update release groups version configuration, as well as project.json and package.json version configuration, if applicable.\n\n{% tabs %}\n{% tab label=\"Before\" %}\n\n```json {% fileName=\"nx.json\" %}\n{\n \"release\": {\n \"version\": {\n \"generatorOptions\": {\n \"packageRoot\": \"build/packages/{projectName}\",\n \"currentVersionResolver\": \"registry\",\n \"skipLockFileUpdate\": true,\n \"preserveLocalDependencyProtocols\": true\n }\n }\n }\n}\n```\n\n{% /tab %}\n{% tab label=\"After\" %}\n\n```json {% fileName=\"nx.json\" %}\n{\n \"release\": {\n \"version\": {\n \"manifestRootsToUpdate\": [\"build/packages/{projectName}\"],\n \"currentVersionResolver\": \"registry\",\n \"versionActionsOptions\": {\n \"skipLockFileUpdate\": true\n }\n }\n }\n}\n```\n\n{% /tab %}\n{% /tabs %}\n"
|
||||
}
|
||||
@ -82,3 +82,22 @@ Nx Release supports creating GitHub releases for project level changelogs as wel
|
||||
{% callout type="warning" title="Project and Workspace GitHub Releases" %}
|
||||
Nx Release does not support creating GitHub releases for both project level changelogs and the workspace changelog. You will need to choose one or the other.
|
||||
{% /callout %}
|
||||
|
||||
## Customizing the GitHub instance to use GitHub Enterprise Server
|
||||
|
||||
If you are not using github.com, and instead using a self-hosted GitHub Enterprise Server instance, you can use a configuration object instead of the string for "createRelease" to provide the relevant hostname, and optionally override the API base URL, although this is not typically needed as it will default to `https://${hostname}/api/v3`.
|
||||
|
||||
```json
|
||||
{
|
||||
"release": {
|
||||
"changelog": {
|
||||
"workspaceChangelog": {
|
||||
"createRelease": {
|
||||
"provider": "github-enterprise-server",
|
||||
"hostname": "github.example.com"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@ -66,24 +66,21 @@ An example partial output of running Nx Release with independent releases and co
|
||||
|
||||
NX Running release version for project: pkg-1
|
||||
|
||||
pkg-1 🔍 Reading data for package "@myorg/pkg-1" from packages/pkg-1/package.json
|
||||
pkg-1 📄 Resolved the current version as 0.4.0 from git tag "pkg-1@0.4.0".
|
||||
pkg-1 📄 Resolved the specifier as "minor" using git history and the conventional commits standard.
|
||||
pkg-1 ✍️ New version 0.5.0 written to packages/pkg-1/package.json
|
||||
pkg-1 🏷️ Resolved the current version as 0.4.0 from git tag "pkg-1@0.4.0", based on releaseTagPattern "{projectName}@{version}"
|
||||
pkg-1 📄 Resolved the specifier as "patch" using git history and the conventional commits standard
|
||||
pkg-1 ❓ Applied semver relative bump "patch", derived from conventional commits data, to get new version 0.4.1
|
||||
pkg-1 ✍️ New version 0.4.1 written to manifest: packages/pkg-1/package.json
|
||||
|
||||
NX Running release version for project: pkg-2
|
||||
|
||||
pkg-2 🔍 Reading data for package "@myorg/pkg-2" from packages/pkg-2/package.json
|
||||
pkg-2 📄 Resolved the current version as 0.4.0 from git tag "pkg-2@0.4.0".
|
||||
pkg-2 📄 Resolved the specifier as "patch" using git history and the conventional commits standard.
|
||||
pkg-2 ✍️ New version 0.4.1 written to packages/pkg-2/package.json
|
||||
pkg-2 ✍️ Applying new version 0.4.1 to 1 package which depends on pkg-2
|
||||
pkg-2 🏷️ Resolved the current version as 0.4.0 from git tag "pkg-2@0.4.0", based on releaseTagPattern "{projectName}@{version}"
|
||||
pkg-2 📄 Resolved the specifier as "minor" using git history and the conventional commits standard
|
||||
pkg-2 ❓ Applied semver relative bump "minor", derived from conventional commits data, to get new version 0.5.0
|
||||
pkg-2 ✍️ New version 0.5.0 written to manifest: packages/pkg-2/package.json
|
||||
|
||||
NX Running release version for project: pkg-3
|
||||
|
||||
pkg-3 🔍 Reading data for package "@myorg/pkg-3" from packages/pkg-3/package.json
|
||||
pkg-3 📄 Resolved the current version as 0.4.0 from git tag "pkg-3@0.4.0".
|
||||
pkg-3 🚫 No changes were detected using git history and the conventional commits standard.
|
||||
pkg-3 🚫 Skipping versioning "@myorg/pkg-3" as no changes were detected.
|
||||
pkg-3 🏷️ Resolved the current version as 0.4.0 from git tag "pkg-3@0.4.0", based on releaseTagPattern "{projectName}@{version}"
|
||||
pkg-3 🚫 No changes were detected using git history and the conventional commits standard
|
||||
|
||||
```
|
||||
|
||||
@ -17,7 +17,7 @@ In order to ensure that projects are built before the new version is applied to
|
||||
}
|
||||
```
|
||||
|
||||
This command will run the `build` target for all projects before the version step of Nx Release. Any command can be specified, including non-nx commands. This step is often required when [publishing from a custom dist directory](/recipes/nx-release/updating-version-references#scenario-2-i-want-to-publish-from-a-custom-dist-directory-and-not-update-references-in-my-source-packagejson-files), as the dist directory must be built before the version is applied to the dist directory's package manifest.
|
||||
This command will run the `build` target for all projects before the version step of Nx Release. Any command can be specified, including non-nx commands. This step is often required when [publishing from a custom dist directory](/recipes/nx-release/updating-version-references#scenario-2-i-want-to-publish-from-a-custom-dist-directory-and-update-references-in-my-both-my-source-and-dist-packagejson-files), as the dist directory must be built before the version is applied to the dist directory's package manifest.
|
||||
|
||||
When using release groups in which the member projects are versioned together, you can use `groupPreVersionCommand` and it will be executed before the versioning step for that release group.
|
||||
|
||||
|
||||
@ -1,17 +1,17 @@
|
||||
---
|
||||
title: Configure Version Prefix for Dependencies
|
||||
description: Learn how to set up custom version prefixes in Nx Release to control how dependency versions are specified in your package.json files, with options for exact, patch, or minor-level compatibility.
|
||||
title: Configuring Version Prefix for Dependencies
|
||||
description: Learn how to set up custom version prefixes in Nx Release to control how dependency versions are specified in your manifest files (such as package.json, Cargo.toml, etc.), with options for exact, patch, or minor-level compatibility.
|
||||
---
|
||||
|
||||
# Configuring Version Prefix for Dependency Versions
|
||||
|
||||
This guide explains how to configure a custom version prefix in Nx Release using the `versionPrefix` option. The version prefix allows you to automatically add a specific prefix format to dependencies, providing control over how dependency versions are specified in your project's `package.json` files.
|
||||
This guide explains how to configure a custom version prefix in Nx Release using the `versionPrefix` option. The version prefix allows you to automatically add a specific prefix format to dependencies, providing control over how dependency versions are specified in your project's manifest files (such as `package.json`, `Cargo.toml`, etc.).
|
||||
|
||||
## The `versionPrefix` Option
|
||||
|
||||
The `versionPrefix` option controls which prefix is applied to dependency versions during the versioning process. By default, `versionPrefix` is set to `"auto"`, which selects a prefix format (either `""`, `"~"`, `"^"`, or `"="`) by respecting what is already in the `package.json` file.
|
||||
The `versionPrefix` option controls which prefix is applied to dependency versions during the versioning process. By default, `versionPrefix` is set to `"auto"`, which selects a prefix format (either `""`, `"~"`, `"^"`, or `"="`) by respecting what is already in the manifest file.
|
||||
|
||||
For example, having the following `package.json` file:
|
||||
For example, having the following `package.json` file as an example manifest:
|
||||
|
||||
```json
|
||||
{
|
||||
@ -45,7 +45,7 @@ Preserving the prefix for `dependency-one` and `dependency-two` and continuing t
|
||||
|
||||
You can set `versionPrefix` to one of the following values:
|
||||
|
||||
- `"auto"`: Automatically chooses a prefix based on the existing declaration in the `package.json` file. This is the default value.
|
||||
- `"auto"`: Automatically chooses a prefix based on the existing declaration in the manifest file. This is the default value.
|
||||
- `""`: Uses the exact version without a prefix.
|
||||
- `"~"`: Specifies compatibility with patch-level updates.
|
||||
- `"^"`: Specifies compatibility with minor-level updates.
|
||||
@ -53,16 +53,20 @@ You can set `versionPrefix` to one of the following values:
|
||||
|
||||
Example configuration:
|
||||
|
||||
{% callout type="note" title="Breaking Changes in Nx 21" %}
|
||||
In Nx v21, the configuration structure has changed. The example below shows the Nx 21 format.
|
||||
|
||||
For Nx 20, wrap the `versionPrefix` option inside a `generatorOptions` object.
|
||||
{% /callout %}
|
||||
|
||||
```json
|
||||
{
|
||||
"release": {
|
||||
"version": {
|
||||
"generatorOptions": {
|
||||
"versionPrefix": "~"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Configuring Version Prefix in `nx.json` or `project.json`
|
||||
@ -73,12 +77,10 @@ To set the versionPrefix option globally or for a specific project, add it to ei
|
||||
{
|
||||
"release": {
|
||||
"version": {
|
||||
"generatorOptions": {
|
||||
"versionPrefix": "^" // or "", "~", "^", "=" depending on your preference
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
With the `versionPrefix` option set to `^`, your `package.json` dependencies might look like this:
|
||||
|
||||
@ -61,7 +61,7 @@ The project configuration for Nx Release is in two parts - one for the version s
|
||||
|
||||
#### Update the Version Step
|
||||
|
||||
The version step of Nx Release is responsible for determining the new version of the package. If you have set the `version.generatorOptions.currentVersionResolver` to 'registry', then Nx Release will check the remote registry for the current version of the package.
|
||||
The version step of Nx Release is responsible for determining the new version of the package. If you have set the `version.currentVersionResolver` to 'registry', then Nx Release will check the remote registry for the current version of the package.
|
||||
|
||||
**Note:** If you do not use the 'registry' current version resolver, then this step is not needed.
|
||||
|
||||
@ -76,7 +76,6 @@ To set custom registry options for the current version lookup, add the registry
|
||||
},
|
||||
"release": {
|
||||
"version": {
|
||||
"generatorOptions": {
|
||||
"currentVersionResolverMetadata": {
|
||||
"registry": "https://my-unique-registry.com/",
|
||||
"tag": "next"
|
||||
@ -84,7 +83,6 @@ To set custom registry options for the current version lookup, add the registry
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Update the Publish Step
|
||||
|
||||
@ -62,11 +62,6 @@ nx release --first-release --dry-run
|
||||
Nx Release will prompt you to pick a version bump for all the packages in the release. By default, all package versions are kept in sync, so the prompt only needs to be answered one time. If needed, you can [configure Nx to release projects independently](/recipes/nx-release/release-projects-independently).
|
||||
|
||||
```text {% command="nx release --first-release --dry-run" %}
|
||||
|
||||
NX Running release version for project: pkg-1
|
||||
|
||||
pkg-1 🔍 Reading data for package "@myorg/pkg-1" from packages/pkg-1/package.json
|
||||
pkg-1 📄 Resolved the current version as 0.0.1 from packages/pkg-1/package.json
|
||||
? What kind of change is this for the 3 matched projects(s)? …
|
||||
❯ major
|
||||
premajor
|
||||
@ -86,23 +81,21 @@ After this prompt, the command will finish, showing you the preview of changes t
|
||||
|
||||
NX Running release version for project: pkg-1
|
||||
|
||||
pkg-1 🔍 Reading data for package "@myorg/pkg-1" from packages/pkg-1/package.json
|
||||
pkg-1 📄 Resolved the current version as 0.0.1 from packages/pkg-1/package.json
|
||||
✔ What kind of change is this for the 3 matched projects(s)? · patch
|
||||
pkg-1 ✍️ New version 0.0.2 written to packages/pkg-1/package.json
|
||||
pkg-1 📄 Resolved the current version as 0.0.1 from manifest: packages/pkg-1/package.json
|
||||
pkg-1 ❓ Applied semver relative bump "major", from the prompted specifier, to get new version 1.0.0
|
||||
pkg-1 ✍️ New version 1.0.0 written to manifest: packages/pkg-1/package.json
|
||||
|
||||
NX Running release version for project: pkg-2
|
||||
|
||||
pkg-2 🔍 Reading data for package "@myorg/pkg-2" from packages/pkg-2/package.json
|
||||
pkg-2 📄 Resolved the current version as 0.0.1 from packages/pkg-2/package.json
|
||||
pkg-2 ✍️ New version 0.0.2 written to packages/pkg-2/package.json
|
||||
pkg-2 ✍️ Applying new version 0.0.2 to 1 package which depends on pkg-2
|
||||
pkg-2 📄 Resolved the current version as 0.0.1 from manifest: packages/pkg-2/package.json
|
||||
pkg-2 ❓ Applied version 1.0.0 directly, because the project is a member of a fixed release group containing pkg-1
|
||||
pkg-2 ✍️ New version 1.0.0 written to manifest: packages/pkg-2/package.json
|
||||
|
||||
NX Running release version for project: pkg-3
|
||||
|
||||
pkg-3 🔍 Reading data for package "@myorg/pkg-3" from packages/pkg-3/package.json
|
||||
pkg-3 📄 Resolved the current version as 0.0.1 from packages/pkg-3/package.json
|
||||
pkg-3 ✍️ New version 0.0.2 written to packages/pkg-3/package.json
|
||||
pkg-3 📄 Resolved the current version as 0.0.1 from manifest: packages/pkg-3/package.json
|
||||
pkg-3 ❓ Applied version 1.0.0 directly, because the project is a member of a fixed release group containing pkg-1
|
||||
pkg-3 ✍️ New version 1.0.0 written to manifest: packages/pkg-3/package.json
|
||||
|
||||
UPDATE packages/pkg-1/package.json [dry-run]
|
||||
|
||||
|
||||
@ -9,6 +9,14 @@ This recipe guides you through versioning Rust libraries, generating changelogs,
|
||||
|
||||
{% github-repository url="https://github.com/JamesHenry/release-js-and-rust" /%}
|
||||
|
||||
{% callout type="caution" title="Currently requires legacy versioning" %}
|
||||
In Nx v21, the implementation details of versioning were rewritten to enhance flexibility and allow for better cross-ecosystem support. An automated migration was provided in Nx v21 to update your configuration to the new format when running `nx migrate`.
|
||||
|
||||
During the lifecycle of Nx v21, you can still opt into the old versioning by setting `release.version.useLegacyVersioning` to `true`, which will keep the original configuration structure and behavior. In Nx v22, the legacy versioning implementation will be removed entirely, so this should only be done temporarily to ease the transition.
|
||||
|
||||
Importantly, this recipe currently requires the use of legacy versioning, because the `@monodon/rust` plugin does not yet provide the necessary `VersionActions` implementation to support the new versioning behavior. This will be added in a minor release of Nx v21 and this recipe will be updated accordingly.
|
||||
{% /callout %}
|
||||
|
||||
## Initialize Nx Release in Your Workspace
|
||||
|
||||
### Install Nx
|
||||
@ -35,10 +43,14 @@ Configure which projects to release by adding the `release.projects` property to
|
||||
|
||||
For example, to release just the projects in the `crates` directory:
|
||||
|
||||
```json nx.json
|
||||
```jsonc nx.json
|
||||
{
|
||||
"release": {
|
||||
"projects": ["crates/*"]
|
||||
"projects": ["crates/*"],
|
||||
"version": {
|
||||
// Legacy versioning is currently required for the @monodon/rust plugin, see the note above for more details
|
||||
"useLegacyVersioning": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@ -72,7 +72,7 @@ export default async () => {
|
||||
gitCommit: false,
|
||||
gitTag: false,
|
||||
firstRelease: true,
|
||||
generatorOptionsOverrides: {
|
||||
versionActionsOptionsOverrides: {
|
||||
skipLockFileUpdate: true,
|
||||
},
|
||||
});
|
||||
|
||||
@ -9,7 +9,15 @@ The versioning stage of Nx Release is customizable and programming language agno
|
||||
|
||||
Nx provides the TypeScript/JavaScript (and therefore `package.json`) functionality out of the box, so that is what will be covered in more detail in this recipe. For other ecosystems, please see the documentation of the respective plugins.
|
||||
|
||||
An important characteristic of Nx release is that it does not manipulate your packages in memory before releasing them. This maintains complete transparency between you and the tooling being leveraged to publish your packages, such as `npm publish` or `pnpm publish`, which are leveraged automatically by Nx Release during its publishing phase. The relevance of this will become clear for [Scenario 3 below](#scenario-3-i-want-to-update-package-versions-directly-in-my-source-files-but-use-local-dependency-references-via-fileworkspace).
|
||||
An important characteristic of Nx release is that it does not directly manipulate your packages in memory before releasing them. This maintains complete transparency between you and the tooling being leveraged to publish your packages, such as `npm publish` or `pnpm publish`, which are leveraged automatically by Nx Release during its publishing phase. The relevance of this will become clear for [Scenario 4 below](#scenario-4-i-want-to-update-package-versions-directly-in-my-source-files-but-use-local-dependency-references-via-fileworkspace).
|
||||
|
||||
{% callout type="note" title="Breaking Changes in Nx v21" %}
|
||||
In Nx v21, the implementation details of versioning were rewritten to enhance flexibility and allow for better cross-ecosystem support. An automated migration was provided in Nx v21 to update your configuration to the new format when running `nx migrate`.
|
||||
|
||||
During the lifecycle of Nx v21, you can still opt into the old versioning by setting `release.version.useLegacyVersioning` to `true`, which will keep the original configuration structure and behavior. In Nx v22, the legacy versioning implementation will be removed entirely, so this should only be done temporarily to ease the transition.
|
||||
|
||||
The following examples shows the Nx v21 configuration format, you can view the v20 version of the website to see the legacy format.
|
||||
{% /callout %}
|
||||
|
||||
## Scenario 1: I want to update semantic version numbers directly in my source package.json files
|
||||
|
||||
@ -65,25 +73,28 @@ When running `nx release` and applying a patch release, the following changes wi
|
||||
|
||||
By default, the changes will be staged and committed unless git operations are disabled.
|
||||
|
||||
## Scenario 2: I want to publish from a custom dist directory and not update references in my source package.json files
|
||||
## Scenario 2: I want to publish from a custom dist directory and update references in my both my source and dist package.json files
|
||||
|
||||
Nx Release has the concept of a "package root", which is different than the project root. The package root is the directory from which the package is versioned and published. By default, the package root is the project root detected by Nx as we have seen in Scenario 1 above, but the package root can be configured independently for the versioning and publishing steps.
|
||||
Nx Release has the concept of a "manifest root", which is different than the project root. The manifest root is the directory from which the project is versioned. By default, the manifest root is the project root detected by Nx as we have seen in Scenario 1 above, but the manifest root can be configured independently to be one or more other locations than the project root.
|
||||
|
||||
If we want to build our projects to a centralized `dist/` directory in the Nx workspace, we can tell Nx Release to discover it for the versioning and publishing steps by adding the following configuration to the `nx.json` file, or the `project.json` file of relevant projects:
|
||||
As of Nx v21, multiple manifest roots can be configured using the `release.version.manifestRootsToUpdate` option, resulting in multiple manifest files (such as `package.json`) being updated at once for a single project during a the versioning phase.
|
||||
|
||||
{% callout type="warning" title="The source control tracked package.json files are no longer the source of truth for the package version" %}
|
||||
Because we are no longer updating the version references in the source package.json files, the source control tracked package.json files are no longer the source of truth for the package version. We need to reference git tags or the latest value in the registry as the source of truth for the package version instead. We will also need to handle intra-workspace dependency references in the source package.json files differently using file/workspace references, which will be covered below.
|
||||
{% /callout %}
|
||||
If, for example, we want to build our projects to a centralized `dist/` directory in the Nx workspace, and update both the source and dist package.json files when versioning, we can tell Nx Release to discover it for the versioning and publishing steps by adding the following configuration to the `nx.json` file, or the `project.json` file of relevant projects:
|
||||
|
||||
```jsonc {% fileName="nx.json" %}
|
||||
{
|
||||
"release": {
|
||||
// Ensure that versioning works from the dist directory
|
||||
// Ensure that versioning works in both the source and dist directories
|
||||
"version": {
|
||||
"generatorOptions": {
|
||||
"packageRoot": "dist/packages/{projectName}", // path structure for your dist directory, where {projectRoot} and {projectName} are available placeholders that will be interpolated by Nx
|
||||
"currentVersionResolver": "git-tag" // or "registry", because we are no longer referencing our source package.json as the source of truth for the current version
|
||||
// path structures for both the source and dist directories, where {projectRoot} and {projectName} are available placeholders that will be interpolated by Nx
|
||||
"manifestRootsToUpdate": [
|
||||
"{projectRoot}",
|
||||
// We use the object form of the manifestRootsToUpdate to specify that we want to update the dist package.json files and not preserve the local dependency references (if not using pnpm or bun)
|
||||
{
|
||||
"path": "dist/packages/{projectName}",
|
||||
"preserveLocalDependencyProtocols": false // (NOT NEEDED WHEN USING pnpm or bun) because we need to ensure our dist package.json files are valid for publishing and the local dependency references such as "workspace:" and "file:" are removed
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"targetDefaults": {
|
||||
@ -91,6 +102,7 @@ Because we are no longer updating the version references in the source package.j
|
||||
// The nx-release-publish target is added implicitly behind the scenes by Nx Release, and we can therefore configure it in targetDefaults
|
||||
"nx-release-publish": {
|
||||
"options": {
|
||||
// the packageRoot property is specific the TS/JS nx-release-publish implementation, other ecosystem plugins may have different options
|
||||
"packageRoot": "dist/packages/{projectName}" // path structure for your dist directory, where {projectRoot} and {projectName} are available placeholders that will be interpolated by Nx
|
||||
}
|
||||
}
|
||||
@ -98,6 +110,14 @@ Because we are no longer updating the version references in the source package.j
|
||||
}
|
||||
```
|
||||
|
||||
## Scenario 3: I want to publish from a custom dist directory and not update references in my source package.json files
|
||||
|
||||
A slight modification of Scenario 2 above, where we want to publish from a custom dist directory and not update references in our source package.json files.
|
||||
|
||||
{% callout type="warning" title="The source control tracked package.json files are no longer the source of truth for the package version" %}
|
||||
Because we are no longer updating the version references in the source package.json files, the source control tracked package.json files are no longer the source of truth for the package version. We need to reference git tags or the latest value in the registry as the source of truth for the package version instead. We will also need to handle intra-workspace dependency references in the source package.json files differently using file/workspace references, which will be covered below.
|
||||
{% /callout %}
|
||||
|
||||
Because our source package.json files are no longer updated during versioning, we will need to handle intra-workspace dependency references in the source package.json files differently. The way to achieve this is by using local `file:` or `workspace:` references in the source package.json files.
|
||||
|
||||
For example, using our packages from Scenario 1 above, if we want to reference the `my-other-project-in-the-monorepo` project from `my-project`, we can update the source package.json file as follows:
|
||||
@ -111,33 +131,55 @@ For example, using our packages from Scenario 1 above, if we want to reference t
|
||||
}
|
||||
```
|
||||
|
||||
This reference will never need to change when versioning is carried out and the package manager will reliably link the two packages together (and tools like TypeScript can follow these references for import resolution etc).
|
||||
If the package manager we are using is not using pnpm or bun (See Scenario 4 below), we will need to let Nx release know that we want to overwrite the workspace reference with the actual version number when publishing, because since Nx v21 it will preserve them by default. We can do this by setting the `release.version.preserveLocalDependencyProtocols` option to `false` in the `nx.json` file:
|
||||
|
||||
Our dist package.json will therefore ultimately look like this:
|
||||
```jsonc {% fileName="nx.json" %}
|
||||
{
|
||||
"release": {
|
||||
// Ensure that versioning works only in the dist directory
|
||||
"version": {
|
||||
"manifestRootsToUpdate": ["dist/packages/{projectName}"], // path structure for your dist directory, where {projectRoot} and {projectName} are available placeholders that will be interpolated by Nx
|
||||
"currentVersionResolver": "git-tag", // or "registry", because we are no longer referencing our source package.json as the source of truth for the current version
|
||||
"preserveLocalDependencyProtocols": false // (NOT NEEDED WHEN USING pnpm or bun) because we need to ensure our dist package.json files are valid for publishing and the local dependency references are removed
|
||||
}
|
||||
},
|
||||
"targetDefaults": {
|
||||
// Ensure that publishing works from the dist directory
|
||||
// The nx-release-publish target is added implicitly behind the scenes by Nx Release, and we can therefore configure it in targetDefaults
|
||||
"nx-release-publish": {
|
||||
"options": {
|
||||
"packageRoot": "dist/packages/{projectName}" // path structure for your dist directory, where {projectRoot} and {projectName} are available placeholders that will be interpolated by Nx
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
After applying a patch version, our dist package.json will therefore ultimately look like this:
|
||||
|
||||
```jsonc {% fileName="dist/packages/my-project/package.json" %}
|
||||
{
|
||||
"name": "my-project",
|
||||
"version": "0.1.2", // the version number is applied
|
||||
"dependencies": {
|
||||
"my-other-project-in-the-monorepo": "0.1.2" // the dependency reference is updated from the workspace reference to the actual version number
|
||||
"my-other-project-in-the-monorepo": "0.1.2" // the dependency reference is updated from the workspace reference to the actual version number (if not using pnpm or bun)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This package.json is now valid and ready to be published to the registry.
|
||||
This package.json is now valid and ready to be published to the registry with any package manager.
|
||||
|
||||
## Scenario 3: I want to update package versions directly in my source files, but use local dependency references via file/workspace
|
||||
## Scenario 4: I want to update package versions directly in my source files, but use local dependency references via file/workspace
|
||||
|
||||
{% callout type="caution" title="This scenario is currently only supported when your package manager is pnpm or bun" %}
|
||||
{% callout type="caution" title="This scenario is currently only fully supported when your package manager is pnpm or bun" %}
|
||||
pnpm and bun are the only package managers that provide a publish command that both supports dynamically swapping the `file:` and `workspace:*` references with the actual version number at publish time, and provides the customization needed for us to wrap it. `yarn npm publish` does support the replacements but is very limited on customization options.
|
||||
{% /callout %}
|
||||
|
||||
This is a more advanced scenario because it removes the clean separation of concerns between versioning and publishing. The reason for this is that the `file:` and `workspace:` references simply have to be replaced with actual version numbers before they are written to the registry, otherwise they will break when a user tries to install the package. If versioning does not replace them, publishing needs to.
|
||||
This is a more advanced scenario because it removes the clean separation of concerns between versioning and publishing. The reason for this is that the `file:` and `workspace:*` references simply have to be replaced with actual version numbers before they are written to the registry, otherwise they will break when a user tries to install the package. If versioning does not replace them, publishing needs to.
|
||||
|
||||
As mentioned at the start of this recipe, Nx Release intentionally does not manipulate your packages in memory during publishing, so this scenario is only supported when your package manager provides publishing functionality which dynamically swaps the local references. **Currently this is only supported by pnpm and bun.**
|
||||
|
||||
Let's first look at the default behavior of Nx Release, which is to update the all version references in the source package.json files with the new version number.
|
||||
As of Nx v21, by default, `release.version.preserveLocalDependencyProtocols` is set to `true`, which means that `file:` and `workspace:*` references are preserved.
|
||||
|
||||
For example, using this source package.json file, when applying a patch release:
|
||||
|
||||
@ -151,38 +193,7 @@ For example, using this source package.json file, when applying a patch release:
|
||||
}
|
||||
```
|
||||
|
||||
Nx release will see this and update the "version" number to `0.1.3`, and want to replace the `workspace:*` reference with the actual version number of the dependency - also `0.1.3`. This cleanly prepares the package.json ready to be published:
|
||||
|
||||
```jsonc {% fileName="packages/my-project/package.json" %}
|
||||
{
|
||||
"name": "my-project",
|
||||
"version": "0.1.3",
|
||||
"dependencies": {
|
||||
// whilst this is now ready to publish, it is not really what we wanted to happen,
|
||||
// because we have now hardcoded the version number in the source package.json file
|
||||
// and we have lost the evergreen "workspace:*" reference
|
||||
"my-other-project-in-the-monorepo": "0.1.3"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Now Nx release can publish this and your package will work for all its consumers, but you have the side-effect of having hardcoded the version number in the source package.json file. This is exactly what we covered in [Scenario 1 above](#scenario-1-i-want-to-update-semantic-version-numbers-directly-in-my-source-packagejson-files).
|
||||
|
||||
To instead configure Nx Release to not update the dependency references in the source package.json files, you can set the "preserveLocalDependencyProtocols" version generator option to `true`:
|
||||
|
||||
```jsonc {% fileName="nx.json" %}
|
||||
{
|
||||
"release": {
|
||||
"version": {
|
||||
"generatorOptions": {
|
||||
"preserveLocalDependencyProtocols": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Now, that same patch release to the source package.json file will result in the following:
|
||||
Nx release will see this and update the "version" number to `0.1.3`, and leave the `workspace:*` reference alone:
|
||||
|
||||
```jsonc {% fileName="packages/my-project/package.json" %}
|
||||
{
|
||||
|
||||
@ -44,10 +44,7 @@ The following is an expanded example showing all options. Your `nx.json` will li
|
||||
},
|
||||
"release": {
|
||||
"version": {
|
||||
"generatorOptions": {
|
||||
"currentVersionResolver": "git-tag",
|
||||
"specifierSource": "conventional-commits"
|
||||
}
|
||||
"conventionalCommits": true
|
||||
},
|
||||
"changelog": {
|
||||
"git": {
|
||||
@ -397,29 +394,38 @@ The default `"releaseTagPattern"` for independent releases at the project level
|
||||
|
||||
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.
|
||||
{% callout type="note" title="Breaking Changes in Nx v21" %}
|
||||
In Nx v21, the implementation details of versioning were rewritten to enhance flexibility and allow for better cross-ecosystem support. An automated migration was provided in Nx v21 to update your configuration to the new format when running `nx migrate`.
|
||||
|
||||
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`:
|
||||
During the lifecycle of Nx v21, you can still opt into the old versioning by setting `release.version.useLegacyVersioning` to `true`, which will keep the original configuration structure and behavior. In Nx v22, the legacy versioning implementation will be removed entirely, so this should only be done temporarily to ease the transition.
|
||||
{% /callout %}
|
||||
|
||||
Behind the scenes, ecosystem-specific `version` logic is powered by a `VersionActions` implementation. Out of the box Nx wires up the most widely applicable `VersionActions` implementation for you, which is `@nx/js/src/release/version-actions` provided by the `@nx/js` plugin.
|
||||
|
||||
Core version options are therefore directly at the top level of the `version` property (as of Nx v21), while ecosystem-specific options are available through `versionActionsOptions`:
|
||||
|
||||
```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"
|
||||
// Core options
|
||||
"conventionalCommits": true,
|
||||
"manifestRootsToUpdate": ["dist/packages/{projectName}"],
|
||||
// Ecosystem-specific options
|
||||
"versionActionsOptions": {
|
||||
"skipLockFileUpdate": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
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).
|
||||
Some important changes in Nx 21:
|
||||
|
||||
- The `release.version.generatorOptions` object has been removed, with its properties moved to the top level of `release.version`
|
||||
- `packageRoot` has been replaced by the more flexible `manifestRootsToUpdate` array
|
||||
- Ecosystem-specific options like `skipLockFileUpdate` are now under `versionActionsOptions`
|
||||
- `preserveLocalDependencyProtocols` (also now at the top level)now defaults to `true` (previously `false` when it was a generatorOption)
|
||||
|
||||
### Changelog
|
||||
|
||||
|
||||
@ -11,7 +11,7 @@ import {
|
||||
updateJson,
|
||||
} from '@nx/e2e/utils';
|
||||
import { execSync } from 'child_process';
|
||||
import { NxReleaseVersionV2Configuration } from 'nx/src/config/nx-json';
|
||||
import { NxReleaseVersionConfiguration } from 'nx/src/config/nx-json';
|
||||
import type { PackageJson } from 'nx/src/utils/package-json';
|
||||
|
||||
describe('nx release - custom npm registries', () => {
|
||||
@ -378,7 +378,7 @@ describe('nx release - custom npm registries', () => {
|
||||
|
||||
updateJson<ProjectConfiguration>(`${projectName}/project.json`, (json) => {
|
||||
const releaseConfig = (json.release ?? {}) as {
|
||||
version: NxReleaseVersionV2Configuration;
|
||||
version: NxReleaseVersionConfiguration;
|
||||
};
|
||||
|
||||
if (options.projectConfig) {
|
||||
|
||||
@ -19,7 +19,7 @@ import {
|
||||
updateJson,
|
||||
} from '@nx/e2e/utils';
|
||||
import { execSync } from 'node:child_process';
|
||||
import type { NxReleaseVersionV2Configuration } from 'nx/src/config/nx-json';
|
||||
import type { NxReleaseVersionConfiguration } from 'nx/src/config/nx-json';
|
||||
|
||||
expect.addSnapshotSerializer({
|
||||
serialize(str: string) {
|
||||
@ -1128,7 +1128,7 @@ describe('nx release', () => {
|
||||
|
||||
updateJson<NxJsonConfiguration>('nx.json', (nxJson) => {
|
||||
(
|
||||
nxJson.release.version as NxReleaseVersionV2Configuration
|
||||
nxJson.release.version as NxReleaseVersionConfiguration
|
||||
).fallbackCurrentVersionResolver = 'disk';
|
||||
return nxJson;
|
||||
});
|
||||
@ -1149,14 +1149,14 @@ describe('nx release', () => {
|
||||
|
||||
updateJson<NxJsonConfiguration>('nx.json', (nxJson) => {
|
||||
(
|
||||
nxJson.release.version as NxReleaseVersionV2Configuration
|
||||
nxJson.release.version as NxReleaseVersionConfiguration
|
||||
).currentVersionResolver = 'registry';
|
||||
(
|
||||
nxJson.release.version as NxReleaseVersionV2Configuration
|
||||
nxJson.release.version as NxReleaseVersionConfiguration
|
||||
).currentVersionResolverMetadata = {
|
||||
tag: 'other',
|
||||
};
|
||||
delete (nxJson.release.version as NxReleaseVersionV2Configuration)
|
||||
delete (nxJson.release.version as NxReleaseVersionConfiguration)
|
||||
.fallbackCurrentVersionResolver;
|
||||
return nxJson;
|
||||
});
|
||||
@ -1197,7 +1197,7 @@ describe('nx release', () => {
|
||||
|
||||
updateJson<NxJsonConfiguration>('nx.json', (nxJson) => {
|
||||
(
|
||||
nxJson.release.version as NxReleaseVersionV2Configuration
|
||||
nxJson.release.version as NxReleaseVersionConfiguration
|
||||
).fallbackCurrentVersionResolver = 'disk';
|
||||
return nxJson;
|
||||
});
|
||||
|
||||
@ -40,7 +40,7 @@
|
||||
"parallel": false
|
||||
}
|
||||
},
|
||||
"e2e": {
|
||||
"DISABLED__e2e": {
|
||||
"executor": "nx:run-commands",
|
||||
"outputs": [],
|
||||
"options": {
|
||||
|
||||
@ -10,7 +10,7 @@ import {
|
||||
import { exec } from 'node:child_process';
|
||||
import { join } from 'node:path';
|
||||
import { AfterAllProjectsVersioned, VersionActions } from 'nx/release';
|
||||
import type { NxReleaseVersionV2Configuration } from 'nx/src/config/nx-json';
|
||||
import type { NxReleaseVersionConfiguration } from 'nx/src/config/nx-json';
|
||||
import { parseRegistryOptions } from '../utils/npm-config';
|
||||
import { updateLockFile } from './utils/update-lock-file';
|
||||
import chalk = require('chalk');
|
||||
@ -61,7 +61,7 @@ export default class JsVersionActions extends VersionActions {
|
||||
|
||||
async readCurrentVersionFromRegistry(
|
||||
tree: Tree,
|
||||
currentVersionResolverMetadata: NxReleaseVersionV2Configuration['currentVersionResolverMetadata']
|
||||
currentVersionResolverMetadata: NxReleaseVersionConfiguration['currentVersionResolverMetadata']
|
||||
): Promise<{
|
||||
currentVersion: string;
|
||||
logText: string;
|
||||
@ -161,8 +161,91 @@ export default class JsVersionActions extends VersionActions {
|
||||
};
|
||||
}
|
||||
|
||||
async updateProjectVersion(
|
||||
tree: Tree,
|
||||
newVersion: string
|
||||
): Promise<string[]> {
|
||||
const logMessages: string[] = [];
|
||||
for (const manifestToUpdate of this.manifestsToUpdate) {
|
||||
updateJson(tree, manifestToUpdate.manifestPath, (json) => {
|
||||
json.version = newVersion;
|
||||
return json;
|
||||
});
|
||||
logMessages.push(
|
||||
`✍️ New version ${newVersion} written to manifest: ${manifestToUpdate.manifestPath}`
|
||||
);
|
||||
}
|
||||
return logMessages;
|
||||
}
|
||||
|
||||
async updateProjectDependencies(
|
||||
tree: Tree,
|
||||
projectGraph: ProjectGraph,
|
||||
dependenciesToUpdate: Record<string, string>
|
||||
): Promise<string[]> {
|
||||
let numDependenciesToUpdate = Object.keys(dependenciesToUpdate).length;
|
||||
if (numDependenciesToUpdate === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const logMessages: string[] = [];
|
||||
for (const manifestToUpdate of this.manifestsToUpdate) {
|
||||
updateJson(tree, manifestToUpdate.manifestPath, (json) => {
|
||||
const dependencyTypes = [
|
||||
'dependencies',
|
||||
'devDependencies',
|
||||
'peerDependencies',
|
||||
'optionalDependencies',
|
||||
];
|
||||
|
||||
for (const depType of dependencyTypes) {
|
||||
if (json[depType]) {
|
||||
for (const [dep, version] of Object.entries(dependenciesToUpdate)) {
|
||||
// Resolve the package name from the project graph metadata, as it may not match the project name
|
||||
const packageName =
|
||||
projectGraph.nodes[dep].data.metadata?.js?.packageName;
|
||||
if (!packageName) {
|
||||
throw new Error(
|
||||
`Unable to determine the package name for project "${dep}" from the project graph metadata, please ensure that the "@nx/js" plugin is installed and the project graph has been built. If the issue persists, please report this issue on https://github.com/nrwl/nx/issues`
|
||||
);
|
||||
}
|
||||
const currentVersion = json[depType][packageName];
|
||||
if (currentVersion) {
|
||||
// Check if the local dependency protocol should be preserved or not
|
||||
if (
|
||||
manifestToUpdate.preserveLocalDependencyProtocols &&
|
||||
this.isLocalDependencyProtocol(currentVersion)
|
||||
) {
|
||||
// Reduce the count appropriately to avoid confusing user-facing logs
|
||||
numDependenciesToUpdate--;
|
||||
continue;
|
||||
}
|
||||
json[depType][packageName] = version;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return json;
|
||||
});
|
||||
|
||||
// If we ignored local dependecy protocols, then we could have dynamically ended up with zero here and we should not log anything related to dependencies
|
||||
if (numDependenciesToUpdate === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const depText =
|
||||
numDependenciesToUpdate === 1 ? 'dependency' : 'dependencies';
|
||||
|
||||
logMessages.push(
|
||||
`✍️ Updated ${numDependenciesToUpdate} ${depText} in manifest: ${manifestToUpdate.manifestPath}`
|
||||
);
|
||||
}
|
||||
return logMessages;
|
||||
}
|
||||
|
||||
// NOTE: The TODOs were carried over from the original implementation, they are not yet implemented
|
||||
async isLocalDependencyProtocol(versionSpecifier: string): Promise<boolean> {
|
||||
private isLocalDependencyProtocol(versionSpecifier: string): boolean {
|
||||
const localPackageProtocols = [
|
||||
'file:', // all package managers
|
||||
'workspace:', // not npm
|
||||
@ -203,71 +286,4 @@ export default class JsVersionActions extends VersionActions {
|
||||
// }
|
||||
return true;
|
||||
}
|
||||
|
||||
async updateProjectVersion(
|
||||
tree: Tree,
|
||||
newVersion: string
|
||||
): Promise<string[]> {
|
||||
const logMessages: string[] = [];
|
||||
for (const manifestPath of this.manifestsToUpdate) {
|
||||
updateJson(tree, manifestPath, (json) => {
|
||||
json.version = newVersion;
|
||||
return json;
|
||||
});
|
||||
logMessages.push(
|
||||
`✍️ New version ${newVersion} written to manifest: ${manifestPath}`
|
||||
);
|
||||
}
|
||||
return logMessages;
|
||||
}
|
||||
|
||||
async updateProjectDependencies(
|
||||
tree: Tree,
|
||||
projectGraph: ProjectGraph,
|
||||
dependenciesToUpdate: Record<string, string>
|
||||
): Promise<string[]> {
|
||||
const numDependenciesToUpdate = Object.keys(dependenciesToUpdate).length;
|
||||
const depText =
|
||||
numDependenciesToUpdate === 1 ? 'dependency' : 'dependencies';
|
||||
if (numDependenciesToUpdate === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const logMessages: string[] = [];
|
||||
for (const manifestPath of this.manifestsToUpdate) {
|
||||
updateJson(tree, manifestPath, (json) => {
|
||||
const dependencyTypes = [
|
||||
'dependencies',
|
||||
'devDependencies',
|
||||
'peerDependencies',
|
||||
'optionalDependencies',
|
||||
];
|
||||
|
||||
for (const depType of dependencyTypes) {
|
||||
if (json[depType]) {
|
||||
for (const [dep, version] of Object.entries(dependenciesToUpdate)) {
|
||||
// Resolve the package name from the project graph metadata, as it may not match the project name
|
||||
const packageName =
|
||||
projectGraph.nodes[dep].data.metadata?.js?.packageName;
|
||||
if (!packageName) {
|
||||
throw new Error(
|
||||
`Unable to determine the package name for project "${dep}" from the project graph metadata, please ensure that the "@nx/js" plugin is installed and the project graph has been built. If the issue persists, please report this issue on https://github.com/nrwl/nx/issues`
|
||||
);
|
||||
}
|
||||
if (json[depType][packageName]) {
|
||||
json[depType][packageName] = version;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return json;
|
||||
});
|
||||
|
||||
logMessages.push(
|
||||
`✍️ Updated ${numDependenciesToUpdate} ${depText} in manifest: ${manifestPath}`
|
||||
);
|
||||
}
|
||||
return logMessages;
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,7 +29,7 @@ export default async () => {
|
||||
gitCommit: false,
|
||||
gitTag: false,
|
||||
firstRelease: true,
|
||||
generatorOptionsOverrides: {
|
||||
versionActionsOptionsOverrides: {
|
||||
skipLockFileUpdate: true
|
||||
}
|
||||
});
|
||||
|
||||
@ -63,6 +63,11 @@
|
||||
"description": "Set `useLegacyCache` to true for migrating workspaces",
|
||||
"implementation": "./src/migrations/update-20-0-1/use-legacy-cache",
|
||||
"x-repair-skip": true
|
||||
},
|
||||
"release-version-config-changes": {
|
||||
"version": "21.0.0-beta.1",
|
||||
"description": "Updates release version config based on the breaking changes in Nx v21",
|
||||
"implementation": "./src/migrations/update-21-0-0/release-version-config-changes"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -707,49 +707,17 @@
|
||||
"$comment": "When using the latest versioning implementation a lot of configuration has been able to move directly onto the version property.",
|
||||
"properties": {
|
||||
"useLegacyVersioning": {
|
||||
"const": true
|
||||
"const": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"then": {
|
||||
"properties": {
|
||||
"useLegacyVersioning": {
|
||||
"type": "boolean",
|
||||
"description": "Whether to use the legacy versioning strategy. This value will be true in Nx v20 and false in Nx v21. The legacy versioning implementation will be removed in Nx v22, as will this flag.",
|
||||
"default": true
|
||||
},
|
||||
"conventionalCommits": {
|
||||
"type": "boolean",
|
||||
"description": "Shorthand for enabling the current version of projects to be resolved from git tags, and the next version to be determined by analyzing commit messages according to the Conventional Commits specification.",
|
||||
"default": false
|
||||
},
|
||||
"git": {
|
||||
"$ref": "#/definitions/NxReleaseGitConfiguration"
|
||||
},
|
||||
"preVersionCommand": {
|
||||
"type": "string",
|
||||
"description": "A command to run after validation of nx release configuration, but before versioning begins. Useful 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'."
|
||||
},
|
||||
"generator": {
|
||||
"type": "string",
|
||||
"description": "The generator implementation to use for versioning.",
|
||||
"default": "@nx/js:release-version"
|
||||
},
|
||||
"generatorOptions": {
|
||||
"type": "object",
|
||||
"description": "These options will be passed to the configured \"release.version.generator\" (which will be \"@nx/js:release-version\" if not set explicitly).",
|
||||
"additionalProperties": true
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"else": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"useLegacyVersioning": {
|
||||
"type": "boolean",
|
||||
"description": "Whether to use the legacy versioning strategy. This value will be true in Nx v20 and false in Nx v21. The legacy versioning implementation will be removed in Nx v22, as will this flag.",
|
||||
"default": true
|
||||
"default": false
|
||||
},
|
||||
"conventionalCommits": {
|
||||
"type": "boolean",
|
||||
@ -791,10 +759,6 @@
|
||||
"enum": ["disk"],
|
||||
"description": "The fallback version resolver to use when the configured currentVersionResolver fails to resolve the current version."
|
||||
},
|
||||
"firstRelease": {
|
||||
"type": "boolean",
|
||||
"description": "Whether or not this is the first release of one of more projects. This removes certain validation checks that are not possible to enforce if the project has never been released before."
|
||||
},
|
||||
"versionPrefix": {
|
||||
"type": "string",
|
||||
"enum": ["auto", "", "~", "^", "="],
|
||||
@ -833,6 +797,38 @@
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"else": {
|
||||
"properties": {
|
||||
"useLegacyVersioning": {
|
||||
"type": "boolean",
|
||||
"description": "Whether to use the legacy versioning strategy. This value was true in Nx v20 and became false in Nx v21. The legacy versioning implementation will be removed in Nx v22, as will this flag.",
|
||||
"default": false
|
||||
},
|
||||
"conventionalCommits": {
|
||||
"type": "boolean",
|
||||
"description": "Shorthand for enabling the current version of projects to be resolved from git tags, and the next version to be determined by analyzing commit messages according to the Conventional Commits specification.",
|
||||
"default": false
|
||||
},
|
||||
"git": {
|
||||
"$ref": "#/definitions/NxReleaseGitConfiguration"
|
||||
},
|
||||
"preVersionCommand": {
|
||||
"type": "string",
|
||||
"description": "A command to run after validation of nx release configuration, but before versioning begins. Useful 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'."
|
||||
},
|
||||
"generator": {
|
||||
"type": "string",
|
||||
"description": "The generator implementation to use for versioning.",
|
||||
"default": "@nx/js:release-version"
|
||||
},
|
||||
"generatorOptions": {
|
||||
"type": "object",
|
||||
"description": "These options will be passed to the configured \"release.version.generator\" (which will be \"@nx/js:release-version\" if not set explicitly).",
|
||||
"additionalProperties": true
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"NxReleaseGroupVersionConfiguration": {
|
||||
|
||||
@ -45,7 +45,13 @@ export type VersionOptions = NxReleaseArgs &
|
||||
specifier?: string;
|
||||
preid?: string;
|
||||
stageChanges?: boolean;
|
||||
/**
|
||||
* @deprecated Use versionActionsOptionsOverrides instead.
|
||||
*
|
||||
* Using generatorOptionsOverrides is only valid when release.version.useLegacyVersioning is set to true.
|
||||
*/
|
||||
generatorOptionsOverrides?: Record<string, unknown>;
|
||||
versionActionsOptionsOverrides?: Record<string, unknown>;
|
||||
};
|
||||
|
||||
export type ChangelogOptions = NxReleaseArgs &
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -19,7 +19,7 @@ import {
|
||||
NxReleaseChangelogConfiguration,
|
||||
NxReleaseConfiguration,
|
||||
NxReleaseGitConfiguration,
|
||||
NxReleaseVersionV2Configuration,
|
||||
NxReleaseVersionConfiguration,
|
||||
} from '../../../config/nx-json';
|
||||
import { ProjectFileMap, ProjectGraph } from '../../../config/project-graph';
|
||||
import { readJsonFile } from '../../../utils/fileutils';
|
||||
@ -286,23 +286,14 @@ export async function createNxReleaseConfig(
|
||||
defaultGeneratorOptions.currentVersionResolver,
|
||||
specifierSource: defaultGeneratorOptions.specifierSource,
|
||||
preserveLocalDependencyProtocols:
|
||||
(
|
||||
userConfig.version as
|
||||
| NxReleaseVersionV2Configuration
|
||||
| undefined
|
||||
)?.preserveLocalDependencyProtocols ?? true,
|
||||
(userConfig.version as NxReleaseVersionConfiguration | undefined)
|
||||
?.preserveLocalDependencyProtocols ?? true,
|
||||
logUnchangedProjects:
|
||||
(
|
||||
userConfig.version as
|
||||
| NxReleaseVersionV2Configuration
|
||||
| undefined
|
||||
)?.logUnchangedProjects ?? true,
|
||||
(userConfig.version as NxReleaseVersionConfiguration | undefined)
|
||||
?.logUnchangedProjects ?? true,
|
||||
updateDependents:
|
||||
(
|
||||
userConfig.version as
|
||||
| NxReleaseVersionV2Configuration
|
||||
| undefined
|
||||
)?.updateDependents ?? 'auto',
|
||||
(userConfig.version as NxReleaseVersionConfiguration | undefined)
|
||||
?.updateDependents ?? 'auto',
|
||||
}),
|
||||
} as DeepRequired<NxReleaseConfiguration['version']>,
|
||||
changelog: {
|
||||
@ -482,10 +473,10 @@ export async function createNxReleaseConfig(
|
||||
};
|
||||
} else {
|
||||
(
|
||||
rootVersionWithoutGlobalOptions as NxReleaseVersionV2Configuration
|
||||
rootVersionWithoutGlobalOptions as NxReleaseVersionConfiguration
|
||||
).currentVersionResolver = 'git-tag';
|
||||
(
|
||||
rootVersionWithoutGlobalOptions as NxReleaseVersionV2Configuration
|
||||
rootVersionWithoutGlobalOptions as NxReleaseVersionConfiguration
|
||||
).specifierSource = 'conventional-commits';
|
||||
}
|
||||
}
|
||||
@ -493,9 +484,9 @@ export async function createNxReleaseConfig(
|
||||
delete rootVersionWithoutGlobalOptions.generatorOptions
|
||||
.currentVersionResolver;
|
||||
delete rootVersionWithoutGlobalOptions.generatorOptions.specifierSource;
|
||||
delete (rootVersionWithoutGlobalOptions as NxReleaseVersionV2Configuration)
|
||||
delete (rootVersionWithoutGlobalOptions as NxReleaseVersionConfiguration)
|
||||
.currentVersionResolver;
|
||||
delete (rootVersionWithoutGlobalOptions as NxReleaseVersionV2Configuration)
|
||||
delete (rootVersionWithoutGlobalOptions as NxReleaseVersionConfiguration)
|
||||
.specifierSource;
|
||||
}
|
||||
|
||||
@ -508,13 +499,13 @@ export async function createNxReleaseConfig(
|
||||
};
|
||||
} else {
|
||||
(
|
||||
rootVersionWithoutGlobalOptions as NxReleaseVersionV2Configuration
|
||||
rootVersionWithoutGlobalOptions as NxReleaseVersionConfiguration
|
||||
).specifierSource = 'version-plans';
|
||||
}
|
||||
}
|
||||
if (userConfig.versionPlans === false) {
|
||||
delete rootVersionWithoutGlobalOptions.generatorOptions.specifierSource;
|
||||
delete (rootVersionWithoutGlobalOptions as NxReleaseVersionV2Configuration)
|
||||
delete (rootVersionWithoutGlobalOptions as NxReleaseVersionConfiguration)
|
||||
.specifierSource;
|
||||
}
|
||||
|
||||
@ -681,10 +672,10 @@ export async function createNxReleaseConfig(
|
||||
};
|
||||
} else {
|
||||
(
|
||||
finalReleaseGroup.version as NxReleaseVersionV2Configuration
|
||||
finalReleaseGroup.version as NxReleaseVersionConfiguration
|
||||
).currentVersionResolver = 'git-tag';
|
||||
(
|
||||
finalReleaseGroup.version as NxReleaseVersionV2Configuration
|
||||
finalReleaseGroup.version as NxReleaseVersionConfiguration
|
||||
).specifierSource = 'conventional-commits';
|
||||
}
|
||||
}
|
||||
@ -692,11 +683,14 @@ export async function createNxReleaseConfig(
|
||||
releaseGroup.version?.conventionalCommits === false &&
|
||||
releaseGroupName !== IMPLICIT_DEFAULT_RELEASE_GROUP
|
||||
) {
|
||||
delete finalReleaseGroup.version.generatorOptions.currentVersionResolver;
|
||||
delete finalReleaseGroup.version.generatorOptions.specifierSource;
|
||||
delete (finalReleaseGroup.version as NxReleaseVersionV2Configuration)
|
||||
if (USE_LEGACY_VERSIONING) {
|
||||
delete finalReleaseGroup.version.generatorOptions
|
||||
?.currentVersionResolver;
|
||||
delete finalReleaseGroup.version.generatorOptions?.specifierSource;
|
||||
}
|
||||
delete (finalReleaseGroup.version as NxReleaseVersionConfiguration)
|
||||
.currentVersionResolver;
|
||||
delete (finalReleaseGroup.version as NxReleaseVersionV2Configuration)
|
||||
delete (finalReleaseGroup.version as NxReleaseVersionConfiguration)
|
||||
.specifierSource;
|
||||
}
|
||||
|
||||
@ -712,7 +706,7 @@ export async function createNxReleaseConfig(
|
||||
};
|
||||
} else {
|
||||
(
|
||||
finalReleaseGroup.version as NxReleaseVersionV2Configuration
|
||||
finalReleaseGroup.version as NxReleaseVersionConfiguration
|
||||
).specifierSource = 'version-plans';
|
||||
}
|
||||
}
|
||||
@ -720,8 +714,10 @@ export async function createNxReleaseConfig(
|
||||
releaseGroup.versionPlans === false &&
|
||||
releaseGroupName !== IMPLICIT_DEFAULT_RELEASE_GROUP
|
||||
) {
|
||||
delete finalReleaseGroup.version.generatorOptions.specifierSource;
|
||||
delete (finalReleaseGroup.version as NxReleaseVersionV2Configuration)
|
||||
if (USE_LEGACY_VERSIONING) {
|
||||
delete finalReleaseGroup.version.generatorOptions?.specifierSource;
|
||||
}
|
||||
delete (finalReleaseGroup.version as NxReleaseVersionConfiguration)
|
||||
.specifierSource;
|
||||
}
|
||||
releaseGroups[releaseGroupName] = finalReleaseGroup;
|
||||
@ -1110,10 +1106,9 @@ function hasInvalidConventionalCommitsConfig(
|
||||
if (
|
||||
userConfig.version?.conventionalCommits === true &&
|
||||
// v2 config - directly on version config
|
||||
((userConfig.version as NxReleaseVersionV2Configuration)
|
||||
((userConfig.version as NxReleaseVersionConfiguration)
|
||||
?.currentVersionResolver ||
|
||||
(userConfig.version as NxReleaseVersionV2Configuration)
|
||||
?.specifierSource ||
|
||||
(userConfig.version as NxReleaseVersionConfiguration)?.specifierSource ||
|
||||
// Legacy config - on generatorOptions
|
||||
(userConfig.version as LegacyNxReleaseVersionConfiguration)
|
||||
?.generatorOptions?.currentVersionResolver ||
|
||||
@ -1128,9 +1123,9 @@ function hasInvalidConventionalCommitsConfig(
|
||||
if (
|
||||
group.version?.conventionalCommits === true &&
|
||||
// v2 config - directly on version config
|
||||
((group.version as NxReleaseVersionV2Configuration)
|
||||
((group.version as NxReleaseVersionConfiguration)
|
||||
?.currentVersionResolver ||
|
||||
(group.version as NxReleaseVersionV2Configuration)?.specifierSource ||
|
||||
(group.version as NxReleaseVersionConfiguration)?.specifierSource ||
|
||||
// Legacy config - on generatorOptions
|
||||
(group.version as LegacyNxReleaseVersionConfiguration)
|
||||
?.generatorOptions?.currentVersionResolver ||
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import type { NxJsonConfiguration } from '../../../config/nx-json';
|
||||
|
||||
// TODO(v22): remove this function and entire concept of legacy versioning in v22
|
||||
export function shouldUseLegacyVersioning(
|
||||
releaseConfig: NxJsonConfiguration['release'] | undefined
|
||||
) {
|
||||
return process.env.NX_INTERNAL_USE_LEGACY_VERSIONING === 'false'
|
||||
? false
|
||||
: // TODO(v21): switch this to false by default in Nx v21 and remove this function in v22
|
||||
releaseConfig?.version?.useLegacyVersioning ?? true;
|
||||
return process.env.NX_INTERNAL_USE_LEGACY_VERSIONING === 'true'
|
||||
? true
|
||||
: releaseConfig?.version?.useLegacyVersioning ?? false;
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@ import { execSync } from 'node:child_process';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import {
|
||||
NxReleaseConfiguration,
|
||||
NxReleaseVersionV2Configuration,
|
||||
NxReleaseVersionConfiguration,
|
||||
readNxJson,
|
||||
} from '../../config/nx-json';
|
||||
import { formatChangedFilesWithPrettierIfAvailable } from '../../generators/internal-utils/format-changed-files-with-prettier-if-available';
|
||||
@ -233,6 +233,7 @@ export function createAPI(overrideReleaseConfig: NxReleaseConfiguration) {
|
||||
projects: args.projects,
|
||||
groups: args.groups,
|
||||
},
|
||||
versionActionsOptionsOverrides: args.versionActionsOptionsOverrides,
|
||||
}
|
||||
);
|
||||
|
||||
@ -273,10 +274,11 @@ export function createAPI(overrideReleaseConfig: NxReleaseConfiguration) {
|
||||
printAndFlushChanges(tree, !!args.dryRun);
|
||||
|
||||
const { changedFiles: changed, deletedFiles: deleted } =
|
||||
await processor.afterAllProjectsVersioned(
|
||||
(nxReleaseConfig.version as NxReleaseVersionV2Configuration)
|
||||
.versionActionsOptions
|
||||
);
|
||||
await processor.afterAllProjectsVersioned({
|
||||
...(nxReleaseConfig.version as NxReleaseVersionConfiguration)
|
||||
.versionActionsOptions,
|
||||
...(args.versionActionsOptionsOverrides ?? {}),
|
||||
});
|
||||
changed.forEach((f) => additionalChangedFiles.add(f));
|
||||
deleted.forEach((f) => additionalDeletedFiles.add(f));
|
||||
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
import * as semver from 'semver';
|
||||
import { NxReleaseVersionV2Configuration } from '../../../config/nx-json';
|
||||
import {
|
||||
ManifestRootToUpdate,
|
||||
NxReleaseVersionConfiguration,
|
||||
} from '../../../config/nx-json';
|
||||
import {
|
||||
ProjectGraph,
|
||||
ProjectGraphProjectNode,
|
||||
@ -32,14 +35,15 @@ import {
|
||||
* and referenced throughout the versioning process.
|
||||
*/
|
||||
export interface FinalConfigForProject {
|
||||
specifierSource: NxReleaseVersionV2Configuration['specifierSource'];
|
||||
currentVersionResolver: NxReleaseVersionV2Configuration['currentVersionResolver'];
|
||||
currentVersionResolverMetadata: NxReleaseVersionV2Configuration['currentVersionResolverMetadata'];
|
||||
fallbackCurrentVersionResolver: NxReleaseVersionV2Configuration['fallbackCurrentVersionResolver'];
|
||||
versionPrefix: NxReleaseVersionV2Configuration['versionPrefix'];
|
||||
preserveLocalDependencyProtocols: NxReleaseVersionV2Configuration['preserveLocalDependencyProtocols'];
|
||||
versionActionsOptions: NxReleaseVersionV2Configuration['versionActionsOptions'];
|
||||
manifestRootsToUpdate: NxReleaseVersionV2Configuration['manifestRootsToUpdate'];
|
||||
specifierSource: NxReleaseVersionConfiguration['specifierSource'];
|
||||
currentVersionResolver: NxReleaseVersionConfiguration['currentVersionResolver'];
|
||||
currentVersionResolverMetadata: NxReleaseVersionConfiguration['currentVersionResolverMetadata'];
|
||||
fallbackCurrentVersionResolver: NxReleaseVersionConfiguration['fallbackCurrentVersionResolver'];
|
||||
versionPrefix: NxReleaseVersionConfiguration['versionPrefix'];
|
||||
preserveLocalDependencyProtocols: NxReleaseVersionConfiguration['preserveLocalDependencyProtocols'];
|
||||
versionActionsOptions: NxReleaseVersionConfiguration['versionActionsOptions'];
|
||||
// Consistently expanded to the object form for easier processing in VersionActions
|
||||
manifestRootsToUpdate: Array<Exclude<ManifestRootToUpdate, string>>;
|
||||
}
|
||||
|
||||
interface GroupNode {
|
||||
@ -80,6 +84,8 @@ interface ReleaseGroupProcessorOptions {
|
||||
projects?: string[];
|
||||
groups?: string[];
|
||||
};
|
||||
// Optional overrides that may be passed in from the programmatic API
|
||||
versionActionsOptionsOverrides?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export class ReleaseGroupProcessor {
|
||||
@ -384,7 +390,7 @@ export class ReleaseGroupProcessor {
|
||||
|
||||
// Cache updateDependents setting relevant for each project
|
||||
const updateDependents =
|
||||
((group.version as NxReleaseVersionV2Configuration)
|
||||
((group.version as NxReleaseVersionConfiguration)
|
||||
?.updateDependents as 'auto' | 'never') || 'auto';
|
||||
this.projectToUpdateDependentsSetting.set(project, updateDependents);
|
||||
}
|
||||
@ -1109,7 +1115,7 @@ export class ReleaseGroupProcessor {
|
||||
|
||||
private getCachedFinalConfigForProject(
|
||||
projectName: string
|
||||
): NxReleaseVersionV2Configuration {
|
||||
): NxReleaseVersionConfiguration {
|
||||
const cachedFinalConfig = this.finalConfigsByProject.get(projectName);
|
||||
if (!cachedFinalConfig) {
|
||||
throw new Error(
|
||||
@ -1128,10 +1134,10 @@ export class ReleaseGroupProcessor {
|
||||
projectGraphNode: ProjectGraphProjectNode
|
||||
): FinalConfigForProject {
|
||||
const releaseGroupVersionConfig = releaseGroup.version as
|
||||
| NxReleaseVersionV2Configuration
|
||||
| NxReleaseVersionConfiguration
|
||||
| undefined;
|
||||
const projectVersionConfig = projectGraphNode.data.release?.version as
|
||||
| NxReleaseVersionV2Configuration
|
||||
| NxReleaseVersionConfiguration
|
||||
| undefined;
|
||||
|
||||
/**
|
||||
@ -1210,15 +1216,30 @@ Valid values are: ${validReleaseVersionPrefixes
|
||||
/**
|
||||
* versionActionsOptions, defaults to {}
|
||||
*/
|
||||
const versionActionsOptions =
|
||||
let versionActionsOptions =
|
||||
projectVersionConfig?.versionActionsOptions ??
|
||||
releaseGroupVersionConfig?.versionActionsOptions ??
|
||||
{};
|
||||
// Apply any optional overrides that may be passed in from the programmatic API
|
||||
versionActionsOptions = {
|
||||
...versionActionsOptions,
|
||||
...(this.options.versionActionsOptionsOverrides ?? {}),
|
||||
};
|
||||
|
||||
const manifestRootsToUpdate =
|
||||
const manifestRootsToUpdate = (
|
||||
projectVersionConfig?.manifestRootsToUpdate ??
|
||||
releaseGroupVersionConfig?.manifestRootsToUpdate ??
|
||||
[];
|
||||
[]
|
||||
).map((manifestRoot) => {
|
||||
if (typeof manifestRoot === 'string') {
|
||||
return {
|
||||
path: manifestRoot,
|
||||
// Apply the project level preserveLocalDependencyProtocols setting that was already resolved
|
||||
preserveLocalDependencyProtocols,
|
||||
};
|
||||
}
|
||||
return manifestRoot;
|
||||
});
|
||||
|
||||
return {
|
||||
specifierSource,
|
||||
@ -1284,16 +1305,6 @@ Valid values are: ${validReleaseVersionPrefixes
|
||||
if (!currentDependencyVersion) {
|
||||
continue;
|
||||
}
|
||||
// If preserveLocalDependencyProtocols is true, and the dependency uses a local dependency protocol, skip updating the dependency
|
||||
if (
|
||||
cachedFinalConfigForProject.preserveLocalDependencyProtocols &&
|
||||
(await versionActions.isLocalDependencyProtocol(
|
||||
currentDependencyVersion
|
||||
))
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let finalPrefix = '';
|
||||
if (cachedFinalConfigForProject.versionPrefix === 'auto') {
|
||||
const prefixMatch = currentDependencyVersion?.match(/^([~^=])/);
|
||||
@ -1380,7 +1391,7 @@ Valid values are: ${validReleaseVersionPrefixes
|
||||
|
||||
const releaseGroup = this.groupGraph.get(releaseGroupName)!.group;
|
||||
const releaseGroupVersionConfig =
|
||||
releaseGroup.version as NxReleaseVersionV2Configuration;
|
||||
releaseGroup.version as NxReleaseVersionConfiguration;
|
||||
|
||||
// Get updateDependents from the release group level config
|
||||
const updateDependents =
|
||||
@ -1445,7 +1456,7 @@ Valid values are: ${validReleaseVersionPrefixes
|
||||
|
||||
// Get updateDependents from the release group level config
|
||||
const releaseGroupVersionConfig =
|
||||
releaseGroup.version as NxReleaseVersionV2Configuration;
|
||||
releaseGroup.version as NxReleaseVersionConfiguration;
|
||||
const updateDependents =
|
||||
(releaseGroupVersionConfig?.updateDependents as 'auto' | 'never') ||
|
||||
'auto';
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import * as enquirer from 'enquirer';
|
||||
import { NxReleaseVersionV2Configuration } from '../../../config/nx-json';
|
||||
import { NxReleaseVersionConfiguration } from '../../../config/nx-json';
|
||||
import type { ProjectGraph } from '../../../config/project-graph';
|
||||
import { createTreeWithEmptyWorkspace } from '../../../generators/testing-utils/create-tree-with-empty-workspace';
|
||||
import { Tree } from '../../../generators/tree';
|
||||
@ -141,7 +141,7 @@ async function releaseVersionGeneratorForTest(
|
||||
* because this takes place after all projects have been versioned)
|
||||
*/
|
||||
return processor.afterAllProjectsVersioned(
|
||||
(nxReleaseConfig.version as NxReleaseVersionV2Configuration)
|
||||
(nxReleaseConfig.version as NxReleaseVersionConfiguration)
|
||||
.versionActionsOptions
|
||||
);
|
||||
},
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import chalk = require('chalk');
|
||||
import { prompt } from 'enquirer';
|
||||
import * as ora from 'ora';
|
||||
import { NxReleaseVersionV2Configuration } from '../../../config/nx-json';
|
||||
import { NxReleaseVersionConfiguration } from '../../../config/nx-json';
|
||||
import type { ProjectGraphProjectNode } from '../../../config/project-graph';
|
||||
import type { Tree } from '../../../generators/tree';
|
||||
import type { ReleaseGroupWithName } from '../config/filter-release-groups';
|
||||
@ -362,7 +362,7 @@ async function handleNoAvailableDiskFallback({
|
||||
projectName: string;
|
||||
versionActions: VersionActions;
|
||||
specifierSource: Exclude<
|
||||
NxReleaseVersionV2Configuration['specifierSource'],
|
||||
NxReleaseVersionConfiguration['specifierSource'],
|
||||
'prompt'
|
||||
>;
|
||||
currentVersionSourceMessage: string;
|
||||
|
||||
@ -2,7 +2,7 @@ import TOML from '@ltd/j-toml';
|
||||
import { join } from 'node:path';
|
||||
import type {
|
||||
NxJsonConfiguration,
|
||||
NxReleaseVersionV2Configuration,
|
||||
NxReleaseVersionConfiguration,
|
||||
} from '../../../config/nx-json';
|
||||
import type {
|
||||
ProjectGraph,
|
||||
@ -146,7 +146,7 @@ export class ExampleRustVersionActions extends VersionActions {
|
||||
|
||||
async readCurrentVersionFromRegistry(
|
||||
tree: Tree,
|
||||
_currentVersionResolverMetadata: NxReleaseVersionV2Configuration['currentVersionResolverMetadata']
|
||||
_currentVersionResolverMetadata: NxReleaseVersionConfiguration['currentVersionResolverMetadata']
|
||||
): Promise<{
|
||||
currentVersion: string;
|
||||
logText: string;
|
||||
@ -161,8 +161,10 @@ export class ExampleRustVersionActions extends VersionActions {
|
||||
|
||||
async updateProjectVersion(tree: Tree, newVersion: string) {
|
||||
const logMessages: string[] = [];
|
||||
for (const manifestPath of this.manifestsToUpdate) {
|
||||
const cargoTomlString = tree.read(manifestPath, 'utf-8')!.toString();
|
||||
for (const manifestToUpdate of this.manifestsToUpdate) {
|
||||
const cargoTomlString = tree
|
||||
.read(manifestToUpdate.manifestPath, 'utf-8')!
|
||||
.toString();
|
||||
const cargoToml = this.parseCargoToml(cargoTomlString);
|
||||
ExampleRustVersionActions.modifyCargoTable(
|
||||
cargoToml,
|
||||
@ -172,9 +174,9 @@ export class ExampleRustVersionActions extends VersionActions {
|
||||
);
|
||||
const updatedCargoTomlString =
|
||||
ExampleRustVersionActions.stringifyCargoToml(cargoToml);
|
||||
tree.write(manifestPath, updatedCargoTomlString);
|
||||
tree.write(manifestToUpdate.manifestPath, updatedCargoTomlString);
|
||||
logMessages.push(
|
||||
`✍️ New version ${newVersion} written to manifest: ${manifestPath}`
|
||||
`✍️ New version ${newVersion} written to manifest: ${manifestToUpdate.manifestPath}`
|
||||
);
|
||||
}
|
||||
return logMessages;
|
||||
@ -201,10 +203,7 @@ export class ExampleRustVersionActions extends VersionActions {
|
||||
};
|
||||
}
|
||||
|
||||
async isLocalDependencyProtocol(_versionSpecifier: string): Promise<boolean> {
|
||||
return false;
|
||||
}
|
||||
|
||||
// NOTE: Does not take the preserveLocalDependencyProtocols setting into account yet
|
||||
async updateProjectDependencies(
|
||||
tree: Tree,
|
||||
_projectGraph: ProjectGraph,
|
||||
@ -218,8 +217,10 @@ export class ExampleRustVersionActions extends VersionActions {
|
||||
}
|
||||
|
||||
const logMessages: string[] = [];
|
||||
for (const manifestPath of this.manifestsToUpdate) {
|
||||
const cargoTomlString = tree.read(manifestPath, 'utf-8')!.toString();
|
||||
for (const manifestToUpdate of this.manifestsToUpdate) {
|
||||
const cargoTomlString = tree
|
||||
.read(manifestToUpdate.manifestPath, 'utf-8')!
|
||||
.toString();
|
||||
const cargoToml = this.parseCargoToml(cargoTomlString);
|
||||
|
||||
for (const [dep, version] of Object.entries(dependenciesToUpdate)) {
|
||||
@ -233,10 +234,10 @@ export class ExampleRustVersionActions extends VersionActions {
|
||||
|
||||
const updatedCargoTomlString =
|
||||
ExampleRustVersionActions.stringifyCargoToml(cargoToml);
|
||||
tree.write(manifestPath, updatedCargoTomlString);
|
||||
tree.write(manifestToUpdate.manifestPath, updatedCargoTomlString);
|
||||
|
||||
logMessages.push(
|
||||
`✍️ Updated ${numDependenciesToUpdate} ${depText} in manifest: ${manifestPath}`
|
||||
`✍️ Updated ${numDependenciesToUpdate} ${depText} in manifest: ${manifestToUpdate.manifestPath}`
|
||||
);
|
||||
}
|
||||
return logMessages;
|
||||
@ -261,10 +262,6 @@ export class ExampleNonSemverVersionActions extends VersionActions {
|
||||
};
|
||||
}
|
||||
|
||||
async isLocalDependencyProtocol() {
|
||||
return false;
|
||||
}
|
||||
|
||||
async updateProjectVersion(tree, newVersion) {
|
||||
tree.write(
|
||||
join(this.projectGraphNode.data.root, 'version.txt'),
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { join } from 'node:path';
|
||||
import { ReleaseType } from 'semver';
|
||||
import { NxReleaseVersionV2Configuration } from '../../../config/nx-json';
|
||||
import { NxReleaseVersionConfiguration } from '../../../config/nx-json';
|
||||
import type {
|
||||
ProjectGraph,
|
||||
ProjectGraphDependency,
|
||||
@ -106,13 +106,13 @@ export async function resolveVersionActionsForProject(
|
||||
// Project level release version config takes priority, if set
|
||||
const projectVersionConfig = projectGraphNode.data.release?.version as
|
||||
| Pick<
|
||||
NxReleaseVersionV2Configuration,
|
||||
NxReleaseVersionConfiguration,
|
||||
'versionActions' | 'versionActionsOptions'
|
||||
>
|
||||
| undefined;
|
||||
const releaseGroupVersionConfig = releaseGroup.version as
|
||||
| Pick<
|
||||
NxReleaseVersionV2Configuration,
|
||||
NxReleaseVersionConfiguration,
|
||||
'versionActions' | 'versionActionsOptions'
|
||||
>
|
||||
| undefined;
|
||||
@ -194,8 +194,14 @@ export abstract class VersionActions {
|
||||
* The interpolated manifest paths to update, if applicable based on the user's configuration, when new
|
||||
* versions and dependencies are determined. If no manifest files should be updated based on the user's
|
||||
* configuration, this will be an empty array.
|
||||
*
|
||||
* The final value for preserveLocalDependencyProtocols will be based on the resolved config for the current
|
||||
* project and any overrides from the user's configuration for the manifestRootsToUpdate.
|
||||
*/
|
||||
manifestsToUpdate: string[] = [];
|
||||
manifestsToUpdate: {
|
||||
manifestPath: string;
|
||||
preserveLocalDependencyProtocols: boolean;
|
||||
}[] = [];
|
||||
|
||||
constructor(
|
||||
public releaseGroup: ReleaseGroupWithName,
|
||||
@ -216,9 +222,11 @@ export abstract class VersionActions {
|
||||
if (
|
||||
tree.exists(join(this.projectGraphNode.data.root, manifestFilename))
|
||||
) {
|
||||
this.finalConfigForProject.manifestRootsToUpdate.push(
|
||||
this.projectGraphNode.data.root
|
||||
);
|
||||
this.finalConfigForProject.manifestRootsToUpdate.push({
|
||||
path: this.projectGraphNode.data.root,
|
||||
preserveLocalDependencyProtocols:
|
||||
this.finalConfigForProject.preserveLocalDependencyProtocols,
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -226,19 +234,28 @@ export abstract class VersionActions {
|
||||
|
||||
const interpolatedManifestRoots =
|
||||
this.finalConfigForProject.manifestRootsToUpdate.map((manifestRoot) => {
|
||||
return interpolate(manifestRoot, {
|
||||
return {
|
||||
...manifestRoot,
|
||||
path: interpolate(manifestRoot.path, {
|
||||
workspaceRoot: '',
|
||||
projectRoot: this.projectGraphNode.data.root,
|
||||
projectName: this.projectGraphNode.name,
|
||||
});
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
for (const interpolatedManifestRoot of interpolatedManifestRoots) {
|
||||
let hasValidManifest = false;
|
||||
for (const manifestFilename of this.validManifestFilenames) {
|
||||
const manifestPath = join(interpolatedManifestRoot, manifestFilename);
|
||||
const manifestPath = join(
|
||||
interpolatedManifestRoot.path,
|
||||
manifestFilename
|
||||
);
|
||||
if (tree.exists(manifestPath)) {
|
||||
this.manifestsToUpdate.push(manifestPath);
|
||||
this.manifestsToUpdate.push({
|
||||
...interpolatedManifestRoot,
|
||||
manifestPath,
|
||||
});
|
||||
hasValidManifest = true;
|
||||
break;
|
||||
}
|
||||
@ -248,7 +265,7 @@ export abstract class VersionActions {
|
||||
this.validManifestFilenames?.join(' or ');
|
||||
|
||||
throw new Error(
|
||||
`The project "${this.projectGraphNode.name}" does not have a ${validManifestFilenames} file available in ./${interpolatedManifestRoot}.
|
||||
`The project "${this.projectGraphNode.name}" does not have a ${validManifestFilenames} file available in ./${interpolatedManifestRoot.path}.
|
||||
|
||||
To fix this you will either need to add a ${validManifestFilenames} file at that location, or configure "release" within your nx.json to exclude "${this.projectGraphNode.name}" from the current release group, or amend the "release.version.manifestRootsToUpdate" configuration to point to where the relevant manifest should be.`
|
||||
);
|
||||
@ -348,7 +365,7 @@ To fix this you will either need to add a ${validManifestFilenames} file at that
|
||||
*/
|
||||
abstract readCurrentVersionFromRegistry(
|
||||
tree: Tree,
|
||||
currentVersionResolverMetadata: NxReleaseVersionV2Configuration['currentVersionResolverMetadata']
|
||||
currentVersionResolverMetadata: NxReleaseVersionConfiguration['currentVersionResolverMetadata']
|
||||
): Promise<{
|
||||
currentVersion: string | null;
|
||||
logText: string;
|
||||
@ -397,14 +414,6 @@ To fix this you will either need to add a ${validManifestFilenames} file at that
|
||||
dependencyCollection: string | null;
|
||||
}>;
|
||||
|
||||
/**
|
||||
* Implementation details of determining if a version specifier uses a local dependency protocol that is relevant to this
|
||||
* specific project. E.g. in a package.json context, `file:` and `workspace:` protocols should return true here.
|
||||
*/
|
||||
abstract isLocalDependencyProtocol(
|
||||
versionSpecifier: string
|
||||
): Promise<boolean>;
|
||||
|
||||
/**
|
||||
* Implementation details of updating a newly derived version in some source of truth.
|
||||
*
|
||||
|
||||
@ -57,12 +57,12 @@ interface NxInstallationConfiguration {
|
||||
}
|
||||
|
||||
/**
|
||||
* This named configuration interface will be changing in Nx v21. This interface will be made available
|
||||
* under LegacyNxReleaseVersionConfiguration, which is already available as an alias.
|
||||
* This named configuration interface represents the options prior to Nx v21. This interface will be made available
|
||||
* under LegacyNxReleaseVersionConfiguration throughout the lifetime of Nx v21.
|
||||
*
|
||||
* In Nx v22, this configuration interface will no longer be valid.
|
||||
*/
|
||||
export interface NxReleaseVersionConfiguration {
|
||||
export interface LegacyNxReleaseVersionConfiguration {
|
||||
generator?: string;
|
||||
generatorOptions?: Record<string, unknown>;
|
||||
/**
|
||||
@ -77,12 +77,15 @@ export interface NxReleaseVersionConfiguration {
|
||||
*/
|
||||
conventionalCommits?: boolean;
|
||||
}
|
||||
export type LegacyNxReleaseVersionConfiguration = NxReleaseVersionConfiguration;
|
||||
|
||||
export type ManifestRootToUpdate =
|
||||
| string
|
||||
| { path: string; preserveLocalDependencyProtocols: boolean };
|
||||
|
||||
// NOTE: It's important to keep the nx-schema.json in sync with this interface. If you make changes here, make sure they are reflected in the schema.
|
||||
export interface NxReleaseVersionV2Configuration {
|
||||
export interface NxReleaseVersionConfiguration {
|
||||
/**
|
||||
* Whether to use the legacy versioning strategy. This value will be true in Nx v20 and false in Nx v21.
|
||||
* Whether to use the legacy versioning strategy. This value was true in Nx v20 and became false in Nx v21.
|
||||
* The legacy versioning implementation will be removed in Nx v22, as will this flag.
|
||||
*/
|
||||
useLegacyVersioning?: boolean;
|
||||
@ -110,8 +113,11 @@ export interface NxReleaseVersionV2Configuration {
|
||||
*
|
||||
* By default, only the project root will be used, but you could customize this to only version a manifest in a
|
||||
* dist directory, or even version multiple manifests in different directories, such as both source and dist.
|
||||
*
|
||||
* For more advanced scenarios, the preserveLocalDependencyProtocols can be overridden per manifest by providing
|
||||
* and object instead of a string.
|
||||
*/
|
||||
manifestRootsToUpdate?: string[];
|
||||
manifestRootsToUpdate?: ManifestRootToUpdate[];
|
||||
/**
|
||||
* The resolver to use for determining the current version of a project during versioning.
|
||||
* This is needed for versioning approaches which involve relatively modifying a current version
|
||||
@ -333,7 +339,7 @@ export interface NxReleaseConfiguration {
|
||||
*/
|
||||
version?: (
|
||||
| LegacyNxReleaseVersionConfiguration
|
||||
| NxReleaseVersionV2Configuration
|
||||
| NxReleaseVersionConfiguration
|
||||
) & {
|
||||
/**
|
||||
* A command to run after validation of nx release configuration, but before versioning begins.
|
||||
@ -414,7 +420,7 @@ export interface NxReleaseConfiguration {
|
||||
*/
|
||||
version?: (
|
||||
| LegacyNxReleaseVersionConfiguration
|
||||
| NxReleaseVersionV2Configuration
|
||||
| NxReleaseVersionConfiguration
|
||||
) & {
|
||||
useLegacyVersioning?: boolean;
|
||||
git?: NxReleaseGitConfiguration;
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import type { PackageJson } from '../utils/package-json';
|
||||
import type {
|
||||
LegacyNxReleaseVersionConfiguration,
|
||||
NxJsonConfiguration,
|
||||
NxReleaseVersionConfiguration,
|
||||
NxReleaseVersionV2Configuration,
|
||||
} from './nx-json';
|
||||
|
||||
/**
|
||||
@ -109,10 +109,13 @@ export interface ProjectConfiguration {
|
||||
*/
|
||||
release?: {
|
||||
version?:
|
||||
| Pick<NxReleaseVersionConfiguration, 'generator' | 'generatorOptions'>
|
||||
| Pick<
|
||||
LegacyNxReleaseVersionConfiguration,
|
||||
'generator' | 'generatorOptions'
|
||||
>
|
||||
| Pick<
|
||||
// Expose a subset of version config options at the project level
|
||||
NxReleaseVersionV2Configuration,
|
||||
NxReleaseVersionConfiguration,
|
||||
| 'versionActions'
|
||||
| 'versionActionsOptions'
|
||||
| 'manifestRootsToUpdate'
|
||||
|
||||
@ -0,0 +1,59 @@
|
||||
#### Nx Release Version Config Changes
|
||||
|
||||
In Nx v21, the implementation details of versioning were rewritten to massively enhance flexibility and lay the groundwork for future features.
|
||||
|
||||
As part of this, some elements of the release configuration were updated. During the lifecycle of Nx v21, you can still opt into the old versioning by setting `release.version.useLegacyVersioning` to `true`, in which case the release configuration should remain unchanged.
|
||||
|
||||
In Nx v22, the legacy versioning implementation will be removed entirely and the configuration will have to be updated to match what this migration does for you.
|
||||
|
||||
#### Sample Code Changes
|
||||
|
||||
"generatorOptions" is longer exists and most non-ecosystem specific options have moved to the top level of "version" and are therefore fully documented on the JSON schema as a core option.
|
||||
|
||||
"packageRoot: string" has been replaced by the more flexible concept of "manifestRootsToUpdate: string[]", allowing for multiple manifest files (such as `package.json` in the JS/TS ecosystem)
|
||||
to be updated in a single versioning run.
|
||||
|
||||
Ecosystem specific options, such as "skipLockFileUpdate", which is specific to the JS/TS ecosystem, are available via the new "versionActionsOptions" object, which is so named because of the new `VersionActions` abstraction introduced in Nx v21,
|
||||
which allows for different ecosystems and use-cases to be supported via very minimal implementation effort.
|
||||
|
||||
"preserveLocalDependencyProtocols" changed from `false` by default to `true` by default in Nx v21, so it can simply be removed from the configuration when set to true.
|
||||
|
||||
The migration will also update release groups version configuration, as well as project.json and package.json version configuration, if applicable.
|
||||
|
||||
{% tabs %}
|
||||
{% tab label="Before" %}
|
||||
|
||||
```json {% fileName="nx.json" %}
|
||||
{
|
||||
"release": {
|
||||
"version": {
|
||||
"generatorOptions": {
|
||||
"packageRoot": "build/packages/{projectName}",
|
||||
"currentVersionResolver": "registry",
|
||||
"skipLockFileUpdate": true,
|
||||
"preserveLocalDependencyProtocols": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
{% /tab %}
|
||||
{% tab label="After" %}
|
||||
|
||||
```json {% fileName="nx.json" %}
|
||||
{
|
||||
"release": {
|
||||
"version": {
|
||||
"manifestRootsToUpdate": ["build/packages/{projectName}"],
|
||||
"currentVersionResolver": "registry",
|
||||
"versionActionsOptions": {
|
||||
"skipLockFileUpdate": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
{% /tab %}
|
||||
{% /tabs %}
|
||||
@ -0,0 +1,379 @@
|
||||
import { createTreeWithEmptyWorkspace } from '../../generators/testing-utils/create-tree-with-empty-workspace';
|
||||
import { Tree } from '../../generators/tree';
|
||||
import { readJson, writeJson } from '../../generators/utils/json';
|
||||
import { readNxJson, updateNxJson } from '../../generators/utils/nx-json';
|
||||
|
||||
import update from './release-version-config-changes';
|
||||
|
||||
describe('release version config changes', () => {
|
||||
let tree: Tree;
|
||||
|
||||
beforeEach(() => {
|
||||
tree = createTreeWithEmptyWorkspace();
|
||||
});
|
||||
|
||||
it('should do nothing when nxJson.release.version is not set', async () => {
|
||||
updateNxJson(tree, {});
|
||||
await update(tree);
|
||||
expect(readNxJson(tree)).toEqual({});
|
||||
|
||||
updateNxJson(tree, {
|
||||
release: {},
|
||||
});
|
||||
await update(tree);
|
||||
expect(readNxJson(tree)).toEqual({
|
||||
release: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should do nothing when useLegacyVersioning is explicitly true', async () => {
|
||||
const nxJsonBefore = {
|
||||
release: {
|
||||
version: {
|
||||
useLegacyVersioning: true,
|
||||
generatorOptions: {
|
||||
specifierSource: 'prompt',
|
||||
currentVersionResolver: 'registry',
|
||||
currentVersionResolverMetadata: {},
|
||||
fallbackCurrentVersionResolver: 'disk',
|
||||
versionPrefix: 'auto',
|
||||
updateDependents: 'auto',
|
||||
logUnchangedProjects: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
updateNxJson(tree, nxJsonBefore);
|
||||
|
||||
await update(tree);
|
||||
|
||||
expect(readNxJson(tree)).toEqual(nxJsonBefore);
|
||||
});
|
||||
|
||||
it('should set useLegacyVersioning to true when using a generator other than the @nx/js one, and nothing else', async () => {
|
||||
updateNxJson(tree, {
|
||||
release: {
|
||||
version: {
|
||||
generator: 'some-other-generator',
|
||||
generatorOptions: {
|
||||
something: 'related-to-the-custom-generator',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await update(tree);
|
||||
|
||||
expect(readNxJson(tree)).toMatchInlineSnapshot(`
|
||||
{
|
||||
"release": {
|
||||
"version": {
|
||||
"generator": "some-other-generator",
|
||||
"generatorOptions": {
|
||||
"something": "related-to-the-custom-generator",
|
||||
},
|
||||
"useLegacyVersioning": true,
|
||||
},
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should promote certain generatorOptions to top-level options and remove generatorOptions', async () => {
|
||||
updateNxJson(tree, {
|
||||
release: {
|
||||
version: {
|
||||
generatorOptions: {
|
||||
specifierSource: 'prompt',
|
||||
currentVersionResolver: 'registry',
|
||||
currentVersionResolverMetadata: {},
|
||||
fallbackCurrentVersionResolver: 'disk',
|
||||
versionPrefix: 'auto',
|
||||
updateDependents: 'auto',
|
||||
logUnchangedProjects: true,
|
||||
preserveLocalDependencyProtocols: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await update(tree);
|
||||
|
||||
expect(readNxJson(tree)).toMatchInlineSnapshot(`
|
||||
{
|
||||
"release": {
|
||||
"version": {
|
||||
"currentVersionResolver": "registry",
|
||||
"currentVersionResolverMetadata": {},
|
||||
"fallbackCurrentVersionResolver": "disk",
|
||||
"logUnchangedProjects": true,
|
||||
"preserveLocalDependencyProtocols": false,
|
||||
"specifierSource": "prompt",
|
||||
"updateDependents": "auto",
|
||||
"versionPrefix": "auto",
|
||||
},
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should remove preserveLocalDependencyProtocols if it is explicitly true', async () => {
|
||||
updateNxJson(tree, {
|
||||
release: {
|
||||
version: {
|
||||
generatorOptions: { preserveLocalDependencyProtocols: true },
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await update(tree);
|
||||
|
||||
expect(readNxJson(tree)).toMatchInlineSnapshot(`
|
||||
{
|
||||
"release": {
|
||||
"version": {},
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should set preserveLocalDependencyProtocols to false if it is not explicitly true', async () => {
|
||||
updateNxJson(tree, {
|
||||
release: {
|
||||
version: { generatorOptions: {} },
|
||||
},
|
||||
});
|
||||
|
||||
await update(tree);
|
||||
|
||||
expect(readNxJson(tree)).toMatchInlineSnapshot(`
|
||||
{
|
||||
"release": {
|
||||
"version": {
|
||||
"preserveLocalDependencyProtocols": false,
|
||||
},
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should replace generatorOptions.packageRoot with manifestRootsToUpdate', async () => {
|
||||
updateNxJson(tree, {
|
||||
release: {
|
||||
version: { generatorOptions: { packageRoot: 'dist/{projectName}' } },
|
||||
},
|
||||
});
|
||||
|
||||
await update(tree);
|
||||
|
||||
expect(readNxJson(tree)).toMatchInlineSnapshot(`
|
||||
{
|
||||
"release": {
|
||||
"version": {
|
||||
"manifestRootsToUpdate": [
|
||||
"dist/{projectName}",
|
||||
],
|
||||
"preserveLocalDependencyProtocols": false,
|
||||
},
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should move certain generatorOptions to versionActionsOptions', async () => {
|
||||
updateNxJson(tree, {
|
||||
release: {
|
||||
version: {
|
||||
generatorOptions: {
|
||||
skipLockFileUpdate: true,
|
||||
installArgs: '--some-flag',
|
||||
installIgnoreScripts: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await update(tree);
|
||||
|
||||
expect(readNxJson(tree)).toMatchInlineSnapshot(`
|
||||
{
|
||||
"release": {
|
||||
"version": {
|
||||
"preserveLocalDependencyProtocols": false,
|
||||
"versionActionsOptions": {
|
||||
"installArgs": "--some-flag",
|
||||
"installIgnoreScripts": true,
|
||||
"skipLockFileUpdate": true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should perform the updates on release groups as well', async () => {
|
||||
updateNxJson(tree, {
|
||||
release: {
|
||||
groups: {
|
||||
group1: {
|
||||
projects: ['project1', 'project2'],
|
||||
version: {
|
||||
generatorOptions: {
|
||||
specifierSource: 'prompt',
|
||||
currentVersionResolver: 'registry',
|
||||
currentVersionResolverMetadata: {},
|
||||
fallbackCurrentVersionResolver: 'disk',
|
||||
versionPrefix: 'auto',
|
||||
updateDependents: 'auto',
|
||||
logUnchangedProjects: true,
|
||||
preserveLocalDependencyProtocols: true,
|
||||
skipLockFileUpdate: true,
|
||||
installArgs: '--some-flag',
|
||||
installIgnoreScripts: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await update(tree);
|
||||
|
||||
expect(readNxJson(tree)).toMatchInlineSnapshot(`
|
||||
{
|
||||
"release": {
|
||||
"groups": {
|
||||
"group1": {
|
||||
"projects": [
|
||||
"project1",
|
||||
"project2",
|
||||
],
|
||||
"version": {
|
||||
"currentVersionResolver": "registry",
|
||||
"currentVersionResolverMetadata": {},
|
||||
"fallbackCurrentVersionResolver": "disk",
|
||||
"logUnchangedProjects": true,
|
||||
"specifierSource": "prompt",
|
||||
"updateDependents": "auto",
|
||||
"versionActionsOptions": {
|
||||
"installArgs": "--some-flag",
|
||||
"installIgnoreScripts": true,
|
||||
"skipLockFileUpdate": true,
|
||||
},
|
||||
"versionPrefix": "auto",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should update project.json, if applicable', async () => {
|
||||
updateNxJson(tree, {});
|
||||
|
||||
writeJson(tree, 'my-lib/project.json', {
|
||||
name: 'my-lib',
|
||||
projectType: 'library',
|
||||
release: {
|
||||
version: {
|
||||
generatorOptions: {
|
||||
specifierSource: 'prompt',
|
||||
currentVersionResolver: 'registry',
|
||||
currentVersionResolverMetadata: {},
|
||||
fallbackCurrentVersionResolver: 'disk',
|
||||
versionPrefix: 'auto',
|
||||
updateDependents: 'auto',
|
||||
logUnchangedProjects: true,
|
||||
preserveLocalDependencyProtocols: true,
|
||||
skipLockFileUpdate: true,
|
||||
installArgs: '--some-flag',
|
||||
installIgnoreScripts: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await update(tree);
|
||||
|
||||
expect(readJson(tree, 'my-lib/project.json')).toMatchInlineSnapshot(`
|
||||
{
|
||||
"name": "my-lib",
|
||||
"projectType": "library",
|
||||
"release": {
|
||||
"version": {
|
||||
"currentVersionResolver": "registry",
|
||||
"currentVersionResolverMetadata": {},
|
||||
"fallbackCurrentVersionResolver": "disk",
|
||||
"logUnchangedProjects": true,
|
||||
"specifierSource": "prompt",
|
||||
"updateDependents": "auto",
|
||||
"versionActionsOptions": {
|
||||
"installArgs": "--some-flag",
|
||||
"installIgnoreScripts": true,
|
||||
"skipLockFileUpdate": true,
|
||||
},
|
||||
"versionPrefix": "auto",
|
||||
},
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should update package.json, if applicable', async () => {
|
||||
updateNxJson(tree, {});
|
||||
|
||||
writeJson(tree, 'my-lib/package.json', {
|
||||
name: 'my-lib',
|
||||
version: '1.0.0',
|
||||
dependencies: {},
|
||||
nx: {
|
||||
release: {
|
||||
version: {
|
||||
generatorOptions: {
|
||||
specifierSource: 'prompt',
|
||||
currentVersionResolver: 'registry',
|
||||
currentVersionResolverMetadata: {},
|
||||
fallbackCurrentVersionResolver: 'disk',
|
||||
versionPrefix: 'auto',
|
||||
updateDependents: 'auto',
|
||||
logUnchangedProjects: true,
|
||||
preserveLocalDependencyProtocols: true,
|
||||
skipLockFileUpdate: true,
|
||||
installArgs: '--some-flag',
|
||||
installIgnoreScripts: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await update(tree);
|
||||
|
||||
expect(readJson(tree, 'my-lib/package.json')).toMatchInlineSnapshot(`
|
||||
{
|
||||
"dependencies": {},
|
||||
"name": "my-lib",
|
||||
"nx": {
|
||||
"release": {
|
||||
"version": {
|
||||
"currentVersionResolver": "registry",
|
||||
"currentVersionResolverMetadata": {},
|
||||
"fallbackCurrentVersionResolver": "disk",
|
||||
"logUnchangedProjects": true,
|
||||
"specifierSource": "prompt",
|
||||
"updateDependents": "auto",
|
||||
"versionActionsOptions": {
|
||||
"installArgs": "--some-flag",
|
||||
"installIgnoreScripts": true,
|
||||
"skipLockFileUpdate": true,
|
||||
},
|
||||
"versionPrefix": "auto",
|
||||
},
|
||||
},
|
||||
},
|
||||
"version": "1.0.0",
|
||||
}
|
||||
`);
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,134 @@
|
||||
import { join } from 'node:path';
|
||||
import type {
|
||||
LegacyNxReleaseVersionConfiguration,
|
||||
NxJsonConfiguration,
|
||||
NxReleaseVersionConfiguration,
|
||||
} from '../../config/nx-json';
|
||||
import { formatChangedFilesWithPrettierIfAvailable } from '../../generators/internal-utils/format-changed-files-with-prettier-if-available';
|
||||
import type { Tree } from '../../generators/tree';
|
||||
import { readJson, writeJson } from '../../generators/utils/json';
|
||||
import { readNxJson, updateNxJson } from '../../generators/utils/nx-json';
|
||||
import { getProjects } from '../../generators/utils/project-configuration';
|
||||
|
||||
export default async function update(tree: Tree) {
|
||||
const nxJson = readNxJson(tree) as NxJsonConfiguration;
|
||||
if (!nxJson) {
|
||||
return;
|
||||
}
|
||||
// If the user has explicitly set the useLegacyVersioning property to true, do nothing
|
||||
if (nxJson.release?.version?.useLegacyVersioning === true) {
|
||||
return;
|
||||
}
|
||||
|
||||
function updateProperties(
|
||||
versionConfig: LegacyNxReleaseVersionConfiguration
|
||||
) {
|
||||
// If the user is using a generator other than the @nx/js one, set useLegacyVersioning to true and nothing else
|
||||
if (
|
||||
'generator' in versionConfig &&
|
||||
versionConfig.generator !== '@nx/js:release-version'
|
||||
) {
|
||||
(versionConfig as NxReleaseVersionConfiguration).useLegacyVersioning =
|
||||
true;
|
||||
return;
|
||||
}
|
||||
|
||||
// These options used to live inside of generatorOptions, but are now like for like top-level nx core options
|
||||
const coreOptionsToPromoteToTopLevel = [
|
||||
'specifierSource',
|
||||
'currentVersionResolver',
|
||||
'currentVersionResolverMetadata',
|
||||
'fallbackCurrentVersionResolver',
|
||||
'versionPrefix',
|
||||
'updateDependents',
|
||||
'logUnchangedProjects',
|
||||
];
|
||||
if ('generatorOptions' in versionConfig) {
|
||||
for (const option of coreOptionsToPromoteToTopLevel) {
|
||||
if (versionConfig.generatorOptions[option]) {
|
||||
versionConfig[option] = versionConfig.generatorOptions[option];
|
||||
}
|
||||
}
|
||||
|
||||
// preserveLocalDependencyProtocols has changed to true by default, so remove it if explicitly true, otherwise set to false explicitly
|
||||
if (versionConfig.generatorOptions.preserveLocalDependencyProtocols) {
|
||||
delete versionConfig.generatorOptions.preserveLocalDependencyProtocols;
|
||||
} else {
|
||||
(
|
||||
versionConfig as NxReleaseVersionConfiguration
|
||||
).preserveLocalDependencyProtocols = false;
|
||||
}
|
||||
|
||||
// packageRoot has been replaced by manifestRootsToUpdate
|
||||
if (typeof versionConfig.generatorOptions.packageRoot === 'string') {
|
||||
(versionConfig as NxReleaseVersionConfiguration).manifestRootsToUpdate =
|
||||
[versionConfig.generatorOptions.packageRoot];
|
||||
delete versionConfig.generatorOptions.packageRoot;
|
||||
}
|
||||
|
||||
// These options have been moved to versionActionsOptions
|
||||
const versionActionsOptions = [
|
||||
'skipLockFileUpdate',
|
||||
'installArgs',
|
||||
'installIgnoreScripts',
|
||||
];
|
||||
for (const option of versionActionsOptions) {
|
||||
if (versionConfig.generatorOptions[option]) {
|
||||
(
|
||||
versionConfig as NxReleaseVersionConfiguration
|
||||
).versionActionsOptions =
|
||||
(versionConfig as NxReleaseVersionConfiguration)
|
||||
.versionActionsOptions || {};
|
||||
(
|
||||
versionConfig as NxReleaseVersionConfiguration
|
||||
).versionActionsOptions[option] =
|
||||
versionConfig.generatorOptions[option];
|
||||
delete versionConfig.generatorOptions[option];
|
||||
}
|
||||
}
|
||||
delete versionConfig.generatorOptions;
|
||||
}
|
||||
}
|
||||
|
||||
// nx.json
|
||||
if (nxJson.release) {
|
||||
// Top level version config
|
||||
if (nxJson.release.version) {
|
||||
updateProperties(nxJson.release.version);
|
||||
}
|
||||
|
||||
// Version config for each group
|
||||
if (nxJson.release.groups) {
|
||||
for (const group of Object.values(nxJson.release.groups)) {
|
||||
if (group.version) {
|
||||
updateProperties(group.version);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// project.json or package.json
|
||||
const projects = getProjects(tree);
|
||||
for (const project of projects.values()) {
|
||||
const projectJsonPath = join(project.root, 'project.json');
|
||||
if (tree.exists(projectJsonPath)) {
|
||||
const projectJson = readJson(tree, projectJsonPath);
|
||||
if (projectJson.release?.version) {
|
||||
updateProperties(projectJson.release.version);
|
||||
writeJson(tree, projectJsonPath, projectJson);
|
||||
}
|
||||
}
|
||||
const packageJsonPath = join(project.root, 'package.json');
|
||||
if (tree.exists(packageJsonPath)) {
|
||||
const packageJson = readJson(tree, packageJsonPath);
|
||||
if (packageJson.nx?.release?.version) {
|
||||
updateProperties(packageJson.nx.release.version);
|
||||
writeJson(tree, packageJsonPath, packageJson);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateNxJson(tree, nxJson);
|
||||
|
||||
await formatChangedFilesWithPrettierIfAvailable(tree);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user