From 9d9cdea1173223a6630e96d93dbc67fdf83bd119 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 30 Jan 2023 15:54:30 +0100 Subject: [PATCH] create backend-dev-utils with cli ipc client MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Fredrik Adelöw Signed-off-by: Patrik Oldsberg --- .changeset/green-adults-retire.md | 5 + packages/backend-dev-utils/.eslintrc.js | 1 + packages/backend-dev-utils/README.md | 5 + packages/backend-dev-utils/package.json | 36 ++++++ packages/backend-dev-utils/src/index.ts | 21 ++++ packages/backend-dev-utils/src/ipcClient.ts | 120 +++++++++++++++++++ packages/backend-dev-utils/src/setupTests.ts | 16 +++ yarn.lock | 8 ++ 8 files changed, 212 insertions(+) create mode 100644 .changeset/green-adults-retire.md create mode 100644 packages/backend-dev-utils/.eslintrc.js create mode 100644 packages/backend-dev-utils/README.md create mode 100644 packages/backend-dev-utils/package.json create mode 100644 packages/backend-dev-utils/src/index.ts create mode 100644 packages/backend-dev-utils/src/ipcClient.ts create mode 100644 packages/backend-dev-utils/src/setupTests.ts diff --git a/.changeset/green-adults-retire.md b/.changeset/green-adults-retire.md new file mode 100644 index 0000000000..c13e8d664f --- /dev/null +++ b/.changeset/green-adults-retire.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-dev-utils': minor +--- + +Introduced a new package for backend development utilities. Similar to how `@backstage/dev-utils` is used in the frontend. diff --git a/packages/backend-dev-utils/.eslintrc.js b/packages/backend-dev-utils/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/packages/backend-dev-utils/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/packages/backend-dev-utils/README.md b/packages/backend-dev-utils/README.md new file mode 100644 index 0000000000..8acce94cf0 --- /dev/null +++ b/packages/backend-dev-utils/README.md @@ -0,0 +1,5 @@ +# backend-dev-utils + +Welcome to the backend-dev-utils package! + +_This package is experimental._ diff --git a/packages/backend-dev-utils/package.json b/packages/backend-dev-utils/package.json new file mode 100644 index 0000000000..735185e37f --- /dev/null +++ b/packages/backend-dev-utils/package.json @@ -0,0 +1,36 @@ +{ + "name": "@backstage/backend-dev-utils", + "version": "0.0.0", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "publishConfig": { + "access": "public", + "main": "dist/index.cjs.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "node-library" + }, + "homepage": "https://backstage.io", + "repository": { + "type": "git", + "url": "https://github.com/backstage/backstage", + "directory": "packages/backend-dev-utils" + }, + "scripts": { + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "clean": "backstage-cli package clean", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack" + }, + "devDependencies": { + "@backstage/cli": "workspace:^" + }, + "files": [ + "dist" + ] +} diff --git a/packages/backend-dev-utils/src/index.ts b/packages/backend-dev-utils/src/index.ts new file mode 100644 index 0000000000..bddecad73d --- /dev/null +++ b/packages/backend-dev-utils/src/index.ts @@ -0,0 +1,21 @@ +/* + * 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. + */ + +/** + * Local development helpers for backend. + * + * @packageDocumentation + */ diff --git a/packages/backend-dev-utils/src/ipcClient.ts b/packages/backend-dev-utils/src/ipcClient.ts new file mode 100644 index 0000000000..d3fa184a3f --- /dev/null +++ b/packages/backend-dev-utils/src/ipcClient.ts @@ -0,0 +1,120 @@ +/* + * 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. + */ + +type SendMessage = Exclude; + +interface Request { + id: number; + method: string; + body: unknown; + type: string; +} + +type Response = + | { + type: string; + id: number; + body: unknown; + } + | { + type: string; + id: number; + error: Error; + }; + +const requestType = '@backstage/cli/channel/request'; +const responseType = '@backstage/cli/channel/response'; + +/** + * The client side of an IPC communication channel. + * + * @internal + */ +export class BackstageIpcClient { + #messageId = 0; + #sendMessage: SendMessage; + + /** + * Creates a new client if we're in a child process with IPC and BACKSTAGE_CLI_CHANNEL is set. + */ + static create(): BackstageIpcClient | undefined { + const sendMessage = process.send?.bind(process); + return sendMessage && process.env.BACKSTAGE_CLI_CHANNEL + ? new BackstageIpcClient(sendMessage) + : undefined; + } + + constructor(sendMessage: SendMessage) { + this.#sendMessage = sendMessage; + } + + /** + * Send a request to the parent process and wait for a response. + */ + async request( + method: string, + body: TRequestBody, + ): Promise { + return new Promise((resolve, reject) => { + const id = this.#messageId++; + + const request: Request = { + type: requestType, + id, + method, + body, + }; + + this.#sendMessage(request, (e: Error) => { + if (e) { + reject(e); + return; + } + + const timeout = setTimeout(() => { + reject(new Error('IPC request timed out')); + }, 1000); + timeout.unref(); + + const messageHandler = (response: Response) => { + if (response?.type !== responseType) { + return; + } + if (response.id !== id) { + return; + } + + if ('error' in response) { + const error = new Error(response.error.message); + if (response.error.name) { + error.name = response.error.name; + } + reject(error); + } else { + resolve(response.body as TResponseBody); + } + + clearTimeout(timeout); + process.removeListener('message', messageHandler); + }; + + process.addListener('message', messageHandler as () => void); + }); + }); + } +} + +export const ipcClient = BackstageIpcClient.create(); diff --git a/packages/backend-dev-utils/src/setupTests.ts b/packages/backend-dev-utils/src/setupTests.ts new file mode 100644 index 0000000000..4b9026cde5 --- /dev/null +++ b/packages/backend-dev-utils/src/setupTests.ts @@ -0,0 +1,16 @@ +/* + * 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 {}; diff --git a/yarn.lock b/yarn.lock index 3d809a40c8..ecd381c8f8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3519,6 +3519,14 @@ __metadata: languageName: unknown linkType: soft +"@backstage/backend-dev-utils@workspace:packages/backend-dev-utils": + version: 0.0.0-use.local + resolution: "@backstage/backend-dev-utils@workspace:packages/backend-dev-utils" + dependencies: + "@backstage/cli": "workspace:^" + languageName: unknown + linkType: soft + "@backstage/backend-plugin-api@workspace:^, @backstage/backend-plugin-api@workspace:packages/backend-plugin-api": version: 0.0.0-use.local resolution: "@backstage/backend-plugin-api@workspace:packages/backend-plugin-api"