cleanup(core): extract "core" folder from "command-line"
This commit is contained in:
parent
b794aa68a9
commit
8749c18f91
@ -4,8 +4,8 @@ import { callRule, runSchematic } from '../utils/testing';
|
|||||||
import { stripIndents } from '@angular-devkit/core/src/utils/literals';
|
import { stripIndents } from '@angular-devkit/core/src/utils/literals';
|
||||||
import { updateJsonInTree } from '@nrwl/workspace/src/utils/ast-utils';
|
import { updateJsonInTree } from '@nrwl/workspace/src/utils/ast-utils';
|
||||||
import { updateWorkspace } from '@nrwl/workspace/src/utils/workspace';
|
import { updateWorkspace } from '@nrwl/workspace/src/utils/workspace';
|
||||||
import { NxJson } from '@nrwl/workspace/src/command-line/shared';
|
|
||||||
import { rulesNodeJSSha, rulesNodeJSVersion } from '../utils/versions';
|
import { rulesNodeJSSha, rulesNodeJSVersion } from '../utils/versions';
|
||||||
|
import { NxJson } from '@nrwl/workspace/src/core/shared-interfaces';
|
||||||
|
|
||||||
describe('@nrwl/bazel:sync', () => {
|
describe('@nrwl/bazel:sync', () => {
|
||||||
let tree: Tree;
|
let tree: Tree;
|
||||||
|
|||||||
@ -21,7 +21,7 @@ import { join, normalize } from '@angular-devkit/core';
|
|||||||
import {
|
import {
|
||||||
ProjectGraph,
|
ProjectGraph,
|
||||||
ProjectGraphNode
|
ProjectGraphNode
|
||||||
} from '@nrwl/workspace/src/command-line/project-graph';
|
} from '@nrwl/workspace/src/core/project-graph';
|
||||||
import { rulesNodeJSSha, rulesNodeJSVersion } from '../utils/versions';
|
import { rulesNodeJSSha, rulesNodeJSVersion } from '../utils/versions';
|
||||||
import { TargetDefinition } from '@angular-devkit/core/src/workspace';
|
import { TargetDefinition } from '@angular-devkit/core/src/workspace';
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
// we can import from '@nrwl/workspace' because it will require typescript
|
// we can import from '@nrwl/workspace' because it will require typescript
|
||||||
import { output } from '@nrwl/workspace/src/command-line/output';
|
import { output } from '@nrwl/workspace/src/utils/output';
|
||||||
import { execSync } from 'child_process';
|
import { execSync } from 'child_process';
|
||||||
import { writeFileSync } from 'fs';
|
import { writeFileSync } from 'fs';
|
||||||
import * as inquirer from 'inquirer';
|
import * as inquirer from 'inquirer';
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
import {
|
|
||||||
readWorkspaceJson,
|
|
||||||
readNxJson,
|
|
||||||
normalizedProjectRoot
|
|
||||||
} from '@nrwl/workspace/src/command-line/shared';
|
|
||||||
import { appRootPath } from '@nrwl/workspace/src/utils/app-root';
|
import { appRootPath } from '@nrwl/workspace/src/utils/app-root';
|
||||||
import {
|
import {
|
||||||
DepConstraint,
|
DepConstraint,
|
||||||
@ -24,7 +19,12 @@ import {
|
|||||||
createProjectGraph,
|
createProjectGraph,
|
||||||
ProjectGraph,
|
ProjectGraph,
|
||||||
ProjectType
|
ProjectType
|
||||||
} from '@nrwl/workspace/src/command-line/project-graph';
|
} from '@nrwl/workspace/src/core/project-graph';
|
||||||
|
import {
|
||||||
|
normalizedProjectRoot,
|
||||||
|
readNxJson,
|
||||||
|
readWorkspaceJson
|
||||||
|
} from '@nrwl/workspace/src/core/file-utils';
|
||||||
|
|
||||||
type Options = [
|
type Options = [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import {
|
|||||||
DependencyType,
|
DependencyType,
|
||||||
ProjectGraph,
|
ProjectGraph,
|
||||||
ProjectType
|
ProjectType
|
||||||
} from '@nrwl/workspace/src/command-line/project-graph';
|
} from '@nrwl/workspace/src/core/project-graph';
|
||||||
import { extname } from 'path';
|
import { extname } from 'path';
|
||||||
|
|
||||||
describe('Enforce Module Boundaries', () => {
|
describe('Enforce Module Boundaries', () => {
|
||||||
|
|||||||
@ -10,8 +10,8 @@ import {
|
|||||||
DefaultTasksRunnerOptions
|
DefaultTasksRunnerOptions
|
||||||
} from '@nrwl/workspace/src/tasks-runner/default-tasks-runner';
|
} from '@nrwl/workspace/src/tasks-runner/default-tasks-runner';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import { TasksMap } from '@nrwl/workspace/src/command-line/run-tasks/run-command';
|
import { TasksMap } from '@nrwl/workspace/src/tasks-runner/run-command';
|
||||||
import { ProjectGraph } from '@nrwl/workspace/src/command-line/project-graph';
|
import { ProjectGraph } from '@nrwl/workspace/src/core/project-graph';
|
||||||
const axios = require('axios');
|
const axios = require('axios');
|
||||||
|
|
||||||
interface InsightsTaskRunnerOptions extends DefaultTasksRunnerOptions {
|
interface InsightsTaskRunnerOptions extends DefaultTasksRunnerOptions {
|
||||||
|
|||||||
@ -19,16 +19,13 @@ export {
|
|||||||
ExistingPrettierConfig,
|
ExistingPrettierConfig,
|
||||||
resolveUserExistingPrettierConfig
|
resolveUserExistingPrettierConfig
|
||||||
} from './src/utils/common';
|
} from './src/utils/common';
|
||||||
export { output } from './src/command-line/output';
|
export { output } from './src/utils/output';
|
||||||
export {
|
export {
|
||||||
commandsObject,
|
commandsObject,
|
||||||
supportedNxCommands
|
supportedNxCommands
|
||||||
} from './src/command-line/nx-commands';
|
} from './src/command-line/nx-commands';
|
||||||
export {
|
export { readWorkspaceJson, readNxJson } from './src/core/file-utils';
|
||||||
readWorkspaceJson,
|
export { NxJson } from './src/core/shared-interfaces';
|
||||||
readNxJson,
|
|
||||||
NxJson
|
|
||||||
} from './src/command-line/shared';
|
|
||||||
export {
|
export {
|
||||||
readJsonInTree,
|
readJsonInTree,
|
||||||
updateJsonInTree,
|
updateJsonInTree,
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import {
|
|||||||
import { JsonObject } from '@angular-devkit/core';
|
import { JsonObject } from '@angular-devkit/core';
|
||||||
import { exec } from 'child_process';
|
import { exec } from 'child_process';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { TEN_MEGABYTES } from '../../command-line/shared';
|
import { TEN_MEGABYTES } from '@nrwl/workspace/src/core/file-utils';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
require('dotenv').config();
|
require('dotenv').config();
|
||||||
|
|||||||
145
packages/workspace/src/command-line/affected.ts
Normal file
145
packages/workspace/src/command-line/affected.ts
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
import * as yargs from 'yargs';
|
||||||
|
import { generateGraph } from './dep-graph';
|
||||||
|
import { output } from '../utils/output';
|
||||||
|
import { parseFiles, printArgsWarning } from './shared';
|
||||||
|
import { runCommand } from '../tasks-runner/run-command';
|
||||||
|
import { NxArgs, splitArgsIntoNxArgsAndTargetArgs } from './utils';
|
||||||
|
import { filterAffected } from '../core/affected-project-graph';
|
||||||
|
import {
|
||||||
|
createProjectGraph,
|
||||||
|
ProjectGraphNode,
|
||||||
|
ProjectType,
|
||||||
|
withDeps
|
||||||
|
} from '../core/project-graph';
|
||||||
|
import { calculateFileChanges, readEnvironment } from '../core/file-utils';
|
||||||
|
import { printAffected } from './print-affected';
|
||||||
|
import { projectHasTargetAndConfiguration } from '../utils/project-has-target-and-configuration';
|
||||||
|
|
||||||
|
export function affected(command: string, parsedArgs: yargs.Arguments): void {
|
||||||
|
const { nxArgs, targetArgs } = splitArgsIntoNxArgsAndTargetArgs(parsedArgs);
|
||||||
|
|
||||||
|
const env = readEnvironment(nxArgs.target);
|
||||||
|
const projectGraph = createProjectGraph();
|
||||||
|
const fileChanges = readFileChanges(nxArgs);
|
||||||
|
let affectedGraph = filterAffected(projectGraph, fileChanges);
|
||||||
|
if (parsedArgs.withDeps) {
|
||||||
|
affectedGraph = withDeps(projectGraph, Object.values(affectedGraph.nodes));
|
||||||
|
}
|
||||||
|
const affectedProjects = Object.values(
|
||||||
|
parsedArgs.all ? projectGraph.nodes : affectedGraph.nodes
|
||||||
|
)
|
||||||
|
.filter(n => !parsedArgs.exclude.includes(n.name))
|
||||||
|
.filter(n => !parsedArgs.onlyFailed || !env.workspace.getResult(n.name));
|
||||||
|
|
||||||
|
try {
|
||||||
|
switch (command) {
|
||||||
|
case 'apps':
|
||||||
|
const apps = affectedProjects
|
||||||
|
.filter(p => p.type === ProjectType.app)
|
||||||
|
.map(p => p.name);
|
||||||
|
if (parsedArgs.plain) {
|
||||||
|
console.log(apps.join(' '));
|
||||||
|
} else {
|
||||||
|
printArgsWarning(parsedArgs);
|
||||||
|
if (apps.length) {
|
||||||
|
output.log({
|
||||||
|
title: 'Affected apps:',
|
||||||
|
bodyLines: apps.map(app => `${output.colors.gray('-')} ${app}`)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'libs':
|
||||||
|
const libs = affectedProjects
|
||||||
|
.filter(p => p.type === ProjectType.lib)
|
||||||
|
.map(p => p.name);
|
||||||
|
if (parsedArgs.plain) {
|
||||||
|
console.log(libs.join(' '));
|
||||||
|
} else {
|
||||||
|
printArgsWarning(parsedArgs);
|
||||||
|
if (libs.length) {
|
||||||
|
output.log({
|
||||||
|
title: 'Affected libs:',
|
||||||
|
bodyLines: libs.map(lib => `${output.colors.gray('-')} ${lib}`)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'dep-graph':
|
||||||
|
const projectNames = affectedProjects.map(p => p.name);
|
||||||
|
printArgsWarning(parsedArgs);
|
||||||
|
generateGraph(parsedArgs as any, projectNames);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'print-affected':
|
||||||
|
if (nxArgs.target) {
|
||||||
|
const projectWithTargetAndConfig = allProjectsWithTargetAndConfiguration(
|
||||||
|
affectedProjects,
|
||||||
|
nxArgs
|
||||||
|
);
|
||||||
|
printAffected(
|
||||||
|
projectWithTargetAndConfig,
|
||||||
|
affectedProjects,
|
||||||
|
projectGraph,
|
||||||
|
nxArgs,
|
||||||
|
targetArgs
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
printAffected([], affectedProjects, projectGraph, nxArgs, targetArgs);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'affected': {
|
||||||
|
const projectWithTargetAndConfig = allProjectsWithTargetAndConfiguration(
|
||||||
|
affectedProjects,
|
||||||
|
nxArgs
|
||||||
|
);
|
||||||
|
printArgsWarning(parsedArgs);
|
||||||
|
runCommand(
|
||||||
|
projectWithTargetAndConfig,
|
||||||
|
projectGraph,
|
||||||
|
env,
|
||||||
|
nxArgs,
|
||||||
|
targetArgs
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
printError(e, parsedArgs.verbose);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function readFileChanges(nxArgs: NxArgs) {
|
||||||
|
// Do we still need this `--all` option?
|
||||||
|
if (nxArgs.all) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const files = parseFiles(nxArgs).files;
|
||||||
|
return calculateFileChanges(files, nxArgs.base, nxArgs.head);
|
||||||
|
}
|
||||||
|
|
||||||
|
function allProjectsWithTargetAndConfiguration(
|
||||||
|
projects: ProjectGraphNode[],
|
||||||
|
nxArgs: NxArgs
|
||||||
|
) {
|
||||||
|
return projects.filter(p =>
|
||||||
|
projectHasTargetAndConfiguration(p, nxArgs.target, nxArgs.configuration)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function printError(e: any, verbose?: boolean) {
|
||||||
|
const bodyLines = [e.message];
|
||||||
|
if (verbose && e.stack) {
|
||||||
|
bodyLines.push('');
|
||||||
|
bodyLines.push(e.stack);
|
||||||
|
}
|
||||||
|
output.error({
|
||||||
|
title: 'There was a critical error when running your command',
|
||||||
|
bodyLines
|
||||||
|
});
|
||||||
|
}
|
||||||
@ -5,8 +5,8 @@ import {
|
|||||||
createProjectGraph,
|
createProjectGraph,
|
||||||
ProjectGraph,
|
ProjectGraph,
|
||||||
ProjectGraphNode
|
ProjectGraphNode
|
||||||
} from './project-graph';
|
} from '../core/project-graph';
|
||||||
import { output } from './output';
|
import { output } from '../utils/output';
|
||||||
|
|
||||||
export function generateGraph(
|
export function generateGraph(
|
||||||
args: { file?: string; filter?: string[]; exclude?: string[] },
|
args: { file?: string; filter?: string[]; exclude?: string[] },
|
||||||
|
|||||||
@ -2,16 +2,13 @@ import { execSync } from 'child_process';
|
|||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as resolve from 'resolve';
|
import * as resolve from 'resolve';
|
||||||
import { getProjectRoots, parseFiles, printArgsWarning } from './shared';
|
import { getProjectRoots, parseFiles, printArgsWarning } from './shared';
|
||||||
import { YargsAffectedOptions } from './run-tasks/affected';
|
|
||||||
import { fileExists } from '../utils/fileutils';
|
import { fileExists } from '../utils/fileutils';
|
||||||
import { output } from './output';
|
import { output } from '../utils/output';
|
||||||
import { createProjectGraph } from './project-graph';
|
import { createProjectGraph } from '../core/project-graph';
|
||||||
import { filterAffected } from './affected-project-graph';
|
import { filterAffected } from '../core/affected-project-graph';
|
||||||
import { calculateFileChanges } from './file-utils';
|
import { calculateFileChanges } from '../core/file-utils';
|
||||||
|
import * as yargs from 'yargs';
|
||||||
export interface YargsFormatOptions extends YargsAffectedOptions {
|
import { NxArgs } from './utils';
|
||||||
libsAndApps?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
const PRETTIER_EXTENSIONS = [
|
const PRETTIER_EXTENSIONS = [
|
||||||
'ts',
|
'ts',
|
||||||
@ -26,11 +23,11 @@ const PRETTIER_EXTENSIONS = [
|
|||||||
'md'
|
'md'
|
||||||
];
|
];
|
||||||
|
|
||||||
export function format(command: 'check' | 'write', args: YargsFormatOptions) {
|
export function format(command: 'check' | 'write', args: yargs.Arguments) {
|
||||||
let patterns: string[];
|
let patterns: string[];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
patterns = getPatterns(args);
|
patterns = getPatterns(args as any);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
output.error({
|
output.error({
|
||||||
title: e.message,
|
title: e.message,
|
||||||
@ -60,7 +57,7 @@ export function format(command: 'check' | 'write', args: YargsFormatOptions) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPatterns(args: YargsAffectedOptions) {
|
function getPatterns(args: NxArgs & { libsAndApps: boolean; _: string[] }) {
|
||||||
const allFilesPattern = [`"**/*.{${PRETTIER_EXTENSIONS.join(',')}}"`];
|
const allFilesPattern = [`"**/*.{${PRETTIER_EXTENSIONS.join(',')}}"`];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
import { createProjectGraph } from './project-graph';
|
import { createProjectGraph } from '../core/project-graph';
|
||||||
import { WorkspaceIntegrityChecks } from './workspace-integrity-checks';
|
import { WorkspaceIntegrityChecks } from './workspace-integrity-checks';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import { appRootPath } from '../utils/app-root';
|
import { appRootPath } from '../utils/app-root';
|
||||||
import { allFilesInDir } from '../command-line/file-utils';
|
import { allFilesInDir } from '../core/file-utils';
|
||||||
import { output } from './output';
|
import { output } from '../utils/output';
|
||||||
|
|
||||||
export function workspaceLint() {
|
export function workspaceLint() {
|
||||||
const graph = createProjectGraph();
|
const graph = createProjectGraph();
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import {
|
|||||||
readCapabilitiesFromNodeModules
|
readCapabilitiesFromNodeModules
|
||||||
} from '../utils/plugin-utils';
|
} from '../utils/plugin-utils';
|
||||||
import { approvedPlugins } from '../utils/plugins';
|
import { approvedPlugins } from '../utils/plugins';
|
||||||
import { output } from './output';
|
import { output } from '../utils/output';
|
||||||
|
|
||||||
export interface YargsListArgs extends yargs.Arguments, ListArgs {}
|
export interface YargsListArgs extends yargs.Arguments, ListArgs {}
|
||||||
|
|
||||||
|
|||||||
@ -3,13 +3,14 @@ import { execSync } from 'child_process';
|
|||||||
import { platform } from 'os';
|
import { platform } from 'os';
|
||||||
import * as yargs from 'yargs';
|
import * as yargs from 'yargs';
|
||||||
import { nxVersion } from '../utils/versions';
|
import { nxVersion } from '../utils/versions';
|
||||||
import { affected, runMany } from './run-tasks';
|
|
||||||
import { generateGraph } from './dep-graph';
|
import { generateGraph } from './dep-graph';
|
||||||
import { format } from './format';
|
import { format } from './format';
|
||||||
import { workspaceLint } from './lint';
|
import { workspaceLint } from './lint';
|
||||||
import { list } from './list';
|
import { list } from './list';
|
||||||
import { report } from './report';
|
import { report } from './report';
|
||||||
import { workspaceSchematic } from './workspace-schematic';
|
import { workspaceSchematic } from './workspace-schematic';
|
||||||
|
import { affected } from './affected';
|
||||||
|
import { runMany } from '@nrwl/workspace/src/command-line/run-many';
|
||||||
|
|
||||||
const noop = (yargs: yargs.Argv): yargs.Argv => yargs;
|
const noop = (yargs: yargs.Argv): yargs.Argv => yargs;
|
||||||
|
|
||||||
@ -133,7 +134,7 @@ export const commandsObject = yargs
|
|||||||
.command(
|
.command(
|
||||||
'print-affected',
|
'print-affected',
|
||||||
'Graph execution plan',
|
'Graph execution plan',
|
||||||
yargs => withAffectedOptions(yargs),
|
yargs => withAffectedOptions(withPrintAffectedOptions(yargs)),
|
||||||
args =>
|
args =>
|
||||||
affected('print-affected', {
|
affected('print-affected', {
|
||||||
...args
|
...args
|
||||||
@ -225,6 +226,10 @@ function withFormatOptions(yargs: yargs.Argv): yargs.Argv {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function withPrintAffectedOptions(yargs: yargs.Argv): yargs.Argv {
|
||||||
|
return yargs.option('select', { type: 'string' });
|
||||||
|
}
|
||||||
|
|
||||||
function withAffectedOptions(yargs: yargs.Argv): yargs.Argv {
|
function withAffectedOptions(yargs: yargs.Argv): yargs.Argv {
|
||||||
return yargs
|
return yargs
|
||||||
.option('files', {
|
.option('files', {
|
||||||
|
|||||||
@ -1,84 +0,0 @@
|
|||||||
import * as fs from 'fs';
|
|
||||||
import * as path from 'path';
|
|
||||||
|
|
||||||
import { readWorkspaceConfigPath, updateJsonFile } from '../utils/fileutils';
|
|
||||||
|
|
||||||
type Migration = { description: string; run(): void };
|
|
||||||
type MigrationName = { name: string; migration: Migration };
|
|
||||||
|
|
||||||
const allMigrations = fs
|
|
||||||
.readdirSync(path.join(__dirname, '/../../migrations'))
|
|
||||||
.filter(f => f.endsWith('.js') && !f.endsWith('.d.js'))
|
|
||||||
.map(file => ({
|
|
||||||
migration: require(`../../migrations/${file}`).default,
|
|
||||||
name: path.parse(file).name
|
|
||||||
}));
|
|
||||||
|
|
||||||
const latestMigration = readLatestMigration();
|
|
||||||
const migrationsToRun = calculateMigrationsToRun(
|
|
||||||
allMigrations,
|
|
||||||
latestMigration
|
|
||||||
);
|
|
||||||
|
|
||||||
if (migrationsToRun.length === 0) {
|
|
||||||
console.log('No migrations to run');
|
|
||||||
process.exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
printMigrationsNames(latestMigration, migrationsToRun);
|
|
||||||
runMigrations(migrationsToRun);
|
|
||||||
updateLatestMigration();
|
|
||||||
|
|
||||||
console.log('All migrations run successfully');
|
|
||||||
|
|
||||||
function readLatestMigration(): string {
|
|
||||||
const angularCli = readWorkspaceConfigPath();
|
|
||||||
return angularCli.project.latestMigration;
|
|
||||||
}
|
|
||||||
|
|
||||||
function calculateMigrationsToRun(
|
|
||||||
migrations: MigrationName[],
|
|
||||||
latestMigration: string
|
|
||||||
) {
|
|
||||||
const startingWith = latestMigration
|
|
||||||
? migrations.findIndex(item => item.name === latestMigration) + 1
|
|
||||||
: 0;
|
|
||||||
return migrations.slice(startingWith);
|
|
||||||
}
|
|
||||||
|
|
||||||
function printMigrationsNames(
|
|
||||||
latestMigration: string,
|
|
||||||
migrations: MigrationName[]
|
|
||||||
): void {
|
|
||||||
console.log(
|
|
||||||
`Nx will run the following migrations (after ${latestMigration}):`
|
|
||||||
);
|
|
||||||
migrations.forEach(m => {
|
|
||||||
console.log(`- ${m.name}`);
|
|
||||||
});
|
|
||||||
console.log('---------------------------------------------');
|
|
||||||
}
|
|
||||||
|
|
||||||
function runMigrations(migrations: MigrationName[]): void {
|
|
||||||
migrations.forEach(m => {
|
|
||||||
try {
|
|
||||||
console.log(`Running ${m.name}`);
|
|
||||||
console.log(m.migration.description);
|
|
||||||
m.migration.run();
|
|
||||||
console.log('---------------------------------------------');
|
|
||||||
} catch (e) {
|
|
||||||
console.error(`Migration ${m.name} failed`);
|
|
||||||
console.error(e);
|
|
||||||
console.error(`Please run 'git checkout .'`);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateLatestMigration(): void {
|
|
||||||
// we must reread .angular-cli.json because some of the migrations could have modified it
|
|
||||||
updateJsonFile('.angular-cli.json', angularCliJson => {
|
|
||||||
angularCliJson.project.latestMigration =
|
|
||||||
migrationsToRun[migrationsToRun.length - 1].name;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
77
packages/workspace/src/command-line/print-affected.ts
Normal file
77
packages/workspace/src/command-line/print-affected.ts
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
import { ProjectGraph, ProjectGraphNode } from '../core/project-graph';
|
||||||
|
import { Task } from '../tasks-runner/tasks-runner';
|
||||||
|
import { createTask } from '../tasks-runner/run-command';
|
||||||
|
import { basename } from 'path';
|
||||||
|
import { getCommand, getOutputs } from '../tasks-runner/utils';
|
||||||
|
import * as yargs from 'yargs';
|
||||||
|
import { NxArgs } from './utils';
|
||||||
|
import { cliCommand } from '@nrwl/workspace/src/core/file-utils';
|
||||||
|
|
||||||
|
export function printAffected(
|
||||||
|
affectedProjectsWithTargetAndConfig: ProjectGraphNode[],
|
||||||
|
affectedProjects: ProjectGraphNode[],
|
||||||
|
projectGraph: ProjectGraph,
|
||||||
|
nxArgs: NxArgs,
|
||||||
|
targetArgs: yargs.Arguments
|
||||||
|
) {
|
||||||
|
const projectNames = affectedProjects.map(p => p.name);
|
||||||
|
const tasksJson = createTasks(
|
||||||
|
affectedProjectsWithTargetAndConfig,
|
||||||
|
projectGraph,
|
||||||
|
nxArgs,
|
||||||
|
targetArgs
|
||||||
|
);
|
||||||
|
const result = {
|
||||||
|
tasks: tasksJson,
|
||||||
|
projects: projectNames,
|
||||||
|
projectGraph: serializeProjectGraph(projectGraph)
|
||||||
|
};
|
||||||
|
console.log(JSON.stringify(selectPrintAffected(result, null), null, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
function createTasks(
|
||||||
|
affectedProjectsWithTargetAndConfig: ProjectGraphNode[],
|
||||||
|
projectGraph: ProjectGraph,
|
||||||
|
nxArgs: NxArgs,
|
||||||
|
targetArgs: yargs.Arguments
|
||||||
|
) {
|
||||||
|
const tasks: Task[] = affectedProjectsWithTargetAndConfig.map(
|
||||||
|
affectedProject =>
|
||||||
|
createTask({
|
||||||
|
project: affectedProject,
|
||||||
|
target: nxArgs.target,
|
||||||
|
configuration: nxArgs.configuration,
|
||||||
|
overrides: targetArgs
|
||||||
|
})
|
||||||
|
);
|
||||||
|
const cli = cliCommand();
|
||||||
|
const isYarn = basename(process.env.npm_execpath || 'npm').startsWith('yarn');
|
||||||
|
return tasks.map(task => ({
|
||||||
|
id: task.id,
|
||||||
|
overrides: targetArgs,
|
||||||
|
target: task.target,
|
||||||
|
command: `${isYarn ? 'yarn' : 'npm run'} ${getCommand(cli, isYarn, task)}`,
|
||||||
|
outputs: getOutputs(projectGraph.nodes, task)
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
function serializeProjectGraph(projectGraph: ProjectGraph) {
|
||||||
|
const nodes = Object.values(projectGraph.nodes).map(n => n.name);
|
||||||
|
return { nodes, dependencies: projectGraph.dependencies };
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectPrintAffected(result: any, select: string) {
|
||||||
|
if (!select) return result;
|
||||||
|
const parts = select.indexOf('.') > -1 ? select.split('.') : [select];
|
||||||
|
return parts
|
||||||
|
.reduce((m, c) => {
|
||||||
|
if (m[c]) {
|
||||||
|
return m[c];
|
||||||
|
} else {
|
||||||
|
throw new Error(
|
||||||
|
`Cannot select '${select}' in the results of print-affected.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}, result)
|
||||||
|
.join(', ');
|
||||||
|
}
|
||||||
@ -2,7 +2,7 @@ import { terminal } from '@angular-devkit/core';
|
|||||||
import { readFileSync } from 'fs';
|
import { readFileSync } from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import { appRootPath } from '../utils/app-root';
|
import { appRootPath } from '../utils/app-root';
|
||||||
import { output } from './output';
|
import { output } from '../utils/output';
|
||||||
|
|
||||||
export const packagesWeCareAbout = [
|
export const packagesWeCareAbout = [
|
||||||
'@nrwl/angular',
|
'@nrwl/angular',
|
||||||
|
|||||||
86
packages/workspace/src/command-line/run-many.ts
Normal file
86
packages/workspace/src/command-line/run-many.ts
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
import * as yargs from 'yargs';
|
||||||
|
import { runCommand } from '../tasks-runner/run-command';
|
||||||
|
import { splitArgsIntoNxArgsAndTargetArgs, NxArgs } from './utils';
|
||||||
|
import { output } from '../utils/output';
|
||||||
|
import {
|
||||||
|
createProjectGraph,
|
||||||
|
ProjectGraph,
|
||||||
|
ProjectGraphNode,
|
||||||
|
withDeps
|
||||||
|
} from '../core/project-graph';
|
||||||
|
import { readEnvironment } from '../core/file-utils';
|
||||||
|
import { projectHasTargetAndConfiguration } from '../utils/project-has-target-and-configuration';
|
||||||
|
|
||||||
|
export function runMany(parsedArgs: yargs.Arguments): void {
|
||||||
|
const { nxArgs, targetArgs } = splitArgsIntoNxArgsAndTargetArgs(parsedArgs);
|
||||||
|
const env = readEnvironment(nxArgs.target);
|
||||||
|
const projectGraph = createProjectGraph();
|
||||||
|
const projects = projectsToRun(nxArgs, projectGraph);
|
||||||
|
runCommand(projects, projectGraph, env, nxArgs, targetArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
function projectsToRun(nxArgs: NxArgs, projectGraph: ProjectGraph) {
|
||||||
|
const allProjects = Object.values(projectGraph.nodes);
|
||||||
|
if (nxArgs.all) {
|
||||||
|
return runnableForTargetAndConfiguration(
|
||||||
|
allProjects,
|
||||||
|
nxArgs.target,
|
||||||
|
nxArgs.configuration
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
checkForInvalidProjects(nxArgs, allProjects);
|
||||||
|
let selectedProjects = allProjects.filter(
|
||||||
|
p => nxArgs.projects.indexOf(p.name) > -1
|
||||||
|
);
|
||||||
|
if (nxArgs.withDeps) {
|
||||||
|
selectedProjects = Object.values(
|
||||||
|
withDeps(projectGraph, selectedProjects).nodes
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return runnableForTargetAndConfiguration(
|
||||||
|
selectedProjects,
|
||||||
|
nxArgs.target,
|
||||||
|
nxArgs.configuration,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkForInvalidProjects(
|
||||||
|
nxArgs: NxArgs,
|
||||||
|
allProjects: ProjectGraphNode[]
|
||||||
|
) {
|
||||||
|
const invalid = nxArgs.projects.filter(
|
||||||
|
name => !allProjects.find(p => p.name === name)
|
||||||
|
);
|
||||||
|
if (invalid.length !== 0) {
|
||||||
|
throw new Error(`Invalid projects: ${invalid.join(', ')}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function runnableForTargetAndConfiguration(
|
||||||
|
projects: ProjectGraphNode[],
|
||||||
|
target: string,
|
||||||
|
configuration?: string,
|
||||||
|
strict = false
|
||||||
|
): ProjectGraphNode[] {
|
||||||
|
const notRunnable = [];
|
||||||
|
const runnable = [];
|
||||||
|
|
||||||
|
for (let project of projects) {
|
||||||
|
if (projectHasTargetAndConfiguration(project, target, configuration)) {
|
||||||
|
runnable.push(project);
|
||||||
|
} else {
|
||||||
|
notRunnable.push(project);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strict && notRunnable.length) {
|
||||||
|
output.warn({
|
||||||
|
title: `the following do not have configuration for "${target}"`,
|
||||||
|
bodyLines: notRunnable.map(p => '- ' + p)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return runnable;
|
||||||
|
}
|
||||||
@ -1,275 +0,0 @@
|
|||||||
import { basename } from 'path';
|
|
||||||
import * as yargs from 'yargs';
|
|
||||||
import { Task } from '../../tasks-runner/tasks-runner';
|
|
||||||
import { generateGraph } from '../dep-graph';
|
|
||||||
import { output } from '../output';
|
|
||||||
import { cliCommand, parseFiles, printArgsWarning } from '../shared';
|
|
||||||
import { getCommand, getOutputs } from '../../tasks-runner/utils';
|
|
||||||
import { createTask, runCommand } from './run-command';
|
|
||||||
import {
|
|
||||||
Arguments,
|
|
||||||
projectHasTargetAndConfiguration,
|
|
||||||
readEnvironment,
|
|
||||||
splitArgs
|
|
||||||
} from './utils';
|
|
||||||
import { filterAffected } from '../affected-project-graph';
|
|
||||||
import {
|
|
||||||
createProjectGraph,
|
|
||||||
ProjectGraph,
|
|
||||||
ProjectGraphNode,
|
|
||||||
ProjectType,
|
|
||||||
reverse,
|
|
||||||
withDeps
|
|
||||||
} from '../project-graph';
|
|
||||||
import { calculateFileChanges } from '../file-utils';
|
|
||||||
|
|
||||||
export interface YargsAffectedOptions
|
|
||||||
extends yargs.Arguments,
|
|
||||||
AffectedOptions {}
|
|
||||||
|
|
||||||
export interface AffectedOptions {
|
|
||||||
target?: string;
|
|
||||||
configuration?: string;
|
|
||||||
runner?: string;
|
|
||||||
parallel?: boolean;
|
|
||||||
maxParallel?: number;
|
|
||||||
untracked?: boolean;
|
|
||||||
uncommitted?: boolean;
|
|
||||||
all?: boolean;
|
|
||||||
base?: string;
|
|
||||||
head?: string;
|
|
||||||
exclude?: string[];
|
|
||||||
files?: string[];
|
|
||||||
onlyFailed?: boolean;
|
|
||||||
'only-failed'?: boolean;
|
|
||||||
'max-parallel'?: boolean;
|
|
||||||
verbose?: boolean;
|
|
||||||
help?: boolean;
|
|
||||||
version?: boolean;
|
|
||||||
quiet?: boolean;
|
|
||||||
plain?: boolean;
|
|
||||||
withDeps?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function affected(
|
|
||||||
command: string,
|
|
||||||
parsedArgs: YargsAffectedOptions
|
|
||||||
): void {
|
|
||||||
const env = readEnvironment(parsedArgs.target);
|
|
||||||
const projectGraph = createProjectGraph();
|
|
||||||
|
|
||||||
const fileChanges = readFileChanges(parsedArgs);
|
|
||||||
let affectedGraph = filterAffected(projectGraph, fileChanges);
|
|
||||||
if (parsedArgs.withDeps) {
|
|
||||||
affectedGraph = withDeps(projectGraph, Object.values(affectedGraph.nodes));
|
|
||||||
}
|
|
||||||
|
|
||||||
const projects = Object.values(
|
|
||||||
parsedArgs.all ? projectGraph.nodes : affectedGraph.nodes
|
|
||||||
)
|
|
||||||
.filter(n => !parsedArgs.exclude.includes(n.name))
|
|
||||||
.filter(n => !parsedArgs.onlyFailed || !env.workspace.getResult(n.name));
|
|
||||||
|
|
||||||
try {
|
|
||||||
switch (command) {
|
|
||||||
case 'apps':
|
|
||||||
const apps = projects
|
|
||||||
.filter(p => p.type === ProjectType.app)
|
|
||||||
.map(p => p.name);
|
|
||||||
if (parsedArgs.plain) {
|
|
||||||
console.log(apps.join(' '));
|
|
||||||
} else {
|
|
||||||
printArgsWarning(parsedArgs);
|
|
||||||
if (apps.length) {
|
|
||||||
output.log({
|
|
||||||
title: 'Affected apps:',
|
|
||||||
bodyLines: apps.map(app => `${output.colors.gray('-')} ${app}`)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'libs':
|
|
||||||
const libs = projects
|
|
||||||
.filter(p => p.type === ProjectType.lib)
|
|
||||||
.map(p => p.name);
|
|
||||||
if (parsedArgs.plain) {
|
|
||||||
console.log(libs.join(' '));
|
|
||||||
} else {
|
|
||||||
printArgsWarning(parsedArgs);
|
|
||||||
if (libs.length) {
|
|
||||||
output.log({
|
|
||||||
title: 'Affected libs:',
|
|
||||||
bodyLines: libs.map(lib => `${output.colors.gray('-')} ${lib}`)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'print-affected':
|
|
||||||
if (parsedArgs && parsedArgs.target) {
|
|
||||||
const {
|
|
||||||
args,
|
|
||||||
projectWithTargetAndConfig
|
|
||||||
} = allProjectsWithTargetAndConfiguration(projects, parsedArgs);
|
|
||||||
printAffectedWithTasks(
|
|
||||||
projectWithTargetAndConfig,
|
|
||||||
projects,
|
|
||||||
projectGraph,
|
|
||||||
args
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
printAffectedWithoutTasks(projects, projectGraph);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'dep-graph': {
|
|
||||||
const projectNames = projects.map(p => p.name);
|
|
||||||
printArgsWarning(parsedArgs);
|
|
||||||
generateGraph(parsedArgs as any, projectNames);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'affected': {
|
|
||||||
const {
|
|
||||||
args,
|
|
||||||
projectWithTargetAndConfig
|
|
||||||
} = allProjectsWithTargetAndConfiguration(projects, parsedArgs);
|
|
||||||
printArgsWarning(parsedArgs);
|
|
||||||
|
|
||||||
runCommand(projectWithTargetAndConfig, projectGraph, args, env);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
printError(e, parsedArgs.verbose);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
function readFileChanges(parsedArgs: YargsAffectedOptions) {
|
|
||||||
// Do we still need this `--all` option?
|
|
||||||
if (parsedArgs.all) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
const files = parseFiles(parsedArgs).files;
|
|
||||||
return calculateFileChanges(files, parsedArgs.base, parsedArgs.head);
|
|
||||||
}
|
|
||||||
|
|
||||||
function allProjectsWithTargetAndConfiguration(
|
|
||||||
projects: ProjectGraphNode[],
|
|
||||||
parsedArgs: YargsAffectedOptions
|
|
||||||
) {
|
|
||||||
const args = splitArgs(parsedArgs, nxSpecificFlags);
|
|
||||||
const projectWithTargetAndConfig = projects.filter(p =>
|
|
||||||
projectHasTargetAndConfiguration(
|
|
||||||
p,
|
|
||||||
args.nxArgs.target,
|
|
||||||
args.nxArgs.configuration
|
|
||||||
)
|
|
||||||
);
|
|
||||||
return { args, projectWithTargetAndConfig };
|
|
||||||
}
|
|
||||||
|
|
||||||
function printError(e: any, verbose?: boolean) {
|
|
||||||
const bodyLines = [e.message];
|
|
||||||
if (verbose && e.stack) {
|
|
||||||
bodyLines.push('');
|
|
||||||
bodyLines.push(e.stack);
|
|
||||||
}
|
|
||||||
output.error({
|
|
||||||
title: 'There was a critical error when running your command',
|
|
||||||
bodyLines
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function printAffectedWithTasks(
|
|
||||||
affectedProjectsWithTargetAndConfig: ProjectGraphNode[],
|
|
||||||
affectedProjects: ProjectGraphNode[],
|
|
||||||
projectGraph: ProjectGraph,
|
|
||||||
args: Arguments<YargsAffectedOptions>
|
|
||||||
) {
|
|
||||||
const tasks: Task[] = affectedProjectsWithTargetAndConfig.map(
|
|
||||||
affectedProject =>
|
|
||||||
createTask({
|
|
||||||
project: affectedProject,
|
|
||||||
target: args.nxArgs.target,
|
|
||||||
configuration: args.nxArgs.configuration,
|
|
||||||
overrides: args.overrides
|
|
||||||
})
|
|
||||||
);
|
|
||||||
const cli = cliCommand();
|
|
||||||
const isYarn = basename(process.env.npm_execpath || 'npm').startsWith('yarn');
|
|
||||||
const projectNames = affectedProjects.map(p => p.name);
|
|
||||||
const tasksJson = tasks.map(task => ({
|
|
||||||
id: task.id,
|
|
||||||
overrides: task.overrides,
|
|
||||||
target: task.target,
|
|
||||||
command: `${isYarn ? 'yarn' : 'npm run'} ${getCommand(cli, isYarn, task)}`,
|
|
||||||
outputs: getOutputs(projectGraph.nodes, task)
|
|
||||||
}));
|
|
||||||
console.log(
|
|
||||||
JSON.stringify(
|
|
||||||
{
|
|
||||||
tasks: tasksJson,
|
|
||||||
projects: projectNames,
|
|
||||||
projectGraph: serializeProjectGraph(projectGraph)
|
|
||||||
},
|
|
||||||
null,
|
|
||||||
2
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function printAffectedWithoutTasks(
|
|
||||||
affectedProjects: ProjectGraphNode[],
|
|
||||||
projectGraph: ProjectGraph
|
|
||||||
) {
|
|
||||||
const projectNames = affectedProjects.map(p => p.name);
|
|
||||||
console.log(
|
|
||||||
JSON.stringify(
|
|
||||||
{
|
|
||||||
tasks: [],
|
|
||||||
projects: projectNames,
|
|
||||||
projectGraph: serializeProjectGraph(projectGraph)
|
|
||||||
},
|
|
||||||
null,
|
|
||||||
2
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function serializeProjectGraph(projectGraph: ProjectGraph) {
|
|
||||||
const nodes = Object.values(projectGraph.nodes).map(n => n.name);
|
|
||||||
return { nodes, dependencies: projectGraph.dependencies };
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* These options are only for getting an array with properties of AffectedOptions.
|
|
||||||
*
|
|
||||||
* @remark They are not defaults or useful for anything else
|
|
||||||
*/
|
|
||||||
const dummyOptions: AffectedOptions = {
|
|
||||||
target: '',
|
|
||||||
configuration: '',
|
|
||||||
onlyFailed: false,
|
|
||||||
'only-failed': false,
|
|
||||||
untracked: false,
|
|
||||||
uncommitted: false,
|
|
||||||
runner: '',
|
|
||||||
help: false,
|
|
||||||
version: false,
|
|
||||||
quiet: false,
|
|
||||||
all: false,
|
|
||||||
base: 'base',
|
|
||||||
head: 'head',
|
|
||||||
exclude: ['exclude'],
|
|
||||||
files: [''],
|
|
||||||
verbose: false,
|
|
||||||
plain: false
|
|
||||||
};
|
|
||||||
|
|
||||||
const nxSpecificFlags = Object.keys(dummyOptions);
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
export * from './run-many';
|
|
||||||
export * from './affected';
|
|
||||||
@ -1,128 +0,0 @@
|
|||||||
import * as yargs from 'yargs';
|
|
||||||
import { runCommand } from './run-command';
|
|
||||||
import {
|
|
||||||
readEnvironment,
|
|
||||||
splitArgs,
|
|
||||||
projectHasTargetAndConfiguration
|
|
||||||
} from './utils';
|
|
||||||
import { output } from '../output';
|
|
||||||
import {
|
|
||||||
createProjectGraph,
|
|
||||||
ProjectGraph,
|
|
||||||
ProjectGraphNode,
|
|
||||||
withDeps
|
|
||||||
} from '../project-graph';
|
|
||||||
|
|
||||||
export type YargsRunManyOptions = yargs.Arguments & RunManyOptions;
|
|
||||||
|
|
||||||
export interface RunManyOptions {
|
|
||||||
target: string;
|
|
||||||
projects: string[];
|
|
||||||
all: boolean;
|
|
||||||
configuration?: string;
|
|
||||||
runner?: string;
|
|
||||||
parallel?: boolean;
|
|
||||||
maxParallel?: number;
|
|
||||||
onlyFailed?: boolean;
|
|
||||||
'only-failed'?: boolean;
|
|
||||||
'max-parallel'?: boolean;
|
|
||||||
verbose?: boolean;
|
|
||||||
help?: boolean;
|
|
||||||
version?: boolean;
|
|
||||||
quiet?: boolean;
|
|
||||||
withDeps?: boolean;
|
|
||||||
'with-deps'?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function runMany(parsedArgs: yargs.Arguments): void {
|
|
||||||
const args = splitArgs(normalize(parsedArgs) as YargsRunManyOptions, flags);
|
|
||||||
const env = readEnvironment(args.nxArgs.target);
|
|
||||||
const projectGraph = createProjectGraph();
|
|
||||||
const projects = projectsToRun(args.nxArgs, projectGraph);
|
|
||||||
runCommand(projects, projectGraph, args, env);
|
|
||||||
}
|
|
||||||
|
|
||||||
function projectsToRun(nxArgs: RunManyOptions, projectGraph: ProjectGraph) {
|
|
||||||
const allProjects = Object.values(projectGraph.nodes);
|
|
||||||
if (nxArgs.all) {
|
|
||||||
return runnableForTargetAndConfiguration(
|
|
||||||
allProjects,
|
|
||||||
nxArgs.target,
|
|
||||||
nxArgs.configuration
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
let selectedProjects = allProjects.filter(
|
|
||||||
p => nxArgs.projects.indexOf(p.name) > -1
|
|
||||||
);
|
|
||||||
if (nxArgs.withDeps) {
|
|
||||||
selectedProjects = Object.values(
|
|
||||||
withDeps(projectGraph, selectedProjects).nodes
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return runnableForTargetAndConfiguration(
|
|
||||||
selectedProjects,
|
|
||||||
nxArgs.target,
|
|
||||||
nxArgs.configuration,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function normalize(args: yargs.Arguments): yargs.Arguments {
|
|
||||||
if (!args.all) {
|
|
||||||
args.all = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!args.projects) {
|
|
||||||
args.projects = [];
|
|
||||||
} else {
|
|
||||||
args.projects = args.projects.split(',').map((p: string) => p.trim());
|
|
||||||
}
|
|
||||||
|
|
||||||
return args;
|
|
||||||
}
|
|
||||||
|
|
||||||
function runnableForTargetAndConfiguration(
|
|
||||||
projects: ProjectGraphNode[],
|
|
||||||
target: string,
|
|
||||||
configuration?: string,
|
|
||||||
strict = false
|
|
||||||
): ProjectGraphNode[] {
|
|
||||||
const notRunnable = [];
|
|
||||||
const runnable = [];
|
|
||||||
|
|
||||||
for (let project of projects) {
|
|
||||||
if (projectHasTargetAndConfiguration(project, target, configuration)) {
|
|
||||||
runnable.push(project);
|
|
||||||
} else {
|
|
||||||
notRunnable.push(project);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strict && notRunnable.length) {
|
|
||||||
output.warn({
|
|
||||||
title: `the following do not have configuration for "${target}"`,
|
|
||||||
bodyLines: notRunnable.map(p => '- ' + p)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return runnable;
|
|
||||||
}
|
|
||||||
|
|
||||||
const dummyOptions: RunManyOptions = {
|
|
||||||
target: '',
|
|
||||||
projects: [],
|
|
||||||
all: false,
|
|
||||||
configuration: '',
|
|
||||||
onlyFailed: false,
|
|
||||||
'only-failed': false,
|
|
||||||
runner: '',
|
|
||||||
help: false,
|
|
||||||
version: false,
|
|
||||||
quiet: false,
|
|
||||||
verbose: false,
|
|
||||||
withDeps: false,
|
|
||||||
'with-deps': false
|
|
||||||
};
|
|
||||||
|
|
||||||
const flags = Object.keys(dummyOptions);
|
|
||||||
@ -1,51 +0,0 @@
|
|||||||
import { splitArgs } from './utils';
|
|
||||||
|
|
||||||
describe('splitArgs', () => {
|
|
||||||
it('should split nx specific arguments into nxArgs', () => {
|
|
||||||
expect(
|
|
||||||
splitArgs(
|
|
||||||
{
|
|
||||||
files: [''],
|
|
||||||
notNxArg: true,
|
|
||||||
_: ['--override'],
|
|
||||||
$0: ''
|
|
||||||
},
|
|
||||||
['files']
|
|
||||||
).nxArgs
|
|
||||||
).toEqual({
|
|
||||||
files: ['']
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should split non nx specific arguments into target args', () => {
|
|
||||||
expect(
|
|
||||||
splitArgs(
|
|
||||||
{
|
|
||||||
files: [''],
|
|
||||||
notNxArg: true,
|
|
||||||
_: ['--override'],
|
|
||||||
$0: ''
|
|
||||||
},
|
|
||||||
['files']
|
|
||||||
).targetArgs
|
|
||||||
).toEqual({
|
|
||||||
notNxArg: true
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should split delimited args into task overrides', () => {
|
|
||||||
expect(
|
|
||||||
splitArgs(
|
|
||||||
{
|
|
||||||
files: [''],
|
|
||||||
notNxArg: true,
|
|
||||||
_: ['', '--override'],
|
|
||||||
$0: ''
|
|
||||||
},
|
|
||||||
['files']
|
|
||||||
).overrides
|
|
||||||
).toEqual({
|
|
||||||
override: true
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,75 +0,0 @@
|
|||||||
import * as yargsParser from 'yargs-parser';
|
|
||||||
import * as yargs from 'yargs';
|
|
||||||
import { NxJson, readNxJson, readWorkspaceJson } from '../shared';
|
|
||||||
import { WorkspaceResults } from '../workspace-results';
|
|
||||||
import { ProjectGraphNode } from '../project-graph';
|
|
||||||
|
|
||||||
export interface Arguments<T extends yargs.Arguments> {
|
|
||||||
nxArgs: T;
|
|
||||||
targetArgs: T;
|
|
||||||
overrides: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ignoreArgs = ['$0', '_'];
|
|
||||||
export function splitArgs<T extends yargs.Arguments>(
|
|
||||||
args: T,
|
|
||||||
nxSpecific: (keyof T)[]
|
|
||||||
): Arguments<T> {
|
|
||||||
const nx: any = {};
|
|
||||||
const targetArgs: any = {};
|
|
||||||
|
|
||||||
const overrides = yargsParser(args._.slice(1));
|
|
||||||
delete overrides._;
|
|
||||||
|
|
||||||
Object.entries(args).forEach(([key, value]) => {
|
|
||||||
if (nxSpecific.includes(key as any)) {
|
|
||||||
nx[key] = value;
|
|
||||||
} else if (!ignoreArgs.includes(key)) {
|
|
||||||
targetArgs[key] = value;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return { nxArgs: nx, targetArgs, overrides };
|
|
||||||
}
|
|
||||||
export interface TaskArgs {
|
|
||||||
projects: string[];
|
|
||||||
target: string;
|
|
||||||
all?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function projectHasTargetAndConfiguration(
|
|
||||||
project: ProjectGraphNode,
|
|
||||||
target: string,
|
|
||||||
configuration?: string
|
|
||||||
) {
|
|
||||||
if (
|
|
||||||
!project.data ||
|
|
||||||
!project.data.architect ||
|
|
||||||
!project.data.architect[target]
|
|
||||||
) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!configuration) {
|
|
||||||
return !!project.data.architect[target];
|
|
||||||
} else {
|
|
||||||
return (
|
|
||||||
project.data.architect[target].configurations &&
|
|
||||||
project.data.architect[target].configurations[configuration]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Environment {
|
|
||||||
nxJson: NxJson;
|
|
||||||
workspaceJson: any;
|
|
||||||
workspace: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function readEnvironment(target: string): Environment {
|
|
||||||
const nxJson = readNxJson();
|
|
||||||
const workspaceJson = readWorkspaceJson();
|
|
||||||
const workspace = new WorkspaceResults(target);
|
|
||||||
|
|
||||||
return { nxJson, workspaceJson, workspace };
|
|
||||||
}
|
|
||||||
@ -1,44 +1,12 @@
|
|||||||
import { execSync } from 'child_process';
|
import { execSync } from 'child_process';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import { appRootPath } from '../utils/app-root';
|
import { output } from '../utils/output';
|
||||||
import { readJsonFile } from '../utils/fileutils';
|
import { createProjectGraph, ProjectGraphNode } from '../core/project-graph';
|
||||||
import { YargsAffectedOptions } from './run-tasks/affected';
|
import { NxArgs } from './utils';
|
||||||
import { output } from './output';
|
import { NxJson } from '../core/shared-interfaces';
|
||||||
import { allFilesInDir, FileData } from './file-utils';
|
import { readWorkspaceJson, TEN_MEGABYTES } from '../core/file-utils';
|
||||||
import {
|
|
||||||
createProjectGraph,
|
|
||||||
ProjectGraphNode,
|
|
||||||
ProjectType
|
|
||||||
} from './project-graph';
|
|
||||||
|
|
||||||
export const TEN_MEGABYTES = 1024 * 10000;
|
export function printArgsWarning(options: NxArgs) {
|
||||||
export type ImplicitDependencyEntry = { [key: string]: '*' | string[] };
|
|
||||||
export type NormalizedImplicitDependencyEntry = { [key: string]: string[] };
|
|
||||||
export type ImplicitDependencies = {
|
|
||||||
files: NormalizedImplicitDependencyEntry;
|
|
||||||
projects: NormalizedImplicitDependencyEntry;
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface NxJson {
|
|
||||||
implicitDependencies?: ImplicitDependencyEntry;
|
|
||||||
npmScope: string;
|
|
||||||
projects: {
|
|
||||||
[projectName: string]: NxJsonProjectConfig;
|
|
||||||
};
|
|
||||||
tasksRunnerOptions?: {
|
|
||||||
[tasksRunnerName: string]: {
|
|
||||||
runner: string;
|
|
||||||
options?: unknown;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface NxJsonProjectConfig {
|
|
||||||
implicitDependencies?: string[];
|
|
||||||
tags?: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export function printArgsWarning(options: YargsAffectedOptions) {
|
|
||||||
const { files, uncommitted, untracked, base, head, all } = options;
|
const { files, uncommitted, untracked, base, head, all } = options;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@ -72,7 +40,7 @@ export function printArgsWarning(options: YargsAffectedOptions) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function parseFiles(options: YargsAffectedOptions): { files: string[] } {
|
export function parseFiles(options: NxArgs): { files: string[] } {
|
||||||
const { files, uncommitted, untracked, base, head } = options;
|
const { files, uncommitted, untracked, base, head } = options;
|
||||||
|
|
||||||
if (files) {
|
if (files) {
|
||||||
@ -147,146 +115,7 @@ function parseGitOutput(command: string): string[] {
|
|||||||
.filter(a => a.length > 0);
|
.filter(a => a.length > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
function detectAndSetInvalidProjectValues(
|
// TODO: remove it in Nx 10
|
||||||
map: Map<string, string[]>,
|
|
||||||
sourceName: string,
|
|
||||||
desiredProjectNames: string[],
|
|
||||||
validProjects: any
|
|
||||||
) {
|
|
||||||
const invalidProjects = desiredProjectNames.filter(
|
|
||||||
projectName => !validProjects[projectName]
|
|
||||||
);
|
|
||||||
if (invalidProjects.length > 0) {
|
|
||||||
map.set(sourceName, invalidProjects);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function assertWorkspaceValidity(workspaceJson, nxJson) {
|
|
||||||
const workspaceJsonProjects = Object.keys(workspaceJson.projects);
|
|
||||||
const nxJsonProjects = Object.keys(nxJson.projects);
|
|
||||||
|
|
||||||
if (minus(workspaceJsonProjects, nxJsonProjects).length > 0) {
|
|
||||||
throw new Error(
|
|
||||||
`${workspaceFileName()} and nx.json are out of sync. The following projects are missing in nx.json: ${minus(
|
|
||||||
workspaceJsonProjects,
|
|
||||||
nxJsonProjects
|
|
||||||
).join(', ')}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (minus(nxJsonProjects, workspaceJsonProjects).length > 0) {
|
|
||||||
throw new Error(
|
|
||||||
`${workspaceFileName()} and nx.json are out of sync. The following projects are missing in ${workspaceFileName()}: ${minus(
|
|
||||||
nxJsonProjects,
|
|
||||||
workspaceJsonProjects
|
|
||||||
).join(', ')}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const projects = {
|
|
||||||
...workspaceJson.projects,
|
|
||||||
...nxJson.projects
|
|
||||||
};
|
|
||||||
|
|
||||||
const invalidImplicitDependencies = new Map<string, string[]>();
|
|
||||||
|
|
||||||
Object.entries<'*' | string[]>(nxJson.implicitDependencies || {})
|
|
||||||
.filter(([_, val]) => val !== '*') // These are valid since it is calculated
|
|
||||||
.reduce((map, [filename, projectNames]: [string, string[]]) => {
|
|
||||||
detectAndSetInvalidProjectValues(map, filename, projectNames, projects);
|
|
||||||
return map;
|
|
||||||
}, invalidImplicitDependencies);
|
|
||||||
|
|
||||||
nxJsonProjects
|
|
||||||
.filter(nxJsonProjectName => {
|
|
||||||
const project = nxJson.projects[nxJsonProjectName];
|
|
||||||
return !!project.implicitDependencies;
|
|
||||||
})
|
|
||||||
.reduce((map, nxJsonProjectName) => {
|
|
||||||
const project = nxJson.projects[nxJsonProjectName];
|
|
||||||
detectAndSetInvalidProjectValues(
|
|
||||||
map,
|
|
||||||
nxJsonProjectName,
|
|
||||||
project.implicitDependencies,
|
|
||||||
projects
|
|
||||||
);
|
|
||||||
return map;
|
|
||||||
}, invalidImplicitDependencies);
|
|
||||||
|
|
||||||
if (invalidImplicitDependencies.size === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let message = `The following implicitDependencies specified in nx.json are invalid:
|
|
||||||
`;
|
|
||||||
invalidImplicitDependencies.forEach((projectNames, key) => {
|
|
||||||
const str = ` ${key}
|
|
||||||
${projectNames.map(projectName => ` ${projectName}`).join('\n')}`;
|
|
||||||
message += str;
|
|
||||||
});
|
|
||||||
|
|
||||||
throw new Error(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
function minus(a: string[], b: string[]): string[] {
|
|
||||||
const res = [];
|
|
||||||
a.forEach(aa => {
|
|
||||||
if (!b.find(bb => bb === aa)) {
|
|
||||||
res.push(aa);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function cliCommand() {
|
|
||||||
return workspaceFileName() === 'angular.json' ? 'ng' : 'nx';
|
|
||||||
}
|
|
||||||
|
|
||||||
export function readWorkspaceJson(): any {
|
|
||||||
return readJsonFile(`${appRootPath}/${workspaceFileName()}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function workspaceFileName() {
|
|
||||||
const packageJson = readPackageJson();
|
|
||||||
if (
|
|
||||||
packageJson.devDependencies['@angular/cli'] ||
|
|
||||||
packageJson.dependencies['@angular/cli']
|
|
||||||
) {
|
|
||||||
return 'angular.json';
|
|
||||||
} else {
|
|
||||||
return 'workspace.json';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function readPackageJson(): any {
|
|
||||||
return readJsonFile(`${appRootPath}/package.json`);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function readNxJson(): NxJson {
|
|
||||||
const config = readJsonFile<NxJson>(`${appRootPath}/nx.json`);
|
|
||||||
if (!config.npmScope) {
|
|
||||||
throw new Error(`nx.json must define the npmScope property.`);
|
|
||||||
}
|
|
||||||
return config;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function readWorkspaceFiles(): FileData[] {
|
|
||||||
const workspaceJson = readWorkspaceJson();
|
|
||||||
const files = [];
|
|
||||||
|
|
||||||
// Add known workspace files and directories
|
|
||||||
files.push(...allFilesInDir(appRootPath, false));
|
|
||||||
files.push(...allFilesInDir(`${appRootPath}/tools`));
|
|
||||||
|
|
||||||
// Add files for workspace projects
|
|
||||||
Object.keys(workspaceJson.projects).forEach(projectName => {
|
|
||||||
const project = workspaceJson.projects[projectName];
|
|
||||||
files.push(...allFilesInDir(`${appRootPath}/${project.root}`));
|
|
||||||
});
|
|
||||||
|
|
||||||
return files;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getProjectNodes(
|
export function getProjectNodes(
|
||||||
workspaceJson: any,
|
workspaceJson: any,
|
||||||
nxJson: NxJson
|
nxJson: NxJson
|
||||||
@ -295,30 +124,7 @@ export function getProjectNodes(
|
|||||||
return Object.values(graph.nodes);
|
return Object.values(graph.nodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function normalizedProjectRoot(p: ProjectGraphNode): string {
|
|
||||||
if (p.data && p.data.root) {
|
|
||||||
return p.data.root
|
|
||||||
.split('/')
|
|
||||||
.filter(v => !!v)
|
|
||||||
.slice(1)
|
|
||||||
.join('/');
|
|
||||||
} else {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getProjectRoots(projectNames: string[]): string[] {
|
export function getProjectRoots(projectNames: string[]): string[] {
|
||||||
const { projects } = readWorkspaceJson();
|
const { projects } = readWorkspaceJson();
|
||||||
return projectNames.map(name => projects[name].root);
|
return projectNames.map(name => projects[name].root);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the time when file was last modified
|
|
||||||
* Returns -Infinity for a non-existent file
|
|
||||||
*/
|
|
||||||
export function mtime(filePath: string): number {
|
|
||||||
if (!fs.existsSync(filePath)) {
|
|
||||||
return -Infinity;
|
|
||||||
}
|
|
||||||
return fs.statSync(filePath).mtimeMs;
|
|
||||||
}
|
|
||||||
|
|||||||
31
packages/workspace/src/command-line/utils.spec.ts
Normal file
31
packages/workspace/src/command-line/utils.spec.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import { splitArgsIntoNxArgsAndTargetArgs } from './utils';
|
||||||
|
|
||||||
|
describe('splitArgs', () => {
|
||||||
|
it('should split nx specific arguments into nxArgs', () => {
|
||||||
|
expect(
|
||||||
|
splitArgsIntoNxArgsAndTargetArgs({
|
||||||
|
files: [''],
|
||||||
|
notNxArg: true,
|
||||||
|
_: ['--override'],
|
||||||
|
$0: ''
|
||||||
|
}).nxArgs
|
||||||
|
).toEqual({
|
||||||
|
projects: [],
|
||||||
|
files: ['']
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should split non nx specific arguments into target args', () => {
|
||||||
|
expect(
|
||||||
|
splitArgsIntoNxArgsAndTargetArgs({
|
||||||
|
files: [''],
|
||||||
|
notNxArg: true,
|
||||||
|
_: ['--override'],
|
||||||
|
$0: ''
|
||||||
|
}).targetArgs
|
||||||
|
).toEqual({
|
||||||
|
notNxArg: true,
|
||||||
|
override: true
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
92
packages/workspace/src/command-line/utils.ts
Normal file
92
packages/workspace/src/command-line/utils.ts
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
import * as yargsParser from 'yargs-parser';
|
||||||
|
import * as yargs from 'yargs';
|
||||||
|
import { WorkspaceResults } from './workspace-results';
|
||||||
|
import { ProjectGraphNode } from '../core/project-graph';
|
||||||
|
import { readWorkspaceJson, readNxJson } from '../core/file-utils';
|
||||||
|
import { NxJson } from '../core/shared-interfaces';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* These options are only for getting an array with properties of AffectedOptions.
|
||||||
|
*
|
||||||
|
* @remark They are not defaults or useful for anything else
|
||||||
|
*/
|
||||||
|
const dummyOptions: NxArgs = {
|
||||||
|
target: '',
|
||||||
|
configuration: '',
|
||||||
|
runner: '',
|
||||||
|
parallel: false,
|
||||||
|
maxParallel: 0,
|
||||||
|
'max-parallel': 0,
|
||||||
|
untracked: false,
|
||||||
|
uncommitted: false,
|
||||||
|
all: false,
|
||||||
|
base: 'base',
|
||||||
|
head: 'head',
|
||||||
|
exclude: ['exclude'],
|
||||||
|
files: [''],
|
||||||
|
onlyFailed: false,
|
||||||
|
'only-failed': false,
|
||||||
|
verbose: false,
|
||||||
|
help: false,
|
||||||
|
version: false,
|
||||||
|
quiet: false,
|
||||||
|
plain: false,
|
||||||
|
withDeps: false,
|
||||||
|
'with-deps': false,
|
||||||
|
projects: []
|
||||||
|
} as any;
|
||||||
|
|
||||||
|
const nxSpecific = Object.keys(dummyOptions);
|
||||||
|
|
||||||
|
export interface NxArgs {
|
||||||
|
target?: string;
|
||||||
|
configuration?: string;
|
||||||
|
runner?: string;
|
||||||
|
parallel?: boolean;
|
||||||
|
maxParallel?: number;
|
||||||
|
'max-parallel'?: number;
|
||||||
|
untracked?: boolean;
|
||||||
|
uncommitted?: boolean;
|
||||||
|
all?: boolean;
|
||||||
|
base?: string;
|
||||||
|
head?: string;
|
||||||
|
exclude?: string[];
|
||||||
|
files?: string[];
|
||||||
|
onlyFailed?: boolean;
|
||||||
|
'only-failed'?: boolean;
|
||||||
|
verbose?: boolean;
|
||||||
|
help?: boolean;
|
||||||
|
version?: boolean;
|
||||||
|
quiet?: boolean;
|
||||||
|
plain?: boolean;
|
||||||
|
withDeps?: boolean;
|
||||||
|
'with-deps'?: boolean;
|
||||||
|
projects?: string[];
|
||||||
|
_: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const ignoreArgs = ['$0', '_'];
|
||||||
|
|
||||||
|
export function splitArgsIntoNxArgsAndTargetArgs(
|
||||||
|
args: yargs.Arguments
|
||||||
|
): { nxArgs: NxArgs; targetArgs: yargs.Arguments } {
|
||||||
|
const nxArgs: any = {};
|
||||||
|
const targetArgs = yargsParser(args._);
|
||||||
|
delete targetArgs._;
|
||||||
|
|
||||||
|
Object.entries(args).forEach(([key, value]) => {
|
||||||
|
if (nxSpecific.includes(key as any)) {
|
||||||
|
nxArgs[key] = value;
|
||||||
|
} else if (!ignoreArgs.includes(key)) {
|
||||||
|
targetArgs[key] = value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!nxArgs.projects) {
|
||||||
|
nxArgs.projects = [];
|
||||||
|
} else {
|
||||||
|
nxArgs.projects = args.projects.split(',').map((p: string) => p.trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
return { nxArgs, targetArgs };
|
||||||
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import { WorkspaceIntegrityChecks } from './workspace-integrity-checks';
|
import { WorkspaceIntegrityChecks } from './workspace-integrity-checks';
|
||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
import { ProjectType, ProjectGraph } from './project-graph';
|
import { ProjectType, ProjectGraph } from '../core/project-graph';
|
||||||
import { extname } from 'path';
|
import { extname } from 'path';
|
||||||
|
|
||||||
describe('WorkspaceIntegrityChecks', () => {
|
describe('WorkspaceIntegrityChecks', () => {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { output, CLIErrorMessageConfig } from './output';
|
import { output, CLIErrorMessageConfig } from '../utils/output';
|
||||||
import { workspaceFileName } from './shared';
|
import { ProjectGraph } from '../core/project-graph';
|
||||||
import { ProjectGraph } from './project-graph';
|
import { workspaceFileName } from '@nrwl/workspace/src/core/file-utils';
|
||||||
|
|
||||||
export class WorkspaceIntegrityChecks {
|
export class WorkspaceIntegrityChecks {
|
||||||
constructor(private projectGraph: ProjectGraph, private files: string[]) {}
|
constructor(private projectGraph: ProjectGraph, private files: string[]) {}
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import * as fs from 'fs';
|
|||||||
import { WorkspaceResults } from './workspace-results';
|
import { WorkspaceResults } from './workspace-results';
|
||||||
import { serializeJson } from '../utils/fileutils';
|
import { serializeJson } from '../utils/fileutils';
|
||||||
import { stripIndents } from '@angular-devkit/core/src/utils/literals';
|
import { stripIndents } from '@angular-devkit/core/src/utils/literals';
|
||||||
import { output } from './output';
|
import { output } from '../utils/output';
|
||||||
|
|
||||||
describe('WorkspacesResults', () => {
|
describe('WorkspacesResults', () => {
|
||||||
let results: WorkspaceResults;
|
let results: WorkspaceResults;
|
||||||
|
|||||||
@ -29,7 +29,7 @@ import * as yargsParser from 'yargs-parser';
|
|||||||
import { appRootPath } from '../utils/app-root';
|
import { appRootPath } from '../utils/app-root';
|
||||||
import { detectPackageManager } from '../utils/detect-package-manager';
|
import { detectPackageManager } from '../utils/detect-package-manager';
|
||||||
import { fileExists, readJsonFile } from '../utils/fileutils';
|
import { fileExists, readJsonFile } from '../utils/fileutils';
|
||||||
import { output } from './output';
|
import { output } from '../utils/output';
|
||||||
|
|
||||||
const rootDirectory = appRootPath;
|
const rootDirectory = appRootPath;
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { NxJson } from '../shared';
|
import { NxJson } from '../shared-interfaces';
|
||||||
|
|
||||||
export interface AffectedProjectGraphContext {
|
export interface AffectedProjectGraphContext {
|
||||||
workspaceJson: any;
|
workspaceJson: any;
|
||||||
@ -4,7 +4,7 @@ import { stripIndents } from '@angular-devkit/core/src/utils/literals';
|
|||||||
import { createProjectGraph } from '../project-graph';
|
import { createProjectGraph } from '../project-graph';
|
||||||
import { filterAffected } from './affected-project-graph';
|
import { filterAffected } from './affected-project-graph';
|
||||||
import { FileData } from '../file-utils';
|
import { FileData } from '../file-utils';
|
||||||
import { NxJson } from '../shared';
|
import { NxJson } from '../shared-interfaces';
|
||||||
|
|
||||||
jest.mock('fs', () => require('memfs').fs);
|
jest.mock('fs', () => require('memfs').fs);
|
||||||
jest.mock('../../utils/app-root', () => ({ appRootPath: '/root' }));
|
jest.mock('../../utils/app-root', () => ({ appRootPath: '/root' }));
|
||||||
@ -1,7 +1,7 @@
|
|||||||
import { ProjectGraph } from '../project-graph';
|
import { ProjectGraph } from '../project-graph';
|
||||||
import { NxJson, readNxJson, readWorkspaceJson } from '../shared';
|
import { FileChange, readNxJson, readWorkspaceJson } from '../file-utils';
|
||||||
import { FileChange } from '../file-utils';
|
|
||||||
import { filterAffectedProjects } from './filter-affected-projects';
|
import { filterAffectedProjects } from './filter-affected-projects';
|
||||||
|
import { NxJson } from '../shared-interfaces';
|
||||||
|
|
||||||
export function filterAffected(
|
export function filterAffected(
|
||||||
graph: ProjectGraph,
|
graph: ProjectGraph,
|
||||||
@ -1,4 +1,4 @@
|
|||||||
import { assertWorkspaceValidity } from './shared';
|
import { assertWorkspaceValidity } from './assert-workspace-validity';
|
||||||
|
|
||||||
describe('assertWorkspaceValidity', () => {
|
describe('assertWorkspaceValidity', () => {
|
||||||
let mockNxJson: any;
|
let mockNxJson: any;
|
||||||
92
packages/workspace/src/core/assert-workspace-validity.ts
Normal file
92
packages/workspace/src/core/assert-workspace-validity.ts
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
import { workspaceFileName } from './file-utils';
|
||||||
|
|
||||||
|
export function assertWorkspaceValidity(workspaceJson, nxJson) {
|
||||||
|
const workspaceJsonProjects = Object.keys(workspaceJson.projects);
|
||||||
|
const nxJsonProjects = Object.keys(nxJson.projects);
|
||||||
|
|
||||||
|
if (minus(workspaceJsonProjects, nxJsonProjects).length > 0) {
|
||||||
|
throw new Error(
|
||||||
|
`${workspaceFileName()} and nx.json are out of sync. The following projects are missing in nx.json: ${minus(
|
||||||
|
workspaceJsonProjects,
|
||||||
|
nxJsonProjects
|
||||||
|
).join(', ')}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (minus(nxJsonProjects, workspaceJsonProjects).length > 0) {
|
||||||
|
throw new Error(
|
||||||
|
`${workspaceFileName()} and nx.json are out of sync. The following projects are missing in ${workspaceFileName()}: ${minus(
|
||||||
|
nxJsonProjects,
|
||||||
|
workspaceJsonProjects
|
||||||
|
).join(', ')}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const projects = {
|
||||||
|
...workspaceJson.projects,
|
||||||
|
...nxJson.projects
|
||||||
|
};
|
||||||
|
|
||||||
|
const invalidImplicitDependencies = new Map<string, string[]>();
|
||||||
|
|
||||||
|
Object.entries<'*' | string[]>(nxJson.implicitDependencies || {})
|
||||||
|
.filter(([_, val]) => val !== '*') // These are valid since it is calculated
|
||||||
|
.reduce((map, [filename, projectNames]: [string, string[]]) => {
|
||||||
|
detectAndSetInvalidProjectValues(map, filename, projectNames, projects);
|
||||||
|
return map;
|
||||||
|
}, invalidImplicitDependencies);
|
||||||
|
|
||||||
|
nxJsonProjects
|
||||||
|
.filter(nxJsonProjectName => {
|
||||||
|
const project = nxJson.projects[nxJsonProjectName];
|
||||||
|
return !!project.implicitDependencies;
|
||||||
|
})
|
||||||
|
.reduce((map, nxJsonProjectName) => {
|
||||||
|
const project = nxJson.projects[nxJsonProjectName];
|
||||||
|
detectAndSetInvalidProjectValues(
|
||||||
|
map,
|
||||||
|
nxJsonProjectName,
|
||||||
|
project.implicitDependencies,
|
||||||
|
projects
|
||||||
|
);
|
||||||
|
return map;
|
||||||
|
}, invalidImplicitDependencies);
|
||||||
|
|
||||||
|
if (invalidImplicitDependencies.size === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let message = `The following implicitDependencies specified in nx.json are invalid:
|
||||||
|
`;
|
||||||
|
invalidImplicitDependencies.forEach((projectNames, key) => {
|
||||||
|
const str = ` ${key}
|
||||||
|
${projectNames.map(projectName => ` ${projectName}`).join('\n')}`;
|
||||||
|
message += str;
|
||||||
|
});
|
||||||
|
|
||||||
|
throw new Error(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
function detectAndSetInvalidProjectValues(
|
||||||
|
map: Map<string, string[]>,
|
||||||
|
sourceName: string,
|
||||||
|
desiredProjectNames: string[],
|
||||||
|
validProjects: any
|
||||||
|
) {
|
||||||
|
const invalidProjects = desiredProjectNames.filter(
|
||||||
|
projectName => !validProjects[projectName]
|
||||||
|
);
|
||||||
|
if (invalidProjects.length > 0) {
|
||||||
|
map.set(sourceName, invalidProjects);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function minus(a: string[], b: string[]): string[] {
|
||||||
|
const res = [];
|
||||||
|
a.forEach(aa => {
|
||||||
|
if (!b.find(bb => bb === aa)) {
|
||||||
|
res.push(aa);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return res;
|
||||||
|
}
|
||||||
@ -2,10 +2,14 @@ import * as path from 'path';
|
|||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import { appRootPath } from '../utils/app-root';
|
import { appRootPath } from '../utils/app-root';
|
||||||
import { extname } from 'path';
|
import { extname } from 'path';
|
||||||
import { mtime } from './shared';
|
|
||||||
import { jsonDiff } from '../utils/json-diff';
|
import { jsonDiff } from '../utils/json-diff';
|
||||||
import { readFileSync } from 'fs';
|
import { readFileSync } from 'fs';
|
||||||
import { execSync } from 'child_process';
|
import { execSync } from 'child_process';
|
||||||
|
import { readJsonFile } from '../utils/fileutils';
|
||||||
|
import { Environment, NxJson } from './shared-interfaces';
|
||||||
|
import { ProjectGraphNode } from './project-graph';
|
||||||
|
import { WorkspaceResults } from '../command-line/workspace-results';
|
||||||
|
|
||||||
const ignore = require('ignore');
|
const ignore = require('ignore');
|
||||||
|
|
||||||
export interface FileData {
|
export interface FileData {
|
||||||
@ -59,7 +63,7 @@ export function calculateFileChanges(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const TEN_MEGABYTES = 1024 * 10000;
|
export const TEN_MEGABYTES = 1024 * 10000;
|
||||||
|
|
||||||
function defaultReadFileAtRevision(
|
function defaultReadFileAtRevision(
|
||||||
file: string,
|
file: string,
|
||||||
@ -126,3 +130,83 @@ function getIgnoredGlobs() {
|
|||||||
function readFileIfExisting(path: string) {
|
function readFileIfExisting(path: string) {
|
||||||
return fs.existsSync(path) ? fs.readFileSync(path, 'UTF-8').toString() : '';
|
return fs.existsSync(path) ? fs.readFileSync(path, 'UTF-8').toString() : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function readWorkspaceJson(): any {
|
||||||
|
return readJsonFile(`${appRootPath}/${workspaceFileName()}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function cliCommand() {
|
||||||
|
return workspaceFileName() === 'angular.json' ? 'ng' : 'nx';
|
||||||
|
}
|
||||||
|
|
||||||
|
export function workspaceFileName() {
|
||||||
|
const packageJson = readPackageJson();
|
||||||
|
if (
|
||||||
|
packageJson.devDependencies['@angular/cli'] ||
|
||||||
|
packageJson.dependencies['@angular/cli']
|
||||||
|
) {
|
||||||
|
return 'angular.json';
|
||||||
|
} else {
|
||||||
|
return 'workspace.json';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function readPackageJson(): any {
|
||||||
|
return readJsonFile(`${appRootPath}/package.json`);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function readNxJson(): NxJson {
|
||||||
|
const config = readJsonFile<NxJson>(`${appRootPath}/nx.json`);
|
||||||
|
if (!config.npmScope) {
|
||||||
|
throw new Error(`nx.json must define the npmScope property.`);
|
||||||
|
}
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function readWorkspaceFiles(): FileData[] {
|
||||||
|
const workspaceJson = readWorkspaceJson();
|
||||||
|
const files = [];
|
||||||
|
|
||||||
|
// Add known workspace files and directories
|
||||||
|
files.push(...allFilesInDir(appRootPath, false));
|
||||||
|
files.push(...allFilesInDir(`${appRootPath}/tools`));
|
||||||
|
|
||||||
|
// Add files for workspace projects
|
||||||
|
Object.keys(workspaceJson.projects).forEach(projectName => {
|
||||||
|
const project = workspaceJson.projects[projectName];
|
||||||
|
files.push(...allFilesInDir(`${appRootPath}/${project.root}`));
|
||||||
|
});
|
||||||
|
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function readEnvironment(target: string): Environment {
|
||||||
|
const nxJson = readNxJson();
|
||||||
|
const workspaceJson = readWorkspaceJson();
|
||||||
|
const workspace = new WorkspaceResults(target);
|
||||||
|
|
||||||
|
return { nxJson, workspaceJson, workspace };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the time when file was last modified
|
||||||
|
* Returns -Infinity for a non-existent file
|
||||||
|
*/
|
||||||
|
export function mtime(filePath: string): number {
|
||||||
|
if (!fs.existsSync(filePath)) {
|
||||||
|
return -Infinity;
|
||||||
|
}
|
||||||
|
return fs.statSync(filePath).mtimeMs;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function normalizedProjectRoot(p: ProjectGraphNode): string {
|
||||||
|
if (p.data && p.data.root) {
|
||||||
|
return p.data.root
|
||||||
|
.split('/')
|
||||||
|
.filter(v => !!v)
|
||||||
|
.slice(1)
|
||||||
|
.join('/');
|
||||||
|
} else {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,7 +5,7 @@ import {
|
|||||||
ProjectGraphNodeRecords
|
ProjectGraphNodeRecords
|
||||||
} from '../project-graph-models';
|
} from '../project-graph-models';
|
||||||
import { TypeScriptImportLocator } from './typescript-import-locator';
|
import { TypeScriptImportLocator } from './typescript-import-locator';
|
||||||
import { normalizedProjectRoot } from '../../shared';
|
import { normalizedProjectRoot } from '../../file-utils';
|
||||||
|
|
||||||
export function buildExplicitTypeScriptDependencies(
|
export function buildExplicitTypeScriptDependencies(
|
||||||
ctx: ProjectGraphContext,
|
ctx: ProjectGraphContext,
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import { NxJson } from '../shared';
|
|
||||||
import { FileMap } from '../file-graph';
|
import { FileMap } from '../file-graph';
|
||||||
import { FileData } from '../file-utils';
|
import { FileData } from '../file-utils';
|
||||||
|
import { NxJson } from '../shared-interfaces';
|
||||||
|
|
||||||
export interface ProjectGraph {
|
export interface ProjectGraph {
|
||||||
nodes: Record<string, ProjectGraphNode>;
|
nodes: Record<string, ProjectGraphNode>;
|
||||||
@ -4,7 +4,7 @@ import { stripIndents } from '@angular-devkit/core/src/utils/literals';
|
|||||||
import { createProjectGraph } from './project-graph';
|
import { createProjectGraph } from './project-graph';
|
||||||
import { DependencyType } from './project-graph-models';
|
import { DependencyType } from './project-graph-models';
|
||||||
import { FileData } from '../file-utils';
|
import { FileData } from '../file-utils';
|
||||||
import { NxJson } from '../shared';
|
import { NxJson } from '../shared-interfaces';
|
||||||
|
|
||||||
jest.mock('fs', () => require('memfs').fs);
|
jest.mock('fs', () => require('memfs').fs);
|
||||||
jest.mock('../../utils/app-root', () => ({ appRootPath: '/root' }));
|
jest.mock('../../utils/app-root', () => ({ appRootPath: '/root' }));
|
||||||
@ -1,13 +1,6 @@
|
|||||||
import { mkdirSync, readFileSync } from 'fs';
|
import { mkdirSync, readFileSync } from 'fs';
|
||||||
import { ProjectGraph, ProjectGraphContext } from './project-graph-models';
|
import { ProjectGraph, ProjectGraphContext } from './project-graph-models';
|
||||||
import { ProjectGraphBuilder } from './project-graph-builder';
|
import { ProjectGraphBuilder } from './project-graph-builder';
|
||||||
import {
|
|
||||||
assertWorkspaceValidity,
|
|
||||||
mtime,
|
|
||||||
readNxJson,
|
|
||||||
readWorkspaceFiles,
|
|
||||||
readWorkspaceJson
|
|
||||||
} from '../shared';
|
|
||||||
import { appRootPath } from '../../utils/app-root';
|
import { appRootPath } from '../../utils/app-root';
|
||||||
import {
|
import {
|
||||||
directoryExists,
|
directoryExists,
|
||||||
@ -15,7 +8,13 @@ import {
|
|||||||
readJsonFile,
|
readJsonFile,
|
||||||
writeJsonFile
|
writeJsonFile
|
||||||
} from '../../utils/fileutils';
|
} from '../../utils/fileutils';
|
||||||
import { FileData } from '../file-utils';
|
import {
|
||||||
|
FileData,
|
||||||
|
mtime,
|
||||||
|
readNxJson,
|
||||||
|
readWorkspaceFiles,
|
||||||
|
readWorkspaceJson
|
||||||
|
} from '../file-utils';
|
||||||
import { createFileMap, FileMap } from '../file-graph';
|
import { createFileMap, FileMap } from '../file-graph';
|
||||||
import { BuildNodes, buildWorkspaceProjectNodes } from './build-nodes';
|
import { BuildNodes, buildWorkspaceProjectNodes } from './build-nodes';
|
||||||
import {
|
import {
|
||||||
@ -23,6 +22,7 @@ import {
|
|||||||
buildExplicitTypeScriptDependencies,
|
buildExplicitTypeScriptDependencies,
|
||||||
buildImplicitProjectDependencies
|
buildImplicitProjectDependencies
|
||||||
} from './build-dependencies';
|
} from './build-dependencies';
|
||||||
|
import { assertWorkspaceValidity } from '../assert-workspace-validity';
|
||||||
|
|
||||||
export function createProjectGraph(
|
export function createProjectGraph(
|
||||||
workspaceJson = readWorkspaceJson(),
|
workspaceJson = readWorkspaceJson(),
|
||||||
26
packages/workspace/src/core/shared-interfaces.ts
Normal file
26
packages/workspace/src/core/shared-interfaces.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
export type ImplicitDependencyEntry = { [key: string]: '*' | string[] };
|
||||||
|
|
||||||
|
export interface NxJson {
|
||||||
|
implicitDependencies?: ImplicitDependencyEntry;
|
||||||
|
npmScope: string;
|
||||||
|
projects: {
|
||||||
|
[projectName: string]: NxJsonProjectConfig;
|
||||||
|
};
|
||||||
|
tasksRunnerOptions?: {
|
||||||
|
[tasksRunnerName: string]: {
|
||||||
|
runner: string;
|
||||||
|
options?: unknown;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NxJsonProjectConfig {
|
||||||
|
implicitDependencies?: string[];
|
||||||
|
tags?: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Environment {
|
||||||
|
nxJson: NxJson;
|
||||||
|
workspaceJson: any;
|
||||||
|
workspace: any;
|
||||||
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
import { output } from '../output';
|
import { output } from '../utils/output';
|
||||||
|
|
||||||
export interface ReporterArgs {
|
export interface ReporterArgs {
|
||||||
target?: string;
|
target?: string;
|
||||||
@ -2,7 +2,7 @@ import defaultTaskRunner from './default-tasks-runner';
|
|||||||
import { AffectedEventType, Task } from './tasks-runner';
|
import { AffectedEventType, Task } from './tasks-runner';
|
||||||
jest.mock('npm-run-all', () => jest.fn());
|
jest.mock('npm-run-all', () => jest.fn());
|
||||||
import * as runAll from 'npm-run-all';
|
import * as runAll from 'npm-run-all';
|
||||||
jest.mock('../command-line/shared', () => ({
|
jest.mock('../core/file-utils', () => ({
|
||||||
cliCommand: () => 'nx'
|
cliCommand: () => 'nx'
|
||||||
}));
|
}));
|
||||||
jest.mock('../utils/fileutils', () => ({
|
jest.mock('../utils/fileutils', () => ({
|
||||||
|
|||||||
@ -7,10 +7,10 @@ import {
|
|||||||
TaskCompleteEvent,
|
TaskCompleteEvent,
|
||||||
TasksRunner
|
TasksRunner
|
||||||
} from './tasks-runner';
|
} from './tasks-runner';
|
||||||
import { cliCommand } from '../command-line/shared';
|
import { output } from '../utils/output';
|
||||||
import { output } from '../command-line/output';
|
|
||||||
import { readJsonFile } from '../utils/fileutils';
|
import { readJsonFile } from '../utils/fileutils';
|
||||||
import { getCommand } from './utils';
|
import { getCommand } from './utils';
|
||||||
|
import { cliCommand } from '../core/file-utils';
|
||||||
|
|
||||||
export interface DefaultTasksRunnerOptions {
|
export interface DefaultTasksRunnerOptions {
|
||||||
parallel?: boolean;
|
parallel?: boolean;
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { NxJson } from '../shared';
|
import { TasksRunner } from './tasks-runner';
|
||||||
import { TasksRunner } from '../../tasks-runner/tasks-runner';
|
import defaultTasksRunner from './default-tasks-runner';
|
||||||
import defaultTasksRunner from '../../tasks-runner/default-tasks-runner';
|
|
||||||
import { getRunner } from './run-command';
|
import { getRunner } from './run-command';
|
||||||
|
import { NxJson } from '../core/shared-interfaces';
|
||||||
|
|
||||||
describe('getRunner', () => {
|
describe('getRunner', () => {
|
||||||
let nxJson: NxJson;
|
let nxJson: NxJson;
|
||||||
@ -1,22 +1,18 @@
|
|||||||
import { NxJson } from '../shared';
|
|
||||||
import {
|
import {
|
||||||
AffectedEventType,
|
AffectedEventType,
|
||||||
Task,
|
Task,
|
||||||
TaskCompleteEvent,
|
TaskCompleteEvent,
|
||||||
TasksRunner
|
TasksRunner
|
||||||
} from '../../tasks-runner/tasks-runner';
|
} from './tasks-runner';
|
||||||
import { defaultTasksRunner } from '../../tasks-runner/default-tasks-runner';
|
import { defaultTasksRunner } from './default-tasks-runner';
|
||||||
import { isRelativePath } from '../../utils/fileutils';
|
import { isRelativePath } from '../utils/fileutils';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
import { appRootPath } from '../../utils/app-root';
|
import { appRootPath } from '../utils/app-root';
|
||||||
import { DefaultReporter, ReporterArgs } from './default-reporter';
|
import { DefaultReporter, ReporterArgs } from './default-reporter';
|
||||||
import {
|
|
||||||
Arguments,
|
|
||||||
Environment,
|
|
||||||
projectHasTargetAndConfiguration
|
|
||||||
} from './utils';
|
|
||||||
import * as yargs from 'yargs';
|
import * as yargs from 'yargs';
|
||||||
import { ProjectGraph, ProjectGraphNode } from '../project-graph';
|
import { ProjectGraph, ProjectGraphNode } from '../core/project-graph';
|
||||||
|
import { Environment, NxJson } from '../core/shared-interfaces';
|
||||||
|
import { projectHasTargetAndConfiguration } from '../utils/project-has-target-and-configuration';
|
||||||
|
|
||||||
export interface TasksMap {
|
export interface TasksMap {
|
||||||
[projectName: string]: { [targetName: string]: Task };
|
[projectName: string]: { [targetName: string]: Task };
|
||||||
@ -27,17 +23,18 @@ type RunArgs = yargs.Arguments & ReporterArgs;
|
|||||||
export function runCommand<T extends RunArgs>(
|
export function runCommand<T extends RunArgs>(
|
||||||
projectsToRun: ProjectGraphNode[],
|
projectsToRun: ProjectGraphNode[],
|
||||||
projectGraph: ProjectGraph,
|
projectGraph: ProjectGraph,
|
||||||
{ nxArgs, overrides, targetArgs }: Arguments<T>,
|
{ nxJson, workspace }: Environment,
|
||||||
{ nxJson, workspace }: Environment
|
nxArgs: any,
|
||||||
|
targetArgs: any
|
||||||
) {
|
) {
|
||||||
const reporter = new DefaultReporter();
|
const reporter = new DefaultReporter();
|
||||||
reporter.beforeRun(projectsToRun.map(p => p.name), nxArgs, overrides);
|
reporter.beforeRun(projectsToRun.map(p => p.name), nxArgs, targetArgs);
|
||||||
const tasks: Task[] = projectsToRun.map(project =>
|
const tasks: Task[] = projectsToRun.map(project =>
|
||||||
createTask({
|
createTask({
|
||||||
project,
|
project,
|
||||||
target: nxArgs.target,
|
target: nxArgs.target,
|
||||||
configuration: nxArgs.configuration,
|
configuration: nxArgs.configuration,
|
||||||
overrides: overrides
|
overrides: targetArgs
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -54,7 +51,7 @@ export function runCommand<T extends RunArgs>(
|
|||||||
project: project,
|
project: project,
|
||||||
target: nxArgs.target,
|
target: nxArgs.target,
|
||||||
configuration: nxArgs.configuration,
|
configuration: nxArgs.configuration,
|
||||||
overrides: overrides
|
overrides: targetArgs
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -1,7 +1,7 @@
|
|||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { Target } from '@angular-devkit/architect';
|
import { Target } from '@angular-devkit/architect';
|
||||||
|
|
||||||
import { ProjectGraph } from '../command-line/project-graph';
|
import { ProjectGraph } from '../core/project-graph';
|
||||||
|
|
||||||
export interface Task {
|
export interface Task {
|
||||||
id: string;
|
id: string;
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { Task } from './tasks-runner';
|
import { Task } from './tasks-runner';
|
||||||
import { ProjectGraphNode } from '../command-line/project-graph';
|
import { ProjectGraphNode } from '../core/project-graph';
|
||||||
|
|
||||||
const commonCommands = ['build', 'test', 'lint', 'e2e', 'deploy'];
|
const commonCommands = ['build', 'test', 'lint', 'e2e', 'deploy'];
|
||||||
|
|
||||||
|
|||||||
@ -3,8 +3,8 @@ import * as ts from 'typescript';
|
|||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
|
|
||||||
import { Rule } from './nxEnforceModuleBoundariesRule';
|
import { Rule } from './nxEnforceModuleBoundariesRule';
|
||||||
import { DependencyType, ProjectGraph } from '../command-line/project-graph';
|
import { DependencyType, ProjectGraph } from '../core/project-graph';
|
||||||
import { ProjectType } from '../command-line/project-graph';
|
import { ProjectType } from '../core/project-graph';
|
||||||
import { extname } from 'path';
|
import { extname } from 'path';
|
||||||
|
|
||||||
describe('Enforce Module Boundaries', () => {
|
describe('Enforce Module Boundaries', () => {
|
||||||
|
|||||||
@ -5,12 +5,7 @@ import {
|
|||||||
createProjectGraph,
|
createProjectGraph,
|
||||||
ProjectGraph,
|
ProjectGraph,
|
||||||
ProjectGraphNode
|
ProjectGraphNode
|
||||||
} from '../command-line/project-graph';
|
} from '../core/project-graph';
|
||||||
import {
|
|
||||||
normalizedProjectRoot,
|
|
||||||
readNxJson,
|
|
||||||
readWorkspaceJson
|
|
||||||
} from '../command-line/shared';
|
|
||||||
import { appRootPath } from '../utils/app-root';
|
import { appRootPath } from '../utils/app-root';
|
||||||
import {
|
import {
|
||||||
DepConstraint,
|
DepConstraint,
|
||||||
@ -27,7 +22,12 @@ import {
|
|||||||
onlyLoadChildren
|
onlyLoadChildren
|
||||||
} from '../utils/runtime-lint-utils';
|
} from '../utils/runtime-lint-utils';
|
||||||
import { normalize } from '@angular-devkit/core';
|
import { normalize } from '@angular-devkit/core';
|
||||||
import { ProjectType } from '../command-line/project-graph';
|
import { ProjectType } from '../core/project-graph';
|
||||||
|
import {
|
||||||
|
normalizedProjectRoot,
|
||||||
|
readNxJson,
|
||||||
|
readWorkspaceJson
|
||||||
|
} from '@nrwl/workspace/src/core/file-utils';
|
||||||
|
|
||||||
export class Rule extends Lint.Rules.AbstractRule {
|
export class Rule extends Lint.Rules.AbstractRule {
|
||||||
constructor(
|
constructor(
|
||||||
|
|||||||
@ -11,13 +11,10 @@ import * as stripJsonComments from 'strip-json-comments';
|
|||||||
import { serializeJson } from './fileutils';
|
import { serializeJson } from './fileutils';
|
||||||
import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks';
|
import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks';
|
||||||
import { getWorkspacePath } from './cli-config-utils';
|
import { getWorkspacePath } from './cli-config-utils';
|
||||||
import {
|
import { createProjectGraph, ProjectGraph } from '../core/project-graph';
|
||||||
createProjectGraph,
|
import { FileData } from '../core/file-utils';
|
||||||
ProjectGraph
|
|
||||||
} from '../command-line/project-graph';
|
|
||||||
import { NxJson } from '../command-line/shared';
|
|
||||||
import { FileData } from '../command-line/file-utils';
|
|
||||||
import { extname, join, normalize, Path } from '@angular-devkit/core';
|
import { extname, join, normalize, Path } from '@angular-devkit/core';
|
||||||
|
import { NxJson } from '@nrwl/workspace/src/core/shared-interfaces';
|
||||||
|
|
||||||
function nodesByPosition(first: ts.Node, second: ts.Node): number {
|
function nodesByPosition(first: ts.Node, second: ts.Node): number {
|
||||||
return first.getStart() - second.getStart();
|
return first.getStart() - second.getStart();
|
||||||
@ -42,7 +39,7 @@ function insertAfterLastOccurrence(
|
|||||||
}
|
}
|
||||||
if (!lastItem && fallbackPos == undefined) {
|
if (!lastItem && fallbackPos == undefined) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`tried to insert ${toInsert} as first occurence with no fallback position`
|
`tried to insert ${toInsert} as first occurrence with no fallback position`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const lastItemPosition: number = lastItem ? lastItem.getEnd() : fallbackPos;
|
const lastItemPosition: number = lastItem ? lastItem.getEnd() : fallbackPos;
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { Tree } from '@angular-devkit/schematics';
|
import { Tree } from '@angular-devkit/schematics';
|
||||||
import { readJsonInTree } from './ast-utils';
|
import { readJsonInTree } from './ast-utils';
|
||||||
import { NxJson } from '../command-line/shared';
|
import { NxJson } from '@nrwl/workspace/src/core/shared-interfaces';
|
||||||
|
|
||||||
export function getWorkspacePath(host: Tree) {
|
export function getWorkspacePath(host: Tree) {
|
||||||
const possibleFiles = ['/workspace.json', '/angular.json', '/.angular.json'];
|
const possibleFiles = ['/workspace.json', '/angular.json', '/.angular.json'];
|
||||||
|
|||||||
@ -12,11 +12,6 @@ export interface CLIWarnMessageConfig {
|
|||||||
slug?: string;
|
slug?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CLILogMessageConfig {
|
|
||||||
title: string;
|
|
||||||
bodyLines?: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CLINoteMessageConfig {
|
export interface CLINoteMessageConfig {
|
||||||
title: string;
|
title: string;
|
||||||
bodyLines?: string[];
|
bodyLines?: string[];
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
import { ProjectGraphNode } from '@nrwl/workspace/src/core/project-graph';
|
||||||
|
|
||||||
|
export function projectHasTargetAndConfiguration(
|
||||||
|
project: ProjectGraphNode,
|
||||||
|
target: string,
|
||||||
|
configuration?: string
|
||||||
|
) {
|
||||||
|
if (
|
||||||
|
!project.data ||
|
||||||
|
!project.data.architect ||
|
||||||
|
!project.data.architect[target]
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!configuration) {
|
||||||
|
return !!project.data.architect[target];
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
project.data.architect[target].configurations &&
|
||||||
|
project.data.architect[target].configurations[configuration]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,13 +1,12 @@
|
|||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import { normalizedProjectRoot } from '../command-line/shared';
|
|
||||||
import {
|
import {
|
||||||
DependencyType,
|
DependencyType,
|
||||||
ProjectGraphNode,
|
ProjectGraphNode,
|
||||||
ProjectGraphDependency,
|
ProjectGraphDependency,
|
||||||
ProjectGraph
|
ProjectGraph
|
||||||
} from '../command-line/project-graph';
|
} from '../core/project-graph';
|
||||||
import { normalize } from '@angular-devkit/core';
|
import { normalize } from '@angular-devkit/core';
|
||||||
import { FileData } from '../command-line/file-utils';
|
import { FileData, normalizedProjectRoot } from '../core/file-utils';
|
||||||
|
|
||||||
export type Deps = { [projectName: string]: ProjectGraphDependency[] };
|
export type Deps = { [projectName: string]: ProjectGraphDependency[] };
|
||||||
export type DepConstraint = {
|
export type DepConstraint = {
|
||||||
|
|||||||
@ -1,17 +1,9 @@
|
|||||||
import {
|
import { Tree } from '@angular-devkit/schematics';
|
||||||
Tree,
|
|
||||||
MergeStrategy,
|
|
||||||
DirEntry,
|
|
||||||
FileEntry,
|
|
||||||
FilePredicate,
|
|
||||||
UpdateRecorder,
|
|
||||||
Action
|
|
||||||
} from '@angular-devkit/schematics';
|
|
||||||
import { NxJson } from '../command-line/shared';
|
|
||||||
import {
|
import {
|
||||||
_test_addWorkspaceFile,
|
_test_addWorkspaceFile,
|
||||||
WorkspaceFormat
|
WorkspaceFormat
|
||||||
} from '@angular-devkit/core/src/workspace/core';
|
} from '@angular-devkit/core/src/workspace/core';
|
||||||
|
import { NxJson } from '@nrwl/workspace/src/core/shared-interfaces';
|
||||||
|
|
||||||
export function getFileContent(tree: Tree, path: string): string {
|
export function getFileContent(tree: Tree, path: string): string {
|
||||||
const fileEntry = tree.get(path);
|
const fileEntry = tree.get(path);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user