From ef770923df4f39c0a0dce4ef57013dfe98bd3d95 Mon Sep 17 00:00:00 2001 From: Aramis Sennyey Date: Mon, 3 Apr 2023 12:22:50 -0400 Subject: [PATCH] Lint on generate success. Move YAML file to src/schema/ Signed-off-by: Aramis Sennyey --- .changeset/cold-seahorses-greet.md | 2 +- .changeset/fresh-lions-compete.md | 2 +- .github/workflows/ci.yml | 2 +- packages/backend-openapi-utils/README.md | 4 ++-- .../src/commands/openapi/constants.ts | 18 ++++++++++++++++++ .../src/commands/openapi/generate.ts | 16 ++++++++++++---- .../repo-tools/src/commands/openapi/verify.ts | 18 ++++++++---------- packages/repo-tools/src/lib/paths.ts | 8 ++++---- .../{ => src}/schema/openapi.ts | 0 .../{ => src/schema}/openapi.yaml | 0 .../src/service/createRouter.ts | 2 +- 11 files changed, 48 insertions(+), 24 deletions(-) create mode 100644 packages/repo-tools/src/commands/openapi/constants.ts rename plugins/catalog-backend/{ => src}/schema/openapi.ts (100%) rename plugins/catalog-backend/{ => src/schema}/openapi.yaml (100%) diff --git a/.changeset/cold-seahorses-greet.md b/.changeset/cold-seahorses-greet.md index e50cdfd673..71bc5db2cc 100644 --- a/.changeset/cold-seahorses-greet.md +++ b/.changeset/cold-seahorses-greet.md @@ -2,4 +2,4 @@ '@backstage/plugin-catalog-backend': patch --- -Update `openapi.yaml` and use `ApiRouter` type from `@backstage/backend-openapi-utils` to handle automatic types from the OpenAPI spec file. +Updates and moves OpenAPI spec to `src/schema/openapi.yaml` and uses `ApiRouter` type from `@backstage/backend-openapi-utils` to handle automatic types from the OpenAPI spec file. diff --git a/.changeset/fresh-lions-compete.md b/.changeset/fresh-lions-compete.md index 76c2161c37..87f15f538d 100644 --- a/.changeset/fresh-lions-compete.md +++ b/.changeset/fresh-lions-compete.md @@ -2,4 +2,4 @@ '@backstage/repo-tools': minor --- -Adding two new commands to support OpenAPI spec writing, `schema:openapi:generate` to generate the Typescript file that `@backstage/backend-openapi-utils` needs for typing and `schema:openapi:verify` to verify that this file exists and matches your `openapi.yaml` file. +Adding two new commands to support OpenAPI spec writing, `schema:openapi:generate` to generate the Typescript file that `@backstage/backend-openapi-utils` needs for typing and `schema:openapi:verify` to verify that this file exists and matches your `src/schema/openapi.yaml` file. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3788687ab2..fb03709cce 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -92,7 +92,7 @@ jobs: - name: verify api reference run: node scripts/verify-api-reference.js - - name: verify openapi.yaml matches schema/openapi.ts files + - name: verify openapi yaml file matches generated ts file run: yarn backstage-repo-tools schema:openapi:verify - name: verify doc links diff --git a/packages/backend-openapi-utils/README.md b/packages/backend-openapi-utils/README.md index 2f624f7620..51455ccccb 100644 --- a/packages/backend-openapi-utils/README.md +++ b/packages/backend-openapi-utils/README.md @@ -8,13 +8,13 @@ This package is meant to provide a typed Express router for an OpenAPI spec. Bas ### Configuration -1. Run `yarn --cwd backstage-cli package schema:openapi:generate` to translate your `openapi.yaml` to a new Typescript file in `schema/openapi.ts`. In the case of projects that require linting + a license header, you will need to do this manually. +1. Run `yarn --cwd backstage-cli package schema:openapi:generate` to translate your `src/schema/openapi.yaml` to a new Typescript file in `src/schema/openapi.ts`. In the case of projects that require linting + a license header, you will need to do this manually. 2. In your plugin's `src/service/createRouter.ts`, ```ts import {ApiRouter} from `@backstage/backend-openapi-utils`; -import spec from '../../schema/openapi' +import spec from '../schema/openapi' ... export function createRouter(){ diff --git a/packages/repo-tools/src/commands/openapi/constants.ts b/packages/repo-tools/src/commands/openapi/constants.ts new file mode 100644 index 0000000000..7c91f423c1 --- /dev/null +++ b/packages/repo-tools/src/commands/openapi/constants.ts @@ -0,0 +1,18 @@ +/* + * Copyright 2023 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. + */ +export const YAML_SCHEMA_PATH = 'src/schema/openapi.yaml'; +export const TS_MODULE = 'src/schema/openapi'; +export const TS_SCHEMA_PATH = `${TS_MODULE}.ts`; diff --git a/packages/repo-tools/src/commands/openapi/generate.ts b/packages/repo-tools/src/commands/openapi/generate.ts index 8ce88c1dcc..fc73013765 100644 --- a/packages/repo-tools/src/commands/openapi/generate.ts +++ b/packages/repo-tools/src/commands/openapi/generate.ts @@ -19,26 +19,34 @@ import YAML from 'js-yaml'; import chalk from 'chalk'; import { resolve } from 'path'; import { runner } from './runner'; +import { TS_SCHEMA_PATH, YAML_SCHEMA_PATH } from './constants'; +import { promisify } from 'util'; +import { exec as execCb } from 'child_process'; + +const exec = promisify(execCb); async function generate( directoryPath: string, config?: { skipMissingYamlFile: boolean }, ) { const { skipMissingYamlFile } = config ?? {}; - const openapiPath = resolve(directoryPath, 'openapi.yaml'); + const openapiPath = resolve(directoryPath, YAML_SCHEMA_PATH); if (!(await fs.pathExists(openapiPath))) { if (skipMissingYamlFile) { return; } - throw new Error('Could not find openapi.yaml in root of directory.'); + throw new Error(`Could not find ${YAML_SCHEMA_PATH} in root of directory.`); } const yaml = YAML.load(await fs.readFile(openapiPath, 'utf8')); - // For now, we're not adding a header or linting after pasting. + const tsPath = resolve(directoryPath, TS_SCHEMA_PATH); + await fs.writeFile( - resolve(directoryPath, 'schema/openapi.ts'), + tsPath, `export default ${JSON.stringify(yaml, null, 2)} as const`, ); + + await exec(`yarn backstage-cli package lint --fix ${tsPath}`); } export async function bulkCommand(paths: string[] = []): Promise { diff --git a/packages/repo-tools/src/commands/openapi/verify.ts b/packages/repo-tools/src/commands/openapi/verify.ts index c45e388a07..8febe11cf5 100644 --- a/packages/repo-tools/src/commands/openapi/verify.ts +++ b/packages/repo-tools/src/commands/openapi/verify.ts @@ -23,9 +23,10 @@ import { relative as relativePath, resolve as resolvePath } from 'path'; import Parser from '@apidevtools/swagger-parser'; import { runner } from './runner'; import { paths as cliPaths } from '../../lib/paths'; +import { TS_MODULE, TS_SCHEMA_PATH, YAML_SCHEMA_PATH } from './constants'; async function verify(directoryPath: string) { - const openapiPath = join(directoryPath, 'openapi.yaml'); + const openapiPath = join(directoryPath, YAML_SCHEMA_PATH); if (!(await fs.pathExists(openapiPath))) { return; } @@ -33,30 +34,27 @@ async function verify(directoryPath: string) { const yaml = YAML.load(await fs.readFile(openapiPath, 'utf8')); await Parser.validate(cloneDeep(yaml) as any); - const schemaPath = join(directoryPath, 'schema/openapi.ts'); + const schemaPath = join(directoryPath, TS_SCHEMA_PATH); if (!(await fs.pathExists(schemaPath))) { - throw new Error('No `schema/openapi.ts` file found.'); + throw new Error(`No \`${TS_SCHEMA_PATH}\` file found.`); } - const schema = await import( - resolvePath(join(directoryPath, 'schema/openapi')) - ); + const schema = await import(resolvePath(join(directoryPath, TS_MODULE))); if (!schema.default) { - throw new Error('`schemas/openapi.ts` needs to have a default export.'); + throw new Error(`\`${TS_SCHEMA_PATH}\` needs to have a default export.`); } if (!isEqual(schema.default, yaml)) { throw new Error( - `\`openapi.yaml\` and \`schema/openapi.ts\` do not match. Please run \`yarn --cwd ${relativePath( + `\`${YAML_SCHEMA_PATH}\` and \`${TS_SCHEMA_PATH}\` do not match. Please run \`yarn --cwd ${relativePath( cliPaths.targetRoot, directoryPath, - )} schema:openapi:generate\` to regenerate \`schema/openapi.ts\`.`, + )} schema:openapi:generate\` to regenerate \`${TS_SCHEMA_PATH}\`.`, ); } } export async function bulkCommand(paths: string[] = []): Promise { - console.log(paths); const resultsList = await runner(paths, dir => verify(dir)); let failed = false; diff --git a/packages/repo-tools/src/lib/paths.ts b/packages/repo-tools/src/lib/paths.ts index 71eff3d941..73feeae21c 100644 --- a/packages/repo-tools/src/lib/paths.ts +++ b/packages/repo-tools/src/lib/paths.ts @@ -90,10 +90,10 @@ export async function getWorkspacePackagePathPatterns(): Promise< } /** - * Given a list of paths from the user or none and return the listing package directories from the - * workspace. - * @param cliPaths - * @returns + * Given a list of paths from the user, returns the listing package directories from the + * workspace. Returns all directories if no paths are given. + * @param cliPaths User given paths from CLI. + * @returns Matching package directories or all if no cli paths passed in. */ export async function getMatchingWorkspacePaths(cliPaths: string[]) { const isAllPackages = !cliPaths?.length; diff --git a/plugins/catalog-backend/schema/openapi.ts b/plugins/catalog-backend/src/schema/openapi.ts similarity index 100% rename from plugins/catalog-backend/schema/openapi.ts rename to plugins/catalog-backend/src/schema/openapi.ts diff --git a/plugins/catalog-backend/openapi.yaml b/plugins/catalog-backend/src/schema/openapi.yaml similarity index 100% rename from plugins/catalog-backend/openapi.yaml rename to plugins/catalog-backend/src/schema/openapi.yaml diff --git a/plugins/catalog-backend/src/service/createRouter.ts b/plugins/catalog-backend/src/service/createRouter.ts index 3aff802660..830e909272 100644 --- a/plugins/catalog-backend/src/service/createRouter.ts +++ b/plugins/catalog-backend/src/service/createRouter.ts @@ -51,7 +51,7 @@ import { validateRequestBody, } from './util'; import type { ApiRouter } from '@backstage/backend-openapi-utils'; -import spec from '../../schema/openapi'; +import spec from '../schema/openapi'; /** * Options used by {@link createRouter}.