Merge pull request #19372 from backstage/rugvip/noptions
backend-plugin-api: remove plugin and module options
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend': patch
|
||||
---
|
||||
|
||||
Removed the options from the alpha `scaffolderPlugin` export. To extend the scaffolder plugin you instead now use the available extension points, `scaffolderActionsExtensionPoint`, `scaffolderTaskBrokerExtensionPoint`, and `scaffolderTemplatingExtensionPoint`.
|
||||
@@ -0,0 +1,17 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend': patch
|
||||
---
|
||||
|
||||
Deprecated the following type exports, which have been moved to `@backstage/plugin-scaffolder-node` instead:
|
||||
|
||||
- `TemplateFilter`
|
||||
- `TemplateGlobal`
|
||||
- `TaskStatus`
|
||||
- `TaskCompletionState`
|
||||
- `SerializedTask`
|
||||
- `TaskEventType`
|
||||
- `SerializedTaskEvent`
|
||||
- `TaskBrokerDispatchResult`
|
||||
- `TaskBrokerDispatchOptions`
|
||||
- `TaskContext`
|
||||
- `TaskBroker`
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-node': patch
|
||||
---
|
||||
|
||||
Added several new types that were moved from `@backstage/plugin-scaffolder-backend`.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-node': patch
|
||||
---
|
||||
|
||||
Added two new alpha extension points, `scaffolderTaskBrokerExtensionPoint` and `scaffolderTemplatingExtensionPoint`.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend': patch
|
||||
---
|
||||
|
||||
The `concurrentTasksLimit` option can now be configured via static configuration as well. Setting it to 0 will now also disable the task worker.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/backend-plugin-api': minor
|
||||
---
|
||||
|
||||
**BREAKING**: Removed the ability to define options for plugins and modules. Existing options should be migrated to instead use either static configuration or extension points.
|
||||
@@ -119,14 +119,14 @@ export namespace coreServices {
|
||||
}
|
||||
|
||||
// @public
|
||||
export function createBackendModule<TOptions extends [options?: object] = []>(
|
||||
config: BackendModuleConfig | ((...params: TOptions) => BackendModuleConfig),
|
||||
): (...params: TOptions) => BackendFeature;
|
||||
export function createBackendModule(
|
||||
config: BackendModuleConfig,
|
||||
): () => BackendFeature;
|
||||
|
||||
// @public
|
||||
export function createBackendPlugin<TOptions extends [options?: object] = []>(
|
||||
config: BackendPluginConfig | ((...params: TOptions) => BackendPluginConfig),
|
||||
): (...params: TOptions) => BackendFeature;
|
||||
export function createBackendPlugin(
|
||||
config: BackendPluginConfig,
|
||||
): () => BackendFeature;
|
||||
|
||||
// @public
|
||||
export function createExtensionPoint<T>(
|
||||
|
||||
@@ -33,22 +33,19 @@ describe('createExtensionPoint', () => {
|
||||
|
||||
describe('createBackendPlugin', () => {
|
||||
it('should create a BackendPlugin', () => {
|
||||
const plugin = createBackendPlugin((_options: { a: string }) => ({
|
||||
const plugin = createBackendPlugin({
|
||||
pluginId: 'x',
|
||||
register(r) {
|
||||
r.registerInit({ deps: {}, async init() {} });
|
||||
},
|
||||
}));
|
||||
});
|
||||
expect(plugin).toBeDefined();
|
||||
expect(plugin({ a: 'a' })).toBeDefined();
|
||||
expect(plugin({ a: 'a' })).toEqual({
|
||||
expect(plugin()).toEqual({
|
||||
$$type: '@backstage/BackendFeature',
|
||||
version: 'v1',
|
||||
getRegistrations: expect.any(Function),
|
||||
});
|
||||
expect(
|
||||
(plugin({ a: 'a' }) as InternalBackendFeature).getRegistrations(),
|
||||
).toEqual([
|
||||
expect((plugin() as InternalBackendFeature).getRegistrations()).toEqual([
|
||||
{
|
||||
type: 'plugin',
|
||||
pluginId: 'x',
|
||||
@@ -60,91 +57,27 @@ describe('createBackendPlugin', () => {
|
||||
},
|
||||
]);
|
||||
// @ts-expect-error
|
||||
expect(plugin()).toBeDefined();
|
||||
// @ts-expect-error
|
||||
expect(plugin({ b: 'b' })).toBeDefined();
|
||||
});
|
||||
|
||||
it('should create plugins with optional options', () => {
|
||||
const plugin = createBackendPlugin((_options?: { a: string }) => ({
|
||||
pluginId: 'x',
|
||||
register() {},
|
||||
}));
|
||||
expect(plugin).toBeDefined();
|
||||
expect(plugin({ a: 'a' })).toBeDefined();
|
||||
expect(plugin()).toBeDefined();
|
||||
// @ts-expect-error
|
||||
expect(plugin({ b: 'b' })).toBeDefined();
|
||||
});
|
||||
|
||||
it('should create plugins without options', () => {
|
||||
const plugin = createBackendPlugin({
|
||||
pluginId: 'x',
|
||||
register() {},
|
||||
});
|
||||
expect(plugin).toBeDefined();
|
||||
// @ts-expect-error
|
||||
expect(plugin({ a: 'a' })).toBeDefined();
|
||||
// @ts-expect-error
|
||||
expect(plugin({})).toBeDefined();
|
||||
});
|
||||
|
||||
it('should create a BackendPlugin with options as interface', () => {
|
||||
interface TestOptions {
|
||||
a: string;
|
||||
}
|
||||
const plugin = createBackendPlugin((_options: TestOptions) => ({
|
||||
pluginId: 'x',
|
||||
register() {},
|
||||
}));
|
||||
expect(plugin).toBeDefined();
|
||||
expect(plugin({ a: 'a' })).toBeDefined();
|
||||
expect(plugin({ a: 'a' })).toEqual({
|
||||
$$type: '@backstage/BackendFeature',
|
||||
version: 'v1',
|
||||
getRegistrations: expect.any(Function),
|
||||
});
|
||||
// @ts-expect-error
|
||||
expect(plugin()).toBeDefined();
|
||||
// @ts-expect-error
|
||||
expect(plugin({ b: 'b' })).toBeDefined();
|
||||
});
|
||||
|
||||
it('should create plugins with optional options as interface', () => {
|
||||
interface TestOptions {
|
||||
a: string;
|
||||
}
|
||||
const plugin = createBackendPlugin((_options?: TestOptions) => ({
|
||||
pluginId: 'x',
|
||||
register() {},
|
||||
}));
|
||||
expect(plugin).toBeDefined();
|
||||
expect(plugin({ a: 'a' })).toBeDefined();
|
||||
expect(plugin()).toBeDefined();
|
||||
// @ts-expect-error
|
||||
expect(plugin({ b: 'b' })).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('createBackendModule', () => {
|
||||
it('should create a BackendModule', () => {
|
||||
const mod = createBackendModule((_options: { a: string }) => ({
|
||||
const mod = createBackendModule({
|
||||
pluginId: 'x',
|
||||
moduleId: 'y',
|
||||
register(r) {
|
||||
r.registerInit({ deps: {}, async init() {} });
|
||||
},
|
||||
}));
|
||||
});
|
||||
expect(mod).toBeDefined();
|
||||
expect(mod({ a: 'a' })).toBeDefined();
|
||||
expect(mod({ a: 'a' })).toEqual({
|
||||
expect(mod()).toBeDefined();
|
||||
expect(mod()).toEqual({
|
||||
$$type: '@backstage/BackendFeature',
|
||||
version: 'v1',
|
||||
getRegistrations: expect.any(Function),
|
||||
});
|
||||
expect(
|
||||
(mod({ a: 'a' }) as InternalBackendFeature).getRegistrations(),
|
||||
).toEqual([
|
||||
expect((mod() as InternalBackendFeature).getRegistrations()).toEqual([
|
||||
{
|
||||
type: 'module',
|
||||
pluginId: 'x',
|
||||
@@ -157,72 +90,6 @@ describe('createBackendModule', () => {
|
||||
},
|
||||
]);
|
||||
// @ts-expect-error
|
||||
expect(mod()).toBeDefined();
|
||||
// @ts-expect-error
|
||||
expect(mod({ b: 'b' })).toBeDefined();
|
||||
});
|
||||
|
||||
it('should create modules with optional options', () => {
|
||||
const mod = createBackendModule((_options?: { a: string }) => ({
|
||||
pluginId: 'x',
|
||||
moduleId: 'y',
|
||||
register() {},
|
||||
}));
|
||||
expect(mod).toBeDefined();
|
||||
expect(mod({ a: 'a' })).toBeDefined();
|
||||
expect(mod()).toBeDefined();
|
||||
// @ts-expect-error
|
||||
expect(mod({ b: 'b' })).toBeDefined();
|
||||
});
|
||||
|
||||
it('should create modules without options', () => {
|
||||
const mod = createBackendModule({
|
||||
pluginId: 'x',
|
||||
moduleId: 'y',
|
||||
register() {},
|
||||
});
|
||||
expect(mod).toBeDefined();
|
||||
// @ts-expect-error
|
||||
expect(mod({ a: 'a' })).toBeDefined();
|
||||
// @ts-expect-error
|
||||
expect(mod({})).toBeDefined();
|
||||
});
|
||||
|
||||
it('should create a BackendModule as interface', () => {
|
||||
interface TestOptions {
|
||||
a: string;
|
||||
}
|
||||
const mod = createBackendModule((_options: TestOptions) => ({
|
||||
pluginId: 'x',
|
||||
moduleId: 'y',
|
||||
register() {},
|
||||
}));
|
||||
expect(mod).toBeDefined();
|
||||
expect(mod({ a: 'a' })).toBeDefined();
|
||||
expect(mod({ a: 'a' })).toEqual({
|
||||
$$type: '@backstage/BackendFeature',
|
||||
version: 'v1',
|
||||
getRegistrations: expect.any(Function),
|
||||
});
|
||||
// @ts-expect-error
|
||||
expect(mod()).toBeDefined();
|
||||
// @ts-expect-error
|
||||
expect(mod({ b: 'b' })).toBeDefined();
|
||||
});
|
||||
|
||||
it('should create modules with optional options as interface', () => {
|
||||
interface TestOptions {
|
||||
a: string;
|
||||
}
|
||||
const mod = createBackendModule((_options?: TestOptions) => ({
|
||||
pluginId: 'x',
|
||||
moduleId: 'y',
|
||||
register() {},
|
||||
}));
|
||||
expect(mod).toBeDefined();
|
||||
expect(mod({ a: 'a' })).toBeDefined();
|
||||
expect(mod()).toBeDefined();
|
||||
// @ts-expect-error
|
||||
expect(mod({ b: 'b' })).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -85,14 +85,10 @@ export interface BackendPluginConfig {
|
||||
* @see {@link https://backstage.io/docs/backend-system/architecture/plugins | The architecture of plugins}
|
||||
* @see {@link https://backstage.io/docs/backend-system/architecture/naming-patterns | Recommended naming patterns}
|
||||
*/
|
||||
export function createBackendPlugin<TOptions extends [options?: object] = []>(
|
||||
config: BackendPluginConfig | ((...params: TOptions) => BackendPluginConfig),
|
||||
): (...params: TOptions) => BackendFeature {
|
||||
const configCallback = typeof config === 'function' ? config : () => config;
|
||||
|
||||
const factory: BackendFeatureFactory<TOptions> = (...options) => {
|
||||
const c = configCallback(...options);
|
||||
|
||||
export function createBackendPlugin(
|
||||
config: BackendPluginConfig,
|
||||
): () => BackendFeature {
|
||||
const factory: BackendFeatureFactory = () => {
|
||||
let registrations: InternalBackendPluginRegistration[];
|
||||
|
||||
return {
|
||||
@@ -107,7 +103,7 @@ export function createBackendPlugin<TOptions extends [options?: object] = []>(
|
||||
let init: InternalBackendPluginRegistration['init'] | undefined =
|
||||
undefined;
|
||||
|
||||
c.register({
|
||||
config.register({
|
||||
registerExtensionPoint(ext, impl) {
|
||||
if (init) {
|
||||
throw new Error(
|
||||
@@ -129,14 +125,14 @@ export function createBackendPlugin<TOptions extends [options?: object] = []>(
|
||||
|
||||
if (!init) {
|
||||
throw new Error(
|
||||
`registerInit was not called by register in ${c.pluginId}`,
|
||||
`registerInit was not called by register in ${config.pluginId}`,
|
||||
);
|
||||
}
|
||||
|
||||
registrations = [
|
||||
{
|
||||
type: 'plugin',
|
||||
pluginId: c.pluginId,
|
||||
pluginId: config.pluginId,
|
||||
extensionPoints,
|
||||
init,
|
||||
},
|
||||
@@ -179,13 +175,10 @@ export interface BackendModuleConfig {
|
||||
* @see {@link https://backstage.io/docs/backend-system/architecture/modules | The architecture of modules}
|
||||
* @see {@link https://backstage.io/docs/backend-system/architecture/naming-patterns | Recommended naming patterns}
|
||||
*/
|
||||
export function createBackendModule<TOptions extends [options?: object] = []>(
|
||||
config: BackendModuleConfig | ((...params: TOptions) => BackendModuleConfig),
|
||||
): (...params: TOptions) => BackendFeature {
|
||||
const configCallback = typeof config === 'function' ? config : () => config;
|
||||
const factory: BackendFeatureFactory<TOptions> = (...options: TOptions) => {
|
||||
const c = configCallback(...options);
|
||||
|
||||
export function createBackendModule(
|
||||
config: BackendModuleConfig,
|
||||
): () => BackendFeature {
|
||||
const factory: BackendFeatureFactory = () => {
|
||||
let registrations: InternalBackendModuleRegistration[];
|
||||
|
||||
return {
|
||||
@@ -200,7 +193,7 @@ export function createBackendModule<TOptions extends [options?: object] = []>(
|
||||
let init: InternalBackendModuleRegistration['init'] | undefined =
|
||||
undefined;
|
||||
|
||||
c.register({
|
||||
config.register({
|
||||
registerExtensionPoint(ext, impl) {
|
||||
if (init) {
|
||||
throw new Error(
|
||||
@@ -222,15 +215,15 @@ export function createBackendModule<TOptions extends [options?: object] = []>(
|
||||
|
||||
if (!init) {
|
||||
throw new Error(
|
||||
`registerInit was not called by register in ${c.moduleId} module for ${c.pluginId}`,
|
||||
`registerInit was not called by register in ${config.moduleId} module for ${config.pluginId}`,
|
||||
);
|
||||
}
|
||||
|
||||
registrations = [
|
||||
{
|
||||
type: 'module',
|
||||
pluginId: c.pluginId,
|
||||
moduleId: c.moduleId,
|
||||
pluginId: config.pluginId,
|
||||
moduleId: config.moduleId,
|
||||
extensionPoints,
|
||||
init,
|
||||
},
|
||||
|
||||
@@ -72,10 +72,8 @@ export interface BackendModuleRegistrationPoints {
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export interface BackendFeatureFactory<
|
||||
TOptions extends [options?: object] = [],
|
||||
> {
|
||||
(...options: TOptions): BackendFeature;
|
||||
export interface BackendFeatureFactory {
|
||||
(): BackendFeature;
|
||||
$$type: '@backstage/BackendFeatureFactory';
|
||||
}
|
||||
|
||||
|
||||
@@ -12,11 +12,7 @@ import { PermissionCriteria } from '@backstage/plugin-permission-common';
|
||||
import { PermissionRule } from '@backstage/plugin-permission-node';
|
||||
import { PermissionRuleParams } from '@backstage/plugin-permission-common';
|
||||
import { ResourcePermission } from '@backstage/plugin-permission-common';
|
||||
import { TaskBroker } from '@backstage/plugin-scaffolder-backend';
|
||||
import { TemplateAction } from '@backstage/plugin-scaffolder-node';
|
||||
import { TemplateEntityStepV1beta3 } from '@backstage/plugin-scaffolder-common';
|
||||
import { TemplateFilter } from '@backstage/plugin-scaffolder-backend';
|
||||
import { TemplateGlobal } from '@backstage/plugin-scaffolder-backend';
|
||||
import { TemplateParametersV1beta3 } from '@backstage/plugin-scaffolder-common';
|
||||
|
||||
// @alpha
|
||||
@@ -90,18 +86,7 @@ export const scaffolderActionConditions: Conditions<{
|
||||
}>;
|
||||
|
||||
// @alpha
|
||||
export const scaffolderPlugin: (
|
||||
options?: ScaffolderPluginOptions | undefined,
|
||||
) => BackendFeature;
|
||||
|
||||
// @alpha
|
||||
export type ScaffolderPluginOptions = {
|
||||
actions?: TemplateAction<any, any>[];
|
||||
taskWorkers?: number;
|
||||
taskBroker?: TaskBroker;
|
||||
additionalTemplateFilters?: Record<string, TemplateFilter>;
|
||||
additionalTemplateGlobals?: Record<string, TemplateGlobal>;
|
||||
};
|
||||
export const scaffolderPlugin: () => BackendFeature;
|
||||
|
||||
// @alpha
|
||||
export const scaffolderTemplateConditions: Conditions<{
|
||||
|
||||
@@ -19,11 +19,9 @@ import { GithubCredentialsProvider } from '@backstage/integration';
|
||||
import { HumanDuration } from '@backstage/types';
|
||||
import { IdentityApi } from '@backstage/plugin-auth-node';
|
||||
import { JsonObject } from '@backstage/types';
|
||||
import { JsonValue } from '@backstage/types';
|
||||
import { Knex } from 'knex';
|
||||
import { LocationSpec } from '@backstage/plugin-catalog-common';
|
||||
import { Logger } from 'winston';
|
||||
import { Observable } from '@backstage/types';
|
||||
import { Octokit } from 'octokit';
|
||||
import { PermissionEvaluator } from '@backstage/plugin-permission-common';
|
||||
import { PermissionRule } from '@backstage/plugin-permission-node';
|
||||
@@ -35,12 +33,23 @@ import { RESOURCE_TYPE_SCAFFOLDER_TEMPLATE } from '@backstage/plugin-scaffolder-
|
||||
import { Schema } from 'jsonschema';
|
||||
import { ScmIntegrationRegistry } from '@backstage/integration';
|
||||
import { ScmIntegrations } from '@backstage/integration';
|
||||
import { SerializedTask as SerializedTask_2 } from '@backstage/plugin-scaffolder-node';
|
||||
import { SerializedTaskEvent as SerializedTaskEvent_2 } from '@backstage/plugin-scaffolder-node';
|
||||
import { TaskBroker as TaskBroker_2 } from '@backstage/plugin-scaffolder-node';
|
||||
import { TaskBrokerDispatchOptions as TaskBrokerDispatchOptions_2 } from '@backstage/plugin-scaffolder-node';
|
||||
import { TaskBrokerDispatchResult as TaskBrokerDispatchResult_2 } from '@backstage/plugin-scaffolder-node';
|
||||
import { TaskCompletionState as TaskCompletionState_2 } from '@backstage/plugin-scaffolder-node';
|
||||
import { TaskContext as TaskContext_2 } from '@backstage/plugin-scaffolder-node';
|
||||
import { TaskEventType as TaskEventType_2 } from '@backstage/plugin-scaffolder-node';
|
||||
import { TaskSecrets as TaskSecrets_2 } from '@backstage/plugin-scaffolder-node';
|
||||
import { TaskSpec } from '@backstage/plugin-scaffolder-common';
|
||||
import { TaskSpecV1beta3 } from '@backstage/plugin-scaffolder-common';
|
||||
import { TaskStatus as TaskStatus_2 } from '@backstage/plugin-scaffolder-node';
|
||||
import { TemplateAction as TemplateAction_2 } from '@backstage/plugin-scaffolder-node';
|
||||
import { TemplateActionOptions } from '@backstage/plugin-scaffolder-node';
|
||||
import { TemplateEntityStepV1beta3 } from '@backstage/plugin-scaffolder-common';
|
||||
import { TemplateFilter as TemplateFilter_2 } from '@backstage/plugin-scaffolder-node';
|
||||
import { TemplateGlobal as TemplateGlobal_2 } from '@backstage/plugin-scaffolder-node';
|
||||
import { TemplateParametersV1beta3 } from '@backstage/plugin-scaffolder-common';
|
||||
import { UrlReader } from '@backstage/backend-common';
|
||||
import { ZodType } from 'zod';
|
||||
@@ -886,89 +895,29 @@ export class ScaffolderEntitiesProcessor implements CatalogProcessor {
|
||||
validateEntityKind(entity: Entity): Promise<boolean>;
|
||||
}
|
||||
|
||||
// @public
|
||||
export type SerializedTask = {
|
||||
id: string;
|
||||
spec: TaskSpec;
|
||||
status: TaskStatus;
|
||||
createdAt: string;
|
||||
lastHeartbeatAt?: string;
|
||||
createdBy?: string;
|
||||
secrets?: TaskSecrets_2;
|
||||
};
|
||||
// @public @deprecated
|
||||
export type SerializedTask = SerializedTask_2;
|
||||
|
||||
// @public
|
||||
export type SerializedTaskEvent = {
|
||||
id: number;
|
||||
taskId: string;
|
||||
body: JsonObject;
|
||||
type: TaskEventType;
|
||||
createdAt: string;
|
||||
};
|
||||
// @public @deprecated
|
||||
export type SerializedTaskEvent = SerializedTaskEvent_2;
|
||||
|
||||
// @public
|
||||
export interface TaskBroker {
|
||||
// (undocumented)
|
||||
cancel?(taskId: string): Promise<void>;
|
||||
// (undocumented)
|
||||
claim(): Promise<TaskContext>;
|
||||
// (undocumented)
|
||||
dispatch(
|
||||
options: TaskBrokerDispatchOptions,
|
||||
): Promise<TaskBrokerDispatchResult>;
|
||||
// (undocumented)
|
||||
event$(options: { taskId: string; after: number | undefined }): Observable<{
|
||||
events: SerializedTaskEvent[];
|
||||
}>;
|
||||
// (undocumented)
|
||||
get(taskId: string): Promise<SerializedTask>;
|
||||
// (undocumented)
|
||||
list?(options?: { createdBy?: string }): Promise<{
|
||||
tasks: SerializedTask[];
|
||||
}>;
|
||||
// (undocumented)
|
||||
vacuumTasks(options: { timeoutS: number }): Promise<void>;
|
||||
}
|
||||
// @public @deprecated
|
||||
export type TaskBroker = TaskBroker_2;
|
||||
|
||||
// @public
|
||||
export type TaskBrokerDispatchOptions = {
|
||||
spec: TaskSpec;
|
||||
secrets?: TaskSecrets_2;
|
||||
createdBy?: string;
|
||||
};
|
||||
// @public @deprecated
|
||||
export type TaskBrokerDispatchOptions = TaskBrokerDispatchOptions_2;
|
||||
|
||||
// @public
|
||||
export type TaskBrokerDispatchResult = {
|
||||
taskId: string;
|
||||
};
|
||||
// @public @deprecated
|
||||
export type TaskBrokerDispatchResult = TaskBrokerDispatchResult_2;
|
||||
|
||||
// @public
|
||||
export type TaskCompletionState = 'failed' | 'completed';
|
||||
// @public @deprecated
|
||||
export type TaskCompletionState = TaskCompletionState_2;
|
||||
|
||||
// @public
|
||||
export interface TaskContext {
|
||||
// (undocumented)
|
||||
cancelSignal: AbortSignal;
|
||||
// (undocumented)
|
||||
complete(result: TaskCompletionState, metadata?: JsonObject): Promise<void>;
|
||||
// (undocumented)
|
||||
createdBy?: string;
|
||||
// (undocumented)
|
||||
done: boolean;
|
||||
// (undocumented)
|
||||
emitLog(message: string, logMetadata?: JsonObject): Promise<void>;
|
||||
// (undocumented)
|
||||
getWorkspaceName(): Promise<string>;
|
||||
// (undocumented)
|
||||
isDryRun?: boolean;
|
||||
// (undocumented)
|
||||
secrets?: TaskSecrets_2;
|
||||
// (undocumented)
|
||||
spec: TaskSpec;
|
||||
}
|
||||
// @public @deprecated
|
||||
export type TaskContext = TaskContext_2;
|
||||
|
||||
// @public
|
||||
export type TaskEventType = 'completion' | 'log' | 'cancelled';
|
||||
// @public @deprecated
|
||||
export type TaskEventType = TaskEventType_2;
|
||||
|
||||
// @public
|
||||
export class TaskManager implements TaskContext {
|
||||
@@ -1000,13 +949,8 @@ export class TaskManager implements TaskContext {
|
||||
// @public @deprecated (undocumented)
|
||||
export type TaskSecrets = TaskSecrets_2;
|
||||
|
||||
// @public
|
||||
export type TaskStatus =
|
||||
| 'cancelled'
|
||||
| 'completed'
|
||||
| 'failed'
|
||||
| 'open'
|
||||
| 'processing';
|
||||
// @public @deprecated
|
||||
export type TaskStatus = TaskStatus_2;
|
||||
|
||||
// @public
|
||||
export interface TaskStore {
|
||||
@@ -1103,13 +1047,11 @@ export class TemplateActionRegistry {
|
||||
register(action: TemplateAction_2): void;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export type TemplateFilter = (...args: JsonValue[]) => JsonValue | undefined;
|
||||
// @public @deprecated (undocumented)
|
||||
export type TemplateFilter = TemplateFilter_2;
|
||||
|
||||
// @public (undocumented)
|
||||
export type TemplateGlobal =
|
||||
| ((...args: JsonValue[]) => JsonValue | undefined)
|
||||
| JsonValue;
|
||||
// @public @deprecated (undocumented)
|
||||
export type TemplateGlobal = TemplateGlobal_2;
|
||||
|
||||
// @public (undocumented)
|
||||
export type TemplatePermissionRuleInput<
|
||||
|
||||
+9
@@ -28,5 +28,14 @@ export interface Config {
|
||||
* The commit message used when new components are created.
|
||||
*/
|
||||
defaultCommitMessage?: string;
|
||||
|
||||
/**
|
||||
* Sets the number of concurrent tasks that can be run at any given time on the TaskWorker.
|
||||
*
|
||||
* Defaults to 10.
|
||||
*
|
||||
* Set to 0 to disable task workers altogether.
|
||||
*/
|
||||
concurrentTasksLimit?: number;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -23,120 +23,104 @@ import { ScmIntegrations } from '@backstage/integration';
|
||||
import { catalogServiceRef } from '@backstage/plugin-catalog-node/alpha';
|
||||
import {
|
||||
scaffolderActionsExtensionPoint,
|
||||
ScaffolderActionsExtensionPoint,
|
||||
scaffolderTaskBrokerExtensionPoint,
|
||||
scaffolderTemplatingExtensionPoint,
|
||||
TaskBroker,
|
||||
TemplateAction,
|
||||
} from '@backstage/plugin-scaffolder-node';
|
||||
import {
|
||||
TemplateFilter,
|
||||
TemplateGlobal,
|
||||
TaskBroker,
|
||||
} from '@backstage/plugin-scaffolder-backend';
|
||||
} from '@backstage/plugin-scaffolder-node';
|
||||
import { createBuiltinActions } from './scaffolder';
|
||||
import { createRouter } from './service/router';
|
||||
|
||||
/**
|
||||
* Catalog plugin options
|
||||
* Scaffolder plugin
|
||||
*
|
||||
* @alpha
|
||||
*/
|
||||
export type ScaffolderPluginOptions = {
|
||||
actions?: TemplateAction<any, any>[];
|
||||
taskWorkers?: number;
|
||||
taskBroker?: TaskBroker;
|
||||
additionalTemplateFilters?: Record<string, TemplateFilter>;
|
||||
additionalTemplateGlobals?: Record<string, TemplateGlobal>;
|
||||
};
|
||||
export const scaffolderPlugin = createBackendPlugin({
|
||||
pluginId: 'scaffolder',
|
||||
register(env) {
|
||||
const addedActions = new Array<TemplateAction<any, any>>();
|
||||
env.registerExtensionPoint(scaffolderActionsExtensionPoint, {
|
||||
addActions(...newActions: TemplateAction<any>[]) {
|
||||
addedActions.push(...newActions);
|
||||
},
|
||||
});
|
||||
|
||||
class ScaffolderActionsExtensionPointImpl
|
||||
implements ScaffolderActionsExtensionPoint
|
||||
{
|
||||
#actions = new Array<TemplateAction<any, any>>();
|
||||
let taskBroker: TaskBroker | undefined;
|
||||
env.registerExtensionPoint(scaffolderTaskBrokerExtensionPoint, {
|
||||
setTaskBroker(newTaskBroker) {
|
||||
if (taskBroker) {
|
||||
throw new Error('Task broker may only be set once');
|
||||
}
|
||||
taskBroker = newTaskBroker;
|
||||
},
|
||||
});
|
||||
|
||||
addActions(...actions: TemplateAction<any>[]): void {
|
||||
this.#actions.push(...actions);
|
||||
}
|
||||
const additionalTemplateFilters: Record<string, TemplateFilter> = {};
|
||||
const additionalTemplateGlobals: Record<string, TemplateGlobal> = {};
|
||||
env.registerExtensionPoint(scaffolderTemplatingExtensionPoint, {
|
||||
addTemplateFilters(newFilters) {
|
||||
Object.assign(additionalTemplateFilters, newFilters);
|
||||
},
|
||||
addTemplateGlobals(newGlobals) {
|
||||
Object.assign(additionalTemplateGlobals, newGlobals);
|
||||
},
|
||||
});
|
||||
|
||||
get actions() {
|
||||
return this.#actions;
|
||||
}
|
||||
}
|
||||
env.registerInit({
|
||||
deps: {
|
||||
logger: coreServices.logger,
|
||||
config: coreServices.rootConfig,
|
||||
reader: coreServices.urlReader,
|
||||
permissions: coreServices.permissions,
|
||||
database: coreServices.database,
|
||||
httpRouter: coreServices.httpRouter,
|
||||
catalogClient: catalogServiceRef,
|
||||
},
|
||||
async init({
|
||||
logger,
|
||||
config,
|
||||
reader,
|
||||
database,
|
||||
httpRouter,
|
||||
catalogClient,
|
||||
permissions,
|
||||
}) {
|
||||
const log = loggerToWinstonLogger(logger);
|
||||
|
||||
/**
|
||||
* Catalog plugin
|
||||
*
|
||||
* @alpha
|
||||
*/
|
||||
export const scaffolderPlugin = createBackendPlugin(
|
||||
(options?: ScaffolderPluginOptions) => ({
|
||||
pluginId: 'scaffolder',
|
||||
register(env) {
|
||||
const actionsExtensions = new ScaffolderActionsExtensionPointImpl();
|
||||
|
||||
env.registerExtensionPoint(
|
||||
scaffolderActionsExtensionPoint,
|
||||
actionsExtensions,
|
||||
);
|
||||
|
||||
env.registerInit({
|
||||
deps: {
|
||||
logger: coreServices.logger,
|
||||
config: coreServices.rootConfig,
|
||||
reader: coreServices.urlReader,
|
||||
permissions: coreServices.permissions,
|
||||
database: coreServices.database,
|
||||
httpRouter: coreServices.httpRouter,
|
||||
catalogClient: catalogServiceRef,
|
||||
},
|
||||
async init({
|
||||
logger,
|
||||
config,
|
||||
reader,
|
||||
database,
|
||||
httpRouter,
|
||||
catalogClient,
|
||||
permissions,
|
||||
}) {
|
||||
const {
|
||||
additionalTemplateFilters,
|
||||
taskBroker,
|
||||
taskWorkers,
|
||||
additionalTemplateGlobals,
|
||||
} = options ?? {};
|
||||
const log = loggerToWinstonLogger(logger);
|
||||
|
||||
const actions = options?.actions || [
|
||||
...actionsExtensions.actions,
|
||||
...createBuiltinActions({
|
||||
integrations: ScmIntegrations.fromConfig(config),
|
||||
catalogClient,
|
||||
reader,
|
||||
config,
|
||||
additionalTemplateFilters,
|
||||
additionalTemplateGlobals,
|
||||
}),
|
||||
];
|
||||
|
||||
const actionIds = actions.map(action => action.id).join(', ');
|
||||
log.info(
|
||||
`Starting scaffolder with the following actions enabled ${actionIds}`,
|
||||
);
|
||||
|
||||
const router = await createRouter({
|
||||
logger: log,
|
||||
config,
|
||||
database,
|
||||
const actions = [
|
||||
...addedActions,
|
||||
...createBuiltinActions({
|
||||
integrations: ScmIntegrations.fromConfig(config),
|
||||
catalogClient,
|
||||
reader,
|
||||
actions,
|
||||
taskBroker,
|
||||
taskWorkers,
|
||||
config,
|
||||
additionalTemplateFilters,
|
||||
additionalTemplateGlobals,
|
||||
permissions,
|
||||
});
|
||||
httpRouter.use(router);
|
||||
},
|
||||
});
|
||||
},
|
||||
}),
|
||||
);
|
||||
}),
|
||||
];
|
||||
|
||||
const actionIds = actions.map(action => action.id).join(', ');
|
||||
log.info(
|
||||
`Starting scaffolder with the following actions enabled ${actionIds}`,
|
||||
);
|
||||
|
||||
const router = await createRouter({
|
||||
logger: log,
|
||||
config,
|
||||
database,
|
||||
catalogClient,
|
||||
reader,
|
||||
actions,
|
||||
taskBroker,
|
||||
additionalTemplateFilters,
|
||||
additionalTemplateGlobals,
|
||||
permissions,
|
||||
});
|
||||
httpRouter.use(router);
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
@@ -17,4 +17,3 @@
|
||||
export * from './modules';
|
||||
export * from './service';
|
||||
export { scaffolderPlugin } from './ScaffolderPlugin';
|
||||
export type { ScaffolderPluginOptions } from './ScaffolderPlugin';
|
||||
|
||||
@@ -16,6 +16,10 @@
|
||||
|
||||
import { Isolate } from 'isolated-vm';
|
||||
import { resolvePackagePath } from '@backstage/backend-common';
|
||||
import {
|
||||
TemplateFilter as _TemplateFilter,
|
||||
TemplateGlobal as _TemplateGlobal,
|
||||
} from '@backstage/plugin-scaffolder-node';
|
||||
import fs from 'fs-extra';
|
||||
import { JsonValue } from '@backstage/types';
|
||||
|
||||
@@ -86,13 +90,17 @@ const { render, renderCompat } = (() => {
|
||||
})();
|
||||
`;
|
||||
|
||||
/** @public */
|
||||
export type TemplateFilter = (...args: JsonValue[]) => JsonValue | undefined;
|
||||
/**
|
||||
* @public
|
||||
* @deprecated Import from `@backstage/plugin-scaffolder-node` instead.
|
||||
*/
|
||||
export type TemplateFilter = _TemplateFilter;
|
||||
|
||||
/** @public */
|
||||
export type TemplateGlobal =
|
||||
| ((...args: JsonValue[]) => JsonValue | undefined)
|
||||
| JsonValue;
|
||||
/**
|
||||
* @public
|
||||
* @deprecated Import from `@backstage/plugin-scaffolder-node` instead.
|
||||
*/
|
||||
export type TemplateGlobal = _TemplateGlobal;
|
||||
|
||||
export interface SecureTemplaterOptions {
|
||||
/* Enables jinja compatibility and the "jsonify" filter */
|
||||
|
||||
@@ -14,131 +14,94 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { JsonValue, JsonObject, Observable } from '@backstage/types';
|
||||
import { JsonValue, JsonObject } from '@backstage/types';
|
||||
import { TaskSpec, TaskStep } from '@backstage/plugin-scaffolder-common';
|
||||
import { TaskSecrets } from '@backstage/plugin-scaffolder-node';
|
||||
import { TemplateAction } from '@backstage/plugin-scaffolder-node';
|
||||
import {
|
||||
TemplateAction,
|
||||
TaskStatus as _TaskStatus,
|
||||
TaskCompletionState as _TaskCompletionState,
|
||||
SerializedTask as _SerializedTask,
|
||||
TaskEventType as _TaskEventType,
|
||||
SerializedTaskEvent as _SerializedTaskEvent,
|
||||
TaskBrokerDispatchResult as _TaskBrokerDispatchResult,
|
||||
TaskBrokerDispatchOptions as _TaskBrokerDispatchOptions,
|
||||
TaskContext as _TaskContext,
|
||||
TaskBroker as _TaskBroker,
|
||||
} from '@backstage/plugin-scaffolder-node';
|
||||
|
||||
/**
|
||||
* The status of each step of the Task
|
||||
*
|
||||
* @public
|
||||
* @deprecated Import from `@backstage/plugin-scaffolder-node` instead.
|
||||
*/
|
||||
export type TaskStatus =
|
||||
| 'cancelled'
|
||||
| 'completed'
|
||||
| 'failed'
|
||||
| 'open'
|
||||
| 'processing';
|
||||
export type TaskStatus = _TaskStatus;
|
||||
|
||||
/**
|
||||
* The state of a completed task.
|
||||
*
|
||||
* @public
|
||||
* @deprecated Import from `@backstage/plugin-scaffolder-node` instead.
|
||||
*/
|
||||
export type TaskCompletionState = 'failed' | 'completed';
|
||||
export type TaskCompletionState = _TaskCompletionState;
|
||||
|
||||
/**
|
||||
* SerializedTask
|
||||
*
|
||||
* @public
|
||||
* @deprecated Import from `@backstage/plugin-scaffolder-node` instead.
|
||||
*/
|
||||
export type SerializedTask = {
|
||||
id: string;
|
||||
spec: TaskSpec;
|
||||
status: TaskStatus;
|
||||
createdAt: string;
|
||||
lastHeartbeatAt?: string;
|
||||
createdBy?: string;
|
||||
secrets?: TaskSecrets;
|
||||
};
|
||||
export type SerializedTask = _SerializedTask;
|
||||
|
||||
/**
|
||||
* TaskEventType
|
||||
*
|
||||
* @public
|
||||
* @deprecated Import from `@backstage/plugin-scaffolder-node` instead.
|
||||
*/
|
||||
export type TaskEventType = 'completion' | 'log' | 'cancelled';
|
||||
export type TaskEventType = _TaskEventType;
|
||||
|
||||
/**
|
||||
* SerializedTaskEvent
|
||||
*
|
||||
* @public
|
||||
* @deprecated Import from `@backstage/plugin-scaffolder-node` instead.
|
||||
*/
|
||||
export type SerializedTaskEvent = {
|
||||
id: number;
|
||||
taskId: string;
|
||||
body: JsonObject;
|
||||
type: TaskEventType;
|
||||
createdAt: string;
|
||||
};
|
||||
export type SerializedTaskEvent = _SerializedTaskEvent;
|
||||
|
||||
/**
|
||||
* The result of {@link TaskBroker.dispatch}
|
||||
* The result of `TaskBroker.dispatch`.
|
||||
*
|
||||
* @public
|
||||
* @deprecated Import from `@backstage/plugin-scaffolder-node` instead.
|
||||
*/
|
||||
export type TaskBrokerDispatchResult = {
|
||||
taskId: string;
|
||||
};
|
||||
export type TaskBrokerDispatchResult = _TaskBrokerDispatchResult;
|
||||
|
||||
/**
|
||||
* The options passed to {@link TaskBroker.dispatch}
|
||||
* The options passed to `TaskBroker.dispatch`.
|
||||
* Currently a spec and optional secrets
|
||||
*
|
||||
* @public
|
||||
* @deprecated Import from `@backstage/plugin-scaffolder-node` instead.
|
||||
*/
|
||||
export type TaskBrokerDispatchOptions = {
|
||||
spec: TaskSpec;
|
||||
secrets?: TaskSecrets;
|
||||
createdBy?: string;
|
||||
};
|
||||
export type TaskBrokerDispatchOptions = _TaskBrokerDispatchOptions;
|
||||
|
||||
/**
|
||||
* Task
|
||||
*
|
||||
* @public
|
||||
* @deprecated Import from `@backstage/plugin-scaffolder-node` instead.
|
||||
*/
|
||||
export interface TaskContext {
|
||||
cancelSignal: AbortSignal;
|
||||
spec: TaskSpec;
|
||||
secrets?: TaskSecrets;
|
||||
createdBy?: string;
|
||||
done: boolean;
|
||||
isDryRun?: boolean;
|
||||
|
||||
complete(result: TaskCompletionState, metadata?: JsonObject): Promise<void>;
|
||||
|
||||
emitLog(message: string, logMetadata?: JsonObject): Promise<void>;
|
||||
|
||||
getWorkspaceName(): Promise<string>;
|
||||
}
|
||||
export type TaskContext = _TaskContext;
|
||||
|
||||
/**
|
||||
* TaskBroker
|
||||
*
|
||||
* @public
|
||||
* @deprecated Import from `@backstage/plugin-scaffolder-node` instead.
|
||||
*/
|
||||
export interface TaskBroker {
|
||||
cancel?(taskId: string): Promise<void>;
|
||||
|
||||
claim(): Promise<TaskContext>;
|
||||
|
||||
dispatch(
|
||||
options: TaskBrokerDispatchOptions,
|
||||
): Promise<TaskBrokerDispatchResult>;
|
||||
|
||||
vacuumTasks(options: { timeoutS: number }): Promise<void>;
|
||||
|
||||
event$(options: {
|
||||
taskId: string;
|
||||
after: number | undefined;
|
||||
}): Observable<{ events: SerializedTaskEvent[] }>;
|
||||
|
||||
get(taskId: string): Promise<SerializedTask>;
|
||||
|
||||
list?(options?: { createdBy?: string }): Promise<{ tasks: SerializedTask[] }>;
|
||||
}
|
||||
export type TaskBroker = _TaskBroker;
|
||||
|
||||
/**
|
||||
* TaskStoreEmitOptions
|
||||
|
||||
@@ -231,13 +231,15 @@ export async function createRouter(
|
||||
catalogClient,
|
||||
actions,
|
||||
taskWorkers,
|
||||
concurrentTasksLimit,
|
||||
scheduler,
|
||||
additionalTemplateFilters,
|
||||
additionalTemplateGlobals,
|
||||
permissions,
|
||||
permissionRules,
|
||||
} = options;
|
||||
const concurrentTasksLimit =
|
||||
options.concurrentTasksLimit ??
|
||||
options.config.getOptionalNumber('scaffolder.concurrentTasksLimit');
|
||||
|
||||
const logger = parentLogger.child({ plugin: 'scaffolder' });
|
||||
|
||||
@@ -275,19 +277,21 @@ export async function createRouter(
|
||||
const actionRegistry = new TemplateActionRegistry();
|
||||
|
||||
const workers = [];
|
||||
for (let i = 0; i < (taskWorkers || 1); i++) {
|
||||
const worker = await TaskWorker.create({
|
||||
taskBroker,
|
||||
actionRegistry,
|
||||
integrations,
|
||||
logger,
|
||||
workingDirectory,
|
||||
additionalTemplateFilters,
|
||||
additionalTemplateGlobals,
|
||||
concurrentTasksLimit,
|
||||
permissions,
|
||||
});
|
||||
workers.push(worker);
|
||||
if (concurrentTasksLimit !== 0) {
|
||||
for (let i = 0; i < (taskWorkers || 1); i++) {
|
||||
const worker = await TaskWorker.create({
|
||||
taskBroker,
|
||||
actionRegistry,
|
||||
integrations,
|
||||
logger,
|
||||
workingDirectory,
|
||||
additionalTemplateFilters,
|
||||
additionalTemplateGlobals,
|
||||
concurrentTasksLimit,
|
||||
permissions,
|
||||
});
|
||||
workers.push(worker);
|
||||
}
|
||||
}
|
||||
|
||||
const actionsToRegister = Array.isArray(actions)
|
||||
|
||||
@@ -7,10 +7,17 @@
|
||||
|
||||
import { ExtensionPoint } from '@backstage/backend-plugin-api';
|
||||
import { JsonObject } from '@backstage/types';
|
||||
import { JsonValue } from '@backstage/types';
|
||||
import { Logger } from 'winston';
|
||||
import { Observable } from '@backstage/types';
|
||||
import { Schema } from 'jsonschema';
|
||||
import { ScmIntegrations } from '@backstage/integration';
|
||||
import { SpawnOptionsWithoutStdio } from 'child_process';
|
||||
import { TaskBroker as TaskBroker_2 } from '@backstage/plugin-scaffolder-node';
|
||||
import { TaskSpec } from '@backstage/plugin-scaffolder-common';
|
||||
import { TemplateAction as TemplateAction_2 } from '@backstage/plugin-scaffolder-node';
|
||||
import { TemplateFilter as TemplateFilter_2 } from '@backstage/plugin-scaffolder-node';
|
||||
import { TemplateGlobal as TemplateGlobal_2 } from '@backstage/plugin-scaffolder-node';
|
||||
import { TemplateInfo } from '@backstage/plugin-scaffolder-common';
|
||||
import { UrlReader } from '@backstage/backend-common';
|
||||
import { UserEntity } from '@backstage/catalog-model';
|
||||
@@ -105,17 +112,129 @@ export function fetchFile(options: {
|
||||
// @alpha
|
||||
export interface ScaffolderActionsExtensionPoint {
|
||||
// (undocumented)
|
||||
addActions(...actions: TemplateAction<any, any>[]): void;
|
||||
addActions(...actions: TemplateAction_2<any, any>[]): void;
|
||||
}
|
||||
|
||||
// @alpha
|
||||
export const scaffolderActionsExtensionPoint: ExtensionPoint<ScaffolderActionsExtensionPoint>;
|
||||
|
||||
// @alpha
|
||||
export interface ScaffolderTaskBrokerExtensionPoint {
|
||||
// (undocumented)
|
||||
setTaskBroker(taskBroker: TaskBroker_2): void;
|
||||
}
|
||||
|
||||
// @alpha
|
||||
export const scaffolderTaskBrokerExtensionPoint: ExtensionPoint<ScaffolderTaskBrokerExtensionPoint>;
|
||||
|
||||
// @alpha
|
||||
export interface ScaffolderTemplatingExtensionPoint {
|
||||
// (undocumented)
|
||||
addTemplateFilters(filters: Record<string, TemplateFilter_2>): void;
|
||||
// (undocumented)
|
||||
addTemplateGlobals(filters: Record<string, TemplateGlobal_2>): void;
|
||||
}
|
||||
|
||||
// @alpha
|
||||
export const scaffolderTemplatingExtensionPoint: ExtensionPoint<ScaffolderTemplatingExtensionPoint>;
|
||||
|
||||
// @public
|
||||
export type SerializedTask = {
|
||||
id: string;
|
||||
spec: TaskSpec;
|
||||
status: TaskStatus;
|
||||
createdAt: string;
|
||||
lastHeartbeatAt?: string;
|
||||
createdBy?: string;
|
||||
secrets?: TaskSecrets;
|
||||
};
|
||||
|
||||
// @public
|
||||
export type SerializedTaskEvent = {
|
||||
id: number;
|
||||
taskId: string;
|
||||
body: JsonObject;
|
||||
type: TaskEventType;
|
||||
createdAt: string;
|
||||
};
|
||||
|
||||
// @public
|
||||
export interface TaskBroker {
|
||||
// (undocumented)
|
||||
cancel?(taskId: string): Promise<void>;
|
||||
// (undocumented)
|
||||
claim(): Promise<TaskContext>;
|
||||
// (undocumented)
|
||||
dispatch(
|
||||
options: TaskBrokerDispatchOptions,
|
||||
): Promise<TaskBrokerDispatchResult>;
|
||||
// (undocumented)
|
||||
event$(options: { taskId: string; after: number | undefined }): Observable<{
|
||||
events: SerializedTaskEvent[];
|
||||
}>;
|
||||
// (undocumented)
|
||||
get(taskId: string): Promise<SerializedTask>;
|
||||
// (undocumented)
|
||||
list?(options?: { createdBy?: string }): Promise<{
|
||||
tasks: SerializedTask[];
|
||||
}>;
|
||||
// (undocumented)
|
||||
vacuumTasks(options: { timeoutS: number }): Promise<void>;
|
||||
}
|
||||
|
||||
// @public
|
||||
export type TaskBrokerDispatchOptions = {
|
||||
spec: TaskSpec;
|
||||
secrets?: TaskSecrets;
|
||||
createdBy?: string;
|
||||
};
|
||||
|
||||
// @public
|
||||
export type TaskBrokerDispatchResult = {
|
||||
taskId: string;
|
||||
};
|
||||
|
||||
// @public
|
||||
export type TaskCompletionState = 'failed' | 'completed';
|
||||
|
||||
// @public
|
||||
export interface TaskContext {
|
||||
// (undocumented)
|
||||
cancelSignal: AbortSignal;
|
||||
// (undocumented)
|
||||
complete(result: TaskCompletionState, metadata?: JsonObject): Promise<void>;
|
||||
// (undocumented)
|
||||
createdBy?: string;
|
||||
// (undocumented)
|
||||
done: boolean;
|
||||
// (undocumented)
|
||||
emitLog(message: string, logMetadata?: JsonObject): Promise<void>;
|
||||
// (undocumented)
|
||||
getWorkspaceName(): Promise<string>;
|
||||
// (undocumented)
|
||||
isDryRun?: boolean;
|
||||
// (undocumented)
|
||||
secrets?: TaskSecrets;
|
||||
// (undocumented)
|
||||
spec: TaskSpec;
|
||||
}
|
||||
|
||||
// @public
|
||||
export type TaskEventType = 'completion' | 'log' | 'cancelled';
|
||||
|
||||
// @public
|
||||
export type TaskSecrets = Record<string, string> & {
|
||||
backstageToken?: string;
|
||||
};
|
||||
|
||||
// @public
|
||||
export type TaskStatus =
|
||||
| 'cancelled'
|
||||
| 'completed'
|
||||
| 'failed'
|
||||
| 'open'
|
||||
| 'processing';
|
||||
|
||||
// @public (undocumented)
|
||||
export type TemplateAction<
|
||||
TActionInput extends JsonObject = JsonObject,
|
||||
@@ -158,4 +277,12 @@ export type TemplateExample = {
|
||||
description: string;
|
||||
example: string;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
export type TemplateFilter = (...args: JsonValue[]) => JsonValue | undefined;
|
||||
|
||||
// @public (undocumented)
|
||||
export type TemplateGlobal =
|
||||
| ((...args: JsonValue[]) => JsonValue | undefined)
|
||||
| JsonValue;
|
||||
```
|
||||
|
||||
@@ -15,7 +15,12 @@
|
||||
*/
|
||||
|
||||
import { createExtensionPoint } from '@backstage/backend-plugin-api';
|
||||
import { TemplateAction } from './actions';
|
||||
import {
|
||||
TemplateAction,
|
||||
TemplateFilter,
|
||||
TemplateGlobal,
|
||||
TaskBroker,
|
||||
} from '@backstage/plugin-scaffolder-node';
|
||||
|
||||
/**
|
||||
* Extension point for managing scaffolder actions.
|
||||
@@ -35,3 +40,42 @@ export const scaffolderActionsExtensionPoint =
|
||||
createExtensionPoint<ScaffolderActionsExtensionPoint>({
|
||||
id: 'scaffolder.actions',
|
||||
});
|
||||
|
||||
/**
|
||||
* Extension point for replacing the scaffolder task broker.
|
||||
*
|
||||
* @alpha
|
||||
*/
|
||||
export interface ScaffolderTaskBrokerExtensionPoint {
|
||||
setTaskBroker(taskBroker: TaskBroker): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extension point for replacing the scaffolder task broker.
|
||||
*
|
||||
* @alpha
|
||||
*/
|
||||
export const scaffolderTaskBrokerExtensionPoint =
|
||||
createExtensionPoint<ScaffolderTaskBrokerExtensionPoint>({
|
||||
id: 'scaffolder.taskBroker',
|
||||
});
|
||||
|
||||
/**
|
||||
* Extension point for adding template filters and globals.
|
||||
*
|
||||
* @alpha
|
||||
*/
|
||||
export interface ScaffolderTemplatingExtensionPoint {
|
||||
addTemplateFilters(filters: Record<string, TemplateFilter>): void;
|
||||
addTemplateGlobals(filters: Record<string, TemplateGlobal>): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extension point for adding template filters and globals.
|
||||
*
|
||||
* @alpha
|
||||
*/
|
||||
export const scaffolderTemplatingExtensionPoint =
|
||||
createExtensionPoint<ScaffolderTemplatingExtensionPoint>({
|
||||
id: 'scaffolder.templating',
|
||||
});
|
||||
|
||||
@@ -22,7 +22,12 @@
|
||||
|
||||
export * from './actions';
|
||||
export * from './tasks';
|
||||
export type { TemplateFilter, TemplateGlobal } from './types';
|
||||
export {
|
||||
scaffolderActionsExtensionPoint,
|
||||
type ScaffolderActionsExtensionPoint,
|
||||
scaffolderTaskBrokerExtensionPoint,
|
||||
type ScaffolderTaskBrokerExtensionPoint,
|
||||
scaffolderTemplatingExtensionPoint,
|
||||
type ScaffolderTemplatingExtensionPoint,
|
||||
} from './extensions';
|
||||
|
||||
@@ -14,4 +14,15 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export { type TaskSecrets } from './types';
|
||||
export type {
|
||||
TaskSecrets,
|
||||
SerializedTask,
|
||||
SerializedTaskEvent,
|
||||
TaskBroker,
|
||||
TaskBrokerDispatchOptions,
|
||||
TaskBrokerDispatchResult,
|
||||
TaskCompletionState,
|
||||
TaskContext,
|
||||
TaskEventType,
|
||||
TaskStatus,
|
||||
} from './types';
|
||||
|
||||
@@ -14,6 +14,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { TaskSpec } from '@backstage/plugin-scaffolder-common';
|
||||
import { JsonObject, Observable } from '@backstage/types';
|
||||
|
||||
/**
|
||||
* TaskSecrets
|
||||
*
|
||||
@@ -22,3 +25,124 @@
|
||||
export type TaskSecrets = Record<string, string> & {
|
||||
backstageToken?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* The status of each step of the Task
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type TaskStatus =
|
||||
| 'cancelled'
|
||||
| 'completed'
|
||||
| 'failed'
|
||||
| 'open'
|
||||
| 'processing';
|
||||
|
||||
/**
|
||||
* The state of a completed task.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type TaskCompletionState = 'failed' | 'completed';
|
||||
|
||||
/**
|
||||
* SerializedTask
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type SerializedTask = {
|
||||
id: string;
|
||||
spec: TaskSpec;
|
||||
status: TaskStatus;
|
||||
createdAt: string;
|
||||
lastHeartbeatAt?: string;
|
||||
createdBy?: string;
|
||||
secrets?: TaskSecrets;
|
||||
};
|
||||
|
||||
/**
|
||||
* TaskEventType
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type TaskEventType = 'completion' | 'log' | 'cancelled';
|
||||
|
||||
/**
|
||||
* SerializedTaskEvent
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type SerializedTaskEvent = {
|
||||
id: number;
|
||||
taskId: string;
|
||||
body: JsonObject;
|
||||
type: TaskEventType;
|
||||
createdAt: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* The result of {@link TaskBroker.dispatch}
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type TaskBrokerDispatchResult = {
|
||||
taskId: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* The options passed to {@link TaskBroker.dispatch}
|
||||
* Currently a spec and optional secrets
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type TaskBrokerDispatchOptions = {
|
||||
spec: TaskSpec;
|
||||
secrets?: TaskSecrets;
|
||||
createdBy?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Task
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface TaskContext {
|
||||
cancelSignal: AbortSignal;
|
||||
spec: TaskSpec;
|
||||
secrets?: TaskSecrets;
|
||||
createdBy?: string;
|
||||
done: boolean;
|
||||
isDryRun?: boolean;
|
||||
|
||||
complete(result: TaskCompletionState, metadata?: JsonObject): Promise<void>;
|
||||
|
||||
emitLog(message: string, logMetadata?: JsonObject): Promise<void>;
|
||||
|
||||
getWorkspaceName(): Promise<string>;
|
||||
}
|
||||
|
||||
/**
|
||||
* TaskBroker
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface TaskBroker {
|
||||
cancel?(taskId: string): Promise<void>;
|
||||
|
||||
claim(): Promise<TaskContext>;
|
||||
|
||||
dispatch(
|
||||
options: TaskBrokerDispatchOptions,
|
||||
): Promise<TaskBrokerDispatchResult>;
|
||||
|
||||
vacuumTasks(options: { timeoutS: number }): Promise<void>;
|
||||
|
||||
event$(options: {
|
||||
taskId: string;
|
||||
after: number | undefined;
|
||||
}): Observable<{ events: SerializedTaskEvent[] }>;
|
||||
|
||||
get(taskId: string): Promise<SerializedTask>;
|
||||
|
||||
list?(options?: { createdBy?: string }): Promise<{ tasks: SerializedTask[] }>;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2023 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.
|
||||
*/
|
||||
|
||||
import { JsonValue } from '@backstage/types';
|
||||
|
||||
/** @public */
|
||||
export type TemplateFilter = (...args: JsonValue[]) => JsonValue | undefined;
|
||||
|
||||
/** @public */
|
||||
export type TemplateGlobal =
|
||||
| ((...args: JsonValue[]) => JsonValue | undefined)
|
||||
| JsonValue;
|
||||
Reference in New Issue
Block a user