Socket
Socket
Sign inDemoInstall

nx

Package Overview
Dependencies
Maintainers
8
Versions
1357
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 19.5.6 to 19.6.0-beta.0

src/command-line/release/config/deep-merge-json.d.ts

24

package.json
{
"name": "nx",
"version": "19.5.6",
"version": "19.6.0-beta.0",
"private": false,

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

"ora": "5.3.0",
"@nrwl/tao": "19.5.6"
"@nrwl/tao": "19.6.0-beta.0"
},

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

"optionalDependencies": {
"@nx/nx-darwin-x64": "19.5.6",
"@nx/nx-darwin-arm64": "19.5.6",
"@nx/nx-linux-x64-gnu": "19.5.6",
"@nx/nx-linux-x64-musl": "19.5.6",
"@nx/nx-win32-x64-msvc": "19.5.6",
"@nx/nx-linux-arm64-gnu": "19.5.6",
"@nx/nx-linux-arm64-musl": "19.5.6",
"@nx/nx-linux-arm-gnueabihf": "19.5.6",
"@nx/nx-win32-arm64-msvc": "19.5.6",
"@nx/nx-freebsd-x64": "19.5.6"
"@nx/nx-darwin-x64": "19.6.0-beta.0",
"@nx/nx-darwin-arm64": "19.6.0-beta.0",
"@nx/nx-linux-x64-gnu": "19.6.0-beta.0",
"@nx/nx-linux-x64-musl": "19.6.0-beta.0",
"@nx/nx-win32-x64-msvc": "19.6.0-beta.0",
"@nx/nx-linux-arm64-gnu": "19.6.0-beta.0",
"@nx/nx-linux-arm64-musl": "19.6.0-beta.0",
"@nx/nx-linux-arm-gnueabihf": "19.6.0-beta.0",
"@nx/nx-win32-arm64-msvc": "19.6.0-beta.0",
"@nx/nx-freebsd-x64": "19.6.0-beta.0"
},

@@ -102,0 +102,0 @@ "nx-migrations": {

/**
* @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; } });

@@ -400,2 +400,5 @@ {

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

@@ -402,0 +405,0 @@ "type": "boolean",

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"];

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

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

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

'useInferencePlugins',
'neverConnectToCloud',
];

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

@@ -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 @@ }) {

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

// - 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);
}

@@ -59,2 +60,5 @@ return defaultRunner === 'nx/tasks-runners/default';

const nxJson = (0, configuration_1.readNxJson)();
const installationSource = process.env.NX_CONSOLE
? 'nx-console'
: 'nx-connect';
if ((0, nx_cloud_utils_1.isNxCloudUsed)(nxJson)) {

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

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

@@ -79,3 +83,3 @@ title: '✔ This workspace already has Nx Cloud set up',

const token = await connectWorkspaceToCloud({
installationSource: command ?? 'nx-connect',
installationSource: command ?? installationSource,
});

@@ -82,0 +86,0 @@ const connectCloudUrl = await (0, url_shorten_1.createNxCloudOnboardingURL)('nx-connect', token);

@@ -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,247 +32,358 @@ 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.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;
/**
* 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].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);
}
}
}
}
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.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: [],
};
})
.filter(Boolean), nxReleaseConfig.conventionalCommits);
}
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;
let commits = [];
if (releaseGroup.versionPlans) {

@@ -291,4 +403,4 @@ changes = filterHiddenChanges(releaseGroup.versionPlans

isBreaking: parsedMessage.breaking,
affectedProjects: Object.keys(vp.projectVersionBumps),
githubReferences: [],
affectedProjects: '*',
};

@@ -300,24 +412,20 @@ })

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}`);
(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) => ({

@@ -345,3 +453,3 @@ type: c.type,

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

@@ -375,101 +483,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,
};
};

@@ -476,0 +490,0 @@ }

@@ -9,2 +9,3 @@ import { CommandModule } from 'yargs';

verbose?: boolean;
printConfig?: boolean | 'debug';
}

@@ -11,0 +12,0 @@ interface GitCommitAndTagOptions {

@@ -43,2 +43,16 @@ "use strict";

})
// 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) => {

@@ -45,0 +59,0 @@ if (argv.groups && argv.projects) {

@@ -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");

@@ -20,94 +20,107 @@ const fs_extra_1 = require("fs-extra");

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 deep_merge_json_1 = require("./config/deep-merge-json");
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), nxJson.release);
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;
}
};
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',
],
});
process.exit(1);
}
}
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 versionPlanMessage = args.message || (await promptForMessage());
const versionPlanFileContent = (0, generate_version_plan_content_1.generateVersionPlanContent)(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;
}
const versionPlanMessage = args.message || (await promptForMessage());
const versionPlanFileContent = (0, generate_version_plan_content_1.generateVersionPlanContent)(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;
};
}

@@ -114,0 +127,0 @@ async function promptForVersion(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,115 @@ 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',
});
}
// 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);
}
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 {
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.versionPlans.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 +139,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 +220,0 @@ async function promptForPublish() {

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

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

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

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,176 @@ 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);
}
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 = [];
/**
* 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 +246,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 = [

@@ -151,4 +264,3 @@ ...tree.listChanges().map((f) => f.path),

return {
// An overall workspace version cannot be relevant when filtering to independent projects
workspaceVersion: undefined,
workspaceVersion,
projectsVersionData: versionData,

@@ -189,103 +301,5 @@ };

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 +306,0 @@ }

@@ -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 @@ }) {

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

useAgents: boolean;
excludeTaskDependencies: boolean;
}

@@ -23,0 +24,0 @@ export declare function withRunOptions<T>(yargs: Argv<T>): Argv<T & RunOptions>;

@@ -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,3 +148,3 @@ import type { ChangelogRenderOptions } from '../../release/changelog-renderer';

}
interface NxReleaseConfiguration {
export interface NxReleaseConfiguration {
/**

@@ -384,2 +384,7 @@ * Shorthand for amending the projects which will be included in the implicit default release group (all projects by default).

/**
* 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

@@ -409,2 +414,6 @@ * caching and displaying run links.

useInferencePlugins?: boolean;
/**
* Set this to false to disable connection to Nx Cloud
*/
neverConnectToCloud?: boolean;
}

