@@ -12,6 +12,7 @@ import {
12
12
type IWatchLoopState ,
13
13
Operation ,
14
14
OperationExecutionManager ,
15
+ OperationGroupRecord ,
15
16
OperationStatus ,
16
17
WatchLoop
17
18
} from '@rushstack/operation-graph' ;
@@ -28,7 +29,7 @@ import type { MetricsCollector } from '../metrics/MetricsCollector';
28
29
import { HeftParameterManager } from '../pluginFramework/HeftParameterManager' ;
29
30
import { TaskOperationRunner } from '../operations/runners/TaskOperationRunner' ;
30
31
import { PhaseOperationRunner } from '../operations/runners/PhaseOperationRunner' ;
31
- import type { HeftPhase } from '../pluginFramework/HeftPhase' ;
32
+ import type { IHeftPhase , HeftPhase } from '../pluginFramework/HeftPhase' ;
32
33
import type { IHeftAction , IHeftActionOptions } from './actions/IHeftAction' ;
33
34
import type {
34
35
IHeftLifecycleCleanHookOptions ,
@@ -37,14 +38,31 @@ import type {
37
38
IHeftLifecycleToolStartHookOptions
38
39
} from '../pluginFramework/HeftLifecycleSession' ;
39
40
import type { HeftLifecycle } from '../pluginFramework/HeftLifecycle' ;
40
- import type { HeftTask } from '../pluginFramework/HeftTask' ;
41
+ import type { IHeftTask , HeftTask } from '../pluginFramework/HeftTask' ;
41
42
import { deleteFilesAsync , type IDeleteOperation } from '../plugins/DeleteFilesPlugin' ;
42
43
import { Constants } from '../utilities/Constants' ;
43
44
44
45
export interface IHeftActionRunnerOptions extends IHeftActionOptions {
45
46
action : IHeftAction ;
46
47
}
47
48
49
+ /**
50
+ * Metadata for an operation that represents a task.
51
+ * @public
52
+ */
53
+ export interface IHeftTaskOperationMetadata {
54
+ task : IHeftTask ;
55
+ phase : IHeftPhase ;
56
+ }
57
+
58
+ /**
59
+ * Metadata for an operation that represents a phase.
60
+ * @public
61
+ */
62
+ export interface IHeftPhaseOperationMetadata {
63
+ phase : IHeftPhase ;
64
+ }
65
+
48
66
export function initializeHeft (
49
67
heftConfiguration : HeftConfiguration ,
50
68
terminal : ITerminal ,
@@ -291,9 +309,13 @@ export class HeftActionRunner {
291
309
292
310
initializeHeft ( this . _heftConfiguration , terminal , this . parameterManager . defaultParameters . verbose ) ;
293
311
294
- const operations : ReadonlySet < Operation > = this . _generateOperations ( ) ;
312
+ const operations : ReadonlySet < Operation < IHeftTaskOperationMetadata , IHeftPhaseOperationMetadata > > =
313
+ this . _generateOperations ( ) ;
295
314
296
- const executionManager : OperationExecutionManager = new OperationExecutionManager ( operations ) ;
315
+ const executionManager : OperationExecutionManager <
316
+ IHeftTaskOperationMetadata ,
317
+ IHeftPhaseOperationMetadata
318
+ > = new OperationExecutionManager ( operations ) ;
297
319
298
320
const cliAbortSignal : AbortSignal = ensureCliAbortSignal ( this . _terminal ) ;
299
321
@@ -346,20 +368,52 @@ export class HeftActionRunner {
346
368
}
347
369
348
370
private async _executeOnceAsync (
349
- executionManager : OperationExecutionManager ,
371
+ executionManager : OperationExecutionManager < IHeftTaskOperationMetadata , IHeftPhaseOperationMetadata > ,
350
372
abortSignal : AbortSignal ,
351
373
requestRun ?: ( requestor ?: string ) => void
352
374
) : Promise < OperationStatus > {
375
+ const { taskStart, taskFinish, phaseStart, phaseFinish } = this . _internalHeftSession . lifecycle . hooks ;
353
376
// Record this as the start of task execution.
354
377
this . _metricsCollector . setStartTime ( ) ;
355
378
// Execute the action operations
356
379
return await runWithLoggingAsync (
357
380
( ) => {
358
- const operationExecutionManagerOptions : IOperationExecutionOptions = {
381
+ const operationExecutionManagerOptions : IOperationExecutionOptions <
382
+ IHeftTaskOperationMetadata ,
383
+ IHeftPhaseOperationMetadata
384
+ > = {
359
385
terminal : this . _terminal ,
360
386
parallelism : this . _parallelism ,
361
387
abortSignal,
362
- requestRun
388
+ requestRun,
389
+ beforeExecuteOperationAsync : async (
390
+ operation : Operation < IHeftTaskOperationMetadata , IHeftPhaseOperationMetadata >
391
+ ) => {
392
+ if ( taskStart . isUsed ( ) ) {
393
+ await taskStart . promise ( { operation } ) ;
394
+ }
395
+ } ,
396
+ afterExecuteOperationAsync : async (
397
+ operation : Operation < IHeftTaskOperationMetadata , IHeftPhaseOperationMetadata >
398
+ ) => {
399
+ if ( taskFinish . isUsed ( ) ) {
400
+ await taskFinish . promise ( { operation } ) ;
401
+ }
402
+ } ,
403
+ beforeExecuteOperationGroupAsync : async (
404
+ operationGroup : OperationGroupRecord < IHeftPhaseOperationMetadata >
405
+ ) => {
406
+ if ( operationGroup . metadata . phase && phaseStart . isUsed ( ) ) {
407
+ await phaseStart . promise ( { operation : operationGroup } ) ;
408
+ }
409
+ } ,
410
+ afterExecuteOperationGroupAsync : async (
411
+ operationGroup : OperationGroupRecord < IHeftPhaseOperationMetadata >
412
+ ) => {
413
+ if ( operationGroup . metadata . phase && phaseFinish . isUsed ( ) ) {
414
+ await phaseFinish . promise ( { operation : operationGroup } ) ;
415
+ }
416
+ }
363
417
} ;
364
418
365
419
return executionManager . executeAsync ( operationExecutionManagerOptions ) ;
@@ -373,10 +427,14 @@ export class HeftActionRunner {
373
427
) ;
374
428
}
375
429
376
- private _generateOperations ( ) : Set < Operation > {
430
+ private _generateOperations ( ) : Set < Operation < IHeftTaskOperationMetadata , IHeftPhaseOperationMetadata > > {
377
431
const { selectedPhases } = this . _action ;
378
432
379
- const operations : Map < string , Operation > = new Map ( ) ;
433
+ const operations : Map <
434
+ string ,
435
+ Operation < IHeftTaskOperationMetadata , IHeftPhaseOperationMetadata >
436
+ > = new Map ( ) ;
437
+ const operationGroups : Map < string , OperationGroupRecord < IHeftPhaseOperationMetadata > > = new Map ( ) ;
380
438
const internalHeftSession : InternalHeftSession = this . _internalHeftSession ;
381
439
382
440
let hasWarnedAboutSkippedPhases : boolean = false ;
@@ -399,18 +457,28 @@ export class HeftActionRunner {
399
457
}
400
458
401
459
// Create operation for the phase start node
402
- const phaseOperation : Operation = _getOrCreatePhaseOperation ( internalHeftSession , phase , operations ) ;
460
+ const phaseOperation : Operation = _getOrCreatePhaseOperation (
461
+ internalHeftSession ,
462
+ phase ,
463
+ operations ,
464
+ operationGroups
465
+ ) ;
403
466
404
467
// Create operations for each task
405
468
for ( const task of phase . tasks ) {
406
- const taskOperation : Operation = _getOrCreateTaskOperation ( internalHeftSession , task , operations ) ;
469
+ const taskOperation : Operation = _getOrCreateTaskOperation (
470
+ internalHeftSession ,
471
+ task ,
472
+ operations ,
473
+ operationGroups
474
+ ) ;
407
475
// Set the phase operation as a dependency of the task operation to ensure the phase operation runs first
408
476
taskOperation . addDependency ( phaseOperation ) ;
409
477
410
478
// Set all dependency tasks as dependencies of the task operation
411
479
for ( const dependencyTask of task . dependencyTasks ) {
412
480
taskOperation . addDependency (
413
- _getOrCreateTaskOperation ( internalHeftSession , dependencyTask , operations )
481
+ _getOrCreateTaskOperation ( internalHeftSession , dependencyTask , operations , operationGroups )
414
482
) ;
415
483
}
416
484
@@ -422,7 +490,8 @@ export class HeftActionRunner {
422
490
const consumingPhaseOperation : Operation = _getOrCreatePhaseOperation (
423
491
internalHeftSession ,
424
492
consumingPhase ,
425
- operations
493
+ operations ,
494
+ operationGroups
426
495
) ;
427
496
consumingPhaseOperation . addDependency ( taskOperation ) ;
428
497
// This is purely to simplify the reported graph for phase circularities
@@ -440,15 +509,24 @@ function _getOrCreatePhaseOperation(
440
509
this : void ,
441
510
internalHeftSession : InternalHeftSession ,
442
511
phase : HeftPhase ,
443
- operations : Map < string , Operation >
512
+ operations : Map < string , Operation > ,
513
+ operationGroups : Map < string , OperationGroupRecord < IHeftPhaseOperationMetadata > >
444
514
) : Operation {
445
515
const key : string = phase . phaseName ;
446
516
447
517
let operation : Operation | undefined = operations . get ( key ) ;
448
518
if ( ! operation ) {
519
+ let group : OperationGroupRecord < IHeftPhaseOperationMetadata > | undefined = operationGroups . get (
520
+ phase . phaseName
521
+ ) ;
522
+ if ( ! group ) {
523
+ group = new OperationGroupRecord ( phase . phaseName , { phase } ) ;
524
+ operationGroups . set ( phase . phaseName , group ) ;
525
+ }
449
526
// Only create the operation. Dependencies are hooked up separately
450
527
operation = new Operation ( {
451
- groupName : phase . phaseName ,
528
+ group,
529
+ name : phase . phaseName ,
452
530
runner : new PhaseOperationRunner ( { phase, internalHeftSession } )
453
531
} ) ;
454
532
operations . set ( key , operation ) ;
@@ -460,18 +538,31 @@ function _getOrCreateTaskOperation(
460
538
this : void ,
461
539
internalHeftSession : InternalHeftSession ,
462
540
task : HeftTask ,
463
- operations : Map < string , Operation >
541
+ operations : Map < string , Operation > ,
542
+ operationGroups : Map < string , OperationGroupRecord < IHeftPhaseOperationMetadata > >
464
543
) : Operation {
465
544
const key : string = `${ task . parentPhase . phaseName } .${ task . taskName } ` ;
466
545
467
- let operation : Operation | undefined = operations . get ( key ) ;
546
+ let operation : Operation < IHeftTaskOperationMetadata > | undefined = operations . get (
547
+ key
548
+ ) as Operation < IHeftTaskOperationMetadata > ;
468
549
if ( ! operation ) {
550
+ const group : OperationGroupRecord < IHeftPhaseOperationMetadata > | undefined = operationGroups . get (
551
+ task . parentPhase . phaseName
552
+ ) ;
553
+ if ( ! group ) {
554
+ throw new InternalError (
555
+ `Task ${ task . taskName } in phase ${ task . parentPhase . phaseName } has no group. This should not happen.`
556
+ ) ;
557
+ }
469
558
operation = new Operation ( {
470
- groupName : task . parentPhase . phaseName ,
559
+ group ,
471
560
runner : new TaskOperationRunner ( {
472
561
internalHeftSession,
473
562
task
474
- } )
563
+ } ) ,
564
+ name : task . taskName ,
565
+ metadata : { task, phase : task . parentPhase }
475
566
} ) ;
476
567
operations . set ( key , operation ) ;
477
568
}
0 commit comments