From 8623025c9b789b85bdf87b9cdf9cc94995f55859 Mon Sep 17 00:00:00 2001 From: Johan Haals Date: Tue, 26 Jan 2021 12:00:40 +0100 Subject: [PATCH] Wip wip --- .../src/scaffolder/stages/legacy.ts | 106 +++++++++++++++++ .../scaffolder/tasks/MemoryTaskBroker.test.ts | 2 +- .../src/scaffolder/tasks/TemplateConverter.ts | 110 ++++++++++++++++++ .../src/scaffolder/tasks/types.ts | 11 +- .../scaffolder-backend/src/service/router.ts | 2 + 5 files changed, 226 insertions(+), 5 deletions(-) create mode 100644 plugins/scaffolder-backend/src/scaffolder/stages/legacy.ts create mode 100644 plugins/scaffolder-backend/src/scaffolder/tasks/TemplateConverter.ts diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/legacy.ts b/plugins/scaffolder-backend/src/scaffolder/stages/legacy.ts new file mode 100644 index 0000000000..c9bd89c3dd --- /dev/null +++ b/plugins/scaffolder-backend/src/scaffolder/stages/legacy.ts @@ -0,0 +1,106 @@ +/* + * Copyright 2021 Spotify AB + * + * 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 { Config } from '@backstage/config'; +import { TemplateActionRegistry } from '../TemplateConverter'; +import { FilePreparer } from './prepare'; +import Docker from 'dockerode'; + +type Options = { + logger: Logger; + config: Config; + dockerClient: Docker; +}; + +export function registerLegacyActions( + registry: TemplateActionRegistry, + options: Options, +) { + registry.register({ + id: 'legacy:prepare', + async handler(ctx) { + const { logger } = ctx; + console.log(ctx); + logger.info('Task claimed, waiting ...'); + // Give us some time to curl observe + await new Promise(resolve => setTimeout(resolve, 5000)); + + logger.info('Prepare the skeleton'); + + const { protocol, pullPath } = ctx.parameters; + + const preparer = + protocol === 'file' + ? new FilePreparer() + : preparers.get(pullPath as string); + + await preparer.prepare(task.spec.template, { + logger, + ctx.workspaceDir, + }); + ctx.output('catalogInfoUrl', 'httpderp://asdasd'); + }, + }); + + // try { + // const { values, template } = task.spec; + // task.emitLog('Prepare the skeleton'); + // const { protocol, location: pullPath } = parseLocationAnnotation( + // task.spec.template, + // ); + // const preparer = + // protocol === 'file' ? new FilePreparer() : preparers.get(pullPath); + // const templater = templaters.get(template); + // const publisher = publishers.get(values.storePath); + + // const skeletonDir = await preparer.prepare(task.spec.template, { + // logger: taskLogger, + // workingDirectory: workingDirectory, + // }); + + registry.register({ + id: 'legacy:template', + async handler(ctx) { + const { logger } = ctx; + + const templater = templaters.get(ctx.parameters.templater as string); + + logger.info('Run the templater'); + const { resultDir } = await templater.run({ + directory: ctx.workspaceDir, + dockerClient, + logStream: ctx.logStream, + values: ctx.parameters.values as TemplaterValues, + }); + }, + }); + // task.emitLog('Publish template'); + // logger.info('Will now store the template'); + + // logger.info('Totally storing the template now'); + // await new Promise(resolve => setTimeout(resolve, 5000)); + // // const result = await publisher.publish({ + // // values: values, + // // directory: resultDir, + // // logger, + // // }); + // // task.emitLog(`Result: ${JSON.stringify(result)}`); + + // await task.complete('completed'); + // } catch (error) { + // await task.complete('failed'); + // } +} diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/MemoryTaskBroker.test.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/MemoryTaskBroker.test.ts index 1ac416ad4f..686a6d9132 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/MemoryTaskBroker.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/MemoryTaskBroker.test.ts @@ -15,7 +15,7 @@ */ import { TemplateEntityV1alpha1 } from '@backstage/catalog-model'; -import { TemplaterValues } from '../stages/templater/types'; +import { TemplaterValues } from './actions/templater/types'; import { MemoryDatabase } from './MemoryDatabase'; import { MemoryTaskBroker, TaskAgent } from './MemoryTaskBroker'; diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/TemplateConverter.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/TemplateConverter.ts new file mode 100644 index 0000000000..e435812fe5 --- /dev/null +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/TemplateConverter.ts @@ -0,0 +1,110 @@ +/* + * Copyright 2021 Spotify AB + * + * 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/config'; +import { TemplateEntityV1alpha1 } from '@backstage/catalog-model'; +import { Logger } from 'winston'; +import type { Writable } from 'stream'; +import { + getTemplaterKey, + parseLocationAnnotation, + TemplaterValues, +} from '../jobs/actions'; +import { TaskSpec } from './types'; +import { ConflictError, NotFoundError } from '@backstage/backend-common'; + +function templateEntityToSpec( + template: TemplateEntityV1alpha1, + values: TemplaterValues, +): TaskSpec { + const steps: TaskSpec['steps'] = []; + + const { protocol, location: pullPath } = parseLocationAnnotation(template); + const templater = getTemplaterKey(template); + + steps.push({ + id: 'prepare', + name: 'Prepare', + action: 'legacy:prepare', + parameters: { + protocol, + pullPath, + }, + }); + + steps.push({ + id: 'template', + name: 'Template', + action: 'legacy:template', + parameters: { + templater, + values, + }, + }); + + steps.push({ + id: 'publish', + name: 'Publishing', + action: 'publish', + parameters: { + values, + directory, + }, + }); + + return { steps }; +} + +type ActionContext = { + logger: Logger; + logStream: Writable; + + workspaceDir: string; + parameters: { [name: string]: JsonValue }; + output(name: string, value: JsonValue): void; +}; + +type TemplateAction = { + id: string; + handler: (ctx: ActionContext) => Promise; +}; + +export class TemplateActionRegistry { + private readonly actions = new Map(); + + register(action: TemplateAction) { + if (this.actions.has(action.id)) { + throw new ConflictError( + `Template action with id ${action.id} as already been registered`, + ); + } + this.actions.set(action.id, action); + } + + // validate + // ensure that action exist. + // template variables exist. + + get(actionId: string): TemplateAction { + const action = this.actions.get(actionId); + if (!action) { + throw new NotFoundError( + `Template action with id ${actionId} is not registered.`, + ); + } + return action; + } +} diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/types.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/types.ts index 47226dc6e9..620b6e7243 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/types.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/types.ts @@ -14,8 +14,7 @@ * limitations under the License. */ -import { TemplateEntityV1alpha1 } from '@backstage/catalog-model'; -import { TemplaterValues } from '..'; +import { JsonObject } from '@backstage/config'; export type Status = | 'open' @@ -47,8 +46,12 @@ export type DbTaskEventRow = { }; export type TaskSpec = { - template: TemplateEntityV1alpha1; - values: TemplaterValues; + steps: Array<{ + id: string; + name: string; + action: string; + parameters?: JsonObject; + }>; }; export type DispatchResult = { diff --git a/plugins/scaffolder-backend/src/service/router.ts b/plugins/scaffolder-backend/src/service/router.ts index 9514d215d0..fc40d45ce2 100644 --- a/plugins/scaffolder-backend/src/service/router.ts +++ b/plugins/scaffolder-backend/src/service/router.ts @@ -38,6 +38,8 @@ import { MemoryDatabase, TaskWorker, } from '../scaffolder/tasks'; +import { TemplateActionRegistry } from '../scaffolder/tasks/TemplateConverter'; +import { LOCATION_ANNOTATION } from '@backstage/catalog-model'; export interface RouterOptions { preparers: PreparerBuilder;