nx
Version:
186 lines (185 loc) • 9.15 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.releasePublishCLIHandler = void 0;
exports.createAPI = createAPI;
const nx_json_1 = require("../../config/nx-json");
const file_map_utils_1 = require("../../project-graph/file-map-utils");
const project_graph_1 = require("../../project-graph/project-graph");
const run_command_1 = require("../../tasks-runner/run-command");
const command_line_utils_1 = require("../../utils/command-line-utils");
const handle_errors_1 = require("../../utils/handle-errors");
const output_1 = require("../../utils/output");
const project_graph_utils_1 = require("../../utils/project-graph-utils");
const graph_1 = require("../graph/graph");
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 print_config_1 = require("./utils/print-config");
const workspace_root_1 = require("../../utils/workspace-root");
const tasks_execution_hooks_1 = require("../../project-graph/plugins/tasks-execution-hooks");
const releasePublishCLIHandler = (args) => (0, handle_errors_1.handleErrors)(args.verbose, async () => {
const publishProjectsResult = await createAPI({})(args);
// If all projects are published successfully, return 0, otherwise return 1
return Object.values(publishProjectsResult).every((result) => result.code === 0)
? 0
: 1;
});
exports.releasePublishCLIHandler = releasePublishCLIHandler;
function createAPI(overrideReleaseConfig) {
/**
* 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.
*/
return async function releasePublish(args) {
/**
* 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 ?? {});
// 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, filterLog, 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 (filterLog &&
process.env.NX_RELEASE_INTERNAL_SUPPRESS_FILTER_LOG !== 'true') {
output_1.output.note(filterLog);
}
/**
* 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 overallPublishProjectsResult = {};
if (args.projects?.length) {
/**
* Run publishing for all remaining release groups and filtered projects within them
*/
for (const releaseGroup of releaseGroups) {
const publishProjectsResult = await runPublishOnProjects(_args, projectGraph, nxJson, Array.from(releaseGroupToFilteredProjects.get(releaseGroup)), {
excludeTaskDependencies: shouldExcludeTaskDependencies,
loadDotEnvFiles: process.env.NX_LOAD_DOT_ENV_FILES !== 'false',
});
overallPublishProjectsResult = {
...overallPublishProjectsResult,
...publishProjectsResult,
};
}
return overallPublishProjectsResult;
}
/**
* Run publishing for all remaining release groups
*/
for (const releaseGroup of releaseGroups) {
const publishProjectsResult = await runPublishOnProjects(_args, projectGraph, nxJson, releaseGroup.projects, {
excludeTaskDependencies: shouldExcludeTaskDependencies,
loadDotEnvFiles: process.env.NX_LOAD_DOT_ENV_FILES !== 'false',
});
overallPublishProjectsResult = {
...overallPublishProjectsResult,
...publishProjectsResult,
};
}
return overallPublishProjectsResult;
};
}
async function runPublishOnProjects(args, projectGraph, nxJson, projectNames, extraOptions) {
const projectsToRun = projectNames.map((projectName) => projectGraph.nodes[projectName]);
const overrides = (0, command_line_utils_1.createOverrides)(args.__overrides_unparsed__);
if (args.registry) {
overrides.registry = args.registry;
}
if (args.tag) {
overrides.tag = args.tag;
}
if (args.otp) {
overrides.otp = args.otp;
}
if (args.access) {
overrides.access = args.access;
}
if (args.dryRun) {
overrides.dryRun = args.dryRun;
/**
* Ensure the env var is set too, so that any and all publish executors triggered
* indirectly via dependsOn can also pick up on the fact that this is a dry run.
*/
process.env.NX_DRY_RUN = 'true';
}
if (args.firstRelease) {
overrides.firstRelease = args.firstRelease;
}
const requiredTargetName = 'nx-release-publish';
if (args.graph) {
const file = (0, command_line_utils_1.readGraphFileFromGraphArg)(args);
const projectNamesWithTarget = projectsToRun
.map((t) => t.name)
.filter((projectName) => (0, project_graph_utils_1.projectHasTarget)(projectGraph.nodes[projectName], requiredTargetName));
await (0, graph_1.generateGraph)({
watch: true,
all: false,
open: true,
view: 'tasks',
targets: [requiredTargetName],
projects: projectNamesWithTarget,
file,
}, projectNamesWithTarget);
return {};
}
const projectsWithTarget = projectsToRun.filter((project) => (0, project_graph_utils_1.projectHasTarget)(project, requiredTargetName));
if (projectsWithTarget.length === 0) {
throw new Error(`Based on your config, the following projects were matched for publishing but do not have the "${requiredTargetName}" target specified:\n${[
...projectsToRun.map((p) => `- ${p.name}`),
'',
`This is usually caused by not having an appropriate plugin, such as "@nx/js" installed, which will add the appropriate "${requiredTargetName}" target for you automatically.`,
].join('\n')}\n`);
}
await (0, tasks_execution_hooks_1.runPreTasksExecution)({
workspaceRoot: workspace_root_1.workspaceRoot,
nxJsonConfiguration: nxJson,
});
/**
* Run the relevant nx-release-publish executor on each of the selected projects.
*/
const commandResults = await (0, run_command_1.runCommandForTasks)(projectsWithTarget, projectGraph, { nxJson }, {
targets: [requiredTargetName],
outputStyle: 'static',
...args,
// It is possible for workspaces to have circular dependencies between packages and still release them to a registry
nxIgnoreCycles: true,
}, overrides, null, {}, extraOptions);
const publishProjectsResult = {};
for (const taskData of Object.values(commandResults)) {
publishProjectsResult[taskData.task.target.project] = {
code: taskData.code,
};
}
await (0, tasks_execution_hooks_1.runPostTasksExecution)({
taskResults: commandResults,
workspaceRoot: workspace_root_1.workspaceRoot,
nxJsonConfiguration: nxJson,
});
return publishProjectsResult;
}