chore: wip

Signed-off-by: blam <ben@blam.sh>

Signed-off-by: blam <ben@blam.sh>
This commit is contained in:
blam
2025-02-04 13:36:31 +01:00
committed by benjdlambert
parent 01b228423e
commit 3ff5c07a70
4 changed files with 54 additions and 387 deletions
-38
View File
@@ -1,38 +0,0 @@
/*
* Copyright 2024 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* A utility type that enhances the readability of hover overlays (type hints) for object types.
*
* @example Prettifying a basic object merge
*
* ### Basic object type
* ```ts
* type Example = { item1: string } & { item2: number }
* // ?^ { item1: string } & { item2: number }
* ```
*
* ### Usage
* ```ts
* type Example = Prettify<{ item1: string } & { item2: number }>
* // ?^ { item1: string, item2: number }
* ```
*
* @public
*/
export type Prettify<T extends Record<PropertyKey, unknown>> = {
[K in keyof T]: T[K];
} & {};
@@ -14,42 +14,24 @@
* limitations under the License.
*/
import type { JsonObject, Prettify } from '@backstage/types';
import type { Schema } from 'jsonschema';
import { ActionContext, TemplateAction } from './types';
import { z } from 'zod';
import { Schema } from 'jsonschema';
import zodToJsonSchema from 'zod-to-json-schema';
import type {
InferActionType,
ActionContextV2,
TemplateActionV2,
ActionContextV1,
TemplateActionV1,
TemplateExample,
} from './types';
import { JsonObject } from '@backstage/types';
/**
* @deprecated migrate to {@link TemplateActionOptionsV2}
* @public
*/
export type TemplateActionOptionsV1<
TInputParams extends JsonObject = JsonObject,
TOutputParams extends JsonObject = JsonObject,
TInputSchema extends Schema | z.ZodType = Schema,
TOutputSchema extends Schema | z.ZodType = Schema,
TActionInput extends JsonObject = TInputSchema extends z.ZodType<
any,
any,
infer IReturn
>
? IReturn
: TInputParams,
TActionOutput extends JsonObject = TOutputSchema extends z.ZodType<
any,
any,
infer IReturn
>
? IReturn
: TOutputParams,
/** @public */
export type TemplateExample = {
description: string;
example: string;
};
/** @public */
export type TemplateActionOptions<
TActionInput extends JsonObject = {},
TActionOutput extends JsonObject = {},
TInputSchema extends Schema | z.ZodType = {},
TOutputSchema extends Schema | z.ZodType = {},
> = {
id: string;
description?: string;
@@ -59,89 +41,15 @@ export type TemplateActionOptionsV1<
input?: TInputSchema;
output?: TOutputSchema;
};
handler: (ctx: ActionContextV1<TActionInput, TActionOutput>) => Promise<void>;
handler: (ctx: ActionContext<TActionInput, TActionOutput>) => Promise<void>;
};
/**
* @public
*/
export type TemplateActionOptionsV2<
TInputParams extends Record<
PropertyKey,
(zod: typeof z) => z.ZodType
> = Record<PropertyKey, (zod: typeof z) => z.ZodType>,
TOutputParams extends Record<
PropertyKey,
(zod: typeof z) => z.ZodType
> = Record<PropertyKey, (zod: typeof z) => z.ZodType>,
> = {
id: string;
description?: string;
examples?: TemplateExample[];
supportsDryRun?: boolean;
schema: {
input: TInputParams;
output: TOutputParams;
};
handler: (
ctx: ActionContextV2<
InferActionType<TInputParams>,
InferActionType<TOutputParams>
>,
) => Promise<void>;
};
/**
* @deprecated migrate to {@link TemplateActionOptionsV2}
* @public
*/
export type TemplateActionOptions<
TInputParams extends JsonObject = JsonObject,
TOutputParams extends JsonObject = JsonObject,
TInputSchema extends Schema | z.ZodType = Schema,
TOutputSchema extends Schema | z.ZodType = Schema,
TActionInput extends JsonObject = TInputSchema extends z.ZodType<
any,
any,
infer IReturn
>
? IReturn
: TInputParams,
TActionOutput extends JsonObject = TOutputSchema extends z.ZodType<
any,
any,
infer IReturn
>
? IReturn
: TOutputParams,
> = TemplateActionOptionsV1<
TInputParams,
TOutputParams,
TInputSchema,
TOutputSchema,
TActionInput,
TActionOutput
>;
function isZod(schema?: Schema | z.ZodType): schema is z.ZodType {
return !!(schema && 'safeParseAsync' in schema);
}
function transformZodRecordToObject(
record: Record<PropertyKey, (zod: typeof z) => z.ZodType>,
): z.ZodObject<Record<PropertyKey, z.ZodType>> {
return z.object(
Object.fromEntries(Object.entries(record).map(([k, v]) => [k, v(z)])),
);
}
/**
* This function is used to create new template actions to get type safety.
* Will convert zod schemas to json schemas for use throughout the system.
* @deprecated migrate to {@link createTemplateActionV2}
* @public
*/
export function createTemplateActionV1<
export const createTemplateAction = <
TInputParams extends JsonObject = JsonObject,
TOutputParams extends JsonObject = JsonObject,
TInputSchema extends Schema | z.ZodType = {},
@@ -161,91 +69,29 @@ export function createTemplateActionV1<
? IReturn
: TOutputParams,
>(
action: TemplateActionOptionsV1<
TInputParams,
TOutputParams,
TInputSchema,
TOutputSchema,
action: TemplateActionOptions<
TActionInput,
TActionOutput
TActionOutput,
TInputSchema,
TOutputSchema
>,
): TemplateActionV1<TActionInput, TActionOutput> {
): TemplateAction<TActionInput, TActionOutput> => {
const inputSchema =
action.schema && action.schema.input && isZod(action.schema.input)
? (zodToJsonSchema(action.schema.input) as Schema)
action.schema?.input && 'safeParseAsync' in action.schema.input
? zodToJsonSchema(action.schema.input)
: action.schema?.input;
const outputSchema =
action.schema && action.schema.output && isZod(action.schema.output)
? (zodToJsonSchema(action.schema.output) as Schema)
action.schema?.output && 'safeParseAsync' in action.schema.output
? zodToJsonSchema(action.schema.output)
: action.schema?.output;
return {
...action,
schema: {
...action.schema,
input: inputSchema,
output: outputSchema,
input: inputSchema as TInputSchema,
output: outputSchema as TOutputSchema,
},
};
}
/**
* This function is used to create new template actions to get type safety.
* Will convert zod schemas to json schemas for use throughout the system.
* @public
*/
export function createTemplateActionV2<
TInputParams extends Record<PropertyKey, (zod: typeof z) => z.ZodType>,
TOutputParams extends Record<PropertyKey, (zod: typeof z) => z.ZodType>,
>(
action: TemplateActionOptionsV2<TInputParams, TOutputParams>,
): TemplateActionV2<
InferActionType<TInputParams>,
InferActionType<TOutputParams>
> {
const input = transformZodRecordToObject(action.schema.input);
const output = transformZodRecordToObject(action.schema.output);
return {
...action,
schema: {
...action.schema,
input: zodToJsonSchema(input) as Schema,
output: zodToJsonSchema(output) as Schema,
},
};
}
function isV1Action(
action: TemplateActionOptionsV1 | TemplateActionOptionsV2,
): action is TemplateActionOptionsV1 {
return (
isZod(action.schema?.input) ||
typeof action.schema?.input === 'string' ||
isZod(action.schema?.output) ||
typeof action.schema?.output === 'string'
);
}
/**
* This function is used to create new template actions to get type safety.
* Will convert zod schemas to json schemas for use throughout the system.
* @public
*/
export function createTemplateAction<
TInputParams extends JsonObject = JsonObject,
TOutputParams extends JsonObject = JsonObject,
TAction extends
| TemplateActionOptionsV1
| TemplateActionOptionsV2 = TemplateActionOptionsV1,
TReturn = TAction extends TemplateActionOptionsV1
? Prettify<TemplateActionV1<TInputParams, TOutputParams>>
: Prettify<TemplateActionV2>,
>(action: TAction): TReturn {
if (isV1Action(action)) {
return createTemplateActionV1(action) as TReturn;
}
return createTemplateActionV2(action) as TReturn;
}
};
+8 -18
View File
@@ -16,31 +16,21 @@
export {
createTemplateAction,
type TemplateActionOptionsV2,
type TemplateActionOptionsV1,
type TemplateActionOptions,
type TemplateExample,
} from './createTemplateAction';
export {
executeShellCommand,
type ExecuteShellCommandOptions,
} from './executeShellCommand';
export { fetchContents, fetchFile } from './fetch';
export { type ActionContext, type TemplateAction } from './types';
export {
addFiles,
cloneRepo,
commitAndPushBranch,
commitAndPushRepo,
createBranch,
initRepoAndPush,
commitAndPushRepo,
commitAndPushBranch,
addFiles,
createBranch,
cloneRepo,
} from './gitHelpers';
export type {
ActionContext,
ActionContextV1,
ActionContextV2,
InferActionType,
TemplateAction,
TemplateActionV1,
TemplateActionV2,
TemplateExample,
} from './types';
export { getRepoSourceDirectory, parseRepoUrl } from './util';
export { parseRepoUrl, getRepoSourceDirectory } from './util';
+17 -148
View File
@@ -14,45 +14,21 @@
* limitations under the License.
*/
import type {
BackstageCredentials,
LoggerService,
} from '@backstage/backend-plugin-api';
import type { UserEntity } from '@backstage/catalog-model';
import type { TemplateInfo } from '@backstage/plugin-scaffolder-common';
import type { JsonObject, JsonValue, Prettify } from '@backstage/types';
import type { Schema } from 'jsonschema';
import type { Writable } from 'stream';
import type { Logger } from 'winston';
import { z } from 'zod';
import type { TaskSecrets } from '../tasks';
import { Logger } from 'winston';
import { Writable } from 'stream';
import { JsonObject, JsonValue } from '@backstage/types';
import { TaskSecrets } from '../tasks';
import { TemplateInfo } from '@backstage/plugin-scaffolder-common';
import { UserEntity } from '@backstage/catalog-model';
import { Schema } from 'jsonschema';
import { BackstageCredentials } from '@backstage/backend-plugin-api';
/**
* ActionContext is passed into scaffolder actions.
* @public
*/
export type TemplateExample = {
description: string;
example: string;
};
/** @public */
export type InferActionType<
T extends Record<PropertyKey, (zod: typeof z) => z.ZodType>,
> = Prettify<{
[K in keyof T]: T[K] extends (
zod: typeof z,
) => z.ZodType<any, any, infer IReturn>
? Extract<IReturn, JsonValue | undefined>
: never;
}>;
/**
* ActionContextV1 is passed into scaffolder actions.
* @deprecated migrate to {@link ActionContextV2}
* @public
*/
export type ActionContextV1<
TActionInput extends JsonObject = JsonObject,
export type ActionContext<
TActionInput extends JsonObject,
TActionOutput extends JsonObject = JsonObject,
> = {
// TODO(blam): move this to LoggerService
@@ -67,10 +43,8 @@ export type ActionContextV1<
fn: () => Promise<T> | T;
}): Promise<T>;
output(
...params: {
/* This maps the key to the value for type checking */
[K in keyof TActionOutput]: [name: K, value: TActionOutput[K]];
}[keyof TActionOutput]
name: keyof TActionOutput,
value: TActionOutput[keyof TActionOutput],
): void;
/**
@@ -123,123 +97,18 @@ export type ActionContextV1<
each?: JsonObject;
};
/**
* ActionContextV2 is passed into scaffolder actions.
* @public
*/
export type ActionContextV2<
TActionInput extends JsonObject = JsonObject,
TActionOutput extends JsonObject = JsonObject,
> = {
logger: LoggerService;
secrets?: TaskSecrets;
workspacePath: string;
input: TActionInput;
checkpoint<U extends JsonValue>(
key: string,
fn: () => Promise<U>,
): Promise<U>;
output(
...params: {
/* This maps the key to the value for type checking */
[K in keyof TActionOutput]: [name: K, value: TActionOutput[K]];
}[keyof TActionOutput]
): void;
/**
* Creates a temporary directory for use by the action, which is then cleaned up automatically.
*/
createTemporaryDirectory(): Promise<string>;
/**
* Get the credentials for the current request
*/
getInitiatorCredentials(): Promise<BackstageCredentials>;
templateInfo?: TemplateInfo;
/**
* Whether this action invocation is a dry-run or not.
* This will only ever be true if the actions as marked as supporting dry-runs.
*/
isDryRun?: boolean;
/**
* The user which triggered the action.
*/
user?: {
/**
* The decorated entity from the Catalog
*/
entity?: UserEntity;
/**
* An entity ref for the author of the task
*/
ref?: string;
};
/**
* Implement the signal to make your custom step abortable https://developer.mozilla.org/en-US/docs/Web/API/AbortController/signal
*/
signal?: AbortSignal;
/**
* Optional value of each invocation
*/
each?: JsonObject;
};
/**
* @deprecated migrate to {@link ActionContextV2}
* @public
*/
export type ActionContext<
TActionInput extends JsonObject = JsonObject,
TActionOutput extends JsonObject = JsonObject,
> = ActionContextV2<TActionInput, TActionOutput>;
/**
* @deprecated migrate to {@link TemplateActionV2}
* @public
*/
export type TemplateActionV1<
/** @public */
export type TemplateAction<
TActionInput extends JsonObject = JsonObject,
TActionOutput extends JsonObject = JsonObject,
> = {
id: string;
description?: string;
examples?: TemplateExample[];
examples?: { description: string; example: string }[];
supportsDryRun?: boolean;
schema?: {
input?: Schema;
output?: Schema;
};
handler: (ctx: ActionContextV1<TActionInput, TActionOutput>) => Promise<void>;
handler: (ctx: ActionContext<TActionInput, TActionOutput>) => Promise<void>;
};
/**
* @public
*/
export type TemplateActionV2<
TActionInput extends JsonObject = JsonObject,
TActionOutput extends JsonObject = JsonObject,
> = {
id: string;
description?: string;
examples?: TemplateExample[];
supportsDryRun?: boolean;
schema: {
input: Schema;
output: Schema;
};
handler: (ctx: ActionContextV2<TActionInput, TActionOutput>) => Promise<void>;
};
/**
* @deprecated migrate to {@link ActionContextV2}
* @public
*/
export type TemplateAction<
TActionInput extends JsonObject = JsonObject,
TActionOutput extends JsonObject = JsonObject,
> = TemplateActionV1<TActionInput, TActionOutput>;