@@ -411,0 +420,0 @@ export type PluginConfiguration = string | ExpandedPluginConfiguration;

@@ -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; } });

@@ -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 @@ }

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

@@ -10,3 +11,4 @@ export interface ConnectToNxCloudOptions {

}
export declare function connectToNxCloud(tree: Tree, schema: ConnectToNxCloudOptions): Promise<string>;
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;

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

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

@@ -45,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)();

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

}
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);
}
return response.data;
}
async function printSuccessMessage(token, installationSource, usesGithub) {

@@ -74,16 +87,30 @@ const connectCloudUrl = await (0, url_shorten_1.createNxCloudOnboardingURL)(installationSource, token, usesGithub);

}
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 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;
});
}
(0, nx_json_1.updateNxJson)(tree, nxJson);
}
async function connectToNxCloud(tree, schema) {
function addNxCloudIdToNxJson(tree, nxCloudId, directory = tree.root) {
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;
});
}
}
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) {

@@ -95,15 +122,29 @@ printCloudConnectionDisabledMessage();

const usesGithub = schema.github ?? (await (0, url_shorten_1.repoUsesGithub)(schema.github));
let responseFromCreateNxCloudWorkspace;
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,
});
return responseFromCreateNxCloudWorkspace.token;
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;
}
}
}
}
exports.default = connectToNxCloud;
async function connectToNxCloudGenerator(tree, options) {
await connectToNxCloud(tree, options);
}
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);

@@ -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 @@ }

@@ -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());

@@ -40,7 +44,10 @@ async function loadRemoteNxPlugin(plugin, root) {

// 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);

@@ -95,2 +102,5 @@ }, rej, socket)));

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

@@ -108,2 +118,5 @@ },

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

@@ -120,2 +133,5 @@ }

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

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

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

@@ -201,3 +220,3 @@ }

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

@@ -207,9 +226,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);
});

@@ -216,0 +238,0 @@ pending.set(tx, {

@@ -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;

@@ -8,0 +9,0 @@ exports.validateProject = validateProject;

@@ -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,

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

// 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');

@@ -343,2 +345,5 @@ }

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

@@ -345,0 +350,0 @@ result.url ??= nxJson.nxCloudUrl;

@@ -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;
}

@@ -104,0 +108,0 @@ function readProjectAndTargetFromTargetString(targetString, projects) {

@@ -32,2 +32,3 @@ import type { Arguments } from 'yargs';

batch?: boolean;
excludeTaskDependencies?: boolean;
}

@@ -34,0 +35,0 @@ export declare function createOverrides(__overrides_unparsed__?: string[]): Record<string, any>;

@@ -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 @@ }

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