@@ -5,12 +5,7 @@ import path from 'path';
5
5
import { JsonFile } from '@rushstack/node-core-library' ;
6
6
7
7
import { RushConfiguration } from '../../../api/RushConfiguration' ;
8
- import type { RushConfigurationProject } from '../../../api/RushConfigurationProject' ;
9
- import {
10
- CommandLineConfiguration ,
11
- type IPhase ,
12
- type IPhasedCommandConfig
13
- } from '../../../api/CommandLineConfiguration' ;
8
+ import { CommandLineConfiguration , type IPhasedCommandConfig } from '../../../api/CommandLineConfiguration' ;
14
9
import { PhasedOperationPlugin } from '../PhasedOperationPlugin' ;
15
10
import type { Operation } from '../Operation' ;
16
11
import type { ICommandLineJson } from '../../../api/CommandLineJson' ;
@@ -21,18 +16,30 @@ import {
21
16
PhasedCommandHooks
22
17
} from '../../../pluginFramework/PhasedCommandHooks' ;
23
18
24
- interface ISerializedOperation {
25
- name : string ;
26
- silent : boolean ;
27
- dependencies : string [ ] ;
19
+ function serializeOperation ( operation : Operation ) : string {
20
+ return `${ operation . name } (${ operation . enabled ? 'enabled' : 'disabled' } ${ operation . runner ! . silent ? ', silent' : '' } ) -> [${ Array . from (
21
+ operation . dependencies ,
22
+ ( dep : Operation ) => dep . name
23
+ )
24
+ . sort ( )
25
+ . join ( ', ' ) } ]`;
26
+ }
27
+
28
+ function compareOperation ( a : Operation , b : Operation ) : number {
29
+ if ( a . enabled && ! b . enabled ) {
30
+ return - 1 ;
31
+ }
32
+ if ( ! a . enabled && b . enabled ) {
33
+ return 1 ;
34
+ }
35
+ return a . name < b . name ? - 1 : a . name > b . name ? 1 : 0 ;
28
36
}
29
37
30
- function serializeOperation ( operation : Operation ) : ISerializedOperation {
31
- return {
32
- name : operation . name ,
33
- silent : ! operation . enabled || operation . runner ! . silent ,
34
- dependencies : Array . from ( operation . dependencies , ( dep : Operation ) => dep . name )
35
- } ;
38
+ function expectOperationsToMatchSnapshot ( operations : Set < Operation > , name : string ) : void {
39
+ const serializedOperations : string [ ] = Array . from ( operations )
40
+ . sort ( compareOperation )
41
+ . map ( serializeOperation ) ;
42
+ expect ( serializedOperations ) . toMatchSnapshot ( name ) ;
36
43
}
37
44
38
45
describe ( PhasedOperationPlugin . name , ( ) => {
@@ -58,11 +65,22 @@ describe(PhasedOperationPlugin.name, () => {
58
65
return operations ;
59
66
}
60
67
61
- async function testCreateOperationsAsync (
62
- phaseSelection : Set < IPhase > ,
63
- projectSelection : Set < RushConfigurationProject > ,
64
- changedProjects : Set < RushConfigurationProject >
65
- ) : Promise < Set < Operation > > {
68
+ interface ITestCreateOperationsContext {
69
+ phaseOriginal ?: ICreateOperationsContext [ 'phaseOriginal' ] ;
70
+ phaseSelection : ICreateOperationsContext [ 'phaseSelection' ] ;
71
+ projectSelection : ICreateOperationsContext [ 'projectSelection' ] ;
72
+ projectsInUnknownState : ICreateOperationsContext [ 'projectsInUnknownState' ] ;
73
+ includePhaseDeps ?: ICreateOperationsContext [ 'includePhaseDeps' ] ;
74
+ }
75
+
76
+ async function testCreateOperationsAsync ( options : ITestCreateOperationsContext ) : Promise < Set < Operation > > {
77
+ const {
78
+ phaseSelection,
79
+ projectSelection,
80
+ projectsInUnknownState,
81
+ phaseOriginal = phaseSelection ,
82
+ includePhaseDeps = false
83
+ } = options ;
66
84
const hooks : PhasedCommandHooks = new PhasedCommandHooks ( ) ;
67
85
// Apply the plugin being tested
68
86
new PhasedOperationPlugin ( ) . apply ( hooks ) ;
@@ -71,16 +89,18 @@ describe(PhasedOperationPlugin.name, () => {
71
89
72
90
const context : Pick <
73
91
ICreateOperationsContext ,
92
+ | 'includePhaseDeps'
74
93
| 'phaseOriginal'
75
94
| 'phaseSelection'
76
95
| 'projectSelection'
77
96
| 'projectsInUnknownState'
78
97
| 'projectConfigurations'
79
98
> = {
80
- phaseOriginal : phaseSelection ,
99
+ includePhaseDeps,
100
+ phaseOriginal,
81
101
phaseSelection,
82
102
projectSelection,
83
- projectsInUnknownState : changedProjects ,
103
+ projectsInUnknownState,
84
104
projectConfigurations : new Map ( )
85
105
} ;
86
106
const operations : Set < Operation > = await hooks . createOperations . promise (
@@ -106,154 +126,205 @@ describe(PhasedOperationPlugin.name, () => {
106
126
'build'
107
127
) ! as IPhasedCommandConfig ;
108
128
109
- const operations : Set < Operation > = await testCreateOperationsAsync (
110
- buildCommand . phases ,
111
- new Set ( rushConfiguration . projects ) ,
112
- new Set ( rushConfiguration . projects )
113
- ) ;
129
+ const operations : Set < Operation > = await testCreateOperationsAsync ( {
130
+ phaseSelection : buildCommand . phases ,
131
+ projectSelection : new Set ( rushConfiguration . projects ) ,
132
+ projectsInUnknownState : new Set ( rushConfiguration . projects )
133
+ } ) ;
114
134
115
135
// All projects
116
- expect ( Array . from ( operations , serializeOperation ) ) . toMatchSnapshot ( ) ;
136
+ expectOperationsToMatchSnapshot ( operations , 'full' ) ;
117
137
} ) ;
118
138
119
139
it ( 'handles filtered projects' , async ( ) => {
120
140
const buildCommand : IPhasedCommandConfig = commandLineConfiguration . commands . get (
121
141
'build'
122
142
) ! as IPhasedCommandConfig ;
123
143
124
- let operations : Set < Operation > = await testCreateOperationsAsync (
125
- buildCommand . phases ,
126
- new Set ( [ rushConfiguration . getProjectByName ( 'g' ) ! ] ) ,
127
- new Set ( [ rushConfiguration . getProjectByName ( 'g' ) ! ] )
128
- ) ;
144
+ let operations : Set < Operation > = await testCreateOperationsAsync ( {
145
+ phaseSelection : buildCommand . phases ,
146
+ projectSelection : new Set ( [ rushConfiguration . getProjectByName ( 'g' ) ! ] ) ,
147
+ projectsInUnknownState : new Set ( [ rushConfiguration . getProjectByName ( 'g' ) ! ] )
148
+ } ) ;
129
149
130
150
// Single project
131
- expect ( Array . from ( operations , serializeOperation ) ) . toMatchSnapshot ( ) ;
151
+ expectOperationsToMatchSnapshot ( operations , 'single' ) ;
132
152
133
- operations = await testCreateOperationsAsync (
134
- buildCommand . phases ,
135
- new Set ( [
153
+ operations = await testCreateOperationsAsync ( {
154
+ phaseSelection : buildCommand . phases ,
155
+ projectSelection : new Set ( [
136
156
rushConfiguration . getProjectByName ( 'f' ) ! ,
137
157
rushConfiguration . getProjectByName ( 'a' ) ! ,
138
158
rushConfiguration . getProjectByName ( 'c' ) !
139
159
] ) ,
140
- new Set ( [
160
+ projectsInUnknownState : new Set ( [
141
161
rushConfiguration . getProjectByName ( 'f' ) ! ,
142
162
rushConfiguration . getProjectByName ( 'a' ) ! ,
143
163
rushConfiguration . getProjectByName ( 'c' ) !
144
164
] )
145
- ) ;
165
+ } ) ;
146
166
147
167
// Filtered projects
148
- expect ( Array . from ( operations , serializeOperation ) ) . toMatchSnapshot ( ) ;
168
+ expectOperationsToMatchSnapshot ( operations , 'filtered' ) ;
149
169
} ) ;
150
170
151
171
it ( 'handles some changed projects' , async ( ) => {
152
172
const buildCommand : IPhasedCommandConfig = commandLineConfiguration . commands . get (
153
173
'build'
154
174
) ! as IPhasedCommandConfig ;
155
175
156
- let operations : Set < Operation > = await testCreateOperationsAsync (
157
- buildCommand . phases ,
158
- new Set ( rushConfiguration . projects ) ,
159
- new Set ( [ rushConfiguration . getProjectByName ( 'g' ) ! ] )
160
- ) ;
176
+ let operations : Set < Operation > = await testCreateOperationsAsync ( {
177
+ phaseSelection : buildCommand . phases ,
178
+ projectSelection : new Set ( rushConfiguration . projects ) ,
179
+ projectsInUnknownState : new Set ( [ rushConfiguration . getProjectByName ( 'g' ) ! ] )
180
+ } ) ;
161
181
162
182
// Single project
163
- expect ( Array . from ( operations , serializeOperation ) ) . toMatchSnapshot ( ) ;
183
+ expectOperationsToMatchSnapshot ( operations , 'single' ) ;
164
184
165
- operations = await testCreateOperationsAsync (
166
- buildCommand . phases ,
167
- new Set ( rushConfiguration . projects ) ,
168
- new Set ( [
185
+ operations = await testCreateOperationsAsync ( {
186
+ phaseSelection : buildCommand . phases ,
187
+ projectSelection : new Set ( rushConfiguration . projects ) ,
188
+ projectsInUnknownState : new Set ( [
169
189
rushConfiguration . getProjectByName ( 'f' ) ! ,
170
190
rushConfiguration . getProjectByName ( 'a' ) ! ,
171
191
rushConfiguration . getProjectByName ( 'c' ) !
172
192
] )
173
- ) ;
193
+ } ) ;
174
194
175
195
// Filtered projects
176
- expect ( Array . from ( operations , serializeOperation ) ) . toMatchSnapshot ( ) ;
196
+ expectOperationsToMatchSnapshot ( operations , 'multiple' ) ;
177
197
} ) ;
178
198
179
199
it ( 'handles some changed projects within filtered projects' , async ( ) => {
180
200
const buildCommand : IPhasedCommandConfig = commandLineConfiguration . commands . get (
181
201
'build'
182
202
) ! as IPhasedCommandConfig ;
183
203
184
- const operations : Set < Operation > = await testCreateOperationsAsync (
185
- buildCommand . phases ,
186
- new Set ( [
204
+ const operations : Set < Operation > = await testCreateOperationsAsync ( {
205
+ phaseSelection : buildCommand . phases ,
206
+ projectSelection : new Set ( [
187
207
rushConfiguration . getProjectByName ( 'f' ) ! ,
188
208
rushConfiguration . getProjectByName ( 'a' ) ! ,
189
209
rushConfiguration . getProjectByName ( 'c' ) !
190
210
] ) ,
191
- new Set ( [ rushConfiguration . getProjectByName ( 'a' ) ! , rushConfiguration . getProjectByName ( 'c' ) ! ] )
192
- ) ;
211
+ projectsInUnknownState : new Set ( [
212
+ rushConfiguration . getProjectByName ( 'a' ) ! ,
213
+ rushConfiguration . getProjectByName ( 'c' ) !
214
+ ] )
215
+ } ) ;
193
216
194
217
// Single project
195
- expect ( Array . from ( operations , serializeOperation ) ) . toMatchSnapshot ( ) ;
218
+ expectOperationsToMatchSnapshot ( operations , 'multiple' ) ;
219
+ } ) ;
220
+
221
+ it ( 'handles different phaseOriginal vs phaseSelection without --include-phase-deps' , async ( ) => {
222
+ const operations : Set < Operation > = await testCreateOperationsAsync ( {
223
+ includePhaseDeps : false ,
224
+ phaseSelection : new Set ( [
225
+ commandLineConfiguration . phases . get ( '_phase:no-deps' ) ! ,
226
+ commandLineConfiguration . phases . get ( '_phase:upstream-self' ) !
227
+ ] ) ,
228
+ phaseOriginal : new Set ( [ commandLineConfiguration . phases . get ( '_phase:upstream-self' ) ! ] ) ,
229
+ projectSelection : new Set ( [ rushConfiguration . getProjectByName ( 'a' ) ! ] ) ,
230
+ projectsInUnknownState : new Set ( [ rushConfiguration . getProjectByName ( 'a' ) ! ] )
231
+ } ) ;
232
+
233
+ expectOperationsToMatchSnapshot ( operations , 'single-project' ) ;
234
+ } ) ;
235
+
236
+ it ( 'handles different phaseOriginal vs phaseSelection with --include-phase-deps' , async ( ) => {
237
+ const operations : Set < Operation > = await testCreateOperationsAsync ( {
238
+ includePhaseDeps : true ,
239
+ phaseSelection : new Set ( [
240
+ commandLineConfiguration . phases . get ( '_phase:no-deps' ) ! ,
241
+ commandLineConfiguration . phases . get ( '_phase:upstream-self' ) !
242
+ ] ) ,
243
+ phaseOriginal : new Set ( [ commandLineConfiguration . phases . get ( '_phase:upstream-self' ) ! ] ) ,
244
+ projectSelection : new Set ( [ rushConfiguration . getProjectByName ( 'a' ) ! ] ) ,
245
+ projectsInUnknownState : new Set ( [ rushConfiguration . getProjectByName ( 'a' ) ! ] )
246
+ } ) ;
247
+
248
+ expectOperationsToMatchSnapshot ( operations , 'single-project' ) ;
249
+ } ) ;
250
+
251
+ it ( 'handles different phaseOriginal vs phaseSelection cross-project with --include-phase-deps' , async ( ) => {
252
+ const operations : Set < Operation > = await testCreateOperationsAsync ( {
253
+ includePhaseDeps : true ,
254
+ phaseSelection : new Set ( [
255
+ commandLineConfiguration . phases . get ( '_phase:no-deps' ) ! ,
256
+ commandLineConfiguration . phases . get ( '_phase:upstream-1' ) !
257
+ ] ) ,
258
+ phaseOriginal : new Set ( [ commandLineConfiguration . phases . get ( '_phase:upstream-1' ) ! ] ) ,
259
+ projectSelection : new Set ( [
260
+ rushConfiguration . getProjectByName ( 'a' ) ! ,
261
+ rushConfiguration . getProjectByName ( 'h' ) !
262
+ ] ) ,
263
+ projectsInUnknownState : new Set ( [ rushConfiguration . getProjectByName ( 'h' ) ! ] )
264
+ } ) ;
265
+
266
+ expectOperationsToMatchSnapshot ( operations , 'multiple-project' ) ;
196
267
} ) ;
197
268
198
269
it ( 'handles filtered phases' , async ( ) => {
199
270
// Single phase with a missing dependency
200
- let operations : Set < Operation > = await testCreateOperationsAsync (
201
- new Set ( [ commandLineConfiguration . phases . get ( '_phase:upstream-self' ) ! ] ) ,
202
- new Set ( rushConfiguration . projects ) ,
203
- new Set ( rushConfiguration . projects )
204
- ) ;
205
- expect ( Array . from ( operations , serializeOperation ) ) . toMatchSnapshot ( ) ;
271
+ let operations : Set < Operation > = await testCreateOperationsAsync ( {
272
+ phaseSelection : new Set ( [ commandLineConfiguration . phases . get ( '_phase:upstream-self' ) ! ] ) ,
273
+ projectSelection : new Set ( rushConfiguration . projects ) ,
274
+ projectsInUnknownState : new Set ( rushConfiguration . projects )
275
+ } ) ;
276
+ expectOperationsToMatchSnapshot ( operations , 'single-phase' ) ;
206
277
207
278
// Two phases with a missing link
208
- operations = await testCreateOperationsAsync (
209
- new Set ( [
279
+ operations = await testCreateOperationsAsync ( {
280
+ phaseSelection : new Set ( [
210
281
commandLineConfiguration . phases . get ( '_phase:complex' ) ! ,
211
282
commandLineConfiguration . phases . get ( '_phase:upstream-3' ) ! ,
212
283
commandLineConfiguration . phases . get ( '_phase:upstream-1' ) ! ,
213
284
commandLineConfiguration . phases . get ( '_phase:no-deps' ) !
214
285
] ) ,
215
- new Set ( rushConfiguration . projects ) ,
216
- new Set ( rushConfiguration . projects )
217
- ) ;
218
- expect ( Array . from ( operations , serializeOperation ) ) . toMatchSnapshot ( ) ;
286
+ projectSelection : new Set ( rushConfiguration . projects ) ,
287
+ projectsInUnknownState : new Set ( rushConfiguration . projects )
288
+ } ) ;
289
+ expectOperationsToMatchSnapshot ( operations , 'two-phases' ) ;
219
290
} ) ;
220
291
221
292
it ( 'handles filtered phases on filtered projects' , async ( ) => {
222
293
// Single phase with a missing dependency
223
- let operations : Set < Operation > = await testCreateOperationsAsync (
224
- new Set ( [ commandLineConfiguration . phases . get ( '_phase:upstream-2' ) ! ] ) ,
225
- new Set ( [
294
+ let operations : Set < Operation > = await testCreateOperationsAsync ( {
295
+ phaseSelection : new Set ( [ commandLineConfiguration . phases . get ( '_phase:upstream-2' ) ! ] ) ,
296
+ projectSelection : new Set ( [
226
297
rushConfiguration . getProjectByName ( 'f' ) ! ,
227
298
rushConfiguration . getProjectByName ( 'a' ) ! ,
228
299
rushConfiguration . getProjectByName ( 'c' ) !
229
300
] ) ,
230
- new Set ( [
301
+ projectsInUnknownState : new Set ( [
231
302
rushConfiguration . getProjectByName ( 'f' ) ! ,
232
303
rushConfiguration . getProjectByName ( 'a' ) ! ,
233
304
rushConfiguration . getProjectByName ( 'c' ) !
234
305
] )
235
- ) ;
236
- expect ( Array . from ( operations , serializeOperation ) ) . toMatchSnapshot ( ) ;
306
+ } ) ;
307
+ expectOperationsToMatchSnapshot ( operations , 'single-phase' ) ;
237
308
238
309
// Phases with missing links
239
- operations = await testCreateOperationsAsync (
240
- new Set ( [
310
+ operations = await testCreateOperationsAsync ( {
311
+ phaseSelection : new Set ( [
241
312
commandLineConfiguration . phases . get ( '_phase:complex' ) ! ,
242
313
commandLineConfiguration . phases . get ( '_phase:upstream-3' ) ! ,
243
314
commandLineConfiguration . phases . get ( '_phase:upstream-1' ) ! ,
244
315
commandLineConfiguration . phases . get ( '_phase:no-deps' ) !
245
316
] ) ,
246
- new Set ( [
317
+ projectSelection : new Set ( [
247
318
rushConfiguration . getProjectByName ( 'f' ) ! ,
248
319
rushConfiguration . getProjectByName ( 'a' ) ! ,
249
320
rushConfiguration . getProjectByName ( 'c' ) !
250
321
] ) ,
251
- new Set ( [
322
+ projectsInUnknownState : new Set ( [
252
323
rushConfiguration . getProjectByName ( 'f' ) ! ,
253
324
rushConfiguration . getProjectByName ( 'a' ) ! ,
254
325
rushConfiguration . getProjectByName ( 'c' ) !
255
326
] )
256
- ) ;
257
- expect ( Array . from ( operations , serializeOperation ) ) . toMatchSnapshot ( ) ;
327
+ } ) ;
328
+ expectOperationsToMatchSnapshot ( operations , 'missing-links' ) ;
258
329
} ) ;
259
330
} ) ;
0 commit comments