diff --git a/.changeset/long-cups-exercise.md b/.changeset/long-cups-exercise.md new file mode 100644 index 0000000000..54898569fa --- /dev/null +++ b/.changeset/long-cups-exercise.md @@ -0,0 +1,52 @@ +--- +'@backstage/plugin-explore-backend': patch +--- + +Allow to provide explore tools through config instead of data in code. + +```yaml title="app-config.yaml" +explore: + tools: + - title: New Relic + description: Observability platform built to help engineers create and monitor their software + url: /newrelic + image: https://i.imgur.com/L37ikrX.jpg + tags: + - newrelic + - performance + - monitoring + - errors + - alerting + - title: CircleCI + description: Provides builds overview, detailed build info and retriggering functionality for CircleCI. + url: /circleci + image: https://miro.medium.com/max/1200/1*hkTBp22vLAqlIHkrkZHPnw.png + tags: + - circleci + - ci + - dev + # [...] +``` + +```diff title="packages/backend/src/plugins/explore.ts" +- import { ExploreTool } from '@backstage/plugin-explore-common'; +- const exploreTools: ExploreTool[] = [ +- { +- title: 'New Relic', +- description: 'Observability platform built to help engineers create and monitor their software', +- url: '/newrelic', +- image: 'https://i.imgur.com/L37ikrX.jpg', +- tags: ['newrelic', 'performance', 'monitoring', 'errors', 'alerting'], +- }, +- { +- title: 'CircleCI', +- description: 'Provides builds overview, detailed build info and retriggering functionality for CircleCI.', +- url: '/circleci', +- image: 'https://miro.medium.com/max/1200/1*hkTBp22vLAqlIHkrkZHPnw.png', +- tags: ['circleci', 'ci', 'dev'], +- }, +- ]; +- +- StaticExploreToolProvider.fromData(tools) ++ StaticExploreToolProvider.fromData(env.config) +``` diff --git a/plugins/explore-backend/README.md b/plugins/explore-backend/README.md index 86f60ae226..a7a6496fe4 100644 --- a/plugins/explore-backend/README.md +++ b/plugins/explore-backend/README.md @@ -7,14 +7,61 @@ for these tools. ## Getting started -### Install the Package +### Adding the plugin to your `packages/backend` + +#### Tools as Config + +Install dependencies + +```bash +# From your Backstage root directory +yarn add --cwd packages/backend @backstage/plugin-explore-backend +``` + +You'll need to add the plugin to the router in your `backend` package. You can +do this by creating a file called `packages/backend/src/plugins/explore.ts` with the following content: + +```ts title="packages/backend/src/plugins/explore.ts" +import { + createRouter, + StaticExploreToolProvider, +} from '@backstage/plugin-explore-backend'; +import { Router } from 'express'; +import { PluginEnvironment } from '../types'; + +export default async function createPlugin( + env: PluginEnvironment, +): Promise { + return await createRouter({ + logger: env.logger, + toolProvider: StaticExploreToolProvider.fromConfig(env.config), + }); +} +``` + +#### Tools as Code + +Install dependencies ```bash # From your Backstage root directory yarn add --cwd packages/backend @backstage/plugin-explore-backend @backstage/plugin-explore-common ``` -### Adding the plugin to your `packages/backend` +Config: + +```yaml +explore: + tools: + - title: New Relic + description: new relic plugin + url: /newrelic + image: https://i.imgur.com/L37ikrX.jpg + tags: + - newrelic + - proxy + - nerdGraph +``` You'll need to add the plugin to the router in your `backend` package. You can do this by creating a file called `packages/backend/src/plugins/explore.ts` with the following content: @@ -49,6 +96,8 @@ export default async function createPlugin( } ``` +#### Register the plugin router + With the `explore.ts` router setup in place, add the router to `packages/backend/src/index.ts`: diff --git a/plugins/explore-backend/api-report.md b/plugins/explore-backend/api-report.md index e3933e350b..b652f5515b 100644 --- a/plugins/explore-backend/api-report.md +++ b/plugins/explore-backend/api-report.md @@ -3,6 +3,7 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +import { Config } from '@backstage/config'; import { ExploreTool } from '@backstage/plugin-explore-common'; import express from 'express'; import { GetExploreToolsRequest } from '@backstage/plugin-explore-common'; @@ -30,6 +31,8 @@ export interface RouterOptions { // @public export class StaticExploreToolProvider implements ExploreToolProvider { + // (undocumented) + static fromConfig(config: Config): StaticExploreToolProvider; // (undocumented) static fromData(tools: ExploreTool[]): StaticExploreToolProvider; // (undocumented) diff --git a/plugins/explore-backend/config.d.ts b/plugins/explore-backend/config.d.ts new file mode 100644 index 0000000000..700549417a --- /dev/null +++ b/plugins/explore-backend/config.d.ts @@ -0,0 +1,31 @@ +/* + * 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 interface Config { + explore?: { + /** + * Tools to be used for the explore tool provider. + */ + tools?: Array<{ + title: string; + description?: string; + url: string; + image: string; + tags?: string[]; + lifecycle?: string; + }>; + }; +} diff --git a/plugins/explore-backend/package.json b/plugins/explore-backend/package.json index 6c08dfa2d1..d6f9f4637a 100644 --- a/plugins/explore-backend/package.json +++ b/plugins/explore-backend/package.json @@ -27,6 +27,7 @@ "@backstage/plugin-explore-common": "workspace:^", "@backstage/plugin-search-backend-module-explore": "workspace:^", "@backstage/plugin-search-common": "workspace:^", + "@backstage/types": "workspace:^", "@types/express": "*", "express": "^4.18.1", "express-promise-router": "^4.1.0", @@ -42,6 +43,8 @@ "supertest": "^6.2.4" }, "files": [ + "config.d.ts", "dist" - ] + ], + "configSchema": "config.d.ts" } diff --git a/plugins/explore-backend/src/tools/providers/StaticExploreToolProvider.test.ts b/plugins/explore-backend/src/tools/providers/StaticExploreToolProvider.test.ts index 626426eed9..1df3c6c2f9 100644 --- a/plugins/explore-backend/src/tools/providers/StaticExploreToolProvider.test.ts +++ b/plugins/explore-backend/src/tools/providers/StaticExploreToolProvider.test.ts @@ -14,7 +14,9 @@ * limitations under the License. */ +import { ConfigReader } from '@backstage/config'; import { ExploreTool } from '@backstage/plugin-explore-common'; +import { JsonObject } from '@backstage/types'; import { StaticExploreToolProvider } from './StaticExploreToolProvider'; describe('StaticExploreToolProvider', () => { @@ -40,7 +42,24 @@ describe('StaticExploreToolProvider', () => { const allTools: ExploreTool[] = [tool1, tool2, tool3]; describe('getTools', () => { - it('returns a list of all tools', async () => { + it('fromConfig returns a list of all tools', async () => { + const config = new ConfigReader({ + explore: { + tools: [ + tool1 as JsonObject, + tool2 as JsonObject, + tool3 as JsonObject, + ], + }, + }); + const provider = StaticExploreToolProvider.fromConfig(config); + + await expect(provider.getTools({})).resolves.toEqual({ + tools: allTools, + }); + }); + + it('fromData returns a list of all tools', async () => { const provider = StaticExploreToolProvider.fromData(allTools); await expect(provider.getTools({})).resolves.toEqual({ diff --git a/plugins/explore-backend/src/tools/providers/StaticExploreToolProvider.ts b/plugins/explore-backend/src/tools/providers/StaticExploreToolProvider.ts index ad8bcafada..b8f04a2099 100644 --- a/plugins/explore-backend/src/tools/providers/StaticExploreToolProvider.ts +++ b/plugins/explore-backend/src/tools/providers/StaticExploreToolProvider.ts @@ -14,6 +14,7 @@ * limitations under the License. */ +import { Config } from '@backstage/config'; import { ExploreTool, GetExploreToolsRequest, @@ -35,7 +36,22 @@ const anyOf = (prop: T | T[], matches: T[]) => export class StaticExploreToolProvider implements ExploreToolProvider { private readonly tools: ExploreTool[]; - static fromData(tools: ExploreTool[]) { + static fromConfig(config: Config): StaticExploreToolProvider { + const tools: ExploreTool[] = + config.getOptionalConfigArray('explore.tools')?.map(toolConfig => { + return { + description: toolConfig.getOptionalString('description'), + image: toolConfig.getString('image'), + lifecycle: toolConfig.getOptionalString('lifecycle'), + tags: toolConfig.getOptionalStringArray('tags'), + title: toolConfig.getString('title'), + url: toolConfig.getString('url'), + } as ExploreTool; + }) ?? []; + return this.fromData(tools); + } + + static fromData(tools: ExploreTool[]): StaticExploreToolProvider { return new StaticExploreToolProvider(tools); } diff --git a/yarn.lock b/yarn.lock index 5916fc9179..ea07bf95bc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6769,6 +6769,7 @@ __metadata: "@backstage/plugin-explore-common": "workspace:^" "@backstage/plugin-search-backend-module-explore": "workspace:^" "@backstage/plugin-search-common": "workspace:^" + "@backstage/types": "workspace:^" "@types/express": "*" "@types/supertest": ^2.0.8 express: ^4.18.1