From f0de7895f9c05d603ce90f709e9dabe82134d227 Mon Sep 17 00:00:00 2001 From: Dominik Pfaffenbauer Date: Mon, 9 Jan 2023 16:29:59 +0100 Subject: [PATCH 01/38] Add Scaffolder Sentry Plugin Signed-off-by: Dominik Pfaffenbauer --- .../.eslintrc.js | 1 + .../README.md | 160 ++++++++++++++++++ .../package.json | 48 ++++++ .../src/actions/createProject.ts | 122 +++++++++++++ .../src/index.ts | 17 ++ 5 files changed, 348 insertions(+) create mode 100644 plugins/scaffolder-backend-module-sentry/.eslintrc.js create mode 100644 plugins/scaffolder-backend-module-sentry/README.md create mode 100644 plugins/scaffolder-backend-module-sentry/package.json create mode 100644 plugins/scaffolder-backend-module-sentry/src/actions/createProject.ts create mode 100644 plugins/scaffolder-backend-module-sentry/src/index.ts diff --git a/plugins/scaffolder-backend-module-sentry/.eslintrc.js b/plugins/scaffolder-backend-module-sentry/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/scaffolder-backend-module-sentry/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/scaffolder-backend-module-sentry/README.md b/plugins/scaffolder-backend-module-sentry/README.md new file mode 100644 index 0000000000..cbab253bd9 --- /dev/null +++ b/plugins/scaffolder-backend-module-sentry/README.md @@ -0,0 +1,160 @@ +# scaffolder-backend-module-sentry + +Welcome to the Setnry Module for Scaffolder. + +Here you can find all Sentry related features to imrpove your scaffolder: + +## Getting started + +You need to configure the action in your ackend: + +## From your Backstage root directory + +```bash +# From your Backstage root directory +yarn add --cwd packages/backend @backstage/plugin-scaffolder-backend-module-sentry +``` + +Configure the action (you can check +the [docs](https://backstage.io/docs/features/software-templates/writing-custom-actions#registering-custom-actions) to +see all options): + +```typescript +const actions = [ + createSentryCreateProjectAction({ + integrations, + reader: env.reader, + containerRunner, + }), +]; + +return await createRouter({ + containerRunner, + catalogClient, + actions, + logger: env.logger, + config: env.config, + database: env.database, + reader: env.reader, +}); +``` + +You need to define your Sentry API Token in your `app-config.yaml`: + +```yaml +scaffolder: + sentry: + token: ${SENTRY_TOKEN} +``` + +After that you can use the action in your template: + +```yaml +apiVersion: scaffolder.backstage.io/v1beta3 +kind: Template +metadata: + name: sentry-demo + title: Sentry template + description: scaffolder sentry app +spec: + owner: backstage/techdocs-core + type: service + + parameters: + - title: Fill in some steps + required: + - name + - owner + properties: + name: + title: Name + type: string + description: Unique name of the component + ui:autofocus: true + ui:options: + rows: 5 + owner: + title: Owner + type: string + description: Owner of the component + ui:field: OwnerPicker + ui:options: + catalogFilter: + kind: Group + system: + title: System + type: string + description: System of the component + ui:field: EntityPicker + ui:options: + catalogFilter: + kind: System + defaultKind: System + + - title: Choose a location + required: + - repoUrl + - dryRun + properties: + repoUrl: + title: Repository Location + type: string + ui:field: RepoUrlPicker + ui:options: + allowedHosts: + - github.com + dryRun: + title: Only perform a dry run, don't publish anything + type: boolean + default: false + + steps: + - id: fetch + name: Fetch + action: fetch:template + input: + url: https://github.com/TEMPLATE + values: + name: ${{ parameters.name }} + + - id: create-sentry-project + if: ${{ parameters.dryRun !== true }} + name: Create Sentry Project + action: sentry:create-project + input: + organizationSlug: ORG-SLUG + teamSlug: TEAM-SLUG + name: ${{ parameters.name }} + + - id: publish + if: ${{ parameters.dryRun !== true }} + name: Publish + action: publish:github + input: + allowedHosts: + - github.com + description: This is ${{ parameters.name }} + repoUrl: ${{ parameters.repoUrl }} + + - id: register + if: ${{ parameters.dryRun !== true }} + name: Register + action: catalog:register + input: + repoContentsUrl: ${{ steps['publish'].output.repoContentsUrl }} + catalogInfoPath: '/catalog-info.yaml' + + - name: Results + if: ${{ parameters.dryRun }} + action: debug:log + input: + listWorkspace: true + + output: + links: + - title: Repository + url: ${{ steps['publish'].output.remoteUrl }} + - title: Open in catalog + icon: catalog + entityRef: ${{ steps['register'].output.entityRef }} +``` diff --git a/plugins/scaffolder-backend-module-sentry/package.json b/plugins/scaffolder-backend-module-sentry/package.json new file mode 100644 index 0000000000..8eaf5c398d --- /dev/null +++ b/plugins/scaffolder-backend-module-sentry/package.json @@ -0,0 +1,48 @@ +{ + "name": "@backstage/plugin-scaffolder-backend-module-sentry", + "version": "0.1.0", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "publishConfig": { + "access": "public", + "main": "dist/index.esm.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "frontend-plugin" + }, + "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" + }, + "dependencies": { + "@backstage/config": "workspace:^", + "@backstage/errors": "workspace:^", + "@backstage/integration": "workspace:^", + "@backstage/plugin-scaffolder-backend": "workspace:^" + }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + }, + "devDependencies": { + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", + "@testing-library/jest-dom": "^5.10.1", + "@testing-library/react": "^12.1.3", + "@testing-library/user-event": "^14.0.0", + "@types/node": "*", + "cross-fetch": "^3.1.5", + "msw": "^0.49.0" + }, + "files": [ + "dist" + ] +} diff --git a/plugins/scaffolder-backend-module-sentry/src/actions/createProject.ts b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.ts new file mode 100644 index 0000000000..a3457ae159 --- /dev/null +++ b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.ts @@ -0,0 +1,122 @@ +/* + * Copyright 2021 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. + */ + +import { createTemplateAction } from '@backstage/plugin-scaffolder-backend'; +import { InputError } from '@backstage/errors'; +import { Config } from '@backstage/config'; + +/** + * Creates the `sentry:craete-project` Scaffolder action. + * + * @remarks + * + * See {@link https://backstage.io/docs/features/software-templates/writing-custom-actions}. + * + * @param options - Configuration of the Sentry API. + * @public + */ +export function createSentryCreateProjectAction(options: { config: Config }) { + const { config } = options; + + return createTemplateAction<{ + organizationSlug: string; + teamSlug: string; + name: string; + slug: string; + authToken?: string; + }>({ + id: 'sentry:create-project', + schema: { + input: { + required: ['organizationSlug', 'teamSlug', 'name'], + type: 'object', + properties: { + organizationSlug: { + title: 'The slug of the organization the team belongs to', + type: 'string', + }, + teamSlug: { + title: 'The slug of the team to create a new project for', + type: 'string', + }, + name: { + title: 'The name for the new project', + type: 'string', + }, + slug: { + title: + 'Optional slug for the new project. If not provided a slug is generated from the name', + type: 'string', + }, + authToken: { + title: + 'authenticate via bearer auth token. Requires scope: project:write', + type: 'string', + }, + }, + }, + }, + async handler(ctx) { + const { organizationSlug, teamSlug, name, slug, authToken } = ctx.input; + + const body: any = { + name: name, + }; + + if (slug) { + body.slug = slug; + } + + const token = authToken + ? authToken + : config.getOptionalString('scaffolder.sentry.token'); + + if (!token) { + throw new InputError(`No valid sentry token given`); + } + + const response = await fetch( + `https://sentry.io/api/0/teams/${organizationSlug}/${teamSlug}/projects/`, + { + method: 'POST', + headers: { + Authorization: `Bearer ${token}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify(body), + }, + ); + + const contentType = response.headers.get('content-type'); + + if (contentType !== 'application/json') { + throw new InputError( + `Unexpected Sentry Response Type: ${await response.text()}`, + ); + } + + const code = response.status; + const result = await response.json(); + + if (code !== 201) { + throw new InputError(`Sentry Response was: ${await result.detail}`); + } + + ctx.output('id', result.id); + ctx.output('result', result); + }, + }); +} diff --git a/plugins/scaffolder-backend-module-sentry/src/index.ts b/plugins/scaffolder-backend-module-sentry/src/index.ts new file mode 100644 index 0000000000..f6c0820874 --- /dev/null +++ b/plugins/scaffolder-backend-module-sentry/src/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2021 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 { createSentryCreateProjectAction } from './actions/createProject'; From 4070a59c93a0bea334aa9fea511d7cd573b9ebd5 Mon Sep 17 00:00:00 2001 From: Dominik Pfaffenbauer Date: Mon, 9 Jan 2023 16:40:53 +0100 Subject: [PATCH 02/38] add yarn.lock Signed-off-by: Dominik Pfaffenbauer --- yarn.lock | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/yarn.lock b/yarn.lock index 588d41c776..0062c90d30 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7359,6 +7359,29 @@ __metadata: languageName: unknown linkType: soft +"@backstage/plugin-scaffolder-backend-module-sentry@workspace:plugins/scaffolder-backend-module-sentry": + version: 0.0.0-use.local + resolution: "@backstage/plugin-scaffolder-backend-module-sentry@workspace:plugins/scaffolder-backend-module-sentry" + dependencies: + "@backstage/cli": "workspace:^" + "@backstage/config": "workspace:^" + "@backstage/core-app-api": "workspace:^" + "@backstage/dev-utils": "workspace:^" + "@backstage/errors": "workspace:^" + "@backstage/integration": "workspace:^" + "@backstage/plugin-scaffolder-backend": "workspace:^" + "@backstage/test-utils": "workspace:^" + "@testing-library/jest-dom": ^5.10.1 + "@testing-library/react": ^12.1.3 + "@testing-library/user-event": ^14.0.0 + "@types/node": "*" + cross-fetch: ^3.1.5 + msw: ^0.49.0 + peerDependencies: + react: ^16.13.1 || ^17.0.0 + languageName: unknown + linkType: soft + "@backstage/plugin-scaffolder-backend-module-yeoman@workspace:plugins/scaffolder-backend-module-yeoman": version: 0.0.0-use.local resolution: "@backstage/plugin-scaffolder-backend-module-yeoman@workspace:plugins/scaffolder-backend-module-yeoman" From 66ff367af6e24f6cbe0324fb9eb1e6059c8b7228 Mon Sep 17 00:00:00 2001 From: Dominik Pfaffenbauer Date: Mon, 9 Jan 2023 16:42:23 +0100 Subject: [PATCH 03/38] add changeset Signed-off-by: Dominik Pfaffenbauer --- .changeset/olive-actors-beam.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/olive-actors-beam.md diff --git a/.changeset/olive-actors-beam.md b/.changeset/olive-actors-beam.md new file mode 100644 index 0000000000..940502bc8d --- /dev/null +++ b/.changeset/olive-actors-beam.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend-module-sentry': minor +--- + +Add Sentry "Create Project" Scaffolder as new package From b6d6350256c535121f53c963c436a7de0dd59f34 Mon Sep 17 00:00:00 2001 From: Dominik Pfaffenbauer Date: Mon, 9 Jan 2023 16:56:58 +0100 Subject: [PATCH 04/38] Doc Spell Issues Signed-off-by: Dominik Pfaffenbauer --- plugins/scaffolder-backend-module-sentry/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/scaffolder-backend-module-sentry/README.md b/plugins/scaffolder-backend-module-sentry/README.md index cbab253bd9..14751185c4 100644 --- a/plugins/scaffolder-backend-module-sentry/README.md +++ b/plugins/scaffolder-backend-module-sentry/README.md @@ -1,12 +1,12 @@ # scaffolder-backend-module-sentry -Welcome to the Setnry Module for Scaffolder. +Welcome to the Sentry Module for Scaffolder. -Here you can find all Sentry related features to imrpove your scaffolder: +Here you can find all Sentry related features to improve your scaffolder: ## Getting started -You need to configure the action in your ackend: +You need to configure the action in your backend: ## From your Backstage root directory From 599e00b9884aa86f198ad4529bb908013b93d1d1 Mon Sep 17 00:00:00 2001 From: Dominik Pfaffenbauer Date: Mon, 9 Jan 2023 17:10:39 +0100 Subject: [PATCH 05/38] Add API Report Signed-off-by: Dominik Pfaffenbauer --- .../api-report.md | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 plugins/scaffolder-backend-module-sentry/api-report.md diff --git a/plugins/scaffolder-backend-module-sentry/api-report.md b/plugins/scaffolder-backend-module-sentry/api-report.md new file mode 100644 index 0000000000..a72e8a1524 --- /dev/null +++ b/plugins/scaffolder-backend-module-sentry/api-report.md @@ -0,0 +1,21 @@ +## API Report File for "@backstage/plugin-scaffolder-backend-module-sentry" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { Config } from '@backstage/config'; +import { TemplateAction } from '@backstage/plugin-scaffolder-backend'; + +// @public +export function createSentryCreateProjectAction(options: { + config: Config; +}): TemplateAction<{ + organizationSlug: string; + teamSlug: string; + name: string; + slug: string; + authToken?: string | undefined; +}>; + +// (No @packageDocumentation comment for this package) +``` From 44c18b4d3f0cfb110c06f0a0903c047fbd7a1cc0 Mon Sep 17 00:00:00 2001 From: Jussi Hallila Date: Tue, 10 Jan 2023 13:40:38 +0100 Subject: [PATCH 06/38] Expose optional persistenceContext on TechInsights construction This enables integrators to provide their own database implementations for fact handling if something more suitable than Postgres/SQlite is needed. Signed-off-by: Jussi Hallila --- .changeset/rude-pumas-draw.md | 5 +++ plugins/tech-insights-backend/api-report.md | 41 +++++++++++++++++++ plugins/tech-insights-backend/src/index.ts | 1 + .../persistence/TechInsightsDatabase.ts | 5 +++ .../src/service/techInsightsContextBuilder.ts | 14 +++++-- 5 files changed, 63 insertions(+), 3 deletions(-) create mode 100644 .changeset/rude-pumas-draw.md diff --git a/.changeset/rude-pumas-draw.md b/.changeset/rude-pumas-draw.md new file mode 100644 index 0000000000..df3592ece8 --- /dev/null +++ b/.changeset/rude-pumas-draw.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-tech-insights-backend': patch +--- + +Expose optional persistenceContext on TechInsights construction to enable integrators to provide their own database implementations for fact handling. diff --git a/plugins/tech-insights-backend/api-report.md b/plugins/tech-insights-backend/api-report.md index 8dc8efbb24..faca4a615c 100644 --- a/plugins/tech-insights-backend/api-report.md +++ b/plugins/tech-insights-backend/api-report.md @@ -5,6 +5,7 @@ ```ts import { CheckResult } from '@backstage/plugin-tech-insights-common'; import { Config } from '@backstage/config'; +import { DateTime } from 'luxon'; import { Duration } from 'luxon'; import express from 'express'; import { FactChecker } from '@backstage/plugin-tech-insights-node'; @@ -13,12 +14,16 @@ import { FactLifecycle } from '@backstage/plugin-tech-insights-node'; import { FactRetriever } from '@backstage/plugin-tech-insights-node'; import { FactRetrieverRegistration } from '@backstage/plugin-tech-insights-node'; import { FactSchema } from '@backstage/plugin-tech-insights-node'; +import { FactSchemaDefinition } from '@backstage/plugin-tech-insights-node'; +import { FlatTechInsightFact } from '@backstage/plugin-tech-insights-node'; import { HumanDuration } from '@backstage/types'; +import { Knex } from 'knex'; import { Logger } from 'winston'; import { PluginDatabaseManager } from '@backstage/backend-common'; import { PluginEndpointDiscovery } from '@backstage/backend-common'; import { PluginTaskScheduler } from '@backstage/backend-tasks'; import { TechInsightCheck } from '@backstage/plugin-tech-insights-node'; +import { TechInsightFact } from '@backstage/plugin-tech-insights-node'; import { TechInsightsStore } from '@backstage/plugin-tech-insights-node'; import { TokenManager } from '@backstage/backend-common'; @@ -106,6 +111,41 @@ export type TechInsightsContext< factRetrieverEngine: FactRetrieverEngine; }; +// @public +export class TechInsightsDatabase implements TechInsightsStore { + constructor(db: Knex, logger: Logger); + // (undocumented) + getFactsBetweenTimestampsByIds( + ids: string[], + entityTriplet: string, + startDateTime: DateTime, + endDateTime: DateTime, + ): Promise<{ + [factId: string]: FlatTechInsightFact[]; + }>; + // (undocumented) + getLatestFactsByIds( + ids: string[], + entityTriplet: string, + ): Promise<{ + [factId: string]: FlatTechInsightFact; + }>; + // (undocumented) + getLatestSchemas(ids?: string[]): Promise; + // (undocumented) + insertFacts({ + id, + facts, + lifecycle, + }: { + id: string; + facts: TechInsightFact[]; + lifecycle?: FactLifecycle; + }): Promise; + // (undocumented) + insertFactSchema(schemaDefinition: FactSchemaDefinition): Promise; +} + // @public (undocumented) export interface TechInsightsOptions< CheckType extends TechInsightCheck, @@ -122,6 +162,7 @@ export interface TechInsightsOptions< factRetrievers?: FactRetrieverRegistration[]; // (undocumented) logger: Logger; + persistenceContext?: PersistenceContext; // (undocumented) scheduler: PluginTaskScheduler; // (undocumented) diff --git a/plugins/tech-insights-backend/src/index.ts b/plugins/tech-insights-backend/src/index.ts index 28a922cd67..8106517a3f 100644 --- a/plugins/tech-insights-backend/src/index.ts +++ b/plugins/tech-insights-backend/src/index.ts @@ -23,6 +23,7 @@ export type { TechInsightsContext, } from './service/techInsightsContextBuilder'; export type { FactRetrieverEngine } from './service/fact/FactRetrieverEngine'; +export type { TechInsightsDatabase } from './service/persistence/TechInsightsDatabase'; export type { PersistenceContext } from './service/persistence/persistenceContext'; export { createFactRetrieverRegistration } from './service/fact/createFactRetriever'; export type { FactRetrieverRegistry } from './service/fact/FactRetrieverRegistry'; diff --git a/plugins/tech-insights-backend/src/service/persistence/TechInsightsDatabase.ts b/plugins/tech-insights-backend/src/service/persistence/TechInsightsDatabase.ts index c6751e864a..65db088431 100644 --- a/plugins/tech-insights-backend/src/service/persistence/TechInsightsDatabase.ts +++ b/plugins/tech-insights-backend/src/service/persistence/TechInsightsDatabase.ts @@ -46,6 +46,11 @@ type RawDbFactSchemaRow = { entityFilter?: string; }; +/** + * Default TechInsightsDatabase implementation. + * + * @public + */ export class TechInsightsDatabase implements TechInsightsStore { private readonly CHUNK_SIZE = 50; diff --git a/plugins/tech-insights-backend/src/service/techInsightsContextBuilder.ts b/plugins/tech-insights-backend/src/service/techInsightsContextBuilder.ts index f85d99b2a8..20693d0a7d 100644 --- a/plugins/tech-insights-backend/src/service/techInsightsContextBuilder.ts +++ b/plugins/tech-insights-backend/src/service/techInsightsContextBuilder.ts @@ -74,6 +74,12 @@ export interface TechInsightsOptions< */ factRetrieverRegistry?: FactRetrieverRegistry; + /** + * Optional persistenceContext implementation that replaces the default one. + * This can be used to replace underlying database with a more suitable implementation if needed + */ + persistenceContext?: PersistenceContext; + logger: Logger; config: Config; discovery: PluginEndpointDiscovery; @@ -139,9 +145,11 @@ export const buildTechInsightsContext = async < const factRetrieverRegistry = buildFactRetrieverRegistry(); - const persistenceContext = await initializePersistenceContext(database, { - logger, - }); + const persistenceContext = + options.persistenceContext ?? + (await initializePersistenceContext(database, { + logger, + })); const factRetrieverEngine = await DefaultFactRetrieverEngine.create({ scheduler, From 4e7bd0a1b1ce05d470fbf9d5b2c433e6419d5264 Mon Sep 17 00:00:00 2001 From: Jussi Hallila Date: Tue, 10 Jan 2023 13:46:27 +0100 Subject: [PATCH 07/38] Fix english language Signed-off-by: Jussi Hallila --- .changeset/rude-pumas-draw.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/rude-pumas-draw.md b/.changeset/rude-pumas-draw.md index df3592ece8..e36d1dd997 100644 --- a/.changeset/rude-pumas-draw.md +++ b/.changeset/rude-pumas-draw.md @@ -2,4 +2,4 @@ '@backstage/plugin-tech-insights-backend': patch --- -Expose optional persistenceContext on TechInsights construction to enable integrators to provide their own database implementations for fact handling. +Expose optional `persistenceContext` on `TechInsights` construction to enable integrators to provide their own database implementations for fact handling. From 1322d305f5b84f86b42283f67c5827156e9f3880 Mon Sep 17 00:00:00 2001 From: Drew Boswell <6523434+drewboswell@users.noreply.github.com> Date: Tue, 10 Jan 2023 15:14:26 +0100 Subject: [PATCH 08/38] Update ADOPTERS.md Signed-off-by: Drew Boswell <6523434+drewboswell@users.noreply.github.com> --- ADOPTERS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/ADOPTERS.md b/ADOPTERS.md index fd2c656820..fa8e9de00a 100644 --- a/ADOPTERS.md +++ b/ADOPTERS.md @@ -226,3 +226,4 @@ _You can do this by using the [Adopter form](https://info.backstage.spotify.com/ | [Tractable AI](https://tractable.ai/) | [Stephan Schielke](https://github.com/stephanschielke) | We are hitting a critical point in our scale (100+ engineers) and need to get a handle on discoverability and ownership. The Service Catalog, TechDocs and Search are essential to us to achieve that. | | [Garanti BBVA Teknoloji](https://www.linkedin.com/company/garanti-teknoloji/) | [Caglar Cataloglu](https://github.com/crozwise) | We are using Backstage focusing on improving experience of developers, minimizing friction from idea to production. We call our portal as "Hyperspace" and very excited for our community (2000+ engineers) that finally we have a platform to boost our productivity! | [Booking.com](https://www.linkedin.com/company/booking.com/) | [Mesut Yilmazyildirim](https://www.linkedin.com/in/myilmazyildirim) | We are adopting Backstage as the new reliability platform inside the company. We are migrating UIs of our internal developer tools to Backstage for a better user experience. +| [Swissquote Bank](https://swissquote.com/company/jobs/open-positions) | [Bruno Rocha](https://www.linkedin.com/in/bruno-rocha1/) | Integrating Backstage as the visualization layer & tactical overview of our services and teams. From e75f39e603e639ebffaccb535ed0c5565763447f Mon Sep 17 00:00:00 2001 From: Carlos Esteban Lopez Date: Thu, 15 Dec 2022 00:02:48 -0500 Subject: [PATCH 09/38] feat: Lint paragraphs except in test files & fix Signed-off-by: Carlos Esteban Lopez --- .eslintrc.js | 1 + .../Breadcrumbs/Breadcrumbs.stories.tsx | 20 +++++++++---------- .../EntityBazaarInfoContent.tsx | 7 ++++++- .../HomePageBazaarInfoCard.tsx | 5 +++-- .../src/components/FossaCard/FossaCard.tsx | 13 +++++++----- .../WorkflowRunsTable/WorkflowRunsTable.tsx | 4 ++-- .../homePageComponents/RandomJoke/Content.tsx | 7 ++++--- .../BuildsPage/lib/CITable/CITable.tsx | 10 +++++----- .../ArgoRollouts/StepsProgress.tsx | 7 ++++--- .../ListTasksPage/columns/CreatedAtColumn.tsx | 5 ++++- .../columns/OwnerEntityColumn.tsx | 3 ++- .../home/StackOverflowQuestions/Content.tsx | 5 +++-- .../RadarLegend/RadarLegendRing.tsx | 3 ++- .../tech-radar/src/components/RadarPage.tsx | 5 +++-- .../BuildTimeline/BuildTimeline.tsx | 3 ++- yarn.lock | 2 +- 16 files changed, 60 insertions(+), 40 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index cf01ffe3a6..df54fa865d 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -247,6 +247,7 @@ module.exports = { { forbid: [ { element: 'button', message: 'use MUI