From 6bf5faa3f2127471b15a0c03ef1d5995d3861813 Mon Sep 17 00:00:00 2001 From: blam Date: Wed, 23 Feb 2022 15:25:52 +0100 Subject: [PATCH] chore: reworking where the types are stored and where the client is created Signed-off-by: blam --- plugins/scaffolder/src/api.ts | 117 ++++++++----------------------- plugins/scaffolder/src/index.ts | 2 +- plugins/scaffolder/src/plugin.ts | 9 +-- plugins/scaffolder/src/types.ts | 84 +++++++++++++++++++++- 4 files changed, 117 insertions(+), 95 deletions(-) diff --git a/plugins/scaffolder/src/api.ts b/plugins/scaffolder/src/api.ts index 594ca74aa4..02d09a7a07 100644 --- a/plugins/scaffolder/src/api.ts +++ b/plugins/scaffolder/src/api.ts @@ -14,11 +14,7 @@ * limitations under the License. */ -import { - EntityName, - EntityRef, - parseEntityRef, -} from '@backstage/catalog-model'; +import { parseEntityRef } from '@backstage/catalog-model'; import { createApiRef, DiscoveryApi, @@ -26,11 +22,20 @@ import { } from '@backstage/core-plugin-api'; import { ResponseError } from '@backstage/errors'; import { ScmIntegrationRegistry } from '@backstage/integration'; -import { JsonObject, JsonValue, Observable } from '@backstage/types'; -import { Field, FieldValidation } from '@rjsf/core'; +import { Observable } from '@backstage/types'; import qs from 'qs'; import ObservableImpl from 'zen-observable'; -import { ListActionsResponse, ScaffolderTask, Status } from './types'; +import { + ListActionsResponse, + LogEvent, + ScaffolderApi, + TemplateParameterSchema, + ScaffolderScaffoldOptions, + ScaffolderScaffoldResponse, + ScaffolderStreamLogsOptions, + ScaffolderGetIntegrationsListOptions, + ScaffolderGetIntegrationsListResponse, +} from './types'; /** * Utility API reference for the {@link ScaffolderApi}. @@ -41,70 +46,6 @@ export const scaffolderApiRef = createApiRef({ id: 'plugin.scaffolder.service', }); -type TemplateParameterSchema = { - title: string; - steps: Array<{ - title: string; - schema: JsonObject; - }>; -}; - -export type LogEvent = { - type: 'log' | 'completion'; - body: { - message: string; - stepId?: string; - status?: Status; - }; - createdAt: string; - id: string; - taskId: string; -}; - -export type CustomField = { - name: string; - component: Field; - validation: (data: JsonValue, field: FieldValidation) => void; -}; - -/** - * An API to interact with the scaffolder backend. - * - * @public - */ -export interface ScaffolderApi { - getTemplateParameterSchema( - templateRef: EntityRef, - ): Promise; - - /** - * Executes the scaffolding of a component, given a template and its - * parameter values. - * - * @param templateName - Name of the Template entity for the scaffolder to use. New project is going to be created out of this template. - * @param values - Parameters for the template, e.g. name, description - * @param secrets - Optional secrets to pass to as the secrets parameter to the template. - */ - scaffold( - templateName: string, - values: Record, - secrets?: Record, - ): Promise; - - getTask(taskId: string): Promise; - - getIntegrationsList(options: { - allowedHosts: string[]; - }): Promise<{ type: string; title: string; host: string }[]>; - - /** - * Returns a list of all installed actions. - */ - listActions(): Promise; - - streamLogs(options: { taskId: string; after?: number }): Observable; -} - /** * An API to interact with the scaffolder backend. * @@ -128,8 +69,10 @@ export class ScaffolderClient implements ScaffolderApi { this.useLongPollingLogs = options.useLongPollingLogs ?? false; } - async getIntegrationsList(options: { allowedHosts: string[] }) { - return [ + async getIntegrationsList( + options: ScaffolderGetIntegrationsListOptions, + ): Promise { + const integrations = [ ...this.scmIntegrationsApi.azure.list(), ...this.scmIntegrationsApi.bitbucket.list(), ...this.scmIntegrationsApi.github.list(), @@ -137,10 +80,14 @@ export class ScaffolderClient implements ScaffolderApi { ] .map(c => ({ type: c.type, title: c.title, host: c.config.host })) .filter(c => options.allowedHosts.includes(c.host)); + + return { + integrations, + }; } async getTemplateParameterSchema( - templateRef: EntityRef, + templateRef: string, ): Promise { const { namespace, kind, name } = parseEntityRef(templateRef); @@ -164,15 +111,14 @@ export class ScaffolderClient implements ScaffolderApi { * Executes the scaffolding of a component, given a template and its * parameter values. * - * @param templateName - Template name for the scaffolder to use. New project is going to be created out of this template. - * @param values - Parameters for the template, e.g. name, description - * @param secrets - Optional secrets to pass to as the secrets parameter to the template. + * @param options.templateName - Template name for the scaffolder to use. New project is going to be created out of this template. + * @param options.values - Parameters for the template, e.g. name, description + * @param options.secrets - Optional secrets to pass to as the secrets parameter to the template. */ async scaffold( - templateName: string, - values: Record, - secrets: Record = {}, - ): Promise { + options: ScaffolderScaffoldOptions, + ): Promise { + const { templateName, values, secrets = {} } = options; const url = `${await this.discoveryApi.getBaseUrl('scaffolder')}/v2/tasks`; const response = await this.fetchApi.fetch(url, { method: 'POST', @@ -193,7 +139,7 @@ export class ScaffolderClient implements ScaffolderApi { } const { id } = (await response.json()) as { id: string }; - return id; + return { jobId: id }; } async getTask(taskId: string) { @@ -208,10 +154,7 @@ export class ScaffolderClient implements ScaffolderApi { return await response.json(); } - streamLogs(options: { - taskId: string; - after?: number; - }): Observable { + streamLogs(options: ScaffolderStreamLogsOptions): Observable { if (this.useLongPollingLogs) { return this.streamLogsPolling(options); } diff --git a/plugins/scaffolder/src/index.ts b/plugins/scaffolder/src/index.ts index 34091b3fea..17c48e55ac 100644 --- a/plugins/scaffolder/src/index.ts +++ b/plugins/scaffolder/src/index.ts @@ -21,7 +21,7 @@ */ export { scaffolderApiRef, ScaffolderClient } from './api'; -export type { ScaffolderApi } from './api'; +export * from './types'; export { createScaffolderFieldExtension, ScaffolderFieldExtensions, diff --git a/plugins/scaffolder/src/plugin.ts b/plugins/scaffolder/src/plugin.ts index ccf8d2ee34..c84d2bb73c 100644 --- a/plugins/scaffolder/src/plugin.ts +++ b/plugins/scaffolder/src/plugin.ts @@ -64,11 +64,12 @@ export const scaffolderPlugin = createPlugin({ }, }); +export const EntityPickerExtension = createScaffolderFieldExtension({ + component: EntityPicker, + name: 'EntityPicker', +}); export const EntityPickerFieldExtension = scaffolderPlugin.provide( - createScaffolderFieldExtension({ - component: EntityPicker, - name: 'EntityPicker', - }), + EntityPickerExtension, ); export const EntityNamePickerFieldExtension = scaffolderPlugin.provide( diff --git a/plugins/scaffolder/src/types.ts b/plugins/scaffolder/src/types.ts index 291f680710..9b65bc5e5e 100644 --- a/plugins/scaffolder/src/types.ts +++ b/plugins/scaffolder/src/types.ts @@ -13,8 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { JSONSchema } from '@backstage/catalog-model'; import { TaskSpec } from '@backstage/plugin-scaffolder-common'; +import { JsonObject, Observable } from '@backstage/types'; +import { JSONSchema7 } from 'json-schema'; export type Status = 'open' | 'processing' | 'failed' | 'completed' | 'skipped'; export type JobStatus = 'PENDING' | 'STARTED' | 'COMPLETED' | 'FAILED'; @@ -51,8 +52,8 @@ export type ListActionsResponse = Array<{ id: string; description?: string; schema?: { - input?: JSONSchema; - output?: JSONSchema; + input?: JSONSchema7; + output?: JSONSchema7; }; }>; @@ -72,3 +73,80 @@ export type TaskOutput = { } & { [key: string]: unknown; }; + +export type TemplateParameterSchema = { + title: string; + steps: Array<{ + title: string; + schema: JsonObject; + }>; +}; + +export type LogEvent = { + type: 'log' | 'completion'; + body: { + message: string; + stepId?: string; + status?: Status; + }; + createdAt: string; + id: string; + taskId: string; +}; +export interface ScaffolderScaffoldOptions { + templateName: string; + values: Record; + secrets?: Record; +} + +export interface ScaffolderScaffoldResponse { + jobId: string; +} + +export interface ScaffolderGetIntegrationsListOptions { + allowedHosts: string[]; +} + +export interface ScaffolderGetIntegrationsListResponse { + integrations: { type: string; title: string; host: string }[]; +} + +export interface ScaffolderStreamLogsOptions { + taskId: string; + after?: number; +} +/** + * An API to interact with the scaffolder backend. + * + * @public + */ +export interface ScaffolderApi { + getTemplateParameterSchema( + templateRef: string, + ): Promise; + + /** + * Executes the scaffolding of a component, given a template and its + * parameter values. + * + * @param options.templateName - Name of the Template entity for the scaffolder to use. New project is going to be created out of this template. + * @param options.values - Parameters for the template, e.g. name, description + * @param options.secrets - Optional secrets to pass to as the secrets parameter to the template. + */ + scaffold( + options: ScaffolderScaffoldOptions, + ): Promise; + + getTask(taskId: string): Promise; + + getIntegrationsList( + options: ScaffolderGetIntegrationsListOptions, + ): Promise; + + /** + * Returns a list of all installed actions. + */ + listActions(): Promise; + + streamLogs(options: ScaffolderStreamLogsOptions): Observable; +}