Socket
Socket
Sign inDemoInstall

nx

Package Overview
Dependencies
Maintainers
8
Versions
1360
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

nx - npm Package Compare versions

Comparing version 0.0.0-pr-27085-57245c5 to 0.0.0-pr-27530-4059102

src/command-line/import/command-object.d.ts

3

bin/nx-cloud.d.ts
#!/usr/bin/env node
export {};
import type { CloudTaskRunnerOptions } from '../src/nx-cloud/nx-cloud-tasks-runner-shell';
export declare function invokeCommandWithNxCloudClient(options: CloudTaskRunnerOptions): Promise<any>;
#!/usr/bin/env node
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const resolution_helpers_1 = require("../src/nx-cloud/resolution-helpers");
exports.invokeCommandWithNxCloudClient = invokeCommandWithNxCloudClient;
const get_cloud_options_1 = require("../src/nx-cloud/utilities/get-cloud-options");
const update_manager_1 = require("../src/nx-cloud/update-manager");
const output_1 = require("../src/utils/output");
const client_1 = require("../src/nx-cloud/utilities/client");
const command = process.argv[2];

@@ -13,25 +14,16 @@ const options = (0, get_cloud_options_1.getCloudOptions)();

try {
const { nxCloudClient } = await (0, update_manager_1.verifyOrUpdateNxCloudClient)(options);
const paths = (0, resolution_helpers_1.findAncestorNodeModules)(__dirname, []);
nxCloudClient.configureLightClientRequire()(paths);
if (command in nxCloudClient.commands) {
nxCloudClient.commands[command]()
.then(() => process.exit(0))
.catch((e) => {
console.error(e);
process.exit(1);
});
}
else {
const client = await (0, client_1.getCloudClient)(options);
client.invoke(command);
}
catch (e) {
if (e instanceof client_1.UnknownCommandError) {
output_1.output.error({
title: `Unknown Command "${command}"`,
title: `Unknown Command "${e.command}"`,
});
output_1.output.log({
title: 'Available Commands:',
bodyLines: Object.keys(nxCloudClient.commands).map((c) => `- ${c}`),
bodyLines: e.availableCommands.map((c) => `- ${c}`),
});
process.exit(1);
}
}
catch (e) {
const body = ['Cannot run commands from the `nx-cloud` CLI.'];

@@ -38,0 +30,0 @@ if (e instanceof update_manager_1.NxCloudEnterpriseOutdatedError) {

@@ -31,2 +31,3 @@ "use strict";

}
process.env.NX_DAEMON = 'false';
await Promise.all(tasks.map((promise) => {

@@ -57,1 +58,9 @@ return promise.catch((e) => {

}
process.on('uncaughtException', (e) => {
logger_1.logger.verbose(e);
process.exit(0);
});
process.on('unhandledRejection', (e) => {
logger_1.logger.verbose(e);
process.exit(0);
});
{
"name": "nx",
"version": "0.0.0-pr-27085-57245c5",
"version": "0.0.0-pr-27530-4059102",
"private": false,

@@ -44,3 +44,3 @@ "description": "The core Nx plugin contains the core functionality of Nx like the project graph, nx commands and task orchestration.",

"@zkochan/js-yaml": "0.0.7",
"axios": "^1.6.0",
"axios": "^1.7.4",
"chalk": "^4.1.0",

@@ -75,3 +75,3 @@ "cli-cursor": "3.1.0",

"ora": "5.3.0",
"@nrwl/tao": "0.0.0-pr-27085-57245c5"
"@nrwl/tao": "0.0.0-pr-27530-4059102"
},

@@ -91,12 +91,12 @@ "peerDependencies": {

"optionalDependencies": {
"@nx/nx-darwin-x64": "0.0.0-pr-27085-57245c5",
"@nx/nx-darwin-arm64": "0.0.0-pr-27085-57245c5",
"@nx/nx-linux-x64-gnu": "0.0.0-pr-27085-57245c5",
"@nx/nx-linux-x64-musl": "0.0.0-pr-27085-57245c5",
"@nx/nx-win32-x64-msvc": "0.0.0-pr-27085-57245c5",
"@nx/nx-linux-arm64-gnu": "0.0.0-pr-27085-57245c5",
"@nx/nx-linux-arm64-musl": "0.0.0-pr-27085-57245c5",
"@nx/nx-linux-arm-gnueabihf": "0.0.0-pr-27085-57245c5",
"@nx/nx-win32-arm64-msvc": "0.0.0-pr-27085-57245c5",
"@nx/nx-freebsd-x64": "0.0.0-pr-27085-57245c5"
"@nx/nx-darwin-x64": "0.0.0-pr-27530-4059102",
"@nx/nx-darwin-arm64": "0.0.0-pr-27530-4059102",
"@nx/nx-linux-x64-gnu": "0.0.0-pr-27530-4059102",
"@nx/nx-linux-x64-musl": "0.0.0-pr-27530-4059102",
"@nx/nx-win32-x64-msvc": "0.0.0-pr-27530-4059102",
"@nx/nx-linux-arm64-gnu": "0.0.0-pr-27530-4059102",
"@nx/nx-linux-arm64-musl": "0.0.0-pr-27530-4059102",
"@nx/nx-linux-arm-gnueabihf": "0.0.0-pr-27530-4059102",
"@nx/nx-win32-arm64-msvc": "0.0.0-pr-27530-4059102",
"@nx/nx-freebsd-x64": "0.0.0-pr-27530-4059102"
},

@@ -197,3 +197,4 @@ "nx-migrations": {

"main": "./bin/nx.js",
"type": "commonjs"
"type": "commonjs",
"types": "./bin/nx.d.ts"
}

@@ -25,3 +25,3 @@ <p style="text-align: center;">

Nx is a build system with built-in tooling and advanced CI capabilities. It helps you maintain and scale monorepos, both locally and on CI.
Nx is a build system, optimized for monorepos, with plugins for popular frameworks and tools and advanced CI capabilities including caching and distribution.

@@ -28,0 +28,0 @@ ## Getting Started

@@ -28,6 +28,7 @@ "use strict";

}
let relevantChanges = changes;
// workspace root level changelog
if (project === null) {
// No changes for the workspace
if (changes.length === 0) {
if (relevantChanges.length === 0) {
if (dependencyBumps?.length) {

@@ -46,3 +47,3 @@ applyAdditionalDependencyBumps({

}
const typeGroups = groupBy(changes, 'type');
const typeGroups = groupBy(relevantChanges, 'type');
markdownLines.push('', createVersionTitle(releaseVersion, changelogRenderOptions), '');

@@ -80,3 +81,3 @@ for (const type of Object.keys(changeTypes)) {

// project level changelog
const relevantChanges = changes.filter((c) => c.affectedProjects &&
relevantChanges = relevantChanges.filter((c) => c.affectedProjects &&
(c.affectedProjects === '*' || c.affectedProjects.includes(project)));

@@ -134,3 +135,3 @@ // Generating for a named project, but that project has no relevant changes in the current set of commits, exit early

const _authors = new Map();
for (const change of changes) {
for (const change of relevantChanges) {
if (!change.author) {

@@ -222,9 +223,24 @@ continue;

function formatChange(change, changelogRenderOptions, repoSlug) {
let description = change.description;
let extraLines = [];
let extraLinesStr = '';
if (description.includes('\n')) {
[description, ...extraLines] = description.split('\n');
// Align the extra lines with the start of the description for better readability
const indentation = ' ';
extraLinesStr = extraLines
.filter((l) => l.trim().length > 0)
.map((l) => `${indentation}${l}`)
.join('\n');
}
let changeLine = '- ' +
(change.isBreaking ? '⚠️ ' : '') +
(change.scope ? `**${change.scope.trim()}:** ` : '') +
change.description;
description;
if (repoSlug && changelogRenderOptions.commitReferences) {
changeLine += (0, github_1.formatReferences)(change.githubReferences, repoSlug);
}
if (extraLinesStr) {
changeLine += '\n\n' + extraLinesStr;
}
return changeLine;

@@ -231,0 +247,0 @@ }

/**
* @public Programmatic API for nx release
*/
export { release, releaseChangelog, releasePublish, releaseVersion, } from '../src/command-line/release';
export { ReleaseClient, release, releaseChangelog, releasePublish, releaseVersion, } from '../src/command-line/release';
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.releaseVersion = exports.releasePublish = exports.releaseChangelog = exports.release = void 0;
exports.releaseVersion = exports.releasePublish = exports.releaseChangelog = exports.release = exports.ReleaseClient = void 0;
/**

@@ -8,2 +8,3 @@ * @public Programmatic API for nx release

var release_1 = require("../src/command-line/release");
Object.defineProperty(exports, "ReleaseClient", { enumerable: true, get: function () { return release_1.ReleaseClient; } });
Object.defineProperty(exports, "release", { enumerable: true, get: function () { return release_1.release; } });

@@ -10,0 +11,0 @@ Object.defineProperty(exports, "releaseChangelog", { enumerable: true, get: function () { return release_1.releaseChangelog; } });

@@ -189,4 +189,11 @@ {

"versionPlans": {
"type": "boolean",
"description": "Enables using version plans as a specifier source for versioning and to determine changes for changelog generation."
"oneOf": [
{
"$ref": "#/definitions/NxReleaseVersionPlansConfiguration"
},
{
"type": "boolean",
"description": "Enables using version plans as a specifier source for versioning and to determine changes for changelog generation."
}
]
}

@@ -243,4 +250,11 @@ },

"versionPlans": {
"type": "boolean",
"description": "Enables using version plans as a specifier source for versioning and to determine changes for changelog generation."
"oneOf": [
{
"$ref": "#/definitions/NxReleaseVersionPlansConfiguration"
},
{
"type": "boolean",
"description": "Enables using version plans as a specifier source for versioning and to determine changes for changelog generation."
}
]
},

@@ -251,2 +265,27 @@ "releaseTagPattern": {

}
},
"sync": {
"type": "object",
"description": "Configuration for the `nx sync` command",
"properties": {
"globalGenerators": {
"type": "array",
"items": {
"type": "string"
},
"description": "List of workspace-wide sync generators to be run (not attached to targets)"
},
"generatorOptions": {
"type": "object",
"description": "Options for the sync generators.",
"additionalProperties": {
"type": "object"
}
},
"applyChanges": {
"type": "boolean",
"description": "Whether to automatically apply sync generator changes when running tasks. If not set, the user will be prompted. If set to `true`, the user will not be prompted and the changes will be applied. If set to `false`, the user will not be prompted and the changes will not be applied."
}
},
"additionalProperties": false
}

@@ -403,2 +442,5 @@ },

},
"nxCloudId": {
"type": "string"
},
"captureStderr": {

@@ -677,2 +719,14 @@ "type": "boolean",

},
"NxReleaseVersionPlansConfiguration": {
"type": "object",
"properties": {
"ignorePatternsForPlanCheck": {
"type": "array",
"items": {
"type": "string"
},
"description": "Changes to files matching any of these optional patterns will be excluded from the affected project logic within the `nx release plan:check` command. This is useful for ignoring files that are not relevant to the versioning process, such as documentation or configuration files."
}
}
},
"ChangelogRenderOptions": {

@@ -679,0 +733,0 @@ "type": "object",

@@ -118,4 +118,8 @@ {

"anyOf": [
{ "required": ["projects"] },
{ "required": ["dependencies"] }
{
"required": ["projects"]
},
{
"required": ["dependencies"]
}
]

@@ -142,2 +146,20 @@ }

"description": "Whether this target can be run in parallel with other tasks"
},
"metadata": {
"type": "object",
"description": "Metadata about the target",
"properties": {
"description": {
"type": "string",
"description": "A description of the target"
}
},
"additionalProperties": true
},
"syncGenerators": {
"type": "array",
"items": {
"type": "string"
},
"description": "List of generators to run before the target to ensure the workspace is up to date"
}

@@ -159,2 +181,13 @@ }

},
"metadata": {
"type": "object",
"description": "Metadata about the project.",
"properties": {
"description": {
"type": "string",
"description": "A description of the project."
}
},
"additionalProperties": true
},
"release": {

@@ -211,3 +244,5 @@ "type": "object",

"description": "The projects that the targets belong to.",
"items": { "type": "string" }
"items": {
"type": "string"
}
}

@@ -236,4 +271,8 @@ ]

"anyOf": [
{ "required": ["projects"] },
{ "required": ["dependencies"] }
{
"required": ["projects"]
},
{
"required": ["dependencies"]
}
]

@@ -270,3 +309,5 @@ }

"type": "array",
"items": { "type": "string" },
"items": {
"type": "string"
},
"description": "The list of external dependencies that our target depends on for `nx:run-commands` and community plugins."

@@ -273,0 +314,0 @@ }

export declare const allowedProjectExtensions: readonly ["tags", "implicitDependencies", "configFilePath", "$schema", "generators", "namedInputs", "name", "files", "root", "sourceRoot", "projectType", "release", "includedScripts", "metadata"];
export declare const allowedWorkspaceExtensions: readonly ["implicitDependencies", "affected", "defaultBase", "tasksRunnerOptions", "workspaceLayout", "plugins", "targetDefaults", "files", "generators", "namedInputs", "extends", "cli", "pluginsConfig", "defaultProject", "installation", "release", "nxCloudAccessToken", "nxCloudUrl", "nxCloudEncryptionKey", "parallel", "cacheDirectory", "useDaemonProcess", "useInferencePlugins"];
export declare const allowedWorkspaceExtensions: readonly ["implicitDependencies", "affected", "defaultBase", "tasksRunnerOptions", "workspaceLayout", "plugins", "targetDefaults", "files", "generators", "namedInputs", "extends", "cli", "pluginsConfig", "defaultProject", "installation", "release", "nxCloudAccessToken", "nxCloudId", "nxCloudUrl", "nxCloudEncryptionKey", "parallel", "cacheDirectory", "useDaemonProcess", "useInferencePlugins", "neverConnectToCloud", "sync"];

@@ -57,2 +57,3 @@ "use strict";

'nxCloudAccessToken',
'nxCloudId',
'nxCloudUrl',

@@ -64,2 +65,4 @@ 'nxCloudEncryptionKey',

'useInferencePlugins',
'neverConnectToCloud',
'sync',
];

@@ -66,0 +69,0 @@ if (!patched) {

@@ -89,4 +89,4 @@ "use strict";

currentDirectory: process.cwd(),
scheduleTarget: architect.scheduleTarget,
scheduleBuilder: architect.scheduleBuilder,
scheduleTarget: (...args) => architect.scheduleTarget(...args),
scheduleBuilder: (...args) => architect.scheduleBuilder(...args),
addTeardown(teardown) {

@@ -93,0 +93,0 @@ // No-op as Nx doesn't require an implementation of this function

@@ -20,3 +20,3 @@ "use strict";

async function affected(command, args, extraTargetDependencies = {}, extraOptions = {
excludeTaskDependencies: false,
excludeTaskDependencies: args.excludeTaskDependencies,
loadDotEnvFiles: process.env.NX_LOAD_DOT_ENV_FILES !== 'false',

@@ -23,0 +23,0 @@ }) {

@@ -0,1 +1,2 @@

import { ConnectToNxCloudOptions } from '../../nx-cloud/generators/connect-to-nx-cloud/connect-to-nx-cloud';
import { NxJsonConfiguration } from '../../config/nx-json';

@@ -6,4 +7,5 @@ import { NxArgs } from '../../utils/command-line-utils';

export declare function connectToNxCloudIfExplicitlyAsked(opts: NxArgs): Promise<void>;
export declare function connectWorkspaceToCloud(options: ConnectToNxCloudOptions, directory?: string): Promise<string>;
export declare function connectToNxCloudCommand(command?: string): Promise<boolean>;
export declare function connectExistingRepoToNxCloudPrompt(command?: string, key?: MessageKey): Promise<boolean>;
export declare function connectToNxCloudWithPrompt(command: string): Promise<void>;

@@ -5,2 +5,3 @@ "use strict";

exports.connectToNxCloudIfExplicitlyAsked = connectToNxCloudIfExplicitlyAsked;
exports.connectWorkspaceToCloud = connectWorkspaceToCloud;
exports.connectToNxCloudCommand = connectToNxCloudCommand;

@@ -20,2 +21,4 @@ exports.connectExistingRepoToNxCloudPrompt = connectExistingRepoToNxCloudPrompt;

const chalk = require("chalk");
const ora = require("ora");
const open = require("open");
function onlyDefaultRunnerIsUsed(nxJson) {

@@ -27,3 +30,4 @@ const defaultRunner = nxJson.tasksRunnerOptions?.default?.runner;

// - If no access token defined, uses default
return !(nxJson.nxCloudAccessToken ?? process.env.NX_CLOUD_ACCESS_TOKEN);
return (!(nxJson.nxCloudAccessToken ?? process.env.NX_CLOUD_ACCESS_TOKEN) &&
!nxJson.nxCloudId);
}

@@ -49,4 +53,14 @@ return defaultRunner === 'nx/tasks-runners/default';

}
async function connectWorkspaceToCloud(options, directory = workspace_root_1.workspaceRoot) {
const tree = new tree_1.FsTree(directory, false, 'connect-to-nx-cloud');
const accessToken = await (0, connect_to_nx_cloud_1.connectToNxCloud)(tree, options);
tree.lock();
(0, tree_1.flushChanges)(directory, tree.listChanges());
return accessToken;
}
async function connectToNxCloudCommand(command) {
const nxJson = (0, configuration_1.readNxJson)();
const installationSource = process.env.NX_CONSOLE
? 'nx-console'
: 'nx-connect';
if ((0, nx_cloud_utils_1.isNxCloudUsed)(nxJson)) {

@@ -57,3 +71,3 @@ const token = process.env.NX_CLOUD_ACCESS_TOKEN || nxJson.nxCloudAccessToken;

}
const connectCloudUrl = await (0, url_shorten_1.shortenedCloudUrl)('nx-connect', token);
const connectCloudUrl = await (0, url_shorten_1.createNxCloudOnboardingURL)(installationSource, token);
output_1.output.log({

@@ -70,11 +84,28 @@ title: '✔ This workspace already has Nx Cloud set up',

}
const tree = new tree_1.FsTree(workspace_root_1.workspaceRoot, false, 'connect-to-nx-cloud');
const callback = await (0, connect_to_nx_cloud_1.connectToNxCloud)(tree, {
installationSource: command ?? 'nx-connect',
const token = await connectWorkspaceToCloud({
installationSource: command ?? installationSource,
});
tree.lock();
(0, tree_1.flushChanges)(workspace_root_1.workspaceRoot, tree.listChanges());
await callback();
const connectCloudUrl = await (0, url_shorten_1.createNxCloudOnboardingURL)('nx-connect', token);
try {
const cloudConnectSpinner = ora(`Opening Nx Cloud ${connectCloudUrl} in your browser to connect your workspace.`).start();
await sleep(2000);
await open(connectCloudUrl);
cloudConnectSpinner.succeed();
}
catch (e) {
output_1.output.note({
title: `Your Nx Cloud workspace is ready.`,
bodyLines: [
`To claim it, connect it to your Nx Cloud account:`,
`- Go to the following URL to connect your workspace to Nx Cloud:`,
'',
`${connectCloudUrl}`,
],
});
}
return true;
}
function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
async function connectExistingRepoToNxCloudPrompt(command = 'init', key = 'setupNxCloud') {

@@ -81,0 +112,0 @@ const res = await nxCloudPrompt(key).then((value) => value === 'yes');

@@ -8,5 +8,6 @@ "use strict";

const output_1 = require("../../utils/output");
const child_process_2 = require("../../utils/child-process");
const nx_json_1 = require("../../config/nx-json");
const connect_to_nx_cloud_1 = require("./connect-to-nx-cloud");
const connect_to_nx_cloud_2 = require("../../nx-cloud/generators/connect-to-nx-cloud/connect-to-nx-cloud");
const url_shorten_1 = require("../../nx-cloud/utilities/url-shorten");
async function viewLogs() {

@@ -31,5 +32,6 @@ const cloudUsed = (0, nx_cloud_utils_1.isNxCloudUsed)((0, nx_json_1.readNxJson)());

});
(0, child_process_2.runNxSync)(`g nx:connect-to-nx-cloud --installation-source=view-logs --quiet --no-interactive`, {
stdio: 'ignore',
const token = await (0, connect_to_nx_cloud_1.connectWorkspaceToCloud)({
installationSource: 'view-logs',
});
await (0, connect_to_nx_cloud_2.printSuccessMessage)(token, 'view-logs', await (0, url_shorten_1.repoUsesGithub)());
}

@@ -36,0 +38,0 @@ catch (e) {

@@ -315,2 +315,6 @@ "use strict";

{
command: 'show projects --projects tag:ui-*',
description: 'Show all projects with a tag starting with "ui-". The "projects" option is useful to see which projects would be selected by run-many',
},
{
command: 'show projects --with-target serve',

@@ -317,0 +321,0 @@ description: 'Show all projects with a serve target',

@@ -77,3 +77,3 @@ "use strict";

output_1.output.log({ title: '🛠️ Setting up Nx Cloud' });
(0, utils_1.initCloud)(repoRoot, 'nx-init-monorepo');
await (0, utils_1.initCloud)('nx-init-monorepo');
}

@@ -80,0 +80,0 @@ }

@@ -96,3 +96,3 @@ "use strict";

output_1.output.log({ title: '🛠️ Setting up Nx Cloud' });
(0, utils_1.initCloud)(repoRoot, 'nx-init-nest');
await (0, utils_1.initCloud)('nx-init-nest');
}

@@ -99,0 +99,0 @@ }

@@ -70,4 +70,4 @@ "use strict";

output_1.output.log({ title: '🛠️ Setting up Nx Cloud' });
(0, utils_1.initCloud)(repoRoot, 'nx-init-npm-repo');
await (0, utils_1.initCloud)('nx-init-npm-repo');
}
}

@@ -47,3 +47,3 @@ "use strict";

output_1.output.log({ title: '🛠️ Setting up Nx Cloud' });
(0, utils_1.initCloud)(repoRoot, 'nx-init-angular');
await (0, utils_1.initCloud)('nx-init-angular');
}

@@ -50,0 +50,0 @@ }

@@ -88,3 +88,3 @@ "use strict";

output_1.output.log({ title: '🛠️ Setting up Nx Cloud' });
(0, utils_1.initCloud)(repoRoot, 'nx-init-angular');
await (0, utils_1.initCloud)('nx-init-angular');
}

@@ -91,0 +91,0 @@ };

@@ -9,3 +9,3 @@ import { PackageJson } from '../../../utils/package-json';

export declare function runInstall(repoRoot: string, pmc?: PackageManagerCommands): void;
export declare function initCloud(repoRoot: string, installationSource: 'nx-init-angular' | 'nx-init-cra' | 'nx-init-monorepo' | 'nx-init-nest' | 'nx-init-npm-repo'): void;
export declare function initCloud(installationSource: 'nx-init' | 'nx-init-angular' | 'nx-init-cra' | 'nx-init-monorepo' | 'nx-init-nest' | 'nx-init-npm-repo'): Promise<void>;
export declare function addVsCodeRecommendedExtensions(repoRoot: string, extensions: string[]): void;

@@ -12,0 +12,0 @@ export declare function markRootPackageJsonAsNxProjectLegacy(repoRoot: string, cacheableScripts: string[], pmc: PackageManagerCommands): void;

@@ -15,3 +15,2 @@ "use strict";

const path_1 = require("path");
const child_process_2 = require("../../../utils/child-process");
const fileutils_1 = require("../../../utils/fileutils");

@@ -23,2 +22,5 @@ const output_1 = require("../../../utils/output");

const fs_1 = require("fs");
const connect_to_nx_cloud_1 = require("../../../nx-cloud/generators/connect-to-nx-cloud/connect-to-nx-cloud");
const url_shorten_1 = require("../../../nx-cloud/utilities/url-shorten");
const connect_to_nx_cloud_2 = require("../../connect/connect-to-nx-cloud");
function createNxJsonFile(repoRoot, topologicalTargets, cacheableOperations, scriptOutputs) {

@@ -133,7 +135,7 @@ const nxJsonPath = (0, path_2.joinPathFragments)(repoRoot, 'nx.json');

}
function initCloud(repoRoot, installationSource) {
(0, child_process_2.runNxSync)(`g nx:connect-to-nx-cloud --installationSource=${installationSource} --quiet --no-interactive`, {
stdio: [0, 1, 2],
cwd: repoRoot,
async function initCloud(installationSource) {
const token = await (0, connect_to_nx_cloud_2.connectWorkspaceToCloud)({
installationSource,
});
await (0, connect_to_nx_cloud_1.printSuccessMessage)(token, installationSource, await (0, url_shorten_1.repoUsesGithub)());
}

@@ -140,0 +142,0 @@ function addVsCodeRecommendedExtensions(repoRoot, extensions) {

@@ -0,1 +1,3 @@

import { PackageManagerCommands } from '../../utils/package-manager';
import { NxJsonConfiguration } from '../../config/nx-json';
export interface InitArgs {

@@ -7,2 +9,7 @@ interactive: boolean;

}
export declare function installPlugins(repoRoot: string, plugins: string[], pmc: PackageManagerCommands, updatePackageScripts: boolean): void;
export declare function initHandler(options: InitArgs): Promise<void>;
export declare function detectPlugins(nxJson: NxJsonConfiguration, interactive: boolean): Promise<{
plugins: string[];
updatePackageScripts: boolean;
}>;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.installPlugins = installPlugins;
exports.initHandler = initHandler;
exports.detectPlugins = detectPlugins;
const fs_1 = require("fs");

@@ -20,2 +22,18 @@ const semver_1 = require("semver");

const add_nx_to_monorepo_1 = require("./implementation/add-nx-to-monorepo");
const nx_json_1 = require("../../config/nx-json");
const get_package_name_from_import_path_1 = require("../../utils/get-package-name-from-import-path");
function installPlugins(repoRoot, plugins, pmc, updatePackageScripts) {
if (plugins.length === 0) {
return;
}
(0, utils_1.addDepsToPackageJson)(repoRoot, plugins);
(0, utils_1.runInstall)(repoRoot, pmc);
output_1.output.log({ title: '🔨 Configuring plugins' });
for (const plugin of plugins) {
(0, child_process_2.execSync)(`${pmc.exec} nx g ${plugin}:init --keepExistingVersions ${updatePackageScripts ? '--updatePackageScripts' : ''} --no-interactive`, {
stdio: [0, 1, 2],
cwd: repoRoot,
});
}
}
async function initHandler(options) {

@@ -35,5 +53,6 @@ process.env.NX_RUNNING_NX_INIT = 'true';

(0, add_nx_scripts_1.generateDotNxSetup)(version);
const { plugins } = await detectPlugins();
const nxJson = (0, nx_json_1.readNxJson)(process.cwd());
const { plugins } = await detectPlugins(nxJson, options.interactive);
plugins.forEach((plugin) => {
(0, child_process_2.execSync)(`./nx add ${plugin}`, {
(0, child_process_1.runNxSync)(`add ${plugin}`, {
stdio: 'inherit',

@@ -57,4 +76,2 @@ });

}
output_1.output.log({ title: '🧐 Checking dependencies' });
const { plugins, updatePackageScripts } = await detectPlugins();
const packageJson = (0, fileutils_1.readJsonFile)('package.json');

@@ -82,20 +99,10 @@ if ((0, utils_1.isMonorepo)(packageJson)) {

(0, utils_1.updateGitIgnore)(repoRoot);
(0, utils_1.addDepsToPackageJson)(repoRoot, plugins);
const nxJson = (0, nx_json_1.readNxJson)(repoRoot);
output_1.output.log({ title: '🧐 Checking dependencies' });
const { plugins, updatePackageScripts } = await detectPlugins(nxJson, options.interactive);
output_1.output.log({ title: '📦 Installing Nx' });
(0, utils_1.runInstall)(repoRoot, pmc);
if (plugins.length > 0) {
output_1.output.log({ title: '🔨 Configuring plugins' });
for (const plugin of plugins) {
(0, child_process_2.execSync)(`${pmc.exec} nx g ${plugin}:init --keepExistingVersions ${updatePackageScripts ? '--updatePackageScripts' : ''} --no-interactive`, {
stdio: [0, 1, 2],
cwd: repoRoot,
});
}
}
installPlugins(repoRoot, plugins, pmc, updatePackageScripts);
if (useNxCloud) {
output_1.output.log({ title: '🛠️ Setting up Nx Cloud' });
(0, child_process_2.execSync)(`${pmc.exec} nx g nx:connect-to-nx-cloud --installationSource=nx-init --quiet --hideFormatLogs --no-interactive`, {
stdio: [0, 1, 2],
cwd: repoRoot,
});
await (0, utils_1.initCloud)('nx-init');
}

@@ -127,4 +134,8 @@ (0, utils_1.printFinalMessage)({

};
async function detectPlugins() {
async function detectPlugins(nxJson, interactive) {
let files = ['package.json'].concat(await (0, workspace_context_1.globWithWorkspaceContext)(process.cwd(), ['**/*/package.json']));
const currentPlugins = new Set((nxJson.plugins ?? []).map((p) => {
const plugin = typeof p === 'string' ? p : p.plugin;
return (0, get_package_name_from_import_path_1.getPackageNameFromImportPath)(plugin);
}));
const detectedPlugins = new Set();

@@ -155,2 +166,8 @@ for (const file of files) {

}
// Remove existing plugins
for (const plugin of detectedPlugins) {
if (currentPlugins.has(plugin)) {
detectedPlugins.delete(plugin);
}
}
const plugins = Array.from(detectedPlugins);

@@ -163,2 +180,15 @@ if (plugins.length === 0) {

}
if (!interactive) {
output_1.output.log({
title: `Recommended Plugins:`,
bodyLines: [
`Adding these Nx plugins to integrate with the tools used in your workspace:`,
...plugins.map((p) => `- ${p}`),
],
});
return {
plugins,
updatePackageScripts: true,
};
}
output_1.output.log({

@@ -165,0 +195,0 @@ title: `Recommended Plugins:`,

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.listHandler = listHandler;
const workspace_root_1 = require("../../utils/workspace-root");
const nx_json_1 = require("../../config/nx-json");
const project_graph_1 = require("../../project-graph/project-graph");
const output_1 = require("../../utils/output");
const plugins_1 = require("../../utils/plugins");
const local_plugins_1 = require("../../utils/plugins/local-plugins");
const project_graph_1 = require("../../project-graph/project-graph");
const nx_json_1 = require("../../config/nx-json");
const workspace_root_1 = require("../../utils/workspace-root");
/**

@@ -19,3 +18,2 @@ * List available plugins or capabilities within a specific plugin

async function listHandler(args) {
const nxJson = (0, nx_json_1.readNxJson)();
const projectGraph = await (0, project_graph_1.createProjectGraphAsync)({ exitOnError: true });

@@ -27,10 +25,10 @@ const projects = (0, project_graph_1.readProjectsConfigurationFromProjectGraph)(projectGraph);

else {
const corePlugins = (0, plugins_1.fetchCorePlugins)();
const localPlugins = await (0, local_plugins_1.getLocalWorkspacePlugins)(projects, nxJson);
const nxJson = (0, nx_json_1.readNxJson)();
const localPlugins = await (0, plugins_1.getLocalWorkspacePlugins)(projects, nxJson);
const installedPlugins = await (0, plugins_1.getInstalledPluginsAndCapabilities)(workspace_root_1.workspaceRoot, projects.projects);
if (localPlugins.size) {
(0, local_plugins_1.listLocalWorkspacePlugins)(localPlugins);
(0, plugins_1.listPlugins)(localPlugins, 'Local workspace plugins:');
}
(0, plugins_1.listInstalledPlugins)(installedPlugins);
(0, plugins_1.listCorePlugins)(installedPlugins, corePlugins);
(0, plugins_1.listPlugins)(installedPlugins, 'Installed plugins:');
(0, plugins_1.listAlsoAvailableCorePlugins)(installedPlugins);
output_1.output.note({

@@ -41,9 +39,7 @@ title: 'Community Plugins',

'There are many excellent plugins maintained by the Nx community.',
'Search for the one you need here: https://nx.dev/plugins/registry.',
'Search for the one you need here: https://nx.dev/plugin-registry.',
],
});
output_1.output.note({
title: `Use "nx list [plugin]" to find out more`,
});
output_1.output.note({ title: `Use "nx list [plugin]" to find out more` });
}
}

@@ -33,2 +33,3 @@ "use strict";

const project_graph_1 = require("../../project-graph/project-graph");
const format_changed_files_with_prettier_if_available_1 = require("../../generators/internal-utils/format-changed-files-with-prettier-if-available");
const execAsync = (0, util_1.promisify)(child_process_1.exec);

@@ -673,6 +674,6 @@ function normalizeVersion(version) {

}
function createMigrationsFile(root, migrations) {
(0, fileutils_1.writeJsonFile)((0, path_1.join)(root, 'migrations.json'), { migrations });
async function createMigrationsFile(root, migrations) {
await writeFormattedJsonFile((0, path_1.join)(root, 'migrations.json'), { migrations });
}
function updatePackageJson(root, updatedPackages) {
async function updatePackageJson(root, updatedPackages) {
const packageJsonPath = (0, path_1.join)(root, 'package.json');

@@ -699,3 +700,3 @@ if (!(0, fs_1.existsSync)(packageJsonPath)) {

});
(0, fileutils_1.writeJsonFile)(packageJsonPath, json, {
await writeFormattedJsonFile(packageJsonPath, json, {
appendNewLine: parseOptions.endsWithNewline,

@@ -725,3 +726,3 @@ });

}
(0, fileutils_1.writeJsonFile)(nxJsonPath, nxJson, {
await writeFormattedJsonFile(nxJsonPath, nxJson, {
appendNewLine: parseOptions.endsWithNewline,

@@ -772,6 +773,6 @@ });

const { migrations, packageUpdates, minVersionWithSkippedUpdates } = await migrator.migrate(opts.targetPackage, opts.targetVersion);
updatePackageJson(root, packageUpdates);
await updatePackageJson(root, packageUpdates);
await updateInstallationDetails(root, packageUpdates);
if (migrations.length > 0) {
createMigrationsFile(root, [
await createMigrationsFile(root, [
...addSplitConfigurationMigrationIfAvailable(from, packageUpdates),

@@ -843,2 +844,13 @@ ...migrations,

}
async function writeFormattedJsonFile(filePath, content, options) {
const formattedContent = await (0, format_changed_files_with_prettier_if_available_1.formatFilesWithPrettierIfAvailable)([{ path: filePath, content: JSON.stringify(content) }], workspace_root_1.workspaceRoot, { silent: true });
if (formattedContent.has(filePath)) {
(0, fs_1.writeFileSync)(filePath, formattedContent.get(filePath), {
encoding: 'utf-8',
});
}
else {
(0, fileutils_1.writeJsonFile)(filePath, content, options);
}
}
function addSplitConfigurationMigrationIfAvailable(from, packageJson) {

@@ -907,3 +919,7 @@ if (!packageJson['@nrwl/workspace'])

});
logger_1.logger.info(`Running the following migrations:`);
sortedMigrations.forEach((m) => logger_1.logger.info(`- ${m.package}: ${m.name} (${m.description})`));
logger_1.logger.info(`---------------------------------------------------------\n`);
for (const m of sortedMigrations) {
logger_1.logger.info(`Running migration ${m.package}: ${m.name}`);
try {

@@ -913,10 +929,12 @@ const { collection, collectionPath } = readMigrationCollection(m.package, root);

const changes = await runNxMigration(root, collectionPath, collection, m.name);
logger_1.logger.info(`Ran ${m.name} from ${m.package}`);
logger_1.logger.info(` ${m.description}\n`);
if (changes.length < 1) {
logger_1.logger.info(`No changes were made\n`);
migrationsWithNoChanges.push(m);
// If no changes are made, continue on without printing anything
continue;
}
logger_1.logger.info(`Ran ${m.name} from ${m.package}`);
logger_1.logger.info(` ${m.description}\n`);
logger_1.logger.info('Changes:');
(0, tree_1.printChanges)(changes, ' ');
logger_1.logger.info('');
}

@@ -926,10 +944,12 @@ else {

const { madeChanges, loggingQueue } = await ngCliAdapter.runMigration(root, m.package, m.name, (0, project_graph_1.readProjectsConfigurationFromProjectGraph)(await (0, project_graph_1.createProjectGraphAsync)()).projects, isVerbose);
logger_1.logger.info(`Ran ${m.name} from ${m.package}`);
logger_1.logger.info(` ${m.description}\n`);
if (!madeChanges) {
logger_1.logger.info(`No changes were made\n`);
migrationsWithNoChanges.push(m);
// If no changes are made, continue on without printing anything
continue;
}
logger_1.logger.info(`Ran ${m.name} from ${m.package}`);
logger_1.logger.info(` ${m.description}\n`);
logger_1.logger.info('Changes:');
loggingQueue.forEach((log) => logger_1.logger.info(' ' + log));
logger_1.logger.info('');
}

@@ -936,0 +956,0 @@ if (shouldCreateCommits) {

@@ -13,16 +13,18 @@ "use strict";

const command_object_7 = require("./generate/command-object");
const command_object_8 = require("./init/command-object");
const command_object_9 = require("./list/command-object");
const command_object_10 = require("./migrate/command-object");
const command_object_11 = require("./new/command-object");
const command_object_12 = require("./repair/command-object");
const command_object_13 = require("./report/command-object");
const command_object_14 = require("./run/command-object");
const command_object_15 = require("./run-many/command-object");
const command_object_16 = require("./show/command-object");
const command_object_17 = require("./watch/command-object");
const command_object_18 = require("./reset/command-object");
const command_object_19 = require("./release/command-object");
const command_object_20 = require("./add/command-object");
const command_object_8 = require("./import/command-object");
const command_object_9 = require("./init/command-object");
const command_object_10 = require("./list/command-object");
const command_object_11 = require("./migrate/command-object");
const command_object_12 = require("./new/command-object");
const command_object_13 = require("./repair/command-object");
const command_object_14 = require("./report/command-object");
const command_object_15 = require("./run/command-object");
const command_object_16 = require("./run-many/command-object");
const command_object_17 = require("./show/command-object");
const command_object_18 = require("./watch/command-object");
const command_object_19 = require("./reset/command-object");
const command_object_20 = require("./release/command-object");
const command_object_21 = require("./add/command-object");
const command_objects_1 = require("./deprecated/command-objects");
const command_object_22 = require("./sync/command-object");
// Ensure that the output takes up the available width of the terminal.

@@ -44,3 +46,3 @@ yargs.wrap(yargs.terminalWidth());

.demandCommand(1, '')
.command(command_object_20.yargsAddCommand)
.command(command_object_21.yargsAddCommand)
.command(command_object_1.yargsAffectedBuildCommand)

@@ -59,18 +61,21 @@ .command(command_object_1.yargsAffectedCommand)

.command(command_object_7.yargsGenerateCommand)
.command(command_object_8.yargsInitCommand)
.command(command_object_10.yargsInternalMigrateCommand)
.command(command_object_9.yargsListCommand)
.command(command_object_10.yargsMigrateCommand)
.command(command_object_11.yargsNewCommand)
.command(command_object_8.yargsImportCommand)
.command(command_object_9.yargsInitCommand)
.command(command_object_11.yargsInternalMigrateCommand)
.command(command_object_10.yargsListCommand)
.command(command_object_11.yargsMigrateCommand)
.command(command_object_12.yargsNewCommand)
.command(command_objects_1.yargsPrintAffectedCommand)
.command(command_object_19.yargsReleaseCommand)
.command(command_object_12.yargsRepairCommand)
.command(command_object_13.yargsReportCommand)
.command(command_object_18.yargsResetCommand)
.command(command_object_14.yargsRunCommand)
.command(command_object_15.yargsRunManyCommand)
.command(command_object_16.yargsShowCommand)
.command(command_object_20.yargsReleaseCommand)
.command(command_object_13.yargsRepairCommand)
.command(command_object_14.yargsReportCommand)
.command(command_object_19.yargsResetCommand)
.command(command_object_15.yargsRunCommand)
.command(command_object_16.yargsRunManyCommand)
.command(command_object_17.yargsShowCommand)
.command(command_object_22.yargsSyncCommand)
.command(command_object_22.yargsSyncCheckCommand)
.command(command_object_2.yargsViewLogsCommand)
.command(command_object_17.yargsWatchCommand)
.command(command_object_14.yargsNxInfixCommand)
.command(command_object_18.yargsWatchCommand)
.command(command_object_15.yargsNxInfixCommand)
.scriptName('nx')

@@ -77,0 +82,0 @@ .help()

@@ -1,2 +0,2 @@

import { NxReleaseChangelogConfiguration } from '../../config/nx-json';
import { NxReleaseChangelogConfiguration, NxReleaseConfiguration } from '../../config/nx-json';
import { ChangelogOptions } from './command-object';

@@ -33,8 +33,3 @@ import { Reference } from './utils/git';

export declare const releaseChangelogCLIHandler: (args: ChangelogOptions) => Promise<number>;
/**
* NOTE: This function is also exported for programmatic usage and forms part of the public API
* of Nx. We intentionally do not wrap the implementation with handleErrors because users need
* to have control over their own error handling when using the API.
*/
export declare function releaseChangelog(args: ChangelogOptions): Promise<NxReleaseChangelogResult>;
export declare function createAPI(overrideReleaseConfig: NxReleaseConfiguration): (args: ChangelogOptions) => Promise<NxReleaseChangelogResult>;
export declare function shouldCreateGitHubRelease(changelogConfig: NxReleaseChangelogConfiguration | false | undefined, createReleaseArg?: ChangelogOptions['createRelease'] | undefined): boolean;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.releaseChangelogCLIHandler = void 0;
exports.releaseChangelog = releaseChangelog;
exports.createAPI = createAPI;
exports.shouldCreateGitHubRelease = shouldCreateGitHubRelease;

@@ -23,2 +23,3 @@ const chalk = require("chalk");

const config_1 = require("./config/config");
const deep_merge_json_1 = require("./config/deep-merge-json");
const filter_release_groups_1 = require("./config/filter-release-groups");

@@ -31,290 +32,420 @@ const version_plans_1 = require("./config/version-plans");

const print_changes_1 = require("./utils/print-changes");
const print_config_1 = require("./utils/print-config");
const resolve_changelog_renderer_1 = require("./utils/resolve-changelog-renderer");
const resolve_nx_json_error_message_1 = require("./utils/resolve-nx-json-error-message");
const shared_1 = require("./utils/shared");
const releaseChangelogCLIHandler = (args) => (0, params_1.handleErrors)(args.verbose, () => releaseChangelog(args));
const releaseChangelogCLIHandler = (args) => (0, params_1.handleErrors)(args.verbose, () => createAPI({})(args));
exports.releaseChangelogCLIHandler = releaseChangelogCLIHandler;
/**
* NOTE: This function is also exported for programmatic usage and forms part of the public API
* of Nx. We intentionally do not wrap the implementation with handleErrors because users need
* to have control over their own error handling when using the API.
*/
async function releaseChangelog(args) {
const projectGraph = await (0, project_graph_1.createProjectGraphAsync)({ exitOnError: true });
const nxJson = (0, nx_json_1.readNxJson)();
if (args.verbose) {
process.env.NX_VERBOSE_LOGGING = 'true';
}
// Apply default configuration to any optional user configuration
const { error: configError, nxReleaseConfig } = await (0, config_1.createNxReleaseConfig)(projectGraph, await (0, file_map_utils_1.createProjectFileMapUsingProjectGraph)(projectGraph), nxJson.release);
if (configError) {
return await (0, config_1.handleNxReleaseConfigError)(configError);
}
// The nx release top level command will always override these three git args. This is how we can tell
// if the top level release command was used or if the user is using the changelog subcommand.
// If the user explicitly overrides these args, then it doesn't matter if the top level config is set,
// as all of the git options would be overridden anyway.
if ((args.gitCommit === undefined ||
args.gitTag === undefined ||
args.stageChanges === undefined) &&
nxJson.release?.git) {
const nxJsonMessage = await (0, resolve_nx_json_error_message_1.resolveNxJsonConfigErrorMessage)([
'release',
'git',
]);
output_1.output.error({
title: `The "release.git" property in nx.json may not be used with the "nx release changelog" subcommand or programmatic API. Instead, configure git options for subcommands directly with "release.version.git" and "release.changelog.git".`,
bodyLines: [nxJsonMessage],
});
process.exit(1);
}
const { error: filterError, releaseGroups, releaseGroupToFilteredProjects, } = (0, filter_release_groups_1.filterReleaseGroups)(projectGraph, nxReleaseConfig, args.projects, args.groups);
if (filterError) {
output_1.output.error(filterError);
process.exit(1);
}
const rawVersionPlans = await (0, version_plans_1.readRawVersionPlans)();
(0, version_plans_1.setVersionPlansOnGroups)(rawVersionPlans, releaseGroups, Object.keys(projectGraph.nodes));
if (args.deleteVersionPlans === undefined) {
// default to deleting version plans in this command instead of after versioning
args.deleteVersionPlans = true;
}
const changelogGenerationEnabled = !!nxReleaseConfig.changelog.workspaceChangelog ||
Object.values(nxReleaseConfig.groups).some((g) => g.changelog);
if (!changelogGenerationEnabled) {
output_1.output.warn({
title: `Changelogs are disabled. No changelog entries will be generated`,
bodyLines: [
`To explicitly enable changelog generation, configure "release.changelog.workspaceChangelog" or "release.changelog.projectChangelogs" in nx.json.`,
],
});
return {};
}
const tree = new tree_1.FsTree(workspace_root_1.workspaceRoot, args.verbose);
const useAutomaticFromRef = nxReleaseConfig.changelog?.automaticFromRef || args.firstRelease;
function createAPI(overrideReleaseConfig) {
/**
* For determining the versions to use within changelog files, there are a few different possibilities:
* - the user is using the nx CLI, and therefore passes a single --version argument which represents the version for any and all changelog
* files which will be generated (i.e. both the workspace changelog, and all project changelogs, depending on which of those has been enabled)
* - the user is using the nxReleaseChangelog API programmatically, and:
* - passes only a version property
* - this works in the same way as described above for the CLI
* - passes only a versionData object
* - this is a special case where the user is providing a version for each project, and therefore the version argument is not needed
* - NOTE: it is not possible to generate a workspace level changelog with only a versionData object, and this will produce an error
* - passes both a version and a versionData object
* - in this case, the version property will be used as the reference for the workspace changelog, and the versionData object will be used
* to generate project changelogs
* NOTE: This function is also exported for programmatic usage and forms part of the public API
* of Nx. We intentionally do not wrap the implementation with handleErrors because users need
* to have control over their own error handling when using the API.
*/
const { workspaceChangelogVersion, projectsVersionData } = resolveChangelogVersions(args, releaseGroups, releaseGroupToFilteredProjects);
const to = args.to || 'HEAD';
const toSHA = await (0, git_1.getCommitHash)(to);
const headSHA = to === 'HEAD' ? toSHA : await (0, git_1.getCommitHash)('HEAD');
/**
* Protect the user against attempting to create a new commit when recreating an old release changelog,
* this seems like it would always be unintentional.
*/
const autoCommitEnabled = args.gitCommit ?? nxReleaseConfig.changelog.git.commit;
if (autoCommitEnabled && headSHA !== toSHA) {
throw new Error(`You are attempting to recreate the changelog for an old release, but you have enabled auto-commit mode. Please disable auto-commit mode by updating your nx.json, or passing --git-commit=false`);
}
const commitMessage = args.gitCommitMessage || nxReleaseConfig.changelog.git.commitMessage;
const commitMessageValues = (0, shared_1.createCommitMessageValues)(releaseGroups, releaseGroupToFilteredProjects, projectsVersionData, commitMessage);
// Resolve any git tags as early as possible so that we can hard error in case of any duplicates before reaching the actual git command
const gitTagValues = args.gitTag ?? nxReleaseConfig.changelog.git.tag
? (0, shared_1.createGitTagValues)(releaseGroups, releaseGroupToFilteredProjects, projectsVersionData)
: [];
(0, shared_1.handleDuplicateGitTags)(gitTagValues);
const postGitTasks = [];
let workspaceChangelogChanges = [];
// TODO: remove this after the changelog renderer is refactored to remove coupling with git commits
let workspaceChangelogCommits = [];
// If there are multiple release groups, we'll just skip the workspace changelog anyway.
const versionPlansEnabledForWorkspaceChangelog = releaseGroups[0].versionPlans;
if (versionPlansEnabledForWorkspaceChangelog) {
if (releaseGroups.length === 1) {
const releaseGroup = releaseGroups[0];
if (releaseGroup.projectsRelationship === 'fixed') {
const versionPlans = releaseGroup.versionPlans;
workspaceChangelogChanges = filterHiddenChanges(versionPlans
.map((vp) => {
const parsedMessage = (0, git_1.parseConventionalCommitsMessage)(vp.message);
// only properly formatted conventional commits messages will be included in the changelog
if (!parsedMessage) {
return null;
}
return {
type: parsedMessage.type,
scope: parsedMessage.scope,
description: parsedMessage.description,
body: '',
isBreaking: parsedMessage.breaking,
githubReferences: [],
};
})
.filter(Boolean), nxReleaseConfig.conventionalCommits);
return async function releaseChangelog(args) {
const projectGraph = await (0, project_graph_1.createProjectGraphAsync)({ exitOnError: true });
const nxJson = (0, nx_json_1.readNxJson)();
const userProvidedReleaseConfig = (0, deep_merge_json_1.deepMergeJson)(nxJson.release ?? {}, overrideReleaseConfig ?? {});
if (args.verbose) {
process.env.NX_VERBOSE_LOGGING = 'true';
}
// Apply default configuration to any optional user configuration
const { error: configError, nxReleaseConfig } = await (0, config_1.createNxReleaseConfig)(projectGraph, await (0, file_map_utils_1.createProjectFileMapUsingProjectGraph)(projectGraph), userProvidedReleaseConfig);
if (configError) {
return await (0, config_1.handleNxReleaseConfigError)(configError);
}
// --print-config exits directly as it is not designed to be combined with any other programmatic operations
if (args.printConfig) {
return (0, print_config_1.printConfigAndExit)({
userProvidedReleaseConfig,
nxReleaseConfig,
isDebug: args.printConfig === 'debug',
});
}
// The nx release top level command will always override these three git args. This is how we can tell
// if the top level release command was used or if the user is using the changelog subcommand.
// If the user explicitly overrides these args, then it doesn't matter if the top level config is set,
// as all of the git options would be overridden anyway.
if ((args.gitCommit === undefined ||
args.gitTag === undefined ||
args.stageChanges === undefined) &&
userProvidedReleaseConfig.git) {
const nxJsonMessage = await (0, resolve_nx_json_error_message_1.resolveNxJsonConfigErrorMessage)([
'release',
'git',
]);
output_1.output.error({
title: `The "release.git" property in nx.json may not be used with the "nx release changelog" subcommand or programmatic API. Instead, configure git options for subcommands directly with "release.version.git" and "release.changelog.git".`,
bodyLines: [nxJsonMessage],
});
process.exit(1);
}
const { error: filterError, releaseGroups, releaseGroupToFilteredProjects, } = (0, filter_release_groups_1.filterReleaseGroups)(projectGraph, nxReleaseConfig, args.projects, args.groups);
if (filterError) {
output_1.output.error(filterError);
process.exit(1);
}
const rawVersionPlans = await (0, version_plans_1.readRawVersionPlans)();
(0, version_plans_1.setResolvedVersionPlansOnGroups)(rawVersionPlans, releaseGroups, Object.keys(projectGraph.nodes));
if (args.deleteVersionPlans === undefined) {
// default to deleting version plans in this command instead of after versioning
args.deleteVersionPlans = true;
}
const changelogGenerationEnabled = !!nxReleaseConfig.changelog.workspaceChangelog ||
Object.values(nxReleaseConfig.groups).some((g) => g.changelog);
if (!changelogGenerationEnabled) {
output_1.output.warn({
title: `Changelogs are disabled. No changelog entries will be generated`,
bodyLines: [
`To explicitly enable changelog generation, configure "release.changelog.workspaceChangelog" or "release.changelog.projectChangelogs" in nx.json.`,
],
});
return {};
}
const tree = new tree_1.FsTree(workspace_root_1.workspaceRoot, args.verbose);
const useAutomaticFromRef = nxReleaseConfig.changelog?.automaticFromRef || args.firstRelease;
/**
* For determining the versions to use within changelog files, there are a few different possibilities:
* - the user is using the nx CLI, and therefore passes a single --version argument which represents the version for any and all changelog
* files which will be generated (i.e. both the workspace changelog, and all project changelogs, depending on which of those has been enabled)
* - the user is using the nxReleaseChangelog API programmatically, and:
* - passes only a version property
* - this works in the same way as described above for the CLI
* - passes only a versionData object
* - this is a special case where the user is providing a version for each project, and therefore the version argument is not needed
* - NOTE: it is not possible to generate a workspace level changelog with only a versionData object, and this will produce an error
* - passes both a version and a versionData object
* - in this case, the version property will be used as the reference for the workspace changelog, and the versionData object will be used
* to generate project changelogs
*/
const { workspaceChangelogVersion, projectsVersionData } = resolveChangelogVersions(args, releaseGroups, releaseGroupToFilteredProjects);
const to = args.to || 'HEAD';
const toSHA = await (0, git_1.getCommitHash)(to);
const headSHA = to === 'HEAD' ? toSHA : await (0, git_1.getCommitHash)('HEAD');
/**
* Protect the user against attempting to create a new commit when recreating an old release changelog,
* this seems like it would always be unintentional.
*/
const autoCommitEnabled = args.gitCommit ?? nxReleaseConfig.changelog.git.commit;
if (autoCommitEnabled && headSHA !== toSHA) {
throw new Error(`You are attempting to recreate the changelog for an old release, but you have enabled auto-commit mode. Please disable auto-commit mode by updating your nx.json, or passing --git-commit=false`);
}
const commitMessage = args.gitCommitMessage || nxReleaseConfig.changelog.git.commitMessage;
const commitMessageValues = (0, shared_1.createCommitMessageValues)(releaseGroups, releaseGroupToFilteredProjects, projectsVersionData, commitMessage);
// Resolve any git tags as early as possible so that we can hard error in case of any duplicates before reaching the actual git command
const gitTagValues = args.gitTag ?? nxReleaseConfig.changelog.git.tag
? (0, shared_1.createGitTagValues)(releaseGroups, releaseGroupToFilteredProjects, projectsVersionData)
: [];
(0, shared_1.handleDuplicateGitTags)(gitTagValues);
const postGitTasks = [];
let workspaceChangelogChanges = [];
// TODO: remove this after the changelog renderer is refactored to remove coupling with git commits
let workspaceChangelogCommits = [];
// If there are multiple release groups, we'll just skip the workspace changelog anyway.
const versionPlansEnabledForWorkspaceChangelog = releaseGroups[0].resolvedVersionPlans;
if (versionPlansEnabledForWorkspaceChangelog) {
if (releaseGroups.length === 1) {
const releaseGroup = releaseGroups[0];
if (releaseGroup.projectsRelationship === 'fixed') {
const versionPlans = releaseGroup.resolvedVersionPlans;
workspaceChangelogChanges = versionPlans
.flatMap((vp) => {
const releaseType = versionPlanSemverReleaseTypeToChangelogType(vp.groupVersionBump);
const changes = !vp.triggeredByProjects
? {
type: releaseType.type,
scope: '',
description: vp.message,
body: '',
isBreaking: releaseType.isBreaking,
githubReferences: [],
affectedProjects: '*',
}
: vp.triggeredByProjects.map((project) => {
return {
type: releaseType.type,
scope: project,
description: vp.message,
body: '',
// TODO: what about github references?
isBreaking: releaseType.isBreaking,
githubReferences: [],
affectedProjects: [project],
};
});
return changes;
})
.filter(Boolean);
}
}
}
}
else {
let workspaceChangelogFromRef = args.from ||
(await (0, git_1.getLatestGitTagForPattern)(nxReleaseConfig.releaseTagPattern))?.tag;
if (!workspaceChangelogFromRef) {
if (useAutomaticFromRef) {
workspaceChangelogFromRef = await (0, git_1.getFirstGitCommit)();
if (args.verbose) {
console.log(`Determined workspace --from ref from the first commit in the workspace: ${workspaceChangelogFromRef}`);
else {
let workspaceChangelogFromRef = args.from ||
(await (0, git_1.getLatestGitTagForPattern)(nxReleaseConfig.releaseTagPattern))
?.tag;
if (!workspaceChangelogFromRef) {
if (useAutomaticFromRef) {
workspaceChangelogFromRef = await (0, git_1.getFirstGitCommit)();
if (args.verbose) {
console.log(`Determined workspace --from ref from the first commit in the workspace: ${workspaceChangelogFromRef}`);
}
}
else {
throw new Error(`Unable to determine the previous git tag. If this is the first release of your workspace, use the --first-release option or set the "release.changelog.automaticFromRef" config property in nx.json to generate a changelog from the first commit. Otherwise, be sure to configure the "release.releaseTagPattern" property in nx.json to match the structure of your repository's git tags.`);
}
}
else {
throw new Error(`Unable to determine the previous git tag. If this is the first release of your workspace, use the --first-release option or set the "release.changelog.automaticFromRef" config property in nx.json to generate a changelog from the first commit. Otherwise, be sure to configure the "release.releaseTagPattern" property in nx.json to match the structure of your repository's git tags.`);
}
// Make sure that the fromRef is actually resolvable
const workspaceChangelogFromSHA = await (0, git_1.getCommitHash)(workspaceChangelogFromRef);
workspaceChangelogCommits = await getCommits(workspaceChangelogFromSHA, toSHA);
workspaceChangelogChanges = filterHiddenChanges(workspaceChangelogCommits.map((c) => {
return {
type: c.type,
scope: c.scope,
description: c.description,
body: c.body,
isBreaking: c.isBreaking,
githubReferences: c.references,
author: c.author,
shortHash: c.shortHash,
revertedHashes: c.revertedHashes,
affectedProjects: '*',
};
}), nxReleaseConfig.conventionalCommits);
}
// Make sure that the fromRef is actually resolvable
const workspaceChangelogFromSHA = await (0, git_1.getCommitHash)(workspaceChangelogFromRef);
workspaceChangelogCommits = await getCommits(workspaceChangelogFromSHA, toSHA);
workspaceChangelogChanges = filterHiddenChanges(workspaceChangelogCommits.map((c) => {
return {
type: c.type,
scope: c.scope,
description: c.description,
body: c.body,
isBreaking: c.isBreaking,
githubReferences: c.references,
author: c.author,
shortHash: c.shortHash,
revertedHashes: c.revertedHashes,
affectedProjects: '*',
};
}), nxReleaseConfig.conventionalCommits);
}
const workspaceChangelog = await generateChangelogForWorkspace({
tree,
args,
projectGraph,
nxReleaseConfig,
workspaceChangelogVersion,
changes: workspaceChangelogChanges,
// TODO: remove this after the changelog renderer is refactored to remove coupling with git commits
commits: filterHiddenCommits(workspaceChangelogCommits, nxReleaseConfig.conventionalCommits),
});
if (workspaceChangelog &&
shouldCreateGitHubRelease(nxReleaseConfig.changelog.workspaceChangelog, args.createRelease)) {
let hasPushed = false;
postGitTasks.push(async (latestCommit) => {
if (!hasPushed) {
output_1.output.logSingleLine(`Pushing to git remote`);
// Before we can create/update the release we need to ensure the commit exists on the remote
await (0, git_1.gitPush)({
gitRemote: args.gitRemote,
dryRun: args.dryRun,
verbose: args.verbose,
});
hasPushed = true;
}
output_1.output.logSingleLine(`Creating GitHub Release`);
await (0, github_1.createOrUpdateGithubRelease)(workspaceChangelog.releaseVersion, workspaceChangelog.contents, latestCommit, { dryRun: args.dryRun });
const workspaceChangelog = await generateChangelogForWorkspace({
tree,
args,
projectGraph,
nxReleaseConfig,
workspaceChangelogVersion,
changes: workspaceChangelogChanges,
// TODO: remove this after the changelog renderer is refactored to remove coupling with git commits
commits: filterHiddenCommits(workspaceChangelogCommits, nxReleaseConfig.conventionalCommits),
});
}
/**
* Compute any additional dependency bumps up front because there could be cases of circular dependencies,
* and figuring them out during the main iteration would be too late.
*/
const projectToAdditionalDependencyBumps = new Map();
for (const releaseGroup of releaseGroups) {
if (releaseGroup.projectsRelationship !== 'independent') {
continue;
if (workspaceChangelog &&
shouldCreateGitHubRelease(nxReleaseConfig.changelog.workspaceChangelog, args.createRelease)) {
let hasPushed = false;
postGitTasks.push(async (latestCommit) => {
if (!hasPushed) {
output_1.output.logSingleLine(`Pushing to git remote`);
// Before we can create/update the release we need to ensure the commit exists on the remote
await (0, git_1.gitPush)({
gitRemote: args.gitRemote,
dryRun: args.dryRun,
verbose: args.verbose,
});
hasPushed = true;
}
output_1.output.logSingleLine(`Creating GitHub Release`);
await (0, github_1.createOrUpdateGithubRelease)(workspaceChangelog.releaseVersion, workspaceChangelog.contents, latestCommit, { dryRun: args.dryRun });
});
}
for (const project of releaseGroup.projects) {
// If the project does not have any changes, do not process its dependents
if (!projectsVersionData[project] ||
projectsVersionData[project].newVersion === null) {
/**
* Compute any additional dependency bumps up front because there could be cases of circular dependencies,
* and figuring them out during the main iteration would be too late.
*/
const projectToAdditionalDependencyBumps = new Map();
for (const releaseGroup of releaseGroups) {
if (releaseGroup.projectsRelationship !== 'independent') {
continue;
}
const dependentProjects = (projectsVersionData[project].dependentProjects || [])
.map((dep) => {
return {
dependencyName: dep.source,
newVersion: projectsVersionData[dep.source].newVersion,
};
})
.filter((b) => b.newVersion !== null);
for (const dependent of dependentProjects) {
const additionalDependencyBumpsForProject = projectToAdditionalDependencyBumps.has(dependent.dependencyName)
? projectToAdditionalDependencyBumps.get(dependent.dependencyName)
: [];
additionalDependencyBumpsForProject.push({
dependencyName: project,
newVersion: projectsVersionData[project].newVersion,
});
projectToAdditionalDependencyBumps.set(dependent.dependencyName, additionalDependencyBumpsForProject);
for (const project of releaseGroup.projects) {
// If the project does not have any changes, do not process its dependents
if (!projectsVersionData[project] ||
projectsVersionData[project].newVersion === null) {
continue;
}
const dependentProjects = (projectsVersionData[project].dependentProjects || [])
.map((dep) => {
return {
dependencyName: dep.source,
newVersion: projectsVersionData[dep.source].newVersion,
};
})
.filter((b) => b.newVersion !== null);
for (const dependent of dependentProjects) {
const additionalDependencyBumpsForProject = projectToAdditionalDependencyBumps.has(dependent.dependencyName)
? projectToAdditionalDependencyBumps.get(dependent.dependencyName)
: [];
additionalDependencyBumpsForProject.push({
dependencyName: project,
newVersion: projectsVersionData[project].newVersion,
});
projectToAdditionalDependencyBumps.set(dependent.dependencyName, additionalDependencyBumpsForProject);
}
}
}
}
const allProjectChangelogs = {};
for (const releaseGroup of releaseGroups) {
const config = releaseGroup.changelog;
// The entire feature is disabled at the release group level, exit early
if (config === false) {
continue;
}
const projects = args.projects?.length
? // If the user has passed a list of projects, we need to use the filtered list of projects within the release group, plus any dependents
Array.from(releaseGroupToFilteredProjects.get(releaseGroup)).flatMap((project) => {
return [
project,
...(projectsVersionData[project]?.dependentProjects.map((dep) => dep.source) || []),
];
})
: // Otherwise, we use the full list of projects within the release group
releaseGroup.projects;
const projectNodes = projects.map((name) => projectGraph.nodes[name]);
if (releaseGroup.projectsRelationship === 'independent') {
for (const project of projectNodes) {
let changes = null;
const allProjectChangelogs = {};
for (const releaseGroup of releaseGroups) {
const config = releaseGroup.changelog;
// The entire feature is disabled at the release group level, exit early
if (config === false) {
continue;
}
const projects = args.projects?.length
? // If the user has passed a list of projects, we need to use the filtered list of projects within the release group, plus any dependents
Array.from(releaseGroupToFilteredProjects.get(releaseGroup)).flatMap((project) => {
return [
project,
...(projectsVersionData[project]?.dependentProjects.map((dep) => dep.source) || []),
];
})
: // Otherwise, we use the full list of projects within the release group
releaseGroup.projects;
const projectNodes = projects.map((name) => projectGraph.nodes[name]);
if (releaseGroup.projectsRelationship === 'independent') {
for (const project of projectNodes) {
let changes = null;
// TODO: remove this after the changelog renderer is refactored to remove coupling with git commits
let commits;
if (releaseGroup.resolvedVersionPlans) {
changes = releaseGroup.resolvedVersionPlans
.map((vp) => {
const bumpForProject = vp.projectVersionBumps[project.name];
if (!bumpForProject) {
return null;
}
const releaseType = versionPlanSemverReleaseTypeToChangelogType(bumpForProject);
return {
type: releaseType.type,
scope: project.name,
description: vp.message,
body: '',
isBreaking: releaseType.isBreaking,
affectedProjects: Object.keys(vp.projectVersionBumps),
// TODO: can we include github references when using version plans?
githubReferences: [],
};
})
.filter(Boolean);
}
else {
let fromRef = args.from ||
(await (0, git_1.getLatestGitTagForPattern)(releaseGroup.releaseTagPattern, {
projectName: project.name,
releaseGroupName: releaseGroup.name,
}))?.tag;
if (!fromRef && useAutomaticFromRef) {
const firstCommit = await (0, git_1.getFirstGitCommit)();
const allCommits = await getCommits(firstCommit, toSHA);
const commitsForProject = allCommits.filter((c) => c.affectedFiles.find((f) => f.startsWith(project.data.root)));
fromRef = commitsForProject[0]?.shortHash;
if (args.verbose) {
console.log(`Determined --from ref for ${project.name} from the first commit in which it exists: ${fromRef}`);
}
commits = commitsForProject;
}
if (!fromRef && !commits) {
throw new Error(`Unable to determine the previous git tag. If this is the first release of your workspace, use the --first-release option or set the "release.changelog.automaticFromRef" config property in nx.json to generate a changelog from the first commit. Otherwise, be sure to configure the "release.releaseTagPattern" property in nx.json to match the structure of your repository's git tags.`);
}
if (!commits) {
commits = await getCommits(fromRef, toSHA);
}
const { fileMap } = await (0, file_map_utils_1.createFileMapUsingProjectGraph)(projectGraph);
const fileToProjectMap = createFileToProjectMap(fileMap.projectFileMap);
changes = filterHiddenChanges(commits.map((c) => ({
type: c.type,
scope: c.scope,
description: c.description,
body: c.body,
isBreaking: c.isBreaking,
githubReferences: c.references,
author: c.author,
shortHash: c.shortHash,
revertedHashes: c.revertedHashes,
affectedProjects: commitChangesNonProjectFiles(c, fileMap.nonProjectFiles)
? '*'
: getProjectsAffectedByCommit(c, fileToProjectMap),
})), nxReleaseConfig.conventionalCommits);
}
const projectChangelogs = await generateChangelogForProjects({
tree,
args,
projectGraph,
changes,
projectsVersionData,
releaseGroup,
projects: [project],
nxReleaseConfig,
projectToAdditionalDependencyBumps,
// TODO: remove this after the changelog renderer is refactored to remove coupling with git commits
commits: filterHiddenCommits(commits, nxReleaseConfig.conventionalCommits),
});
let hasPushed = false;
for (const [projectName, projectChangelog] of Object.entries(projectChangelogs)) {
if (projectChangelogs &&
shouldCreateGitHubRelease(releaseGroup.changelog, args.createRelease)) {
postGitTasks.push(async (latestCommit) => {
if (!hasPushed) {
output_1.output.logSingleLine(`Pushing to git remote`);
// Before we can create/update the release we need to ensure the commit exists on the remote
await (0, git_1.gitPush)({
gitRemote: args.gitRemote,
dryRun: args.dryRun,
verbose: args.verbose,
});
hasPushed = true;
}
output_1.output.logSingleLine(`Creating GitHub Release`);
await (0, github_1.createOrUpdateGithubRelease)(projectChangelog.releaseVersion, projectChangelog.contents, latestCommit, { dryRun: args.dryRun });
});
}
allProjectChangelogs[projectName] = projectChangelog;
}
}
}
else {
let changes = [];
// TODO: remove this after the changelog renderer is refactored to remove coupling with git commits
let commits;
if (releaseGroup.versionPlans) {
changes = filterHiddenChanges(releaseGroup.versionPlans
.map((vp) => {
const parsedMessage = (0, git_1.parseConventionalCommitsMessage)(vp.message);
// only properly formatted conventional commits messages will be included in the changelog
if (!parsedMessage) {
return null;
}
return {
type: parsedMessage.type,
scope: parsedMessage.scope,
description: parsedMessage.description,
body: '',
isBreaking: parsedMessage.breaking,
affectedProjects: Object.keys(vp.projectVersionBumps),
githubReferences: [],
};
let commits = [];
if (releaseGroup.resolvedVersionPlans) {
changes = releaseGroup.resolvedVersionPlans
.flatMap((vp) => {
const releaseType = versionPlanSemverReleaseTypeToChangelogType(vp.groupVersionBump);
const changes = !vp.triggeredByProjects
? {
type: releaseType.type,
scope: '',
description: vp.message,
body: '',
isBreaking: releaseType.isBreaking,
githubReferences: [],
affectedProjects: '*',
}
: vp.triggeredByProjects.map((project) => {
return {
type: releaseType.type,
scope: project,
description: vp.message,
body: '',
// TODO: what about github references?
isBreaking: releaseType.isBreaking,
githubReferences: [],
affectedProjects: [project],
};
});
return changes;
})
.filter(Boolean), nxReleaseConfig.conventionalCommits);
.filter(Boolean);
}
else {
let fromRef = args.from ||
(await (0, git_1.getLatestGitTagForPattern)(releaseGroup.releaseTagPattern, {
projectName: project.name,
}))?.tag;
if (!fromRef && useAutomaticFromRef) {
const firstCommit = await (0, git_1.getFirstGitCommit)();
const allCommits = await getCommits(firstCommit, toSHA);
const commitsForProject = allCommits.filter((c) => c.affectedFiles.find((f) => f.startsWith(project.data.root)));
fromRef = commitsForProject[0]?.shortHash;
if (args.verbose) {
console.log(`Determined --from ref for ${project.name} from the first commit in which it exists: ${fromRef}`);
(await (0, git_1.getLatestGitTagForPattern)(releaseGroup.releaseTagPattern))
?.tag;
if (!fromRef) {
if (useAutomaticFromRef) {
fromRef = await (0, git_1.getFirstGitCommit)();
if (args.verbose) {
console.log(`Determined release group --from ref from the first commit in the workspace: ${fromRef}`);
}
}
commits = commitsForProject;
else {
throw new Error(`Unable to determine the previous git tag. If this is the first release of your release group, use the --first-release option or set the "release.changelog.automaticFromRef" config property in nx.json to generate a changelog from the first commit. Otherwise, be sure to configure the "release.releaseTagPattern" property in nx.json to match the structure of your repository's git tags.`);
}
}
if (!fromRef && !commits) {
throw new Error(`Unable to determine the previous git tag. If this is the first release of your workspace, use the --first-release option or set the "release.changelog.automaticFromRef" config property in nx.json to generate a changelog from the first commit. Otherwise, be sure to configure the "release.releaseTagPattern" property in nx.json to match the structure of your repository's git tags.`);
}
if (!commits) {
commits = await getCommits(fromRef, toSHA);
}
// Make sure that the fromRef is actually resolvable
const fromSHA = await (0, git_1.getCommitHash)(fromRef);
const { fileMap } = await (0, file_map_utils_1.createFileMapUsingProjectGraph)(projectGraph);
const fileToProjectMap = createFileToProjectMap(fileMap.projectFileMap);
commits = await getCommits(fromSHA, toSHA);
changes = filterHiddenChanges(commits.map((c) => ({

@@ -342,3 +473,3 @@ type: c.type,

releaseGroup,
projects: [project],
projects: projectNodes,
nxReleaseConfig,

@@ -372,101 +503,7 @@ projectToAdditionalDependencyBumps,

}
else {
let changes = [];
// TODO: remove this after the changelog renderer is refactored to remove coupling with git commits
let commits = [];
if (releaseGroup.versionPlans) {
changes = filterHiddenChanges(releaseGroup.versionPlans
.map((vp) => {
const parsedMessage = (0, git_1.parseConventionalCommitsMessage)(vp.message);
// only properly formatted conventional commits messages will be included in the changelog
if (!parsedMessage) {
return null;
}
return {
type: parsedMessage.type,
scope: parsedMessage.scope,
description: parsedMessage.description,
body: '',
isBreaking: parsedMessage.breaking,
githubReferences: [],
affectedProjects: '*',
};
})
.filter(Boolean), nxReleaseConfig.conventionalCommits);
}
else {
let fromRef = args.from ||
(await (0, git_1.getLatestGitTagForPattern)(releaseGroup.releaseTagPattern))
?.tag;
if (!fromRef) {
if (useAutomaticFromRef) {
fromRef = await (0, git_1.getFirstGitCommit)();
if (args.verbose) {
console.log(`Determined release group --from ref from the first commit in the workspace: ${fromRef}`);
}
}
else {
throw new Error(`Unable to determine the previous git tag. If this is the first release of your release group, use the --first-release option or set the "release.changelog.automaticFromRef" config property in nx.json to generate a changelog from the first commit. Otherwise, be sure to configure the "release.releaseTagPattern" property in nx.json to match the structure of your repository's git tags.`);
}
}
// Make sure that the fromRef is actually resolvable
const fromSHA = await (0, git_1.getCommitHash)(fromRef);
const { fileMap } = await (0, file_map_utils_1.createFileMapUsingProjectGraph)(projectGraph);
const fileToProjectMap = createFileToProjectMap(fileMap.projectFileMap);
commits = await getCommits(fromSHA, toSHA);
changes = filterHiddenChanges(commits.map((c) => ({
type: c.type,
scope: c.scope,
description: c.description,
body: c.body,
isBreaking: c.isBreaking,
githubReferences: c.references,
author: c.author,
shortHash: c.shortHash,
revertedHashes: c.revertedHashes,
affectedProjects: commitChangesNonProjectFiles(c, fileMap.nonProjectFiles)
? '*'
: getProjectsAffectedByCommit(c, fileToProjectMap),
})), nxReleaseConfig.conventionalCommits);
}
const projectChangelogs = await generateChangelogForProjects({
tree,
args,
projectGraph,
changes,
projectsVersionData,
releaseGroup,
projects: projectNodes,
nxReleaseConfig,
projectToAdditionalDependencyBumps,
// TODO: remove this after the changelog renderer is refactored to remove coupling with git commits
commits: filterHiddenCommits(commits, nxReleaseConfig.conventionalCommits),
});
let hasPushed = false;
for (const [projectName, projectChangelog] of Object.entries(projectChangelogs)) {
if (projectChangelogs &&
shouldCreateGitHubRelease(releaseGroup.changelog, args.createRelease)) {
postGitTasks.push(async (latestCommit) => {
if (!hasPushed) {
output_1.output.logSingleLine(`Pushing to git remote`);
// Before we can create/update the release we need to ensure the commit exists on the remote
await (0, git_1.gitPush)({
gitRemote: args.gitRemote,
dryRun: args.dryRun,
verbose: args.verbose,
});
hasPushed = true;
}
output_1.output.logSingleLine(`Creating GitHub Release`);
await (0, github_1.createOrUpdateGithubRelease)(projectChangelog.releaseVersion, projectChangelog.contents, latestCommit, { dryRun: args.dryRun });
});
}
allProjectChangelogs[projectName] = projectChangelog;
}
}
}
await applyChangesAndExit(args, nxReleaseConfig, tree, toSHA, postGitTasks, commitMessageValues, gitTagValues, releaseGroups);
return {
workspaceChangelog,
projectChangelogs: allProjectChangelogs,
await applyChangesAndExit(args, nxReleaseConfig, tree, toSHA, postGitTasks, commitMessageValues, gitTagValues, releaseGroups);
return {
workspaceChangelog,
projectChangelogs: allProjectChangelogs,
};
};

@@ -555,4 +592,4 @@ }

releaseGroups.forEach((group) => {
if (group.versionPlans) {
group.versionPlans.forEach((plan) => {
if (group.resolvedVersionPlans) {
group.resolvedVersionPlans.forEach((plan) => {
(0, fs_extra_1.removeSync)(plan.absolutePath);

@@ -907,1 +944,17 @@ planFiles.add(plan.relativePath);

}
function versionPlanSemverReleaseTypeToChangelogType(bump) {
switch (bump) {
case 'premajor':
case 'major':
return { type: 'feat', isBreaking: true };
case 'preminor':
case 'minor':
return { type: 'feat', isBreaking: false };
case 'prerelease':
case 'prepatch':
case 'patch':
return { type: 'fix', isBreaking: false };
default:
throw new Error(`Invalid semver bump type: ${bump}`);
}
}
import { CommandModule } from 'yargs';
import { OutputStyle, RunManyOptions } from '../yargs-utils/shared-options';
import { VersionData } from './utils/shared';
export interface NxReleaseArgs {
export interface BaseNxReleaseArgs {
verbose?: boolean;
printConfig?: boolean | 'debug';
}
export interface NxReleaseArgs extends BaseNxReleaseArgs {
groups?: string[];
projects?: string[];
dryRun?: boolean;
verbose?: boolean;
}

@@ -45,3 +48,11 @@ interface GitCommitAndTagOptions {

};
export type PlanCheckOptions = BaseNxReleaseArgs & {
base?: string;
head?: string;
files?: string;
uncommitted?: boolean;
untracked?: boolean;
};
export type ReleaseOptions = NxReleaseArgs & FirstReleaseArgs & {
specifier?: string;
yes?: boolean;

@@ -48,0 +59,0 @@ skipPublish?: boolean;

@@ -6,2 +6,3 @@ "use strict";

const nx_json_1 = require("../../config/nx-json");
const command_line_utils_1 = require("../../utils/command-line-utils");
const logger_1 = require("../../utils/logger");

@@ -18,2 +19,3 @@ const shared_options_1 = require("../yargs-utils/shared-options");

.command(planCommand)
.command(planCheckCommand)
.demandCommand()

@@ -44,2 +46,16 @@ // Error on typos/mistyped CLI args, there is no reason to support arbitrary unknown args for these commands

})
// NOTE: The camel case format is required for the coerce() function to be called correctly. It still supports --print-config casing.
.option('printConfig', {
type: 'string',
describe: 'Print the resolved nx release configuration that would be used for the current command and then exit',
coerce: (val) => {
if (val === '') {
return true;
}
if (val === 'false') {
return false;
}
return val;
},
})
.check((argv) => {

@@ -197,2 +213,3 @@ if (argv.groups && argv.projects) {

aliases: ['pl'],
// TODO: Remove this when docs are added
// Create a plan to pick a new version and generate a changelog entry.

@@ -229,24 +246,20 @@ // Hidden for now until the feature is more stable

};
const planCheckCommand = {
command: 'plan:check',
// TODO: Remove this when docs are added
// Create a plan to pick a new version and generate a changelog entry.
// Hidden for now until the feature is more stable
describe: false,
builder: (yargs) => (0, shared_options_1.withAffectedOptions)(yargs),
handler: async (args) => {
const release = await Promise.resolve().then(() => require('./plan-check'));
const result = await release.releasePlanCheckCLIHandler(args);
process.exit(result);
},
};
function coerceParallelOption(args) {
if (args['parallel'] === 'false' || args['parallel'] === false) {
return {
...args,
parallel: 1,
};
}
else if (args['parallel'] === 'true' ||
args['parallel'] === true ||
args['parallel'] === '') {
return {
...args,
parallel: Number(args['maxParallel'] || args['max-parallel'] || 3),
};
}
else if (args['parallel'] !== undefined) {
return {
...args,
parallel: Number(args['parallel']),
};
}
return args;
return {
...args,
parallel: (0, command_line_utils_1.readParallelFromArgsAndEnv)(args),
};
}

@@ -253,0 +266,0 @@ function withGitCommitAndGitTagOptions(yargs) {

@@ -76,2 +76,6 @@ "use strict";

const defaultFixedReleaseTagPattern = 'v{version}';
/**
* TODO: in v20, make it so that this pattern is used by default when any custom groups are used
*/
const defaultFixedGroupReleaseTagPattern = '{releaseGroupName}-v{version}';
const defaultIndependentReleaseTagPattern = '{projectName}@{version}';

@@ -144,3 +148,4 @@ const workspaceProjectsRelationship = userConfig.projectsRelationship || 'fixed';

conventionalCommits: conventional_commits_1.DEFAULT_CONVENTIONAL_COMMITS_CONFIG,
versionPlans: false,
versionPlans: (userConfig.versionPlans ||
false),
};

@@ -201,3 +206,4 @@ const groupProjectsRelationship = userConfig.projectsRelationship || WORKSPACE_DEFAULTS.projectsRelationship;

], normalizeTrueToEmptyObject(userConfig.changelog));
const rootVersionPlansConfig = userConfig.versionPlans ?? WORKSPACE_DEFAULTS.versionPlans;
const rootVersionPlansConfig = (userConfig.versionPlans ??
WORKSPACE_DEFAULTS.versionPlans);
const rootConventionalCommitsConfig = deepMergeDefaults([WORKSPACE_DEFAULTS.conventionalCommits], fillUnspecifiedConventionalCommitsProperties(normalizeConventionalCommitsConfig(userConfig.conventionalCommits)));

@@ -204,0 +210,0 @@ // these options are not supported at the group level, only the root/command level

import { ProjectGraph } from '../../../config/project-graph';
import { NxReleaseConfig } from './config';
import { GroupVersionPlan, ProjectsVersionPlan } from './version-plans';
export type ReleaseGroupWithName = Omit<NxReleaseConfig['groups'][string], 'versionPlans'> & {
export type ReleaseGroupWithName = NxReleaseConfig['groups'][string] & {
name: string;
versionPlans: (ProjectsVersionPlan | GroupVersionPlan)[] | false;
resolvedVersionPlans: (ProjectsVersionPlan | GroupVersionPlan)[] | false;
};

@@ -8,0 +8,0 @@ export declare function filterReleaseGroups(projectGraph: ProjectGraph, nxReleaseConfig: NxReleaseConfig, projectsFilter?: string[], groupsFilter?: string[]): {

@@ -12,3 +12,3 @@ "use strict";

name,
versionPlans: group.versionPlans ? [] : false,
resolvedVersionPlans: group.versionPlans ? [] : false,
};

@@ -15,0 +15,0 @@ });

@@ -18,2 +18,7 @@ import { ReleaseType } from 'semver';

groupVersionBump: ReleaseType;
/**
* Will not be set if the group name was the trigger, otherwise will be a list of
* all the individual project names explicitly found in the version plan file.
*/
triggeredByProjects?: string[];
}

@@ -24,3 +29,3 @@ export interface ProjectsVersionPlan extends VersionPlan {

export declare function readRawVersionPlans(): Promise<RawVersionPlan[]>;
export declare function setVersionPlansOnGroups(rawVersionPlans: RawVersionPlan[], releaseGroups: ReleaseGroupWithName[], allProjectNamesInWorkspace: string[]): ReleaseGroupWithName[];
export declare function setResolvedVersionPlansOnGroups(rawVersionPlans: RawVersionPlan[], releaseGroups: ReleaseGroupWithName[], allProjectNamesInWorkspace: string[]): ReleaseGroupWithName[];
export declare function getVersionPlansAbsolutePath(): string;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.readRawVersionPlans = readRawVersionPlans;
exports.setVersionPlansOnGroups = setVersionPlansOnGroups;
exports.setResolvedVersionPlansOnGroups = setResolvedVersionPlansOnGroups;
exports.getVersionPlansAbsolutePath = getVersionPlansAbsolutePath;

@@ -32,3 +32,3 @@ const fs_1 = require("fs");

content: parsedContent.attributes,
message: getSingleLineMessage(parsedContent.body),
message: parsedContent.body,
createdOnMs: versionPlanStats.birthtimeMs,

@@ -39,10 +39,13 @@ });

}
function setVersionPlansOnGroups(rawVersionPlans, releaseGroups, allProjectNamesInWorkspace) {
function setResolvedVersionPlansOnGroups(rawVersionPlans, releaseGroups, allProjectNamesInWorkspace) {
const groupsByName = releaseGroups.reduce((acc, group) => acc.set(group.name, group), new Map());
const isDefaultGroup = isDefault(releaseGroups);
for (const rawVersionPlan of rawVersionPlans) {
if (!rawVersionPlan.message) {
throw new Error(`Please add a changelog message to version plan: '${rawVersionPlan.fileName}'`);
}
for (const [key, value] of Object.entries(rawVersionPlan.content)) {
if (groupsByName.has(key)) {
const group = groupsByName.get(key);
if (!group.versionPlans) {
if (!group.resolvedVersionPlans) {
if (isDefaultGroup) {

@@ -71,3 +74,3 @@ throw new Error(`Found a version bump in '${rawVersionPlan.fileName}' but version plans are not enabled.`);

}
const existingPlan = (group.versionPlans.find((plan) => plan.fileName === rawVersionPlan.fileName));
const existingPlan = (group.resolvedVersionPlans.find((plan) => plan.fileName === rawVersionPlan.fileName));
if (existingPlan) {

@@ -84,3 +87,3 @@ if (existingPlan.groupVersionBump !== value) {

else {
group.versionPlans.push({
group.resolvedVersionPlans.push({
absolutePath: rawVersionPlan.absolutePath,

@@ -108,3 +111,3 @@ relativePath: rawVersionPlan.relativePath,

}
if (!groupForProject.versionPlans) {
if (!groupForProject.resolvedVersionPlans) {
if (isDefaultGroup) {

@@ -121,3 +124,3 @@ throw new Error(`Found a version bump for project '${key}' in '${rawVersionPlan.fileName}' but version plans are not enabled.`);

if (groupForProject.projectsRelationship === 'independent') {
const existingPlan = (groupForProject.versionPlans.find((plan) => plan.fileName === rawVersionPlan.fileName));
const existingPlan = (groupForProject.resolvedVersionPlans.find((plan) => plan.fileName === rawVersionPlan.fileName));
if (existingPlan) {

@@ -127,3 +130,3 @@ existingPlan.projectVersionBumps[key] = value;

else {
groupForProject.versionPlans.push({
groupForProject.resolvedVersionPlans.push({
absolutePath: rawVersionPlan.absolutePath,

@@ -141,3 +144,3 @@ relativePath: rawVersionPlan.relativePath,

else {
const existingPlan = (groupForProject.versionPlans.find((plan) => plan.fileName === rawVersionPlan.fileName));
const existingPlan = (groupForProject.resolvedVersionPlans.find((plan) => plan.fileName === rawVersionPlan.fileName));
// This can occur if the same fixed release group has multiple entries for different projects within

@@ -154,5 +157,8 @@ // the same version plan file. This will be the case when users are using the default release group.

}
else {
existingPlan.triggeredByProjects.push(key);
}
}
else {
groupForProject.versionPlans.push({
groupForProject.resolvedVersionPlans.push({
absolutePath: rawVersionPlan.absolutePath,

@@ -164,3 +170,5 @@ relativePath: rawVersionPlan.relativePath,

// This is a fixed group, so the version bump is for the group, even if a project within it was specified
// but we track the projects that triggered the version bump so that we can accurately produce changelog entries.
groupVersionBump: value,
triggeredByProjects: [key],
});

@@ -174,4 +182,4 @@ }

releaseGroups.forEach((group) => {
if (group.versionPlans) {
group.versionPlans.sort((a, b) => b.createdOnMs - a.createdOnMs);
if (group.resolvedVersionPlans) {
group.resolvedVersionPlans.sort((a, b) => b.createdOnMs - a.createdOnMs);
}

@@ -191,5 +199,1 @@ });

}
// changelog messages may only be a single line long, so ignore anything else
function getSingleLineMessage(message) {
return message.trim().split('\n')[0];
}

@@ -0,16 +1,28 @@

import type { NxReleaseConfiguration } from '../../config/nx-json';
/**
* @public
*/
export { releaseChangelog } from './changelog';
export declare class ReleaseClient {
private overrideReleaseConfig;
releaseChangelog: (args: import("./command-object").ChangelogOptions) => Promise<import("./changelog").NxReleaseChangelogResult>;
releasePublish: (args: import("./command-object").PublishOptions, isCLI?: boolean) => Promise<number>;
releaseVersion: (args: import("./command-object").VersionOptions) => Promise<import("./version").NxReleaseVersionResult>;
release: (args: import("./command-object").ReleaseOptions) => Promise<import("./version").NxReleaseVersionResult | number>;
constructor(overrideReleaseConfig: NxReleaseConfiguration);
}
/**
* @public
*/
export { releasePublish } from './publish';
export declare const releaseChangelog: any;
/**
* @public
*/
export { releaseVersion } from './version';
export declare const releasePublish: any;
/**
* @public
*/
export { release } from './release';
export declare const releaseVersion: any;
/**
* @public
*/
export declare const release: any;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.release = exports.releaseVersion = exports.releasePublish = exports.releaseChangelog = void 0;
exports.release = exports.releaseVersion = exports.releasePublish = exports.releaseChangelog = exports.ReleaseClient = void 0;
const changelog_1 = require("./changelog");
const publish_1 = require("./publish");
const release_1 = require("./release");
const version_1 = require("./version");
/**
* @public
*/
var changelog_1 = require("./changelog");
Object.defineProperty(exports, "releaseChangelog", { enumerable: true, get: function () { return changelog_1.releaseChangelog; } });
class ReleaseClient {
constructor(overrideReleaseConfig) {
this.overrideReleaseConfig = overrideReleaseConfig;
this.releaseChangelog = (0, changelog_1.createAPI)(this.overrideReleaseConfig);
this.releasePublish = (0, publish_1.createAPI)(this.overrideReleaseConfig);
this.releaseVersion = (0, version_1.createAPI)(this.overrideReleaseConfig);
this.release = (0, release_1.createAPI)(this.overrideReleaseConfig);
}
}
exports.ReleaseClient = ReleaseClient;
const defaultClient = new ReleaseClient({});
/**
* @public
*/
var publish_1 = require("./publish");
Object.defineProperty(exports, "releasePublish", { enumerable: true, get: function () { return publish_1.releasePublish; } });
exports.releaseChangelog = defaultClient.releaseChangelog.bind(defaultClient);
/**
* @public
*/
var version_1 = require("./version");
Object.defineProperty(exports, "releaseVersion", { enumerable: true, get: function () { return version_1.releaseVersion; } });
exports.releasePublish = defaultClient.releasePublish.bind(defaultClient);
/**
* @public
*/
var release_1 = require("./release");
Object.defineProperty(exports, "release", { enumerable: true, get: function () { return release_1.release; } });
exports.releaseVersion = defaultClient.releaseVersion.bind(defaultClient);
/**
* @public
*/
exports.release = defaultClient.release.bind(defaultClient);

@@ -0,3 +1,4 @@

import { NxReleaseConfiguration } from '../../config/nx-json';
import { PlanOptions } from './command-object';
export declare const releasePlanCLIHandler: (args: PlanOptions) => Promise<number>;
export declare function releasePlan(args: PlanOptions): Promise<string | number>;
export declare function createAPI(overrideReleaseConfig: NxReleaseConfiguration): (args: PlanOptions) => Promise<string | number>;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.releasePlanCLIHandler = void 0;
exports.releasePlan = releasePlan;
exports.createAPI = createAPI;
const enquirer_1 = require("enquirer");
const fs_extra_1 = require("fs-extra");
const path_1 = require("path");
const node_path_1 = require("node:path");
const semver_1 = require("semver");
const tmp_1 = require("tmp");
const nx_json_1 = require("../../config/nx-json");

@@ -15,98 +16,94 @@ const file_map_utils_1 = require("../../project-graph/file-map-utils");

const config_1 = require("./config/config");
const deep_merge_json_1 = require("./config/deep-merge-json");
const filter_release_groups_1 = require("./config/filter-release-groups");
const version_plans_1 = require("./config/version-plans");
const git_1 = require("./utils/git");
const generate_version_plan_content_1 = require("./utils/generate-version-plan-content");
const launch_editor_1 = require("./utils/launch-editor");
const print_changes_1 = require("./utils/print-changes");
const releasePlanCLIHandler = (args) => (0, params_1.handleErrors)(args.verbose, () => releasePlan(args));
const print_config_1 = require("./utils/print-config");
const releasePlanCLIHandler = (args) => (0, params_1.handleErrors)(args.verbose, () => createAPI({})(args));
exports.releasePlanCLIHandler = releasePlanCLIHandler;
async function releasePlan(args) {
const projectGraph = await (0, project_graph_1.createProjectGraphAsync)({ exitOnError: true });
const nxJson = (0, nx_json_1.readNxJson)();
if (args.verbose) {
process.env.NX_VERBOSE_LOGGING = 'true';
}
// Apply default configuration to any optional user configuration
const { error: configError, nxReleaseConfig } = await (0, config_1.createNxReleaseConfig)(projectGraph, await (0, file_map_utils_1.createProjectFileMapUsingProjectGraph)(projectGraph), nxJson.release);
if (configError) {
return await (0, config_1.handleNxReleaseConfigError)(configError);
}
const { error: filterError, releaseGroups, releaseGroupToFilteredProjects, } = (0, filter_release_groups_1.filterReleaseGroups)(projectGraph, nxReleaseConfig, args.projects, args.groups);
if (filterError) {
output_1.output.error(filterError);
process.exit(1);
}
const versionPlanBumps = {};
const setBumpIfNotNone = (projectOrGroup, version) => {
if (version !== 'none') {
versionPlanBumps[projectOrGroup] = version;
function createAPI(overrideReleaseConfig) {
return async function releasePlan(args) {
const projectGraph = await (0, project_graph_1.createProjectGraphAsync)({ exitOnError: true });
const nxJson = (0, nx_json_1.readNxJson)();
const userProvidedReleaseConfig = (0, deep_merge_json_1.deepMergeJson)(nxJson.release ?? {}, overrideReleaseConfig ?? {});
if (args.verbose) {
process.env.NX_VERBOSE_LOGGING = 'true';
}
};
if (args.message) {
const message = (0, git_1.parseConventionalCommitsMessage)(args.message);
if (!message) {
output_1.output.error({
title: 'Changelog message is not in conventional commits format.',
bodyLines: [
'Please ensure your message is in the form of:',
' type(optional scope): description',
'',
'For example:',
' feat(pkg-b): add new feature',
' fix(pkg-a): correct a bug',
' chore: update build process',
' fix(core)!: breaking change in core package',
],
// Apply default configuration to any optional user configuration
const { error: configError, nxReleaseConfig } = await (0, config_1.createNxReleaseConfig)(projectGraph, await (0, file_map_utils_1.createProjectFileMapUsingProjectGraph)(projectGraph), userProvidedReleaseConfig);
if (configError) {
return await (0, config_1.handleNxReleaseConfigError)(configError);
}
// --print-config exits directly as it is not designed to be combined with any other programmatic operations
if (args.printConfig) {
return (0, print_config_1.printConfigAndExit)({
userProvidedReleaseConfig,
nxReleaseConfig,
isDebug: args.printConfig === 'debug',
});
}
const { error: filterError, releaseGroups, releaseGroupToFilteredProjects, } = (0, filter_release_groups_1.filterReleaseGroups)(projectGraph, nxReleaseConfig, args.projects, args.groups);
if (filterError) {
output_1.output.error(filterError);
process.exit(1);
}
}
if (releaseGroups[0].name === config_1.IMPLICIT_DEFAULT_RELEASE_GROUP) {
const group = releaseGroups[0];
if (group.projectsRelationship === 'independent') {
for (const project of group.projects) {
setBumpIfNotNone(project, args.bump ||
(await promptForVersion(`How do you want to bump the version of the project "${project}"?`)));
const versionPlanBumps = {};
const setBumpIfNotNone = (projectOrGroup, version) => {
if (version !== 'none') {
versionPlanBumps[projectOrGroup] = version;
}
}
else {
// TODO: use project names instead of the implicit default release group name? (though this might be confusing, as users might think they can just delete one of the project bumps to change the behavior to independent versioning)
setBumpIfNotNone(group.name, args.bump ||
(await promptForVersion(`How do you want to bump the versions of all projects?`)));
}
}
else {
for (const group of releaseGroups) {
};
if (releaseGroups[0].name === config_1.IMPLICIT_DEFAULT_RELEASE_GROUP) {
const group = releaseGroups[0];
if (group.projectsRelationship === 'independent') {
for (const project of releaseGroupToFilteredProjects.get(group)) {
for (const project of group.projects) {
setBumpIfNotNone(project, args.bump ||
(await promptForVersion(`How do you want to bump the version of the project "${project}" within group "${group.name}"?`)));
(await promptForVersion(`How do you want to bump the version of the project "${project}"?`)));
}
}
else {
// TODO: use project names instead of the implicit default release group name? (though this might be confusing, as users might think they can just delete one of the project bumps to change the behavior to independent versioning)
setBumpIfNotNone(group.name, args.bump ||
(await promptForVersion(`How do you want to bump the versions of the projects in the group "${group.name}"?`)));
(await promptForVersion(`How do you want to bump the versions of all projects?`)));
}
}
}
if (!Object.keys(versionPlanBumps).length) {
output_1.output.warn({
title: 'No version bumps were selected so no version plan file was created.',
});
else {
for (const group of releaseGroups) {
if (group.projectsRelationship === 'independent') {
for (const project of releaseGroupToFilteredProjects.get(group)) {
setBumpIfNotNone(project, args.bump ||
(await promptForVersion(`How do you want to bump the version of the project "${project}" within group "${group.name}"?`)));
}
}
else {
setBumpIfNotNone(group.name, args.bump ||
(await promptForVersion(`How do you want to bump the versions of the projects in the group "${group.name}"?`)));
}
}
}
if (!Object.keys(versionPlanBumps).length) {
output_1.output.warn({
title: 'No version bumps were selected so no version plan file was created.',
});
return 0;
}
const versionPlanName = `version-plan-${new Date().getTime()}`;
const versionPlanMessage = args.message || (await promptForMessage(versionPlanName));
const versionPlanFileContent = (0, generate_version_plan_content_1.generateVersionPlanContent)(versionPlanBumps, versionPlanMessage);
const versionPlanFileName = `${versionPlanName}.md`;
if (args.dryRun) {
output_1.output.logSingleLine(`Would create version plan file "${versionPlanFileName}", but --dry-run was set.`);
(0, print_changes_1.printDiff)('', versionPlanFileContent, 1);
}
else {
output_1.output.logSingleLine(`Creating version plan file "${versionPlanFileName}"`);
(0, print_changes_1.printDiff)('', versionPlanFileContent, 1);
const versionPlansAbsolutePath = (0, version_plans_1.getVersionPlansAbsolutePath)();
await (0, fs_extra_1.ensureDir)(versionPlansAbsolutePath);
await (0, fs_extra_1.writeFile)((0, node_path_1.join)(versionPlansAbsolutePath, versionPlanFileName), versionPlanFileContent);
}
return 0;
}
const versionPlanMessage = args.message || (await promptForMessage());
const versionPlanFileContent = getVersionPlanFileContent(versionPlanBumps, versionPlanMessage);
const versionPlanFileName = `version-plan-${new Date().getTime()}.md`;
if (args.dryRun) {
output_1.output.logSingleLine(`Would create version plan file "${versionPlanFileName}", but --dry-run was set.`);
(0, print_changes_1.printDiff)('', versionPlanFileContent, 1);
}
else {
output_1.output.logSingleLine(`Creating version plan file "${versionPlanFileName}"`);
(0, print_changes_1.printDiff)('', versionPlanFileContent, 1);
const versionPlansAbsolutePath = (0, version_plans_1.getVersionPlansAbsolutePath)();
await (0, fs_extra_1.ensureDir)(versionPlansAbsolutePath);
await (0, fs_extra_1.writeFile)((0, path_1.join)(versionPlansAbsolutePath, versionPlanFileName), versionPlanFileContent);
}
return 0;
};
}

@@ -132,11 +129,10 @@ async function promptForVersion(message) {

}
async function promptForMessage() {
async function promptForMessage(versionPlanName) {
let message;
do {
message = await _promptForMessage();
message = await _promptForMessage(versionPlanName);
} while (!message);
return message;
}
// TODO: support non-conventional commits messages (will require significant changelog renderer changes)
async function _promptForMessage() {
async function _promptForMessage(versionPlanName) {
try {

@@ -146,24 +142,22 @@ const reply = await (0, enquirer_1.prompt)([

name: 'message',
message: 'What changelog message would you like associated with this change?',
message: 'What changelog message would you like associated with this change? (Leave blank to open an external editor for multi-line messages/easier editing)',
type: 'input',
},
]);
const conventionalCommitsMessage = (0, git_1.parseConventionalCommitsMessage)(reply.message);
if (!conventionalCommitsMessage) {
let message = reply.message.trim();
if (!message.length) {
const tmpDir = (0, tmp_1.dirSync)().name;
const messageFilePath = (0, node_path_1.join)(tmpDir, `DRAFT_MESSAGE__${versionPlanName}.md`);
(0, fs_extra_1.writeFileSync)(messageFilePath, '');
await (0, launch_editor_1.launchEditor)(messageFilePath);
message = (0, fs_extra_1.readFileSync)(messageFilePath, 'utf-8');
}
message = message.trim();
if (!message) {
output_1.output.warn({
title: 'Changelog message is not in conventional commits format.',
bodyLines: [
'Please ensure your message is in the form of:',
' type(optional scope): description',
'',
'For example:',
' feat(pkg-b): add new feature',
' fix(pkg-a): correct a bug',
' chore: update build process',
' fix(core)!: breaking change in core package',
],
title: 'A changelog message is required in order to create the version plan file',
bodyLines: [],
});
return null;
}
return reply.message;
return message;
}

@@ -177,12 +171,1 @@ catch (e) {

}
function getVersionPlanFileContent(bumps, message) {
return `---
${Object.entries(bumps)
.filter(([_, version]) => version !== 'none')
.map(([projectOrGroup, version]) => `${projectOrGroup}: ${version}`)
.join('\n')}
---
${message}
`;
}

@@ -0,8 +1,4 @@

import { NxReleaseConfiguration } from '../../config/nx-json';
import { PublishOptions } from './command-object';
export declare const releasePublishCLIHandler: (args: PublishOptions) => Promise<number>;
/**
* NOTE: This function is also exported for programmatic usage and forms part of the public API
* of Nx. We intentionally do not wrap the implementation with handleErrors because users need
* to have control over their own error handling when using the API.
*/
export declare function releasePublish(args: PublishOptions, isCLI?: boolean): Promise<number>;
export declare function createAPI(overrideReleaseConfig: NxReleaseConfiguration): (args: PublishOptions, isCLI?: boolean) => Promise<number>;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.releasePublishCLIHandler = void 0;
exports.releasePublish = releasePublish;
exports.createAPI = createAPI;
const nx_json_1 = require("../../config/nx-json");

@@ -15,46 +15,74 @@ const file_map_utils_1 = require("../../project-graph/file-map-utils");

const config_1 = require("./config/config");
const deep_merge_json_1 = require("./config/deep-merge-json");
const filter_release_groups_1 = require("./config/filter-release-groups");
const releasePublishCLIHandler = (args) => (0, params_1.handleErrors)(args.verbose, () => releasePublish(args, true));
const print_config_1 = require("./utils/print-config");
const releasePublishCLIHandler = (args) => (0, params_1.handleErrors)(args.verbose, () => createAPI({})(args, true));
exports.releasePublishCLIHandler = releasePublishCLIHandler;
/**
* NOTE: This function is also exported for programmatic usage and forms part of the public API
* of Nx. We intentionally do not wrap the implementation with handleErrors because users need
* to have control over their own error handling when using the API.
*/
async function releasePublish(args, isCLI = false) {
function createAPI(overrideReleaseConfig) {
/**
* When used via the CLI, the args object will contain a __overrides_unparsed__ property that is
* important for invoking the relevant executor behind the scenes.
*
* We intentionally do not include that in the function signature, however, so as not to cause
* confusing errors for programmatic consumers of this function.
* NOTE: This function is also exported for programmatic usage and forms part of the public API
* of Nx. We intentionally do not wrap the implementation with handleErrors because users need
* to have control over their own error handling when using the API.
*/
const _args = args;
const projectGraph = await (0, project_graph_1.createProjectGraphAsync)({ exitOnError: true });
const nxJson = (0, nx_json_1.readNxJson)();
if (_args.verbose) {
process.env.NX_VERBOSE_LOGGING = 'true';
}
// Apply default configuration to any optional user configuration
const { error: configError, nxReleaseConfig } = await (0, config_1.createNxReleaseConfig)(projectGraph, await (0, file_map_utils_1.createProjectFileMapUsingProjectGraph)(projectGraph), nxJson.release);
if (configError) {
return await (0, config_1.handleNxReleaseConfigError)(configError);
}
const { error: filterError, releaseGroups, releaseGroupToFilteredProjects, } = (0, filter_release_groups_1.filterReleaseGroups)(projectGraph, nxReleaseConfig, _args.projects, _args.groups);
if (filterError) {
output_1.output.error(filterError);
process.exit(1);
}
/**
* If the user is filtering to a subset of projects or groups, we should not run the publish task
* for dependencies, because that could cause projects outset of the filtered set to be published.
*/
const shouldExcludeTaskDependencies = _args.projects?.length > 0 || _args.groups?.length > 0;
let overallExitStatus = 0;
if (args.projects?.length) {
return async function releasePublish(args, isCLI = false) {
/**
* Run publishing for all remaining release groups and filtered projects within them
* When used via the CLI, the args object will contain a __overrides_unparsed__ property that is
* important for invoking the relevant executor behind the scenes.
*
* We intentionally do not include that in the function signature, however, so as not to cause
* confusing errors for programmatic consumers of this function.
*/
const _args = args;
const projectGraph = await (0, project_graph_1.createProjectGraphAsync)({ exitOnError: true });
const nxJson = (0, nx_json_1.readNxJson)();
const userProvidedReleaseConfig = (0, deep_merge_json_1.deepMergeJson)(nxJson.release ?? {}, overrideReleaseConfig ?? {});
if (_args.verbose) {
process.env.NX_VERBOSE_LOGGING = 'true';
}
// Apply default configuration to any optional user configuration
const { error: configError, nxReleaseConfig } = await (0, config_1.createNxReleaseConfig)(projectGraph, await (0, file_map_utils_1.createProjectFileMapUsingProjectGraph)(projectGraph), userProvidedReleaseConfig);
if (configError) {
return await (0, config_1.handleNxReleaseConfigError)(configError);
}
// --print-config exits directly as it is not designed to be combined with any other programmatic operations
if (args.printConfig) {
return (0, print_config_1.printConfigAndExit)({
userProvidedReleaseConfig,
nxReleaseConfig,
isDebug: args.printConfig === 'debug',
});
}
const { error: filterError, releaseGroups, releaseGroupToFilteredProjects, } = (0, filter_release_groups_1.filterReleaseGroups)(projectGraph, nxReleaseConfig, _args.projects, _args.groups);
if (filterError) {
output_1.output.error(filterError);
process.exit(1);
}
/**
* If the user is filtering to a subset of projects or groups, we should not run the publish task
* for dependencies, because that could cause projects outset of the filtered set to be published.
*/
const shouldExcludeTaskDependencies = _args.projects?.length > 0 ||
_args.groups?.length > 0 ||
args.excludeTaskDependencies;
let overallExitStatus = 0;
if (args.projects?.length) {
/**
* Run publishing for all remaining release groups and filtered projects within them
*/
for (const releaseGroup of releaseGroups) {
const status = await runPublishOnProjects(_args, projectGraph, nxJson, Array.from(releaseGroupToFilteredProjects.get(releaseGroup)), isCLI, {
excludeTaskDependencies: shouldExcludeTaskDependencies,
loadDotEnvFiles: process.env.NX_LOAD_DOT_ENV_FILES !== 'false',
});
if (status !== 0) {
overallExitStatus = status || 1;
}
}
return overallExitStatus;
}
/**
* Run publishing for all remaining release groups
*/
for (const releaseGroup of releaseGroups) {
const status = await runPublishOnProjects(_args, projectGraph, nxJson, Array.from(releaseGroupToFilteredProjects.get(releaseGroup)), isCLI, {
const status = await runPublishOnProjects(_args, projectGraph, nxJson, releaseGroup.projects, isCLI, {
excludeTaskDependencies: shouldExcludeTaskDependencies,

@@ -68,16 +96,3 @@ loadDotEnvFiles: process.env.NX_LOAD_DOT_ENV_FILES !== 'false',

return overallExitStatus;
}
/**
* Run publishing for all remaining release groups
*/
for (const releaseGroup of releaseGroups) {
const status = await runPublishOnProjects(_args, projectGraph, nxJson, releaseGroup.projects, isCLI, {
excludeTaskDependencies: shouldExcludeTaskDependencies,
loadDotEnvFiles: process.env.NX_LOAD_DOT_ENV_FILES !== 'false',
});
if (status !== 0) {
overallExitStatus = status || 1;
}
}
return overallExitStatus;
};
}

@@ -84,0 +99,0 @@ async function runPublishOnProjects(args, projectGraph, nxJson, projectNames, isCLI, extraOptions) {

@@ -0,4 +1,5 @@

import { NxReleaseConfiguration } from '../../config/nx-json';
import { ReleaseOptions, VersionOptions } from './command-object';
import { NxReleaseVersionResult } from './version';
export declare const releaseCLIHandler: (args: VersionOptions) => Promise<number>;
export declare function release(args: ReleaseOptions): Promise<NxReleaseVersionResult | number>;
export declare function createAPI(overrideReleaseConfig: NxReleaseConfiguration): (args: ReleaseOptions) => Promise<NxReleaseVersionResult | number>;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.releaseCLIHandler = void 0;
exports.release = release;
exports.createAPI = createAPI;
const enquirer_1 = require("enquirer");

@@ -14,2 +14,3 @@ const fs_extra_1 = require("fs-extra");

const config_1 = require("./config/config");
const deep_merge_json_1 = require("./config/deep-merge-json");
const filter_release_groups_1 = require("./config/filter-release-groups");

@@ -20,115 +21,124 @@ const version_plans_1 = require("./config/version-plans");

const github_1 = require("./utils/github");
const print_config_1 = require("./utils/print-config");
const resolve_nx_json_error_message_1 = require("./utils/resolve-nx-json-error-message");
const shared_1 = require("./utils/shared");
const version_1 = require("./version");
const releaseCLIHandler = (args) => (0, params_1.handleErrors)(args.verbose, () => release(args));
const releaseCLIHandler = (args) => (0, params_1.handleErrors)(args.verbose, () => createAPI({})(args));
exports.releaseCLIHandler = releaseCLIHandler;
async function release(args) {
const projectGraph = await (0, project_graph_1.createProjectGraphAsync)({ exitOnError: true });
const nxJson = (0, nx_json_1.readNxJson)();
if (args.verbose) {
process.env.NX_VERBOSE_LOGGING = 'true';
}
const hasVersionGitConfig = Object.keys(nxJson.release?.version?.git ?? {}).length > 0;
const hasChangelogGitConfig = Object.keys(nxJson.release?.changelog?.git ?? {}).length > 0;
if (hasVersionGitConfig || hasChangelogGitConfig) {
const jsonConfigErrorPath = hasVersionGitConfig
? ['release', 'version', 'git']
: ['release', 'changelog', 'git'];
const nxJsonMessage = await (0, resolve_nx_json_error_message_1.resolveNxJsonConfigErrorMessage)(jsonConfigErrorPath);
output_1.output.error({
title: `The "release" top level command cannot be used with granular git configuration. Instead, configure git options in the "release.git" property in nx.json, or use the version, changelog, and publish subcommands or programmatic API directly.`,
bodyLines: [nxJsonMessage],
function createAPI(overrideReleaseConfig) {
const releaseVersion = (0, version_1.createAPI)(overrideReleaseConfig);
const releaseChangelog = (0, changelog_1.createAPI)(overrideReleaseConfig);
const releasePublish = (0, publish_1.createAPI)(overrideReleaseConfig);
return async function release(args) {
const projectGraph = await (0, project_graph_1.createProjectGraphAsync)({ exitOnError: true });
const nxJson = (0, nx_json_1.readNxJson)();
const userProvidedReleaseConfig = (0, deep_merge_json_1.deepMergeJson)(nxJson.release ?? {}, overrideReleaseConfig ?? {});
if (args.verbose) {
process.env.NX_VERBOSE_LOGGING = 'true';
}
const hasVersionGitConfig = Object.keys(userProvidedReleaseConfig.version?.git ?? {}).length > 0;
const hasChangelogGitConfig = Object.keys(userProvidedReleaseConfig.changelog?.git ?? {}).length > 0;
if (hasVersionGitConfig || hasChangelogGitConfig) {
const jsonConfigErrorPath = hasVersionGitConfig
? ['release', 'version', 'git']
: ['release', 'changelog', 'git'];
const nxJsonMessage = await (0, resolve_nx_json_error_message_1.resolveNxJsonConfigErrorMessage)(jsonConfigErrorPath);
output_1.output.error({
title: `The "release" top level command cannot be used with granular git configuration. Instead, configure git options in the "release.git" property in nx.json, or use the version, changelog, and publish subcommands or programmatic API directly.`,
bodyLines: [nxJsonMessage],
});
process.exit(1);
}
// Apply default configuration to any optional user configuration
const { error: configError, nxReleaseConfig } = await (0, config_1.createNxReleaseConfig)(projectGraph, await (0, file_map_utils_1.createProjectFileMapUsingProjectGraph)(projectGraph), userProvidedReleaseConfig);
if (configError) {
return await (0, config_1.handleNxReleaseConfigError)(configError);
}
// --print-config exits directly as it is not designed to be combined with any other programmatic operations
if (args.printConfig) {
return (0, print_config_1.printConfigAndExit)({
userProvidedReleaseConfig,
nxReleaseConfig,
isDebug: args.printConfig === 'debug',
});
}
const rawVersionPlans = await (0, version_plans_1.readRawVersionPlans)();
if (args.specifier && rawVersionPlans.length > 0) {
output_1.output.error({
title: `A specifier option cannot be provided when using version plans.`,
bodyLines: [
`To override this behavior, use the Nx Release programmatic API directly (https://nx.dev/features/manage-releases#using-the-programmatic-api-for-nx-release).`,
],
});
process.exit(1);
}
// These properties must never be undefined as this command should
// always explicitly override the git operations of the subcommands.
const shouldCommit = userProvidedReleaseConfig.git?.commit ?? true;
const shouldStage = (shouldCommit || userProvidedReleaseConfig.git?.stageChanges) ?? false;
const shouldTag = userProvidedReleaseConfig.git?.tag ?? true;
const versionResult = await releaseVersion({
...args,
stageChanges: shouldStage,
gitCommit: false,
gitTag: false,
deleteVersionPlans: false,
});
process.exit(1);
}
// Apply default configuration to any optional user configuration
const { error: configError, nxReleaseConfig } = await (0, config_1.createNxReleaseConfig)(projectGraph, await (0, file_map_utils_1.createProjectFileMapUsingProjectGraph)(projectGraph), nxJson.release);
if (configError) {
return await (0, config_1.handleNxReleaseConfigError)(configError);
}
// These properties must never be undefined as this command should
// always explicitly override the git operations of the subcommands.
const shouldCommit = nxJson.release?.git?.commit ?? true;
const shouldStage = (shouldCommit || nxJson.release?.git?.stageChanges) ?? false;
const shouldTag = nxJson.release?.git?.tag ?? true;
const versionResult = await (0, version_1.releaseVersion)({
...args,
stageChanges: shouldStage,
gitCommit: false,
gitTag: false,
deleteVersionPlans: false,
});
const changelogResult = await (0, changelog_1.releaseChangelog)({
...args,
versionData: versionResult.projectsVersionData,
version: versionResult.workspaceVersion,
stageChanges: shouldStage,
gitCommit: false,
gitTag: false,
createRelease: false,
deleteVersionPlans: false,
});
const { error: filterError, releaseGroups, releaseGroupToFilteredProjects, } = (0, filter_release_groups_1.filterReleaseGroups)(projectGraph, nxReleaseConfig, args.projects, args.groups);
if (filterError) {
output_1.output.error(filterError);
process.exit(1);
}
const rawVersionPlans = await (0, version_plans_1.readRawVersionPlans)();
(0, version_plans_1.setVersionPlansOnGroups)(rawVersionPlans, releaseGroups, Object.keys(projectGraph.nodes));
const planFiles = new Set();
releaseGroups.forEach((group) => {
if (group.versionPlans) {
if (group.name === config_1.IMPLICIT_DEFAULT_RELEASE_GROUP) {
output_1.output.logSingleLine(`Removing version plan files`);
}
else {
output_1.output.logSingleLine(`Removing version plan files for group ${group.name}`);
}
group.versionPlans.forEach((plan) => {
if (!args.dryRun) {
(0, fs_extra_1.removeSync)(plan.absolutePath);
if (args.verbose) {
console.log(`Removing ${plan.relativePath}`);
}
const changelogResult = await releaseChangelog({
...args,
versionData: versionResult.projectsVersionData,
version: versionResult.workspaceVersion,
stageChanges: shouldStage,
gitCommit: false,
gitTag: false,
createRelease: false,
deleteVersionPlans: false,
});
const { error: filterError, releaseGroups, releaseGroupToFilteredProjects, } = (0, filter_release_groups_1.filterReleaseGroups)(projectGraph, nxReleaseConfig, args.projects, args.groups);
if (filterError) {
output_1.output.error(filterError);
process.exit(1);
}
(0, version_plans_1.setResolvedVersionPlansOnGroups)(rawVersionPlans, releaseGroups, Object.keys(projectGraph.nodes));
const planFiles = new Set();
releaseGroups.forEach((group) => {
if (group.resolvedVersionPlans) {
if (group.name === config_1.IMPLICIT_DEFAULT_RELEASE_GROUP) {
output_1.output.logSingleLine(`Removing version plan files`);
}
else {
if (args.verbose) {
console.log(`Would remove ${plan.relativePath}, but --dry-run was set`);
output_1.output.logSingleLine(`Removing version plan files for group ${group.name}`);
}
group.resolvedVersionPlans.forEach((plan) => {
if (!args.dryRun) {
(0, fs_extra_1.removeSync)(plan.absolutePath);
if (args.verbose) {
console.log(`Removing ${plan.relativePath}`);
}
}
}
planFiles.add(plan.relativePath);
else {
if (args.verbose) {
console.log(`Would remove ${plan.relativePath}, but --dry-run was set`);
}
}
planFiles.add(plan.relativePath);
});
}
});
const deletedFiles = Array.from(planFiles);
if (deletedFiles.length > 0) {
await (0, git_1.gitAdd)({
changedFiles: [],
deletedFiles,
dryRun: args.dryRun,
verbose: args.verbose,
});
}
});
const deletedFiles = Array.from(planFiles);
if (deletedFiles.length > 0) {
await (0, git_1.gitAdd)({
changedFiles: [],
deletedFiles,
dryRun: args.dryRun,
verbose: args.verbose,
});
}
if (shouldCommit) {
output_1.output.logSingleLine(`Committing changes with git`);
const commitMessage = nxReleaseConfig.git.commitMessage;
const commitMessageValues = (0, shared_1.createCommitMessageValues)(releaseGroups, releaseGroupToFilteredProjects, versionResult.projectsVersionData, commitMessage);
await (0, git_1.gitCommit)({
messages: commitMessageValues,
additionalArgs: nxReleaseConfig.git.commitArgs,
dryRun: args.dryRun,
verbose: args.verbose,
});
}
if (shouldTag) {
output_1.output.logSingleLine(`Tagging commit with git`);
// Resolve any git tags as early as possible so that we can hard error in case of any duplicates before reaching the actual git command
const gitTagValues = (0, shared_1.createGitTagValues)(releaseGroups, releaseGroupToFilteredProjects, versionResult.projectsVersionData);
(0, shared_1.handleDuplicateGitTags)(gitTagValues);
for (const tag of gitTagValues) {
await (0, git_1.gitTag)({
tag,
message: nxReleaseConfig.git.tagMessage,
additionalArgs: nxReleaseConfig.git.tagArgs,
if (shouldCommit) {
output_1.output.logSingleLine(`Committing changes with git`);
const commitMessage = nxReleaseConfig.git.commitMessage;
const commitMessageValues = (0, shared_1.createCommitMessageValues)(releaseGroups, releaseGroupToFilteredProjects, versionResult.projectsVersionData, commitMessage);
await (0, git_1.gitCommit)({
messages: commitMessageValues,
additionalArgs: nxReleaseConfig.git.commitArgs,
dryRun: args.dryRun,

@@ -138,66 +148,81 @@ verbose: args.verbose,

}
}
const shouldCreateWorkspaceRelease = (0, changelog_1.shouldCreateGitHubRelease)(nxReleaseConfig.changelog.workspaceChangelog);
let hasPushedChanges = false;
let latestCommit;
if (shouldCreateWorkspaceRelease && changelogResult.workspaceChangelog) {
output_1.output.logSingleLine(`Pushing to git remote`);
// Before we can create/update the release we need to ensure the commit exists on the remote
await (0, git_1.gitPush)({
dryRun: args.dryRun,
verbose: args.verbose,
});
hasPushedChanges = true;
output_1.output.logSingleLine(`Creating GitHub Release`);
latestCommit = await (0, git_1.getCommitHash)('HEAD');
await (0, github_1.createOrUpdateGithubRelease)(changelogResult.workspaceChangelog.releaseVersion, changelogResult.workspaceChangelog.contents, latestCommit, { dryRun: args.dryRun });
}
for (const releaseGroup of releaseGroups) {
const shouldCreateProjectReleases = (0, changelog_1.shouldCreateGitHubRelease)(releaseGroup.changelog);
if (shouldCreateProjectReleases && changelogResult.projectChangelogs) {
const projects = args.projects?.length
? // If the user has passed a list of projects, we need to use the filtered list of projects within the release group
Array.from(releaseGroupToFilteredProjects.get(releaseGroup))
: // Otherwise, we use the full list of projects within the release group
releaseGroup.projects;
const projectNodes = projects.map((name) => projectGraph.nodes[name]);
for (const project of projectNodes) {
const changelog = changelogResult.projectChangelogs[project.name];
if (!changelog) {
continue;
if (shouldTag) {
output_1.output.logSingleLine(`Tagging commit with git`);
// Resolve any git tags as early as possible so that we can hard error in case of any duplicates before reaching the actual git command
const gitTagValues = (0, shared_1.createGitTagValues)(releaseGroups, releaseGroupToFilteredProjects, versionResult.projectsVersionData);
(0, shared_1.handleDuplicateGitTags)(gitTagValues);
for (const tag of gitTagValues) {
await (0, git_1.gitTag)({
tag,
message: nxReleaseConfig.git.tagMessage,
additionalArgs: nxReleaseConfig.git.tagArgs,
dryRun: args.dryRun,
verbose: args.verbose,
});
}
}
const shouldCreateWorkspaceRelease = (0, changelog_1.shouldCreateGitHubRelease)(nxReleaseConfig.changelog.workspaceChangelog);
let hasPushedChanges = false;
let latestCommit;
if (shouldCreateWorkspaceRelease && changelogResult.workspaceChangelog) {
output_1.output.logSingleLine(`Pushing to git remote`);
// Before we can create/update the release we need to ensure the commit exists on the remote
await (0, git_1.gitPush)({
dryRun: args.dryRun,
verbose: args.verbose,
});
hasPushedChanges = true;
output_1.output.logSingleLine(`Creating GitHub Release`);
latestCommit = await (0, git_1.getCommitHash)('HEAD');
await (0, github_1.createOrUpdateGithubRelease)(changelogResult.workspaceChangelog.releaseVersion, changelogResult.workspaceChangelog.contents, latestCommit, { dryRun: args.dryRun });
}
for (const releaseGroup of releaseGroups) {
const shouldCreateProjectReleases = (0, changelog_1.shouldCreateGitHubRelease)(releaseGroup.changelog);
if (shouldCreateProjectReleases && changelogResult.projectChangelogs) {
const projects = args.projects?.length
? // If the user has passed a list of projects, we need to use the filtered list of projects within the release group
Array.from(releaseGroupToFilteredProjects.get(releaseGroup))
: // Otherwise, we use the full list of projects within the release group
releaseGroup.projects;
const projectNodes = projects.map((name) => projectGraph.nodes[name]);
for (const project of projectNodes) {
const changelog = changelogResult.projectChangelogs[project.name];
if (!changelog) {
continue;
}
if (!hasPushedChanges) {
output_1.output.logSingleLine(`Pushing to git remote`);
// Before we can create/update the release we need to ensure the commit exists on the remote
await (0, git_1.gitPush)({
dryRun: args.dryRun,
verbose: args.verbose,
});
hasPushedChanges = true;
}
output_1.output.logSingleLine(`Creating GitHub Release`);
if (!latestCommit) {
latestCommit = await (0, git_1.getCommitHash)('HEAD');
}
await (0, github_1.createOrUpdateGithubRelease)(changelog.releaseVersion, changelog.contents, latestCommit, { dryRun: args.dryRun });
}
if (!hasPushedChanges) {
output_1.output.logSingleLine(`Pushing to git remote`);
// Before we can create/update the release we need to ensure the commit exists on the remote
await (0, git_1.gitPush)({
dryRun: args.dryRun,
verbose: args.verbose,
});
hasPushedChanges = true;
}
output_1.output.logSingleLine(`Creating GitHub Release`);
if (!latestCommit) {
latestCommit = await (0, git_1.getCommitHash)('HEAD');
}
await (0, github_1.createOrUpdateGithubRelease)(changelog.releaseVersion, changelog.contents, latestCommit, { dryRun: args.dryRun });
}
}
}
let hasNewVersion = false;
// null means that all projects are versioned together but there were no changes
if (versionResult.workspaceVersion !== null) {
hasNewVersion = Object.values(versionResult.projectsVersionData).some((version) => version.newVersion !== null);
}
let shouldPublish = !!args.yes && !args.skipPublish && hasNewVersion;
const shouldPromptPublishing = !args.yes && !args.skipPublish && !args.dryRun && hasNewVersion;
if (shouldPromptPublishing) {
shouldPublish = await promptForPublish();
}
if (shouldPublish) {
await (0, publish_1.releasePublish)(args);
}
else {
output_1.output.logSingleLine('Skipped publishing packages.');
}
return versionResult;
let hasNewVersion = false;
// null means that all projects are versioned together but there were no changes
if (versionResult.workspaceVersion !== null) {
hasNewVersion = Object.values(versionResult.projectsVersionData).some((version) => version.newVersion !== null);
}
let shouldPublish = !!args.yes && !args.skipPublish && hasNewVersion;
const shouldPromptPublishing = !args.yes && !args.skipPublish && !args.dryRun && hasNewVersion;
if (shouldPromptPublishing) {
shouldPublish = await promptForPublish();
}
if (shouldPublish) {
await releasePublish(args);
}
else {
output_1.output.logSingleLine('Skipped publishing packages.');
}
return versionResult;
};
}

@@ -204,0 +229,0 @@ async function promptForPublish() {

@@ -131,7 +131,9 @@ "use strict";

const projectVersionData = versionData[releaseGroupProjectNames[0]]; // all at the same version, so we can just pick the first one
const releaseVersion = new ReleaseVersion({
version: projectVersionData.newVersion,
releaseTagPattern: releaseGroup.releaseTagPattern,
});
commitMessageValues.push(`- release-group: ${releaseGroup.name} ${releaseVersion.rawVersion}`);
if (projectVersionData.newVersion !== null) {
const releaseVersion = new ReleaseVersion({
version: projectVersionData.newVersion,
releaseTagPattern: releaseGroup.releaseTagPattern,
});
commitMessageValues.push(`- release-group: ${releaseGroup.name} ${releaseVersion.rawVersion}`);
}
}

@@ -173,2 +175,3 @@ return commitMessageValues;

version: projectVersionData.newVersion,
releaseGroupName: releaseGroup.name,
}));

@@ -175,0 +178,0 @@ }

@@ -0,1 +1,2 @@

import { NxReleaseConfiguration } from '../../config/nx-json';
import { ProjectGraph, ProjectGraphProjectNode } from '../../config/project-graph';

@@ -32,2 +33,7 @@ import { VersionOptions } from './command-object';

updateDependents?: 'never' | 'auto';
/**
* Whether or not to completely omit project logs when that project has no applicable changes. This can be useful for
* large monorepos which have a large number of projects, especially when only a subset are released together.
*/
logUnchangedProjects?: boolean;
}

@@ -49,7 +55,2 @@ export interface NxReleaseVersionResult {

export declare const releaseVersionCLIHandler: (args: VersionOptions) => Promise<number>;
/**
* NOTE: This function is also exported for programmatic usage and forms part of the public API
* of Nx. We intentionally do not wrap the implementation with handleErrors because users need
* to have control over their own error handling when using the API.
*/
export declare function releaseVersion(args: VersionOptions): Promise<NxReleaseVersionResult>;
export declare function createAPI(overrideReleaseConfig: NxReleaseConfiguration): (args: VersionOptions) => Promise<NxReleaseVersionResult>;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.releaseVersionCLIHandler = exports.validReleaseVersionPrefixes = exports.deriveNewSemverVersion = void 0;
exports.releaseVersion = releaseVersion;
exports.createAPI = createAPI;
const chalk = require("chalk");

@@ -20,2 +20,3 @@ const node_child_process_1 = require("node:child_process");

const config_1 = require("./config/config");
const deep_merge_json_1 = require("./config/deep-merge-json");
const filter_release_groups_1 = require("./config/filter-release-groups");

@@ -26,2 +27,3 @@ const version_plans_1 = require("./config/version-plans");

const print_changes_1 = require("./utils/print-changes");
const print_config_1 = require("./utils/print-config");
const resolve_nx_json_error_message_1 = require("./utils/resolve-nx-json-error-message");

@@ -34,74 +36,183 @@ const shared_1 = require("./utils/shared");

exports.validReleaseVersionPrefixes = ['auto', '', '~', '^', '='];
const releaseVersionCLIHandler = (args) => (0, params_1.handleErrors)(args.verbose, () => releaseVersion(args));
const releaseVersionCLIHandler = (args) => (0, params_1.handleErrors)(args.verbose, () => createAPI({})(args));
exports.releaseVersionCLIHandler = releaseVersionCLIHandler;
/**
* NOTE: This function is also exported for programmatic usage and forms part of the public API
* of Nx. We intentionally do not wrap the implementation with handleErrors because users need
* to have control over their own error handling when using the API.
*/
async function releaseVersion(args) {
const projectGraph = await (0, project_graph_1.createProjectGraphAsync)({ exitOnError: true });
const { projects } = (0, project_graph_1.readProjectsConfigurationFromProjectGraph)(projectGraph);
const nxJson = (0, nx_json_1.readNxJson)();
if (args.verbose) {
process.env.NX_VERBOSE_LOGGING = 'true';
}
// Apply default configuration to any optional user configuration
const { error: configError, nxReleaseConfig } = await (0, config_1.createNxReleaseConfig)(projectGraph, await (0, file_map_utils_1.createProjectFileMapUsingProjectGraph)(projectGraph), nxJson.release);
if (configError) {
return await (0, config_1.handleNxReleaseConfigError)(configError);
}
// The nx release top level command will always override these three git args. This is how we can tell
// if the top level release command was used or if the user is using the changelog subcommand.
// If the user explicitly overrides these args, then it doesn't matter if the top level config is set,
// as all of the git options would be overridden anyway.
if ((args.gitCommit === undefined ||
args.gitTag === undefined ||
args.stageChanges === undefined) &&
nxJson.release?.git) {
const nxJsonMessage = await (0, resolve_nx_json_error_message_1.resolveNxJsonConfigErrorMessage)([
'release',
'git',
]);
output_1.output.error({
title: `The "release.git" property in nx.json may not be used with the "nx release version" subcommand or programmatic API. Instead, configure git options for subcommands directly with "release.version.git" and "release.changelog.git".`,
bodyLines: [nxJsonMessage],
});
process.exit(1);
}
const { error: filterError, releaseGroups, releaseGroupToFilteredProjects, } = (0, filter_release_groups_1.filterReleaseGroups)(projectGraph, nxReleaseConfig, args.projects, args.groups);
if (filterError) {
output_1.output.error(filterError);
process.exit(1);
}
const rawVersionPlans = await (0, version_plans_1.readRawVersionPlans)();
(0, version_plans_1.setVersionPlansOnGroups)(rawVersionPlans, releaseGroups, Object.keys(projectGraph.nodes));
if (args.deleteVersionPlans === undefined) {
// default to not delete version plans after versioning as they may be needed for changelog generation
args.deleteVersionPlans = false;
}
runPreVersionCommand(nxReleaseConfig.version.preVersionCommand, {
dryRun: args.dryRun,
verbose: args.verbose,
});
const tree = new tree_1.FsTree(workspace_root_1.workspaceRoot, args.verbose);
const versionData = {};
const commitMessage = args.gitCommitMessage || nxReleaseConfig.version.git.commitMessage;
const generatorCallbacks = [];
function createAPI(overrideReleaseConfig) {
/**
* additionalChangedFiles are files which need to be updated as a side-effect of versioning (such as package manager lock files),
* and need to get staged and committed as part of the existing commit, if applicable.
* NOTE: This function is also exported for programmatic usage and forms part of the public API
* of Nx. We intentionally do not wrap the implementation with handleErrors because users need
* to have control over their own error handling when using the API.
*/
const additionalChangedFiles = new Set();
const additionalDeletedFiles = new Set();
if (args.projects?.length) {
return async function releaseVersion(args) {
const projectGraph = await (0, project_graph_1.createProjectGraphAsync)({ exitOnError: true });
const { projects } = (0, project_graph_1.readProjectsConfigurationFromProjectGraph)(projectGraph);
const nxJson = (0, nx_json_1.readNxJson)();
const userProvidedReleaseConfig = (0, deep_merge_json_1.deepMergeJson)(nxJson.release ?? {}, overrideReleaseConfig ?? {});
if (args.verbose) {
process.env.NX_VERBOSE_LOGGING = 'true';
}
// Apply default configuration to any optional user configuration
const { error: configError, nxReleaseConfig } = await (0, config_1.createNxReleaseConfig)(projectGraph, await (0, file_map_utils_1.createProjectFileMapUsingProjectGraph)(projectGraph), userProvidedReleaseConfig);
if (configError) {
return await (0, config_1.handleNxReleaseConfigError)(configError);
}
// --print-config exits directly as it is not designed to be combined with any other programmatic operations
if (args.printConfig) {
return (0, print_config_1.printConfigAndExit)({
userProvidedReleaseConfig,
nxReleaseConfig,
isDebug: args.printConfig === 'debug',
});
}
// The nx release top level command will always override these three git args. This is how we can tell
// if the top level release command was used or if the user is using the changelog subcommand.
// If the user explicitly overrides these args, then it doesn't matter if the top level config is set,
// as all of the git options would be overridden anyway.
if ((args.gitCommit === undefined ||
args.gitTag === undefined ||
args.stageChanges === undefined) &&
userProvidedReleaseConfig.git) {
const nxJsonMessage = await (0, resolve_nx_json_error_message_1.resolveNxJsonConfigErrorMessage)([
'release',
'git',
]);
output_1.output.error({
title: `The "release.git" property in nx.json may not be used with the "nx release version" subcommand or programmatic API. Instead, configure git options for subcommands directly with "release.version.git" and "release.changelog.git".`,
bodyLines: [nxJsonMessage],
});
process.exit(1);
}
const { error: filterError, releaseGroups, releaseGroupToFilteredProjects, } = (0, filter_release_groups_1.filterReleaseGroups)(projectGraph, nxReleaseConfig, args.projects, args.groups);
if (filterError) {
output_1.output.error(filterError);
process.exit(1);
}
if (!args.specifier) {
const rawVersionPlans = await (0, version_plans_1.readRawVersionPlans)();
(0, version_plans_1.setResolvedVersionPlansOnGroups)(rawVersionPlans, releaseGroups, Object.keys(projectGraph.nodes));
}
else {
if (args.verbose && releaseGroups.some((g) => !!g.versionPlans)) {
console.log(`Skipping version plan discovery as a specifier was provided`);
}
}
if (args.deleteVersionPlans === undefined) {
// default to not delete version plans after versioning as they may be needed for changelog generation
args.deleteVersionPlans = false;
}
runPreVersionCommand(nxReleaseConfig.version.preVersionCommand, {
dryRun: args.dryRun,
verbose: args.verbose,
});
const tree = new tree_1.FsTree(workspace_root_1.workspaceRoot, args.verbose);
const versionData = {};
const commitMessage = args.gitCommitMessage || nxReleaseConfig.version.git.commitMessage;
const generatorCallbacks = [];
/**
* Run versioning for all remaining release groups and filtered projects within them
* additionalChangedFiles are files which need to be updated as a side-effect of versioning (such as package manager lock files),
* and need to get staged and committed as part of the existing commit, if applicable.
*/
const additionalChangedFiles = new Set();
const additionalDeletedFiles = new Set();
if (args.projects?.length) {
/**
* Run versioning for all remaining release groups and filtered projects within them
*/
for (const releaseGroup of releaseGroups) {
const releaseGroupName = releaseGroup.name;
const releaseGroupProjectNames = Array.from(releaseGroupToFilteredProjects.get(releaseGroup));
const projectBatches = (0, batch_projects_by_generator_config_1.batchProjectsByGeneratorConfig)(projectGraph, releaseGroup,
// Only batch based on the filtered projects within the release group
releaseGroupProjectNames);
for (const [generatorConfigString, projectNames,] of projectBatches.entries()) {
const [generatorName, generatorOptions] = JSON.parse(generatorConfigString);
// Resolve the generator for the batch and run versioning on the projects within the batch
const generatorData = resolveGeneratorData({
...extractGeneratorCollectionAndName(`batch "${JSON.stringify(projectNames)}" for release-group "${releaseGroupName}"`, generatorName),
configGeneratorOptions: generatorOptions,
// all project data from the project graph (not to be confused with projectNamesToRunVersionOn)
projects,
});
const generatorCallback = await runVersionOnProjects(projectGraph, nxJson, args, tree, generatorData, args.generatorOptionsOverrides, projectNames, releaseGroup, versionData, nxReleaseConfig.conventionalCommits);
// Capture the callback so that we can run it after flushing the changes to disk
generatorCallbacks.push(async () => {
const result = await generatorCallback(tree, {
dryRun: !!args.dryRun,
verbose: !!args.verbose,
generatorOptions: {
...generatorOptions,
...args.generatorOptionsOverrides,
},
});
const { changedFiles, deletedFiles } = parseGeneratorCallbackResult(result);
changedFiles.forEach((f) => additionalChangedFiles.add(f));
deletedFiles.forEach((f) => additionalDeletedFiles.add(f));
});
}
}
// Resolve any git tags as early as possible so that we can hard error in case of any duplicates before reaching the actual git command
const gitTagValues = args.gitTag ?? nxReleaseConfig.version.git.tag
? (0, shared_1.createGitTagValues)(releaseGroups, releaseGroupToFilteredProjects, versionData)
: [];
(0, shared_1.handleDuplicateGitTags)(gitTagValues);
printAndFlushChanges(tree, !!args.dryRun);
for (const generatorCallback of generatorCallbacks) {
await generatorCallback();
}
const changedFiles = [
...tree.listChanges().map((f) => f.path),
...additionalChangedFiles,
];
// No further actions are necessary in this scenario (e.g. if conventional commits detected no changes)
if (!changedFiles.length) {
return {
// An overall workspace version cannot be relevant when filtering to independent projects
workspaceVersion: undefined,
projectsVersionData: versionData,
};
}
if (args.gitCommit ?? nxReleaseConfig.version.git.commit) {
await (0, shared_1.commitChanges)({
changedFiles,
deletedFiles: Array.from(additionalDeletedFiles),
isDryRun: !!args.dryRun,
isVerbose: !!args.verbose,
gitCommitMessages: (0, shared_1.createCommitMessageValues)(releaseGroups, releaseGroupToFilteredProjects, versionData, commitMessage),
gitCommitArgs: args.gitCommitArgs || nxReleaseConfig.version.git.commitArgs,
});
}
else if (args.stageChanges ??
nxReleaseConfig.version.git.stageChanges) {
output_1.output.logSingleLine(`Staging changed files with git`);
await (0, git_1.gitAdd)({
changedFiles,
dryRun: args.dryRun,
verbose: args.verbose,
});
}
if (args.gitTag ?? nxReleaseConfig.version.git.tag) {
output_1.output.logSingleLine(`Tagging commit with git`);
for (const tag of gitTagValues) {
await (0, git_1.gitTag)({
tag,
message: args.gitTagMessage || nxReleaseConfig.version.git.tagMessage,
additionalArgs: args.gitTagArgs || nxReleaseConfig.version.git.tagArgs,
dryRun: args.dryRun,
verbose: args.verbose,
});
}
}
return {
// An overall workspace version cannot be relevant when filtering to independent projects
workspaceVersion: undefined,
projectsVersionData: versionData,
};
}
/**
* Run versioning for all remaining release groups
*/
for (const releaseGroup of releaseGroups) {
const releaseGroupName = releaseGroup.name;
const releaseGroupProjectNames = Array.from(releaseGroupToFilteredProjects.get(releaseGroup));
const projectBatches = (0, batch_projects_by_generator_config_1.batchProjectsByGeneratorConfig)(projectGraph, releaseGroup,
// Only batch based on the filtered projects within the release group
releaseGroupProjectNames);
// Batch based on all projects within the release group
releaseGroup.projects);
for (const [generatorConfigString, projectNames,] of projectBatches.entries()) {

@@ -142,2 +253,11 @@ const [generatorName, generatorOptions] = JSON.parse(generatorConfigString);

}
// Only applicable when there is a single release group with a fixed relationship
let workspaceVersion = undefined;
if (releaseGroups.length === 1) {
const releaseGroup = releaseGroups[0];
if (releaseGroup.projectsRelationship === 'fixed') {
const releaseGroupProjectNames = Array.from(releaseGroupToFilteredProjects.get(releaseGroup));
workspaceVersion = versionData[releaseGroupProjectNames[0]].newVersion; // all projects have the same version so we can just grab the first
}
}
const changedFiles = [

@@ -147,7 +267,7 @@ ...tree.listChanges().map((f) => f.path),

];
const deletedFiles = Array.from(additionalDeletedFiles);
// No further actions are necessary in this scenario (e.g. if conventional commits detected no changes)
if (!changedFiles.length) {
if (!changedFiles.length && !deletedFiles.length) {
return {
// An overall workspace version cannot be relevant when filtering to independent projects
workspaceVersion: undefined,
workspaceVersion,
projectsVersionData: versionData,

@@ -159,3 +279,3 @@ };

changedFiles,
deletedFiles: Array.from(additionalDeletedFiles),
deletedFiles,
isDryRun: !!args.dryRun,

@@ -171,2 +291,3 @@ isVerbose: !!args.verbose,

changedFiles,
deletedFiles,
dryRun: args.dryRun,

@@ -189,103 +310,5 @@ verbose: args.verbose,

return {
// An overall workspace version cannot be relevant when filtering to independent projects
workspaceVersion: undefined,
projectsVersionData: versionData,
};
}
/**
* Run versioning for all remaining release groups
*/
for (const releaseGroup of releaseGroups) {
const releaseGroupName = releaseGroup.name;
const projectBatches = (0, batch_projects_by_generator_config_1.batchProjectsByGeneratorConfig)(projectGraph, releaseGroup,
// Batch based on all projects within the release group
releaseGroup.projects);
for (const [generatorConfigString, projectNames,] of projectBatches.entries()) {
const [generatorName, generatorOptions] = JSON.parse(generatorConfigString);
// Resolve the generator for the batch and run versioning on the projects within the batch
const generatorData = resolveGeneratorData({
...extractGeneratorCollectionAndName(`batch "${JSON.stringify(projectNames)}" for release-group "${releaseGroupName}"`, generatorName),
configGeneratorOptions: generatorOptions,
// all project data from the project graph (not to be confused with projectNamesToRunVersionOn)
projects,
});
const generatorCallback = await runVersionOnProjects(projectGraph, nxJson, args, tree, generatorData, args.generatorOptionsOverrides, projectNames, releaseGroup, versionData, nxReleaseConfig.conventionalCommits);
// Capture the callback so that we can run it after flushing the changes to disk
generatorCallbacks.push(async () => {
const result = await generatorCallback(tree, {
dryRun: !!args.dryRun,
verbose: !!args.verbose,
generatorOptions: {
...generatorOptions,
...args.generatorOptionsOverrides,
},
});
const { changedFiles, deletedFiles } = parseGeneratorCallbackResult(result);
changedFiles.forEach((f) => additionalChangedFiles.add(f));
deletedFiles.forEach((f) => additionalDeletedFiles.add(f));
});
}
}
// Resolve any git tags as early as possible so that we can hard error in case of any duplicates before reaching the actual git command
const gitTagValues = args.gitTag ?? nxReleaseConfig.version.git.tag
? (0, shared_1.createGitTagValues)(releaseGroups, releaseGroupToFilteredProjects, versionData)
: [];
(0, shared_1.handleDuplicateGitTags)(gitTagValues);
printAndFlushChanges(tree, !!args.dryRun);
for (const generatorCallback of generatorCallbacks) {
await generatorCallback();
}
// Only applicable when there is a single release group with a fixed relationship
let workspaceVersion = undefined;
if (releaseGroups.length === 1) {
const releaseGroup = releaseGroups[0];
if (releaseGroup.projectsRelationship === 'fixed') {
const releaseGroupProjectNames = Array.from(releaseGroupToFilteredProjects.get(releaseGroup));
workspaceVersion = versionData[releaseGroupProjectNames[0]].newVersion; // all projects have the same version so we can just grab the first
}
}
const changedFiles = [
...tree.listChanges().map((f) => f.path),
...additionalChangedFiles,
];
// No further actions are necessary in this scenario (e.g. if conventional commits detected no changes)
if (!changedFiles.length) {
return {
workspaceVersion,
projectsVersionData: versionData,
};
}
if (args.gitCommit ?? nxReleaseConfig.version.git.commit) {
await (0, shared_1.commitChanges)({
changedFiles,
deletedFiles: Array.from(additionalDeletedFiles),
isDryRun: !!args.dryRun,
isVerbose: !!args.verbose,
gitCommitMessages: (0, shared_1.createCommitMessageValues)(releaseGroups, releaseGroupToFilteredProjects, versionData, commitMessage),
gitCommitArgs: args.gitCommitArgs || nxReleaseConfig.version.git.commitArgs,
});
}
else if (args.stageChanges ?? nxReleaseConfig.version.git.stageChanges) {
output_1.output.logSingleLine(`Staging changed files with git`);
await (0, git_1.gitAdd)({
changedFiles,
dryRun: args.dryRun,
verbose: args.verbose,
});
}
if (args.gitTag ?? nxReleaseConfig.version.git.tag) {
output_1.output.logSingleLine(`Tagging commit with git`);
for (const tag of gitTagValues) {
await (0, git_1.gitTag)({
tag,
message: args.gitTagMessage || nxReleaseConfig.version.git.tagMessage,
additionalArgs: args.gitTagArgs || nxReleaseConfig.version.git.tagArgs,
dryRun: args.dryRun,
verbose: args.verbose,
});
}
}
return {
workspaceVersion,
projectsVersionData: versionData,
};

@@ -292,0 +315,0 @@ }

@@ -34,2 +34,3 @@ import { PackageManager } from '../../utils/package-manager';

projectGraphError?: Error | null;
nativeTarget: string | null;
}

@@ -36,0 +37,0 @@ export declare function getReportData(): Promise<ReportData>;

@@ -46,10 +46,14 @@ "use strict";

async function reportHandler() {
const { pm, pmVersion, localPlugins, communityPlugins, registeredPlugins, packageVersionsWeCareAbout, outOfSyncPackageGroup, projectGraphError, } = await getReportData();
const bodyLines = [
`Node : ${process.versions.node}`,
`OS : ${process.platform}-${process.arch}`,
`${pm.padEnd(7)}: ${pmVersion}`,
``,
const { pm, pmVersion, localPlugins, communityPlugins, registeredPlugins, packageVersionsWeCareAbout, outOfSyncPackageGroup, projectGraphError, nativeTarget, } = await getReportData();
const fields = [
['Node', process.versions.node],
['OS', `${process.platform}-${process.arch}`],
['Native Target', nativeTarget ?? 'Unavailable'],
[pm, pmVersion],
];
let padding = Math.max(...packageVersionsWeCareAbout.map((x) => x.package.length)) + 1;
let padding = Math.max(...fields.map((f) => f[0].length));
const bodyLines = fields.map(([field, value]) => `${field.padEnd(padding)} : ${value}`);
bodyLines.push('');
padding =
Math.max(...packageVersionsWeCareAbout.map((x) => x.package.length)) + 1;
packageVersionsWeCareAbout.forEach((p) => {

@@ -120,2 +124,3 @@ bodyLines.push(`${chalk.green(p.package.padEnd(padding))} : ${chalk.bold(p.version)}`);

const outOfSyncPackageGroup = findMisalignedPackagesForPackage(nxPackageJson);
const native = isNativeAvailable();
return {

@@ -130,2 +135,3 @@ pm,

projectGraphError,
nativeTarget: native ? native.getBinaryTarget() : null,
};

@@ -254,4 +260,3 @@ }

try {
require('../../native');
return true;
return require('../../native');
}

@@ -258,0 +263,0 @@ catch {

@@ -6,3 +6,4 @@ import { CommandModule } from 'yargs';

onlyWorkspaceData?: boolean;
onlyCloud?: boolean;
};
export declare const yargsResetCommand: CommandModule<Record<string, unknown>, ResetCommandOptions>;

@@ -17,2 +17,6 @@ "use strict";

})
.option('onlyCloud', {
description: 'Resets the Nx Cloud client. NOTE: Does not clear the remote cache.',
type: 'boolean',
})
.option('onlyWorkspaceData', {

@@ -19,0 +23,0 @@ description: 'Clears the workspace data directory. Used by Nx to store cached data about the current workspace (e.g. partial results, incremental data, etc)',

@@ -9,2 +9,4 @@ "use strict";

const native_file_cache_location_1 = require("../../native/native-file-cache-location");
const client_2 = require("../../nx-cloud/utilities/client");
const get_cloud_options_1 = require("../../nx-cloud/utilities/get-cloud-options");
// Wait at max 5 seconds before giving up on a failing operation.

@@ -65,2 +67,5 @@ const INCREMENTAL_BACKOFF_MAX_DURATION = 5000;

}
if (all || args.onlyCloud) {
await resetCloudClient();
}
if (errors.length > 0) {

@@ -82,2 +87,10 @@ output_1.output.error({

}
async function resetCloudClient() {
// Remove nx cloud marker files. This helps if the use happens to run `nx-cloud start-ci-run` or
// similar commands on their local machine.
try {
(await (0, client_2.getCloudClient)((0, get_cloud_options_1.getCloudOptions)())).invoke('cleanup');
}
catch { }
}
function cleanupCacheEntries() {

@@ -84,0 +97,0 @@ return incrementalBackoff(INCREMENTAL_BACKOFF_FIRST_DELAY, INCREMENTAL_BACKOFF_MAX_DURATION, () => {

@@ -18,3 +18,3 @@ "use strict";

async function runMany(args, extraTargetDependencies = {}, extraOptions = {
excludeTaskDependencies: false,
excludeTaskDependencies: args.excludeTaskDependencies,
loadDotEnvFiles: process.env.NX_LOAD_DOT_ENV_FILES !== 'false',

@@ -21,0 +21,0 @@ }) {

@@ -17,3 +17,3 @@ "use strict";

async function runOne(cwd, args, extraTargetDependencies = {}, extraOptions = {
excludeTaskDependencies: false,
excludeTaskDependencies: args.excludeTaskDependencies,
loadDotEnvFiles: process.env.NX_LOAD_DOT_ENV_FILES !== 'false',

@@ -20,0 +20,0 @@ }) {

@@ -38,16 +38,4 @@ "use strict";

async function iteratorToProcessStatusCode(i) {
// This is a workaround to fix an issue that only happens with
// the @angular-devkit/build-angular:browser builder. Starting
// on version 12.0.1, a SASS compilation implementation was
// introduced making use of workers and it's unref()-ing the worker
// too early, causing the process to exit early in environments
// like CI or when running Docker builds.
const keepProcessAliveInterval = setInterval(() => { }, 1000);
try {
const { success } = await (0, async_iterator_1.getLastValueFromAsyncIterableIterator)(i);
return success ? 0 : 1;
}
finally {
clearInterval(keepProcessAliveInterval);
}
const { success } = await (0, async_iterator_1.getLastValueFromAsyncIterableIterator)(i);
return success ? 0 : 1;
}

@@ -54,0 +42,0 @@ async function parseExecutorAndTarget({ project, target }, root, projectsConfigurations) {

@@ -21,2 +21,3 @@ import { Argv } from 'yargs';

useAgents: boolean;
excludeTaskDependencies: boolean;
}

@@ -32,3 +33,3 @@ export declare function withRunOptions<T>(yargs: Argv<T>): Argv<T & RunOptions>;

}>;
export declare function withVerbose(yargs: Argv): Argv<{
export declare function withVerbose<T>(yargs: Argv<T>): Argv<T & {
verbose: boolean;

@@ -35,0 +36,0 @@ }>;

@@ -70,2 +70,7 @@ "use strict";

})
.options('excludeTaskDependencies', {
describe: 'Skips running dependent tasks first',
type: 'boolean',
default: false,
})
.options('cloud', {

@@ -72,0 +77,0 @@ type: 'boolean',

@@ -39,4 +39,6 @@ "use strict";

const dependencies = {};
for (const projectName of projectNames) {
recursiveResolveDeps(projectGraph, projectName, dependencies);
if (!nxArgs.excludeTaskDependencies) {
for (const projectName of projectNames) {
recursiveResolveDeps(projectGraph, projectName, dependencies);
}
}

@@ -43,0 +45,0 @@ const roots = Object.keys(dependencies).filter((d) => dependencies[d].length === 0);

@@ -148,4 +148,11 @@ import type { ChangelogRenderOptions } from '../../release/changelog-renderer';

}
interface NxReleaseConfiguration {
export interface NxReleaseVersionPlansConfiguration {
/**
* Changes to files matching any of these optional patterns will be excluded from the affected project logic within the `nx release plan:check`
* command. This is useful for ignoring files that are not relevant to the versioning process, such as documentation or configuration files.
*/
ignorePatternsForPlanCheck?: string[];
}
export interface NxReleaseConfiguration {
/**
* Shorthand for amending the projects which will be included in the implicit default release group (all projects by default).

@@ -197,3 +204,3 @@ * @note Only one of `projects` or `groups` can be specified, the cannot be used together.

*/
versionPlans?: boolean;
versionPlans?: NxReleaseVersionPlansConfiguration | boolean;
}>;

@@ -269,4 +276,23 @@ /**

*/
versionPlans?: boolean;
versionPlans?: NxReleaseVersionPlansConfiguration | boolean;
}
export interface NxSyncConfiguration {
/**
* List of workspace-wide sync generators to be run (not attached to targets).
*/
globalGenerators?: string[];
/**
* Options for the sync generators.
*/
generatorOptions?: {
[generatorName: string]: Record<string, unknown>;
};
/**
* Whether to automatically apply sync generator changes when running tasks.
* If not set, the user will be prompted.
* If set to `true`, the user will not be prompted and the changes will be applied.
* If set to `false`, the user will not be prompted and the changes will not be applied.
*/
applyChanges?: boolean;
}
/**

@@ -386,2 +412,7 @@ * Nx.json configuration

/**
* If specified Nx will use nx-cloud by default with the given cloud id.
* To use a different runner that accepts a cloud id, define it in {@link tasksRunnerOptions}
*/
nxCloudId?: string;
/**
* Specifies the url pointing to an instance of nx cloud. Used for remote

@@ -411,2 +442,10 @@ * caching and displaying run links.

useInferencePlugins?: boolean;
/**
* Set this to false to disable connection to Nx Cloud
*/
neverConnectToCloud?: boolean;
/**
* Configuration for the `nx sync` command.
*/
sync?: NxSyncConfiguration;
}

@@ -413,0 +452,0 @@ export type PluginConfiguration = string | ExpandedPluginConfiguration;

@@ -220,2 +220,7 @@ import type { NxJsonConfiguration, NxReleaseVersionConfiguration } from './nx-json';

parallelism?: boolean;
/**
* List of generators to run before the target to ensure the workspace
* is up to date.
*/
syncGenerators?: string[];
}

@@ -8,3 +8,4 @@ export interface DaemonProcessJson {

export declare function writeDaemonJsonProcessCache(daemonJson: DaemonProcessJson): Promise<void>;
export declare function waitForDaemonToExitAndCleanupProcessJson(): Promise<void>;
export declare function safelyCleanUpExistingProcess(): Promise<void>;
export declare function getDaemonProcessIdSync(): number | null;

@@ -7,2 +7,3 @@ "use strict";

exports.writeDaemonJsonProcessCache = writeDaemonJsonProcessCache;
exports.waitForDaemonToExitAndCleanupProcessJson = waitForDaemonToExitAndCleanupProcessJson;
exports.safelyCleanUpExistingProcess = safelyCleanUpExistingProcess;

@@ -31,2 +32,25 @@ exports.getDaemonProcessIdSync = getDaemonProcessIdSync;

}
async function waitForDaemonToExitAndCleanupProcessJson() {
const daemonProcessJson = await readDaemonProcessJsonCache();
if (daemonProcessJson && daemonProcessJson.processId) {
await new Promise((resolve, reject) => {
let count = 0;
const interval = setInterval(() => {
try {
// sending a signal 0 to a process checks if the process is running instead of actually killing it
process.kill(daemonProcessJson.processId, 0);
}
catch (e) {
clearInterval(interval);
resolve();
}
if ((count += 1) > 200) {
clearInterval(interval);
reject(`Daemon process ${daemonProcessJson.processId} didn't exit after 2 seconds.`);
}
}, 10);
});
deleteDaemonJsonProcessCache();
}
}
async function safelyCleanUpExistingProcess() {

@@ -38,23 +62,6 @@ const daemonProcessJson = await readDaemonProcessJsonCache();

// we wait for the process to actually shut down before returning
await new Promise((resolve, reject) => {
let count = 0;
const interval = setInterval(() => {
try {
// sending a signal 0 to a process checks if the process is running instead of actually killing it
process.kill(daemonProcessJson.processId, 0);
}
catch (e) {
clearInterval(interval);
resolve();
}
if ((count += 1) > 200) {
clearInterval(interval);
reject(`Daemon process ${daemonProcessJson.processId} didn't exit after 2 seconds.`);
}
}, 10);
});
await waitForDaemonToExitAndCleanupProcessJson();
}
catch { }
}
deleteDaemonJsonProcessCache();
}

@@ -61,0 +68,0 @@ // Must be sync for the help output use case

@@ -8,2 +8,3 @@ import { ChildProcess } from 'child_process';

import { TaskRun } from '../../utils/task-history';
import type { SyncGeneratorChangesResult } from '../../utils/sync-generators';
export type UnregisterCallback = () => void;

@@ -58,2 +59,6 @@ export type ChangedFile = {

writeTaskRunsToHistory(taskRuns: TaskRun[]): Promise<void>;
getSyncGeneratorChanges(generators: string[]): Promise<SyncGeneratorChangesResult[]>;
flushSyncGeneratorChangesToDisk(generators: string[]): Promise<void>;
getRegisteredSyncGenerators(): Promise<string[]>;
updateWorkspaceContext(createdFiles: string[], updatedFiles: string[], deletedFiles: string[]): Promise<void>;
isServerAvailable(): Promise<boolean>;

@@ -60,0 +65,0 @@ private sendToDaemonViaQueue;

@@ -28,2 +28,7 @@ "use strict";

const hash_glob_1 = require("../message-types/hash-glob");
const force_shutdown_1 = require("../message-types/force-shutdown");
const get_sync_generator_changes_1 = require("../message-types/get-sync-generator-changes");
const get_registered_sync_generators_1 = require("../message-types/get-registered-sync-generators");
const update_workspace_context_1 = require("../message-types/update-workspace-context");
const flush_sync_generator_changes_to_disk_1 = require("../message-types/flush-sync-generator-changes-to-disk");
const DAEMON_ENV_SETTINGS = {

@@ -248,2 +253,31 @@ NX_PROJECT_GLOB_CACHE: 'false',

}
getSyncGeneratorChanges(generators) {
const message = {
type: get_sync_generator_changes_1.GET_SYNC_GENERATOR_CHANGES,
generators,
};
return this.sendToDaemonViaQueue(message);
}
flushSyncGeneratorChangesToDisk(generators) {
const message = {
type: flush_sync_generator_changes_to_disk_1.FLUSH_SYNC_GENERATOR_CHANGES_TO_DISK,
generators,
};
return this.sendToDaemonViaQueue(message);
}
getRegisteredSyncGenerators() {
const message = {
type: get_registered_sync_generators_1.GET_REGISTERED_SYNC_GENERATORS,
};
return this.sendToDaemonViaQueue(message);
}
updateWorkspaceContext(createdFiles, updatedFiles, deletedFiles) {
const message = {
type: update_workspace_context_1.UPDATE_WORKSPACE_CONTEXT,
createdFiles,
updatedFiles,
deletedFiles,
};
return this.sendToDaemonViaQueue(message);
}
async isServerAvailable() {

@@ -327,2 +361,6 @@ return new Promise((resolve) => {

}
// An open promise isn't enough to keep the event loop
// alive, so we set a timeout here and clear it when we hear
// back
const keepAlive = setTimeout(() => { }, 10 * 60 * 1000);
return new Promise((resolve, reject) => {

@@ -334,2 +372,4 @@ perf_hooks_1.performance.mark('sendMessageToDaemon-start');

this.socketMessenger.sendMessage(message);
}).finally(() => {
clearTimeout(keepAlive);
});

@@ -405,3 +445,4 @@ }

try {
await (0, cache_1.safelyCleanUpExistingProcess)();
await this.sendMessageToDaemon({ type: force_shutdown_1.FORCE_SHUTDOWN });
await (0, cache_1.waitForDaemonToExitAndCleanupProcessJson)();
}

@@ -408,0 +449,0 @@ catch (err) {

@@ -5,2 +5,3 @@ "use strict";

const shutdown_utils_1 = require("./shutdown-utils");
const server_1 = require("./server");
async function handleRequestShutdown(server, numberOfConnections) {

@@ -19,2 +20,3 @@ // 1 connection is the client asking to shut down

reason: 'Request to shutdown',
sockets: server_1.openSockets,
});

@@ -21,0 +23,0 @@ }, 0);

@@ -23,2 +23,3 @@ import { FileData, FileMap, ProjectGraph } from '../../config/project-graph';

export declare function addUpdatedAndDeletedFiles(createdFiles: string[], updatedFiles: string[], deletedFiles: string[]): void;
export declare function registerProjectGraphRecomputationListener(listener: (projectGraph: ProjectGraph) => void): void;
export {};

@@ -6,2 +6,3 @@ "use strict";

exports.addUpdatedAndDeletedFiles = addUpdatedAndDeletedFiles;
exports.registerProjectGraphRecomputationListener = registerProjectGraphRecomputationListener;
const perf_hooks_1 = require("perf_hooks");

@@ -24,2 +25,3 @@ const nx_json_1 = require("../../config/nx-json");

const collectedDeletedFiles = new Set();
const projectGraphRecomputationListeners = new Set();
let storedWorkspaceConfigHash;

@@ -31,4 +33,6 @@ let waitPeriod = 100;

try {
let wasScheduled = false;
// recomputing it now on demand. we can ignore the scheduled timeout
if (scheduledTimeoutId) {
wasScheduled = true;
clearTimeout(scheduledTimeoutId);

@@ -51,3 +55,7 @@ scheduledTimeoutId = undefined;

}
return await cachedSerializedProjectGraphPromise;
const result = await cachedSerializedProjectGraphPromise;
if (wasScheduled) {
notifyProjectGraphRecomputationListeners(result.projectGraph);
}
return result;
}

@@ -90,9 +98,13 @@ catch (e) {

processFilesAndCreateAndSerializeProjectGraph(await (0, plugins_1.getPlugins)());
await cachedSerializedProjectGraphPromise;
const { projectGraph } = await cachedSerializedProjectGraphPromise;
if (createdFiles.length > 0) {
(0, file_watcher_sockets_1.notifyFileWatcherSockets)(createdFiles, null, null);
}
notifyProjectGraphRecomputationListeners(projectGraph);
}, waitPeriod);
}
}
function registerProjectGraphRecomputationListener(listener) {
projectGraphRecomputationListeners.add(listener);
}
function computeWorkspaceConfigHash(projectsConfigurations) {

@@ -142,3 +154,3 @@ const projectConfigurationStrings = Object.entries(projectsConfigurations)

const deletedFiles = [...collectedDeletedFiles.values()];
let updatedFileHashes = (0, workspace_context_1.updateFilesInContext)(updatedFiles, deletedFiles);
let updatedFileHashes = (0, workspace_context_1.updateFilesInContext)(workspace_root_1.workspaceRoot, updatedFiles, deletedFiles);
perf_hooks_1.performance.mark('hash-watched-changes-end');

@@ -290,1 +302,6 @@ perf_hooks_1.performance.measure('hash changed files from watcher', 'hash-watched-changes-start', 'hash-watched-changes-end');

}
function notifyProjectGraphRecomputationListeners(projectGraph) {
for (const listener of projectGraphRecomputationListeners) {
listener(projectGraph);
}
}

@@ -7,3 +7,4 @@ import { Server, Socket } from 'net';

};
export declare const openSockets: Set<Socket>;
export declare function handleResult(socket: Socket, type: string, hrFn: () => Promise<HandlerResult>): Promise<void>;
export declare function startServer(): Promise<Server>;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.openSockets = void 0;
exports.handleResult = handleResult;

@@ -42,2 +43,13 @@ exports.startServer = startServer;

const handle_write_task_runs_to_history_1 = require("./handle-write-task-runs-to-history");
const force_shutdown_1 = require("../message-types/force-shutdown");
const handle_force_shutdown_1 = require("./handle-force-shutdown");
const get_sync_generator_changes_1 = require("../message-types/get-sync-generator-changes");
const handle_get_sync_generator_changes_1 = require("./handle-get-sync-generator-changes");
const sync_generators_1 = require("./sync-generators");
const get_registered_sync_generators_1 = require("../message-types/get-registered-sync-generators");
const handle_get_registered_sync_generators_1 = require("./handle-get-registered-sync-generators");
const update_workspace_context_1 = require("../message-types/update-workspace-context");
const handle_update_workspace_context_1 = require("./handle-update-workspace-context");
const flush_sync_generator_changes_to_disk_1 = require("../message-types/flush-sync-generator-changes-to-disk");
const handle_flush_sync_generator_changes_to_disk_1 = require("./handle-flush-sync-generator-changes-to-disk");
let performanceObserver;

@@ -48,4 +60,6 @@ let workspaceWatcherError;

let numberOfOpenConnections = 0;
exports.openSockets = new Set();
const server = (0, net_1.createServer)(async (socket) => {
numberOfOpenConnections += 1;
exports.openSockets.add(socket);
logger_1.serverLogger.log(`Established a connection. Number of open connections: ${numberOfOpenConnections}`);

@@ -69,2 +83,3 @@ (0, shutdown_utils_1.resetInactivityTimeout)(handleInactivityTimeout);

numberOfOpenConnections -= 1;
exports.openSockets.delete(socket);
logger_1.serverLogger.log(`Closed a connection. Number of open connections: ${numberOfOpenConnections}`);

@@ -137,2 +152,17 @@ (0, file_watcher_sockets_1.removeRegisteredFileWatcherSocket)(socket);

}
else if ((0, force_shutdown_1.isHandleForceShutdownMessage)(payload)) {
await handleResult(socket, 'FORCE_SHUTDOWN', () => (0, handle_force_shutdown_1.handleForceShutdown)(server));
}
else if ((0, get_sync_generator_changes_1.isHandleGetSyncGeneratorChangesMessage)(payload)) {
await handleResult(socket, get_sync_generator_changes_1.GET_SYNC_GENERATOR_CHANGES, () => (0, handle_get_sync_generator_changes_1.handleGetSyncGeneratorChanges)(payload.generators));
}
else if ((0, flush_sync_generator_changes_to_disk_1.isHandleFlushSyncGeneratorChangesToDiskMessage)(payload)) {
await handleResult(socket, flush_sync_generator_changes_to_disk_1.FLUSH_SYNC_GENERATOR_CHANGES_TO_DISK, () => (0, handle_flush_sync_generator_changes_to_disk_1.handleFlushSyncGeneratorChangesToDisk)(payload.generators));
}
else if ((0, get_registered_sync_generators_1.isHandleGetRegisteredSyncGeneratorsMessage)(payload)) {
await handleResult(socket, get_registered_sync_generators_1.GET_REGISTERED_SYNC_GENERATORS, () => (0, handle_get_registered_sync_generators_1.handleGetRegisteredSyncGenerators)());
}
else if ((0, update_workspace_context_1.isHandleUpdateWorkspaceContextMessage)(payload)) {
await handleResult(socket, update_workspace_context_1.UPDATE_WORKSPACE_CONTEXT, () => (0, handle_update_workspace_context_1.handleUpdateWorkspaceContext)(payload.createdFiles, payload.updatedFiles, payload.deletedFiles));
}
else {

@@ -164,2 +194,3 @@ await (0, shutdown_utils_1.respondWithErrorAndExit)(socket, `Invalid payload from the client`, new Error(`Unsupported payload sent to daemon server: ${unparsedPayload}`));

reason: `${shutdown_utils_1.SERVER_INACTIVITY_TIMEOUT_MS}ms of inactivity`,
sockets: exports.openSockets,
});

@@ -173,2 +204,3 @@ }

reason: 'received process SIGINT',
sockets: exports.openSockets,
}))

@@ -178,2 +210,3 @@ .on('SIGTERM', () => (0, shutdown_utils_1.handleServerProcessTermination)({

reason: 'received process SIGTERM',
sockets: exports.openSockets,
}))

@@ -183,2 +216,3 @@ .on('SIGHUP', () => (0, shutdown_utils_1.handleServerProcessTermination)({

reason: 'received process SIGHUP',
sockets: exports.openSockets,
}));

@@ -246,2 +280,3 @@ }

reason: outdatedReason,
sockets: exports.openSockets,
});

@@ -337,2 +372,6 @@ return;

}
// listen for project graph recomputation events to collect and schedule sync generators
(0, project_graph_incremental_recomputation_1.registerProjectGraphRecomputationListener)(sync_generators_1.collectAndScheduleSyncGenerators);
// trigger an initial project graph recomputation
(0, project_graph_incremental_recomputation_1.addUpdatedAndDeletedFiles)([], [], []);
return resolve(server);

@@ -339,0 +378,0 @@ }

@@ -11,4 +11,5 @@ import type { Server, Socket } from 'net';

reason: string;
sockets: Iterable<Socket>;
}
export declare function handleServerProcessTermination({ server, reason, }: HandleServerProcessTerminationParams): Promise<void>;
export declare function handleServerProcessTermination({ server, reason, sockets, }: HandleServerProcessTerminationParams): Promise<void>;
export declare function resetInactivityTimeout(cb: () => void): void;

@@ -15,0 +16,0 @@ export declare function respondToClient(socket: Socket, response: string, description: string): Promise<unknown>;

@@ -33,7 +33,12 @@ "use strict";

}
async function handleServerProcessTermination({ server, reason, }) {
async function handleServerProcessTermination({ server, reason, sockets, }) {
try {
server.close();
(0, cache_1.deleteDaemonJsonProcessCache)();
(0, plugins_1.cleanupPlugins)();
await new Promise((res) => {
server.close(() => {
res(null);
});
for (const socket of sockets) {
socket.destroy();
}
});
if (watcherInstance) {

@@ -47,2 +52,4 @@ await watcherInstance.stop();

}
(0, cache_1.deleteDaemonJsonProcessCache)();
(0, plugins_1.cleanupPlugins)();
logger_1.serverLogger.log(`Server stopped because: "${reason}"`);

@@ -49,0 +56,0 @@ }

@@ -13,2 +13,3 @@ "use strict";

const cache_1 = require("../cache");
const server_1 = require("./server");
const ALWAYS_IGNORE = [

@@ -32,2 +33,3 @@ ...(0, ignore_1.getAlwaysIgnore)(workspace_root_1.workspaceRoot),

reason: 'this process is no longer the current daemon (native)',
sockets: server_1.openSockets,
});

@@ -40,2 +42,3 @@ }

reason: 'Stopping the daemon the set of ignored files changed (native)',
sockets: server_1.openSockets,
});

@@ -42,0 +45,0 @@ }

@@ -18,16 +18,29 @@ "use strict";

*/
const getFullOsSocketPath = () => exports.isWindows
? '\\\\.\\pipe\\nx\\' + (0, path_1.resolve)((0, tmp_dir_1.getDaemonSocketDir)())
: (0, path_1.resolve)((0, tmp_dir_1.getDaemonSocketDir)());
const getFullOsSocketPath = () => {
const path = (0, path_1.resolve)((0, tmp_dir_1.getDaemonSocketDir)());
assertValidSocketPath(path);
return exports.isWindows ? '\\\\.\\pipe\\nx\\' + path : path;
};
exports.getFullOsSocketPath = getFullOsSocketPath;
const getForkedProcessOsSocketPath = (id) => {
let path = (0, path_1.resolve)((0, path_1.join)((0, tmp_dir_1.getSocketDir)(), 'fp' + id + '.sock'));
return exports.isWindows ? '\\\\.\\pipe\\nx\\' + (0, path_1.resolve)(path) : (0, path_1.resolve)(path);
assertValidSocketPath(path);
return exports.isWindows ? '\\\\.\\pipe\\nx\\' + path : path;
};
exports.getForkedProcessOsSocketPath = getForkedProcessOsSocketPath;
const getPluginOsSocketPath = (id) => {
let path = (0, path_1.resolve)((0, path_1.join)((0, tmp_dir_1.getSocketDir)(), 'plugin' + id + '.sock'));
return exports.isWindows ? '\\\\.\\pipe\\nx\\' + (0, path_1.resolve)(path) : (0, path_1.resolve)(path);
let path = (0, path_1.resolve)((0, path_1.join)((0, tmp_dir_1.getSocketDir)(true), 'plugin' + id + '.sock'));
assertValidSocketPath(path);
return exports.isWindows ? '\\\\.\\pipe\\nx\\' + path : path;
};
exports.getPluginOsSocketPath = getPluginOsSocketPath;
function assertValidSocketPath(path) {
if (path.length > 95) {
throw new Error([
'Attempted to open socket that exceeds the maximum socket length.',
'',
`Set NX_SOCKET_DIR to a shorter path (e.g. ${exports.isWindows ? '%TMP%/nx-tmp' : '/tmp/nx-tmp'}) to avoid this issue.`,
].join('\n'));
}
}
function killSocketOrPath() {

@@ -34,0 +47,0 @@ try {

@@ -11,3 +11,3 @@ export declare const DAEMON_DIR_FOR_CURRENT_WORKSPACE: string;

*/
export declare function getSocketDir(): string;
export declare function getSocketDir(alreadyUnique?: boolean): string;
export declare function removeSocketDir(): void;

@@ -54,5 +54,7 @@ "use strict";

*/
function getSocketDir() {
function getSocketDir(alreadyUnique = false) {
try {
const dir = process.env.NX_DAEMON_SOCKET_DIR ?? socketDirName();
const dir = process.env.NX_SOCKET_DIR ??
process.env.NX_DAEMON_SOCKET_DIR ??
(alreadyUnique ? tmp_1.tmpdir : socketDirName());
(0, fs_extra_1.ensureDirSync)(dir);

@@ -59,0 +61,0 @@ return dir;

@@ -12,3 +12,3 @@ /**

export { mergeTargetConfigurations } from './project-graph/utils/project-configuration-utils';
export { readProjectConfigurationsFromRootMap } from './project-graph/utils/project-configuration-utils';
export { readProjectConfigurationsFromRootMap, findMatchingConfigFiles, } from './project-graph/utils/project-configuration-utils';
export { splitTarget } from './utils/split-target';

@@ -15,0 +15,0 @@ export { combineOptionsForExecutor } from './utils/params';

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.interpolate = exports.registerTsProject = exports.LoadedNxPlugin = exports.retrieveProjectConfigurations = exports.findProjectForPath = exports.createProjectRootMappingsFromProjectConfigurations = exports.hashWithWorkspaceContext = exports.hashObject = exports.splitByColons = exports.readModulePackageJson = exports.stripIndent = exports.sortObjectByKeys = exports.combineOptionsForExecutor = exports.splitTarget = exports.readProjectConfigurationsFromRootMap = exports.mergeTargetConfigurations = exports.retrieveProjectConfigurationsWithAngularProjects = exports.calculateDefaultProjectName = exports.readNxJsonFromDisk = exports.getExecutorInformation = exports.createTempNpmDirectory = void 0;
exports.interpolate = exports.registerTsProject = exports.LoadedNxPlugin = exports.retrieveProjectConfigurations = exports.findProjectForPath = exports.createProjectRootMappingsFromProjectConfigurations = exports.hashWithWorkspaceContext = exports.hashObject = exports.splitByColons = exports.readModulePackageJson = exports.stripIndent = exports.sortObjectByKeys = exports.combineOptionsForExecutor = exports.splitTarget = exports.findMatchingConfigFiles = exports.readProjectConfigurationsFromRootMap = exports.mergeTargetConfigurations = exports.retrieveProjectConfigurationsWithAngularProjects = exports.calculateDefaultProjectName = exports.readNxJsonFromDisk = exports.getExecutorInformation = exports.createTempNpmDirectory = void 0;
const tslib_1 = require("tslib");

@@ -24,2 +24,3 @@ /**

Object.defineProperty(exports, "readProjectConfigurationsFromRootMap", { enumerable: true, get: function () { return project_configuration_utils_2.readProjectConfigurationsFromRootMap; } });
Object.defineProperty(exports, "findMatchingConfigFiles", { enumerable: true, get: function () { return project_configuration_utils_2.findMatchingConfigFiles; } });
var split_target_1 = require("./utils/split-target");

@@ -26,0 +27,0 @@ Object.defineProperty(exports, "splitTarget", { enumerable: true, get: function () { return split_target_1.splitTarget; } });

@@ -9,1 +9,7 @@ import type { Tree } from '../tree';

}): Promise<void>;
export declare function formatFilesWithPrettierIfAvailable(files: {
path: string;
content: string | Buffer;
}[], root: string, options?: {
silent?: boolean;
}): Promise<Map<string, string>>;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.formatChangedFilesWithPrettierIfAvailable = formatChangedFilesWithPrettierIfAvailable;
exports.formatFilesWithPrettierIfAvailable = formatFilesWithPrettierIfAvailable;
const path = require("path");

@@ -10,2 +11,10 @@ /**

async function formatChangedFilesWithPrettierIfAvailable(tree, options) {
const files = new Set(tree.listChanges().filter((file) => file.type !== 'DELETE'));
const results = await formatFilesWithPrettierIfAvailable(Array.from(files), tree.root, options);
for (const [path, content] of results) {
tree.write(path, content);
}
}
async function formatFilesWithPrettierIfAvailable(files, root, options) {
const results = new Map();
let prettier;

@@ -16,8 +25,8 @@ try {

catch { }
if (!prettier)
return;
const files = new Set(tree.listChanges().filter((file) => file.type !== 'DELETE'));
if (!prettier) {
return results;
}
await Promise.all(Array.from(files).map(async (file) => {
try {
const systemPath = path.join(tree.root, file.path);
const systemPath = path.join(root, file.path);
let options = {

@@ -40,3 +49,3 @@ filepath: systemPath,

}
tree.write(file.path,
results.set(file.path,
// In prettier v3 the format result is a promise

@@ -51,2 +60,3 @@ await prettier.format(file.content.toString('utf-8'), options));

}));
return results;
}

@@ -20,6 +20,6 @@ "use strict";

const json_1 = require("./json");
const nx_json_1 = require("./nx-json");
var nx_json_2 = require("./nx-json");
Object.defineProperty(exports, "readNxJson", { enumerable: true, get: function () { return nx_json_2.readNxJson; } });
Object.defineProperty(exports, "updateNxJson", { enumerable: true, get: function () { return nx_json_2.updateNxJson; } });
const to_project_name_1 = require("../../config/to-project-name");
var nx_json_1 = require("./nx-json");
Object.defineProperty(exports, "readNxJson", { enumerable: true, get: function () { return nx_json_1.readNxJson; } });
Object.defineProperty(exports, "updateNxJson", { enumerable: true, get: function () { return nx_json_1.updateNxJson; } });
/**

@@ -60,6 +60,31 @@ * Adds project configuration to the Nx workspace.

function updateProjectConfiguration(tree, projectName, projectConfiguration) {
const projectConfigFile = (0, path_2.joinPathFragments)(projectConfiguration.root, 'project.json');
if (!tree.exists(projectConfigFile)) {
if (tree.exists((0, path_2.joinPathFragments)(projectConfiguration.root, 'project.json'))) {
updateProjectConfigurationInProjectJson(tree, projectName, projectConfiguration);
}
else if (tree.exists((0, path_2.joinPathFragments)(projectConfiguration.root, 'package.json'))) {
updateProjectConfigurationInPackageJson(tree, projectName, projectConfiguration);
}
else {
throw new Error(`Cannot update Project ${projectName} at ${projectConfiguration.root}. It either doesn't exist yet, or may not use project.json for configuration. Use \`addProjectConfiguration()\` instead if you want to create a new project.`);
}
}
function updateProjectConfigurationInPackageJson(tree, projectName, projectConfiguration) {
const packageJsonFile = (0, path_2.joinPathFragments)(projectConfiguration.root, 'package.json');
const packageJson = (0, json_1.readJson)(tree, packageJsonFile);
if (packageJson.name === projectConfiguration.name ?? projectName) {
delete projectConfiguration.name;
}
if (projectConfiguration.targets &&
!Object.keys(projectConfiguration.targets).length) {
delete projectConfiguration.targets;
}
packageJson.nx = {
...packageJson.nx,
...projectConfiguration,
root: undefined,
};
(0, json_1.writeJson)(tree, packageJsonFile, packageJson);
}
function updateProjectConfigurationInProjectJson(tree, projectName, projectConfiguration) {
const projectConfigFile = (0, path_2.joinPathFragments)(projectConfiguration.root, 'project.json');
handleEmptyTargets(projectName, projectConfiguration);

@@ -152,3 +177,11 @@ (0, json_1.writeJson)(tree, projectConfigFile, {

const packageJson = (0, json_1.readJson)(tree, projectFile);
const config = (0, package_json_1.buildProjectConfigurationFromPackageJson)(packageJson, tree.root, projectFile, (0, nx_json_1.readNxJson)(tree));
// We don't want to have all of the extra inferred stuff in here, as
// when generators update the project they shouldn't inline that stuff.
// so rather than using `buildProjectFromPackageJson` and stripping it out
// we are going to build the config manually.
const config = {
root: (0, path_1.dirname)(projectFile),
name: packageJson.name ?? (0, to_project_name_1.toProjectName)(projectFile),
...packageJson.nx,
};
if (!rootMap[config.root]) {

@@ -158,6 +191,3 @@ (0, project_configuration_utils_1.mergeProjectConfigurationIntoRootMap)(rootMap,

// This is to help avoid running into issues when trying to update the workspace
{
name: config.name,
root: config.root,
}, undefined, undefined, true);
config, undefined, undefined, true);
}

@@ -164,0 +194,0 @@ }

@@ -6,2 +6,3 @@ "use strict";

const json_1 = require("../../generators/utils/json");
const format_changed_files_with_prettier_if_available_1 = require("../../generators/internal-utils/format-changed-files-with-prettier-if-available");
async function default_1(tree) {

@@ -28,2 +29,3 @@ (0, json_1.updateJson)(tree, 'package.json', (json) => {

(0, project_configuration_1.updateNxJson)(tree, nxJson);
await (0, format_changed_files_with_prettier_if_available_1.formatChangedFilesWithPrettierIfAvailable)(tree);
}
import { Tree } from '../../generators/tree';
export default function migrate(tree: Tree): void;
export default function migrate(tree: Tree): Promise<void>;

@@ -5,6 +5,8 @@ "use strict";

const nx_json_1 = require("../../generators/utils/nx-json");
function migrate(tree) {
const format_changed_files_with_prettier_if_available_1 = require("../../generators/internal-utils/format-changed-files-with-prettier-if-available");
async function migrate(tree) {
const nxJson = (0, nx_json_1.readNxJson)(tree);
nxJson.useInferencePlugins = false;
(0, nx_json_1.updateNxJson)(tree, nxJson);
await (0, format_changed_files_with_prettier_if_available_1.formatChangedFilesWithPrettierIfAvailable)(tree);
}

@@ -119,2 +119,4 @@ /* auto-generated by NAPI-RS */

export declare export function getBinaryTarget(): string
/**

@@ -121,0 +123,0 @@ * Expands the given outputs into a list of existing files.

@@ -375,2 +375,3 @@ // prettier-ignore

module.exports.findImports = nativeBinding.findImports
module.exports.getBinaryTarget = nativeBinding.getBinaryTarget
module.exports.getFilesForOutputs = nativeBinding.getFilesForOutputs

@@ -377,0 +378,0 @@ module.exports.hashArray = nativeBinding.hashArray

import { Tree } from '../../../generators/tree';
interface ConnectToNxCloudOptions {
import { NxJsonConfiguration } from '../../../config/nx-json';
export declare function printSuccessMessage(token: string | undefined, installationSource: string, usesGithub: boolean): Promise<string>;
export interface ConnectToNxCloudOptions {
analytics?: boolean;

@@ -9,3 +11,4 @@ installationSource?: string;

}
export declare function connectToNxCloud(tree: Tree, schema: ConnectToNxCloudOptions): Promise<() => void>;
export default connectToNxCloud;
export declare function connectToNxCloud(tree: Tree, schema: ConnectToNxCloudOptions, nxJson?: NxJsonConfiguration<string[] | "*">): Promise<string>;
declare function connectToNxCloudGenerator(tree: Tree, options: ConnectToNxCloudOptions): Promise<void>;
export default connectToNxCloudGenerator;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.printSuccessMessage = printSuccessMessage;
exports.connectToNxCloud = connectToNxCloud;

@@ -11,5 +12,3 @@ const child_process_1 = require("child_process");

const get_cloud_options_1 = require("../../utilities/get-cloud-options");
const git_utils_1 = require("../../../utils/git-utils");
const ora = require("ora");
const open = require("open");
const path_1 = require("path");
function printCloudConnectionDisabledMessage() {

@@ -47,3 +46,3 @@ output_1.output.error({

}
async function createNxCloudWorkspace(workspaceName, installationSource, nxInitDate) {
async function createNxCloudWorkspaceV1(workspaceName, installationSource, nxInitDate) {
const apiUrl = (0, get_cloud_options_1.getCloudUrl)();

@@ -60,94 +59,90 @@ const response = await require('axios').post(`${apiUrl}/nx-cloud/create-org-and-workspace`, {

}
async function printSuccessMessage(token, installationSource, usesGithub, directory) {
const connectCloudUrl = await (0, url_shorten_1.shortenedCloudUrl)(installationSource, token, usesGithub);
if (installationSource === 'nx-connect' && usesGithub) {
try {
const cloudConnectSpinner = ora(`Opening Nx Cloud ${connectCloudUrl} in your browser to connect your workspace.`).start();
await sleep(2000);
open(connectCloudUrl);
cloudConnectSpinner.succeed();
}
catch (e) {
output_1.output.note({
title: `Your Nx Cloud workspace is ready.`,
bodyLines: [
`To claim it, connect it to your Nx Cloud account:`,
`- Go to the following URL to connect your workspace to Nx Cloud:`,
'',
`${connectCloudUrl}`,
],
});
}
async function createNxCloudWorkspaceV2(workspaceName, installationSource, nxInitDate) {
const apiUrl = (0, get_cloud_options_1.getCloudUrl)();
const response = await require('axios').post(`${apiUrl}/nx-cloud/v2/create-org-and-workspace`, {
workspaceName,
installationSource,
nxInitDate,
});
if (response.data.message) {
throw new Error(response.data.message);
}
else {
if (installationSource === 'create-nx-workspace') {
output_1.output.note({
title: `Your Nx Cloud workspace is ready.`,
bodyLines: [
`To claim it, connect it to your Nx Cloud account:`,
`- Push your repository to your git hosting provider.`,
`- Go to the following URL to connect your workspace to Nx Cloud:`,
'',
`${connectCloudUrl}`,
],
});
(0, git_utils_1.commitChanges)(`feat(nx): Added Nx Cloud token to your nx.json
To connect your workspace to Nx Cloud, push your repository
to your git hosting provider and go to the following URL:
${connectCloudUrl}`, directory);
}
else {
output_1.output.note({
title: `Your Nx Cloud workspace is ready.`,
bodyLines: [
`To claim it, connect it to your Nx Cloud account:`,
`- Commit and push your changes.`,
`- Create a pull request for the changes.`,
`- Go to the following URL to connect your workspace to Nx Cloud:`,
'',
`${connectCloudUrl}`,
],
});
}
return response.data;
}
async function printSuccessMessage(token, installationSource, usesGithub) {
const connectCloudUrl = await (0, url_shorten_1.createNxCloudOnboardingURL)(installationSource, token, usesGithub);
output_1.output.note({
title: `Your Nx Cloud workspace is ready.`,
bodyLines: [
`To claim it, connect it to your Nx Cloud account:`,
`- Commit and push your changes.`,
`- Create a pull request for the changes.`,
`- Go to the following URL to connect your workspace to Nx Cloud:`,
'',
`${connectCloudUrl}`,
],
});
return connectCloudUrl;
}
function addNxCloudOptionsToNxJson(tree, token, directory = '') {
const nxJsonPath = (0, path_1.join)(directory, 'nx.json');
if (tree.exists(nxJsonPath)) {
(0, json_1.updateJson)(tree, (0, path_1.join)(directory, 'nx.json'), (nxJson) => {
const overrideUrl = process.env.NX_CLOUD_API || process.env.NRWL_API;
if (overrideUrl) {
nxJson.nxCloudUrl = overrideUrl;
}
nxJson.nxCloudAccessToken = token;
return nxJson;
});
}
}
function addNxCloudOptionsToNxJson(tree, nxJson, token) {
nxJson ??= {
extends: 'nx/presets/npm.json',
};
nxJson.nxCloudAccessToken = token;
const overrideUrl = process.env.NX_CLOUD_API || process.env.NRWL_API;
if (overrideUrl) {
nxJson.nxCloudUrl = overrideUrl;
function addNxCloudIdToNxJson(tree, nxCloudId, directory = '') {
const nxJsonPath = (0, path_1.join)(directory, 'nx.json');
if (tree.exists(nxJsonPath)) {
(0, json_1.updateJson)(tree, (0, path_1.join)(directory, 'nx.json'), (nxJson) => {
const overrideUrl = process.env.NX_CLOUD_API || process.env.NRWL_API;
if (overrideUrl) {
nxJson.nxCloudUrl = overrideUrl;
}
nxJson.nxCloudId = nxCloudId;
return nxJson;
});
}
(0, nx_json_1.updateNxJson)(tree, nxJson);
}
async function connectToNxCloud(tree, schema) {
async function connectToNxCloud(tree, schema, nxJson = (0, nx_json_1.readNxJson)(tree)) {
schema.installationSource ??= 'user';
const nxJson = (0, nx_json_1.readNxJson)(tree);
if (nxJson?.neverConnectToCloud) {
return () => {
printCloudConnectionDisabledMessage();
};
printCloudConnectionDisabledMessage();
return null;
}
else {
const usesGithub = await (0, url_shorten_1.repoUsesGithub)(schema.github);
let responseFromCreateNxCloudWorkspace;
const usesGithub = schema.github ?? (await (0, url_shorten_1.repoUsesGithub)(schema.github));
let responseFromCreateNxCloudWorkspaceV1;
let responseFromCreateNxCloudWorkspaceV2;
// do NOT create Nx Cloud token (createNxCloudWorkspace)
// if user is using github and is running nx-connect
if (!(usesGithub && schema.installationSource === 'nx-connect')) {
responseFromCreateNxCloudWorkspace = await createNxCloudWorkspace(getRootPackageName(tree), schema.installationSource, getNxInitDate());
addNxCloudOptionsToNxJson(tree, nxJson, responseFromCreateNxCloudWorkspace?.token);
await (0, format_changed_files_with_prettier_if_available_1.formatChangedFilesWithPrettierIfAvailable)(tree, {
silent: schema.hideFormatLogs,
});
if (process.env.NX_ENABLE_LOGIN === 'true') {
responseFromCreateNxCloudWorkspaceV2 = await createNxCloudWorkspaceV2(getRootPackageName(tree), schema.installationSource, getNxInitDate());
addNxCloudIdToNxJson(tree, responseFromCreateNxCloudWorkspaceV2?.nxCloudId, schema.directory);
await (0, format_changed_files_with_prettier_if_available_1.formatChangedFilesWithPrettierIfAvailable)(tree, {
silent: schema.hideFormatLogs,
});
return responseFromCreateNxCloudWorkspaceV2.nxCloudId;
}
else {
responseFromCreateNxCloudWorkspaceV1 = await createNxCloudWorkspaceV1(getRootPackageName(tree), schema.installationSource, getNxInitDate());
addNxCloudOptionsToNxJson(tree, responseFromCreateNxCloudWorkspaceV1?.token, schema.directory);
await (0, format_changed_files_with_prettier_if_available_1.formatChangedFilesWithPrettierIfAvailable)(tree, {
silent: schema.hideFormatLogs,
});
return responseFromCreateNxCloudWorkspaceV1.token;
}
}
return async () => await printSuccessMessage(responseFromCreateNxCloudWorkspace?.token, schema.installationSource, usesGithub, schema.directory);
}
}
function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
async function connectToNxCloudGenerator(tree, options) {
await connectToNxCloud(tree, options);
}
exports.default = connectToNxCloud;
exports.default = connectToNxCloudGenerator;

@@ -14,3 +14,4 @@ import { DefaultTasksRunnerOptions } from '../tasks-runner/default-tasks-runner';

clientVersion?: string;
nxCloudId?: string;
}
export declare const nxCloudTasksRunnerShell: TasksRunner<CloudTaskRunnerOptions>;

@@ -11,4 +11,11 @@ "use strict";

const accessToken = environment_1.ACCESS_TOKEN ? environment_1.ACCESS_TOKEN : options.accessToken;
if (!accessToken) {
throw new Error(`Unable to authenticate. Either define accessToken in nx.json or set the NX_CLOUD_ACCESS_TOKEN env variable.`);
const nxCloudId = options.nxCloudId;
// TODO(lourw): Update message with NxCloudId once it is supported
if (!accessToken && !nxCloudId) {
if (process.env.NX_ENABLE_LOGIN === 'true' && !nxCloudId) {
throw new Error(`Unable to authenticate. Please connect your workspace to Nx Cloud to define a valid Nx Cloud Id. If you are in a CI context, please set the NX_CLOUD_ACCESS_TOKEN environment variable or define an access token in your nx.json.`);
}
else {
throw new Error(`Unable to authenticate. Either define accessToken in nx.json or set the NX_CLOUD_ACCESS_TOKEN env variable. If you do not want to use Nx Cloud for this command, either set NX_NO_CLOUD=true, or pass the --no-cloud flag.`);
}
}

@@ -15,0 +22,0 @@ if (options.customProxyConfigPath) {

import { CloudTaskRunnerOptions } from '../nx-cloud-tasks-runner-shell';
export declare function getCloudOptions(): CloudTaskRunnerOptions;
export declare function getCloudOptions(directory?: string): CloudTaskRunnerOptions;
export declare function getCloudUrl(): string;
export declare function removeTrailingSlash(apiUrl: string): string;

@@ -8,4 +8,5 @@ "use strict";

const run_command_1 = require("../../tasks-runner/run-command");
function getCloudOptions() {
const nxJson = (0, nx_json_1.readNxJson)();
const workspace_root_1 = require("../../utils/workspace-root");
function getCloudOptions(directory = workspace_root_1.workspaceRoot) {
const nxJson = (0, nx_json_1.readNxJson)(directory);
// TODO: The default is not always cloud? But it's not handled at the moment

@@ -12,0 +13,0 @@ return (0, run_command_1.getRunnerOptions)('default', nxJson, {}, true);

@@ -1,2 +0,5 @@

export declare function shortenedCloudUrl(installationSource: string, accessToken?: string, usesGithub?: boolean): Promise<string>;
/**
* This is currently duplicated in Nx Console. Please let @MaxKless know if you make changes here.
*/
export declare function createNxCloudOnboardingURL(onboardingSource: string, accessToken?: string, usesGithub?: boolean, meta?: string): Promise<string>;
export declare function repoUsesGithub(github?: boolean, githubSlug?: string, apiUrl?: string): Promise<boolean>;

@@ -3,0 +6,0 @@ export declare function getURLifShortenFailed(usesGithub: boolean, githubSlug: string | null, apiUrl: string, source: string, accessToken?: string): string;

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.shortenedCloudUrl = shortenedCloudUrl;
exports.createNxCloudOnboardingURL = createNxCloudOnboardingURL;
exports.repoUsesGithub = repoUsesGithub;

@@ -13,3 +13,6 @@ exports.getURLifShortenFailed = getURLifShortenFailed;

const get_cloud_options_1 = require("./get-cloud-options");
async function shortenedCloudUrl(installationSource, accessToken, usesGithub) {
/**
* This is currently duplicated in Nx Console. Please let @MaxKless know if you make changes here.
*/
async function createNxCloudOnboardingURL(onboardingSource, accessToken, usesGithub, meta) {
const githubSlug = (0, git_utils_1.getGithubSlugOrNull)();

@@ -32,3 +35,3 @@ const apiUrl = (0, get_cloud_options_1.getCloudUrl)();

}
const source = getSource(installationSource);
const source = getSource(onboardingSource);
try {

@@ -40,2 +43,3 @@ const response = await require('axios').post(`${apiUrl}/nx-cloud/onboarding`, {

selectedRepositoryName: githubSlug === 'github' ? null : githubSlug,
meta,
});

@@ -73,7 +77,4 @@ if (!response?.data || response.data.message) {

}
else if (installationSource.includes('create-nx-workspace')) {
return 'create-nx-workspace';
}
else {
return 'other';
return installationSource;
}

@@ -80,0 +81,0 @@ }

@@ -144,5 +144,10 @@ "use strict";

const npmProjectKey = `npm:${externalPackageJson.name}@${version}`;
const matchingExternalNode = this.npmProjects[npmProjectKey];
let matchingExternalNode = this.npmProjects[npmProjectKey];
if (!matchingExternalNode) {
return null;
// check if it's a package alias, where the resolved package key is used as the version
const aliasNpmProjectKey = `npm:${packageName}@${npmProjectKey}`;
matchingExternalNode = this.npmProjects[aliasNpmProjectKey];
if (!matchingExternalNode) {
return null;
}
}

@@ -149,0 +154,0 @@ this.npmResolutionCache.set(npmImportForProject, matchingExternalNode.name);

@@ -93,3 +93,11 @@ "use strict";

for (const target of Object.keys(siblingProjectJson?.targets ?? {})) {
delete packageJson.scripts?.[target];
const { executor, command, options } = siblingProjectJson.targets[target];
if (
// will use run-commands, different target
command ||
// Either uses a different executor or runs a different script
(executor &&
(executor !== 'nx:run-script' || options?.script !== target))) {
delete packageJson.scripts?.[target];
}
}

@@ -96,0 +104,0 @@ }

@@ -74,6 +74,20 @@ "use strict";

exports.nxPluginCache = new Map();
function isIsolationEnabled() {
// Explicitly enabled, regardless of further conditions
if (process.env.NX_ISOLATE_PLUGINS === 'true') {
return true;
}
if (
// Explicitly disabled
process.env.NX_ISOLATE_PLUGINS === 'false' ||
// Isolation is disabled on WASM builds currently.
native_1.IS_WASM) {
return false;
}
// Default value
return true;
}
async function loadNxPlugins(plugins, root = workspace_root_1.workspaceRoot) {
performance.mark('loadNxPlugins:start');
const loadingMethod = process.env.NX_ISOLATE_PLUGINS === 'true' ||
(!native_1.IS_WASM && process.env.NX_ISOLATE_PLUGINS !== 'false')
const loadingMethod = isIsolationEnabled()
? isolation_1.loadNxPluginInIsolation

@@ -80,0 +94,0 @@ : loader_1.loadNxPlugin;

@@ -109,3 +109,7 @@ import { ProjectGraph, ProjectGraphProcessorContext } from '../../../config/project-graph';

}
export type PluginWorkerMessage = PluginWorkerLoadMessage | PluginWorkerCreateNodesMessage | PluginCreateDependenciesMessage | PluginWorkerProcessProjectGraphMessage | PluginCreateMetadataMessage;
export interface PluginWorkerShutdownMessage {
type: 'shutdown';
payload: {};
}
export type PluginWorkerMessage = PluginWorkerLoadMessage | PluginWorkerShutdownMessage | PluginWorkerCreateNodesMessage | PluginCreateDependenciesMessage | PluginWorkerProcessProjectGraphMessage | PluginCreateMetadataMessage;
export type PluginWorkerResult = PluginWorkerLoadResult | PluginWorkerCreateNodesResult | PluginCreateDependenciesResult | PluginWorkerProcessProjectGraphResult | PluginCreateMetadataResult;

@@ -112,0 +116,0 @@ export declare function isPluginWorkerMessage(message: Serializable): message is PluginWorkerMessage;

@@ -17,2 +17,3 @@ "use strict";

'createMetadata',
'shutdown',
].includes(message.type));

@@ -19,0 +20,0 @@ }

@@ -16,3 +16,7 @@ "use strict";

const pluginNames = new Map();
const MAX_MESSAGE_WAIT = 1000 * 60 * 5; // 5 minutes
const PLUGIN_TIMEOUT_HINT_TEXT = 'As a last resort, you can set NX_PLUGIN_NO_TIMEOUTS=true to bypass this timeout.';
const MINUTES = 10;
const MAX_MESSAGE_WAIT = process.env.NX_PLUGIN_NO_TIMEOUTS === 'true'
? undefined
: 1000 * 60 * MINUTES; // 10 minutes
const nxPluginWorkerCache = (global['nxPluginWorkerCache'] ??= new Map());

@@ -29,4 +33,4 @@ async function loadRemoteNxPlugin(plugin, root) {

worker.off('exit', exitHandler);
shutdownPluginWorker(socket);
socket.destroy();
shutdownPluginWorker(worker);
nxPluginWorkerCache.delete(cacheKey);

@@ -41,7 +45,10 @@ };

// logger.verbose(`[plugin-worker] started worker: ${worker.pid}`);
const loadTimeout = setTimeout(() => {
rej(new Error('Plugin worker timed out when loading plugin:' + plugin));
}, MAX_MESSAGE_WAIT);
const loadTimeout = MAX_MESSAGE_WAIT
? setTimeout(() => {
rej(new Error(`Loading "${plugin}" timed out after ${MINUTES} minutes. ${PLUGIN_TIMEOUT_HINT_TEXT}`));
}, MAX_MESSAGE_WAIT)
: undefined;
socket.on('data', (0, consume_messages_from_socket_1.consumeMessagesFromSocket)(createWorkerHandler(worker, pendingPromises, (val) => {
clearTimeout(loadTimeout);
if (loadTimeout)
clearTimeout(loadTimeout);
res(val);

@@ -54,7 +61,4 @@ }, rej, socket)));

}
function shutdownPluginWorker(worker) {
// Clears the plugin cache so no refs to the workers are held
internal_api_1.nxPluginCache.clear();
// logger.verbose(`[plugin-pool] starting worker shutdown`);
worker.kill('SIGINT');
function shutdownPluginWorker(socket) {
(0, messaging_1.sendMessageOverSocket)(socket, { type: 'shutdown', payload: {} });
}

@@ -97,2 +101,5 @@ /**

});
}, {
plugin: pluginName,
operation: 'createNodes',
});

@@ -110,2 +117,5 @@ },

});
}, {
plugin: pluginName,
operation: 'createDependencies',
});

@@ -122,2 +132,5 @@ }

});
}, {
operation: 'processProjectGraph',
plugin: pluginName,
});

@@ -134,2 +147,5 @@ }

});
}, {
plugin: pluginName,
operation: 'createMetadata',
});

@@ -192,2 +208,3 @@ }

const exitHandler = () => {
internal_api_1.nxPluginCache.clear();
for (const fn of cleanupFunctions) {

@@ -204,3 +221,3 @@ fn();

process.on('SIGTERM', exitHandler);
function registerPendingPromise(tx, pending, callback) {
function registerPendingPromise(tx, pending, callback, context) {
let resolver, rejector, timeout;

@@ -210,9 +227,12 @@ const promise = new Promise((res, rej) => {

resolver = res;
timeout = setTimeout(() => {
rej(new Error(`Plugin worker timed out when processing message ${tx}`));
}, MAX_MESSAGE_WAIT);
timeout = MAX_MESSAGE_WAIT
? setTimeout(() => {
rej(new Error(`${context.plugin} timed out after ${MINUTES} minutes during ${context.operation}. ${PLUGIN_TIMEOUT_HINT_TEXT}`));
}, MAX_MESSAGE_WAIT)
: undefined;
callback();
}).finally(() => {
pending.delete(tx);
clearTimeout(timeout);
if (timeout)
clearTimeout(timeout);
});

@@ -219,0 +239,0 @@ pending.set(tx, {

@@ -52,2 +52,17 @@ "use strict";

},
shutdown: async () => {
// Stops accepting new connections, but existing connections are
// not closed immediately.
server.close(() => {
try {
(0, fs_1.unlinkSync)(socketPath);
}
catch (e) { }
process.exit(0);
});
// Closes existing connection.
socket.end();
// Destroys the socket once it's fully closed.
socket.destroySoon();
},
createNodes: async ({ configFiles, context, tx }) => {

@@ -54,0 +69,0 @@ try {

@@ -228,3 +228,3 @@ "use strict";

catch (e) {
if (e.message.indexOf('inotify_add_watch') > -1) {
if (e.message && e.message.indexOf('inotify_add_watch') > -1) {
// common errors with the daemon due to OS settings (cannot watch all the files available)

@@ -231,0 +231,0 @@ output_1.output.note({

@@ -40,2 +40,3 @@ import { NxJsonConfiguration, TargetDefaults } from '../../config/nx-json';

plugins: LoadedNxPlugin[]): Promise<ConfigurationResult>;
export declare function findMatchingConfigFiles(projectFiles: string[], pattern: string, include: string[], exclude: string[]): string[];
export declare function readProjectConfigurationsFromRootMap(projectRootMap: Record<string, ProjectConfiguration>): Record<string, ProjectConfiguration>;

@@ -42,0 +43,0 @@ export declare function validateProject(project: ProjectConfiguration, knownProjects: Record<string, ProjectConfiguration>): void;

@@ -6,2 +6,3 @@ "use strict";

exports.createProjectConfigurations = createProjectConfigurations;
exports.findMatchingConfigFiles = findMatchingConfigFiles;
exports.readProjectConfigurationsFromRootMap = readProjectConfigurationsFromRootMap;

@@ -449,3 +450,3 @@ exports.validateProject = validateProject;

const targetConfig = project.targets[targetName];
const targetDefaults = readTargetDefaultsForTarget(targetName, nxJsonConfiguration.targetDefaults, targetConfig.executor);
const targetDefaults = deepClone(readTargetDefaultsForTarget(targetName, nxJsonConfiguration.targetDefaults, targetConfig.executor));
// We only apply defaults if they exist

@@ -503,5 +504,8 @@ if (targetDefaults && isCompatibleTarget(targetConfig, targetDefaults)) {

}
function deepClone(obj) {
return JSON.parse(JSON.stringify(obj));
}
function mergeTargetDefaultWithTargetDefinition(targetName, project, targetDefault, sourceMap) {
const targetDefinition = project.targets[targetName] ?? {};
const result = JSON.parse(JSON.stringify(targetDefinition));
const result = deepClone(targetDefinition);
for (const key in targetDefault) {

@@ -508,0 +512,0 @@ switch (key) {

@@ -28,3 +28,3 @@ "use strict";

try {
const p = (0, child_process_1.spawn)('node', [scriptPath, `"${this.cachePath}"`], {
const p = (0, child_process_1.spawn)('node', [scriptPath, `${this.cachePath}`], {
stdio: 'ignore',

@@ -31,0 +31,0 @@ detached: true,

@@ -8,3 +8,3 @@ import { NxJsonConfiguration } from '../config/nx-json';

import { TasksRunner } from './tasks-runner';
export declare function runCommand(projectsToRun: ProjectGraphProjectNode[], projectGraph: ProjectGraph, { nxJson }: {
export declare function runCommand(projectsToRun: ProjectGraphProjectNode[], currentProjectGraph: ProjectGraph, { nxJson }: {
nxJson: NxJsonConfiguration;

@@ -11,0 +11,0 @@ }, nxArgs: NxArgs, overrides: any, initiatingProject: string | null, extraTargetDependencies: Record<string, (TargetDependencyConfig | string)[]>, extraOptions: {

@@ -7,2 +7,4 @@ "use strict";

exports.getRunnerOptions = getRunnerOptions;
const enquirer_1 = require("enquirer");
const ora = require("ora");
const path_1 = require("path");

@@ -13,2 +15,3 @@ const nx_json_1 = require("../config/nx-json");

const hash_task_1 = require("../hasher/hash-task");
const project_graph_1 = require("../project-graph/project-graph");
const fileutils_1 = require("../utils/fileutils");

@@ -19,2 +22,3 @@ const is_ci_1 = require("../utils/is-ci");

const params_1 = require("../utils/params");
const sync_generators_1 = require("../utils/sync-generators");
const workspace_root_1 = require("../utils/workspace-root");

@@ -33,2 +37,3 @@ const create_task_graph_1 = require("./create-task-graph");

const utils_1 = require("./utils");
const chalk = require("chalk");
async function getTerminalOutputLifeCycle(initiatingProject, projectNames, tasks, nxArgs, nxJson, overrides) {

@@ -97,6 +102,6 @@ const { runnerOptions } = getRunner(nxArgs, nxJson);

}
async function runCommand(projectsToRun, projectGraph, { nxJson }, nxArgs, overrides, initiatingProject, extraTargetDependencies, extraOptions) {
async function runCommand(projectsToRun, currentProjectGraph, { nxJson }, nxArgs, overrides, initiatingProject, extraTargetDependencies, extraOptions) {
const status = await (0, params_1.handleErrors)(process.env.NX_VERBOSE_LOGGING === 'true', async () => {
const projectNames = projectsToRun.map((t) => t.name);
const taskGraph = createTaskGraphAndRunValidations(projectGraph, extraTargetDependencies ?? {}, projectNames, nxArgs, overrides, extraOptions);
const { projectGraph, taskGraph } = await ensureWorkspaceIsInSyncAndGetGraphs(currentProjectGraph, nxJson, projectNames, nxArgs, overrides, extraTargetDependencies, extraOptions);
const tasks = Object.values(taskGraph.tasks);

@@ -119,2 +124,117 @@ const { lifeCycle, renderIsDone } = await getTerminalOutputLifeCycle(initiatingProject, projectNames, tasks, nxArgs, nxJson, overrides);

}
async function ensureWorkspaceIsInSyncAndGetGraphs(projectGraph, nxJson, projectNames, nxArgs, overrides, extraTargetDependencies, extraOptions) {
let taskGraph = createTaskGraphAndRunValidations(projectGraph, extraTargetDependencies ?? {}, projectNames, nxArgs, overrides, extraOptions);
// collect unique syncGenerators from the tasks
const uniqueSyncGenerators = new Set();
for (const { target } of Object.values(taskGraph.tasks)) {
const { syncGenerators } = projectGraph.nodes[target.project].data.targets[target.target];
if (!syncGenerators) {
continue;
}
for (const generator of syncGenerators) {
uniqueSyncGenerators.add(generator);
}
}
if (!uniqueSyncGenerators.size) {
// There are no sync generators registered in the tasks to run
return { projectGraph, taskGraph };
}
const syncGenerators = Array.from(uniqueSyncGenerators);
const results = await (0, sync_generators_1.getSyncGeneratorChanges)(syncGenerators);
if (!results.length) {
// There are no changes to sync, workspace is up to date
return { projectGraph, taskGraph };
}
const outOfSyncTitle = 'The workspace is out of sync';
const resultBodyLines = [...(0, sync_generators_1.syncGeneratorResultsToMessageLines)(results), ''];
const fixMessage = 'You can manually run `nx sync` to update your workspace or you can set `sync.applyChanges` to `true` in your `nx.json` to apply the changes automatically when running tasks.';
const willErrorOnCiMessage = 'Please note that this will be an error on CI.';
if ((0, is_ci_1.isCI)() || !process.stdout.isTTY) {
// If the user is running in CI or is running in a non-TTY environment we
// throw an error to stop the execution of the tasks.
throw new Error(`${outOfSyncTitle}\n${resultBodyLines.join('\n')}\n${fixMessage}`);
}
if (nxJson.sync?.applyChanges === false) {
// If the user has set `sync.applyChanges` to `false` in their `nx.json`
// we don't prompt the them and just log a warning informing them that
// the workspace is out of sync and they have it set to not apply changes
// automatically.
output_1.output.warn({
title: outOfSyncTitle,
bodyLines: [
...resultBodyLines,
'Your workspace is set to not apply changes automatically (`sync.applyChanges` is set to `false` in your `nx.json`).',
willErrorOnCiMessage,
fixMessage,
],
});
return { projectGraph, taskGraph };
}
output_1.output.warn({
title: outOfSyncTitle,
bodyLines: [
...resultBodyLines,
nxJson.sync?.applyChanges === true
? 'Proceeding to sync the changes automatically (`sync.applyChanges` is set to `true` in your `nx.json`).'
: willErrorOnCiMessage,
],
});
const applyChanges = nxJson.sync?.applyChanges === true ||
(await promptForApplyingSyncGeneratorChanges());
if (applyChanges) {
const spinner = ora('Syncing the workspace...');
spinner.start();
// Flush sync generator changes to disk
await (0, sync_generators_1.flushSyncGeneratorChanges)(results);
// Re-create project graph and task graph
projectGraph = await (0, project_graph_1.createProjectGraphAsync)();
taskGraph = createTaskGraphAndRunValidations(projectGraph, extraTargetDependencies ?? {}, projectNames, nxArgs, overrides, extraOptions);
if (nxJson.sync?.applyChanges === true) {
spinner.succeed(`The workspace was synced successfully!
Please make sure to commit the changes to your repository or this will error on CI.`);
}
else {
// The user was prompted and we already logged a message about erroring on CI
// so here we just tell them to commit the changes.
spinner.succeed(`The workspace was synced successfully!
Please make sure to commit the changes to your repository.`);
}
}
else {
output_1.output.warn({
title: 'Syncing the workspace was skipped',
bodyLines: [
'This could lead to unexpected results or errors when running tasks.',
fixMessage,
],
});
}
return { projectGraph, taskGraph };
}
async function promptForApplyingSyncGeneratorChanges() {
try {
const promptConfig = {
name: 'applyChanges',
type: 'select',
message: 'Would you like to sync the changes to get your worskpace up to date?',
choices: [
{
name: 'yes',
message: 'Yes, sync the changes and run the tasks',
},
{
name: 'no',
message: 'No, run the tasks without syncing the changes',
},
],
footer: () => chalk.dim('\nYou can skip this prompt by setting the `sync.applyChanges` option in your `nx.json`.'),
};
return await (0, enquirer_1.prompt)([promptConfig]).then(({ applyChanges }) => applyChanges === 'yes');
}
catch {
process.exit(1);
}
}
function setEnvVarsBasedOnArgs(nxArgs, loadDotEnvFiles) {

@@ -327,3 +447,5 @@ if (nxArgs.outputStyle == 'stream' ||

// Cloud access token specified in env var.
process.env.NX_CLOUD_ACCESS_TOKEN;
process.env.NX_CLOUD_ACCESS_TOKEN ||
// Nx Cloud Id specified in nxJson
nxJson.nxCloudId;
return isCloudRunner ? 'nx-cloud' : require.resolve('./default-tasks-runner');

@@ -349,2 +471,5 @@ }

}
if (nxJson.nxCloudId && isCloudDefault) {
result.nxCloudId ??= nxJson.nxCloudId;
}
if (nxJson.nxCloudUrl && isCloudDefault) {

@@ -351,0 +476,0 @@ result.url ??= nxJson.nxCloudUrl;

@@ -11,2 +11,3 @@ "use strict";

const workspace_root_1 = require("../utils/workspace-root");
const node_path_1 = require("node:path");
function getEnvVariablesForBatchProcess(skipNxCache, captureStderr) {

@@ -162,3 +163,3 @@ return {

for (const file of dotEnvFiles) {
loadAndExpandDotEnvFile(file, environmentVariables);
loadAndExpandDotEnvFile((0, node_path_1.join)(workspace_root_1.workspaceRoot, file), environmentVariables);
}

@@ -169,5 +170,5 @@ return environmentVariables;

for (const file of ['.env', '.local.env', '.env.local']) {
unloadDotEnvFile(file, environmentVariables);
unloadDotEnvFile((0, node_path_1.join)(workspace_root_1.workspaceRoot, file), environmentVariables);
}
return environmentVariables;
}

@@ -69,3 +69,3 @@ "use strict";

`Please enable Nx Cloud or use the slower ${nonAtomizedTasks.join(',')} task${nonAtomizedTasks.length > 1 ? 's' : ''}.`,
'Learn more at https://nx.dev/ci/features/split-e2e-tasks#use-atomizer-only-with-nx-cloud-distribution',
'Learn more at https://nx.dev/ci/features/split-e2e-tasks#nx-cloud-is-required-to-run-atomized-tasks',
];

@@ -72,0 +72,0 @@ if (atomizedRootTasks.length === 1) {

@@ -80,6 +80,3 @@ "use strict";

const patternResultCache = new WeakMap();
function expandWildcardTargetConfiguration(dependencyConfig, allTargetNames) {
if (!(0, globs_1.isGlobPattern)(dependencyConfig.target)) {
return [dependencyConfig];
}
function findMatchingTargets(pattern, allTargetNames) {
let cache = patternResultCache.get(allTargetNames);

@@ -90,14 +87,21 @@ if (!cache) {

}
const cachedResult = cache.get(dependencyConfig.target);
const cachedResult = cache.get(pattern);
if (cachedResult) {
return cachedResult;
}
const matcher = minimatch_1.minimatch.filter(dependencyConfig.target);
const matcher = minimatch_1.minimatch.filter(pattern);
const matchingTargets = allTargetNames.filter((t) => matcher(t));
const result = matchingTargets.map((t) => ({
...dependencyConfig,
cache.set(pattern, matchingTargets);
return matchingTargets;
}
function expandWildcardTargetConfiguration(dependencyConfig, allTargetNames) {
if (!(0, globs_1.isGlobPattern)(dependencyConfig.target)) {
return [dependencyConfig];
}
const matchingTargets = findMatchingTargets(dependencyConfig.target, allTargetNames);
return matchingTargets.map((t) => ({
target: t,
projects: dependencyConfig.projects,
dependencies: dependencyConfig.dependencies,
}));
cache.set(dependencyConfig.target, result);
return result;
}

@@ -220,5 +224,5 @@ function readProjectAndTargetFromTargetString(targetString, projects) {

validateOutputs(targetConfiguration.outputs);
return targetConfiguration.outputs
.map((output) => {
return interpolate(output, {
const result = new Set();
for (const output of targetConfiguration.outputs) {
const interpolatedOutput = interpolate(output, {
projectRoot: node.data.root,

@@ -229,4 +233,8 @@ projectName: node.name,

});
})
.filter((output) => !!output && !output.match(/{(projectRoot|workspaceRoot|(options.*))}/));
if (!!interpolatedOutput &&
!interpolatedOutput.match(/{(projectRoot|workspaceRoot|(options.*))}/)) {
result.add(interpolatedOutput);
}
}
return Array.from(result);
}

@@ -233,0 +241,0 @@ // Keep backwards compatibility in case `outputs` doesn't exist

export declare function chunkify(target: string[], maxChunkLength?: number): string[][];
/**
* Get the maximum length of a command-line argument string based on current platform
*
* https://serverfault.com/questions/69430/what-is-the-maximum-length-of-a-command-line-in-mac-os-x
* https://support.microsoft.com/en-us/help/830473/command-prompt-cmd-exe-command-line-string-limitation
* https://unix.stackexchange.com/a/120652
*
* Taken from: https://github.com/lint-staged/lint-staged/blob/adf50b00669f6aac2eeca25dd28ff86a9a3c2a48/lib/index.js#L21-L37
*/
export declare function getMaxArgLength(): 262144 | 8191 | 131072;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.chunkify = chunkify;
const child_process_1 = require("child_process");
const TERMINAL_SIZE = process.platform === 'win32' ? 8192 : getUnixTerminalSize();
exports.getMaxArgLength = getMaxArgLength;
const TERMINAL_SIZE = getMaxArgLength();
function chunkify(target, maxChunkLength = TERMINAL_SIZE - 500) {

@@ -26,13 +26,20 @@ const chunks = [];

}
function getUnixTerminalSize() {
try {
const argMax = (0, child_process_1.execSync)('getconf ARG_MAX').toString().trim();
return Number.parseInt(argMax);
/**
* Get the maximum length of a command-line argument string based on current platform
*
* https://serverfault.com/questions/69430/what-is-the-maximum-length-of-a-command-line-in-mac-os-x
* https://support.microsoft.com/en-us/help/830473/command-prompt-cmd-exe-command-line-string-limitation
* https://unix.stackexchange.com/a/120652
*
* Taken from: https://github.com/lint-staged/lint-staged/blob/adf50b00669f6aac2eeca25dd28ff86a9a3c2a48/lib/index.js#L21-L37
*/
function getMaxArgLength() {
switch (process.platform) {
case 'darwin':
return 262144;
case 'win32':
return 8191;
default:
return 131072;
}
catch {
// This number varies by system, but 100k seems like a safe
// number from some research...
// https://stackoverflow.com/questions/19354870/bash-command-line-and-input-limit
return 100000;
}
}

@@ -32,4 +32,6 @@ import type { Arguments } from 'yargs';

batch?: boolean;
excludeTaskDependencies?: boolean;
}
export declare function createOverrides(__overrides_unparsed__?: string[]): Record<string, any>;
export declare function getBaseRef(nxJson: NxJsonConfiguration): string;
export declare function splitArgsIntoNxArgsAndOverrides(args: {

@@ -45,2 +47,5 @@ [k: string]: any;

};
export declare function readParallelFromArgsAndEnv(args: {
[k: string]: any;
}): number;
export declare function parseFiles(options: NxArgs): {

@@ -47,0 +52,0 @@ files: string[];

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createOverrides = createOverrides;
exports.getBaseRef = getBaseRef;
exports.splitArgsIntoNxArgsAndOverrides = splitArgsIntoNxArgsAndOverrides;
exports.readParallelFromArgsAndEnv = readParallelFromArgsAndEnv;
exports.parseFiles = parseFiles;

@@ -26,2 +28,5 @@ exports.getProjectRoots = getProjectRoots;

}
function getBaseRef(nxJson) {
return nxJson.defaultBase ?? nxJson.affected?.defaultBase ?? 'main';
}
function splitArgsIntoNxArgsAndOverrides(args, mode, options = { printWarnings: true }, nxJson) {

@@ -73,3 +78,3 @@ // this is to lerna case when this function is invoked imperatively

}
// Allow setting base and head via environment variables (lower priority then direct command arguments)
// Allow setting base and head via environment variables (lower priority than direct command arguments)
if (!nxArgs.base && process.env.NX_BASE) {

@@ -92,4 +97,3 @@ nxArgs.base = process.env.NX_BASE;

if (!nxArgs.base) {
nxArgs.base =
nxJson.defaultBase ?? nxJson.affected?.defaultBase ?? 'main';
nxArgs.base = getBaseRef(nxJson);
// No user-provided arguments to set the affected criteria, so inform the user of the defaults being used

@@ -118,4 +122,8 @@ if (options.printWarnings &&

normalizeNxArgsRunner(nxArgs, nxJson, options);
nxArgs['parallel'] = readParallelFromArgsAndEnv(args);
return { nxArgs, overrides };
}
function readParallelFromArgsAndEnv(args) {
if (args['parallel'] === 'false' || args['parallel'] === false) {
nxArgs['parallel'] = 1;
return 1;
}

@@ -125,6 +133,6 @@ else if (args['parallel'] === 'true' ||

args['parallel'] === '' ||
process.env.NX_PARALLEL // dont require passing --parallel if NX_PARALLEL is set
) {
nxArgs['parallel'] = Number(nxArgs['maxParallel'] ||
nxArgs['max-parallel'] ||
// dont require passing --parallel if NX_PARALLEL is set, but allow overriding it
(process.env.NX_PARALLEL && args['parallel'] === undefined)) {
return Number(args['maxParallel'] ||
args['max-parallel'] ||
process.env.NX_PARALLEL ||

@@ -134,5 +142,4 @@ 3);

else if (args['parallel'] !== undefined) {
nxArgs['parallel'] = Number(args['parallel']);
return Number(args['parallel']);
}
return { nxArgs, overrides };
}

@@ -139,0 +146,0 @@ function normalizeNxArgsRunner(nxArgs, nxJson, options) {

@@ -0,1 +1,39 @@

import { ExecSyncOptions } from 'child_process';
export declare function cloneFromUpstream(url: string, destination: string, { originName }?: {
originName: string;
}): Promise<GitRepository>;
export declare class GitRepository {
private directory;
root: string;
constructor(directory: string);
getGitRootPath(cwd: string): string;
addFetchRemote(remoteName: string, branch: string): Promise<string>;
private execAsync;
showStat(): Promise<string>;
listBranches(): Promise<string[]>;
getGitFiles(path: string): Promise<string[]>;
reset(ref: string): Promise<string>;
squashLastTwoCommits(): Promise<string>;
mergeUnrelatedHistories(ref: string, message: string): Promise<string>;
fetch(remote: string, ref?: string): Promise<string>;
checkout(branch: string, opts: {
new: boolean;
base: string;
}): Promise<string>;
move(path: string, destination: string): Promise<string>;
push(ref: string, remoteName: string): Promise<string>;
commit(message: string): Promise<string>;
amendCommit(): Promise<string>;
deleteGitRemote(name: string): Promise<string>;
deleteBranch(branch: string): Promise<string>;
addGitRemote(name: string, url: string): Promise<string>;
}
/**
* This is used by the squash editor script to update the rebase file.
*/
export declare function updateRebaseFile(contents: string): string;
export declare function fetchGitRemote(name: string, branch: string, execOptions: ExecSyncOptions): string | Buffer;
/**
* This is currently duplicated in Nx Console. Please let @MaxKless know if you make changes here.
*/
export declare function getGithubSlugOrNull(): string | null;

@@ -2,0 +40,0 @@ export declare function extractUserAndRepoFromGitHubUrl(gitRemotes: string): string | null;

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.GitRepository = void 0;
exports.cloneFromUpstream = cloneFromUpstream;
exports.updateRebaseFile = updateRebaseFile;
exports.fetchGitRemote = fetchGitRemote;
exports.getGithubSlugOrNull = getGithubSlugOrNull;

@@ -9,5 +13,117 @@ exports.extractUserAndRepoFromGitHubUrl = extractUserAndRepoFromGitHubUrl;

const devkit_exports_1 = require("../devkit-exports");
const path_1 = require("path");
const SQUASH_EDITOR = (0, path_1.join)(__dirname, 'squash.js');
function execAsync(command, execOptions) {
return new Promise((res, rej) => {
(0, child_process_1.exec)(command, execOptions, (err, stdout, stderr) => {
if (err) {
return rej(err);
}
res(stdout);
});
});
}
async function cloneFromUpstream(url, destination, { originName } = { originName: 'origin' }) {
await execAsync(`git clone ${url} ${destination} --depth 1 --origin ${originName}`, {
cwd: (0, path_1.dirname)(destination),
});
return new GitRepository(destination);
}
class GitRepository {
constructor(directory) {
this.directory = directory;
this.root = this.getGitRootPath(this.directory);
}
getGitRootPath(cwd) {
return (0, child_process_1.execSync)('git rev-parse --show-toplevel', {
cwd,
})
.toString()
.trim();
}
addFetchRemote(remoteName, branch) {
return this.execAsync(`git config --add remote.${remoteName}.fetch "+refs/heads/${branch}:refs/remotes/${remoteName}/${branch}"`);
}
execAsync(command) {
return execAsync(command, {
cwd: this.root,
});
}
async showStat() {
return await this.execAsync(`git show --stat`);
}
async listBranches() {
return (await this.execAsync(`git ls-remote --heads --quiet`))
.trim()
.split('\n')
.map((s) => s
.trim()
.substring(s.indexOf('\t') + 1)
.replace('refs/heads/', ''));
}
async getGitFiles(path) {
return (await this.execAsync(`git ls-files ${path}`))
.trim()
.split('\n')
.map((s) => s.trim())
.filter(Boolean);
}
async reset(ref) {
return this.execAsync(`git reset ${ref} --hard`);
}
async squashLastTwoCommits() {
return this.execAsync(`git -c core.editor="node ${SQUASH_EDITOR}" rebase --interactive --no-autosquash HEAD~2`);
}
async mergeUnrelatedHistories(ref, message) {
return this.execAsync(`git merge ${ref} -X ours --allow-unrelated-histories -m "${message}"`);
}
async fetch(remote, ref) {
return this.execAsync(`git fetch ${remote}${ref ? ` ${ref}` : ''}`);
}
async checkout(branch, opts) {
return this.execAsync(`git checkout ${opts.new ? '-b ' : ' '}${branch}${opts.base ? ' ' + opts.base : ''}`);
}
async move(path, destination) {
return this.execAsync(`git mv "${path}" "${destination}"`);
}
async push(ref, remoteName) {
return this.execAsync(`git push -u -f ${remoteName} ${ref}`);
}
async commit(message) {
return this.execAsync(`git commit -am "${message}"`);
}
async amendCommit() {
return this.execAsync(`git commit --amend -a --no-edit`);
}
deleteGitRemote(name) {
return this.execAsync(`git remote rm ${name}`);
}
deleteBranch(branch) {
return this.execAsync(`git branch -D ${branch}`);
}
addGitRemote(name, url) {
return this.execAsync(`git remote add ${name} ${url}`);
}
}
exports.GitRepository = GitRepository;
/**
* This is used by the squash editor script to update the rebase file.
*/
function updateRebaseFile(contents) {
const lines = contents.split('\n');
const lastCommitIndex = lines.findIndex((line) => line === '') - 1;
lines[lastCommitIndex] = lines[lastCommitIndex].replace('pick', 'fixup');
return lines.join('\n');
}
function fetchGitRemote(name, branch, execOptions) {
return (0, child_process_1.execSync)(`git fetch ${name} ${branch} --depth 1`, execOptions);
}
/**
* This is currently duplicated in Nx Console. Please let @MaxKless know if you make changes here.
*/
function getGithubSlugOrNull() {
try {
const gitRemote = (0, child_process_1.execSync)('git remote -v').toString();
const gitRemote = (0, child_process_1.execSync)('git remote -v', {
stdio: 'pipe',
}).toString();
// If there are no remotes, we default to github

@@ -14,0 +130,0 @@ if (!gitRemote || gitRemote.length === 0) {

@@ -9,2 +9,3 @@ "use strict";

!!nxJson.nxCloudAccessToken ||
!!nxJson.nxCloudId ||
!!Object.values(nxJson.tasksRunnerOptions ?? {}).find((r) => r.runner == '@nrwl/nx-cloud' || r.runner == 'nx-cloud'));

@@ -15,3 +16,4 @@ }

if (!cloudRunner &&
!(nxJson.nxCloudAccessToken || process.env.NX_CLOUD_ACCESS_TOKEN))
!(nxJson.nxCloudAccessToken || process.env.NX_CLOUD_ACCESS_TOKEN) &&
!nxJson.nxCloudId)
throw new Error('nx-cloud runner not found in nx.json');

@@ -18,0 +20,0 @@ return cloudRunner?.options?.url ?? nxJson.nxCloudUrl ?? 'https://nx.app';

@@ -1,11 +0,4 @@

import { InputDefinition, ProjectMetadata, TargetConfiguration } from '../config/workspace-json-project-json';
import { ProjectConfiguration, ProjectMetadata, TargetConfiguration } from '../config/workspace-json-project-json';
import { PackageManagerCommands } from './package-manager';
export interface NxProjectPackageJsonConfiguration {
name?: string;
implicitDependencies?: string[];
tags?: string[];
namedInputs?: {
[inputName: string]: (string | InputDefinition)[];
};
targets?: Record<string, TargetConfiguration>;
export interface NxProjectPackageJsonConfiguration extends Partial<ProjectConfiguration> {
includedScripts?: string[];

@@ -12,0 +5,0 @@ }

@@ -52,3 +52,3 @@ "use strict";

}
// yarn and pnpm both use the same 'workspaces' property in package.json
// yarn and npm both use the same 'workspaces' property in package.json
const packageJson = (0, file_utils_1.readPackageJson)();

@@ -180,2 +180,3 @@ return !!packageJson?.workspaces;

encoding: 'utf-8',
windowsHide: true,
}).trim();

@@ -354,3 +355,6 @@ }

const pmc = getPackageManagerCommand();
await execAsync(`${pmc.add} ${packageName}@${version}`, { cwd: dir });
await execAsync(`${pmc.add} ${packageName}@${version}`, {
cwd: dir,
windowsHide: true,
});
const { packageJson } = (0, package_json_1.readModulePackageJson)(packageName, [dir]);

@@ -378,3 +382,5 @@ return packageJson.version;

}
const { stdout } = await execAsync(`${pm} view ${pkg}@${version} ${args}`);
const { stdout } = await execAsync(`${pm} view ${pkg}@${version} ${args}`, {
windowsHide: true,
});
return stdout.toString().trim();

@@ -396,5 +402,8 @@ }

}
const { stdout } = await execAsync(`${pm} pack ${pkg}@${version}`, { cwd });
const { stdout } = await execAsync(`${pm} pack ${pkg}@${version}`, {
cwd,
windowsHide: true,
});
const tarballPath = stdout.trim();
return { tarballPath };
}

@@ -1,3 +0,6 @@

import type { CorePlugin, PluginCapabilities } from './models';
export declare function fetchCorePlugins(): CorePlugin[];
export declare function listCorePlugins(installedPlugins: Map<string, PluginCapabilities>, corePlugins: CorePlugin[]): void;
export interface CorePlugin {
name: string;
capabilities: 'executors' | 'generators' | 'executors,generators' | 'graph';
link?: string;
}
export declare const CORE_PLUGINS: CorePlugin[];
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.fetchCorePlugins = fetchCorePlugins;
exports.listCorePlugins = listCorePlugins;
const chalk = require("chalk");
const output_1 = require("../output");
function fetchCorePlugins() {
return [
{
name: '@nx/angular',
capabilities: 'executors,generators',
},
{
name: '@nx/cypress',
capabilities: 'executors,generators',
},
{
name: '@nx/detox',
capabilities: 'executors,generators',
},
{
name: '@nx/esbuild',
capabilities: 'executors,generators',
},
{
name: '@nx/expo',
capabilities: 'executors,generators',
},
{
name: '@nx/express',
capabilities: 'generators',
},
{
name: '@nx/jest',
capabilities: 'executors,generators',
},
{
name: '@nx/js',
capabilities: 'executors,generators',
},
{
name: '@nx/eslint',
capabilities: 'executors,generators',
},
{
name: '@nx/nest',
capabilities: 'generators',
},
{
name: '@nx/next',
capabilities: 'executors,generators',
},
{
name: '@nx/node',
capabilities: 'executors,generators',
},
{
name: '@nx/nuxt',
capabilities: 'generators',
},
{
name: 'nx',
capabilities: 'executors',
},
{
name: '@nx/plugin',
capabilities: 'executors,generators',
},
{
name: '@nx/react',
capabilities: 'executors,generators',
},
{
name: '@nx/react-native',
capabilities: 'executors,generators',
},
{
name: '@nx/remix',
capabilities: 'executors,generators',
},
{
name: '@nx/rollup',
capabilities: 'executors,generators',
},
{
name: '@nx/storybook',
capabilities: 'executors,generators',
},
{
name: '@nx/vite',
capabilities: 'executors,generators',
},
{
name: '@nx/web',
capabilities: 'executors,generators',
},
{
name: '@nx/webpack',
capabilities: 'executors,generators',
},
{
name: '@nx/workspace',
capabilities: 'executors,generators',
},
];
}
function listCorePlugins(installedPlugins, corePlugins) {
const alsoAvailable = corePlugins.filter((p) => !installedPlugins.has(p.name));
if (alsoAvailable.length) {
output_1.output.log({
title: `Also available:`,
bodyLines: alsoAvailable.map((p) => {
return `${chalk.bold(p.name)} (${p.capabilities})`;
}),
});
}
}
exports.CORE_PLUGINS = void 0;
exports.CORE_PLUGINS = [
{
name: '@nx/angular',
capabilities: 'executors,generators',
},
{
name: '@nx/cypress',
capabilities: 'executors,generators',
},
{
name: '@nx/detox',
capabilities: 'executors,generators',
},
{
name: '@nx/esbuild',
capabilities: 'executors,generators',
},
{
name: '@nx/expo',
capabilities: 'executors,generators',
},
{
name: '@nx/express',
capabilities: 'generators',
},
{
name: '@nx/gradle',
capabilities: 'graph',
},
{
name: '@nx/jest',
capabilities: 'executors,generators',
},
{
name: '@nx/js',
capabilities: 'executors,generators',
},
{
name: '@nx/eslint',
capabilities: 'executors,generators',
},
{
name: '@nx/nest',
capabilities: 'generators',
},
{
name: '@nx/next',
capabilities: 'executors,generators',
},
{
name: '@nx/node',
capabilities: 'executors,generators',
},
{
name: '@nx/nuxt',
capabilities: 'generators',
},
{
name: 'nx',
capabilities: 'executors',
},
{
name: '@nx/plugin',
capabilities: 'executors,generators',
},
{
name: '@nx/react',
capabilities: 'executors,generators',
},
{
name: '@nx/react-native',
capabilities: 'executors,generators',
},
{
name: '@nx/remix',
capabilities: 'executors,generators',
},
{
name: '@nx/rollup',
capabilities: 'executors,generators',
},
{
name: '@nx/storybook',
capabilities: 'executors,generators',
},
{
name: '@nx/vite',
capabilities: 'executors,generators',
},
{
name: '@nx/vue',
capabilities: 'generators',
},
{
name: '@nx/web',
capabilities: 'executors,generators',
},
{
name: '@nx/webpack',
capabilities: 'executors,generators',
},
{
name: '@nx/workspace',
capabilities: 'executors,generators',
},
];

@@ -1,4 +0,4 @@

export { fetchCommunityPlugins } from './community-plugins';
export { fetchCorePlugins, listCorePlugins } from './core-plugins';
export { getInstalledPluginsAndCapabilities, listInstalledPlugins, } from './installed-plugins';
export { getPluginCapabilities, listPluginCapabilities, } from './plugin-capabilities';
export { getInstalledPluginsAndCapabilities } from './installed-plugins';
export { getLocalWorkspacePlugins } from './local-plugins';
export { listPlugins, listAlsoAvailableCorePlugins, listPluginCapabilities, } from './output';
export { getPluginCapabilities } from './plugin-capabilities';
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.listPluginCapabilities = exports.getPluginCapabilities = exports.listInstalledPlugins = exports.getInstalledPluginsAndCapabilities = exports.listCorePlugins = exports.fetchCorePlugins = exports.fetchCommunityPlugins = void 0;
var community_plugins_1 = require("./community-plugins");
Object.defineProperty(exports, "fetchCommunityPlugins", { enumerable: true, get: function () { return community_plugins_1.fetchCommunityPlugins; } });
var core_plugins_1 = require("./core-plugins");
Object.defineProperty(exports, "fetchCorePlugins", { enumerable: true, get: function () { return core_plugins_1.fetchCorePlugins; } });
Object.defineProperty(exports, "listCorePlugins", { enumerable: true, get: function () { return core_plugins_1.listCorePlugins; } });
exports.getPluginCapabilities = exports.listPluginCapabilities = exports.listAlsoAvailableCorePlugins = exports.listPlugins = exports.getLocalWorkspacePlugins = exports.getInstalledPluginsAndCapabilities = void 0;
var installed_plugins_1 = require("./installed-plugins");
Object.defineProperty(exports, "getInstalledPluginsAndCapabilities", { enumerable: true, get: function () { return installed_plugins_1.getInstalledPluginsAndCapabilities; } });
Object.defineProperty(exports, "listInstalledPlugins", { enumerable: true, get: function () { return installed_plugins_1.listInstalledPlugins; } });
var local_plugins_1 = require("./local-plugins");
Object.defineProperty(exports, "getLocalWorkspacePlugins", { enumerable: true, get: function () { return local_plugins_1.getLocalWorkspacePlugins; } });
var output_1 = require("./output");
Object.defineProperty(exports, "listPlugins", { enumerable: true, get: function () { return output_1.listPlugins; } });
Object.defineProperty(exports, "listAlsoAvailableCorePlugins", { enumerable: true, get: function () { return output_1.listAlsoAvailableCorePlugins; } });
Object.defineProperty(exports, "listPluginCapabilities", { enumerable: true, get: function () { return output_1.listPluginCapabilities; } });
var plugin_capabilities_1 = require("./plugin-capabilities");
Object.defineProperty(exports, "getPluginCapabilities", { enumerable: true, get: function () { return plugin_capabilities_1.getPluginCapabilities; } });
Object.defineProperty(exports, "listPluginCapabilities", { enumerable: true, get: function () { return plugin_capabilities_1.listPluginCapabilities; } });

@@ -1,6 +0,5 @@

import type { PluginCapabilities } from './models';
import { ProjectConfiguration } from '../../config/workspace-json-project-json';
import { PackageJson } from '../package-json';
import { ProjectConfiguration } from '../../config/workspace-json-project-json';
import { PluginCapabilities } from './plugin-capabilities';
export declare function findInstalledPlugins(): PackageJson[];
export declare function getInstalledPluginsAndCapabilities(workspaceRoot: string, projects: Record<string, ProjectConfiguration>): Promise<Map<string, PluginCapabilities>>;
export declare function listInstalledPlugins(installedPlugins: Map<string, PluginCapabilities>): void;

@@ -5,13 +5,9 @@ "use strict";

exports.getInstalledPluginsAndCapabilities = getInstalledPluginsAndCapabilities;
exports.listInstalledPlugins = listInstalledPlugins;
const chalk = require("chalk");
const output_1 = require("../output");
const plugin_capabilities_1 = require("./plugin-capabilities");
const shared_1 = require("./shared");
const path_1 = require("path");
const nx_json_1 = require("../../config/nx-json");
const fileutils_1 = require("../fileutils");
const installation_directory_1 = require("../installation-directory");
const package_json_1 = require("../package-json");
const workspace_root_1 = require("../workspace-root");
const path_1 = require("path");
const nx_json_1 = require("../../config/nx-json");
const installation_directory_1 = require("../installation-directory");
const plugin_capabilities_1 = require("./plugin-capabilities");
function findInstalledPlugins() {

@@ -82,24 +78,1 @@ const packageJsonDeps = getDependenciesFromPackageJson();

}
function listInstalledPlugins(installedPlugins) {
const bodyLines = [];
for (const [, p] of installedPlugins) {
const capabilities = [];
if ((0, shared_1.hasElements)(p.executors)) {
capabilities.push('executors');
}
if ((0, shared_1.hasElements)(p.generators)) {
capabilities.push('generators');
}
if (p.projectGraphExtension) {
capabilities.push('graph-extensions');
}
if (p.projectInference) {
capabilities.push('project-inference');
}
bodyLines.push(`${chalk.bold(p.name)} (${capabilities.join()})`);
}
output_1.output.log({
title: `Installed plugins:`,
bodyLines: bodyLines,
});
}

@@ -1,5 +0,4 @@

import type { PluginCapabilities } from './models';
import { NxJsonConfiguration } from '../../config/nx-json';
import { ProjectsConfigurations } from '../../config/workspace-json-project-json';
import { NxJsonConfiguration } from '../../config/nx-json';
import { PluginCapabilities } from './plugin-capabilities';
export declare function getLocalWorkspacePlugins(projectsConfiguration: ProjectsConfigurations, nxJson: NxJsonConfiguration): Promise<Map<string, PluginCapabilities>>;
export declare function listLocalWorkspacePlugins(installedPlugins: Map<string, PluginCapabilities>): void;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getLocalWorkspacePlugins = getLocalWorkspacePlugins;
exports.listLocalWorkspacePlugins = listLocalWorkspacePlugins;
const chalk = require("chalk");
const output_1 = require("../output");
const shared_1 = require("./shared");
const fs_1 = require("fs");
const path_1 = require("path");
const fileutils_1 = require("../fileutils");
const path_1 = require("path");
const workspace_root_1 = require("../workspace-root");
const fs_1 = require("fs");
const plugin_capabilities_1 = require("./plugin-capabilities");

@@ -35,24 +31,1 @@ async function getLocalWorkspacePlugins(projectsConfiguration, nxJson) {

}
function listLocalWorkspacePlugins(installedPlugins) {
const bodyLines = [];
for (const [, p] of installedPlugins) {
const capabilities = [];
if ((0, shared_1.hasElements)(p.executors)) {
capabilities.push('executors');
}
if ((0, shared_1.hasElements)(p.generators)) {
capabilities.push('generators');
}
if (p.projectGraphExtension) {
capabilities.push('graph-extension');
}
if (p.projectInference) {
capabilities.push('project-inference');
}
bodyLines.push(`${chalk.bold(p.name)} (${capabilities.join()})`);
}
output_1.output.log({
title: `Local workspace plugins:`,
bodyLines: bodyLines,
});
}

@@ -0,4 +1,14 @@

import { ExecutorsJsonEntry, GeneratorsJsonEntry } from '../../config/misc-interfaces';
import { ProjectConfiguration } from '../../config/workspace-json-project-json';
import type { PluginCapabilities } from './models';
export interface PluginCapabilities {
name: string;
executors?: {
[name: string]: ExecutorsJsonEntry;
};
generators?: {
[name: string]: GeneratorsJsonEntry;
};
projectInference?: boolean;
projectGraphExtension?: boolean;
}
export declare function getPluginCapabilities(workspaceRoot: string, pluginName: string, projects: Record<string, ProjectConfiguration>, includeRuntimeCapabilities?: boolean): Promise<PluginCapabilities | null>;
export declare function listPluginCapabilities(pluginName: string, projects: Record<string, ProjectConfiguration>): Promise<void>;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getPluginCapabilities = getPluginCapabilities;
exports.listPluginCapabilities = listPluginCapabilities;
const chalk = require("chalk");
const path_1 = require("path");
const fileutils_1 = require("../fileutils");
const installation_directory_1 = require("../installation-directory");
const plugins_1 = require("../../project-graph/plugins");
const loader_1 = require("../../project-graph/plugins/loader");
const fileutils_1 = require("../fileutils");
const installation_directory_1 = require("../installation-directory");
const output_1 = require("../output");
const package_manager_1 = require("../package-manager");
const workspace_root_1 = require("../workspace-root");
const shared_1 = require("./shared");
function tryGetCollection(packageJsonPath, collectionFile, propName) {

@@ -81,80 +75,1 @@ if (!collectionFile) {

}
async function listPluginCapabilities(pluginName, projects) {
const plugin = await getPluginCapabilities(workspace_root_1.workspaceRoot, pluginName, projects);
if (!plugin) {
const pmc = (0, package_manager_1.getPackageManagerCommand)();
output_1.output.note({
title: `${pluginName} is not currently installed`,
bodyLines: [
`Use "${pmc.addDev} ${pluginName}" to install the plugin.`,
`After that, use "${pmc.exec} nx g ${pluginName}:init" to add the required peer deps and initialize the plugin.`,
],
});
return;
}
const hasBuilders = (0, shared_1.hasElements)(plugin.executors);
const hasGenerators = (0, shared_1.hasElements)(plugin.generators);
const hasProjectGraphExtension = !!plugin.projectGraphExtension;
const hasProjectInference = !!plugin.projectInference;
if (!hasBuilders &&
!hasGenerators &&
!hasProjectGraphExtension &&
!hasProjectInference) {
output_1.output.warn({ title: `No capabilities found in ${pluginName}` });
return;
}
const bodyLines = [];
if (hasGenerators) {
bodyLines.push(chalk.bold(chalk.green('GENERATORS')));
bodyLines.push('');
bodyLines.push(...Object.keys(plugin.generators).map((name) => `${chalk.bold(name)} : ${plugin.generators[name].description}`));
if (hasBuilders) {
bodyLines.push('');
}
}
if (hasBuilders) {
bodyLines.push(chalk.bold(chalk.green('EXECUTORS/BUILDERS')));
bodyLines.push('');
bodyLines.push(...Object.keys(plugin.executors).map((name) => `${chalk.bold(name)} : ${resolveExecutorDescription(pluginName, plugin.executors[name], projects)}`));
}
if (hasProjectGraphExtension) {
bodyLines.push(`✔️ Project Graph Extension`);
}
if (hasProjectInference) {
bodyLines.push(`✔️ Project Inference`);
}
output_1.output.log({
title: `Capabilities in ${plugin.name}:`,
bodyLines,
});
}
function resolveExecutorDescription(pluginName, executorJsonEntry, projects, requirePaths = (0, installation_directory_1.getNxRequirePaths)(workspace_root_1.workspaceRoot)) {
try {
if (typeof executorJsonEntry === 'string') {
// it points to another executor, resolve it
const [pkgName, executor] = executorJsonEntry.split(':');
// read the package.json of the parent plugin
const { path: packageJsonPath } = (0, plugins_1.readPluginPackageJson)(pluginName, projects, requirePaths);
// accumulate the require paths to resolve nested packages
const cummulativeRequirePaths = [
...requirePaths,
(0, path_1.dirname)(packageJsonPath),
];
const collection = loadExecutorsCollection(pkgName, projects, cummulativeRequirePaths);
return resolveExecutorDescription(pkgName, collection[executor], projects, cummulativeRequirePaths);
}
return executorJsonEntry.description;
}
catch {
return 'No description available';
}
}
function loadExecutorsCollection(pluginName, projects, requirePaths) {
const { json: packageJson, path: packageJsonPath } = (0, plugins_1.readPluginPackageJson)(pluginName, projects, requirePaths);
return {
...tryGetCollection(packageJsonPath, packageJson.builders, 'builders'),
...tryGetCollection(packageJsonPath, packageJson.executors, 'builders'),
...tryGetCollection(packageJsonPath, packageJson.builders, 'executors'),
...tryGetCollection(packageJsonPath, packageJson.executors, 'executors'),
};
}

@@ -14,3 +14,4 @@ import type { NxWorkspaceFilesExternals } from '../native';

export declare function hashWithWorkspaceContext(workspaceRoot: string, globs: string[], exclude?: string[]): Promise<string>;
export declare function updateFilesInContext(updatedFiles: string[], deletedFiles: string[]): Record<string, string>;
export declare function updateContextWithChangedFiles(workspaceRoot: string, createdFiles: string[], updatedFiles: string[], deletedFiles: string[]): Promise<void>;
export declare function updateFilesInContext(workspaceRoot: string, updatedFiles: string[], deletedFiles: string[]): Record<string, string>;
export declare function getAllFileDataInContext(workspaceRoot: string): Promise<import("../native").FileData[]>;

@@ -17,0 +18,0 @@ export declare function getFilesInDirectoryUsingContext(workspaceRoot: string, dir: string): Promise<string[]>;

@@ -8,2 +8,3 @@ "use strict";

exports.hashWithWorkspaceContext = hashWithWorkspaceContext;
exports.updateContextWithChangedFiles = updateContextWithChangedFiles;
exports.updateFilesInContext = updateFilesInContext;

@@ -60,3 +61,19 @@ exports.getAllFileDataInContext = getAllFileDataInContext;

}
function updateFilesInContext(updatedFiles, deletedFiles) {
async function updateContextWithChangedFiles(workspaceRoot, createdFiles, updatedFiles, deletedFiles) {
if (!client_1.daemonClient.enabled()) {
updateFilesInContext(workspaceRoot, [...createdFiles, ...updatedFiles], deletedFiles);
}
else if ((0, is_on_daemon_1.isOnDaemon)()) {
// make sure to only import this when running on the daemon
const { addUpdatedAndDeletedFiles } = await Promise.resolve().then(() => require('../daemon/server/project-graph-incremental-recomputation'));
// update files for the incremental graph recomputation on the daemon
addUpdatedAndDeletedFiles(createdFiles, updatedFiles, deletedFiles);
}
else {
// daemon is enabled but we are not running on it, ask the daemon to update the context
await client_1.daemonClient.updateWorkspaceContext(createdFiles, updatedFiles, deletedFiles);
}
}
function updateFilesInContext(workspaceRoot, updatedFiles, deletedFiles) {
ensureContextAvailable(workspaceRoot);
return workspaceContext?.incrementalUpdate(updatedFiles, deletedFiles);

@@ -63,0 +80,0 @@ }

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc