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)
|
Base of the current branch (usually master)
|
||||||
|
|
||||||
|
### configuration
|
||||||
|
|
||||||
|
This is the configuration to use when performing tasks on projects
|
||||||
|
|
||||||
### exclude
|
### exclude
|
||||||
|
|
||||||
Default: ``
|
Default: ``
|
||||||
@ -68,6 +72,10 @@ Isolate projects which previously failed
|
|||||||
|
|
||||||
Produces a plain output for affected:apps and affected:libs
|
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
|
||||||
|
|
||||||
Uncommitted changes
|
Uncommitted changes
|
||||||
|
|||||||
@ -58,6 +58,10 @@ All projects
|
|||||||
|
|
||||||
Base of the current branch (usually master)
|
Base of the current branch (usually master)
|
||||||
|
|
||||||
|
### configuration
|
||||||
|
|
||||||
|
This is the configuration to use when performing tasks on projects
|
||||||
|
|
||||||
### exclude
|
### exclude
|
||||||
|
|
||||||
Default: ``
|
Default: ``
|
||||||
@ -98,6 +102,10 @@ Parallelize the command
|
|||||||
|
|
||||||
Produces a plain output for affected:apps and affected:libs
|
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
|
||||||
|
|
||||||
Uncommitted changes
|
Uncommitted changes
|
||||||
|
|||||||
@ -46,6 +46,10 @@ All projects
|
|||||||
|
|
||||||
Base of the current branch (usually master)
|
Base of the current branch (usually master)
|
||||||
|
|
||||||
|
### configuration
|
||||||
|
|
||||||
|
This is the configuration to use when performing tasks on projects
|
||||||
|
|
||||||
### exclude
|
### exclude
|
||||||
|
|
||||||
Default: ``
|
Default: ``
|
||||||
@ -78,6 +82,10 @@ Isolate projects which previously failed
|
|||||||
|
|
||||||
Produces a plain output for affected:apps and affected:libs
|
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
|
||||||
|
|
||||||
Uncommitted changes
|
Uncommitted changes
|
||||||
|
|||||||
@ -58,6 +58,10 @@ All projects
|
|||||||
|
|
||||||
Base of the current branch (usually master)
|
Base of the current branch (usually master)
|
||||||
|
|
||||||
|
### configuration
|
||||||
|
|
||||||
|
This is the configuration to use when performing tasks on projects
|
||||||
|
|
||||||
### exclude
|
### exclude
|
||||||
|
|
||||||
Default: ``
|
Default: ``
|
||||||
@ -98,6 +102,10 @@ Parallelize the command
|
|||||||
|
|
||||||
Produces a plain output for affected:apps and affected:libs
|
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
|
||||||
|
|
||||||
Uncommitted changes
|
Uncommitted changes
|
||||||
|
|||||||
@ -40,6 +40,10 @@ All projects
|
|||||||
|
|
||||||
Base of the current branch (usually master)
|
Base of the current branch (usually master)
|
||||||
|
|
||||||
|
### configuration
|
||||||
|
|
||||||
|
This is the configuration to use when performing tasks on projects
|
||||||
|
|
||||||
### exclude
|
### exclude
|
||||||
|
|
||||||
Default: ``
|
Default: ``
|
||||||
@ -68,6 +72,10 @@ Isolate projects which previously failed
|
|||||||
|
|
||||||
Produces a plain output for affected:apps and affected:libs
|
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
|
||||||
|
|
||||||
Uncommitted changes
|
Uncommitted changes
|
||||||
|
|||||||
@ -58,6 +58,10 @@ All projects
|
|||||||
|
|
||||||
Base of the current branch (usually master)
|
Base of the current branch (usually master)
|
||||||
|
|
||||||
|
### configuration
|
||||||
|
|
||||||
|
This is the configuration to use when performing tasks on projects
|
||||||
|
|
||||||
### exclude
|
### exclude
|
||||||
|
|
||||||
Default: ``
|
Default: ``
|
||||||
@ -98,6 +102,10 @@ Parallelize the command
|
|||||||
|
|
||||||
Produces a plain output for affected:apps and affected:libs
|
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
|
||||||
|
|
||||||
Uncommitted changes
|
Uncommitted changes
|
||||||
|
|||||||
@ -58,6 +58,10 @@ All projects
|
|||||||
|
|
||||||
Base of the current branch (usually master)
|
Base of the current branch (usually master)
|
||||||
|
|
||||||
|
### configuration
|
||||||
|
|
||||||
|
This is the configuration to use when performing tasks on projects
|
||||||
|
|
||||||
### exclude
|
### exclude
|
||||||
|
|
||||||
Default: ``
|
Default: ``
|
||||||
@ -98,6 +102,10 @@ Parallelize the command
|
|||||||
|
|
||||||
Produces a plain output for affected:apps and affected:libs
|
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
|
||||||
|
|
||||||
Uncommitted changes
|
Uncommitted changes
|
||||||
|
|||||||
@ -64,6 +64,10 @@ All projects
|
|||||||
|
|
||||||
Base of the current branch (usually master)
|
Base of the current branch (usually master)
|
||||||
|
|
||||||
|
### configuration
|
||||||
|
|
||||||
|
This is the configuration to use when performing tasks on projects
|
||||||
|
|
||||||
### exclude
|
### exclude
|
||||||
|
|
||||||
Default: ``
|
Default: ``
|
||||||
@ -104,6 +108,10 @@ Parallelize the command
|
|||||||
|
|
||||||
Produces a plain output for affected:apps and affected:libs
|
Produces a plain output for affected:apps and affected:libs
|
||||||
|
|
||||||
|
### runner
|
||||||
|
|
||||||
|
This is the name of the tasks runner configured in nx.json
|
||||||
|
|
||||||
### target
|
### target
|
||||||
|
|
||||||
Task to run for affected projects
|
Task to run for affected projects
|
||||||
|
|||||||
@ -22,6 +22,10 @@ All projects
|
|||||||
|
|
||||||
Base of the current branch (usually master)
|
Base of the current branch (usually master)
|
||||||
|
|
||||||
|
### configuration
|
||||||
|
|
||||||
|
This is the configuration to use when performing tasks on projects
|
||||||
|
|
||||||
### exclude
|
### exclude
|
||||||
|
|
||||||
Default: ``
|
Default: ``
|
||||||
@ -50,6 +54,10 @@ Isolate projects which previously failed
|
|||||||
|
|
||||||
Produces a plain output for affected:apps and affected:libs
|
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
|
||||||
|
|
||||||
Uncommitted changes
|
Uncommitted changes
|
||||||
|
|||||||
@ -22,6 +22,10 @@ All projects
|
|||||||
|
|
||||||
Base of the current branch (usually master)
|
Base of the current branch (usually master)
|
||||||
|
|
||||||
|
### configuration
|
||||||
|
|
||||||
|
This is the configuration to use when performing tasks on projects
|
||||||
|
|
||||||
### exclude
|
### exclude
|
||||||
|
|
||||||
Default: ``
|
Default: ``
|
||||||
@ -50,6 +54,10 @@ Isolate projects which previously failed
|
|||||||
|
|
||||||
Produces a plain output for affected:apps and affected:libs
|
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
|
||||||
|
|
||||||
Uncommitted changes
|
Uncommitted changes
|
||||||
|
|||||||
@ -40,6 +40,10 @@ All projects
|
|||||||
|
|
||||||
Base of the current branch (usually master)
|
Base of the current branch (usually master)
|
||||||
|
|
||||||
|
### configuration
|
||||||
|
|
||||||
|
This is the configuration to use when performing tasks on projects
|
||||||
|
|
||||||
### exclude
|
### exclude
|
||||||
|
|
||||||
Default: ``
|
Default: ``
|
||||||
@ -68,6 +72,10 @@ Isolate projects which previously failed
|
|||||||
|
|
||||||
Produces a plain output for affected:apps and affected:libs
|
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
|
||||||
|
|
||||||
Uncommitted changes
|
Uncommitted changes
|
||||||
|
|||||||
@ -58,6 +58,10 @@ All projects
|
|||||||
|
|
||||||
Base of the current branch (usually master)
|
Base of the current branch (usually master)
|
||||||
|
|
||||||
|
### configuration
|
||||||
|
|
||||||
|
This is the configuration to use when performing tasks on projects
|
||||||
|
|
||||||
### exclude
|
### exclude
|
||||||
|
|
||||||
Default: ``
|
Default: ``
|
||||||
@ -98,6 +102,10 @@ Parallelize the command
|
|||||||
|
|
||||||
Produces a plain output for affected:apps and affected:libs
|
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
|
||||||
|
|
||||||
Uncommitted changes
|
Uncommitted changes
|
||||||
|
|||||||
@ -46,6 +46,10 @@ All projects
|
|||||||
|
|
||||||
Base of the current branch (usually master)
|
Base of the current branch (usually master)
|
||||||
|
|
||||||
|
### configuration
|
||||||
|
|
||||||
|
This is the configuration to use when performing tasks on projects
|
||||||
|
|
||||||
### exclude
|
### exclude
|
||||||
|
|
||||||
Default: ``
|
Default: ``
|
||||||
@ -78,6 +82,10 @@ Isolate projects which previously failed
|
|||||||
|
|
||||||
Produces a plain output for affected:apps and affected:libs
|
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
|
||||||
|
|
||||||
Uncommitted changes
|
Uncommitted changes
|
||||||
|
|||||||
@ -58,6 +58,10 @@ All projects
|
|||||||
|
|
||||||
Base of the current branch (usually master)
|
Base of the current branch (usually master)
|
||||||
|
|
||||||
|
### configuration
|
||||||
|
|
||||||
|
This is the configuration to use when performing tasks on projects
|
||||||
|
|
||||||
### exclude
|
### exclude
|
||||||
|
|
||||||
Default: ``
|
Default: ``
|
||||||
@ -98,6 +102,10 @@ Parallelize the command
|
|||||||
|
|
||||||
Produces a plain output for affected:apps and affected:libs
|
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
|
||||||
|
|
||||||
Uncommitted changes
|
Uncommitted changes
|
||||||
|
|||||||
@ -40,6 +40,10 @@ All projects
|
|||||||
|
|
||||||
Base of the current branch (usually master)
|
Base of the current branch (usually master)
|
||||||
|
|
||||||
|
### configuration
|
||||||
|
|
||||||
|
This is the configuration to use when performing tasks on projects
|
||||||
|
|
||||||
### exclude
|
### exclude
|
||||||
|
|
||||||
Default: ``
|
Default: ``
|
||||||
@ -68,6 +72,10 @@ Isolate projects which previously failed
|
|||||||
|
|
||||||
Produces a plain output for affected:apps and affected:libs
|
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
|
||||||
|
|
||||||
Uncommitted changes
|
Uncommitted changes
|
||||||
|
|||||||
@ -58,6 +58,10 @@ All projects
|
|||||||
|
|
||||||
Base of the current branch (usually master)
|
Base of the current branch (usually master)
|
||||||
|
|
||||||
|
### configuration
|
||||||
|
|
||||||
|
This is the configuration to use when performing tasks on projects
|
||||||
|
|
||||||
### exclude
|
### exclude
|
||||||
|
|
||||||
Default: ``
|
Default: ``
|
||||||
@ -98,6 +102,10 @@ Parallelize the command
|
|||||||
|
|
||||||
Produces a plain output for affected:apps and affected:libs
|
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
|
||||||
|
|
||||||
Uncommitted changes
|
Uncommitted changes
|
||||||
|
|||||||
@ -58,6 +58,10 @@ All projects
|
|||||||
|
|
||||||
Base of the current branch (usually master)
|
Base of the current branch (usually master)
|
||||||
|
|
||||||
|
### configuration
|
||||||
|
|
||||||
|
This is the configuration to use when performing tasks on projects
|
||||||
|
|
||||||
### exclude
|
### exclude
|
||||||
|
|
||||||
Default: ``
|
Default: ``
|
||||||
@ -98,6 +102,10 @@ Parallelize the command
|
|||||||
|
|
||||||
Produces a plain output for affected:apps and affected:libs
|
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
|
||||||
|
|
||||||
Uncommitted changes
|
Uncommitted changes
|
||||||
|
|||||||
@ -64,6 +64,10 @@ All projects
|
|||||||
|
|
||||||
Base of the current branch (usually master)
|
Base of the current branch (usually master)
|
||||||
|
|
||||||
|
### configuration
|
||||||
|
|
||||||
|
This is the configuration to use when performing tasks on projects
|
||||||
|
|
||||||
### exclude
|
### exclude
|
||||||
|
|
||||||
Default: ``
|
Default: ``
|
||||||
@ -104,6 +108,10 @@ Parallelize the command
|
|||||||
|
|
||||||
Produces a plain output for affected:apps and affected:libs
|
Produces a plain output for affected:apps and affected:libs
|
||||||
|
|
||||||
|
### runner
|
||||||
|
|
||||||
|
This is the name of the tasks runner configured in nx.json
|
||||||
|
|
||||||
### target
|
### target
|
||||||
|
|
||||||
Task to run for affected projects
|
Task to run for affected projects
|
||||||
|
|||||||
@ -22,6 +22,10 @@ All projects
|
|||||||
|
|
||||||
Base of the current branch (usually master)
|
Base of the current branch (usually master)
|
||||||
|
|
||||||
|
### configuration
|
||||||
|
|
||||||
|
This is the configuration to use when performing tasks on projects
|
||||||
|
|
||||||
### exclude
|
### exclude
|
||||||
|
|
||||||
Default: ``
|
Default: ``
|
||||||
@ -50,6 +54,10 @@ Isolate projects which previously failed
|
|||||||
|
|
||||||
Produces a plain output for affected:apps and affected:libs
|
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
|
||||||
|
|
||||||
Uncommitted changes
|
Uncommitted changes
|
||||||
|
|||||||
@ -22,6 +22,10 @@ All projects
|
|||||||
|
|
||||||
Base of the current branch (usually master)
|
Base of the current branch (usually master)
|
||||||
|
|
||||||
|
### configuration
|
||||||
|
|
||||||
|
This is the configuration to use when performing tasks on projects
|
||||||
|
|
||||||
### exclude
|
### exclude
|
||||||
|
|
||||||
Default: ``
|
Default: ``
|
||||||
@ -50,6 +54,10 @@ Isolate projects which previously failed
|
|||||||
|
|
||||||
Produces a plain output for affected:apps and affected:libs
|
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
|
||||||
|
|
||||||
Uncommitted changes
|
Uncommitted changes
|
||||||
|
|||||||
@ -40,6 +40,10 @@ All projects
|
|||||||
|
|
||||||
Base of the current branch (usually master)
|
Base of the current branch (usually master)
|
||||||
|
|
||||||
|
### configuration
|
||||||
|
|
||||||
|
This is the configuration to use when performing tasks on projects
|
||||||
|
|
||||||
### exclude
|
### exclude
|
||||||
|
|
||||||
Default: ``
|
Default: ``
|
||||||
@ -68,6 +72,10 @@ Isolate projects which previously failed
|
|||||||
|
|
||||||
Produces a plain output for affected:apps and affected:libs
|
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
|
||||||
|
|
||||||
Uncommitted changes
|
Uncommitted changes
|
||||||
|
|||||||
@ -58,6 +58,10 @@ All projects
|
|||||||
|
|
||||||
Base of the current branch (usually master)
|
Base of the current branch (usually master)
|
||||||
|
|
||||||
|
### configuration
|
||||||
|
|
||||||
|
This is the configuration to use when performing tasks on projects
|
||||||
|
|
||||||
### exclude
|
### exclude
|
||||||
|
|
||||||
Default: ``
|
Default: ``
|
||||||
@ -98,6 +102,10 @@ Parallelize the command
|
|||||||
|
|
||||||
Produces a plain output for affected:apps and affected:libs
|
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
|
||||||
|
|
||||||
Uncommitted changes
|
Uncommitted changes
|
||||||
|
|||||||
@ -46,6 +46,10 @@ All projects
|
|||||||
|
|
||||||
Base of the current branch (usually master)
|
Base of the current branch (usually master)
|
||||||
|
|
||||||
|
### configuration
|
||||||
|
|
||||||
|
This is the configuration to use when performing tasks on projects
|
||||||
|
|
||||||
### exclude
|
### exclude
|
||||||
|
|
||||||
Default: ``
|
Default: ``
|
||||||
@ -78,6 +82,10 @@ Isolate projects which previously failed
|
|||||||
|
|
||||||
Produces a plain output for affected:apps and affected:libs
|
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
|
||||||
|
|
||||||
Uncommitted changes
|
Uncommitted changes
|
||||||
|
|||||||
@ -58,6 +58,10 @@ All projects
|
|||||||
|
|
||||||
Base of the current branch (usually master)
|
Base of the current branch (usually master)
|
||||||
|
|
||||||
|
### configuration
|
||||||
|
|
||||||
|
This is the configuration to use when performing tasks on projects
|
||||||
|
|
||||||
### exclude
|
### exclude
|
||||||
|
|
||||||
Default: ``
|
Default: ``
|
||||||
@ -98,6 +102,10 @@ Parallelize the command
|
|||||||
|
|
||||||
Produces a plain output for affected:apps and affected:libs
|
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
|
||||||
|
|
||||||
Uncommitted changes
|
Uncommitted changes
|
||||||
|
|||||||
@ -40,6 +40,10 @@ All projects
|
|||||||
|
|
||||||
Base of the current branch (usually master)
|
Base of the current branch (usually master)
|
||||||
|
|
||||||
|
### configuration
|
||||||
|
|
||||||
|
This is the configuration to use when performing tasks on projects
|
||||||
|
|
||||||
### exclude
|
### exclude
|
||||||
|
|
||||||
Default: ``
|
Default: ``
|
||||||
@ -68,6 +72,10 @@ Isolate projects which previously failed
|
|||||||
|
|
||||||
Produces a plain output for affected:apps and affected:libs
|
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
|
||||||
|
|
||||||
Uncommitted changes
|
Uncommitted changes
|
||||||
|
|||||||
@ -58,6 +58,10 @@ All projects
|
|||||||
|
|
||||||
Base of the current branch (usually master)
|
Base of the current branch (usually master)
|
||||||
|
|
||||||
|
### configuration
|
||||||
|
|
||||||
|
This is the configuration to use when performing tasks on projects
|
||||||
|
|
||||||
### exclude
|
### exclude
|
||||||
|
|
||||||
Default: ``
|
Default: ``
|
||||||
@ -98,6 +102,10 @@ Parallelize the command
|
|||||||
|
|
||||||
Produces a plain output for affected:apps and affected:libs
|
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
|
||||||
|
|
||||||
Uncommitted changes
|
Uncommitted changes
|
||||||
|
|||||||
@ -58,6 +58,10 @@ All projects
|
|||||||
|
|
||||||
Base of the current branch (usually master)
|
Base of the current branch (usually master)
|
||||||
|
|
||||||
|
### configuration
|
||||||
|
|
||||||
|
This is the configuration to use when performing tasks on projects
|
||||||
|
|
||||||
### exclude
|
### exclude
|
||||||
|
|
||||||
Default: ``
|
Default: ``
|
||||||
@ -98,6 +102,10 @@ Parallelize the command
|
|||||||
|
|
||||||
Produces a plain output for affected:apps and affected:libs
|
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
|
||||||
|
|
||||||
Uncommitted changes
|
Uncommitted changes
|
||||||
|
|||||||
@ -64,6 +64,10 @@ All projects
|
|||||||
|
|
||||||
Base of the current branch (usually master)
|
Base of the current branch (usually master)
|
||||||
|
|
||||||
|
### configuration
|
||||||
|
|
||||||
|
This is the configuration to use when performing tasks on projects
|
||||||
|
|
||||||
### exclude
|
### exclude
|
||||||
|
|
||||||
Default: ``
|
Default: ``
|
||||||
@ -104,6 +108,10 @@ Parallelize the command
|
|||||||
|
|
||||||
Produces a plain output for affected:apps and affected:libs
|
Produces a plain output for affected:apps and affected:libs
|
||||||
|
|
||||||
|
### runner
|
||||||
|
|
||||||
|
This is the name of the tasks runner configured in nx.json
|
||||||
|
|
||||||
### target
|
### target
|
||||||
|
|
||||||
Task to run for affected projects
|
Task to run for affected projects
|
||||||
|
|||||||
@ -22,6 +22,10 @@ All projects
|
|||||||
|
|
||||||
Base of the current branch (usually master)
|
Base of the current branch (usually master)
|
||||||
|
|
||||||
|
### configuration
|
||||||
|
|
||||||
|
This is the configuration to use when performing tasks on projects
|
||||||
|
|
||||||
### exclude
|
### exclude
|
||||||
|
|
||||||
Default: ``
|
Default: ``
|
||||||
@ -50,6 +54,10 @@ Isolate projects which previously failed
|
|||||||
|
|
||||||
Produces a plain output for affected:apps and affected:libs
|
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
|
||||||
|
|
||||||
Uncommitted changes
|
Uncommitted changes
|
||||||
|
|||||||
@ -22,6 +22,10 @@ All projects
|
|||||||
|
|
||||||
Base of the current branch (usually master)
|
Base of the current branch (usually master)
|
||||||
|
|
||||||
|
### configuration
|
||||||
|
|
||||||
|
This is the configuration to use when performing tasks on projects
|
||||||
|
|
||||||
### exclude
|
### exclude
|
||||||
|
|
||||||
Default: ``
|
Default: ``
|
||||||
@ -50,6 +54,10 @@ Isolate projects which previously failed
|
|||||||
|
|
||||||
Produces a plain output for affected:apps and affected:libs
|
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
|
||||||
|
|
||||||
Uncommitted changes
|
Uncommitted changes
|
||||||
|
|||||||
@ -143,13 +143,14 @@ forEachCli(() => {
|
|||||||
|
|
||||||
// affected:build should pass non-nx flags to the CLI
|
// affected:build should pass non-nx flags to the CLI
|
||||||
const buildWithFlags = runCommand(
|
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(`Running target build for projects:`);
|
||||||
expect(buildWithFlags).toContain(`- ${myapp}`);
|
expect(buildWithFlags).toContain(`- ${myapp}`);
|
||||||
expect(buildWithFlags).toContain(`- ${mypublishablelib}`);
|
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()) {
|
if (supportUi()) {
|
||||||
const e2e = runCommand(
|
const e2e = runCommand(
|
||||||
@ -221,7 +222,8 @@ forEachCli(() => {
|
|||||||
const lintWithJsonFormating = runCommand(
|
const lintWithJsonFormating = runCommand(
|
||||||
`npm run affected:lint -- --files="libs/${mylib}/src/index.ts" -- --format json`
|
`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(
|
const unitTestsExcluded = runCommand(
|
||||||
`npm run affected:test -- --files="libs/${mylib}/src/index.ts" --exclude=${myapp},${mypublishablelib}`
|
`npm run affected:test -- --files="libs/${mylib}/src/index.ts" --exclude=${myapp},${mypublishablelib}`
|
||||||
|
|||||||
@ -3,11 +3,11 @@ import {
|
|||||||
getAffectedApps,
|
getAffectedApps,
|
||||||
getAffectedLibs,
|
getAffectedLibs,
|
||||||
getAffectedProjects,
|
getAffectedProjects,
|
||||||
getAffectedProjectsWithTarget,
|
getAffectedProjectsWithTargetAndConfiguration,
|
||||||
getAllApps,
|
getAllApps,
|
||||||
getAllLibs,
|
getAllLibs,
|
||||||
getAllProjects,
|
getAllProjects,
|
||||||
getAllProjectsWithTarget
|
getAllProjectsWithTargetAndConfiguration
|
||||||
} from './affected-apps';
|
} from './affected-apps';
|
||||||
import { DependencyType } from './deps-calculator';
|
import { DependencyType } from './deps-calculator';
|
||||||
|
|
||||||
@ -23,7 +23,11 @@ describe('affected-apps', () => {
|
|||||||
architect: {
|
architect: {
|
||||||
lint: {},
|
lint: {},
|
||||||
test: {},
|
test: {},
|
||||||
build: {}
|
build: {
|
||||||
|
configurations: {
|
||||||
|
production: {}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
app2: {
|
app2: {
|
||||||
@ -196,11 +200,46 @@ describe('affected-apps', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('getAffectedProjectsWithTarget', () => {
|
describe('getAffectedProjectsWithTargetAndConfiguration', () => {
|
||||||
it('should get none if no projects are affected', () => {
|
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', () => {
|
it('should find affected projects that can be linted', () => {
|
||||||
@ -212,12 +251,14 @@ describe('affected-apps', () => {
|
|||||||
projectStates['app1-e2e'].affected = true;
|
projectStates['app1-e2e'].affected = true;
|
||||||
projectStates.app2.affected = true;
|
projectStates.app2.affected = true;
|
||||||
projectStates['customName-e2e'].affected = true;
|
projectStates['customName-e2e'].affected = true;
|
||||||
expect(getAffectedProjectsWithTarget(affectedMetadata, 'lint')).toEqual([
|
expect(
|
||||||
'lib1',
|
getAffectedProjectsWithTargetAndConfiguration(affectedMetadata, 'lint')
|
||||||
'app1',
|
).toEqual([
|
||||||
'app1-e2e',
|
affectedMetadata.dependencyGraph.projects.lib1,
|
||||||
'app2',
|
affectedMetadata.dependencyGraph.projects.app1,
|
||||||
'customName-e2e'
|
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['app1-e2e'].affected = true;
|
||||||
projectStates.app2.affected = true;
|
projectStates.app2.affected = true;
|
||||||
projectStates['customName-e2e'].affected = true;
|
projectStates['customName-e2e'].affected = true;
|
||||||
expect(getAffectedProjectsWithTarget(affectedMetadata, 'test')).toEqual([
|
expect(
|
||||||
'lib1',
|
getAffectedProjectsWithTargetAndConfiguration(affectedMetadata, 'test')
|
||||||
'app1',
|
).toEqual([
|
||||||
'app2'
|
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['app1-e2e'].affected = true;
|
||||||
projectStates.app2.affected = true;
|
projectStates.app2.affected = true;
|
||||||
projectStates['customName-e2e'].affected = true;
|
projectStates['customName-e2e'].affected = true;
|
||||||
expect(getAffectedProjectsWithTarget(affectedMetadata, 'e2e')).toEqual([
|
expect(
|
||||||
'app1-e2e',
|
getAffectedProjectsWithTargetAndConfiguration(affectedMetadata, 'e2e')
|
||||||
'customName-e2e'
|
).toEqual([
|
||||||
|
affectedMetadata.dependencyGraph.projects['app1-e2e'],
|
||||||
|
affectedMetadata.dependencyGraph.projects['customName-e2e']
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -280,36 +325,54 @@ describe('affected-apps', () => {
|
|||||||
|
|
||||||
describe('getAllProjectsWithTarget', () => {
|
describe('getAllProjectsWithTarget', () => {
|
||||||
it('should get all projects that can be linted', () => {
|
it('should get all projects that can be linted', () => {
|
||||||
expect(getAllProjectsWithTarget(affectedMetadata, 'lint')).toEqual([
|
expect(
|
||||||
'lib1',
|
getAllProjectsWithTargetAndConfiguration(affectedMetadata, 'lint')
|
||||||
'app1',
|
).toEqual([
|
||||||
'app1-e2e',
|
affectedMetadata.dependencyGraph.projects.lib1,
|
||||||
'lib2',
|
affectedMetadata.dependencyGraph.projects.app1,
|
||||||
'app2',
|
affectedMetadata.dependencyGraph.projects['app1-e2e'],
|
||||||
'customName-e2e'
|
affectedMetadata.dependencyGraph.projects.lib2,
|
||||||
|
affectedMetadata.dependencyGraph.projects.app2,
|
||||||
|
affectedMetadata.dependencyGraph.projects['customName-e2e']
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should get all projects that can be tested', () => {
|
it('should get all projects that can be tested', () => {
|
||||||
expect(getAllProjectsWithTarget(affectedMetadata, 'test')).toEqual([
|
expect(
|
||||||
'lib1',
|
getAllProjectsWithTargetAndConfiguration(affectedMetadata, 'test')
|
||||||
'app1',
|
).toEqual([
|
||||||
'lib2',
|
affectedMetadata.dependencyGraph.projects.lib1,
|
||||||
'app2'
|
affectedMetadata.dependencyGraph.projects.app1,
|
||||||
|
affectedMetadata.dependencyGraph.projects.lib2,
|
||||||
|
affectedMetadata.dependencyGraph.projects.app2
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should get all projects that can be built', () => {
|
it('should get all projects that can be built', () => {
|
||||||
expect(getAllProjectsWithTarget(affectedMetadata, 'build')).toEqual([
|
expect(
|
||||||
'app1',
|
getAllProjectsWithTargetAndConfiguration(affectedMetadata, 'build')
|
||||||
'app2'
|
).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', () => {
|
it('should get all projects that can be e2e-tested', () => {
|
||||||
expect(getAllProjectsWithTarget(affectedMetadata, 'e2e')).toEqual([
|
expect(
|
||||||
'app1-e2e',
|
getAllProjectsWithTargetAndConfiguration(affectedMetadata, 'e2e')
|
||||||
'customName-e2e'
|
).toEqual([
|
||||||
|
affectedMetadata.dependencyGraph.projects['app1-e2e'],
|
||||||
|
affectedMetadata.dependencyGraph.projects['customName-e2e']
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -26,16 +26,17 @@ export function getAffectedProjects(
|
|||||||
).map(project => project.name);
|
).map(project => project.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getAffectedProjectsWithTarget(
|
export function getAffectedProjectsWithTargetAndConfiguration(
|
||||||
affectedMetadata: AffectedMetadata,
|
affectedMetadata: AffectedMetadata,
|
||||||
target: string
|
target: string,
|
||||||
): string[] {
|
configuration?: string
|
||||||
|
): ProjectNode[] {
|
||||||
return filterAffectedMetadata(
|
return filterAffectedMetadata(
|
||||||
affectedMetadata,
|
affectedMetadata,
|
||||||
project =>
|
project =>
|
||||||
affectedMetadata.projectStates[project.name].affected &&
|
affectedMetadata.projectStates[project.name].affected &&
|
||||||
project.architect[target]
|
projectHasTargetAndConfiguration(project, target, configuration)
|
||||||
).map(project => project.name);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getAllApps(affectedMetadata: AffectedMetadata): string[] {
|
export function getAllApps(affectedMetadata: AffectedMetadata): string[] {
|
||||||
@ -58,14 +59,33 @@ export function getAllProjects(affectedMetadata: AffectedMetadata): string[] {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getAllProjectsWithTarget(
|
export function getAllProjectsWithTargetAndConfiguration(
|
||||||
affectedMetadata: AffectedMetadata,
|
affectedMetadata: AffectedMetadata,
|
||||||
target: string
|
target: string,
|
||||||
): string[] {
|
configuration?: string
|
||||||
return filterAffectedMetadata(
|
): ProjectNode[] {
|
||||||
affectedMetadata,
|
return filterAffectedMetadata(affectedMetadata, project =>
|
||||||
project => project.architect[target]
|
projectHasTargetAndConfiguration(project, target, configuration)
|
||||||
).map(project => project.name);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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(
|
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 yargs from 'yargs';
|
||||||
|
import * as yargsParser from 'yargs-parser';
|
||||||
|
import { join } from 'path';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
parseFiles,
|
parseFiles,
|
||||||
readWorkspaceJson,
|
|
||||||
printArgsWarning,
|
printArgsWarning,
|
||||||
cliCommand,
|
getAffectedMetadata,
|
||||||
getAffectedMetadata
|
AffectedMetadata,
|
||||||
|
readNxJson,
|
||||||
|
ProjectNode,
|
||||||
|
NxJson
|
||||||
} from './shared';
|
} from './shared';
|
||||||
import {
|
import {
|
||||||
getAffectedApps,
|
getAffectedApps,
|
||||||
getAffectedLibs,
|
getAffectedLibs,
|
||||||
getAffectedProjects,
|
getAffectedProjects,
|
||||||
getAffectedProjectsWithTarget,
|
getAffectedProjectsWithTargetAndConfiguration,
|
||||||
getAllApps,
|
getAllApps,
|
||||||
getAllLibs,
|
getAllLibs,
|
||||||
getAllProjects,
|
getAllProjects,
|
||||||
getAllProjectsWithTarget
|
getAllProjectsWithTargetAndConfiguration,
|
||||||
|
projectHasTargetAndConfiguration
|
||||||
} from './affected-apps';
|
} from './affected-apps';
|
||||||
import { generateGraph } from './dep-graph';
|
import { generateGraph } from './dep-graph';
|
||||||
import { WorkspaceResults } from './workspace-results';
|
import { WorkspaceResults } from './workspace-results';
|
||||||
import { output } from './output';
|
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
|
export interface YargsAffectedOptions
|
||||||
extends yargs.Arguments,
|
extends yargs.Arguments,
|
||||||
@ -30,6 +41,8 @@ export interface YargsAffectedOptions
|
|||||||
|
|
||||||
export interface AffectedOptions {
|
export interface AffectedOptions {
|
||||||
target?: string;
|
target?: string;
|
||||||
|
configuration?: string;
|
||||||
|
runner?: string;
|
||||||
parallel?: boolean;
|
parallel?: boolean;
|
||||||
maxParallel?: number;
|
maxParallel?: number;
|
||||||
untracked?: boolean;
|
untracked?: boolean;
|
||||||
@ -49,14 +62,15 @@ export interface AffectedOptions {
|
|||||||
plain?: boolean;
|
plain?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const commonCommands = ['build', 'test', 'lint', 'e2e'];
|
interface ProcessedArgs {
|
||||||
|
affectedArgs: YargsAffectedOptions;
|
||||||
|
taskOverrides: any;
|
||||||
|
tasksRunnerOptions: any;
|
||||||
|
tasksRunner: TasksRunner;
|
||||||
|
}
|
||||||
|
|
||||||
export function affected(parsedArgs: YargsAffectedOptions): void {
|
export function affected(parsedArgs: YargsAffectedOptions): void {
|
||||||
const target = parsedArgs.target;
|
const target = parsedArgs.target;
|
||||||
const rest: string[] = [
|
|
||||||
...parsedArgs._.slice(1),
|
|
||||||
...filterNxSpecificArgs(parsedArgs)
|
|
||||||
];
|
|
||||||
|
|
||||||
const workspaceResults = new WorkspaceResults(target);
|
const workspaceResults = new WorkspaceResults(target);
|
||||||
|
|
||||||
@ -70,10 +84,10 @@ export function affected(parsedArgs: YargsAffectedOptions): void {
|
|||||||
? getAllApps(affectedMetadata)
|
? getAllApps(affectedMetadata)
|
||||||
: getAffectedApps(affectedMetadata)
|
: getAffectedApps(affectedMetadata)
|
||||||
)
|
)
|
||||||
.filter(app => !parsedArgs.exclude.includes(app))
|
.filter(affectedApp => !parsedArgs.exclude.includes(affectedApp))
|
||||||
.filter(
|
.filter(
|
||||||
project =>
|
affectedApp =>
|
||||||
!parsedArgs.onlyFailed || !workspaceResults.getResult(project)
|
!parsedArgs.onlyFailed || !workspaceResults.getResult(affectedApp)
|
||||||
);
|
);
|
||||||
if (parsedArgs.plain) {
|
if (parsedArgs.plain) {
|
||||||
console.log(apps.join(' '));
|
console.log(apps.join(' '));
|
||||||
@ -92,10 +106,10 @@ export function affected(parsedArgs: YargsAffectedOptions): void {
|
|||||||
? getAllLibs(affectedMetadata)
|
? getAllLibs(affectedMetadata)
|
||||||
: getAffectedLibs(affectedMetadata)
|
: getAffectedLibs(affectedMetadata)
|
||||||
)
|
)
|
||||||
.filter(app => !parsedArgs.exclude.includes(app))
|
.filter(affectedLib => !parsedArgs.exclude.includes(affectedLib))
|
||||||
.filter(
|
.filter(
|
||||||
project =>
|
affectedLib =>
|
||||||
!parsedArgs.onlyFailed || !workspaceResults.getResult(project)
|
!parsedArgs.onlyFailed || !workspaceResults.getResult(affectedLib)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (parsedArgs.plain) {
|
if (parsedArgs.plain) {
|
||||||
@ -125,17 +139,28 @@ export function affected(parsedArgs: YargsAffectedOptions): void {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
|
const nxJson = readNxJson();
|
||||||
|
const processedArgs = processArgs(parsedArgs, nxJson);
|
||||||
const projects = (parsedArgs.all
|
const projects = (parsedArgs.all
|
||||||
? getAllProjectsWithTarget(affectedMetadata, target)
|
? getAllProjectsWithTargetAndConfiguration(
|
||||||
: getAffectedProjectsWithTarget(affectedMetadata, target)
|
affectedMetadata,
|
||||||
|
target,
|
||||||
|
processedArgs.affectedArgs.configuration
|
||||||
)
|
)
|
||||||
.filter(project => !parsedArgs.exclude.includes(project))
|
: getAffectedProjectsWithTargetAndConfiguration(
|
||||||
|
affectedMetadata,
|
||||||
|
target,
|
||||||
|
processedArgs.affectedArgs.configuration
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.filter(project => !parsedArgs.exclude.includes(project.name))
|
||||||
.filter(
|
.filter(
|
||||||
project =>
|
project =>
|
||||||
!parsedArgs.onlyFailed || !workspaceResults.getResult(project)
|
!parsedArgs.onlyFailed ||
|
||||||
|
!workspaceResults.getResult(project.name)
|
||||||
);
|
);
|
||||||
printArgsWarning(parsedArgs);
|
printArgsWarning(parsedArgs);
|
||||||
runCommand(target, projects, parsedArgs, rest, workspaceResults);
|
runCommand(projects, affectedMetadata, processedArgs, workspaceResults);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -158,145 +183,202 @@ function printError(e: any, verbose?: boolean) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function runCommand(
|
async function runCommand(
|
||||||
targetName: string,
|
affectedProjects: ProjectNode[],
|
||||||
projects: string[],
|
affectedMetadata: AffectedMetadata,
|
||||||
parsedArgs: YargsAffectedOptions,
|
processedArgs: ProcessedArgs,
|
||||||
args: string[],
|
|
||||||
workspaceResults: WorkspaceResults
|
workspaceResults: WorkspaceResults
|
||||||
) {
|
) {
|
||||||
if (projects.length <= 0) {
|
const {
|
||||||
output.logSingleLine(
|
affectedArgs,
|
||||||
`No affected projects to run target "${targetName}" on`
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const cli = cliCommand();
|
const bodyLines = affectedProjects.map(
|
||||||
|
affectedProject => `${output.colors.gray('-')} ${affectedProject.name}`
|
||||||
const bodyLines = projects.map(
|
|
||||||
project => `${output.colors.gray('-')} ${project}`
|
|
||||||
);
|
);
|
||||||
if (args.length > 0) {
|
if (Object.keys(taskOverrides).length > 0) {
|
||||||
bodyLines.push('');
|
bodyLines.push('');
|
||||||
bodyLines.push(
|
bodyLines.push(`${output.colors.gray('With flags:')}`);
|
||||||
`${output.colors.gray('With flags:')} ${output.bold(args.join(' '))}`
|
Object.entries(taskOverrides)
|
||||||
);
|
.map(([flag, value]) => ` --${flag}=${value}`)
|
||||||
|
.forEach(arg => bodyLines.push(arg));
|
||||||
}
|
}
|
||||||
|
|
||||||
output.log({
|
output.log({
|
||||||
title: `${output.colors.gray(
|
title: `${output.colors.gray('Running target')} ${
|
||||||
'Running target'
|
affectedArgs.target
|
||||||
)} ${targetName} ${output.colors.gray('for projects:')}`,
|
} ${output.colors.gray('for projects:')}`,
|
||||||
bodyLines
|
bodyLines
|
||||||
});
|
});
|
||||||
|
|
||||||
output.addVerticalSeparator();
|
output.addVerticalSeparator();
|
||||||
|
|
||||||
const workspaceJson = readWorkspaceJson();
|
const tasks: Task[] = affectedProjects.map(affectedProject =>
|
||||||
const projectMetadata = new Map<string, any>();
|
createTask({
|
||||||
projects.forEach(project => {
|
project: affectedProject,
|
||||||
projectMetadata.set(project, workspaceJson.projects[project]);
|
target: processedArgs.affectedArgs.target,
|
||||||
});
|
configuration: processedArgs.affectedArgs.configuration,
|
||||||
|
overrides: processedArgs.taskOverrides
|
||||||
// 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 tasksMap: {
|
||||||
const isYarn = path
|
[projectName: string]: { [targetName: string]: Task };
|
||||||
.basename(process.env.npm_execpath || 'npm')
|
} = {};
|
||||||
.startsWith('yarn');
|
Object.entries(affectedMetadata.dependencyGraph.projects).forEach(
|
||||||
await runAll(
|
([projectName, project]) => {
|
||||||
projects.map(proj => {
|
if (
|
||||||
return commonCommands.includes(targetName)
|
projectHasTargetAndConfiguration(
|
||||||
? `${cli} ${isYarn ? '' : '--'} ${targetName} ${proj} ${transformArgs(
|
project,
|
||||||
args,
|
processedArgs.affectedArgs.target,
|
||||||
proj,
|
processedArgs.affectedArgs.configuration
|
||||||
projectMetadata.get(proj)
|
)
|
||||||
).join(' ')} `
|
) {
|
||||||
: `${cli} ${
|
tasksMap[projectName] = {
|
||||||
isYarn ? '' : '--'
|
[processedArgs.affectedArgs.target]: createTask({
|
||||||
} run ${proj}:${targetName} ${transformArgs(
|
project: project,
|
||||||
args,
|
target: processedArgs.affectedArgs.target,
|
||||||
proj,
|
configuration: processedArgs.affectedArgs.configuration,
|
||||||
projectMetadata.get(proj)
|
overrides: processedArgs.taskOverrides
|
||||||
).join(' ')} `;
|
})
|
||||||
}),
|
};
|
||||||
{
|
}
|
||||||
parallel: parsedArgs.parallel || false,
|
|
||||||
maxParallel: parsedArgs.maxParallel || 1,
|
|
||||||
continueOnError: true,
|
|
||||||
stdin: process.stdin,
|
|
||||||
stdout: process.stdout,
|
|
||||||
stderr: process.stderr
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
projects.forEach(project => {
|
tasksRunner(tasks, tasksRunnerOptions, {
|
||||||
workspaceResults.success(project);
|
dependencyGraph: affectedMetadata.dependencyGraph,
|
||||||
});
|
tasksMap
|
||||||
} catch (e) {
|
}).subscribe({
|
||||||
e.results.forEach((result, i) => {
|
next: (event: TaskCompleteEvent) => {
|
||||||
if (result.code === 0) {
|
switch (event.type) {
|
||||||
workspaceResults.success(projects[i]);
|
case AffectedEventType.TaskComplete: {
|
||||||
} else {
|
workspaceResults.setResult(event.task.target.project, event.success);
|
||||||
workspaceResults.fail(projects[i]);
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
} finally {
|
},
|
||||||
|
error: console.error,
|
||||||
|
complete: () => {
|
||||||
// fix for https://github.com/nrwl/nx/issues/1666
|
// fix for https://github.com/nrwl/nx/issues/1666
|
||||||
if (process.stdin['unref']) (process.stdin as any).unref();
|
if (process.stdin['unref']) (process.stdin as any).unref();
|
||||||
}
|
|
||||||
|
|
||||||
workspaceResults.saveResults();
|
workspaceResults.saveResults();
|
||||||
workspaceResults.printResults(
|
workspaceResults.printResults(
|
||||||
parsedArgs.onlyFailed,
|
affectedArgs.onlyFailed,
|
||||||
`Running target "${targetName}" for affected projects succeeded`,
|
`Running target "${affectedArgs.target}" for affected projects succeeded`,
|
||||||
`Running target "${targetName}" for affected projects failed`
|
`Running target "${affectedArgs.target}" for affected projects failed`
|
||||||
);
|
);
|
||||||
|
|
||||||
if (workspaceResults.hasFailure) {
|
if (workspaceResults.hasFailure) {
|
||||||
process.exit(1);
|
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');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (group === 'name') {
|
|
||||||
return projectName;
|
|
||||||
}
|
|
||||||
return projectMetadata[group];
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
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 };
|
const filteredArgs = { ...parsedArgs };
|
||||||
// Delete Nx arguments from parsed Args
|
// Delete Nx arguments from parsed Args
|
||||||
nxSpecificFlags.forEach(flag => {
|
nxSpecificFlags.forEach(flag => {
|
||||||
@ -308,19 +390,55 @@ function filterNxSpecificArgs(parsedArgs: YargsAffectedOptions): string[] {
|
|||||||
// Also remove the node path
|
// Also remove the node path
|
||||||
delete filteredArgs.$0;
|
delete filteredArgs.$0;
|
||||||
|
|
||||||
// Re-serialize into a list of args
|
return filteredArgs;
|
||||||
return Object.keys(filteredArgs).map(filteredArg => {
|
|
||||||
if (!Array.isArray(filteredArgs[filteredArg])) {
|
|
||||||
filteredArgs[filteredArg] = [filteredArgs[filteredArg]];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return filteredArgs[filteredArg]
|
export function processArgs(
|
||||||
.map(value => {
|
parsedArgs: YargsAffectedOptions,
|
||||||
return `--${filteredArg}=${value}`;
|
nxJson: NxJson
|
||||||
})
|
): ProcessedArgs {
|
||||||
.join(' ');
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* These options are only for getting an array with properties of AffectedOptions.
|
* These options are only for getting an array with properties of AffectedOptions.
|
||||||
@ -329,13 +447,12 @@ function filterNxSpecificArgs(parsedArgs: YargsAffectedOptions): string[] {
|
|||||||
*/
|
*/
|
||||||
const dummyOptions: AffectedOptions = {
|
const dummyOptions: AffectedOptions = {
|
||||||
target: '',
|
target: '',
|
||||||
parallel: false,
|
configuration: '',
|
||||||
maxParallel: 3,
|
|
||||||
'max-parallel': false,
|
|
||||||
onlyFailed: false,
|
onlyFailed: false,
|
||||||
'only-failed': false,
|
'only-failed': false,
|
||||||
untracked: false,
|
untracked: false,
|
||||||
uncommitted: false,
|
uncommitted: false,
|
||||||
|
runner: '',
|
||||||
help: false,
|
help: false,
|
||||||
version: false,
|
version: false,
|
||||||
quiet: false,
|
quiet: false,
|
||||||
|
|||||||
@ -254,6 +254,15 @@ function withAffectedOptions(yargs: yargs.Argv): yargs.Argv {
|
|||||||
coerce: parseCSV,
|
coerce: parseCSV,
|
||||||
default: []
|
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', {
|
.options('only-failed', {
|
||||||
describe: 'Isolate projects which previously failed',
|
describe: 'Isolate projects which previously failed',
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
|
|||||||
@ -24,6 +24,12 @@ export interface NxJson {
|
|||||||
projects: {
|
projects: {
|
||||||
[projectName: string]: NxJsonProjectConfig;
|
[projectName: string]: NxJsonProjectConfig;
|
||||||
};
|
};
|
||||||
|
tasksRunnerOptions?: {
|
||||||
|
[tasksRunnerName: string]: {
|
||||||
|
runner: string;
|
||||||
|
options?: unknown;
|
||||||
|
};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NxJsonProjectConfig {
|
export interface NxJsonProjectConfig {
|
||||||
@ -443,6 +449,7 @@ export function createAffectedMetadata(
|
|||||||
): AffectedMetadata {
|
): AffectedMetadata {
|
||||||
const projectStates: ProjectStates = {};
|
const projectStates: ProjectStates = {};
|
||||||
const projects: ProjectMap = {};
|
const projects: ProjectMap = {};
|
||||||
|
|
||||||
projectNodes.forEach(project => {
|
projectNodes.forEach(project => {
|
||||||
projectStates[project.name] = {
|
projectStates[project.name] = {
|
||||||
touched: false,
|
touched: false,
|
||||||
|
|||||||
@ -22,7 +22,7 @@ describe('WorkspacesResults', () => {
|
|||||||
|
|
||||||
describe('success', () => {
|
describe('success', () => {
|
||||||
it('should return true when getting results', () => {
|
it('should return true when getting results', () => {
|
||||||
results.success('proj');
|
results.setResult('proj', true);
|
||||||
|
|
||||||
expect(results.getResult('proj')).toBe(true);
|
expect(results.getResult('proj')).toBe(true);
|
||||||
});
|
});
|
||||||
@ -32,7 +32,7 @@ describe('WorkspacesResults', () => {
|
|||||||
spyOn(fs, 'unlinkSync');
|
spyOn(fs, 'unlinkSync');
|
||||||
spyOn(fs, 'existsSync').and.returnValue(true);
|
spyOn(fs, 'existsSync').and.returnValue(true);
|
||||||
|
|
||||||
results.success('proj');
|
results.setResult('proj', true);
|
||||||
results.saveResults();
|
results.saveResults();
|
||||||
|
|
||||||
expect(fs.writeSync).not.toHaveBeenCalled();
|
expect(fs.writeSync).not.toHaveBeenCalled();
|
||||||
@ -41,7 +41,7 @@ describe('WorkspacesResults', () => {
|
|||||||
|
|
||||||
it('should print results', () => {
|
it('should print results', () => {
|
||||||
const projectName = 'proj';
|
const projectName = 'proj';
|
||||||
results.success(projectName);
|
results.setResult(projectName, true);
|
||||||
spyOn(output, 'success');
|
spyOn(output, 'success');
|
||||||
|
|
||||||
const successTitle = 'Success';
|
const successTitle = 'Success';
|
||||||
@ -60,7 +60,7 @@ describe('WorkspacesResults', () => {
|
|||||||
spyOn(output, 'success');
|
spyOn(output, 'success');
|
||||||
spyOn(output, 'warn');
|
spyOn(output, 'warn');
|
||||||
|
|
||||||
results.success(projectName);
|
results.setResult(projectName, true);
|
||||||
|
|
||||||
const successTitle = 'Success';
|
const successTitle = 'Success';
|
||||||
|
|
||||||
@ -85,7 +85,7 @@ describe('WorkspacesResults', () => {
|
|||||||
|
|
||||||
describe('fail', () => {
|
describe('fail', () => {
|
||||||
it('should return false when getting results', () => {
|
it('should return false when getting results', () => {
|
||||||
results.fail('proj');
|
results.setResult('proj', false);
|
||||||
|
|
||||||
expect(results.getResult('proj')).toBe(false);
|
expect(results.getResult('proj')).toBe(false);
|
||||||
});
|
});
|
||||||
@ -93,7 +93,7 @@ describe('WorkspacesResults', () => {
|
|||||||
it('should save results to file system', () => {
|
it('should save results to file system', () => {
|
||||||
spyOn(fs, 'writeFileSync');
|
spyOn(fs, 'writeFileSync');
|
||||||
|
|
||||||
results.fail('proj');
|
results.setResult('proj', false);
|
||||||
results.saveResults();
|
results.saveResults();
|
||||||
|
|
||||||
expect(fs.writeFileSync).toHaveBeenCalledWith(
|
expect(fs.writeFileSync).toHaveBeenCalledWith(
|
||||||
@ -109,7 +109,7 @@ describe('WorkspacesResults', () => {
|
|||||||
|
|
||||||
it('should print results', () => {
|
it('should print results', () => {
|
||||||
const projectName = 'proj';
|
const projectName = 'proj';
|
||||||
results.fail(projectName);
|
results.setResult(projectName, false);
|
||||||
spyOn(output, 'error');
|
spyOn(output, 'error');
|
||||||
|
|
||||||
const errorTitle = 'Fail';
|
const errorTitle = 'Fail';
|
||||||
@ -128,7 +128,7 @@ describe('WorkspacesResults', () => {
|
|||||||
|
|
||||||
it('should tell the user that they can isolate only the failed tests', () => {
|
it('should tell the user that they can isolate only the failed tests', () => {
|
||||||
const projectName = 'proj';
|
const projectName = 'proj';
|
||||||
results.fail(projectName);
|
results.setResult(projectName, false);
|
||||||
spyOn(output, 'error');
|
spyOn(output, 'error');
|
||||||
|
|
||||||
const errorTitle = 'Fail';
|
const errorTitle = 'Fail';
|
||||||
|
|||||||
@ -51,14 +51,6 @@ export class WorkspaceResults {
|
|||||||
return this.commandResults.results[projectName];
|
return this.commandResults.results[projectName];
|
||||||
}
|
}
|
||||||
|
|
||||||
fail(projectName: string) {
|
|
||||||
this.setResult(projectName, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
success(projectName: string) {
|
|
||||||
this.setResult(projectName, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
saveResults() {
|
saveResults() {
|
||||||
if (Object.values<boolean>(this.commandResults.results).includes(false)) {
|
if (Object.values<boolean>(this.commandResults.results).includes(false)) {
|
||||||
writeJsonFile(RESULTS_FILE, this.commandResults);
|
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;
|
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);
|
cb(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isRelativePath(path: string): boolean {
|
||||||
|
return path.startsWith('./') || path.startsWith('../');
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user