Wrap actions in createTemplateAction
Rename paramers to input Co-authored-by: Ben Lambert <ben@blam.sh> Co-authored-by: Patrik Oldsberg <poldsberg@gmail.com> Co-authored-by: Fredrik Adelöw <freben@users.noreply.github.com> Signed-off-by: Johan Haals <johan.haals@gmail.com>
This commit is contained in:
@@ -14,15 +14,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ParameterBase, TemplateAction } from './types';
|
||||
import { InputBase, TemplateAction } from './types';
|
||||
import { ConflictError, NotFoundError } from '@backstage/backend-common';
|
||||
|
||||
export class TemplateActionRegistry {
|
||||
private readonly actions = new Map<string, TemplateAction<any>>();
|
||||
|
||||
register<Parameters extends ParameterBase>(
|
||||
action: TemplateAction<Parameters>,
|
||||
) {
|
||||
register<Parameters extends InputBase>(action: TemplateAction<Parameters>) {
|
||||
if (this.actions.has(action.id)) {
|
||||
throw new ConflictError(
|
||||
`Template action with ID '${action.id}' has already been registered`,
|
||||
|
||||
@@ -18,72 +18,76 @@ import { InputError } from '@backstage/backend-common';
|
||||
import { ScmIntegrations } from '@backstage/integration';
|
||||
import { CatalogApi } from '@backstage/catalog-client';
|
||||
import { getEntityName } from '@backstage/catalog-model';
|
||||
import { TemplateAction } from '../../types';
|
||||
import { createTemplateAction } from '../../createTemplateAction';
|
||||
|
||||
export function createCatalogRegisterAction(options: {
|
||||
catalogClient: CatalogApi;
|
||||
integrations: ScmIntegrations;
|
||||
}): TemplateAction<
|
||||
| { catalogInfoUrl: string }
|
||||
| { repoContentsUrl: string; catalogInfoPath?: string }
|
||||
> {
|
||||
}) {
|
||||
const { catalogClient, integrations } = options;
|
||||
|
||||
return {
|
||||
return createTemplateAction<
|
||||
| { catalogInfoUrl: string }
|
||||
| { repoContentsUrl: string; catalogInfoPath?: string }
|
||||
>({
|
||||
id: 'catalog:register',
|
||||
parameterSchema: {
|
||||
oneOf: [
|
||||
{
|
||||
type: 'object',
|
||||
required: ['catalogInfoUrl'],
|
||||
properties: {
|
||||
catalogInfoUrl: {
|
||||
title: 'Catalog Info URL',
|
||||
description:
|
||||
'An absolute URL pointing to the catalog info file location',
|
||||
type: 'string',
|
||||
schema: {
|
||||
input: {
|
||||
oneOf: [
|
||||
{
|
||||
type: 'object',
|
||||
required: ['catalogInfoUrl'],
|
||||
properties: {
|
||||
catalogInfoUrl: {
|
||||
title: 'Catalog Info URL',
|
||||
description:
|
||||
'An absolute URL pointing to the catalog info file location',
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'object',
|
||||
required: ['repoContentsUrl'],
|
||||
properties: {
|
||||
repoContentsUrl: {
|
||||
title: 'Repository Contents URL',
|
||||
description:
|
||||
'An absolute URL pointing to the root of a repository directory tree',
|
||||
type: 'string',
|
||||
},
|
||||
catalogInfoPath: {
|
||||
title: 'Fetch URL',
|
||||
description:
|
||||
'A relative path from the repo root pointing to the catalog info file, defaults to /catalog-info.yaml',
|
||||
type: 'string',
|
||||
{
|
||||
type: 'object',
|
||||
required: ['repoContentsUrl'],
|
||||
properties: {
|
||||
repoContentsUrl: {
|
||||
title: 'Repository Contents URL',
|
||||
description:
|
||||
'An absolute URL pointing to the root of a repository directory tree',
|
||||
type: 'string',
|
||||
},
|
||||
catalogInfoPath: {
|
||||
title: 'Fetch URL',
|
||||
description:
|
||||
'A relative path from the repo root pointing to the catalog info file, defaults to /catalog-info.yaml',
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
},
|
||||
async handler(ctx) {
|
||||
const { parameters } = ctx;
|
||||
const { input } = ctx;
|
||||
|
||||
let catalogInfoUrl;
|
||||
if ('catalogInfoUrl' in parameters) {
|
||||
catalogInfoUrl = parameters.catalogInfoUrl;
|
||||
if ('catalogInfoUrl' in input) {
|
||||
catalogInfoUrl = input.catalogInfoUrl;
|
||||
} else {
|
||||
const {
|
||||
repoContentsUrl,
|
||||
catalogInfoPath = '/catalog-info.yaml',
|
||||
} = parameters;
|
||||
const integration = integrations.byUrl(repoContentsUrl as string);
|
||||
} = input;
|
||||
const integration = integrations.byUrl(repoContentsUrl);
|
||||
if (!integration) {
|
||||
throw new InputError('No integration found for host');
|
||||
throw new InputError(
|
||||
`No integration found for host ${repoContentsUrl}`,
|
||||
);
|
||||
}
|
||||
|
||||
catalogInfoUrl = integration.resolveUrl({
|
||||
base: repoContentsUrl as string,
|
||||
url: catalogInfoPath as string,
|
||||
base: repoContentsUrl,
|
||||
url: catalogInfoPath,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -91,13 +95,15 @@ export function createCatalogRegisterAction(options: {
|
||||
|
||||
const result = await catalogClient.addLocation({
|
||||
type: 'url',
|
||||
target: catalogInfoUrl as string,
|
||||
target: catalogInfoUrl,
|
||||
});
|
||||
if (result.entities.length >= 1) {
|
||||
const { kind, name, namespace } = getEntityName(result.entities[0]);
|
||||
ctx.output('entityRef', `${kind}:${namespace}/${name}`);
|
||||
ctx.output('catalogInfoUrl', catalogInfoUrl);
|
||||
if (catalogInfoUrl) {
|
||||
ctx.output('catalogInfoUrl', catalogInfoUrl);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@@ -21,18 +21,22 @@ import { InputError, UrlReader } from '@backstage/backend-common';
|
||||
import { ScmIntegrations } from '@backstage/integration';
|
||||
import { JsonObject } from '@backstage/config';
|
||||
import { TemplaterBuilder, TemplaterValues } from '../../../stages/templater';
|
||||
import { TemplateAction } from '../../types';
|
||||
import { fetchContents } from './helpers';
|
||||
import { createTemplateAction } from '../../createTemplateAction';
|
||||
|
||||
export function createFetchCookiecutterAction(options: {
|
||||
dockerClient: Docker;
|
||||
reader: UrlReader;
|
||||
integrations: ScmIntegrations;
|
||||
templaters: TemplaterBuilder;
|
||||
}): TemplateAction<{ url: string; targetPath?: string; values: JsonObject }> {
|
||||
}) {
|
||||
const { dockerClient, reader, templaters, integrations } = options;
|
||||
|
||||
return {
|
||||
return createTemplateAction<{
|
||||
url: string;
|
||||
targetPath?: string;
|
||||
values: JsonObject;
|
||||
}>({
|
||||
id: 'fetch:cookiecutter',
|
||||
schema: {
|
||||
input: {
|
||||
@@ -73,7 +77,7 @@ export function createFetchCookiecutterAction(options: {
|
||||
reader,
|
||||
integrations,
|
||||
baseUrl: ctx.baseUrl,
|
||||
fetchUrl: ctx.parameters.url,
|
||||
fetchUrl: ctx.input.url,
|
||||
outputPath: templateContentsDir,
|
||||
});
|
||||
|
||||
@@ -87,11 +91,11 @@ export function createFetchCookiecutterAction(options: {
|
||||
workspacePath: workDir,
|
||||
dockerClient,
|
||||
logStream: ctx.logStream,
|
||||
values: ctx.parameters.values as TemplaterValues,
|
||||
values: ctx.input.values as TemplaterValues,
|
||||
});
|
||||
|
||||
// Finally move the template result into the task workspace
|
||||
const targetPath = ctx.parameters.targetPath ?? './';
|
||||
const targetPath = ctx.input.targetPath ?? './';
|
||||
const outputPath = resolvePath(ctx.workspacePath, targetPath);
|
||||
if (!outputPath.startsWith(ctx.workspacePath)) {
|
||||
throw new InputError(
|
||||
@@ -100,5 +104,5 @@ export function createFetchCookiecutterAction(options: {
|
||||
}
|
||||
await fs.copy(resultDir, outputPath);
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@@ -17,16 +17,16 @@
|
||||
import { resolve as resolvePath } from 'path';
|
||||
import { InputError, UrlReader } from '@backstage/backend-common';
|
||||
import { ScmIntegrations } from '@backstage/integration';
|
||||
import { TemplateAction } from '../../types';
|
||||
import { fetchContents } from './helpers';
|
||||
import { createTemplateAction } from '../../createTemplateAction';
|
||||
|
||||
export function createFetchPlainAction(options: {
|
||||
reader: UrlReader;
|
||||
integrations: ScmIntegrations;
|
||||
}): TemplateAction<{ url: string; targetPath?: string }> {
|
||||
}) {
|
||||
const { reader, integrations } = options;
|
||||
|
||||
return {
|
||||
return createTemplateAction<{ url: string; targetPath?: string }>({
|
||||
id: 'fetch:plain',
|
||||
schema: {
|
||||
input: {
|
||||
@@ -52,7 +52,7 @@ export function createFetchPlainAction(options: {
|
||||
ctx.logger.info('Fetching plain content from remote URL');
|
||||
|
||||
// Finally move the template result into the task workspace
|
||||
const targetPath = ctx.parameters.targetPath ?? './';
|
||||
const targetPath = ctx.input.targetPath ?? './';
|
||||
const outputPath = resolvePath(ctx.workspacePath, targetPath);
|
||||
if (!outputPath.startsWith(ctx.workspacePath)) {
|
||||
throw new InputError(
|
||||
@@ -64,9 +64,9 @@ export function createFetchPlainAction(options: {
|
||||
reader,
|
||||
integrations,
|
||||
baseUrl: ctx.baseUrl,
|
||||
fetchUrl: ctx.parameters.url,
|
||||
fetchUrl: ctx.input.url,
|
||||
outputPath,
|
||||
});
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@@ -16,21 +16,21 @@
|
||||
|
||||
import { InputError } from '@backstage/backend-common';
|
||||
import { ScmIntegrations } from '@backstage/integration';
|
||||
import { TemplateAction } from '../../types';
|
||||
import { initRepoAndPush } from '../../../stages/publish/helpers';
|
||||
import { GitRepositoryCreateOptions } from 'azure-devops-node-api/interfaces/GitInterfaces';
|
||||
import { getPersonalAccessTokenHandler, WebApi } from 'azure-devops-node-api';
|
||||
import { parseRepoUrl } from './util';
|
||||
import { createTemplateAction } from '../../createTemplateAction';
|
||||
|
||||
export function createPublishAzureAction(options: {
|
||||
integrations: ScmIntegrations;
|
||||
}): TemplateAction<{
|
||||
repoUrl: string;
|
||||
description?: string;
|
||||
}> {
|
||||
}) {
|
||||
const { integrations } = options;
|
||||
|
||||
return {
|
||||
return createTemplateAction<{
|
||||
repoUrl: string;
|
||||
description?: string;
|
||||
}>({
|
||||
id: 'publish:azure',
|
||||
schema: {
|
||||
input: {
|
||||
@@ -63,12 +63,12 @@ export function createPublishAzureAction(options: {
|
||||
},
|
||||
async handler(ctx) {
|
||||
const { owner, repo, host, organization } = parseRepoUrl(
|
||||
ctx.parameters.repoUrl,
|
||||
ctx.input.repoUrl,
|
||||
);
|
||||
|
||||
if (!organization) {
|
||||
throw new InputError(
|
||||
`No Organization was included in the repo URL to create ${ctx.parameters.repoUrl}`,
|
||||
`No Organization was included in the repo URL to create ${ctx.input.repoUrl}`,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -122,5 +122,5 @@ export function createPublishAzureAction(options: {
|
||||
ctx.output('remoteUrl', remoteUrl);
|
||||
ctx.output('repoContentsUrl', repoContentsUrl);
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@@ -19,10 +19,10 @@ import {
|
||||
BitbucketIntegrationConfig,
|
||||
ScmIntegrations,
|
||||
} from '@backstage/integration';
|
||||
import { TemplateAction } from '../../types';
|
||||
import { initRepoAndPush } from '../../../stages/publish/helpers';
|
||||
import { parseRepoUrl } from './util';
|
||||
import fetch from 'cross-fetch';
|
||||
import { createTemplateAction } from '../../createTemplateAction';
|
||||
|
||||
const createBitbucketCloudRepository = async (opts: {
|
||||
owner: string;
|
||||
@@ -33,8 +33,6 @@ const createBitbucketCloudRepository = async (opts: {
|
||||
}) => {
|
||||
const { owner, repo, description, repoVisibility, authorization } = opts;
|
||||
|
||||
let response: Response;
|
||||
|
||||
const options: RequestInit = {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
@@ -47,6 +45,8 @@ const createBitbucketCloudRepository = async (opts: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
};
|
||||
|
||||
let response: Response;
|
||||
try {
|
||||
response = await fetch(
|
||||
`https://api.bitbucket.org/2.0/repositories/${owner}/${repo}`,
|
||||
@@ -55,20 +55,26 @@ const createBitbucketCloudRepository = async (opts: {
|
||||
} catch (e) {
|
||||
throw new Error(`Unable to create repository, ${e}`);
|
||||
}
|
||||
if (response.status === 200) {
|
||||
const r = await response.json();
|
||||
let remoteUrl = '';
|
||||
for (const link of r.links.clone) {
|
||||
if (link.name === 'https') {
|
||||
remoteUrl = link.href;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO use the urlReader to get the default branch
|
||||
const repoContentsUrl = `${r.links.html.href}/src/master`;
|
||||
return { remoteUrl, repoContentsUrl };
|
||||
if (response.status !== 200) {
|
||||
throw new Error(
|
||||
`Unable to create repository, ${response.status} ${
|
||||
response.statusText
|
||||
}, ${await response.text()}`,
|
||||
);
|
||||
}
|
||||
throw new Error(`Not a valid response code ${await response.text()}`);
|
||||
|
||||
const r = await response.json();
|
||||
let remoteUrl = '';
|
||||
for (const link of r.links.clone) {
|
||||
if (link.name === 'https') {
|
||||
remoteUrl = link.href;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO use the urlReader to get the default branch
|
||||
const repoContentsUrl = `${r.links.html.href}/src/master`;
|
||||
return { remoteUrl, repoContentsUrl };
|
||||
};
|
||||
|
||||
const createBitbucketServerRepository = async (opts: {
|
||||
@@ -110,18 +116,25 @@ const createBitbucketServerRepository = async (opts: {
|
||||
} catch (e) {
|
||||
throw new Error(`Unable to create repository, ${e}`);
|
||||
}
|
||||
if (response.status === 201) {
|
||||
const r = await response.json();
|
||||
let remoteUrl = '';
|
||||
for (const link of r.links.clone) {
|
||||
if (link.name === 'http') {
|
||||
remoteUrl = link.href;
|
||||
}
|
||||
}
|
||||
const repoContentsUrl = `${r.links.self[0].href}`;
|
||||
return { remoteUrl, repoContentsUrl };
|
||||
|
||||
if (response.status !== 201) {
|
||||
throw new Error(
|
||||
`Unable to create repository, ${response.status} ${
|
||||
response.statusText
|
||||
}, ${await response.text()}`,
|
||||
);
|
||||
}
|
||||
throw new Error(`Not a valid response code ${await response.text()}`);
|
||||
|
||||
const r = await response.json();
|
||||
let remoteUrl = '';
|
||||
for (const link of r.links.clone) {
|
||||
if (link.name === 'http') {
|
||||
remoteUrl = link.href;
|
||||
}
|
||||
}
|
||||
|
||||
const repoContentsUrl = `${r.links.self[0].href}`;
|
||||
return { remoteUrl, repoContentsUrl };
|
||||
};
|
||||
|
||||
const getAuthorizationHeader = (config: BitbucketIntegrationConfig) => {
|
||||
@@ -145,14 +158,14 @@ const getAuthorizationHeader = (config: BitbucketIntegrationConfig) => {
|
||||
|
||||
export function createPublishBitbucketAction(options: {
|
||||
integrations: ScmIntegrations;
|
||||
}): TemplateAction<{
|
||||
repoUrl: string;
|
||||
description: string;
|
||||
repoVisibility: 'private' | 'public';
|
||||
}> {
|
||||
}) {
|
||||
const { integrations } = options;
|
||||
|
||||
return {
|
||||
return createTemplateAction<{
|
||||
repoUrl: string;
|
||||
description: string;
|
||||
repoVisibility: 'private' | 'public';
|
||||
}>({
|
||||
id: 'publish:bitbucket',
|
||||
schema: {
|
||||
input: {
|
||||
@@ -189,11 +202,7 @@ export function createPublishBitbucketAction(options: {
|
||||
},
|
||||
},
|
||||
async handler(ctx) {
|
||||
const {
|
||||
repoUrl,
|
||||
description,
|
||||
repoVisibility = 'private',
|
||||
} = ctx.parameters;
|
||||
const { repoUrl, description, repoVisibility = 'private' } = ctx.input;
|
||||
|
||||
const { owner, repo, host } = parseRepoUrl(repoUrl);
|
||||
|
||||
@@ -238,5 +247,5 @@ export function createPublishBitbucketAction(options: {
|
||||
ctx.output('remoteUrl', remoteUrl);
|
||||
ctx.output('repoContentsUrl', repoContentsUrl);
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@@ -20,18 +20,13 @@ import {
|
||||
ScmIntegrations,
|
||||
} from '@backstage/integration';
|
||||
import { Octokit } from '@octokit/rest';
|
||||
import { TemplateAction } from '../../types';
|
||||
import { initRepoAndPush } from '../../../stages/publish/helpers';
|
||||
import { parseRepoUrl } from './util';
|
||||
import { createTemplateAction } from '../../createTemplateAction';
|
||||
|
||||
export function createPublishGithubAction(options: {
|
||||
integrations: ScmIntegrations;
|
||||
}): TemplateAction<{
|
||||
repoUrl: string;
|
||||
description?: string;
|
||||
access?: string;
|
||||
repoVisibility: 'private' | 'internal' | 'public';
|
||||
}> {
|
||||
}) {
|
||||
const { integrations } = options;
|
||||
|
||||
const credentialsProviders = new Map(
|
||||
@@ -41,7 +36,12 @@ export function createPublishGithubAction(options: {
|
||||
}),
|
||||
);
|
||||
|
||||
return {
|
||||
return createTemplateAction<{
|
||||
repoUrl: string;
|
||||
description?: string;
|
||||
access?: string;
|
||||
repoVisibility: 'private' | 'internal' | 'public';
|
||||
}>({
|
||||
id: 'publish:github',
|
||||
schema: {
|
||||
input: {
|
||||
@@ -82,7 +82,7 @@ export function createPublishGithubAction(options: {
|
||||
},
|
||||
},
|
||||
async handler(ctx) {
|
||||
const { repoUrl, description, access, repoVisibility } = ctx.parameters;
|
||||
const { repoUrl, description, access, repoVisibility } = ctx.input;
|
||||
|
||||
const { owner, repo, host } = parseRepoUrl(repoUrl);
|
||||
|
||||
@@ -91,7 +91,7 @@ export function createPublishGithubAction(options: {
|
||||
|
||||
if (!credentialsProvider || !integrationConfig) {
|
||||
throw new InputError(
|
||||
`No matching integration configuration for host ${host}, please check your Integrations config`,
|
||||
`No matching integration configuration for host ${host}, please check your integrations config`,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -165,5 +165,5 @@ export function createPublishGithubAction(options: {
|
||||
ctx.output('remoteUrl', remoteUrl);
|
||||
ctx.output('repoContentsUrl', repoContentsUrl);
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@@ -16,20 +16,20 @@
|
||||
|
||||
import { InputError } from '@backstage/backend-common';
|
||||
import { ScmIntegrations } from '@backstage/integration';
|
||||
import { TemplateAction } from '../../types';
|
||||
import { Gitlab } from '@gitbeaker/node';
|
||||
import { initRepoAndPush } from '../../../stages/publish/helpers';
|
||||
import { parseRepoUrl } from './util';
|
||||
import { createTemplateAction } from '../../createTemplateAction';
|
||||
|
||||
export function createPublishGitlabAction(options: {
|
||||
integrations: ScmIntegrations;
|
||||
}): TemplateAction<{
|
||||
repoUrl: string;
|
||||
repoVisibility: 'private' | 'internal' | 'public';
|
||||
}> {
|
||||
}) {
|
||||
const { integrations } = options;
|
||||
|
||||
return {
|
||||
return createTemplateAction<{
|
||||
repoUrl: string;
|
||||
repoVisibility: 'private' | 'internal' | 'public';
|
||||
}>({
|
||||
id: 'publish:gitlab',
|
||||
schema: {
|
||||
input: {
|
||||
@@ -62,7 +62,7 @@ export function createPublishGitlabAction(options: {
|
||||
},
|
||||
},
|
||||
async handler(ctx) {
|
||||
const { repoUrl, repoVisibility = 'private' } = ctx.parameters;
|
||||
const { repoUrl, repoVisibility = 'private' } = ctx.input;
|
||||
|
||||
const { owner, repo, host } = parseRepoUrl(repoUrl);
|
||||
|
||||
@@ -118,5 +118,5 @@ export function createPublishGitlabAction(options: {
|
||||
ctx.output('remoteUrl', remoteUrl);
|
||||
ctx.output('repoContentsUrl', repoContentsUrl);
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// function createTemplateAction<Parameters extends ParameterBase>(
|
||||
// options: TemplateAction<Parameters>,
|
||||
// ): TemplateAction<any>;
|
||||
|
||||
import { InputBase, TemplateAction } from './types';
|
||||
|
||||
export const createTemplateAction = <Input extends InputBase>(
|
||||
templateAction: TemplateAction<Input>,
|
||||
): TemplateAction<any> => {
|
||||
// TODO(blam): Can add some more validation here to validate the action later on
|
||||
return templateAction;
|
||||
};
|
||||
@@ -16,4 +16,5 @@
|
||||
|
||||
export * from './builtin';
|
||||
export { TemplateActionRegistry } from './TemplateActionRegistry';
|
||||
export { createTemplateAction } from './createTemplateAction';
|
||||
export type { ActionContext, TemplateAction } from './types';
|
||||
|
||||
@@ -21,9 +21,9 @@ import { Schema } from 'jsonschema';
|
||||
|
||||
type PartialJsonObject = Partial<JsonObject>;
|
||||
type PartialJsonValue = PartialJsonObject | JsonValue | undefined;
|
||||
export type ParameterBase = Partial<{ [name: string]: PartialJsonValue }>;
|
||||
export type InputBase = Partial<{ [name: string]: PartialJsonValue }>;
|
||||
|
||||
export type ActionContext<Parameters extends ParameterBase> = {
|
||||
export type ActionContext<Input extends InputBase> = {
|
||||
/**
|
||||
* Base URL for the location of the task spec, typically the url of the source entity file.
|
||||
*/
|
||||
@@ -33,7 +33,7 @@ export type ActionContext<Parameters extends ParameterBase> = {
|
||||
logStream: Writable;
|
||||
|
||||
workspacePath: string;
|
||||
parameters: Parameters;
|
||||
input: Input;
|
||||
output(name: string, value: JsonValue): void;
|
||||
|
||||
/**
|
||||
@@ -42,11 +42,11 @@ export type ActionContext<Parameters extends ParameterBase> = {
|
||||
createTemporaryDirectory(): Promise<string>;
|
||||
};
|
||||
|
||||
export type TemplateAction<Parameters extends ParameterBase> = {
|
||||
export type TemplateAction<Input extends InputBase> = {
|
||||
id: string;
|
||||
schema?: {
|
||||
input?: Schema;
|
||||
output?: Schema;
|
||||
};
|
||||
handler: (ctx: ActionContext<Parameters>) => Promise<void>;
|
||||
handler: (ctx: ActionContext<Input>) => Promise<void>;
|
||||
};
|
||||
|
||||
@@ -37,7 +37,7 @@ export function registerLegacyActions(
|
||||
id: 'legacy:prepare',
|
||||
async handler(ctx) {
|
||||
ctx.logger.info('Preparing the skeleton');
|
||||
const { protocol, url } = ctx.parameters;
|
||||
const { protocol, url } = ctx.input;
|
||||
const preparer =
|
||||
protocol === 'file' ? new FilePreparer() : preparers.get(url as string);
|
||||
|
||||
@@ -53,12 +53,12 @@ export function registerLegacyActions(
|
||||
id: 'legacy:template',
|
||||
async handler(ctx) {
|
||||
ctx.logger.info('Running the templater');
|
||||
const templater = templaters.get(ctx.parameters.templater as string);
|
||||
const templater = templaters.get(ctx.input.templater as string);
|
||||
await templater.run({
|
||||
workspacePath: ctx.workspacePath,
|
||||
dockerClient,
|
||||
logStream: ctx.logStream,
|
||||
values: ctx.parameters.values as TemplaterValues,
|
||||
values: ctx.input.values as TemplaterValues,
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -66,7 +66,7 @@ export function registerLegacyActions(
|
||||
registry.register({
|
||||
id: 'legacy:publish',
|
||||
async handler(ctx) {
|
||||
const { values } = ctx.parameters;
|
||||
const { values } = ctx.input;
|
||||
if (
|
||||
typeof values !== 'object' ||
|
||||
values === null ||
|
||||
|
||||
@@ -98,7 +98,7 @@ export class TaskWorker {
|
||||
throw new Error(`Action '${step.action}' does not exist`);
|
||||
}
|
||||
|
||||
const parameters = JSON.parse(
|
||||
const input = JSON.parse(
|
||||
JSON.stringify(step.input),
|
||||
(_key, value) => {
|
||||
if (typeof value === 'string') {
|
||||
@@ -114,15 +114,13 @@ export class TaskWorker {
|
||||
);
|
||||
|
||||
if (action.schema?.input) {
|
||||
const validateResult = validateJsonSchema(
|
||||
parameters,
|
||||
action.schema,
|
||||
{ propertyName: 'parameters' },
|
||||
);
|
||||
const validateResult = validateJsonSchema(input, action.schema, {
|
||||
propertyName: 'input',
|
||||
});
|
||||
if (!validateResult.valid) {
|
||||
const errors = validateResult.errors.join(', ');
|
||||
throw new InputError(
|
||||
`Invalid parameters passed to action ${action.id}, ${errors}`,
|
||||
`Invalid input passed to action ${action.id}, ${errors}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -136,7 +134,7 @@ export class TaskWorker {
|
||||
baseUrl: task.spec.baseUrl,
|
||||
logger: taskLogger,
|
||||
logStream: stream,
|
||||
parameters,
|
||||
input,
|
||||
workspacePath,
|
||||
async createTemporaryDirectory() {
|
||||
const tmpDir = await fs.mkdtemp(
|
||||
|
||||
@@ -54,7 +54,7 @@ export function templateEntityToSpec(
|
||||
id: 'prepare',
|
||||
name: 'Prepare',
|
||||
action: 'legacy:prepare',
|
||||
parameters: {
|
||||
input: {
|
||||
protocol,
|
||||
url,
|
||||
},
|
||||
@@ -64,7 +64,7 @@ export function templateEntityToSpec(
|
||||
id: 'template',
|
||||
name: 'Template',
|
||||
action: 'legacy:template',
|
||||
parameters: {
|
||||
input: {
|
||||
templater,
|
||||
values,
|
||||
},
|
||||
@@ -74,7 +74,7 @@ export function templateEntityToSpec(
|
||||
id: 'publish',
|
||||
name: 'Publish',
|
||||
action: 'legacy:publish',
|
||||
parameters: {
|
||||
input: {
|
||||
values,
|
||||
},
|
||||
});
|
||||
@@ -83,7 +83,7 @@ export function templateEntityToSpec(
|
||||
id: 'register',
|
||||
name: 'Register',
|
||||
action: 'catalog:register',
|
||||
parameters: {
|
||||
input: {
|
||||
catalogInfoUrl: '{{ steps.publish.output.catalogInfoUrl }}',
|
||||
},
|
||||
});
|
||||
|
||||
@@ -118,7 +118,7 @@ describe('createRouter - working directory', () => {
|
||||
dockerClient: new Docker(),
|
||||
database: createDatabase(),
|
||||
catalogClient: createCatalogClient([template]),
|
||||
urlReader: mockUrlReader,
|
||||
reader: mockUrlReader,
|
||||
}),
|
||||
).rejects.toThrow('access error');
|
||||
});
|
||||
@@ -133,7 +133,7 @@ describe('createRouter - working directory', () => {
|
||||
dockerClient: new Docker(),
|
||||
database: createDatabase(),
|
||||
catalogClient: createCatalogClient([template]),
|
||||
urlReader: mockUrlReader,
|
||||
reader: mockUrlReader,
|
||||
});
|
||||
|
||||
const app = express().use(router);
|
||||
@@ -163,7 +163,7 @@ describe('createRouter - working directory', () => {
|
||||
dockerClient: new Docker(),
|
||||
database: createDatabase(),
|
||||
catalogClient: createCatalogClient([template]),
|
||||
urlReader: mockUrlReader,
|
||||
reader: mockUrlReader,
|
||||
});
|
||||
|
||||
const app = express().use(router);
|
||||
@@ -237,7 +237,7 @@ describe('createRouter', () => {
|
||||
dockerClient: new Docker(),
|
||||
database: createDatabase(),
|
||||
catalogClient: createCatalogClient([template]),
|
||||
urlReader: mockUrlReader,
|
||||
reader: mockUrlReader,
|
||||
});
|
||||
app = express().use(router);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user