Merge pull request #27640 from backstage/blam/retries
scaffolder: move checkpoints to objects notation instead
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend': minor
|
||||
'@backstage/plugin-scaffolder-node': minor
|
||||
---
|
||||
|
||||
BREAKING EXPERIMENTAL: The `checkpoint` method now takes an object instead of previous arguments.
|
||||
|
||||
```ts
|
||||
await ctx.checkpoint({ key: 'repo.create', fn: () => ockokit.repo.create({...})})
|
||||
```
|
||||
|
||||
You can also now return `void` from the checkpoint if the method returns `void` inside the `checkpoint` handler.
|
||||
@@ -152,19 +152,37 @@ 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 () => 'updated',
|
||||
});
|
||||
const key2 = await ctx.checkpoint('key2', async () => {
|
||||
return 'updated';
|
||||
const key2 = await ctx.checkpoint({
|
||||
key: 'key2',
|
||||
fn: async () => 'updated',
|
||||
});
|
||||
const key3 = await ctx.checkpoint('key3', async () => {
|
||||
return 'updated';
|
||||
const key3 = await ctx.checkpoint({
|
||||
key: 'key3',
|
||||
fn: async () => 'updated',
|
||||
});
|
||||
|
||||
const key4 = await ctx.checkpoint({
|
||||
key: 'key4',
|
||||
fn: () => {},
|
||||
});
|
||||
|
||||
const key5 = await ctx.checkpoint({
|
||||
key: 'key5',
|
||||
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);
|
||||
},
|
||||
});
|
||||
|
||||
@@ -632,6 +650,9 @@ describe('NunjucksWorkflowRunner', () => {
|
||||
key1: '${{steps.test.output.key1}}',
|
||||
key2: '${{steps.test.output.key2}}',
|
||||
key3: '${{steps.test.output.key3}}',
|
||||
key4: '${{steps.test.output.key4}}',
|
||||
key5: '${{steps.test.output.key5}}',
|
||||
key6: '${{steps.test.output.key6}}',
|
||||
},
|
||||
}),
|
||||
getTaskState: (): Promise<
|
||||
@@ -661,6 +682,8 @@ describe('NunjucksWorkflowRunner', () => {
|
||||
expect(result.output.key1).toEqual('initial');
|
||||
expect(result.output.key2).toEqual('updated');
|
||||
expect(result.output.key3).toEqual('updated');
|
||||
expect(result.output.key4).toEqual(undefined);
|
||||
expect(result.output.key5).toEqual(undefined);
|
||||
});
|
||||
|
||||
it('should template the output from simple actions', async () => {
|
||||
|
||||
@@ -364,6 +364,7 @@ export class NunjucksWorkflowRunner implements WorkflowRunner {
|
||||
)}`,
|
||||
);
|
||||
}
|
||||
|
||||
await action.handler({
|
||||
input: iteration.input,
|
||||
secrets: task.secrets ?? {},
|
||||
@@ -371,21 +372,25 @@ export class NunjucksWorkflowRunner implements WorkflowRunner {
|
||||
logger: loggerToWinstonLogger(taskLogger),
|
||||
logStream: streamLogger,
|
||||
workspacePath,
|
||||
async checkpoint<U extends JsonValue>(
|
||||
keySuffix: string,
|
||||
fn: () => Promise<U>,
|
||||
) {
|
||||
const key = `v1.task.checkpoint.${step.id}.${keySuffix}`;
|
||||
async checkpoint<T extends JsonValue | void>(opts: {
|
||||
key?: string;
|
||||
fn: () => Promise<T> | T;
|
||||
}) {
|
||||
const { key: checkpointKey, fn } = opts;
|
||||
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 +400,7 @@ export class NunjucksWorkflowRunner implements WorkflowRunner {
|
||||
task.updateCheckpoint?.({
|
||||
key,
|
||||
status: 'success',
|
||||
value,
|
||||
value: value ?? {},
|
||||
});
|
||||
}
|
||||
return value;
|
||||
|
||||
@@ -31,10 +31,10 @@ export type ActionContext<
|
||||
secrets?: TaskSecrets;
|
||||
workspacePath: string;
|
||||
input: TActionInput;
|
||||
checkpoint<U extends JsonValue>(
|
||||
key: string,
|
||||
fn: () => Promise<U>,
|
||||
): Promise<U>;
|
||||
checkpoint<T extends JsonValue | void>(opts: {
|
||||
key: string;
|
||||
fn: () => Promise<T> | T;
|
||||
}): Promise<T>;
|
||||
output(
|
||||
name: keyof TActionOutput,
|
||||
value: TActionOutput[keyof TActionOutput],
|
||||
|
||||
@@ -38,10 +38,10 @@ export type ActionContext<
|
||||
secrets?: TaskSecrets;
|
||||
workspacePath: string;
|
||||
input: TActionInput;
|
||||
checkpoint<U extends JsonValue>(
|
||||
key: string,
|
||||
fn: () => Promise<U>,
|
||||
): Promise<U>;
|
||||
checkpoint<T extends JsonValue | void>(opts: {
|
||||
key: string;
|
||||
fn: () => Promise<T> | T;
|
||||
}): Promise<T>;
|
||||
output(
|
||||
name: keyof TActionOutput,
|
||||
value: TActionOutput[keyof TActionOutput],
|
||||
|
||||
Reference in New Issue
Block a user