@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-node-test-utils': patch
|
||||
'@backstage/plugin-scaffolder-backend': patch
|
||||
'@backstage/plugin-scaffolder-node': patch
|
||||
---
|
||||
|
||||
An internal refactor which adds additional types to experimental checkpoints
|
||||
@@ -37,7 +37,7 @@ import { TemplateEntityStepV1beta3 } from '@backstage/plugin-scaffolder-common';
|
||||
import { TemplateFilter } from '@backstage/plugin-scaffolder-node';
|
||||
import { TemplateGlobal } from '@backstage/plugin-scaffolder-node';
|
||||
import { TemplateParametersV1beta3 } from '@backstage/plugin-scaffolder-common';
|
||||
import { UpdateCheckpointOptions } from '@backstage/plugin-scaffolder-node';
|
||||
import { UpdateTaskCheckpointOptions } from '@backstage/plugin-scaffolder-node';
|
||||
import { UrlReaderService } from '@backstage/backend-plugin-api';
|
||||
import { WorkspaceProvider } from '@backstage/plugin-scaffolder-node/alpha';
|
||||
|
||||
@@ -442,7 +442,7 @@ export class TaskManager implements TaskContext {
|
||||
// (undocumented)
|
||||
get spec(): TaskSpecV1beta3;
|
||||
// (undocumented)
|
||||
updateCheckpoint?(options: UpdateCheckpointOptions): Promise<void>;
|
||||
updateCheckpoint?(options: UpdateTaskCheckpointOptions): Promise<void>;
|
||||
}
|
||||
|
||||
// @public @deprecated
|
||||
|
||||
@@ -50,7 +50,7 @@ import {
|
||||
import { createConditionAuthorizer } from '@backstage/plugin-permission-node';
|
||||
import { actionExecutePermission } from '@backstage/plugin-scaffolder-common/alpha';
|
||||
import {
|
||||
CheckpointOptions,
|
||||
CheckpointContext,
|
||||
TaskContext,
|
||||
TemplateAction,
|
||||
TemplateFilter,
|
||||
@@ -377,7 +377,7 @@ export class NunjucksWorkflowRunner implements WorkflowRunner {
|
||||
logger: taskLogger,
|
||||
workspacePath,
|
||||
async checkpoint<T extends JsonValue | void>(
|
||||
opts: CheckpointOptions<T>,
|
||||
opts: CheckpointContext<T>,
|
||||
) {
|
||||
const { key: checkpointKey, fn } = opts;
|
||||
const key = `v1.task.checkpoint.${step.id}.${checkpointKey}`;
|
||||
|
||||
@@ -23,6 +23,7 @@ import {
|
||||
import { Config } from '@backstage/config';
|
||||
import { TaskSpec } from '@backstage/plugin-scaffolder-common';
|
||||
import {
|
||||
CheckpointState,
|
||||
SerializedTask,
|
||||
SerializedTaskEvent,
|
||||
TaskBroker,
|
||||
@@ -31,6 +32,7 @@ import {
|
||||
TaskContext,
|
||||
TaskSecrets,
|
||||
TaskStatus,
|
||||
UpdateTaskCheckpointOptions,
|
||||
} from '@backstage/plugin-scaffolder-node';
|
||||
import { WorkspaceProvider } from '@backstage/plugin-scaffolder-node/alpha';
|
||||
import { JsonObject, Observable, createDeferred } from '@backstage/types';
|
||||
@@ -38,17 +40,10 @@ import ObservableImpl from 'zen-observable';
|
||||
import { DefaultWorkspaceService, WorkspaceService } from './WorkspaceService';
|
||||
import { readDuration } from './helper';
|
||||
import { InternalTaskSecrets, TaskStore } from './types';
|
||||
import {
|
||||
CheckpointState,
|
||||
CheckpointSuccessState,
|
||||
CheckpointFailedState,
|
||||
UpdateCheckpointOptions,
|
||||
} from '@backstage/plugin-scaffolder-node';
|
||||
|
||||
type TaskState = {
|
||||
checkpoints: CheckpointState;
|
||||
};
|
||||
|
||||
/**
|
||||
* TaskManager
|
||||
* @deprecated this type is deprecated, and there will be a new way to create Workers in the next major version.
|
||||
@@ -144,57 +139,14 @@ export class TaskManager implements TaskContext {
|
||||
return this.storage.getTaskState?.({ taskId: this.task.taskId });
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to safely access the checkpoints field from task state
|
||||
* Ensures type safety when working with task state that might not match our structure
|
||||
*/
|
||||
private getCheckpointsFromState(state?: JsonObject): CheckpointState {
|
||||
if (
|
||||
state &&
|
||||
'checkpoints' in state &&
|
||||
typeof state.checkpoints === 'object'
|
||||
) {
|
||||
return state.checkpoints as CheckpointState;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
async updateCheckpoint?(options: UpdateCheckpointOptions): Promise<void> {
|
||||
const { key, status } = options;
|
||||
|
||||
// Extract appropriate state value based on status
|
||||
let checkpointValue: CheckpointSuccessState | CheckpointFailedState;
|
||||
|
||||
switch (status) {
|
||||
case 'success': {
|
||||
const { value } = options;
|
||||
checkpointValue = { status, value };
|
||||
break;
|
||||
}
|
||||
case 'failed': {
|
||||
const { reason } = options;
|
||||
checkpointValue = { status, reason };
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
// Using status as 'never' gives compile-time guarantee we've handled all cases
|
||||
const exhaustiveCheck: never = status;
|
||||
throw new Error(`Unexpected status: ${exhaustiveCheck}`);
|
||||
}
|
||||
}
|
||||
async updateCheckpoint?(options: UpdateTaskCheckpointOptions): Promise<void> {
|
||||
const { key, ...value } = options;
|
||||
|
||||
if (this.task.state) {
|
||||
const taskState: TaskState = {
|
||||
checkpoints: this.getCheckpointsFromState(this.task.state),
|
||||
};
|
||||
|
||||
// Update with the new checkpoint
|
||||
taskState.checkpoints[key] = checkpointValue;
|
||||
this.task.state = taskState;
|
||||
(this.task.state as TaskState).checkpoints[key] = value;
|
||||
} else {
|
||||
this.task.state = { checkpoints: { [key]: checkpointValue } };
|
||||
this.task.state = { checkpoints: { [key]: value } };
|
||||
}
|
||||
|
||||
await this.storage.saveTaskState?.({
|
||||
taskId: this.task.taskId,
|
||||
state: this.task.state,
|
||||
@@ -278,9 +230,6 @@ export interface CurrentClaimedTask {
|
||||
secrets?: TaskSecrets;
|
||||
/**
|
||||
* The state of checkpoints of the task.
|
||||
* This will be a JsonObject that may contain a `checkpoints` field
|
||||
* with a structure matching the CheckpointState interface.
|
||||
* @see CheckpointState
|
||||
*/
|
||||
state?: JsonObject;
|
||||
/**
|
||||
|
||||
@@ -23,7 +23,7 @@ import {
|
||||
import { JsonObject, JsonValue } from '@backstage/types';
|
||||
import {
|
||||
ActionContext,
|
||||
CheckpointOptions,
|
||||
CheckpointContext,
|
||||
} from '@backstage/plugin-scaffolder-node';
|
||||
import { loggerToWinstonLogger } from './loggerToWinstonLogger';
|
||||
|
||||
@@ -48,7 +48,7 @@ export function createMockActionContext<
|
||||
createTemporaryDirectory: jest.fn(),
|
||||
input: {} as TActionInput,
|
||||
async checkpoint<T extends JsonValue | void>(
|
||||
opts: CheckpointOptions<T>,
|
||||
opts: CheckpointContext<T>,
|
||||
): Promise<T> {
|
||||
return opts.fn();
|
||||
},
|
||||
|
||||
@@ -23,7 +23,7 @@ import {
|
||||
BackstageCredentials,
|
||||
LoggerService,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
import { CheckpointOptions } from '../checkpoints';
|
||||
import { CheckpointContext } from '../checkpoints';
|
||||
|
||||
/**
|
||||
* ActionContext is passed into scaffolder actions.
|
||||
@@ -39,7 +39,7 @@ export type ActionContext<
|
||||
workspacePath: string;
|
||||
input: TActionInput;
|
||||
checkpoint<T extends JsonValue | void>(
|
||||
opts: CheckpointOptions<T>,
|
||||
opts: CheckpointContext<T>,
|
||||
): Promise<T>;
|
||||
output(
|
||||
name: keyof TActionOutput,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
* Copyright 2025 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -13,7 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { JsonValue } from '@backstage/types';
|
||||
|
||||
/**
|
||||
@@ -28,9 +27,9 @@ export type CheckpointStatus = 'failed' | 'success';
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type CheckpointSuccessState = {
|
||||
status: Extract<CheckpointStatus, 'success'>;
|
||||
value: JsonValue;
|
||||
export type CheckpointSuccessState<T extends JsonValue = JsonValue> = {
|
||||
status: 'success';
|
||||
value: T;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -39,34 +38,34 @@ export type CheckpointSuccessState = {
|
||||
* @public
|
||||
*/
|
||||
export type CheckpointFailedState = {
|
||||
status: Extract<CheckpointStatus, 'failed'>;
|
||||
status: 'failed';
|
||||
reason: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents the union of all possible checkpoint state values.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type CheckpointStateValue =
|
||||
| CheckpointSuccessState
|
||||
| CheckpointFailedState;
|
||||
|
||||
/**
|
||||
* A map of checkpoint keys to their states.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type CheckpointState = {
|
||||
[key: string]: CheckpointSuccessState | CheckpointFailedState;
|
||||
[key: string]: CheckpointStateValue;
|
||||
};
|
||||
|
||||
/**
|
||||
* Options for updating a checkpoint in a task.
|
||||
* Context for checkpoint function invocation.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type UpdateCheckpointOptions = {
|
||||
key: string;
|
||||
} & CheckpointState[keyof CheckpointState];
|
||||
|
||||
/**
|
||||
* Options for checkpoint function invocation.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type CheckpointOptions<T extends JsonValue | void = JsonValue> = {
|
||||
export type CheckpointContext<T extends JsonValue | void = JsonValue> = {
|
||||
/**
|
||||
* Unique key for the checkpoint
|
||||
*/
|
||||
|
||||
@@ -25,4 +25,5 @@ export type {
|
||||
TaskContext,
|
||||
TaskEventType,
|
||||
TaskStatus,
|
||||
UpdateTaskCheckpointOptions,
|
||||
} from './types';
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
import { BackstageCredentials } from '@backstage/backend-plugin-api';
|
||||
import { TaskSpec } from '@backstage/plugin-scaffolder-common';
|
||||
import { JsonObject, Observable } from '@backstage/types';
|
||||
import { UpdateCheckpointOptions } from '../checkpoints';
|
||||
import { CheckpointStateValue } from '../checkpoints';
|
||||
|
||||
/**
|
||||
* TaskSecrets
|
||||
@@ -105,6 +105,15 @@ export type TaskBrokerDispatchOptions = {
|
||||
createdBy?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Options for updating a checkpoint in a task.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type UpdateTaskCheckpointOptions = {
|
||||
key: string;
|
||||
} & CheckpointStateValue;
|
||||
|
||||
/**
|
||||
* Task
|
||||
*
|
||||
@@ -130,7 +139,7 @@ export interface TaskContext {
|
||||
| undefined
|
||||
>;
|
||||
|
||||
updateCheckpoint?(options: UpdateCheckpointOptions): Promise<void>;
|
||||
updateCheckpoint?(options: UpdateTaskCheckpointOptions): Promise<void>;
|
||||
|
||||
serializeWorkspace?(options: { path: string }): Promise<void>;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user