diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.test.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.test.ts index 25caf7bad0..b76356a586 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.test.ts @@ -152,19 +152,41 @@ describe('NunjucksWorkflowRunner', () => { id: 'checkpoints-action', description: 'Mock action with checkpoints', handler: async ctx => { - const key1 = await ctx.checkpoint('key1', async () => { - return 'updated'; + const key1 = await ctx.checkpoint({ + key: 'key1', + fn: async () => { + return 'updated'; + }, }); - const key2 = await ctx.checkpoint('key2', async () => { - return 'updated'; + const key2 = await ctx.checkpoint({ + key: 'key2', + fn: async () => { + return 'updated'; + }, }); - const key3 = await ctx.checkpoint('key3', async () => { - return 'updated'; + const key3 = await ctx.checkpoint({ + key: 'key3', + fn: async () => { + return 'updated'; + }, + }); + + const key4 = await ctx.checkpoint({ + fn: () => {}, + }); + + const key5 = await ctx.checkpoint({ + fn: async () => {}, }); ctx.output('key1', key1); ctx.output('key2', key2); ctx.output('key3', key3); + + // @ts-expect-error - this is void return + ctx.output('key4', key4); + // @ts-expect-error - this is void return + ctx.output('key5', key5); }, }); diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts index 6f7551568f..8a4cb8767f 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts @@ -364,6 +364,8 @@ export class NunjucksWorkflowRunner implements WorkflowRunner { )}`, ); } + let checkpointCount = 0; + await action.handler({ input: iteration.input, secrets: task.secrets ?? {}, @@ -371,21 +373,26 @@ export class NunjucksWorkflowRunner implements WorkflowRunner { logger: loggerToWinstonLogger(taskLogger), logStream: streamLogger, workspacePath, - async checkpoint( - keySuffix: string, - fn: () => Promise, - ) { - const key = `v1.task.checkpoint.${step.id}.${keySuffix}`; + async checkpoint(opts: { + key?: string; + fn: () => Promise | T; + }) { + const { key: checkpointKey = checkpointCount++, fn } = opts; + // default the task checkpoint to stepId plus count if there's no explict key provided. + const key = `v1.task.checkpoint.${step.id}.${checkpointKey}`; + try { - let prevValue: U | undefined; + let prevValue: T | undefined; + if (prevTaskState) { const prevState = ( prevTaskState.state?.checkpoints as { [key: string]: CheckpointState; } )?.[key]; + if (prevState && prevState.status === 'success') { - prevValue = prevState.value as U; + prevValue = prevState.value as T; } } @@ -395,7 +402,7 @@ export class NunjucksWorkflowRunner implements WorkflowRunner { task.updateCheckpoint?.({ key, status: 'success', - value, + value: value ?? {}, }); } return value; diff --git a/plugins/scaffolder-node/src/actions/types.ts b/plugins/scaffolder-node/src/actions/types.ts index f0e4c12869..f24dc154e2 100644 --- a/plugins/scaffolder-node/src/actions/types.ts +++ b/plugins/scaffolder-node/src/actions/types.ts @@ -38,10 +38,10 @@ export type ActionContext< secrets?: TaskSecrets; workspacePath: string; input: TActionInput; - checkpoint( - key: string, - fn: () => Promise, - ): Promise; + checkpoint(opts: { + key?: string; + fn: () => Promise | U; + }): Promise; output( name: keyof TActionOutput, value: TActionOutput[keyof TActionOutput],