Add support for passing actions into router

Co-authored-by: blam<ben@blam.sh>
Signed-off-by: Johan Haals <johan.haals@gmail.com>
This commit is contained in:
Johan Haals
2021-02-25 15:38:02 +01:00
parent 807cf164af
commit 3efba84528
6 changed files with 173 additions and 129 deletions
@@ -0,0 +1,71 @@
/*
* 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 { UrlReader } from '@backstage/backend-common';
import { CatalogApi } from '@backstage/catalog-client';
import { ScmIntegrations } from '@backstage/integration';
import { createCatalogRegisterAction } from './catalog';
import { createFetchCookiecutterAction, createFetchPlainAction } from './fetch';
import {
createPublishAzureAction,
createPublishBitbucketAction,
createPublishGithubAction,
createPublishGitlabAction,
} from './publish';
import Docker from 'dockerode';
import { TemplaterBuilder } from '../../stages';
export const createBuiltinActions = (options: {
reader: UrlReader;
integrations: ScmIntegrations;
dockerClient: Docker;
catalogClient: CatalogApi;
templaters: TemplaterBuilder;
}) => {
const {
reader,
integrations,
dockerClient,
templaters,
catalogClient,
} = options;
return [
createFetchPlainAction({
reader,
integrations,
}),
createFetchCookiecutterAction({
reader,
integrations,
dockerClient,
templaters,
}),
createPublishGithubAction({
integrations,
}),
createPublishGitlabAction({
integrations,
}),
createPublishBitbucketAction({
integrations,
}),
createPublishAzureAction({
integrations,
}),
createCatalogRegisterAction({ catalogClient, integrations }),
];
};
@@ -17,3 +17,4 @@
export * from './catalog';
export * from './fetch';
export * from './publish';
export { createBuiltinActions } from './createBuiltinActions';
@@ -15,3 +15,4 @@
*/
export * from './stages';
export * from './jobs';
export * from './actions';
@@ -17,3 +17,5 @@ export * from './prepare';
export * from './publish';
export * from './templater';
export * from './helpers';
export { createLegacyActions } from './legacy';
@@ -14,11 +14,11 @@
* limitations under the License.
*/
import { TemplateActionRegistry } from '../actions/TemplateActionRegistry';
import { FilePreparer, PreparerBuilder } from './prepare';
import Docker from 'dockerode';
import { TemplaterBuilder, TemplaterValues } from './templater';
import { PublisherBuilder } from './publish';
import { createTemplateAction } from '../actions';
type Options = {
dockerClient: Docker;
@@ -27,81 +27,82 @@ type Options = {
publishers: PublisherBuilder;
};
export function registerLegacyActions(
registry: TemplateActionRegistry,
options: Options,
) {
export function createLegacyActions(options: Options) {
const { dockerClient, preparers, templaters, publishers } = options;
registry.register({
id: 'legacy:prepare',
async handler(ctx) {
ctx.logger.info('Preparing the skeleton');
const { protocol, url } = ctx.input;
const preparer =
protocol === 'file' ? new FilePreparer() : preparers.get(url as string);
return [
createTemplateAction({
id: 'legacy:prepare',
async handler(ctx) {
ctx.logger.info('Preparing the skeleton');
const { protocol, url } = ctx.input;
const preparer =
protocol === 'file'
? new FilePreparer()
: preparers.get(url as string);
await preparer.prepare({
url: url as string,
logger: ctx.logger,
workspacePath: ctx.workspacePath,
});
},
});
await preparer.prepare({
url: url as string,
logger: ctx.logger,
workspacePath: ctx.workspacePath,
});
},
}),
createTemplateAction({
id: 'legacy:template',
async handler(ctx) {
ctx.logger.info('Running the templater');
const templater = templaters.get(ctx.input.templater as string);
await templater.run({
workspacePath: ctx.workspacePath,
dockerClient,
logStream: ctx.logStream,
values: ctx.input.values as TemplaterValues,
});
},
}),
createTemplateAction({
id: 'legacy:publish',
async handler(ctx) {
const { values } = ctx.input;
if (
typeof values !== 'object' ||
values === null ||
Array.isArray(values)
) {
throw new Error(
`Invalid values passed to publish, got ${typeof values}`,
);
}
const storePath = values.storePath as unknown;
if (typeof storePath !== 'string') {
throw new Error(
`Invalid store path passed to publish, got ${typeof storePath}`,
);
}
const owner = values.owner as unknown;
if (typeof owner !== 'string') {
throw new Error(
`Invalid owner passed to publish, got ${typeof owner}`,
);
}
registry.register({
id: 'legacy:template',
async handler(ctx) {
ctx.logger.info('Running the templater');
const templater = templaters.get(ctx.input.templater as string);
await templater.run({
workspacePath: ctx.workspacePath,
dockerClient,
logStream: ctx.logStream,
values: ctx.input.values as TemplaterValues,
});
},
});
registry.register({
id: 'legacy:publish',
async handler(ctx) {
const { values } = ctx.input;
if (
typeof values !== 'object' ||
values === null ||
Array.isArray(values)
) {
throw new Error(
`Invalid values passed to publish, got ${typeof values}`,
);
}
const storePath = values.storePath as unknown;
if (typeof storePath !== 'string') {
throw new Error(
`Invalid store path passed to publish, got ${typeof storePath}`,
);
}
const owner = values.owner as unknown;
if (typeof owner !== 'string') {
throw new Error(`Invalid owner passed to publish, got ${typeof owner}`);
}
const publisher = publishers.get(storePath);
ctx.logger.info('Will now store the template');
const { remoteUrl, catalogInfoUrl } = await publisher.publish({
values: {
...values,
owner,
storePath,
},
workspacePath: ctx.workspacePath,
logger: ctx.logger,
});
ctx.output('remoteUrl', remoteUrl);
if (catalogInfoUrl) {
ctx.output('catalogInfoUrl', catalogInfoUrl);
}
},
});
const publisher = publishers.get(storePath);
ctx.logger.info('Will now store the template');
const { remoteUrl, catalogInfoUrl } = await publisher.publish({
values: {
...values,
owner,
storePath,
},
workspacePath: ctx.workspacePath,
logger: ctx.logger,
});
ctx.output('remoteUrl', remoteUrl);
if (catalogInfoUrl) {
ctx.output('catalogInfoUrl', catalogInfoUrl);
}
},
}),
];
}
@@ -40,7 +40,7 @@ import {
} from '../scaffolder/tasks';
import { templateEntityToSpec } from '../scaffolder/tasks/TemplateConverter';
import { TemplateActionRegistry } from '../scaffolder/actions/TemplateActionRegistry';
import { registerLegacyActions } from '../scaffolder/stages/legacy';
import { createLegacyActions } from '../scaffolder/stages/legacy';
import { getEntityBaseUrl, getWorkingDirectory } from './helpers';
import {
InputError,
@@ -54,16 +54,9 @@ import {
TemplateEntityV1beta2,
Entity,
} from '@backstage/catalog-model';
import {
createFetchPlainAction,
createFetchCookiecutterAction,
createPublishGithubAction,
createPublishBitbucketAction,
createPublishAzureAction,
createPublishGitlabAction,
createCatalogRegisterAction,
} from '../scaffolder/actions/builtin';
import { ScmIntegrations } from '@backstage/integration';
import { TemplateAction } from '../scaffolder/actions';
import { createBuiltinActions } from '../scaffolder/actions/builtin/createBuiltinActions';
export interface RouterOptions {
preparers: PreparerBuilder;
@@ -76,6 +69,7 @@ export interface RouterOptions {
dockerClient: Docker;
database: PluginDatabaseManager;
catalogClient: CatalogApi;
actions?: TemplateAction<any>[];
}
function isAlpha1Template(
@@ -109,6 +103,7 @@ export async function createRouter(
dockerClient,
database,
catalogClient,
actions,
} = options;
const logger = parentLogger.child({ plugin: 'scaffolder' });
@@ -129,52 +124,25 @@ export async function createRouter(
workingDirectory,
});
registerLegacyActions(actionRegistry, {
dockerClient,
preparers,
publishers,
templaters,
});
actionRegistry.register(
createFetchPlainAction({
reader,
integrations,
}),
);
actionRegistry.register(
createFetchCookiecutterAction({
reader,
integrations,
dockerClient,
templaters,
}),
);
actionRegistry.register(
createPublishGithubAction({
integrations,
}),
);
actionRegistry.register(
createPublishGitlabAction({
integrations,
}),
);
const actionsToRegister = Array.isArray(actions)
? actions
: [
...createLegacyActions({
dockerClient,
preparers,
publishers,
templaters,
}),
...createBuiltinActions({
dockerClient,
integrations,
catalogClient,
templaters,
reader,
}),
];
actionRegistry.register(
createPublishBitbucketAction({
integrations,
}),
);
actionRegistry.register(
createPublishAzureAction({
integrations,
}),
);
actionRegistry.register(
createCatalogRegisterAction({ catalogClient, integrations }),
);
actionsToRegister.forEach(action => actionRegistry.register(action));
worker.start();