feat(nx): add generic task execution
This commit is contained in:
parent
34a887a93f
commit
ed546337f1
@ -40,6 +40,10 @@ All projects
|
||||
|
||||
Base of the current branch (usually master)
|
||||
|
||||
### configuration
|
||||
|
||||
This is the configuration to use when performing tasks on projects
|
||||
|
||||
### exclude
|
||||
|
||||
Default: ``
|
||||
@ -68,6 +72,10 @@ Isolate projects which previously failed
|
||||
|
||||
Produces a plain output for affected:apps and affected:libs
|
||||
|
||||
### runner
|
||||
|
||||
This is the name of the tasks runner configured in nx.json
|
||||
|
||||
### uncommitted
|
||||
|
||||
Uncommitted changes
|
||||
|
||||
@ -58,6 +58,10 @@ All projects
|
||||
|
||||
Base of the current branch (usually master)
|
||||
|
||||
### configuration
|
||||
|
||||
This is the configuration to use when performing tasks on projects
|
||||
|
||||
### exclude
|
||||
|
||||
Default: ``
|
||||
@ -98,6 +102,10 @@ Parallelize the command
|
||||
|
||||
Produces a plain output for affected:apps and affected:libs
|
||||
|
||||
### runner
|
||||
|
||||
This is the name of the tasks runner configured in nx.json
|
||||
|
||||
### uncommitted
|
||||
|
||||
Uncommitted changes
|
||||
|
||||
@ -46,6 +46,10 @@ All projects
|
||||
|
||||
Base of the current branch (usually master)
|
||||
|
||||
### configuration
|
||||
|
||||
This is the configuration to use when performing tasks on projects
|
||||
|
||||
### exclude
|
||||
|
||||
Default: ``
|
||||
@ -78,6 +82,10 @@ Isolate projects which previously failed
|
||||
|
||||
Produces a plain output for affected:apps and affected:libs
|
||||
|
||||
### runner
|
||||
|
||||
This is the name of the tasks runner configured in nx.json
|
||||
|
||||
### uncommitted
|
||||
|
||||
Uncommitted changes
|
||||
|
||||
@ -58,6 +58,10 @@ All projects
|
||||
|
||||
Base of the current branch (usually master)
|
||||
|
||||
### configuration
|
||||
|
||||
This is the configuration to use when performing tasks on projects
|
||||
|
||||
### exclude
|
||||
|
||||
Default: ``
|
||||
@ -98,6 +102,10 @@ Parallelize the command
|
||||
|
||||
Produces a plain output for affected:apps and affected:libs
|
||||
|
||||
### runner
|
||||
|
||||
This is the name of the tasks runner configured in nx.json
|
||||
|
||||
### uncommitted
|
||||
|
||||
Uncommitted changes
|
||||
|
||||
@ -40,6 +40,10 @@ All projects
|
||||
|
||||
Base of the current branch (usually master)
|
||||
|
||||
### configuration
|
||||
|
||||
This is the configuration to use when performing tasks on projects
|
||||
|
||||
### exclude
|
||||
|
||||
Default: ``
|
||||
@ -68,6 +72,10 @@ Isolate projects which previously failed
|
||||
|
||||
Produces a plain output for affected:apps and affected:libs
|
||||
|
||||
### runner
|
||||
|
||||
This is the name of the tasks runner configured in nx.json
|
||||
|
||||
### uncommitted
|
||||
|
||||
Uncommitted changes
|
||||
|
||||
@ -58,6 +58,10 @@ All projects
|
||||
|
||||
Base of the current branch (usually master)
|
||||
|
||||
### configuration
|
||||
|
||||
This is the configuration to use when performing tasks on projects
|
||||
|
||||
### exclude
|
||||
|
||||
Default: ``
|
||||
@ -98,6 +102,10 @@ Parallelize the command
|
||||
|
||||
Produces a plain output for affected:apps and affected:libs
|
||||
|
||||
### runner
|
||||
|
||||
This is the name of the tasks runner configured in nx.json
|
||||
|
||||
### uncommitted
|
||||
|
||||
Uncommitted changes
|
||||
|
||||
@ -58,6 +58,10 @@ All projects
|
||||
|
||||
Base of the current branch (usually master)
|
||||
|
||||
### configuration
|
||||
|
||||
This is the configuration to use when performing tasks on projects
|
||||
|
||||
### exclude
|
||||
|
||||
Default: ``
|
||||
@ -98,6 +102,10 @@ Parallelize the command
|
||||
|
||||
Produces a plain output for affected:apps and affected:libs
|
||||
|
||||
### runner
|
||||
|
||||
This is the name of the tasks runner configured in nx.json
|
||||
|
||||
### uncommitted
|
||||
|
||||
Uncommitted changes
|
||||
|
||||
@ -64,6 +64,10 @@ All projects
|
||||
|
||||
Base of the current branch (usually master)
|
||||
|
||||
### configuration
|
||||
|
||||
This is the configuration to use when performing tasks on projects
|
||||
|
||||
### exclude
|
||||
|
||||
Default: ``
|
||||
@ -104,6 +108,10 @@ Parallelize the command
|
||||
|
||||
Produces a plain output for affected:apps and affected:libs
|
||||
|
||||
### runner
|
||||
|
||||
This is the name of the tasks runner configured in nx.json
|
||||
|
||||
### target
|
||||
|
||||
Task to run for affected projects
|
||||
|
||||
@ -22,6 +22,10 @@ All projects
|
||||
|
||||
Base of the current branch (usually master)
|
||||
|
||||
### configuration
|
||||
|
||||
This is the configuration to use when performing tasks on projects
|
||||
|
||||
### exclude
|
||||
|
||||
Default: ``
|
||||
@ -50,6 +54,10 @@ Isolate projects which previously failed
|
||||
|
||||
Produces a plain output for affected:apps and affected:libs
|
||||
|
||||
### runner
|
||||
|
||||
This is the name of the tasks runner configured in nx.json
|
||||
|
||||
### uncommitted
|
||||
|
||||
Uncommitted changes
|
||||
|
||||
@ -22,6 +22,10 @@ All projects
|
||||
|
||||
Base of the current branch (usually master)
|
||||
|
||||
### configuration
|
||||
|
||||
This is the configuration to use when performing tasks on projects
|
||||
|
||||
### exclude
|
||||
|
||||
Default: ``
|
||||
@ -50,6 +54,10 @@ Isolate projects which previously failed
|
||||
|
||||
Produces a plain output for affected:apps and affected:libs
|
||||
|
||||
### runner
|
||||
|
||||
This is the name of the tasks runner configured in nx.json
|
||||
|
||||
### uncommitted
|
||||
|
||||
Uncommitted changes
|
||||
|
||||
@ -40,6 +40,10 @@ All projects
|
||||
|
||||
Base of the current branch (usually master)
|
||||
|
||||
### configuration
|
||||
|
||||
This is the configuration to use when performing tasks on projects
|
||||
|
||||
### exclude
|
||||
|
||||
Default: ``
|
||||
@ -68,6 +72,10 @@ Isolate projects which previously failed
|
||||
|
||||
Produces a plain output for affected:apps and affected:libs
|
||||
|
||||
### runner
|
||||
|
||||
This is the name of the tasks runner configured in nx.json
|
||||
|
||||
### uncommitted
|
||||
|
||||
Uncommitted changes
|
||||
|
||||
@ -58,6 +58,10 @@ All projects
|
||||
|
||||
Base of the current branch (usually master)
|
||||
|
||||
### configuration
|
||||
|
||||
This is the configuration to use when performing tasks on projects
|
||||
|
||||
### exclude
|
||||
|
||||
Default: ``
|
||||
@ -98,6 +102,10 @@ Parallelize the command
|
||||
|
||||
Produces a plain output for affected:apps and affected:libs
|
||||
|
||||
### runner
|
||||
|
||||
This is the name of the tasks runner configured in nx.json
|
||||
|
||||
### uncommitted
|
||||
|
||||
Uncommitted changes
|
||||
|
||||
@ -46,6 +46,10 @@ All projects
|
||||
|
||||
Base of the current branch (usually master)
|
||||
|
||||
### configuration
|
||||
|
||||
This is the configuration to use when performing tasks on projects
|
||||
|
||||
### exclude
|
||||
|
||||
Default: ``
|
||||
@ -78,6 +82,10 @@ Isolate projects which previously failed
|
||||
|
||||
Produces a plain output for affected:apps and affected:libs
|
||||
|
||||
### runner
|
||||
|
||||
This is the name of the tasks runner configured in nx.json
|
||||
|
||||
### uncommitted
|
||||
|
||||
Uncommitted changes
|
||||
|
||||
@ -58,6 +58,10 @@ All projects
|
||||
|
||||
Base of the current branch (usually master)
|
||||
|
||||
### configuration
|
||||
|
||||
This is the configuration to use when performing tasks on projects
|
||||
|
||||
### exclude
|
||||
|
||||
Default: ``
|
||||
@ -98,6 +102,10 @@ Parallelize the command
|
||||
|
||||
Produces a plain output for affected:apps and affected:libs
|
||||
|
||||
### runner
|
||||
|
||||
This is the name of the tasks runner configured in nx.json
|
||||
|
||||
### uncommitted
|
||||
|
||||
Uncommitted changes
|
||||
|
||||
@ -40,6 +40,10 @@ All projects
|
||||
|
||||
Base of the current branch (usually master)
|
||||
|
||||
### configuration
|
||||
|
||||
This is the configuration to use when performing tasks on projects
|
||||
|
||||
### exclude
|
||||
|
||||
Default: ``
|
||||
@ -68,6 +72,10 @@ Isolate projects which previously failed
|
||||
|
||||
Produces a plain output for affected:apps and affected:libs
|
||||
|
||||
### runner
|
||||
|
||||
This is the name of the tasks runner configured in nx.json
|
||||
|
||||
### uncommitted
|
||||
|
||||
Uncommitted changes
|
||||
|
||||
@ -58,6 +58,10 @@ All projects
|
||||
|
||||
Base of the current branch (usually master)
|
||||
|
||||
### configuration
|
||||
|
||||
This is the configuration to use when performing tasks on projects
|
||||
|
||||
### exclude
|
||||
|
||||
Default: ``
|
||||
@ -98,6 +102,10 @@ Parallelize the command
|
||||
|
||||
Produces a plain output for affected:apps and affected:libs
|
||||
|
||||
### runner
|
||||
|
||||
This is the name of the tasks runner configured in nx.json
|
||||
|
||||
### uncommitted
|
||||
|
||||
Uncommitted changes
|
||||
|
||||
@ -58,6 +58,10 @@ All projects
|
||||
|
||||
Base of the current branch (usually master)
|
||||
|
||||
### configuration
|
||||
|
||||
This is the configuration to use when performing tasks on projects
|
||||
|
||||
### exclude
|
||||
|
||||
Default: ``
|
||||
@ -98,6 +102,10 @@ Parallelize the command
|
||||
|
||||
Produces a plain output for affected:apps and affected:libs
|
||||
|
||||
### runner
|
||||
|
||||
This is the name of the tasks runner configured in nx.json
|
||||
|
||||
### uncommitted
|
||||
|
||||
Uncommitted changes
|
||||
|
||||
@ -64,6 +64,10 @@ All projects
|
||||
|
||||
Base of the current branch (usually master)
|
||||
|
||||
### configuration
|
||||
|
||||
This is the configuration to use when performing tasks on projects
|
||||
|
||||
### exclude
|
||||
|
||||
Default: ``
|
||||
@ -104,6 +108,10 @@ Parallelize the command
|
||||
|
||||
Produces a plain output for affected:apps and affected:libs
|
||||
|
||||
### runner
|
||||
|
||||
This is the name of the tasks runner configured in nx.json
|
||||
|
||||
### target
|
||||
|
||||
Task to run for affected projects
|
||||
|
||||
@ -22,6 +22,10 @@ All projects
|
||||
|
||||
Base of the current branch (usually master)
|
||||
|
||||
### configuration
|
||||
|
||||
This is the configuration to use when performing tasks on projects
|
||||
|
||||
### exclude
|
||||
|
||||
Default: ``
|
||||
@ -50,6 +54,10 @@ Isolate projects which previously failed
|
||||
|
||||
Produces a plain output for affected:apps and affected:libs
|
||||
|
||||
### runner
|
||||
|
||||
This is the name of the tasks runner configured in nx.json
|
||||
|
||||
### uncommitted
|
||||
|
||||
Uncommitted changes
|
||||
|
||||
@ -22,6 +22,10 @@ All projects
|
||||
|
||||
Base of the current branch (usually master)
|
||||
|
||||
### configuration
|
||||
|
||||
This is the configuration to use when performing tasks on projects
|
||||
|
||||
### exclude
|
||||
|
||||
Default: ``
|
||||
@ -50,6 +54,10 @@ Isolate projects which previously failed
|
||||
|
||||
Produces a plain output for affected:apps and affected:libs
|
||||
|
||||
### runner
|
||||
|
||||
This is the name of the tasks runner configured in nx.json
|
||||
|
||||
### uncommitted
|
||||
|
||||
Uncommitted changes
|
||||
|
||||
@ -40,6 +40,10 @@ All projects
|
||||
|
||||
Base of the current branch (usually master)
|
||||
|
||||
### configuration
|
||||
|
||||
This is the configuration to use when performing tasks on projects
|
||||
|
||||
### exclude
|
||||
|
||||
Default: ``
|
||||
@ -68,6 +72,10 @@ Isolate projects which previously failed
|
||||
|
||||
Produces a plain output for affected:apps and affected:libs
|
||||
|
||||
### runner
|
||||
|
||||
This is the name of the tasks runner configured in nx.json
|
||||
|
||||
### uncommitted
|
||||
|
||||
Uncommitted changes
|
||||
|
||||
@ -58,6 +58,10 @@ All projects
|
||||
|
||||
Base of the current branch (usually master)
|
||||
|
||||
### configuration
|
||||
|
||||
This is the configuration to use when performing tasks on projects
|
||||
|
||||
### exclude
|
||||
|
||||
Default: ``
|
||||
@ -98,6 +102,10 @@ Parallelize the command
|
||||
|
||||
Produces a plain output for affected:apps and affected:libs
|
||||
|
||||
### runner
|
||||
|
||||
This is the name of the tasks runner configured in nx.json
|
||||
|
||||
### uncommitted
|
||||
|
||||
Uncommitted changes
|
||||
|
||||
@ -46,6 +46,10 @@ All projects
|
||||
|
||||
Base of the current branch (usually master)
|
||||
|
||||
### configuration
|
||||
|
||||
This is the configuration to use when performing tasks on projects
|
||||
|
||||
### exclude
|
||||
|
||||
Default: ``
|
||||
@ -78,6 +82,10 @@ Isolate projects which previously failed
|
||||
|
||||
Produces a plain output for affected:apps and affected:libs
|
||||
|
||||
### runner
|
||||
|
||||
This is the name of the tasks runner configured in nx.json
|
||||
|
||||
### uncommitted
|
||||
|
||||
Uncommitted changes
|
||||
|
||||
@ -58,6 +58,10 @@ All projects
|
||||
|
||||
Base of the current branch (usually master)
|
||||
|
||||
### configuration
|
||||
|
||||
This is the configuration to use when performing tasks on projects
|
||||
|
||||
### exclude
|
||||
|
||||
Default: ``
|
||||
@ -98,6 +102,10 @@ Parallelize the command
|
||||
|
||||
Produces a plain output for affected:apps and affected:libs
|
||||
|
||||
### runner
|
||||
|
||||
This is the name of the tasks runner configured in nx.json
|
||||
|
||||
### uncommitted
|
||||
|
||||
Uncommitted changes
|
||||
|
||||
@ -40,6 +40,10 @@ All projects
|
||||
|
||||
Base of the current branch (usually master)
|
||||
|
||||
### configuration
|
||||
|
||||
This is the configuration to use when performing tasks on projects
|
||||
|
||||
### exclude
|
||||
|
||||
Default: ``
|
||||
@ -68,6 +72,10 @@ Isolate projects which previously failed
|
||||
|
||||
Produces a plain output for affected:apps and affected:libs
|
||||
|
||||
### runner
|
||||
|
||||
This is the name of the tasks runner configured in nx.json
|
||||
|
||||
### uncommitted
|
||||
|
||||
Uncommitted changes
|
||||
|
||||
@ -58,6 +58,10 @@ All projects
|
||||
|
||||
Base of the current branch (usually master)
|
||||
|
||||
### configuration
|
||||
|
||||
This is the configuration to use when performing tasks on projects
|
||||
|
||||
### exclude
|
||||
|
||||
Default: ``
|
||||
@ -98,6 +102,10 @@ Parallelize the command
|
||||
|
||||
Produces a plain output for affected:apps and affected:libs
|
||||
|
||||
### runner
|
||||
|
||||
This is the name of the tasks runner configured in nx.json
|
||||
|
||||
### uncommitted
|
||||
|
||||
Uncommitted changes
|
||||
|
||||
@ -58,6 +58,10 @@ All projects
|
||||
|
||||
Base of the current branch (usually master)
|
||||
|
||||
### configuration
|
||||
|
||||
This is the configuration to use when performing tasks on projects
|
||||
|
||||
### exclude
|
||||
|
||||
Default: ``
|
||||
@ -98,6 +102,10 @@ Parallelize the command
|
||||
|
||||
Produces a plain output for affected:apps and affected:libs
|
||||
|
||||
### runner
|
||||
|
||||
This is the name of the tasks runner configured in nx.json
|
||||
|
||||
### uncommitted
|
||||
|
||||
Uncommitted changes
|
||||
|
||||
@ -64,6 +64,10 @@ All projects
|
||||
|
||||
Base of the current branch (usually master)
|
||||
|
||||
### configuration
|
||||
|
||||
This is the configuration to use when performing tasks on projects
|
||||
|
||||
### exclude
|
||||
|
||||
Default: ``
|
||||
@ -104,6 +108,10 @@ Parallelize the command
|
||||
|
||||
Produces a plain output for affected:apps and affected:libs
|
||||
|
||||
### runner
|
||||
|
||||
This is the name of the tasks runner configured in nx.json
|
||||
|
||||
### target
|
||||
|
||||
Task to run for affected projects
|
||||
|
||||
@ -22,6 +22,10 @@ All projects
|
||||
|
||||
Base of the current branch (usually master)
|
||||
|
||||
### configuration
|
||||
|
||||
This is the configuration to use when performing tasks on projects
|
||||
|
||||
### exclude
|
||||
|
||||
Default: ``
|
||||
@ -50,6 +54,10 @@ Isolate projects which previously failed
|
||||
|
||||
Produces a plain output for affected:apps and affected:libs
|
||||
|
||||
### runner
|
||||
|
||||
This is the name of the tasks runner configured in nx.json
|
||||
|
||||
### uncommitted
|
||||
|
||||
Uncommitted changes
|
||||
|
||||
@ -22,6 +22,10 @@ All projects
|
||||
|
||||
Base of the current branch (usually master)
|
||||
|
||||
### configuration
|
||||
|
||||
This is the configuration to use when performing tasks on projects
|
||||
|
||||
### exclude
|
||||
|
||||
Default: ``
|
||||
@ -50,6 +54,10 @@ Isolate projects which previously failed
|
||||
|
||||
Produces a plain output for affected:apps and affected:libs
|
||||
|
||||
### runner
|
||||
|
||||
This is the name of the tasks runner configured in nx.json
|
||||
|
||||
### uncommitted
|
||||
|
||||
Uncommitted changes
|
||||
|
||||
@ -143,13 +143,14 @@ forEachCli(() => {
|
||||
|
||||
// affected:build should pass non-nx flags to the CLI
|
||||
const buildWithFlags = runCommand(
|
||||
`npm run affected:build -- --files="libs/${mylib}/src/index.ts" --stats-json`
|
||||
`npm run affected:build -- --files="libs/${mylib}/src/index.ts" -- --stats-json`
|
||||
);
|
||||
|
||||
expect(buildWithFlags).toContain(`Running target build for projects:`);
|
||||
expect(buildWithFlags).toContain(`- ${myapp}`);
|
||||
expect(buildWithFlags).toContain(`- ${mypublishablelib}`);
|
||||
expect(buildWithFlags).toContain('With flags: --stats-json=true');
|
||||
expect(buildWithFlags).toContain('With flags:');
|
||||
expect(buildWithFlags).toContain('--stats-json=true');
|
||||
|
||||
if (supportUi()) {
|
||||
const e2e = runCommand(
|
||||
@ -221,7 +222,8 @@ forEachCli(() => {
|
||||
const lintWithJsonFormating = runCommand(
|
||||
`npm run affected:lint -- --files="libs/${mylib}/src/index.ts" -- --format json`
|
||||
);
|
||||
expect(lintWithJsonFormating).toContain('With flags: --format json');
|
||||
expect(lintWithJsonFormating).toContain('With flags:');
|
||||
expect(lintWithJsonFormating).toContain('--format=json');
|
||||
|
||||
const unitTestsExcluded = runCommand(
|
||||
`npm run affected:test -- --files="libs/${mylib}/src/index.ts" --exclude=${myapp},${mypublishablelib}`
|
||||
|
||||
@ -3,11 +3,11 @@ import {
|
||||
getAffectedApps,
|
||||
getAffectedLibs,
|
||||
getAffectedProjects,
|
||||
getAffectedProjectsWithTarget,
|
||||
getAffectedProjectsWithTargetAndConfiguration,
|
||||
getAllApps,
|
||||
getAllLibs,
|
||||
getAllProjects,
|
||||
getAllProjectsWithTarget
|
||||
getAllProjectsWithTargetAndConfiguration
|
||||
} from './affected-apps';
|
||||
import { DependencyType } from './deps-calculator';
|
||||
|
||||
@ -23,7 +23,11 @@ describe('affected-apps', () => {
|
||||
architect: {
|
||||
lint: {},
|
||||
test: {},
|
||||
build: {}
|
||||
build: {
|
||||
configurations: {
|
||||
production: {}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
app2: {
|
||||
@ -196,11 +200,46 @@ describe('affected-apps', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('getAffectedProjectsWithTarget', () => {
|
||||
describe('getAffectedProjectsWithTargetAndConfiguration', () => {
|
||||
it('should get none if no projects are affected', () => {
|
||||
expect(getAffectedProjectsWithTarget(affectedMetadata, 'test')).toEqual(
|
||||
[]
|
||||
);
|
||||
expect(
|
||||
getAffectedProjectsWithTargetAndConfiguration(affectedMetadata, 'test')
|
||||
).toEqual([]);
|
||||
});
|
||||
|
||||
it('should find affected projects that can be built', () => {
|
||||
projectStates.lib1 = {
|
||||
affected: true,
|
||||
touched: true
|
||||
};
|
||||
projectStates.app1.affected = true;
|
||||
projectStates['app1-e2e'].affected = true;
|
||||
projectStates.app2.affected = true;
|
||||
projectStates['customName-e2e'].affected = true;
|
||||
expect(
|
||||
getAffectedProjectsWithTargetAndConfiguration(affectedMetadata, 'build')
|
||||
).toEqual([
|
||||
affectedMetadata.dependencyGraph.projects.app1,
|
||||
affectedMetadata.dependencyGraph.projects.app2
|
||||
]);
|
||||
});
|
||||
|
||||
it('should find affected projects that can be built for production', () => {
|
||||
projectStates.lib1 = {
|
||||
affected: true,
|
||||
touched: true
|
||||
};
|
||||
projectStates.app1.affected = true;
|
||||
projectStates['app1-e2e'].affected = true;
|
||||
projectStates.app2.affected = true;
|
||||
projectStates['customName-e2e'].affected = true;
|
||||
expect(
|
||||
getAffectedProjectsWithTargetAndConfiguration(
|
||||
affectedMetadata,
|
||||
'build',
|
||||
'production'
|
||||
)
|
||||
).toEqual([affectedMetadata.dependencyGraph.projects.app1]);
|
||||
});
|
||||
|
||||
it('should find affected projects that can be linted', () => {
|
||||
@ -212,12 +251,14 @@ describe('affected-apps', () => {
|
||||
projectStates['app1-e2e'].affected = true;
|
||||
projectStates.app2.affected = true;
|
||||
projectStates['customName-e2e'].affected = true;
|
||||
expect(getAffectedProjectsWithTarget(affectedMetadata, 'lint')).toEqual([
|
||||
'lib1',
|
||||
'app1',
|
||||
'app1-e2e',
|
||||
'app2',
|
||||
'customName-e2e'
|
||||
expect(
|
||||
getAffectedProjectsWithTargetAndConfiguration(affectedMetadata, 'lint')
|
||||
).toEqual([
|
||||
affectedMetadata.dependencyGraph.projects.lib1,
|
||||
affectedMetadata.dependencyGraph.projects.app1,
|
||||
affectedMetadata.dependencyGraph.projects['app1-e2e'],
|
||||
affectedMetadata.dependencyGraph.projects.app2,
|
||||
affectedMetadata.dependencyGraph.projects['customName-e2e']
|
||||
]);
|
||||
});
|
||||
|
||||
@ -230,10 +271,12 @@ describe('affected-apps', () => {
|
||||
projectStates['app1-e2e'].affected = true;
|
||||
projectStates.app2.affected = true;
|
||||
projectStates['customName-e2e'].affected = true;
|
||||
expect(getAffectedProjectsWithTarget(affectedMetadata, 'test')).toEqual([
|
||||
'lib1',
|
||||
'app1',
|
||||
'app2'
|
||||
expect(
|
||||
getAffectedProjectsWithTargetAndConfiguration(affectedMetadata, 'test')
|
||||
).toEqual([
|
||||
affectedMetadata.dependencyGraph.projects.lib1,
|
||||
affectedMetadata.dependencyGraph.projects.app1,
|
||||
affectedMetadata.dependencyGraph.projects.app2
|
||||
]);
|
||||
});
|
||||
|
||||
@ -246,9 +289,11 @@ describe('affected-apps', () => {
|
||||
projectStates['app1-e2e'].affected = true;
|
||||
projectStates.app2.affected = true;
|
||||
projectStates['customName-e2e'].affected = true;
|
||||
expect(getAffectedProjectsWithTarget(affectedMetadata, 'e2e')).toEqual([
|
||||
'app1-e2e',
|
||||
'customName-e2e'
|
||||
expect(
|
||||
getAffectedProjectsWithTargetAndConfiguration(affectedMetadata, 'e2e')
|
||||
).toEqual([
|
||||
affectedMetadata.dependencyGraph.projects['app1-e2e'],
|
||||
affectedMetadata.dependencyGraph.projects['customName-e2e']
|
||||
]);
|
||||
});
|
||||
});
|
||||
@ -280,36 +325,54 @@ describe('affected-apps', () => {
|
||||
|
||||
describe('getAllProjectsWithTarget', () => {
|
||||
it('should get all projects that can be linted', () => {
|
||||
expect(getAllProjectsWithTarget(affectedMetadata, 'lint')).toEqual([
|
||||
'lib1',
|
||||
'app1',
|
||||
'app1-e2e',
|
||||
'lib2',
|
||||
'app2',
|
||||
'customName-e2e'
|
||||
expect(
|
||||
getAllProjectsWithTargetAndConfiguration(affectedMetadata, 'lint')
|
||||
).toEqual([
|
||||
affectedMetadata.dependencyGraph.projects.lib1,
|
||||
affectedMetadata.dependencyGraph.projects.app1,
|
||||
affectedMetadata.dependencyGraph.projects['app1-e2e'],
|
||||
affectedMetadata.dependencyGraph.projects.lib2,
|
||||
affectedMetadata.dependencyGraph.projects.app2,
|
||||
affectedMetadata.dependencyGraph.projects['customName-e2e']
|
||||
]);
|
||||
});
|
||||
|
||||
it('should get all projects that can be tested', () => {
|
||||
expect(getAllProjectsWithTarget(affectedMetadata, 'test')).toEqual([
|
||||
'lib1',
|
||||
'app1',
|
||||
'lib2',
|
||||
'app2'
|
||||
expect(
|
||||
getAllProjectsWithTargetAndConfiguration(affectedMetadata, 'test')
|
||||
).toEqual([
|
||||
affectedMetadata.dependencyGraph.projects.lib1,
|
||||
affectedMetadata.dependencyGraph.projects.app1,
|
||||
affectedMetadata.dependencyGraph.projects.lib2,
|
||||
affectedMetadata.dependencyGraph.projects.app2
|
||||
]);
|
||||
});
|
||||
|
||||
it('should get all projects that can be built', () => {
|
||||
expect(getAllProjectsWithTarget(affectedMetadata, 'build')).toEqual([
|
||||
'app1',
|
||||
'app2'
|
||||
expect(
|
||||
getAllProjectsWithTargetAndConfiguration(affectedMetadata, 'build')
|
||||
).toEqual([
|
||||
affectedMetadata.dependencyGraph.projects.app1,
|
||||
affectedMetadata.dependencyGraph.projects.app2
|
||||
]);
|
||||
});
|
||||
|
||||
it('should get all projects that can be built for production', () => {
|
||||
expect(
|
||||
getAllProjectsWithTargetAndConfiguration(
|
||||
affectedMetadata,
|
||||
'build',
|
||||
'production'
|
||||
)
|
||||
).toEqual([affectedMetadata.dependencyGraph.projects.app1]);
|
||||
});
|
||||
|
||||
it('should get all projects that can be e2e-tested', () => {
|
||||
expect(getAllProjectsWithTarget(affectedMetadata, 'e2e')).toEqual([
|
||||
'app1-e2e',
|
||||
'customName-e2e'
|
||||
expect(
|
||||
getAllProjectsWithTargetAndConfiguration(affectedMetadata, 'e2e')
|
||||
).toEqual([
|
||||
affectedMetadata.dependencyGraph.projects['app1-e2e'],
|
||||
affectedMetadata.dependencyGraph.projects['customName-e2e']
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
@ -26,16 +26,17 @@ export function getAffectedProjects(
|
||||
).map(project => project.name);
|
||||
}
|
||||
|
||||
export function getAffectedProjectsWithTarget(
|
||||
export function getAffectedProjectsWithTargetAndConfiguration(
|
||||
affectedMetadata: AffectedMetadata,
|
||||
target: string
|
||||
): string[] {
|
||||
target: string,
|
||||
configuration?: string
|
||||
): ProjectNode[] {
|
||||
return filterAffectedMetadata(
|
||||
affectedMetadata,
|
||||
project =>
|
||||
affectedMetadata.projectStates[project.name].affected &&
|
||||
project.architect[target]
|
||||
).map(project => project.name);
|
||||
projectHasTargetAndConfiguration(project, target, configuration)
|
||||
);
|
||||
}
|
||||
|
||||
export function getAllApps(affectedMetadata: AffectedMetadata): string[] {
|
||||
@ -58,14 +59,33 @@ export function getAllProjects(affectedMetadata: AffectedMetadata): string[] {
|
||||
);
|
||||
}
|
||||
|
||||
export function getAllProjectsWithTarget(
|
||||
export function getAllProjectsWithTargetAndConfiguration(
|
||||
affectedMetadata: AffectedMetadata,
|
||||
target: string
|
||||
): string[] {
|
||||
return filterAffectedMetadata(
|
||||
affectedMetadata,
|
||||
project => project.architect[target]
|
||||
).map(project => project.name);
|
||||
target: string,
|
||||
configuration?: string
|
||||
): ProjectNode[] {
|
||||
return filterAffectedMetadata(affectedMetadata, project =>
|
||||
projectHasTargetAndConfiguration(project, target, configuration)
|
||||
);
|
||||
}
|
||||
|
||||
export function projectHasTargetAndConfiguration(
|
||||
project: ProjectNode,
|
||||
target: string,
|
||||
configuration?: string
|
||||
) {
|
||||
if (!project.architect[target]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!configuration) {
|
||||
return !!project.architect[target];
|
||||
} else {
|
||||
return (
|
||||
project.architect[target].configurations &&
|
||||
project.architect[target].configurations[configuration]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function filterAffectedMetadata(
|
||||
|
||||
153
packages/workspace/src/command-line/affected.spec.ts
Normal file
153
packages/workspace/src/command-line/affected.spec.ts
Normal file
@ -0,0 +1,153 @@
|
||||
import { processArgs } from './affected';
|
||||
import { NxJson } from './shared';
|
||||
import defaultTasksRunner from '../tasks-runner/default-tasks-runner';
|
||||
import { TasksRunner } from '../tasks-runner/tasks-runner';
|
||||
|
||||
describe('processArgs', () => {
|
||||
let nxJson: NxJson;
|
||||
let mockRunner: TasksRunner;
|
||||
|
||||
beforeEach(() => {
|
||||
nxJson = {
|
||||
npmScope: 'proj',
|
||||
projects: {}
|
||||
};
|
||||
mockRunner = jest.fn();
|
||||
});
|
||||
|
||||
it('should process nx specific arguments as affected args', () => {
|
||||
expect(
|
||||
processArgs(
|
||||
{
|
||||
files: [''],
|
||||
notNxArg: true,
|
||||
_: ['--override'],
|
||||
$0: ''
|
||||
},
|
||||
nxJson
|
||||
).affectedArgs
|
||||
).toEqual({
|
||||
files: ['']
|
||||
});
|
||||
});
|
||||
|
||||
it('should process non nx specific arguments as tasks runner args', () => {
|
||||
expect(
|
||||
processArgs(
|
||||
{
|
||||
files: [''],
|
||||
notNxArg: true,
|
||||
_: ['--override'],
|
||||
$0: ''
|
||||
},
|
||||
nxJson
|
||||
).tasksRunnerOptions
|
||||
).toEqual({
|
||||
notNxArg: true
|
||||
});
|
||||
});
|
||||
|
||||
it('should process delimited args as task overrides', () => {
|
||||
expect(
|
||||
processArgs(
|
||||
{
|
||||
files: [''],
|
||||
notNxArg: true,
|
||||
_: ['', '--override'],
|
||||
$0: ''
|
||||
},
|
||||
nxJson
|
||||
).taskOverrides
|
||||
).toEqual({
|
||||
override: true
|
||||
});
|
||||
});
|
||||
|
||||
it('should get a default tasks runner', () => {
|
||||
expect(
|
||||
processArgs(
|
||||
{
|
||||
files: [''],
|
||||
notNxArg: true,
|
||||
_: ['', '--override'],
|
||||
$0: ''
|
||||
},
|
||||
nxJson
|
||||
).tasksRunner
|
||||
).toEqual(defaultTasksRunner);
|
||||
});
|
||||
|
||||
it('should get a custom tasks runner', () => {
|
||||
jest.mock('custom-runner', () => mockRunner, {
|
||||
virtual: true
|
||||
});
|
||||
nxJson.tasksRunnerOptions = {
|
||||
custom: {
|
||||
runner: 'custom-runner'
|
||||
}
|
||||
};
|
||||
expect(
|
||||
processArgs(
|
||||
{
|
||||
files: [''],
|
||||
notNxArg: true,
|
||||
runner: 'custom',
|
||||
_: ['', '--override'],
|
||||
$0: ''
|
||||
},
|
||||
nxJson
|
||||
).tasksRunner
|
||||
).toEqual(mockRunner);
|
||||
});
|
||||
|
||||
it('should get a custom tasks runner with options', () => {
|
||||
jest.mock('custom-runner', () => mockRunner, {
|
||||
virtual: true
|
||||
});
|
||||
nxJson.tasksRunnerOptions = {
|
||||
custom: {
|
||||
runner: 'custom-runner',
|
||||
options: {
|
||||
runnerOption: 'runner-option'
|
||||
}
|
||||
}
|
||||
};
|
||||
expect(
|
||||
processArgs(
|
||||
{
|
||||
files: [''],
|
||||
notNxArg: true,
|
||||
runner: 'custom',
|
||||
_: ['', '--override'],
|
||||
$0: ''
|
||||
},
|
||||
nxJson
|
||||
).tasksRunnerOptions
|
||||
).toEqual({
|
||||
runnerOption: 'runner-option',
|
||||
notNxArg: true
|
||||
});
|
||||
});
|
||||
|
||||
it('should get a custom defined default tasks runner', () => {
|
||||
jest.mock('custom-default-runner', () => mockRunner, {
|
||||
virtual: true
|
||||
});
|
||||
nxJson.tasksRunnerOptions = {
|
||||
default: {
|
||||
runner: 'custom-default-runner'
|
||||
}
|
||||
};
|
||||
expect(
|
||||
processArgs(
|
||||
{
|
||||
files: [''],
|
||||
notNxArg: true,
|
||||
_: ['', '--override'],
|
||||
$0: ''
|
||||
},
|
||||
nxJson
|
||||
).tasksRunner
|
||||
).toEqual(mockRunner);
|
||||
});
|
||||
});
|
||||
@ -1,28 +1,39 @@
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as runAll from 'npm-run-all';
|
||||
import * as yargs from 'yargs';
|
||||
import * as yargsParser from 'yargs-parser';
|
||||
import { join } from 'path';
|
||||
|
||||
import {
|
||||
parseFiles,
|
||||
readWorkspaceJson,
|
||||
printArgsWarning,
|
||||
cliCommand,
|
||||
getAffectedMetadata
|
||||
getAffectedMetadata,
|
||||
AffectedMetadata,
|
||||
readNxJson,
|
||||
ProjectNode,
|
||||
NxJson
|
||||
} from './shared';
|
||||
import {
|
||||
getAffectedApps,
|
||||
getAffectedLibs,
|
||||
getAffectedProjects,
|
||||
getAffectedProjectsWithTarget,
|
||||
getAffectedProjectsWithTargetAndConfiguration,
|
||||
getAllApps,
|
||||
getAllLibs,
|
||||
getAllProjects,
|
||||
getAllProjectsWithTarget
|
||||
getAllProjectsWithTargetAndConfiguration,
|
||||
projectHasTargetAndConfiguration
|
||||
} from './affected-apps';
|
||||
import { generateGraph } from './dep-graph';
|
||||
import { WorkspaceResults } from './workspace-results';
|
||||
import { output } from './output';
|
||||
import {
|
||||
AffectedEventType,
|
||||
Task,
|
||||
TaskCompleteEvent,
|
||||
TasksRunner
|
||||
} from '../tasks-runner/tasks-runner';
|
||||
import { appRootPath } from '../utils/app-root';
|
||||
import { defaultTasksRunner } from '../tasks-runner/default-tasks-runner';
|
||||
import { isRelativePath } from '../utils/fileutils';
|
||||
|
||||
export interface YargsAffectedOptions
|
||||
extends yargs.Arguments,
|
||||
@ -30,6 +41,8 @@ export interface YargsAffectedOptions
|
||||
|
||||
export interface AffectedOptions {
|
||||
target?: string;
|
||||
configuration?: string;
|
||||
runner?: string;
|
||||
parallel?: boolean;
|
||||
maxParallel?: number;
|
||||
untracked?: boolean;
|
||||
@ -49,14 +62,15 @@ export interface AffectedOptions {
|
||||
plain?: boolean;
|
||||
}
|
||||
|
||||
const commonCommands = ['build', 'test', 'lint', 'e2e'];
|
||||
interface ProcessedArgs {
|
||||
affectedArgs: YargsAffectedOptions;
|
||||
taskOverrides: any;
|
||||
tasksRunnerOptions: any;
|
||||
tasksRunner: TasksRunner;
|
||||
}
|
||||
|
||||
export function affected(parsedArgs: YargsAffectedOptions): void {
|
||||
const target = parsedArgs.target;
|
||||
const rest: string[] = [
|
||||
...parsedArgs._.slice(1),
|
||||
...filterNxSpecificArgs(parsedArgs)
|
||||
];
|
||||
|
||||
const workspaceResults = new WorkspaceResults(target);
|
||||
|
||||
@ -70,10 +84,10 @@ export function affected(parsedArgs: YargsAffectedOptions): void {
|
||||
? getAllApps(affectedMetadata)
|
||||
: getAffectedApps(affectedMetadata)
|
||||
)
|
||||
.filter(app => !parsedArgs.exclude.includes(app))
|
||||
.filter(affectedApp => !parsedArgs.exclude.includes(affectedApp))
|
||||
.filter(
|
||||
project =>
|
||||
!parsedArgs.onlyFailed || !workspaceResults.getResult(project)
|
||||
affectedApp =>
|
||||
!parsedArgs.onlyFailed || !workspaceResults.getResult(affectedApp)
|
||||
);
|
||||
if (parsedArgs.plain) {
|
||||
console.log(apps.join(' '));
|
||||
@ -92,10 +106,10 @@ export function affected(parsedArgs: YargsAffectedOptions): void {
|
||||
? getAllLibs(affectedMetadata)
|
||||
: getAffectedLibs(affectedMetadata)
|
||||
)
|
||||
.filter(app => !parsedArgs.exclude.includes(app))
|
||||
.filter(affectedLib => !parsedArgs.exclude.includes(affectedLib))
|
||||
.filter(
|
||||
project =>
|
||||
!parsedArgs.onlyFailed || !workspaceResults.getResult(project)
|
||||
affectedLib =>
|
||||
!parsedArgs.onlyFailed || !workspaceResults.getResult(affectedLib)
|
||||
);
|
||||
|
||||
if (parsedArgs.plain) {
|
||||
@ -125,17 +139,28 @@ export function affected(parsedArgs: YargsAffectedOptions): void {
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
const nxJson = readNxJson();
|
||||
const processedArgs = processArgs(parsedArgs, nxJson);
|
||||
const projects = (parsedArgs.all
|
||||
? getAllProjectsWithTarget(affectedMetadata, target)
|
||||
: getAffectedProjectsWithTarget(affectedMetadata, target)
|
||||
? getAllProjectsWithTargetAndConfiguration(
|
||||
affectedMetadata,
|
||||
target,
|
||||
processedArgs.affectedArgs.configuration
|
||||
)
|
||||
: getAffectedProjectsWithTargetAndConfiguration(
|
||||
affectedMetadata,
|
||||
target,
|
||||
processedArgs.affectedArgs.configuration
|
||||
)
|
||||
)
|
||||
.filter(project => !parsedArgs.exclude.includes(project))
|
||||
.filter(project => !parsedArgs.exclude.includes(project.name))
|
||||
.filter(
|
||||
project =>
|
||||
!parsedArgs.onlyFailed || !workspaceResults.getResult(project)
|
||||
!parsedArgs.onlyFailed ||
|
||||
!workspaceResults.getResult(project.name)
|
||||
);
|
||||
printArgsWarning(parsedArgs);
|
||||
runCommand(target, projects, parsedArgs, rest, workspaceResults);
|
||||
runCommand(projects, affectedMetadata, processedArgs, workspaceResults);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -158,145 +183,202 @@ function printError(e: any, verbose?: boolean) {
|
||||
}
|
||||
|
||||
async function runCommand(
|
||||
targetName: string,
|
||||
projects: string[],
|
||||
parsedArgs: YargsAffectedOptions,
|
||||
args: string[],
|
||||
affectedProjects: ProjectNode[],
|
||||
affectedMetadata: AffectedMetadata,
|
||||
processedArgs: ProcessedArgs,
|
||||
workspaceResults: WorkspaceResults
|
||||
) {
|
||||
if (projects.length <= 0) {
|
||||
output.logSingleLine(
|
||||
`No affected projects to run target "${targetName}" on`
|
||||
);
|
||||
const {
|
||||
affectedArgs,
|
||||
taskOverrides,
|
||||
tasksRunnerOptions,
|
||||
tasksRunner
|
||||
} = processedArgs;
|
||||
|
||||
if (affectedProjects.length <= 0) {
|
||||
let description = `with "${affectedArgs.target}"`;
|
||||
if (affectedArgs.configuration) {
|
||||
description += ` that are configured for "${affectedArgs.configuration}"`;
|
||||
}
|
||||
output.logSingleLine(`No projects ${description} were affected`);
|
||||
return;
|
||||
}
|
||||
|
||||
const cli = cliCommand();
|
||||
|
||||
const bodyLines = projects.map(
|
||||
project => `${output.colors.gray('-')} ${project}`
|
||||
const bodyLines = affectedProjects.map(
|
||||
affectedProject => `${output.colors.gray('-')} ${affectedProject.name}`
|
||||
);
|
||||
if (args.length > 0) {
|
||||
if (Object.keys(taskOverrides).length > 0) {
|
||||
bodyLines.push('');
|
||||
bodyLines.push(
|
||||
`${output.colors.gray('With flags:')} ${output.bold(args.join(' '))}`
|
||||
);
|
||||
bodyLines.push(`${output.colors.gray('With flags:')}`);
|
||||
Object.entries(taskOverrides)
|
||||
.map(([flag, value]) => ` --${flag}=${value}`)
|
||||
.forEach(arg => bodyLines.push(arg));
|
||||
}
|
||||
|
||||
output.log({
|
||||
title: `${output.colors.gray(
|
||||
'Running target'
|
||||
)} ${targetName} ${output.colors.gray('for projects:')}`,
|
||||
title: `${output.colors.gray('Running target')} ${
|
||||
affectedArgs.target
|
||||
} ${output.colors.gray('for projects:')}`,
|
||||
bodyLines
|
||||
});
|
||||
|
||||
output.addVerticalSeparator();
|
||||
|
||||
const workspaceJson = readWorkspaceJson();
|
||||
const projectMetadata = new Map<string, any>();
|
||||
projects.forEach(project => {
|
||||
projectMetadata.set(project, workspaceJson.projects[project]);
|
||||
});
|
||||
|
||||
// Make sure the `package.json` has the `nx: "nx"` command needed by `npm-run-all`
|
||||
const packageJson = JSON.parse(
|
||||
fs.readFileSync('./package.json').toString('utf-8')
|
||||
);
|
||||
if (!packageJson.scripts || !packageJson.scripts[cli]) {
|
||||
output.error({
|
||||
title: `The "scripts" section of your 'package.json' must contain "${cli}": "${cli}"`,
|
||||
bodyLines: [
|
||||
output.colors.gray('...'),
|
||||
' "scripts": {',
|
||||
output.colors.gray(' ...'),
|
||||
` "${cli}": "${cli}"`,
|
||||
output.colors.gray(' ...'),
|
||||
' }',
|
||||
output.colors.gray('...')
|
||||
]
|
||||
});
|
||||
return process.exit(1);
|
||||
}
|
||||
|
||||
try {
|
||||
const isYarn = path
|
||||
.basename(process.env.npm_execpath || 'npm')
|
||||
.startsWith('yarn');
|
||||
await runAll(
|
||||
projects.map(proj => {
|
||||
return commonCommands.includes(targetName)
|
||||
? `${cli} ${isYarn ? '' : '--'} ${targetName} ${proj} ${transformArgs(
|
||||
args,
|
||||
proj,
|
||||
projectMetadata.get(proj)
|
||||
).join(' ')} `
|
||||
: `${cli} ${
|
||||
isYarn ? '' : '--'
|
||||
} run ${proj}:${targetName} ${transformArgs(
|
||||
args,
|
||||
proj,
|
||||
projectMetadata.get(proj)
|
||||
).join(' ')} `;
|
||||
}),
|
||||
{
|
||||
parallel: parsedArgs.parallel || false,
|
||||
maxParallel: parsedArgs.maxParallel || 1,
|
||||
continueOnError: true,
|
||||
stdin: process.stdin,
|
||||
stdout: process.stdout,
|
||||
stderr: process.stderr
|
||||
}
|
||||
);
|
||||
|
||||
projects.forEach(project => {
|
||||
workspaceResults.success(project);
|
||||
});
|
||||
} catch (e) {
|
||||
e.results.forEach((result, i) => {
|
||||
if (result.code === 0) {
|
||||
workspaceResults.success(projects[i]);
|
||||
} else {
|
||||
workspaceResults.fail(projects[i]);
|
||||
}
|
||||
});
|
||||
} finally {
|
||||
// fix for https://github.com/nrwl/nx/issues/1666
|
||||
if (process.stdin['unref']) (process.stdin as any).unref();
|
||||
}
|
||||
|
||||
workspaceResults.saveResults();
|
||||
workspaceResults.printResults(
|
||||
parsedArgs.onlyFailed,
|
||||
`Running target "${targetName}" for affected projects succeeded`,
|
||||
`Running target "${targetName}" for affected projects failed`
|
||||
const tasks: Task[] = affectedProjects.map(affectedProject =>
|
||||
createTask({
|
||||
project: affectedProject,
|
||||
target: processedArgs.affectedArgs.target,
|
||||
configuration: processedArgs.affectedArgs.configuration,
|
||||
overrides: processedArgs.taskOverrides
|
||||
})
|
||||
);
|
||||
|
||||
if (workspaceResults.hasFailure) {
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
function transformArgs(
|
||||
args: string[],
|
||||
projectName: string,
|
||||
projectMetadata: any
|
||||
) {
|
||||
return args.map(arg => {
|
||||
const regex = /{project\.([^}]+)}/g;
|
||||
return arg.replace(regex, (_, group: string) => {
|
||||
if (group.includes('.')) {
|
||||
throw new Error('Only top-level properties can be interpolated');
|
||||
const tasksMap: {
|
||||
[projectName: string]: { [targetName: string]: Task };
|
||||
} = {};
|
||||
Object.entries(affectedMetadata.dependencyGraph.projects).forEach(
|
||||
([projectName, project]) => {
|
||||
if (
|
||||
projectHasTargetAndConfiguration(
|
||||
project,
|
||||
processedArgs.affectedArgs.target,
|
||||
processedArgs.affectedArgs.configuration
|
||||
)
|
||||
) {
|
||||
tasksMap[projectName] = {
|
||||
[processedArgs.affectedArgs.target]: createTask({
|
||||
project: project,
|
||||
target: processedArgs.affectedArgs.target,
|
||||
configuration: processedArgs.affectedArgs.configuration,
|
||||
overrides: processedArgs.taskOverrides
|
||||
})
|
||||
};
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if (group === 'name') {
|
||||
return projectName;
|
||||
tasksRunner(tasks, tasksRunnerOptions, {
|
||||
dependencyGraph: affectedMetadata.dependencyGraph,
|
||||
tasksMap
|
||||
}).subscribe({
|
||||
next: (event: TaskCompleteEvent) => {
|
||||
switch (event.type) {
|
||||
case AffectedEventType.TaskComplete: {
|
||||
workspaceResults.setResult(event.task.target.project, event.success);
|
||||
}
|
||||
}
|
||||
return projectMetadata[group];
|
||||
});
|
||||
},
|
||||
error: console.error,
|
||||
complete: () => {
|
||||
// fix for https://github.com/nrwl/nx/issues/1666
|
||||
if (process.stdin['unref']) (process.stdin as any).unref();
|
||||
|
||||
workspaceResults.saveResults();
|
||||
workspaceResults.printResults(
|
||||
affectedArgs.onlyFailed,
|
||||
`Running target "${affectedArgs.target}" for affected projects succeeded`,
|
||||
`Running target "${affectedArgs.target}" for affected projects failed`
|
||||
);
|
||||
|
||||
if (workspaceResults.hasFailure) {
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function filterNxSpecificArgs(parsedArgs: YargsAffectedOptions): string[] {
|
||||
function createTask({
|
||||
project,
|
||||
target,
|
||||
configuration,
|
||||
overrides
|
||||
}: {
|
||||
project: ProjectNode;
|
||||
target: string;
|
||||
configuration: string;
|
||||
overrides: Object;
|
||||
}): Task {
|
||||
return {
|
||||
id: getTaskId({
|
||||
project: project.name,
|
||||
target: target,
|
||||
configuration: configuration
|
||||
}),
|
||||
target: {
|
||||
project: project.name,
|
||||
target,
|
||||
configuration
|
||||
},
|
||||
overrides: interpolateOverrides(overrides, project.name, project)
|
||||
};
|
||||
}
|
||||
|
||||
function getTaskId({
|
||||
project,
|
||||
target,
|
||||
configuration
|
||||
}: {
|
||||
project: string;
|
||||
target: string;
|
||||
configuration?: string;
|
||||
}): string {
|
||||
let id = project + ':' + target;
|
||||
if (configuration) {
|
||||
id += ':' + configuration;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
function getTasksRunner(
|
||||
runner: string | undefined,
|
||||
nxJson: NxJson
|
||||
): {
|
||||
tasksRunner: TasksRunner;
|
||||
options: unknown;
|
||||
} {
|
||||
if (!nxJson.tasksRunnerOptions) {
|
||||
return {
|
||||
tasksRunner: defaultTasksRunner,
|
||||
options: {}
|
||||
};
|
||||
}
|
||||
|
||||
if (!runner && !nxJson.tasksRunnerOptions.default) {
|
||||
return {
|
||||
tasksRunner: defaultTasksRunner,
|
||||
options: {}
|
||||
};
|
||||
}
|
||||
|
||||
runner = runner || 'default';
|
||||
|
||||
if (nxJson.tasksRunnerOptions[runner]) {
|
||||
let modulePath: string = nxJson.tasksRunnerOptions[runner].runner;
|
||||
if (isRelativePath(modulePath)) {
|
||||
modulePath = join(appRootPath, modulePath);
|
||||
}
|
||||
return {
|
||||
tasksRunner: require(modulePath),
|
||||
options: nxJson.tasksRunnerOptions[runner].options
|
||||
};
|
||||
} else {
|
||||
throw new Error(`Could not find runner configuration for ${runner}`);
|
||||
}
|
||||
}
|
||||
|
||||
function getNxSpecificOptions(
|
||||
parsedArgs: YargsAffectedOptions
|
||||
): YargsAffectedOptions {
|
||||
const filteredArgs = {};
|
||||
nxSpecificFlags.forEach(flag => {
|
||||
filteredArgs[flag] = parsedArgs[flag];
|
||||
});
|
||||
return filteredArgs as YargsAffectedOptions;
|
||||
}
|
||||
|
||||
function getNonNxSpecificOptions(
|
||||
parsedArgs: YargsAffectedOptions
|
||||
): YargsAffectedOptions {
|
||||
const filteredArgs = { ...parsedArgs };
|
||||
// Delete Nx arguments from parsed Args
|
||||
nxSpecificFlags.forEach(flag => {
|
||||
@ -308,18 +390,54 @@ function filterNxSpecificArgs(parsedArgs: YargsAffectedOptions): string[] {
|
||||
// Also remove the node path
|
||||
delete filteredArgs.$0;
|
||||
|
||||
// Re-serialize into a list of args
|
||||
return Object.keys(filteredArgs).map(filteredArg => {
|
||||
if (!Array.isArray(filteredArgs[filteredArg])) {
|
||||
filteredArgs[filteredArg] = [filteredArgs[filteredArg]];
|
||||
}
|
||||
return filteredArgs;
|
||||
}
|
||||
|
||||
return filteredArgs[filteredArg]
|
||||
.map(value => {
|
||||
return `--${filteredArg}=${value}`;
|
||||
})
|
||||
.join(' ');
|
||||
export function processArgs(
|
||||
parsedArgs: YargsAffectedOptions,
|
||||
nxJson: NxJson
|
||||
): ProcessedArgs {
|
||||
const affectedArgs = getNxSpecificOptions(parsedArgs);
|
||||
const { tasksRunner, options: configOptions } = getTasksRunner(
|
||||
affectedArgs.runner,
|
||||
nxJson
|
||||
);
|
||||
const tasksRunnerOptions = {
|
||||
...configOptions,
|
||||
...getNonNxSpecificOptions(parsedArgs)
|
||||
};
|
||||
const taskOverrides = yargsParser(parsedArgs._.slice(1));
|
||||
delete taskOverrides._;
|
||||
return {
|
||||
affectedArgs,
|
||||
taskOverrides,
|
||||
tasksRunner,
|
||||
tasksRunnerOptions: tasksRunnerOptions
|
||||
};
|
||||
}
|
||||
|
||||
function interpolateOverrides<T = any>(
|
||||
args: T,
|
||||
projectName: string,
|
||||
projectMetadata: any
|
||||
): T {
|
||||
const interpolatedArgs: T = { ...args };
|
||||
Object.entries(interpolatedArgs).forEach(([name, value]) => {
|
||||
if (typeof value === 'string') {
|
||||
const regex = /{project\.([^}]+)}/g;
|
||||
interpolatedArgs[name] = value.replace(regex, (_, group: string) => {
|
||||
if (group.includes('.')) {
|
||||
throw new Error('Only top-level properties can be interpolated');
|
||||
}
|
||||
|
||||
if (group === 'name') {
|
||||
return projectName;
|
||||
}
|
||||
return projectMetadata[group];
|
||||
});
|
||||
}
|
||||
});
|
||||
return interpolatedArgs;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -329,13 +447,12 @@ function filterNxSpecificArgs(parsedArgs: YargsAffectedOptions): string[] {
|
||||
*/
|
||||
const dummyOptions: AffectedOptions = {
|
||||
target: '',
|
||||
parallel: false,
|
||||
maxParallel: 3,
|
||||
'max-parallel': false,
|
||||
configuration: '',
|
||||
onlyFailed: false,
|
||||
'only-failed': false,
|
||||
untracked: false,
|
||||
uncommitted: false,
|
||||
runner: '',
|
||||
help: false,
|
||||
version: false,
|
||||
quiet: false,
|
||||
|
||||
@ -254,6 +254,15 @@ function withAffectedOptions(yargs: yargs.Argv): yargs.Argv {
|
||||
coerce: parseCSV,
|
||||
default: []
|
||||
})
|
||||
.options('runner', {
|
||||
describe: 'This is the name of the tasks runner configured in nx.json',
|
||||
type: 'string'
|
||||
})
|
||||
.options('configuration', {
|
||||
describe:
|
||||
'This is the configuration to use when performing tasks on projects',
|
||||
type: 'string'
|
||||
})
|
||||
.options('only-failed', {
|
||||
describe: 'Isolate projects which previously failed',
|
||||
type: 'boolean',
|
||||
|
||||
@ -24,6 +24,12 @@ export interface NxJson {
|
||||
projects: {
|
||||
[projectName: string]: NxJsonProjectConfig;
|
||||
};
|
||||
tasksRunnerOptions?: {
|
||||
[tasksRunnerName: string]: {
|
||||
runner: string;
|
||||
options?: unknown;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export interface NxJsonProjectConfig {
|
||||
@ -443,6 +449,7 @@ export function createAffectedMetadata(
|
||||
): AffectedMetadata {
|
||||
const projectStates: ProjectStates = {};
|
||||
const projects: ProjectMap = {};
|
||||
|
||||
projectNodes.forEach(project => {
|
||||
projectStates[project.name] = {
|
||||
touched: false,
|
||||
|
||||
@ -22,7 +22,7 @@ describe('WorkspacesResults', () => {
|
||||
|
||||
describe('success', () => {
|
||||
it('should return true when getting results', () => {
|
||||
results.success('proj');
|
||||
results.setResult('proj', true);
|
||||
|
||||
expect(results.getResult('proj')).toBe(true);
|
||||
});
|
||||
@ -32,7 +32,7 @@ describe('WorkspacesResults', () => {
|
||||
spyOn(fs, 'unlinkSync');
|
||||
spyOn(fs, 'existsSync').and.returnValue(true);
|
||||
|
||||
results.success('proj');
|
||||
results.setResult('proj', true);
|
||||
results.saveResults();
|
||||
|
||||
expect(fs.writeSync).not.toHaveBeenCalled();
|
||||
@ -41,7 +41,7 @@ describe('WorkspacesResults', () => {
|
||||
|
||||
it('should print results', () => {
|
||||
const projectName = 'proj';
|
||||
results.success(projectName);
|
||||
results.setResult(projectName, true);
|
||||
spyOn(output, 'success');
|
||||
|
||||
const successTitle = 'Success';
|
||||
@ -60,7 +60,7 @@ describe('WorkspacesResults', () => {
|
||||
spyOn(output, 'success');
|
||||
spyOn(output, 'warn');
|
||||
|
||||
results.success(projectName);
|
||||
results.setResult(projectName, true);
|
||||
|
||||
const successTitle = 'Success';
|
||||
|
||||
@ -85,7 +85,7 @@ describe('WorkspacesResults', () => {
|
||||
|
||||
describe('fail', () => {
|
||||
it('should return false when getting results', () => {
|
||||
results.fail('proj');
|
||||
results.setResult('proj', false);
|
||||
|
||||
expect(results.getResult('proj')).toBe(false);
|
||||
});
|
||||
@ -93,7 +93,7 @@ describe('WorkspacesResults', () => {
|
||||
it('should save results to file system', () => {
|
||||
spyOn(fs, 'writeFileSync');
|
||||
|
||||
results.fail('proj');
|
||||
results.setResult('proj', false);
|
||||
results.saveResults();
|
||||
|
||||
expect(fs.writeFileSync).toHaveBeenCalledWith(
|
||||
@ -109,7 +109,7 @@ describe('WorkspacesResults', () => {
|
||||
|
||||
it('should print results', () => {
|
||||
const projectName = 'proj';
|
||||
results.fail(projectName);
|
||||
results.setResult(projectName, false);
|
||||
spyOn(output, 'error');
|
||||
|
||||
const errorTitle = 'Fail';
|
||||
@ -128,7 +128,7 @@ describe('WorkspacesResults', () => {
|
||||
|
||||
it('should tell the user that they can isolate only the failed tests', () => {
|
||||
const projectName = 'proj';
|
||||
results.fail(projectName);
|
||||
results.setResult(projectName, false);
|
||||
spyOn(output, 'error');
|
||||
|
||||
const errorTitle = 'Fail';
|
||||
|
||||
@ -51,14 +51,6 @@ export class WorkspaceResults {
|
||||
return this.commandResults.results[projectName];
|
||||
}
|
||||
|
||||
fail(projectName: string) {
|
||||
this.setResult(projectName, false);
|
||||
}
|
||||
|
||||
success(projectName: string) {
|
||||
this.setResult(projectName, true);
|
||||
}
|
||||
|
||||
saveResults() {
|
||||
if (Object.values<boolean>(this.commandResults.results).includes(false)) {
|
||||
writeJsonFile(RESULTS_FILE, this.commandResults);
|
||||
@ -120,7 +112,7 @@ export class WorkspaceResults {
|
||||
});
|
||||
}
|
||||
|
||||
private setResult(projectName: string, result: boolean) {
|
||||
setResult(projectName: string, result: boolean) {
|
||||
this.commandResults.results[projectName] = result;
|
||||
}
|
||||
}
|
||||
|
||||
189
packages/workspace/src/tasks-runner/default-tasks-runner.spec.ts
Normal file
189
packages/workspace/src/tasks-runner/default-tasks-runner.spec.ts
Normal file
@ -0,0 +1,189 @@
|
||||
import defaultTasksRunner from './default-tasks-runner';
|
||||
import { AffectedEventType, Task } from './tasks-runner';
|
||||
jest.mock('npm-run-all', () => jest.fn());
|
||||
import * as runAll from 'npm-run-all';
|
||||
jest.mock('../command-line/shared', () => ({
|
||||
cliCommand: () => 'nx'
|
||||
}));
|
||||
jest.mock('../utils/fileutils', () => ({
|
||||
readJsonFile: () => ({
|
||||
scripts: {
|
||||
nx: 'nx'
|
||||
}
|
||||
})
|
||||
}));
|
||||
|
||||
describe('defaultTasksRunner', () => {
|
||||
let tasks: Task[];
|
||||
beforeEach(() => {
|
||||
tasks = [
|
||||
{
|
||||
id: 'task-1',
|
||||
target: {
|
||||
project: 'app-1',
|
||||
target: 'target'
|
||||
},
|
||||
overrides: {}
|
||||
},
|
||||
{
|
||||
id: 'task-2',
|
||||
target: {
|
||||
project: 'app-2',
|
||||
target: 'target'
|
||||
},
|
||||
overrides: {}
|
||||
}
|
||||
];
|
||||
});
|
||||
|
||||
it('should run the correct commands through "npm-run-all"', done => {
|
||||
runAll.mockImplementation(() => Promise.resolve());
|
||||
defaultTasksRunner(tasks, {}).subscribe({
|
||||
complete: () => {
|
||||
expect(runAll).toHaveBeenCalledWith(
|
||||
['nx run app-1:target', 'nx run app-2:target'],
|
||||
jasmine.anything()
|
||||
);
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should run the correct commands through "npm-run-all" when tasks have a configuration', done => {
|
||||
runAll.mockImplementation(() => Promise.resolve());
|
||||
tasks = tasks.map(task => {
|
||||
task.target.configuration = 'production';
|
||||
return task;
|
||||
});
|
||||
defaultTasksRunner(tasks, {}).subscribe({
|
||||
complete: () => {
|
||||
expect(runAll).toHaveBeenCalledWith(
|
||||
['nx run app-1:target:production', 'nx run app-2:target:production'],
|
||||
jasmine.anything()
|
||||
);
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should run the correct commands through "npm-run-all" when tasks have overrides', done => {
|
||||
runAll.mockImplementation(() => Promise.resolve());
|
||||
tasks = tasks.map(task => {
|
||||
task.overrides = {
|
||||
override: 'override-value'
|
||||
};
|
||||
return task;
|
||||
});
|
||||
defaultTasksRunner(tasks, {}).subscribe({
|
||||
complete: () => {
|
||||
expect(runAll).toHaveBeenCalledWith(
|
||||
[
|
||||
'nx run app-1:target --override=override-value',
|
||||
'nx run app-2:target --override=override-value'
|
||||
],
|
||||
jasmine.anything()
|
||||
);
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should run the correct commands through "npm-run-all" when tasks have configurations and overrides', done => {
|
||||
runAll.mockImplementation(() => Promise.resolve());
|
||||
tasks = tasks.map(task => {
|
||||
task.target.configuration = 'production';
|
||||
task.overrides = {
|
||||
override: 'override-value'
|
||||
};
|
||||
return task;
|
||||
});
|
||||
defaultTasksRunner(tasks, {}).subscribe({
|
||||
complete: () => {
|
||||
expect(runAll).toHaveBeenCalledWith(
|
||||
[
|
||||
'nx run app-1:target:production --override=override-value',
|
||||
'nx run app-2:target:production --override=override-value'
|
||||
],
|
||||
jasmine.anything()
|
||||
);
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should pass the right options when options are passed', done => {
|
||||
runAll.mockImplementation(() => Promise.resolve());
|
||||
defaultTasksRunner(tasks, {
|
||||
parallel: true,
|
||||
maxParallel: 5
|
||||
}).subscribe({
|
||||
complete: () => {
|
||||
expect(runAll).toHaveBeenCalledWith(
|
||||
jasmine.any(Array),
|
||||
jasmine.objectContaining({
|
||||
parallel: true,
|
||||
maxParallel: 5
|
||||
})
|
||||
);
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should run emit task complete events when "run-all-prerender" resolves', done => {
|
||||
runAll.mockImplementation(() => Promise.resolve());
|
||||
let i = 0;
|
||||
const expected = [
|
||||
{
|
||||
task: tasks[0],
|
||||
type: AffectedEventType.TaskComplete,
|
||||
success: true
|
||||
},
|
||||
{
|
||||
task: tasks[1],
|
||||
type: AffectedEventType.TaskComplete,
|
||||
success: true
|
||||
}
|
||||
];
|
||||
defaultTasksRunner(tasks, {}).subscribe({
|
||||
next: event => {
|
||||
expect(event).toEqual(expected[i++]);
|
||||
},
|
||||
complete: done
|
||||
});
|
||||
});
|
||||
|
||||
it('should run emit task complete events when "run-all-prerender" rejects', done => {
|
||||
runAll.mockImplementation(() =>
|
||||
Promise.reject({
|
||||
results: [
|
||||
{
|
||||
code: 0
|
||||
},
|
||||
{
|
||||
code: 1
|
||||
}
|
||||
]
|
||||
})
|
||||
);
|
||||
let i = 0;
|
||||
const expected = [
|
||||
{
|
||||
task: tasks[0],
|
||||
type: AffectedEventType.TaskComplete,
|
||||
success: true
|
||||
},
|
||||
{
|
||||
task: tasks[1],
|
||||
type: AffectedEventType.TaskComplete,
|
||||
success: false
|
||||
}
|
||||
];
|
||||
defaultTasksRunner(tasks, {}).subscribe({
|
||||
next: event => {
|
||||
expect(event).toEqual(expected[i++]);
|
||||
},
|
||||
complete: done
|
||||
});
|
||||
});
|
||||
});
|
||||
121
packages/workspace/src/tasks-runner/default-tasks-runner.ts
Normal file
121
packages/workspace/src/tasks-runner/default-tasks-runner.ts
Normal file
@ -0,0 +1,121 @@
|
||||
import * as runAll from 'npm-run-all';
|
||||
import { Observable } from 'rxjs';
|
||||
import { basename } from 'path';
|
||||
import {
|
||||
AffectedEventType,
|
||||
Task,
|
||||
TaskCompleteEvent,
|
||||
TasksRunner
|
||||
} from './tasks-runner';
|
||||
import { cliCommand } from '../command-line/shared';
|
||||
import { output } from '../command-line/output';
|
||||
import { readJsonFile } from '../utils/fileutils';
|
||||
|
||||
const commonCommands = ['build', 'test', 'lint', 'e2e', 'deploy'];
|
||||
|
||||
export interface DefaultTasksRunnerOptions {
|
||||
parallel?: boolean;
|
||||
maxParallel?: number;
|
||||
}
|
||||
|
||||
export const defaultTasksRunner: TasksRunner<DefaultTasksRunnerOptions> = (
|
||||
tasks: Task[],
|
||||
options: DefaultTasksRunnerOptions
|
||||
): Observable<TaskCompleteEvent> => {
|
||||
const additionalTaskOverrides = getLegacyTaskOverrides(options);
|
||||
tasks.forEach(task => {
|
||||
task.overrides = {
|
||||
...task.overrides,
|
||||
...additionalTaskOverrides
|
||||
};
|
||||
});
|
||||
const commands = getCommands(tasks);
|
||||
return new Observable(subscriber => {
|
||||
runAll(commands, {
|
||||
parallel: options.parallel || false,
|
||||
maxParallel: options.maxParallel || 3,
|
||||
continueOnError: true,
|
||||
stdin: process.stdin,
|
||||
stdout: process.stdout,
|
||||
stderr: process.stderr
|
||||
})
|
||||
.then(() => {
|
||||
tasks.forEach(task => {
|
||||
subscriber.next({
|
||||
task: task,
|
||||
type: AffectedEventType.TaskComplete,
|
||||
success: true
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch(e => {
|
||||
e.results.forEach((result, i) => {
|
||||
subscriber.next({
|
||||
task: tasks[i],
|
||||
type: AffectedEventType.TaskComplete,
|
||||
success: result.code === 0
|
||||
});
|
||||
});
|
||||
})
|
||||
.finally(() => {
|
||||
subscriber.complete();
|
||||
// fix for https://github.com/nrwl/nx/issues/1666
|
||||
if (process.stdin['unref']) (process.stdin as any).unref();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export default defaultTasksRunner;
|
||||
|
||||
function getLegacyTaskOverrides(options: any) {
|
||||
const legacyTaskOverrides = { ...options };
|
||||
delete legacyTaskOverrides.maxParallel;
|
||||
delete legacyTaskOverrides['max-parallel'];
|
||||
delete legacyTaskOverrides.parallel;
|
||||
delete legacyTaskOverrides.verbose;
|
||||
return legacyTaskOverrides;
|
||||
}
|
||||
|
||||
function getCommands(tasks: Task[]) {
|
||||
const cli = cliCommand();
|
||||
assertPackageJsonScriptExists(cli);
|
||||
const isYarn = basename(process.env.npm_execpath || 'npm').startsWith('yarn');
|
||||
return tasks.map(task => {
|
||||
const args = Object.entries(task.overrides)
|
||||
.map(([prop, value]) => `--${prop}=${value}`)
|
||||
.join(' ');
|
||||
return commonCommands.includes(task.target.target)
|
||||
? `${cli}${isYarn ? '' : ' --'} ${task.target.target} ${
|
||||
task.target.project
|
||||
} ${
|
||||
task.target.configuration
|
||||
? `--configuration ${task.target.configuration} `
|
||||
: ''
|
||||
}${args}`
|
||||
: `${cli}${isYarn ? '' : ' --'} run ${task.target.project}:${
|
||||
task.target.target
|
||||
}${task.target.configuration ? `:${task.target.configuration}` : ''}${
|
||||
args ? ' ' + args : ''
|
||||
}`;
|
||||
});
|
||||
}
|
||||
|
||||
function assertPackageJsonScriptExists(cli: string) {
|
||||
// Make sure the `package.json` has the `nx: "nx"` command needed by `npm-run-all`
|
||||
const packageJson = readJsonFile('./package.json');
|
||||
if (!packageJson.scripts || !packageJson.scripts[cli]) {
|
||||
output.error({
|
||||
title: `The "scripts" section of your 'package.json' must contain "${cli}": "${cli}"`,
|
||||
bodyLines: [
|
||||
output.colors.gray('...'),
|
||||
' "scripts": {',
|
||||
output.colors.gray(' ...'),
|
||||
` "${cli}": "${cli}"`,
|
||||
output.colors.gray(' ...'),
|
||||
' }',
|
||||
output.colors.gray('...')
|
||||
]
|
||||
});
|
||||
return process.exit(1);
|
||||
}
|
||||
}
|
||||
37
packages/workspace/src/tasks-runner/tasks-runner.ts
Normal file
37
packages/workspace/src/tasks-runner/tasks-runner.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import { Observable } from 'rxjs';
|
||||
import { Target } from '@angular-devkit/architect';
|
||||
|
||||
import { DependencyGraph } from '../command-line/shared';
|
||||
|
||||
export interface Task {
|
||||
id: string;
|
||||
target: Target;
|
||||
overrides: Object;
|
||||
}
|
||||
|
||||
export enum AffectedEventType {
|
||||
TaskComplete = '[Task] Complete'
|
||||
}
|
||||
|
||||
export interface AffectedEvent {
|
||||
task: Task;
|
||||
type: AffectedEventType;
|
||||
}
|
||||
|
||||
export interface TaskCompleteEvent extends AffectedEvent {
|
||||
type: AffectedEventType.TaskComplete;
|
||||
success: boolean;
|
||||
}
|
||||
|
||||
export type TasksRunner<T = unknown> = (
|
||||
tasks: Task[],
|
||||
options?: T,
|
||||
context?: {
|
||||
dependencyGraph: DependencyGraph;
|
||||
tasksMap: {
|
||||
[projectName: string]: {
|
||||
[targetName: string]: Task;
|
||||
};
|
||||
};
|
||||
}
|
||||
) => Observable<AffectedEvent>;
|
||||
@ -123,3 +123,7 @@ export function renameSync(
|
||||
cb(e);
|
||||
}
|
||||
}
|
||||
|
||||
export function isRelativePath(path: string): boolean {
|
||||
return path.startsWith('./') || path.startsWith('../');
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user