Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 12 additions & 12 deletions apps/heft/src/cli/HeftActionRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -387,32 +387,32 @@ export class HeftActionRunner {
parallelism: this._parallelism,
abortSignal,
requestRun,
beforeExecuteOperationAsync: async (
beforeExecuteOperation(
operation: Operation<IHeftTaskOperationMetadata, IHeftPhaseOperationMetadata>
) => {
): void {
if (taskStart.isUsed()) {
await taskStart.promise({ operation });
taskStart.call({ operation });
}
},
afterExecuteOperationAsync: async (
afterExecuteOperation(
operation: Operation<IHeftTaskOperationMetadata, IHeftPhaseOperationMetadata>
) => {
): void {
if (taskFinish.isUsed()) {
await taskFinish.promise({ operation });
taskFinish.call({ operation });
}
},
beforeExecuteOperationGroupAsync: async (
beforeExecuteOperationGroup(
operationGroup: OperationGroupRecord<IHeftPhaseOperationMetadata>
) => {
): void {
if (operationGroup.metadata.phase && phaseStart.isUsed()) {
await phaseStart.promise({ operation: operationGroup });
phaseStart.call({ operation: operationGroup });
}
},
afterExecuteOperationGroupAsync: async (
afterExecuteOperationGroup(
operationGroup: OperationGroupRecord<IHeftPhaseOperationMetadata>
) => {
): void {
if (operationGroup.metadata.phase && phaseFinish.isUsed()) {
await phaseFinish.promise({ operation: operationGroup });
phaseFinish.call({ operation: operationGroup });
}
}
};
Expand Down
10 changes: 5 additions & 5 deletions apps/heft/src/pluginFramework/HeftLifecycle.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
// See LICENSE in the project root for license information.

import { AsyncParallelHook } from 'tapable';
import { AsyncParallelHook, SyncHook } from 'tapable';
import { InternalError } from '@rushstack/node-core-library';

import { HeftPluginConfiguration } from '../configuration/HeftPluginConfiguration';
Expand Down Expand Up @@ -72,10 +72,10 @@ export class HeftLifecycle extends HeftPluginHost {
toolStart: new AsyncParallelHook<IHeftLifecycleToolStartHookOptions>(),
toolFinish: new AsyncParallelHook<IHeftLifecycleToolFinishHookOptions>(),
recordMetrics: internalHeftSession.metricsCollector.recordMetricsHook,
taskStart: new AsyncParallelHook<IHeftTaskStartHookOptions>(['task']),
taskFinish: new AsyncParallelHook<IHeftTaskFinishHookOptions>(['task']),
phaseStart: new AsyncParallelHook<IHeftPhaseStartHookOptions>(['phase']),
phaseFinish: new AsyncParallelHook<IHeftPhaseFinishHookOptions>(['phase'])
taskStart: new SyncHook<IHeftTaskStartHookOptions>(['task']),
taskFinish: new SyncHook<IHeftTaskFinishHookOptions>(['task']),
phaseStart: new SyncHook<IHeftPhaseStartHookOptions>(['phase']),
phaseFinish: new SyncHook<IHeftPhaseFinishHookOptions>(['phase'])
};
}

Expand Down
18 changes: 9 additions & 9 deletions apps/heft/src/pluginFramework/HeftLifecycleSession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// See LICENSE in the project root for license information.

import * as path from 'path';
import type { AsyncParallelHook } from 'tapable';
import type { AsyncParallelHook, SyncHook } from 'tapable';

import type { IHeftRecordMetricsHookOptions, MetricsCollector } from '../metrics/MetricsCollector';
import type { ScopedLogger, IScopedLogger } from './logging/ScopedLogger';
Expand Down Expand Up @@ -144,35 +144,35 @@ export interface IHeftLifecycleHooks {

/**
* The `taskStart` hook is called at the beginning of a task. It is called before the task has begun
* to execute. To use it, call `taskStart.tapPromise(<pluginName>, <callback>)`.
* to execute. To use it, call `taskStart.tap(<pluginName>, <callback>)`.
*
* @public
*/
taskStart: AsyncParallelHook<IHeftTaskStartHookOptions>;
taskStart: SyncHook<IHeftTaskStartHookOptions>;

/**
* The `taskFinish` hook is called at the end of a task. It is called after the task has completed
* execution. To use it, call `taskFinish.tapPromise(<pluginName>, <callback>)`.
* execution. To use it, call `taskFinish.tap(<pluginName>, <callback>)`.
*
* @public
*/
taskFinish: AsyncParallelHook<IHeftTaskFinishHookOptions>;
taskFinish: SyncHook<IHeftTaskFinishHookOptions>;

/**
* The `phaseStart` hook is called at the beginning of a phase. It is called before the phase has
* begun to execute. To use it, call `phaseStart.tapPromise(<pluginName>, <callback>)`.
* begun to execute. To use it, call `phaseStart.tap(<pluginName>, <callback>)`.
*
* @public
*/
phaseStart: AsyncParallelHook<IHeftPhaseStartHookOptions>;
phaseStart: SyncHook<IHeftPhaseStartHookOptions>;

/**
* The `phaseFinish` hook is called at the end of a phase. It is called after the phase has completed
* execution. To use it, call `phaseFinish.tapPromise(<pluginName>, <callback>)`.
* execution. To use it, call `phaseFinish.tap(<pluginName>, <callback>)`.
*
* @public
*/
phaseFinish: AsyncParallelHook<IHeftPhaseFinishHookOptions>;
phaseFinish: SyncHook<IHeftPhaseFinishHookOptions>;
}

/**
Expand Down
8 changes: 4 additions & 4 deletions build-tests/heft-example-lifecycle-plugin/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export const PLUGIN_NAME: 'example-lifecycle-plugin' = 'example-lifecycle-plugin
export default class ExampleLifecyclePlugin implements IHeftLifecyclePlugin {
public apply(session: IHeftLifecycleSession): void {
const { logger } = session;
session.hooks.taskFinish.tapPromise(PLUGIN_NAME, async (options: IHeftTaskFinishHookOptions) => {
session.hooks.taskFinish.tap(PLUGIN_NAME, (options: IHeftTaskFinishHookOptions) => {
const {
operation: {
metadata: { task },
Expand All @@ -29,7 +29,7 @@ export default class ExampleLifecyclePlugin implements IHeftLifecyclePlugin {
}
});

session.hooks.taskStart.tapPromise(PLUGIN_NAME, async (options: IHeftTaskStartHookOptions) => {
session.hooks.taskStart.tap(PLUGIN_NAME, (options: IHeftTaskStartHookOptions) => {
const {
operation: {
metadata: { task }
Expand All @@ -38,7 +38,7 @@ export default class ExampleLifecyclePlugin implements IHeftLifecyclePlugin {
logger.terminal.writeLine(`--- ${task.taskName} started ---`);
});

session.hooks.phaseStart.tapPromise(PLUGIN_NAME, async (options: IHeftPhaseStartHookOptions) => {
session.hooks.phaseStart.tap(PLUGIN_NAME, (options: IHeftPhaseStartHookOptions) => {
const {
operation: {
metadata: { phase }
Expand All @@ -47,7 +47,7 @@ export default class ExampleLifecyclePlugin implements IHeftLifecyclePlugin {
logger.terminal.writeLine(`--- ${phase.phaseName} started ---`);
});

session.hooks.phaseFinish.tapPromise(PLUGIN_NAME, async (options: IHeftPhaseFinishHookOptions) => {
session.hooks.phaseFinish.tap(PLUGIN_NAME, (options: IHeftPhaseFinishHookOptions) => {
const {
operation: {
metadata: { phase },
Expand Down
10 changes: 10 additions & 0 deletions common/changes/@rushstack/heft/sync-hooks_2025-09-29-22-50.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@rushstack/heft",
"comment": "(BREAKING CHANGE) Make the `taskStart`/`taskFinish`/`phaseStart`/`phaseFinish` hooks synchronous to signify that they are not intended to be used for expensive work.",
"type": "minor"
}
],
"packageName": "@rushstack/heft"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@rushstack/operation-graph",
"comment": "(BREAKING CHANGE) Revert the extensibility points for `(before/after)ExecuteOperation(Group)?Async` to be synchronous to signify that they are only meant for logging, not for expensive work.",
"type": "minor"
}
],
"packageName": "@rushstack/operation-graph"
}
9 changes: 5 additions & 4 deletions common/reviews/api/heft.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import type { Operation } from '@rushstack/operation-graph';
import type { OperationGroupRecord } from '@rushstack/operation-graph';
import { PathResolutionMethod } from '@rushstack/heft-config-file';
import { PropertyInheritanceCustomFunction } from '@rushstack/heft-config-file';
import type { SyncHook } from 'tapable';

export { CommandLineChoiceListParameter }

Expand Down Expand Up @@ -152,11 +153,11 @@ export interface IHeftLifecycleCleanHookOptions {
// @public
export interface IHeftLifecycleHooks {
clean: AsyncParallelHook<IHeftLifecycleCleanHookOptions>;
phaseFinish: AsyncParallelHook<IHeftPhaseFinishHookOptions>;
phaseStart: AsyncParallelHook<IHeftPhaseStartHookOptions>;
phaseFinish: SyncHook<IHeftPhaseFinishHookOptions>;
phaseStart: SyncHook<IHeftPhaseStartHookOptions>;
recordMetrics: AsyncParallelHook<IHeftRecordMetricsHookOptions>;
taskFinish: AsyncParallelHook<IHeftTaskFinishHookOptions>;
taskStart: AsyncParallelHook<IHeftTaskStartHookOptions>;
taskFinish: SyncHook<IHeftTaskFinishHookOptions>;
taskStart: SyncHook<IHeftTaskStartHookOptions>;
toolFinish: AsyncParallelHook<IHeftLifecycleToolFinishHookOptions>;
toolStart: AsyncParallelHook<IHeftLifecycleToolStartHookOptions>;
}
Expand Down
12 changes: 6 additions & 6 deletions common/reviews/api/operation-graph.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ export interface ICancelCommandMessage {

// @beta
export interface IExecuteOperationContext extends Omit<IOperationRunnerContext, 'isFirstRun' | 'requestRun'> {
afterExecuteAsync(operation: Operation, state: IOperationState): Promise<void>;
beforeExecuteAsync(operation: Operation, state: IOperationState): Promise<void>;
afterExecute(operation: Operation, state: IOperationState): void;
beforeExecute(operation: Operation, state: IOperationState): void;
queueWork(workFn: () => Promise<OperationStatus>, priority: number): Promise<OperationStatus>;
requestRun?: OperationRequestRunCallback;
terminal: ITerminal;
Expand All @@ -48,13 +48,13 @@ export interface IOperationExecutionOptions<TOperationMetadata extends {} = {},
// (undocumented)
abortSignal: AbortSignal;
// (undocumented)
afterExecuteOperationAsync?: (operation: Operation<TOperationMetadata, TGroupMetadata>) => Promise<void>;
afterExecuteOperation?: (operation: Operation<TOperationMetadata, TGroupMetadata>) => void;
// (undocumented)
afterExecuteOperationGroupAsync?: (operationGroup: OperationGroupRecord<TGroupMetadata>) => Promise<void>;
afterExecuteOperationGroup?: (operationGroup: OperationGroupRecord<TGroupMetadata>) => void;
// (undocumented)
beforeExecuteOperationAsync?: (operation: Operation<TOperationMetadata, TGroupMetadata>) => Promise<void>;
beforeExecuteOperation?: (operation: Operation<TOperationMetadata, TGroupMetadata>) => void;
// (undocumented)
beforeExecuteOperationGroupAsync?: (operationGroup: OperationGroupRecord<TGroupMetadata>) => Promise<void>;
beforeExecuteOperationGroup?: (operationGroup: OperationGroupRecord<TGroupMetadata>) => void;
// (undocumented)
parallelism: number;
// (undocumented)
Expand Down
8 changes: 4 additions & 4 deletions libraries/operation-graph/src/Operation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,12 @@ export interface IExecuteOperationContext extends Omit<IOperationRunnerContext,
/**
* Function to invoke before execution of an operation, for logging.
*/
beforeExecuteAsync(operation: Operation, state: IOperationState): Promise<void>;
beforeExecute(operation: Operation, state: IOperationState): void;

/**
* Function to invoke after execution of an operation, for logging.
*/
afterExecuteAsync(operation: Operation, state: IOperationState): Promise<void>;
afterExecute(operation: Operation, state: IOperationState): void;

/**
* Function used to schedule the concurrency-limited execution of an operation.
Expand Down Expand Up @@ -328,7 +328,7 @@ export class Operation<TMetadata extends {} = {}, TGroupMetadata extends {} = {}
return innerState.status;
}

await context.beforeExecuteAsync(this, innerState);
context.beforeExecute(this, innerState);

innerState.stopwatch.start();
innerState.status = OperationStatus.Executing;
Expand Down Expand Up @@ -365,7 +365,7 @@ export class Operation<TMetadata extends {} = {}, TGroupMetadata extends {} = {}
}

state.stopwatch.stop();
await context.afterExecuteAsync(this, state);
context.afterExecute(this, state);

return state.status;
}, /* priority */ this.criticalPathLength ?? 0);
Expand Down
24 changes: 11 additions & 13 deletions libraries/operation-graph/src/OperationExecutionManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ export interface IOperationExecutionOptions<

requestRun?: OperationRequestRunCallback;

beforeExecuteOperationAsync?: (operation: Operation<TOperationMetadata, TGroupMetadata>) => Promise<void>;
afterExecuteOperationAsync?: (operation: Operation<TOperationMetadata, TGroupMetadata>) => Promise<void>;
beforeExecuteOperationGroupAsync?: (operationGroup: OperationGroupRecord<TGroupMetadata>) => Promise<void>;
afterExecuteOperationGroupAsync?: (operationGroup: OperationGroupRecord<TGroupMetadata>) => Promise<void>;
beforeExecuteOperation?: (operation: Operation<TOperationMetadata, TGroupMetadata>) => void;
afterExecuteOperation?: (operation: Operation<TOperationMetadata, TGroupMetadata>) => void;
beforeExecuteOperationGroup?: (operationGroup: OperationGroupRecord<TGroupMetadata>) => void;
afterExecuteOperationGroup?: (operationGroup: OperationGroupRecord<TGroupMetadata>) => void;
}

/**
Expand Down Expand Up @@ -126,28 +126,26 @@ export class OperationExecutionManager<TOperationMetadata extends {} = {}, TGrou
return workQueue.pushAsync(workFn, priority);
},

beforeExecuteAsync: async (
operation: Operation<TOperationMetadata, TGroupMetadata>
): Promise<void> => {
beforeExecute: (operation: Operation<TOperationMetadata, TGroupMetadata>): void => {
// Initialize group if uninitialized and log the group name
const { group, runner } = operation;
if (group) {
if (!startedGroups.has(group)) {
startedGroups.add(group);
group.startTimer();
terminal.writeLine(` ---- ${group.name} started ---- `);
await executionOptions.beforeExecuteOperationGroupAsync?.(group);
executionOptions.beforeExecuteOperationGroup?.(group);
}
}
if (!runner?.silent) {
await executionOptions.beforeExecuteOperationAsync?.(operation);
executionOptions.beforeExecuteOperation?.(operation);
}
},

afterExecuteAsync: async (
afterExecute: (
operation: Operation<TOperationMetadata, TGroupMetadata>,
state: IOperationState
): Promise<void> => {
): void => {
const { group, runner } = operation;
if (group) {
group.setOperationAsComplete(operation, state);
Expand All @@ -165,7 +163,7 @@ export class OperationExecutionManager<TOperationMetadata extends {} = {}, TGrou
}

if (!runner?.silent) {
await executionOptions.afterExecuteOperationAsync?.(operation);
executionOptions.afterExecuteOperation?.(operation);
}

if (group) {
Expand All @@ -180,7 +178,7 @@ export class OperationExecutionManager<TOperationMetadata extends {} = {}, TGrou
terminal.writeLine(
` ---- ${group.name} ${finishedLoggingWord} (${group.duration.toFixed(3)}s) ---- `
);
await executionOptions.afterExecuteOperationGroupAsync?.(group);
executionOptions.afterExecuteOperationGroup?.(group);
}
}
}
Expand Down
Loading