From 29d8a188413aef0c841f75db18942f2101155c0b Mon Sep 17 00:00:00 2001 From: solimant Date: Sun, 29 Dec 2024 19:33:15 +0000 Subject: [PATCH] Fix tests Signed-off-by: solimant --- .../src/schema/response-body-validation.ts | 49 +++++++++++++---- .../src/schema/openapi.yaml | 37 ++++++++----- .../openapi/generated/apis/Api.server.ts | 7 +-- .../models/Autocomplete400Response.model.ts | 27 ++++++++++ ...TemplateParameterSchemaStepsInner.model.ts | 5 +- .../generated/models/ValidationError.model.ts | 3 +- .../models/ValidationErrorArgument.model.ts | 24 +++++++++ .../schema/openapi/generated/models/index.ts | 2 + .../src/schema/openapi/generated/router.ts | 52 ++++++++++++++----- .../src/service/router.test.ts | 22 +++++++- .../scaffolder-backend/src/service/router.ts | 14 ++--- .../openapi/generated/apis/Api.client.ts | 6 +-- .../models/Autocomplete400Response.model.ts | 27 ++++++++++ ...TemplateParameterSchemaStepsInner.model.ts | 5 +- .../generated/models/ValidationError.model.ts | 3 +- .../models/ValidationErrorArgument.model.ts | 24 +++++++++ .../schema/openapi/generated/models/index.ts | 2 + plugins/scaffolder-common/package.json | 3 +- .../src/ScaffolderClient.test.ts} | 30 ++++++----- .../scaffolder-common/src/ScaffolderClient.ts | 12 ++--- .../src/types/IdentityApi.ts | 47 +++++++++++++++++ plugins/scaffolder/package.json | 2 + yarn.lock | 14 +++-- 23 files changed, 336 insertions(+), 81 deletions(-) create mode 100644 plugins/scaffolder-backend/src/schema/openapi/generated/models/Autocomplete400Response.model.ts create mode 100644 plugins/scaffolder-backend/src/schema/openapi/generated/models/ValidationErrorArgument.model.ts create mode 100644 plugins/scaffolder-common/client/src/schema/openapi/generated/models/Autocomplete400Response.model.ts create mode 100644 plugins/scaffolder-common/client/src/schema/openapi/generated/models/ValidationErrorArgument.model.ts rename plugins/{scaffolder/src/api.test.ts => scaffolder-common/src/ScaffolderClient.test.ts} (97%) create mode 100644 plugins/scaffolder-common/src/types/IdentityApi.ts diff --git a/packages/backend-openapi-utils/src/schema/response-body-validation.ts b/packages/backend-openapi-utils/src/schema/response-body-validation.ts index 71a4512e75..79f659f0d2 100644 --- a/packages/backend-openapi-utils/src/schema/response-body-validation.ts +++ b/packages/backend-openapi-utils/src/schema/response-body-validation.ts @@ -69,16 +69,19 @@ export class ResponseBodyParser const jsonContentType = Object.keys(contentTypes).find(contentType => contentType.split(';').includes('application/json'), ); - if (!jsonContentType) { - throw new OperationError( - this.operation, - `No application/json content type found in response for status code ${statusCode}`, - ); - } else if ('$ref' in contentTypes[jsonContentType].schema) { + const eventStreamContentType = Object.keys(contentTypes).find( + contentType => contentType.split(';').includes('text/event-stream'), + ); + if (jsonContentType && '$ref' in contentTypes[jsonContentType].schema) { throw new OperationError( this.operation, 'Reference objects are not supported', ); + } else if (!jsonContentType && !eventStreamContentType) { + throw new OperationError( + this.operation, + `No valid content type found in response for status code ${statusCode}`, + ); } } } @@ -113,14 +116,20 @@ export class ResponseBodyParser const jsonContentType = Object.keys(contentTypes ?? {}).find(contentType => contentType.split(';').includes('application/json'), ); - if (!jsonContentType) { + const eventStreamContentType = Object.keys(contentTypes ?? {}).find( + contentType => contentType.split(';').includes('text/event-stream'), + ); + if (!jsonContentType && !eventStreamContentType) { throw new OperationResponseError( this.operation, response, - 'No application/json content type found in response', + 'No valid content type found in response', ); } - const schema = responseSchema.content![jsonContentType].schema; + const schema = + (jsonContentType && responseSchema.content![jsonContentType].schema) || + (eventStreamContentType && + responseSchema.content![eventStreamContentType].schema); // This is a bit of type laziness. Ideally, this would be a type-narrowing function, but I wasn't able to get the types to work. if (!schema) { throw new OperationError(this.operation, 'No schema found in response'); @@ -145,6 +154,28 @@ export class ResponseBodyParser } const validate = this.ajv.compile(schema); + + if (eventStreamContentType) { + const eventStreamBody = await response.text(); + + const jsonMatches = [...eventStreamBody.matchAll(/data:\s*(\{.*?\})/g)]; + const jsonObjects = jsonMatches.map(match => { + return match[1] as any as JsonObject; + }); + + const invalid = jsonObjects.some(jsonObject => !validate(jsonObject)); + if (invalid) { + throw new OperationParsingResponseError( + this.operation, + response, + 'Response body', + validate.errors!, + ); + } + + return undefined; + } + const jsonBody = (await response.json()) as JsonObject; const valid = validate(jsonBody); if (!valid) { diff --git a/plugins/scaffolder-backend/src/schema/openapi.yaml b/plugins/scaffolder-backend/src/schema/openapi.yaml index b1a88c5a49..c6be10aa4c 100644 --- a/plugins/scaffolder-backend/src/schema/openapi.yaml +++ b/plugins/scaffolder-backend/src/schema/openapi.yaml @@ -44,10 +44,8 @@ components: required: false allowReserved: true schema: - type: array - items: - type: integer - minimum: 0 + type: integer + minimum: 0 namespace: name: namespace in: path @@ -69,10 +67,8 @@ components: required: false allowReserved: true schema: - type: array - items: - type: integer - minimum: 0 + type: integer + minimum: 0 order: name: order in: query @@ -534,7 +530,7 @@ components: type: string content: type: string - format: byte + # format: byte executable: type: boolean symlink: @@ -869,9 +865,11 @@ components: type: object properties: title: - $ref: '#/components/schemas/JsonValue' + type: string + # $ref: '#/components/schemas/JsonValue' description: - $ref: '#/components/schemas/JsonValue' + type: string + # $ref: '#/components/schemas/JsonValue' schema: type: object # additionalProperties: {} @@ -971,7 +969,11 @@ components: name: type: string argument: - type: object + oneOf: + - type: boolean + - type: number + - type: object + - type: string stack: type: string required: @@ -1324,6 +1326,17 @@ paths: - id required: - results + '400': + description: Unsupported provider. + content: + application/json: + schema: + type: object + properties: + message: + type: string + name: + type: string parameters: - in: path name: provider diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/apis/Api.server.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/apis/Api.server.ts index d723bf2de3..2e3ea7fa3c 100644 --- a/plugins/scaffolder-backend/src/schema/openapi/generated/apis/Api.server.ts +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/apis/Api.server.ts @@ -21,6 +21,7 @@ // ****************************************************************** import { Action } from '../models/Action.model'; import { Autocomplete200Response } from '../models/Autocomplete200Response.model'; +import { Autocomplete400Response } from '../models/Autocomplete400Response.model'; import { AutocompleteRequest } from '../models/AutocompleteRequest.model'; import { CancelTask200Response } from '../models/CancelTask200Response.model'; import { DryRun200Response } from '../models/DryRun200Response.model'; @@ -43,7 +44,7 @@ export type Autocomplete = { resource: string; }; body: AutocompleteRequest; - response: Autocomplete200Response; + response: Autocomplete200Response | Autocomplete400Response; }; /** * @public @@ -93,8 +94,8 @@ export type ListActions = { export type ListTasks = { query: { createdBy?: Array; - limit?: Array; - offset?: Array; + limit?: number; + offset?: number; order?: Array; status?: Array; }; diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/Autocomplete400Response.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/Autocomplete400Response.model.ts new file mode 100644 index 0000000000..f36f47871e --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/Autocomplete400Response.model.ts @@ -0,0 +1,27 @@ +/* + * Copyright 2024 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export interface Autocomplete400Response { + message?: string; + name?: string; +} diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/TemplateParameterSchemaStepsInner.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/TemplateParameterSchemaStepsInner.model.ts index 43da448f7f..cf42ba5649 100644 --- a/plugins/scaffolder-backend/src/schema/openapi/generated/models/TemplateParameterSchemaStepsInner.model.ts +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/TemplateParameterSchemaStepsInner.model.ts @@ -17,13 +17,12 @@ // ****************************************************************** // * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * // ****************************************************************** -import { JsonValue } from '../models/JsonValue.model'; /** * @public */ export interface TemplateParameterSchemaStepsInner { - title: JsonValue; - description?: JsonValue; + title: string; + description?: string; schema: any; } diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/ValidationError.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/ValidationError.model.ts index a7c30935df..459babc8bb 100644 --- a/plugins/scaffolder-backend/src/schema/openapi/generated/models/ValidationError.model.ts +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/ValidationError.model.ts @@ -17,6 +17,7 @@ // ****************************************************************** // * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * // ****************************************************************** +import { ValidationErrorArgument } from '../models/ValidationErrorArgument.model'; import { ValidationErrorPathInner } from '../models/ValidationErrorPathInner.model'; /** @@ -30,6 +31,6 @@ export interface ValidationError { message: string; instance: any; name: string; - argument: any; + argument: ValidationErrorArgument; stack: string; } diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/ValidationErrorArgument.model.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/ValidationErrorArgument.model.ts new file mode 100644 index 0000000000..60d2a20a5c --- /dev/null +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/ValidationErrorArgument.model.ts @@ -0,0 +1,24 @@ +/* + * Copyright 2024 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export type ValidationErrorArgument = any | boolean | number | string; diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/models/index.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/models/index.ts index 41a96e63ae..7f5a2de608 100644 --- a/plugins/scaffolder-backend/src/schema/openapi/generated/models/index.ts +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/models/index.ts @@ -19,6 +19,7 @@ export * from '../models/ActionExample.model'; export * from '../models/ActionSchema.model'; export * from '../models/Autocomplete200Response.model'; export * from '../models/Autocomplete200ResponseResultsInner.model'; +export * from '../models/Autocomplete400Response.model'; export * from '../models/AutocompleteRequest.model'; export * from '../models/CancelTask200Response.model'; export * from '../models/DryRun200Response.model'; @@ -61,4 +62,5 @@ export * from '../models/TemplateInfoEntity.model'; export * from '../models/TemplateParameterSchema.model'; export * from '../models/TemplateParameterSchemaStepsInner.model'; export * from '../models/ValidationError.model'; +export * from '../models/ValidationErrorArgument.model'; export * from '../models/ValidationErrorPathInner.model'; diff --git a/plugins/scaffolder-backend/src/schema/openapi/generated/router.ts b/plugins/scaffolder-backend/src/schema/openapi/generated/router.ts index 1a94e60653..29c7d9af93 100644 --- a/plugins/scaffolder-backend/src/schema/openapi/generated/router.ts +++ b/plugins/scaffolder-backend/src/schema/openapi/generated/router.ts @@ -80,11 +80,8 @@ export const spec = { required: false, allowReserved: true, schema: { - type: 'array', - items: { - type: 'integer', - minimum: 0, - }, + type: 'integer', + minimum: 0, }, }, namespace: { @@ -112,11 +109,8 @@ export const spec = { required: false, allowReserved: true, schema: { - type: 'array', - items: { - type: 'integer', - minimum: 0, - }, + type: 'integer', + minimum: 0, }, }, order: { @@ -545,7 +539,6 @@ export const spec = { }, content: { type: 'string', - format: 'byte', }, executable: { type: 'boolean', @@ -758,10 +751,10 @@ export const spec = { type: 'object', properties: { title: { - $ref: '#/components/schemas/JsonValue', + type: 'string', }, description: { - $ref: '#/components/schemas/JsonValue', + type: 'string', }, schema: { type: 'object', @@ -805,7 +798,20 @@ export const spec = { type: 'string', }, argument: { - type: 'object', + oneOf: [ + { + type: 'boolean', + }, + { + type: 'number', + }, + { + type: 'object', + }, + { + type: 'string', + }, + ], }, stack: { type: 'string', @@ -1352,6 +1358,24 @@ export const spec = { }, }, }, + '400': { + description: 'Unsupported provider.', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + message: { + type: 'string', + }, + name: { + type: 'string', + }, + }, + }, + }, + }, + }, }, parameters: [ { diff --git a/plugins/scaffolder-backend/src/service/router.test.ts b/plugins/scaffolder-backend/src/service/router.test.ts index a938abe611..38fbbea533 100644 --- a/plugins/scaffolder-backend/src/service/router.test.ts +++ b/plugins/scaffolder-backend/src/service/router.test.ts @@ -16,6 +16,7 @@ import { DatabaseManager } from '@backstage/backend-defaults/database'; import { ConfigReader } from '@backstage/config'; +import express from 'express'; import request from 'supertest'; import ObservableImpl from 'zen-observable'; @@ -65,6 +66,24 @@ import { import { createDefaultFilters } from '../lib/templating/filters/createDefaultFilters'; import { createRouter } from './router'; import { DatabaseTaskStore } from '../scaffolder/tasks/DatabaseTaskStore'; +import { Server } from 'http'; +import { wrapServer } from '@backstage/backend-openapi-utils/testUtils'; + +const mockAccess = jest.fn(); + +jest.mock('fs-extra', () => ({ + ...jest.requireActual('fs-extra'), + access: (...args: any[]) => mockAccess(...args), + promises: { + access: (...args: any[]) => mockAccess(...args), + }, + constants: { + F_OK: 0, + W_OK: 1, + }, + mkdir: jest.fn(), + remove: jest.fn(), +})); function createDatabase(): DatabaseService { return DatabaseManager.fromConfig( @@ -245,7 +264,8 @@ const createTestRouter = async ( }); router.use(mockErrorHandler()); - return { router, logger, taskBroker, permissions, catalog }; + const app = await wrapServer(express().use(router)); + return { router: app, logger, taskBroker, permissions, catalog }; }; describe('scaffolder router', () => { diff --git a/plugins/scaffolder-backend/src/service/router.ts b/plugins/scaffolder-backend/src/service/router.ts index 19dfd8274d..263401f3af 100644 --- a/plugins/scaffolder-backend/src/service/router.ts +++ b/plugins/scaffolder-backend/src/service/router.ts @@ -102,7 +102,6 @@ import { findTemplate, getEntityBaseUrl, getWorkingDirectory, - parseNumberParam, parseStringsParam, } from './helpers'; @@ -404,8 +403,10 @@ export async function createRouter( description: template.metadata.description, 'ui:options': template.metadata['ui:options'], steps: parameters.map(schema => ({ - title: schema.title ?? 'Please enter the following information', - description: schema.description, + title: + (schema.title as string) ?? + 'Please enter the following information', + description: schema.description as string, schema, })), EXPERIMENTAL_formDecorators: @@ -587,8 +588,7 @@ export async function createRouter( }; }); - const limit = parseNumberParam(req.query.limit, 'limit'); - const offset = parseNumberParam(req.query.offset, 'offset'); + const { limit, offset } = req.query; const taskPermissionFilters = await getAuthorizeConditions({ credentials: credentials, @@ -604,8 +604,8 @@ export async function createRouter( }, order, pagination: { - limit: limit ? limit[0] : undefined, - offset: offset ? offset[0] : undefined, + limit, + offset, }, permissionFilters: taskPermissionFilters, }); diff --git a/plugins/scaffolder-common/client/src/schema/openapi/generated/apis/Api.client.ts b/plugins/scaffolder-common/client/src/schema/openapi/generated/apis/Api.client.ts index ef188b6a4d..600ae7bc86 100644 --- a/plugins/scaffolder-common/client/src/schema/openapi/generated/apis/Api.client.ts +++ b/plugins/scaffolder-common/client/src/schema/openapi/generated/apis/Api.client.ts @@ -105,8 +105,8 @@ export type ListActions = {}; export type ListTasks = { query: { createdBy?: Array; - limit?: Array; - offset?: Array; + limit?: number; + offset?: number; order?: Array; status?: Array; }; @@ -339,7 +339,7 @@ export class DefaultApiClient { ): Promise> { const baseUrl = await this.discoveryApi.getBaseUrl(pluginId); - const uriTemplate = `/v2/tasks{?createdBy*,limit*,offset*,order*,status*}`; + const uriTemplate = `/v2/tasks{?createdBy*,limit,offset,order*,status*}`; const uri = parser.parse(uriTemplate).expand({ ...request.query, diff --git a/plugins/scaffolder-common/client/src/schema/openapi/generated/models/Autocomplete400Response.model.ts b/plugins/scaffolder-common/client/src/schema/openapi/generated/models/Autocomplete400Response.model.ts new file mode 100644 index 0000000000..f36f47871e --- /dev/null +++ b/plugins/scaffolder-common/client/src/schema/openapi/generated/models/Autocomplete400Response.model.ts @@ -0,0 +1,27 @@ +/* + * Copyright 2024 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export interface Autocomplete400Response { + message?: string; + name?: string; +} diff --git a/plugins/scaffolder-common/client/src/schema/openapi/generated/models/TemplateParameterSchemaStepsInner.model.ts b/plugins/scaffolder-common/client/src/schema/openapi/generated/models/TemplateParameterSchemaStepsInner.model.ts index 43da448f7f..cf42ba5649 100644 --- a/plugins/scaffolder-common/client/src/schema/openapi/generated/models/TemplateParameterSchemaStepsInner.model.ts +++ b/plugins/scaffolder-common/client/src/schema/openapi/generated/models/TemplateParameterSchemaStepsInner.model.ts @@ -17,13 +17,12 @@ // ****************************************************************** // * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * // ****************************************************************** -import { JsonValue } from '../models/JsonValue.model'; /** * @public */ export interface TemplateParameterSchemaStepsInner { - title: JsonValue; - description?: JsonValue; + title: string; + description?: string; schema: any; } diff --git a/plugins/scaffolder-common/client/src/schema/openapi/generated/models/ValidationError.model.ts b/plugins/scaffolder-common/client/src/schema/openapi/generated/models/ValidationError.model.ts index a7c30935df..459babc8bb 100644 --- a/plugins/scaffolder-common/client/src/schema/openapi/generated/models/ValidationError.model.ts +++ b/plugins/scaffolder-common/client/src/schema/openapi/generated/models/ValidationError.model.ts @@ -17,6 +17,7 @@ // ****************************************************************** // * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * // ****************************************************************** +import { ValidationErrorArgument } from '../models/ValidationErrorArgument.model'; import { ValidationErrorPathInner } from '../models/ValidationErrorPathInner.model'; /** @@ -30,6 +31,6 @@ export interface ValidationError { message: string; instance: any; name: string; - argument: any; + argument: ValidationErrorArgument; stack: string; } diff --git a/plugins/scaffolder-common/client/src/schema/openapi/generated/models/ValidationErrorArgument.model.ts b/plugins/scaffolder-common/client/src/schema/openapi/generated/models/ValidationErrorArgument.model.ts new file mode 100644 index 0000000000..60d2a20a5c --- /dev/null +++ b/plugins/scaffolder-common/client/src/schema/openapi/generated/models/ValidationErrorArgument.model.ts @@ -0,0 +1,24 @@ +/* + * Copyright 2024 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export type ValidationErrorArgument = any | boolean | number | string; diff --git a/plugins/scaffolder-common/client/src/schema/openapi/generated/models/index.ts b/plugins/scaffolder-common/client/src/schema/openapi/generated/models/index.ts index 41a96e63ae..7f5a2de608 100644 --- a/plugins/scaffolder-common/client/src/schema/openapi/generated/models/index.ts +++ b/plugins/scaffolder-common/client/src/schema/openapi/generated/models/index.ts @@ -19,6 +19,7 @@ export * from '../models/ActionExample.model'; export * from '../models/ActionSchema.model'; export * from '../models/Autocomplete200Response.model'; export * from '../models/Autocomplete200ResponseResultsInner.model'; +export * from '../models/Autocomplete400Response.model'; export * from '../models/AutocompleteRequest.model'; export * from '../models/CancelTask200Response.model'; export * from '../models/DryRun200Response.model'; @@ -61,4 +62,5 @@ export * from '../models/TemplateInfoEntity.model'; export * from '../models/TemplateParameterSchema.model'; export * from '../models/TemplateParameterSchemaStepsInner.model'; export * from '../models/ValidationError.model'; +export * from '../models/ValidationErrorArgument.model'; export * from '../models/ValidationErrorPathInner.model'; diff --git a/plugins/scaffolder-common/package.json b/plugins/scaffolder-common/package.json index 4fb33b8156..aa7a86ced6 100644 --- a/plugins/scaffolder-common/package.json +++ b/plugins/scaffolder-common/package.json @@ -61,7 +61,6 @@ }, "dependencies": { "@backstage/catalog-model": "workspace:^", - "@backstage/core-plugin-api": "workspace:^", "@backstage/errors": "workspace:^", "@backstage/integration": "workspace:^", "@backstage/plugin-permission-common": "workspace:^", @@ -73,7 +72,9 @@ }, "devDependencies": { "@backstage/cli": "workspace:^", + "@backstage/test-utils": "workspace:^", "cross-fetch": "^4.0.0", + "msw": "^1.0.0", "uri-template": "^2.0.0" } } diff --git a/plugins/scaffolder/src/api.test.ts b/plugins/scaffolder-common/src/ScaffolderClient.test.ts similarity index 97% rename from plugins/scaffolder/src/api.test.ts rename to plugins/scaffolder-common/src/ScaffolderClient.test.ts index 1df2dacb17..03064d7086 100644 --- a/plugins/scaffolder/src/api.test.ts +++ b/plugins/scaffolder-common/src/ScaffolderClient.test.ts @@ -14,12 +14,15 @@ * limitations under the License. */ -import { ConfigReader } from '@backstage/core-app-api'; import { ScmIntegrations } from '@backstage/integration'; -import { MockFetchApi, registerMswTestHooks } from '@backstage/test-utils'; +import { + MockFetchApi, + mockApis, + registerMswTestHooks, +} from '@backstage/test-utils'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; -import { ScaffolderClient } from './api'; +import { ScaffolderClient } from './ScaffolderClient'; import { fetchEventSource } from '@microsoft/fetch-event-source'; jest.mock('@microsoft/fetch-event-source'); @@ -31,6 +34,17 @@ const server = setupServer(); describe('api', () => { registerMswTestHooks(server); + const githubIntegrationConfig = mockApis.config({ + data: { + integrations: { + github: [ + { + host: 'hello.com', + }, + ], + }, + }, + }); const mockBaseUrl = 'http://backstage/api'; const discoveryApi = { getBaseUrl: async () => mockBaseUrl }; @@ -43,15 +57,7 @@ describe('api', () => { }; const scmIntegrationsApi = ScmIntegrations.fromConfig( - new ConfigReader({ - integrations: { - github: [ - { - host: 'hello.com', - }, - ], - }, - }), + githubIntegrationConfig, ); let apiClient: ScaffolderClient; diff --git a/plugins/scaffolder-common/src/ScaffolderClient.ts b/plugins/scaffolder-common/src/ScaffolderClient.ts index 44973ca569..2a178bf7e7 100644 --- a/plugins/scaffolder-common/src/ScaffolderClient.ts +++ b/plugins/scaffolder-common/src/ScaffolderClient.ts @@ -15,11 +15,6 @@ */ import { parseEntityRef } from '@backstage/catalog-model'; -import { - DiscoveryApi, - FetchApi, - IdentityApi, -} from '@backstage/core-plugin-api'; import { ResponseError } from '@backstage/errors'; import { ScmIntegrationRegistry } from '@backstage/integration'; import { Observable } from '@backstage/types'; @@ -50,6 +45,9 @@ import { TaskStatus, TypedResponse, } from '../client/src/schema/openapi'; +import { DiscoveryApi } from '../client/src/schema/openapi/generated/types/discovery'; +import { FetchApi } from '../client/src/schema/openapi/generated/types/fetch'; +import { IdentityApi } from './types/IdentityApi'; /** * An API to interact with the scaffolder backend. @@ -106,8 +104,8 @@ export class ScaffolderClient implements ScaffolderApi { request.filterByOwnership === 'owned' ? [userEntityRef] : undefined, - limit: request.limit ? [request.limit] : undefined, - offset: request.offset ? [request.offset] : undefined, + limit: request.limit, + offset: request.offset, }, }, options, diff --git a/plugins/scaffolder-common/src/types/IdentityApi.ts b/plugins/scaffolder-common/src/types/IdentityApi.ts new file mode 100644 index 0000000000..5bc8e2401a --- /dev/null +++ b/plugins/scaffolder-common/src/types/IdentityApi.ts @@ -0,0 +1,47 @@ +/* + * Copyright 2020 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. + */ + +/** + * This is a copy of the BackstageUserIdentity, to avoid importing core-plugin-api. + */ +type BackstageUserIdentity = { + /** + * The type of identity that this structure represents. In the frontend app + * this will currently always be 'user'. + */ + type: 'user'; + + /** + * The entityRef of the user in the catalog. + * For example User:default/sandra + */ + userEntityRef: string; + + /** + * The user and group entities that the user claims ownership through + */ + ownershipEntityRefs: string[]; +}; + +/** + * This is a partial copy of the IdentityApi, to avoid importing core-plugin-api. + */ +export type IdentityApi = { + /** + * User identity information within Backstage. + */ + getBackstageIdentity(): Promise; +}; diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index 1b547762ef..3c3e811696 100644 --- a/plugins/scaffolder/package.json +++ b/plugins/scaffolder/package.json @@ -87,10 +87,12 @@ "git-url-parse": "^15.0.0", "humanize-duration": "^3.25.1", "idb-keyval": "5.1.5", + "json-schema": "^0.4.0", "json-schema-library": "^9.0.0", "jszip": "^3.10.1", "lodash": "^4.17.21", "luxon": "^3.0.0", + "qs": "^6.9.4", "react-resizable": "^3.0.5", "react-use": "^17.2.4", "react-window": "^1.8.10", diff --git a/yarn.lock b/yarn.lock index 855748a4e4..34a11b612c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7394,8 +7394,18 @@ __metadata: dependencies: "@backstage/catalog-model": "workspace:^" "@backstage/cli": "workspace:^" + "@backstage/errors": "workspace:^" + "@backstage/integration": "workspace:^" "@backstage/plugin-permission-common": "workspace:^" + "@backstage/test-utils": "workspace:^" "@backstage/types": "workspace:^" + "@microsoft/fetch-event-source": "npm:^2.0.1" + cross-fetch: "npm:^4.0.0" + json-schema: "npm:^0.4.0" + msw: "npm:^1.0.0" + qs: "npm:^6.9.4" + uri-template: "npm:^2.0.0" + zen-observable: "npm:^0.10.0" languageName: unknown linkType: soft @@ -7536,9 +7546,7 @@ __metadata: "@backstage/core-components": "workspace:^" "@backstage/core-plugin-api": "workspace:^" "@backstage/dev-utils": "workspace:^" - "@backstage/errors": "workspace:^" "@backstage/frontend-plugin-api": "workspace:^" - "@backstage/integration": "workspace:^" "@backstage/integration-react": "workspace:^" "@backstage/plugin-catalog": "workspace:^" "@backstage/plugin-catalog-common": "workspace:^" @@ -7555,7 +7563,6 @@ __metadata: "@material-ui/core": "npm:^4.12.2" "@material-ui/icons": "npm:^4.9.1" "@material-ui/lab": "npm:4.0.0-alpha.61" - "@microsoft/fetch-event-source": "npm:^2.0.1" "@react-hookz/web": "npm:^24.0.0" "@rjsf/core": "npm:5.23.2" "@rjsf/material-ui": "npm:5.23.2" @@ -7590,7 +7597,6 @@ __metadata: react-window: "npm:^1.8.10" swr: "npm:^2.0.0" yaml: "npm:^2.0.0" - zen-observable: "npm:^0.10.0" zod: "npm:^3.22.4" zod-to-json-schema: "npm:^3.20.4" peerDependencies: