feat(core): add a variety of usages for nx show (#17073)
This commit is contained in:
parent
f95f8c4b69
commit
5ef9ea68cd
@ -23,6 +23,18 @@ Show all projects in the workspace:
|
||||
nx show projects
|
||||
```
|
||||
|
||||
Show all projects with names starting with "api-". The pattern option is useful to see which projects would be selected by run-many.:
|
||||
|
||||
```shell
|
||||
nx show projects --pattern=api-*
|
||||
```
|
||||
|
||||
Show all projects with a serve target:
|
||||
|
||||
```shell
|
||||
nx show projects --with-target serve
|
||||
```
|
||||
|
||||
Show affected projects in the workspace:
|
||||
|
||||
```shell
|
||||
@ -35,6 +47,18 @@ Show affected projects in the workspace, excluding end-to-end projects:
|
||||
nx show projects --affected --exclude *-e2e
|
||||
```
|
||||
|
||||
Show detailed information about "my-app" in a json format.:
|
||||
|
||||
```shell
|
||||
nx show project my-app
|
||||
```
|
||||
|
||||
Show information about "my-app" in a human readable format.:
|
||||
|
||||
```shell
|
||||
nx show project my-app --json false
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
### help
|
||||
@ -43,6 +67,12 @@ Type: `boolean`
|
||||
|
||||
Show help
|
||||
|
||||
### json
|
||||
|
||||
Type: `boolean`
|
||||
|
||||
Output JSON
|
||||
|
||||
### version
|
||||
|
||||
Type: `boolean`
|
||||
@ -97,6 +127,12 @@ Type: `boolean`
|
||||
|
||||
Show help
|
||||
|
||||
##### projects
|
||||
|
||||
Type: `string`
|
||||
|
||||
Show only projects that match a given pattern.
|
||||
|
||||
##### uncommitted
|
||||
|
||||
Type: `boolean`
|
||||
@ -114,3 +150,37 @@ Untracked changes
|
||||
Type: `boolean`
|
||||
|
||||
Show version number
|
||||
|
||||
##### withTarget
|
||||
|
||||
Type: `string`
|
||||
|
||||
Show only projects that have a specific target
|
||||
|
||||
### project
|
||||
|
||||
Show a list of targets in the workspace.
|
||||
|
||||
```shell
|
||||
nx show project <projectName>
|
||||
```
|
||||
|
||||
#### Options
|
||||
|
||||
##### help
|
||||
|
||||
Type: `boolean`
|
||||
|
||||
Show help
|
||||
|
||||
##### projectName
|
||||
|
||||
Type: `string`
|
||||
|
||||
Show targets for the given project
|
||||
|
||||
##### version
|
||||
|
||||
Type: `boolean`
|
||||
|
||||
Show version number
|
||||
|
||||
@ -23,6 +23,18 @@ Show all projects in the workspace:
|
||||
nx show projects
|
||||
```
|
||||
|
||||
Show all projects with names starting with "api-". The pattern option is useful to see which projects would be selected by run-many.:
|
||||
|
||||
```shell
|
||||
nx show projects --pattern=api-*
|
||||
```
|
||||
|
||||
Show all projects with a serve target:
|
||||
|
||||
```shell
|
||||
nx show projects --with-target serve
|
||||
```
|
||||
|
||||
Show affected projects in the workspace:
|
||||
|
||||
```shell
|
||||
@ -35,6 +47,18 @@ Show affected projects in the workspace, excluding end-to-end projects:
|
||||
nx show projects --affected --exclude *-e2e
|
||||
```
|
||||
|
||||
Show detailed information about "my-app" in a json format.:
|
||||
|
||||
```shell
|
||||
nx show project my-app
|
||||
```
|
||||
|
||||
Show information about "my-app" in a human readable format.:
|
||||
|
||||
```shell
|
||||
nx show project my-app --json false
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
### help
|
||||
@ -43,6 +67,12 @@ Type: `boolean`
|
||||
|
||||
Show help
|
||||
|
||||
### json
|
||||
|
||||
Type: `boolean`
|
||||
|
||||
Output JSON
|
||||
|
||||
### version
|
||||
|
||||
Type: `boolean`
|
||||
@ -97,6 +127,12 @@ Type: `boolean`
|
||||
|
||||
Show help
|
||||
|
||||
##### projects
|
||||
|
||||
Type: `string`
|
||||
|
||||
Show only projects that match a given pattern.
|
||||
|
||||
##### uncommitted
|
||||
|
||||
Type: `boolean`
|
||||
@ -114,3 +150,37 @@ Untracked changes
|
||||
Type: `boolean`
|
||||
|
||||
Show version number
|
||||
|
||||
##### withTarget
|
||||
|
||||
Type: `string`
|
||||
|
||||
Show only projects that have a specific target
|
||||
|
||||
### project
|
||||
|
||||
Show a list of targets in the workspace.
|
||||
|
||||
```shell
|
||||
nx show project <projectName>
|
||||
```
|
||||
|
||||
#### Options
|
||||
|
||||
##### help
|
||||
|
||||
Type: `boolean`
|
||||
|
||||
Show help
|
||||
|
||||
##### projectName
|
||||
|
||||
Type: `string`
|
||||
|
||||
Show targets for the given project
|
||||
|
||||
##### version
|
||||
|
||||
Type: `boolean`
|
||||
|
||||
Show version number
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import type { NxJsonConfiguration } from '@nx/devkit';
|
||||
import type { NxJsonConfiguration, ProjectConfiguration } from '@nx/devkit';
|
||||
import {
|
||||
cleanupProject,
|
||||
createNonNxProjectDirectory,
|
||||
@ -37,7 +37,7 @@ describe('Nx Commands', () => {
|
||||
runCLI('show projects').replace(/.*nx show projects( --verbose)?\n/, '')
|
||||
).toEqual('');
|
||||
|
||||
runCLI(`generate @nx/web:app ${app1}`);
|
||||
runCLI(`generate @nx/web:app ${app1} --tags e2etag`);
|
||||
runCLI(`generate @nx/web:app ${app2}`);
|
||||
|
||||
const s = runCLI('show projects').split('\n');
|
||||
@ -47,6 +47,24 @@ describe('Nx Commands', () => {
|
||||
expect(s).toContain(app2);
|
||||
expect(s).toContain(`${app1}-e2e`);
|
||||
expect(s).toContain(`${app2}-e2e`);
|
||||
|
||||
const withTag = JSON.parse(runCLI('show projects -p tag:e2etag --json'));
|
||||
expect(withTag).toEqual([app1]);
|
||||
|
||||
const withTargets = JSON.parse(
|
||||
runCLI('show projects --with-target e2e --json')
|
||||
);
|
||||
expect(withTargets).toEqual([`${app1}-e2e`, `${app2}-e2e`]);
|
||||
});
|
||||
|
||||
it('should show detailed project info', () => {
|
||||
const app = uniq('myapp');
|
||||
runCLI(`generate @nx/web:app ${app}`);
|
||||
const project: ProjectConfiguration = JSON.parse(
|
||||
runCLI(`show project ${app}`)
|
||||
);
|
||||
expect(project.targets.build).toBeDefined();
|
||||
expect(project.targets.lint).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
3
nx.json
3
nx.json
@ -193,6 +193,5 @@
|
||||
"build-storybook": {
|
||||
"inputs": ["default", "^production", "{workspaceRoot}/.storybook/**/*"]
|
||||
}
|
||||
},
|
||||
"plugins": ["@monodon/rust"]
|
||||
}
|
||||
}
|
||||
|
||||
@ -345,6 +345,17 @@ export const examples: Record<string, Example[]> = {
|
||||
description: 'Show all projects in the workspace',
|
||||
},
|
||||
|
||||
{
|
||||
command: 'show projects --pattern=api-*',
|
||||
description:
|
||||
'Show all projects with names starting with "api-". The pattern option is useful to see which projects would be selected by run-many.',
|
||||
},
|
||||
|
||||
{
|
||||
command: 'show projects --with-target serve',
|
||||
description: 'Show all projects with a serve target',
|
||||
},
|
||||
|
||||
{
|
||||
command: 'show projects --affected',
|
||||
description: 'Show affected projects in the workspace',
|
||||
@ -355,6 +366,17 @@ export const examples: Record<string, Example[]> = {
|
||||
description:
|
||||
'Show affected projects in the workspace, excluding end-to-end projects',
|
||||
},
|
||||
|
||||
{
|
||||
command: 'show project my-app',
|
||||
description: 'Show detailed information about "my-app" in a json format.',
|
||||
},
|
||||
|
||||
{
|
||||
command: 'show project my-app --json false',
|
||||
description:
|
||||
'Show information about "my-app" in a human readable format.',
|
||||
},
|
||||
],
|
||||
watch: [
|
||||
{
|
||||
|
||||
@ -1,35 +1,56 @@
|
||||
import { CommandModule } from 'yargs';
|
||||
import { withAffectedOptions } from '../yargs-utils/shared-options';
|
||||
import { ShowProjectOptions } from './show';
|
||||
import { CommandModule, showHelp } from 'yargs';
|
||||
import { parseCSV, withAffectedOptions } from '../yargs-utils/shared-options';
|
||||
|
||||
export const yargsShowCommand: CommandModule = {
|
||||
export interface NxShowArgs {
|
||||
json?: boolean;
|
||||
}
|
||||
|
||||
export type ShowProjectsOptions = NxShowArgs & {
|
||||
exclude: string;
|
||||
files: string;
|
||||
uncommitted: any;
|
||||
untracked: any;
|
||||
base: string;
|
||||
head: string;
|
||||
affected: boolean;
|
||||
projects: string[];
|
||||
withTarget: string;
|
||||
};
|
||||
|
||||
export type ShowProjectOptions = NxShowArgs & {
|
||||
projectName: string;
|
||||
};
|
||||
|
||||
export const yargsShowCommand: CommandModule<
|
||||
Record<string, unknown>,
|
||||
NxShowArgs
|
||||
> = {
|
||||
command: 'show',
|
||||
describe: 'Show information about the workspace (e.g., list of projects)',
|
||||
builder: (yargs) =>
|
||||
yargs
|
||||
.command(showProjectsCommand)
|
||||
.command(showProjectCommand)
|
||||
.demandCommand()
|
||||
.option('json', {
|
||||
type: 'boolean',
|
||||
description: 'Output JSON',
|
||||
})
|
||||
.example(
|
||||
'$0 show projects',
|
||||
'Show a list of all projects in the workspace'
|
||||
)
|
||||
.example(
|
||||
'$0 show projects --affected',
|
||||
'Show affected projects in the workspace'
|
||||
)
|
||||
.example(
|
||||
'$0 show projects --affected --exclude *-e2e',
|
||||
'Show affected projects in the workspace, excluding end-to-end projects'
|
||||
'$0 show targets',
|
||||
'Show a list of all targets in the workspace'
|
||||
),
|
||||
handler: async (args) => {
|
||||
// Noop, yargs will error if not in a subcommand.
|
||||
showHelp();
|
||||
process.exit(1);
|
||||
},
|
||||
};
|
||||
|
||||
const showProjectsCommand: CommandModule<
|
||||
Record<string, unknown>,
|
||||
ShowProjectOptions
|
||||
> = {
|
||||
const showProjectsCommand: CommandModule<NxShowArgs, ShowProjectsOptions> = {
|
||||
command: 'projects',
|
||||
describe: 'Show a list of projects in the workspace',
|
||||
builder: (yargs) =>
|
||||
@ -38,10 +59,55 @@ const showProjectsCommand: CommandModule<
|
||||
type: 'boolean',
|
||||
description: 'Show only affected projects',
|
||||
})
|
||||
.option('projects', {
|
||||
type: 'string',
|
||||
alias: ['p'],
|
||||
description: 'Show only projects that match a given pattern.',
|
||||
coerce: parseCSV,
|
||||
})
|
||||
.option('withTarget', {
|
||||
type: 'string',
|
||||
alias: ['t'],
|
||||
description: 'Show only projects that have a specific target',
|
||||
})
|
||||
.implies('untracked', 'affected')
|
||||
.implies('uncommitted', 'affected')
|
||||
.implies('files', 'affected')
|
||||
.implies('base', 'affected')
|
||||
.implies('head', 'affected'),
|
||||
.implies('head', 'affected')
|
||||
.example(
|
||||
'$0 show projects --patterns "apps/*"',
|
||||
'Show all projects in the apps directory'
|
||||
)
|
||||
.example(
|
||||
'$0 show projects --patterns "shared-*"',
|
||||
'Show all projects that start with "shared-"'
|
||||
)
|
||||
.example(
|
||||
'$0 show projects --affected',
|
||||
'Show affected projects in the workspace'
|
||||
)
|
||||
.example(
|
||||
'$0 show projects --affected --exclude *-e2e',
|
||||
'Show affected projects in the workspace, excluding end-to-end projects'
|
||||
) as any,
|
||||
handler: (args) => import('./show').then((m) => m.showProjectsHandler(args)),
|
||||
};
|
||||
|
||||
const showProjectCommand: CommandModule<NxShowArgs, ShowProjectOptions> = {
|
||||
command: 'project <projectName>',
|
||||
describe: 'Show a list of targets in the workspace.',
|
||||
builder: (yargs) =>
|
||||
yargs
|
||||
.positional('projectName', {
|
||||
type: 'string',
|
||||
alias: 'p',
|
||||
description: 'Show targets for the given project',
|
||||
})
|
||||
.default('json', true)
|
||||
.example(
|
||||
'$0 show project my-app',
|
||||
'View project information for my-app in JSON format'
|
||||
),
|
||||
handler: (args) => import('./show').then((m) => m.showProjectHandler(args)),
|
||||
};
|
||||
|
||||
@ -10,22 +10,20 @@ import {
|
||||
} from '../../utils/command-line-utils';
|
||||
import { createProjectGraphAsync } from '../../project-graph/project-graph';
|
||||
import { NxJsonConfiguration } from '../../config/nx-json';
|
||||
import { ProjectGraph } from '../../config/project-graph';
|
||||
import {
|
||||
ProjectGraph,
|
||||
ProjectGraphProjectNode,
|
||||
} from '../../config/project-graph';
|
||||
import { findMatchingProjects } from '../../utils/find-matching-projects';
|
||||
import { fileHasher } from '../../hasher/impl';
|
||||
|
||||
export type ShowProjectOptions = {
|
||||
exclude: string;
|
||||
files: string;
|
||||
uncommitted: any;
|
||||
untracked: any;
|
||||
base: string;
|
||||
head: string;
|
||||
affected: boolean;
|
||||
};
|
||||
import {
|
||||
NxShowArgs,
|
||||
ShowProjectsOptions,
|
||||
ShowProjectOptions,
|
||||
} from './command-object';
|
||||
|
||||
export async function showProjectsHandler(
|
||||
args: ShowProjectOptions
|
||||
args: ShowProjectsOptions
|
||||
): Promise<void> {
|
||||
let graph = await createProjectGraphAsync();
|
||||
const nxJson = readNxJson();
|
||||
@ -42,6 +40,19 @@ export async function showProjectsHandler(
|
||||
graph = await getAffectedGraph(nxArgs, nxJson, graph);
|
||||
}
|
||||
|
||||
if (args.projects) {
|
||||
graph.nodes = getGraphNodesMatchingPatterns(graph, args.projects);
|
||||
}
|
||||
|
||||
if (args.withTarget) {
|
||||
graph.nodes = Object.entries(graph.nodes).reduce((acc, [name, node]) => {
|
||||
if (node.data.targets?.[args.withTarget]) {
|
||||
acc[name] = node;
|
||||
}
|
||||
return acc;
|
||||
}, {} as ProjectGraph['nodes']);
|
||||
}
|
||||
|
||||
const selectedProjects = new Set(Object.keys(graph.nodes));
|
||||
|
||||
if (args.exclude) {
|
||||
@ -51,13 +62,81 @@ export async function showProjectsHandler(
|
||||
}
|
||||
}
|
||||
|
||||
const projects = Array.from(selectedProjects).join('\n');
|
||||
if (projects.length) {
|
||||
console.log(projects);
|
||||
if (args.json) {
|
||||
console.log(JSON.stringify(Array.from(selectedProjects), null, 2));
|
||||
} else {
|
||||
for (const project of selectedProjects) {
|
||||
console.log(project);
|
||||
}
|
||||
}
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
export async function showProjectHandler(
|
||||
args: ShowProjectOptions
|
||||
): Promise<void> {
|
||||
const graph = await createProjectGraphAsync();
|
||||
const node = graph.nodes[args.projectName];
|
||||
if (!node) {
|
||||
console.log(`Could not find project ${args.projectName}`);
|
||||
process.exit(1);
|
||||
}
|
||||
if (args.json) {
|
||||
console.log(JSON.stringify(node.data, null, 2));
|
||||
} else {
|
||||
const chalk = require('chalk') as typeof import('chalk');
|
||||
const logIfExists = (label, key: keyof typeof node['data']) => {
|
||||
if (node.data[key]) {
|
||||
console.log(`${chalk.bold(label)}: ${node.data[key]}`);
|
||||
}
|
||||
};
|
||||
|
||||
logIfExists('Name', 'name');
|
||||
logIfExists('Root', 'root');
|
||||
logIfExists('Source Root', 'sourceRoot');
|
||||
logIfExists('Tags', 'tags');
|
||||
logIfExists('Implicit Dependencies', 'implicitDependencies');
|
||||
|
||||
const targets = Object.entries(node.data.targets ?? {});
|
||||
const maxTargetNameLength = Math.max(...targets.map(([t]) => t.length));
|
||||
const maxExecutorNameLength = Math.max(
|
||||
...targets.map(([, t]) => t?.executor?.length ?? 0)
|
||||
);
|
||||
|
||||
if (targets.length > 0) {
|
||||
console.log(`${chalk.bold('Targets')}: `);
|
||||
for (const [target, targetConfig] of targets) {
|
||||
console.log(
|
||||
`- ${chalk.bold((target + ':').padEnd(maxTargetNameLength + 2))} ${(
|
||||
targetConfig?.executor ?? ''
|
||||
).padEnd(maxExecutorNameLength + 2)} ${(() => {
|
||||
const configurations = Object.keys(
|
||||
targetConfig.configurations ?? {}
|
||||
);
|
||||
if (configurations.length) {
|
||||
return chalk.dim(configurations.join(', '));
|
||||
}
|
||||
return '';
|
||||
})()}`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
function getGraphNodesMatchingPatterns(
|
||||
graph: ProjectGraph,
|
||||
patterns: string[]
|
||||
): ProjectGraph['nodes'] {
|
||||
const nodes: Record<string, ProjectGraphProjectNode> = {};
|
||||
const matches = findMatchingProjects(patterns, graph.nodes);
|
||||
for (const match of matches) {
|
||||
nodes[match] = graph.nodes[match];
|
||||
}
|
||||
return nodes;
|
||||
}
|
||||
|
||||
function getAffectedGraph(
|
||||
nxArgs: NxArgs,
|
||||
nxJson: NxJsonConfiguration<'*' | string[]>,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user