;
+ return could not load questions;
}
const getSecondaryText = (answer_count: Number) =>
diff --git a/plugins/tech-radar/src/components/RadarLegend/RadarLegendRing.tsx b/plugins/tech-radar/src/components/RadarLegend/RadarLegendRing.tsx
index 9ad8126ac4..78232a3a88 100644
--- a/plugins/tech-radar/src/components/RadarLegend/RadarLegendRing.tsx
+++ b/plugins/tech-radar/src/components/RadarLegend/RadarLegendRing.tsx
@@ -14,6 +14,7 @@
* limitations under the License.
*/
import { ClassNameMap } from '@material-ui/core/styles/withStyles';
+import Typography from '@material-ui/core/Typography/Typography';
import React from 'react';
import { Entry, Ring } from '../../utils/types';
import { RadarLegendLink } from './RadarLegendLink';
@@ -38,7 +39,7 @@ export const RadarLegendRing = ({
{ring.name}
{entries.length === 0 ? (
-
(empty)
+ (empty)
) : (
{entries.map(entry => (
diff --git a/plugins/tech-radar/src/components/RadarPage.tsx b/plugins/tech-radar/src/components/RadarPage.tsx
index 49f856eddd..03f33f9e4c 100644
--- a/plugins/tech-radar/src/components/RadarPage.tsx
+++ b/plugins/tech-radar/src/components/RadarPage.tsx
@@ -23,6 +23,7 @@ import {
Link,
} from '@backstage/core-components';
import { Grid, Input, makeStyles } from '@material-ui/core';
+import Typography from '@material-ui/core/Typography';
import React from 'react';
import { RadarComponent, TechRadarComponentProps } from './RadarComponent';
@@ -79,7 +80,7 @@ export function RadarPage(props: TechRadarPageProps) {
onChange={e => setSearchText(e.target.value)}
/>
-
+
This is used for visualizing the official guidelines of different
areas of software development such as languages, frameworks,
infrastructure and processes. You can find an explanation for the
@@ -88,7 +89,7 @@ export function RadarPage(props: TechRadarPageProps) {
Zalando Tech Radar
.
-
+
diff --git a/plugins/xcmetrics/src/components/BuildTimeline/BuildTimeline.tsx b/plugins/xcmetrics/src/components/BuildTimeline/BuildTimeline.tsx
index f00ee03d56..83c8288388 100644
--- a/plugins/xcmetrics/src/components/BuildTimeline/BuildTimeline.tsx
+++ b/plugins/xcmetrics/src/components/BuildTimeline/BuildTimeline.tsx
@@ -15,6 +15,7 @@
*/
import { createStyles, makeStyles, useTheme } from '@material-ui/core';
+import Typography from '@material-ui/core/Typography';
import React from 'react';
import {
Bar,
@@ -91,7 +92,7 @@ export const BuildTimeline = ({
width,
}: BuildTimelineProps) => {
const theme = useTheme();
- if (!targets.length) return
in favor of MUI
From e16f80524299e2af2d8cf01a3aa19d21360b29a3 Mon Sep 17 00:00:00 2001
From: Carlos Esteban Lopez
Date: Thu, 15 Dec 2022 12:43:54 -0500
Subject: [PATCH 07/59] fix: Set eslint-plugin-react to existing version in
other packages
Signed-off-by: Carlos Esteban Lopez
---
yarn.lock | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/yarn.lock b/yarn.lock
index b64750defc..a549cab5a9 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -22071,7 +22071,7 @@ __metadata:
languageName: node
linkType: hard
-"eslint-plugin-react@npm:^7.28.0, eslint-plugin-react@npm:^7.31.11":
+"eslint-plugin-react@npm:^7.28.0":
version: 7.31.11
resolution: "eslint-plugin-react@npm:7.31.11"
dependencies:
From 2bdd1f92c15b224f119a10bd1d428e2b3168a9ee Mon Sep 17 00:00:00 2001
From: Carlos Esteban Lopez
Date: Tue, 3 Jan 2023 12:43:54 -0500
Subject: [PATCH 08/59] fix: Add paragraph prop for bottom margin
Signed-off-by: Carlos Esteban Lopez
---
.../src/layout/Breadcrumbs/Breadcrumbs.stories.tsx | 10 +++++-----
.../EntityBazaarInfoContent.tsx | 2 +-
.../HomePageBazaarInfoCard/HomePageBazaarInfoCard.tsx | 2 +-
plugins/fossa/src/components/FossaCard/FossaCard.tsx | 5 +++--
.../components/WorkflowRunsTable/WorkflowRunsTable.tsx | 8 ++++++--
.../home/src/homePageComponents/RandomJoke/Content.tsx | 6 +++---
.../src/components/BuildsPage/lib/CITable/CITable.tsx | 6 +++---
.../CustomResources/ArgoRollouts/StepsProgress.tsx | 4 ++--
.../ListTasksPage/columns/CreatedAtColumn.tsx | 4 +++-
.../ListTasksPage/columns/OwnerEntityColumn.tsx | 2 +-
.../src/home/StackOverflowQuestions/Content.tsx | 4 ++--
.../src/components/RadarLegend/RadarLegendRing.tsx | 4 +++-
plugins/tech-radar/src/components/RadarPage.tsx | 2 +-
.../src/components/BuildTimeline/BuildTimeline.tsx | 2 +-
14 files changed, 35 insertions(+), 26 deletions(-)
diff --git a/packages/core-components/src/layout/Breadcrumbs/Breadcrumbs.stories.tsx b/packages/core-components/src/layout/Breadcrumbs/Breadcrumbs.stories.tsx
index 00563be313..04363f2a4a 100644
--- a/packages/core-components/src/layout/Breadcrumbs/Breadcrumbs.stories.tsx
+++ b/packages/core-components/src/layout/Breadcrumbs/Breadcrumbs.stories.tsx
@@ -36,7 +36,7 @@ export default {
export const InHeader = () => (
Standard breadcrumbs
-
+
Underlined pages are links. This should show a hierarchical relationship.
@@ -61,14 +61,14 @@ export const OutsideOfHeader = () => {
const open = Boolean(anchorEl);
return (
-
+
It might be the case that you want to keep your breadcrumbs outside of
the header. In that case, they should be positioned above the title of
the page.
Standard breadcrumbs
-
+
Underlined pages are links. This should show a hierarchical
relationship.
@@ -82,7 +82,7 @@ export const OutsideOfHeader = () => {
Hidden breadcrumbs
-
+
Use this when you have more than three breadcrumbs. When user clicks on
ellipses, expand the breadcrumbs out.
@@ -96,7 +96,7 @@ export const OutsideOfHeader = () => {
{entries.length === 0 ? (
- (empty)
+
+ (empty)
+
) : (
{entries.map(entry => (
diff --git a/plugins/tech-radar/src/components/RadarPage.tsx b/plugins/tech-radar/src/components/RadarPage.tsx
index 03f33f9e4c..802acef2a8 100644
--- a/plugins/tech-radar/src/components/RadarPage.tsx
+++ b/plugins/tech-radar/src/components/RadarPage.tsx
@@ -80,7 +80,7 @@ export function RadarPage(props: TechRadarPageProps) {
onChange={e => setSearchText(e.target.value)}
/>
-
+
This is used for visualizing the official guidelines of different
areas of software development such as languages, frameworks,
infrastructure and processes. You can find an explanation for the
diff --git a/plugins/xcmetrics/src/components/BuildTimeline/BuildTimeline.tsx b/plugins/xcmetrics/src/components/BuildTimeline/BuildTimeline.tsx
index 83c8288388..54d84ff6c6 100644
--- a/plugins/xcmetrics/src/components/BuildTimeline/BuildTimeline.tsx
+++ b/plugins/xcmetrics/src/components/BuildTimeline/BuildTimeline.tsx
@@ -92,7 +92,7 @@ export const BuildTimeline = ({
width,
}: BuildTimelineProps) => {
const theme = useTheme();
- if (!targets.length) return No Targets;
+ if (!targets.length) return No Targets;
const data = getTimelineData(targets);
From 391d03b1b4700452a055a0b0c2b972ef640fd29d Mon Sep 17 00:00:00 2001
From: Carlos Esteban Lopez
Date: Tue, 10 Jan 2023 16:27:57 -0500
Subject: [PATCH 09/59] chore: Update changeset to PR comment
Signed-off-by: Carlos Esteban Lopez
---
.changeset/many-carpets-beam.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.changeset/many-carpets-beam.md b/.changeset/many-carpets-beam.md
index e7817c638e..454d404e83 100644
--- a/.changeset/many-carpets-beam.md
+++ b/.changeset/many-carpets-beam.md
@@ -11,4 +11,4 @@
'@backstage/plugin-xcmetrics': patch
---
-ESLint rule to forbid
in favor of MUI
+Small updates to some paragraph components to ensure theme typography properties are inherited correctly.
From c1642b2dd1204789779af002c320d78dd28f5c60 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?=
Date: Wed, 11 Jan 2023 10:47:04 +0100
Subject: [PATCH 10/59] some slight additions to the catalog model extension
docs
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Fredrik Adelöw
---
.../software-catalog/extending-the-model.md | 29 +++++++++++++------
1 file changed, 20 insertions(+), 9 deletions(-)
diff --git a/docs/features/software-catalog/extending-the-model.md b/docs/features/software-catalog/extending-the-model.md
index 92ce153da2..31c0ed90db 100644
--- a/docs/features/software-catalog/extending-the-model.md
+++ b/docs/features/software-catalog/extending-the-model.md
@@ -438,7 +438,7 @@ with a new Entity type.
### Creating a custom entity definition
The first step of introducing a custom entity is to define what shape and schema
-it has. We do this both using a TypeScript type, along with a JSONSchema schema.
+it has. We do this using a TypeScript type, as well as a JSONSchema schema.
Most of the time you will want to have at least the TypeScript type of your
extension available in both frontend and backend code, which means you likely
@@ -474,23 +474,35 @@ entity might look like:
import { CatalogProcessor, processingResult } from '@backstage/catalog-backend';
import { entityKindSchemaValidator } from '@backstage/catalog-model';
+// For an example of the JSONSchema format and how to use $ref markers to the
+// base definitions, see:
+// https://github.com/backstage/backstage/tree/master/packages/catalog-model/src/schema/kinds/Component.v1alpha1.schema.json
+import { foobarEntityV1alpha1Schema } from '@internal/catalog-model';
+
export class FoobarEntitiesProcessor implements CatalogProcessor {
// You often end up wanting to support multiple versions of your kind as you
- // iterate on the definition, so we keep each version inside this array.
+ // iterate on the definition, so we keep each version inside this array as a
+ // convenient pattern.
private readonly validators = [
- // This is where we use the JSONSchema that we export from our isomorphic package
+ // This is where we use the JSONSchema that we export from our isomorphic
+ // package
entityKindSchemaValidator(foobarEntityV1alpha1Schema),
];
- // validateEntityKind is responsible for signaling to the catalog processing engine
- // that this entity is valid and should therefore be submitted for further processing.
+ // validateEntityKind is responsible for signaling to the catalog processing
+ // engine that this entity is valid and should therefore be submitted for
+ // further processing.
async validateEntityKind(entity: Entity): Promise {
for (const validator of this.validators) {
+ // If the validator throws an exception, the entity will be marked as
+ // invalid.
if (validator(entity)) {
return true;
}
}
+ // Returning false signals that we don't know what this is, passing the
+ // responsibility to other processors to try to validate it instead.
return false;
}
@@ -505,8 +517,8 @@ export class FoobarEntitiesProcessor implements CatalogProcessor {
) {
const foobarEntity = entity as FoobarEntityV1alpha1;
- // Here we can modify the entity or emit results related to the entity
- // Typically you will want to emit any relations associated with the entity here
+ // Typically you will want to emit any relations associated with the
+ // entity here.
emit(processingResult.relation({ ... }))
}
@@ -519,8 +531,7 @@ Once the processor is created it can be wired up to the catalog via the
`CatalogBuilder` in `packages/backend/src/plugins/catalog.ts`:
```diff
-+ import { FoobarEntitiesProcessor implements CatalogProcessor {
- } from '@internal/plugin-foobar-backend';
++ import { FoobarEntitiesProcessor } from '@internal/plugin-foobar-backend';
// ...
From d5e43e4a09ac67c5b5a64ec8a12c1cf2dbf1ebb4 Mon Sep 17 00:00:00 2001
From: Jussi Hallila
Date: Wed, 11 Jan 2023 11:52:05 +0100
Subject: [PATCH 11/59] Make default repository impl protected Expose a
construction function instead.
Signed-off-by: Jussi Hallila
---
plugins/tech-insights-backend/api-report.md | 51 ++++---------------
plugins/tech-insights-backend/src/index.ts | 7 ++-
.../persistence/TechInsightsDatabase.ts | 2 +-
.../service/persistence/persistenceContext.ts | 7 ++-
4 files changed, 23 insertions(+), 44 deletions(-)
diff --git a/plugins/tech-insights-backend/api-report.md b/plugins/tech-insights-backend/api-report.md
index faca4a615c..7d1d7583ae 100644
--- a/plugins/tech-insights-backend/api-report.md
+++ b/plugins/tech-insights-backend/api-report.md
@@ -5,7 +5,6 @@
```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';
@@ -14,16 +13,12 @@ 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';
@@ -35,6 +30,11 @@ export const buildTechInsightsContext: <
options: TechInsightsOptions,
) => Promise>;
+// @public
+export type CreateDatabaseOptions = {
+ logger: Logger;
+};
+
// @public
export function createFactRetrieverRegistration(
options: FactRetrieverRegistrationOptions,
@@ -82,6 +82,12 @@ export interface FactRetrieverRegistry {
register(registration: FactRetrieverRegistration): Promise;
}
+// @public
+export const initializePersistenceContext: (
+ database: PluginDatabaseManager,
+ options?: CreateDatabaseOptions,
+) => Promise;
+
// @public
export type PersistenceContext = {
techInsightsStore: TechInsightsStore;
@@ -111,41 +117,6 @@ 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,
diff --git a/plugins/tech-insights-backend/src/index.ts b/plugins/tech-insights-backend/src/index.ts
index 8106517a3f..2071acd263 100644
--- a/plugins/tech-insights-backend/src/index.ts
+++ b/plugins/tech-insights-backend/src/index.ts
@@ -18,13 +18,16 @@ export * from './service/router';
export type { RouterOptions } from './service/router';
export { buildTechInsightsContext } from './service/techInsightsContextBuilder';
+export { initializePersistenceContext } from './service/persistence/persistenceContext';
export type {
TechInsightsOptions,
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 type {
+ PersistenceContext,
+ CreateDatabaseOptions,
+} from './service/persistence/persistenceContext';
export { createFactRetrieverRegistration } from './service/fact/createFactRetriever';
export type { FactRetrieverRegistry } from './service/fact/FactRetrieverRegistry';
export type { FactRetrieverRegistrationOptions } from './service/fact/createFactRetriever';
diff --git a/plugins/tech-insights-backend/src/service/persistence/TechInsightsDatabase.ts b/plugins/tech-insights-backend/src/service/persistence/TechInsightsDatabase.ts
index 65db088431..0b14f80843 100644
--- a/plugins/tech-insights-backend/src/service/persistence/TechInsightsDatabase.ts
+++ b/plugins/tech-insights-backend/src/service/persistence/TechInsightsDatabase.ts
@@ -49,7 +49,7 @@ type RawDbFactSchemaRow = {
/**
* Default TechInsightsDatabase implementation.
*
- * @public
+ * @internal
*/
export class TechInsightsDatabase implements TechInsightsStore {
private readonly CHUNK_SIZE = 50;
diff --git a/plugins/tech-insights-backend/src/service/persistence/persistenceContext.ts b/plugins/tech-insights-backend/src/service/persistence/persistenceContext.ts
index 575ee67bdf..87efcd8a3d 100644
--- a/plugins/tech-insights-backend/src/service/persistence/persistenceContext.ts
+++ b/plugins/tech-insights-backend/src/service/persistence/persistenceContext.ts
@@ -36,6 +36,11 @@ export type PersistenceContext = {
techInsightsStore: TechInsightsStore;
};
+/**
+ * A Container for persistence context initialization options
+ *
+ * @public
+ */
export type CreateDatabaseOptions = {
logger: Logger;
};
@@ -45,7 +50,7 @@ const defaultOptions: CreateDatabaseOptions = {
};
/**
- * A factory method to construct persistence context for running implementation.
+ * A factory function to construct persistence context for running implementation.
*
* @public
*/
From a942f70435c1a52168749c73447631d00cf81f46 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?=
Date: Wed, 11 Jan 2023 13:25:57 +0100
Subject: [PATCH 12/59] clickable links in UserSettingsIdentityCard
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Fredrik Adelöw
---
.changeset/large-tools-collect.md | 5 ++
plugins/user-settings/package.json | 1 +
.../General/UserSettingsIdentityCard.test.tsx | 8 ++-
.../General/UserSettingsIdentityCard.tsx | 62 ++++++++++---------
yarn.lock | 1 +
5 files changed, 47 insertions(+), 30 deletions(-)
create mode 100644 .changeset/large-tools-collect.md
diff --git a/.changeset/large-tools-collect.md b/.changeset/large-tools-collect.md
new file mode 100644
index 0000000000..1b3f31fbd2
--- /dev/null
+++ b/.changeset/large-tools-collect.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-user-settings': patch
+---
+
+Minor update to the `UserSettingsIdentityCard` to have clickable entity refs
diff --git a/plugins/user-settings/package.json b/plugins/user-settings/package.json
index 2b1366b2ed..cf611dd41b 100644
--- a/plugins/user-settings/package.json
+++ b/plugins/user-settings/package.json
@@ -36,6 +36,7 @@
"@backstage/core-components": "workspace:^",
"@backstage/core-plugin-api": "workspace:^",
"@backstage/errors": "workspace:^",
+ "@backstage/plugin-catalog-react": "workspace:^",
"@backstage/theme": "workspace:^",
"@backstage/types": "workspace:^",
"@material-ui/core": "^4.12.2",
diff --git a/plugins/user-settings/src/components/General/UserSettingsIdentityCard.test.tsx b/plugins/user-settings/src/components/General/UserSettingsIdentityCard.test.tsx
index 19c3eb2182..026e0517bb 100644
--- a/plugins/user-settings/src/components/General/UserSettingsIdentityCard.test.tsx
+++ b/plugins/user-settings/src/components/General/UserSettingsIdentityCard.test.tsx
@@ -24,6 +24,7 @@ import React from 'react';
import { UserSettingsIdentityCard } from './UserSettingsIdentityCard';
import { ApiProvider } from '@backstage/core-app-api';
import { identityApiRef } from '@backstage/core-plugin-api';
+import { entityRouteRef } from '@backstage/plugin-catalog-react';
const apiRegistry = TestApiRegistry.from([
identityApiRef,
@@ -32,7 +33,7 @@ const apiRegistry = TestApiRegistry.from([
getBackstageIdentity: jest.fn(async () => ({
type: 'user' as const,
userEntityRef: 'foo:bar/foobar',
- ownershipEntityRefs: ['test-ownership'],
+ ownershipEntityRefs: ['user:default/test-ownership'],
})),
},
]);
@@ -44,10 +45,13 @@ describe('', () => {
,
+ {
+ mountedRoutes: { '/catalog/:namespace/:kind/:name': entityRouteRef },
+ },
),
);
- expect(screen.getByText('test-ownership')).toBeInTheDocument();
+ expect(screen.getByText('user:default/test-ownership')).toBeInTheDocument();
expect(screen.getByText('foo:bar/foobar')).toBeInTheDocument();
});
});
diff --git a/plugins/user-settings/src/components/General/UserSettingsIdentityCard.tsx b/plugins/user-settings/src/components/General/UserSettingsIdentityCard.tsx
index 1369f4aab8..a398877ce9 100644
--- a/plugins/user-settings/src/components/General/UserSettingsIdentityCard.tsx
+++ b/plugins/user-settings/src/components/General/UserSettingsIdentityCard.tsx
@@ -15,40 +15,46 @@
*/
import { InfoCard } from '@backstage/core-components';
-import React from 'react';
-import { useUserProfile } from '../useUserProfileInfo';
-import Chip from '@material-ui/core/Chip';
+import { EntityRefLinks } from '@backstage/plugin-catalog-react';
import Grid from '@material-ui/core/Grid';
import Typography from '@material-ui/core/Typography';
+import React from 'react';
+import { useUserProfile } from '../useUserProfileInfo';
-/** @public */
-export const UserSettingsIdentityCard = () => {
+const Contents = () => {
const { backstageIdentity } = useUserProfile();
+ if (!backstageIdentity) {
+ return No Backstage Identity;
+ }
+
return (
-
-
-
-
-
-
- User Entity:{' '}
-
-
-
- Ownership Entities:{' '}
- {backstageIdentity?.ownershipEntityRefs.map(it => (
-
- ))}
-
-
-
-
+
+
+
+ User Entity:{' '}
+ ref}
+ />
+
-
+
+
+ Ownership Entities:{' '}
+ ref}
+ />
+
+
+
);
};
+
+/** @public */
+export const UserSettingsIdentityCard = () => (
+
+
+
+);
diff --git a/yarn.lock b/yarn.lock
index 00a59c3350..07bc1f7f81 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -8424,6 +8424,7 @@ __metadata:
"@backstage/core-plugin-api": "workspace:^"
"@backstage/dev-utils": "workspace:^"
"@backstage/errors": "workspace:^"
+ "@backstage/plugin-catalog-react": "workspace:^"
"@backstage/test-utils": "workspace:^"
"@backstage/theme": "workspace:^"
"@backstage/types": "workspace:^"
From bdd4b973e8ca12a46ba3e72b108db12fe0cf31e7 Mon Sep 17 00:00:00 2001
From: blam
Date: Tue, 3 Jan 2023 15:27:02 +0100
Subject: [PATCH 13/59] chore: provide all core services to the `TestBackend`
Signed-off-by: blam
Signed-off-by: blam
---
.../src/next/implementations/index.ts | 16 ++++++++
.../mockTokenManagerService.ts | 37 +++++++++++++++++++
.../src/next/wiring/TestBackend.test.ts | 37 +++++++++++++++++++
.../src/next/wiring/TestBackend.ts | 22 ++++++++++-
4 files changed, 110 insertions(+), 2 deletions(-)
create mode 100644 packages/backend-test-utils/src/next/implementations/index.ts
create mode 100644 packages/backend-test-utils/src/next/implementations/mockTokenManagerService.ts
diff --git a/packages/backend-test-utils/src/next/implementations/index.ts b/packages/backend-test-utils/src/next/implementations/index.ts
new file mode 100644
index 0000000000..073e47f5e4
--- /dev/null
+++ b/packages/backend-test-utils/src/next/implementations/index.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 { mockTokenManagerFactory } from './mockTokenManagerService';
diff --git a/packages/backend-test-utils/src/next/implementations/mockTokenManagerService.ts b/packages/backend-test-utils/src/next/implementations/mockTokenManagerService.ts
new file mode 100644
index 0000000000..f68e910e0c
--- /dev/null
+++ b/packages/backend-test-utils/src/next/implementations/mockTokenManagerService.ts
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+import { TokenManager } from '@backstage/backend-common';
+import {
+ coreServices,
+ createServiceFactory,
+} from '@backstage/backend-plugin-api';
+
+class TokenManagerMock implements TokenManager {
+ async getToken(): Promise<{ token: string }> {
+ return { token: 'mock-token' };
+ }
+ async authenticate(): Promise {}
+}
+
+export const mockTokenManagerFactory = createServiceFactory({
+ service: coreServices.tokenManager,
+ deps: {},
+ async factory() {
+ return async () => {
+ return new TokenManagerMock();
+ };
+ },
+});
diff --git a/packages/backend-test-utils/src/next/wiring/TestBackend.test.ts b/packages/backend-test-utils/src/next/wiring/TestBackend.test.ts
index 5ea37e9106..9d71005e18 100644
--- a/packages/backend-test-utils/src/next/wiring/TestBackend.test.ts
+++ b/packages/backend-test-utils/src/next/wiring/TestBackend.test.ts
@@ -20,7 +20,9 @@ import {
createServiceFactory,
createServiceRef,
coreServices,
+ createBackendPlugin,
} from '@backstage/backend-plugin-api';
+
import { startTestBackend } from './TestBackend';
// This bit makes sure that test backends are cleaned up properly
@@ -156,4 +158,39 @@ describe('TestBackend', () => {
await backend.stop();
expect(shutdownSpy).toHaveBeenCalled();
});
+
+ it('should provide a set of default services', async () => {
+ expect.assertions(2);
+
+ const testPlugin = createBackendPlugin({
+ id: 'test',
+ register(env) {
+ env.registerInit({
+ deps: {
+ cache: coreServices.cache,
+ config: coreServices.config,
+ database: coreServices.database,
+ discovery: coreServices.discovery,
+ lifecycle: coreServices.lifecycle,
+ logger: coreServices.logger,
+ permissions: coreServices.permissions,
+ rootLifecycle: coreServices.rootLifecycle,
+ rootLogger: coreServices.rootLogger,
+ scheduler: coreServices.scheduler,
+ tokenManager: coreServices.tokenManager,
+ urlReader: coreServices.urlReader,
+ },
+ async init(deps) {
+ expect(Object.keys(deps)).toHaveLength(12);
+ expect(Object.values(deps)).not.toContain(undefined);
+ },
+ });
+ },
+ });
+
+ await startTestBackend({
+ services: [],
+ features: [testPlugin()],
+ }).then(backend => backend.stop());
+ });
});
diff --git a/packages/backend-test-utils/src/next/wiring/TestBackend.ts b/packages/backend-test-utils/src/next/wiring/TestBackend.ts
index 0295332855..7b78ad3d95 100644
--- a/packages/backend-test-utils/src/next/wiring/TestBackend.ts
+++ b/packages/backend-test-utils/src/next/wiring/TestBackend.ts
@@ -21,7 +21,15 @@ import {
rootLifecycleFactory,
loggerFactory,
rootLoggerFactory,
+ configFactory,
+ discoveryFactory,
+ cacheFactory,
+ databaseFactory,
+ permissionsFactory,
+ schedulerFactory,
+ urlReaderFactory,
} from '@backstage/backend-app-api';
+
import {
ServiceFactory,
ServiceRef,
@@ -30,6 +38,8 @@ import {
ExtensionPoint,
} from '@backstage/backend-plugin-api';
+import { mockTokenManagerFactory } from '../implementations';
+
/** @alpha */
export interface TestBackendOptions<
TServices extends any[],
@@ -55,10 +65,18 @@ export interface TestBackendOptions<
}
const defaultServiceFactories = [
- rootLoggerFactory(),
- loggerFactory(),
+ cacheFactory(),
+ configFactory(),
+ databaseFactory(),
+ discoveryFactory(),
lifecycleFactory(),
+ loggerFactory(),
+ permissionsFactory(),
rootLifecycleFactory(),
+ rootLoggerFactory(),
+ schedulerFactory(),
+ mockTokenManagerFactory(),
+ urlReaderFactory(),
];
const backendInstancesToCleanUp = new Array();
From beed5864d0d94fb7660459ec3b6d70d9e5fee692 Mon Sep 17 00:00:00 2001
From: blam
Date: Tue, 3 Jan 2023 17:02:35 +0100
Subject: [PATCH 14/59] chore: added some more mock defintions and refactoring
the `TaskManager.forPlugin`
Signed-off-by: blam
---
.../scheduler/schedulerFactory.ts | 10 +++-
.../backend-tasks/src/tasks/TaskScheduler.ts | 23 ++++++----
.../src/next/implementations/index.ts | 3 ++
.../next/implementations/mockConfigService.ts | 30 ++++++++++++
.../implementations/mockDatabaseService.ts | 46 +++++++++++++++++++
.../implementations/mockDiscoveryService.ts | 40 ++++++++++++++++
.../src/next/wiring/TestBackend.ts | 16 ++++---
7 files changed, 151 insertions(+), 17 deletions(-)
create mode 100644 packages/backend-test-utils/src/next/implementations/mockConfigService.ts
create mode 100644 packages/backend-test-utils/src/next/implementations/mockDatabaseService.ts
create mode 100644 packages/backend-test-utils/src/next/implementations/mockDiscoveryService.ts
diff --git a/packages/backend-app-api/src/services/implementations/scheduler/schedulerFactory.ts b/packages/backend-app-api/src/services/implementations/scheduler/schedulerFactory.ts
index a6edec868a..692f05f6d7 100644
--- a/packages/backend-app-api/src/services/implementations/scheduler/schedulerFactory.ts
+++ b/packages/backend-app-api/src/services/implementations/scheduler/schedulerFactory.ts
@@ -17,6 +17,7 @@
import {
coreServices,
createServiceFactory,
+ loggerToWinstonLogger,
} from '@backstage/backend-plugin-api';
import { TaskScheduler } from '@backstage/backend-tasks';
@@ -26,11 +27,16 @@ export const schedulerFactory = createServiceFactory({
deps: {
config: coreServices.config,
plugin: coreServices.pluginMetadata,
+ databaseManager: coreServices.database,
+ logger: coreServices.logger,
},
async factory({ config }) {
const taskScheduler = TaskScheduler.fromConfig(config);
- return async ({ plugin }) => {
- return taskScheduler.forPlugin(plugin.getId());
+ return async ({ plugin, databaseManager, logger }) => {
+ return taskScheduler.forPlugin(plugin.getId(), {
+ databaseManager,
+ logger: loggerToWinstonLogger(logger),
+ });
};
},
});
diff --git a/packages/backend-tasks/src/tasks/TaskScheduler.ts b/packages/backend-tasks/src/tasks/TaskScheduler.ts
index f14fb9fc2b..f35669d76e 100644
--- a/packages/backend-tasks/src/tasks/TaskScheduler.ts
+++ b/packages/backend-tasks/src/tasks/TaskScheduler.ts
@@ -14,7 +14,11 @@
* limitations under the License.
*/
-import { DatabaseManager, getRootLogger } from '@backstage/backend-common';
+import {
+ DatabaseManager,
+ getRootLogger,
+ PluginDatabaseManager,
+} from '@backstage/backend-common';
import { Config } from '@backstage/config';
import { once } from 'lodash';
import { Duration } from 'luxon';
@@ -56,9 +60,15 @@ export class TaskScheduler {
* @param pluginId - The unique ID of the plugin, for example "catalog"
* @returns A {@link PluginTaskScheduler} instance
*/
- forPlugin(pluginId: string): PluginTaskScheduler {
+ forPlugin(
+ pluginId: string,
+ options?: { databaseManager?: PluginDatabaseManager; logger?: Logger },
+ ): PluginTaskScheduler {
+ const databaseManager =
+ options?.databaseManager ?? this.databaseManager.forPlugin(pluginId);
+ const logger = options?.logger ?? this.logger.child({ plugin: pluginId });
+
const databaseFactory = once(async () => {
- const databaseManager = this.databaseManager.forPlugin(pluginId);
const knex = await databaseManager.getClient();
if (!databaseManager.migrations?.skip) {
@@ -68,16 +78,13 @@ export class TaskScheduler {
const janitor = new PluginTaskSchedulerJanitor({
knex,
waitBetweenRuns: Duration.fromObject({ minutes: 1 }),
- logger: this.logger,
+ logger,
});
janitor.start();
return knex;
});
- return new PluginTaskSchedulerImpl(
- databaseFactory,
- this.logger.child({ plugin: pluginId }),
- );
+ return new PluginTaskSchedulerImpl(databaseFactory, logger);
}
}
diff --git a/packages/backend-test-utils/src/next/implementations/index.ts b/packages/backend-test-utils/src/next/implementations/index.ts
index 073e47f5e4..ba8bb5fb5e 100644
--- a/packages/backend-test-utils/src/next/implementations/index.ts
+++ b/packages/backend-test-utils/src/next/implementations/index.ts
@@ -14,3 +14,6 @@
* limitations under the License.
*/
export { mockTokenManagerFactory } from './mockTokenManagerService';
+export { mockConfigFactory } from './mockConfigService';
+export { mockDatabaseFactory } from './mockDatabaseService';
+export { mockDiscoveryFactory } from './mockDiscoveryService';
diff --git a/packages/backend-test-utils/src/next/implementations/mockConfigService.ts b/packages/backend-test-utils/src/next/implementations/mockConfigService.ts
new file mode 100644
index 0000000000..976167b473
--- /dev/null
+++ b/packages/backend-test-utils/src/next/implementations/mockConfigService.ts
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2022 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 {
+ coreServices,
+ createServiceFactory,
+} from '@backstage/backend-plugin-api';
+import { AppConfig, ConfigReader } from '@backstage/config';
+
+/** @public */
+export const mockConfigFactory = createServiceFactory({
+ service: coreServices.config,
+ deps: {},
+ async factory(_, options?: { config?: AppConfig }) {
+ return new ConfigReader(options?.config);
+ },
+});
diff --git a/packages/backend-test-utils/src/next/implementations/mockDatabaseService.ts b/packages/backend-test-utils/src/next/implementations/mockDatabaseService.ts
new file mode 100644
index 0000000000..b0d67c1f1e
--- /dev/null
+++ b/packages/backend-test-utils/src/next/implementations/mockDatabaseService.ts
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2022 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 { DatabaseManager } from '@backstage/backend-common';
+import {
+ coreServices,
+ createServiceFactory,
+} from '@backstage/backend-plugin-api';
+import { ConfigReader } from '@backstage/config';
+
+/** @public */
+export const mockDatabaseFactory = createServiceFactory({
+ service: coreServices.database,
+ deps: {
+ config: coreServices.config,
+ plugin: coreServices.pluginMetadata,
+ },
+ async factory({ config }) {
+ const databaseManager = config.getOptional('backend.database')
+ ? DatabaseManager.fromConfig(config)
+ : DatabaseManager.fromConfig(
+ new ConfigReader({
+ backend: {
+ database: { client: 'better-sqlite', connection: ':memory:' },
+ },
+ }),
+ );
+
+ return async ({ plugin }) => {
+ return databaseManager.forPlugin(plugin.getId());
+ };
+ },
+});
diff --git a/packages/backend-test-utils/src/next/implementations/mockDiscoveryService.ts b/packages/backend-test-utils/src/next/implementations/mockDiscoveryService.ts
new file mode 100644
index 0000000000..3af69187e8
--- /dev/null
+++ b/packages/backend-test-utils/src/next/implementations/mockDiscoveryService.ts
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+import { SingleHostDiscovery } from '@backstage/backend-common';
+import {
+ coreServices,
+ createServiceFactory,
+} from '@backstage/backend-plugin-api';
+import { ConfigReader } from '@backstage/config';
+
+/** @public */
+export const mockDiscoveryFactory = createServiceFactory({
+ service: coreServices.discovery,
+ deps: {},
+ async factory() {
+ // todo(blam): we want to grab the port from the httpRouter when that's available here
+ // to provide a better way to create our mockDiscoveryService.
+ const discovery = SingleHostDiscovery.fromConfig(
+ new ConfigReader({
+ backend: { baseUrl: 'http://localhost:7000', listen: '0.0.0.0:7000' },
+ }),
+ );
+
+ return async () => {
+ return discovery;
+ };
+ },
+});
diff --git a/packages/backend-test-utils/src/next/wiring/TestBackend.ts b/packages/backend-test-utils/src/next/wiring/TestBackend.ts
index 7b78ad3d95..a4ac8be7a2 100644
--- a/packages/backend-test-utils/src/next/wiring/TestBackend.ts
+++ b/packages/backend-test-utils/src/next/wiring/TestBackend.ts
@@ -21,10 +21,7 @@ import {
rootLifecycleFactory,
loggerFactory,
rootLoggerFactory,
- configFactory,
- discoveryFactory,
cacheFactory,
- databaseFactory,
permissionsFactory,
schedulerFactory,
urlReaderFactory,
@@ -38,7 +35,12 @@ import {
ExtensionPoint,
} from '@backstage/backend-plugin-api';
-import { mockTokenManagerFactory } from '../implementations';
+import {
+ mockConfigFactory,
+ mockDatabaseFactory,
+ mockTokenManagerFactory,
+ mockDiscoveryFactory,
+} from '../implementations';
/** @alpha */
export interface TestBackendOptions<
@@ -66,9 +68,9 @@ export interface TestBackendOptions<
const defaultServiceFactories = [
cacheFactory(),
- configFactory(),
- databaseFactory(),
- discoveryFactory(),
+ mockConfigFactory(),
+ mockDatabaseFactory(),
+ mockDiscoveryFactory(),
lifecycleFactory(),
loggerFactory(),
permissionsFactory(),
From 9ec23f2d7c425a3eb11700e96daad89245768072 Mon Sep 17 00:00:00 2001
From: blam
Date: Wed, 4 Jan 2023 16:23:03 +0100
Subject: [PATCH 15/59] chore: revert the TaskScheduler
Signed-off-by: blam
---
.../backend-tasks/src/tasks/TaskScheduler.ts | 23 +++++++------------
1 file changed, 8 insertions(+), 15 deletions(-)
diff --git a/packages/backend-tasks/src/tasks/TaskScheduler.ts b/packages/backend-tasks/src/tasks/TaskScheduler.ts
index f35669d76e..f14fb9fc2b 100644
--- a/packages/backend-tasks/src/tasks/TaskScheduler.ts
+++ b/packages/backend-tasks/src/tasks/TaskScheduler.ts
@@ -14,11 +14,7 @@
* limitations under the License.
*/
-import {
- DatabaseManager,
- getRootLogger,
- PluginDatabaseManager,
-} from '@backstage/backend-common';
+import { DatabaseManager, getRootLogger } from '@backstage/backend-common';
import { Config } from '@backstage/config';
import { once } from 'lodash';
import { Duration } from 'luxon';
@@ -60,15 +56,9 @@ export class TaskScheduler {
* @param pluginId - The unique ID of the plugin, for example "catalog"
* @returns A {@link PluginTaskScheduler} instance
*/
- forPlugin(
- pluginId: string,
- options?: { databaseManager?: PluginDatabaseManager; logger?: Logger },
- ): PluginTaskScheduler {
- const databaseManager =
- options?.databaseManager ?? this.databaseManager.forPlugin(pluginId);
- const logger = options?.logger ?? this.logger.child({ plugin: pluginId });
-
+ forPlugin(pluginId: string): PluginTaskScheduler {
const databaseFactory = once(async () => {
+ const databaseManager = this.databaseManager.forPlugin(pluginId);
const knex = await databaseManager.getClient();
if (!databaseManager.migrations?.skip) {
@@ -78,13 +68,16 @@ export class TaskScheduler {
const janitor = new PluginTaskSchedulerJanitor({
knex,
waitBetweenRuns: Duration.fromObject({ minutes: 1 }),
- logger,
+ logger: this.logger,
});
janitor.start();
return knex;
});
- return new PluginTaskSchedulerImpl(databaseFactory, logger);
+ return new PluginTaskSchedulerImpl(
+ databaseFactory,
+ this.logger.child({ plugin: pluginId }),
+ );
}
}
From 875cd848fdf22e4eae6473f13efe90403ad27aad Mon Sep 17 00:00:00 2001
From: blam
Date: Wed, 4 Jan 2023 16:31:29 +0100
Subject: [PATCH 16/59] chore: reworking how we do the TaskScheduler for now
Signed-off-by: blam
Signed-off-by: Patrik Oldsberg
---
.../database/databaseFactory.ts | 12 ++++-
.../scheduler/schedulerFactory.ts | 9 ++--
.../backend-tasks/src/tasks/TaskScheduler.ts | 32 +++++++++----
.../src/next/implementations/index.ts | 1 -
.../implementations/mockDatabaseService.ts | 46 -------------------
.../implementations/mockDiscoveryService.ts | 2 +-
.../src/next/wiring/TestBackend.test.ts | 5 +-
.../src/next/wiring/TestBackend.ts | 14 ++++--
8 files changed, 51 insertions(+), 70 deletions(-)
delete mode 100644 packages/backend-test-utils/src/next/implementations/mockDatabaseService.ts
diff --git a/packages/backend-app-api/src/services/implementations/database/databaseFactory.ts b/packages/backend-app-api/src/services/implementations/database/databaseFactory.ts
index f33e825c9b..52cecdbc4d 100644
--- a/packages/backend-app-api/src/services/implementations/database/databaseFactory.ts
+++ b/packages/backend-app-api/src/services/implementations/database/databaseFactory.ts
@@ -19,6 +19,7 @@ import {
coreServices,
createServiceFactory,
} from '@backstage/backend-plugin-api';
+import { ConfigReader } from '@backstage/config';
/** @public */
export const databaseFactory = createServiceFactory({
@@ -28,7 +29,16 @@ export const databaseFactory = createServiceFactory({
plugin: coreServices.pluginMetadata,
},
async factory({ config }) {
- const databaseManager = DatabaseManager.fromConfig(config);
+ const databaseManager = config.getOptional('backend.database')
+ ? DatabaseManager.fromConfig(config)
+ : DatabaseManager.fromConfig(
+ new ConfigReader({
+ backend: {
+ database: { client: 'better-sqlite3', connection: ':memory:' },
+ },
+ }),
+ );
+
return async ({ plugin }) => {
return databaseManager.forPlugin(plugin.getId());
};
diff --git a/packages/backend-app-api/src/services/implementations/scheduler/schedulerFactory.ts b/packages/backend-app-api/src/services/implementations/scheduler/schedulerFactory.ts
index 692f05f6d7..4e472b78f4 100644
--- a/packages/backend-app-api/src/services/implementations/scheduler/schedulerFactory.ts
+++ b/packages/backend-app-api/src/services/implementations/scheduler/schedulerFactory.ts
@@ -14,10 +14,10 @@
* limitations under the License.
*/
+import { loggerToWinstonLogger } from '@backstage/backend-common';
import {
coreServices,
createServiceFactory,
- loggerToWinstonLogger,
} from '@backstage/backend-plugin-api';
import { TaskScheduler } from '@backstage/backend-tasks';
@@ -25,15 +25,14 @@ import { TaskScheduler } from '@backstage/backend-tasks';
export const schedulerFactory = createServiceFactory({
service: coreServices.scheduler,
deps: {
- config: coreServices.config,
plugin: coreServices.pluginMetadata,
databaseManager: coreServices.database,
logger: coreServices.logger,
},
- async factory({ config }) {
- const taskScheduler = TaskScheduler.fromConfig(config);
+ async factory() {
return async ({ plugin, databaseManager, logger }) => {
- return taskScheduler.forPlugin(plugin.getId(), {
+ return TaskScheduler.forPlugin({
+ pluginId: plugin.getId(),
databaseManager,
logger: loggerToWinstonLogger(logger),
});
diff --git a/packages/backend-tasks/src/tasks/TaskScheduler.ts b/packages/backend-tasks/src/tasks/TaskScheduler.ts
index f14fb9fc2b..fe81a0054e 100644
--- a/packages/backend-tasks/src/tasks/TaskScheduler.ts
+++ b/packages/backend-tasks/src/tasks/TaskScheduler.ts
@@ -14,7 +14,11 @@
* limitations under the License.
*/
-import { DatabaseManager, getRootLogger } from '@backstage/backend-common';
+import {
+ DatabaseManager,
+ getRootLogger,
+ PluginDatabaseManager,
+} from '@backstage/backend-common';
import { Config } from '@backstage/config';
import { once } from 'lodash';
import { Duration } from 'luxon';
@@ -57,27 +61,35 @@ export class TaskScheduler {
* @returns A {@link PluginTaskScheduler} instance
*/
forPlugin(pluginId: string): PluginTaskScheduler {
- const databaseFactory = once(async () => {
- const databaseManager = this.databaseManager.forPlugin(pluginId);
- const knex = await databaseManager.getClient();
+ return TaskScheduler.forPlugin({
+ pluginId,
+ databaseManager: this.databaseManager.forPlugin(pluginId),
+ logger: this.logger,
+ });
+ }
- if (!databaseManager.migrations?.skip) {
+ static forPlugin(opts: {
+ pluginId: string;
+ databaseManager: PluginDatabaseManager;
+ logger: Logger;
+ }): PluginTaskScheduler {
+ const databaseFactory = once(async () => {
+ const knex = await opts.databaseManager.getClient();
+
+ if (!opts.databaseManager.migrations?.skip) {
await migrateBackendTasks(knex);
}
const janitor = new PluginTaskSchedulerJanitor({
knex,
waitBetweenRuns: Duration.fromObject({ minutes: 1 }),
- logger: this.logger,
+ logger: opts.logger,
});
janitor.start();
return knex;
});
- return new PluginTaskSchedulerImpl(
- databaseFactory,
- this.logger.child({ plugin: pluginId }),
- );
+ return new PluginTaskSchedulerImpl(databaseFactory, opts.logger);
}
}
diff --git a/packages/backend-test-utils/src/next/implementations/index.ts b/packages/backend-test-utils/src/next/implementations/index.ts
index ba8bb5fb5e..c248502307 100644
--- a/packages/backend-test-utils/src/next/implementations/index.ts
+++ b/packages/backend-test-utils/src/next/implementations/index.ts
@@ -15,5 +15,4 @@
*/
export { mockTokenManagerFactory } from './mockTokenManagerService';
export { mockConfigFactory } from './mockConfigService';
-export { mockDatabaseFactory } from './mockDatabaseService';
export { mockDiscoveryFactory } from './mockDiscoveryService';
diff --git a/packages/backend-test-utils/src/next/implementations/mockDatabaseService.ts b/packages/backend-test-utils/src/next/implementations/mockDatabaseService.ts
deleted file mode 100644
index b0d67c1f1e..0000000000
--- a/packages/backend-test-utils/src/next/implementations/mockDatabaseService.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright 2022 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 { DatabaseManager } from '@backstage/backend-common';
-import {
- coreServices,
- createServiceFactory,
-} from '@backstage/backend-plugin-api';
-import { ConfigReader } from '@backstage/config';
-
-/** @public */
-export const mockDatabaseFactory = createServiceFactory({
- service: coreServices.database,
- deps: {
- config: coreServices.config,
- plugin: coreServices.pluginMetadata,
- },
- async factory({ config }) {
- const databaseManager = config.getOptional('backend.database')
- ? DatabaseManager.fromConfig(config)
- : DatabaseManager.fromConfig(
- new ConfigReader({
- backend: {
- database: { client: 'better-sqlite', connection: ':memory:' },
- },
- }),
- );
-
- return async ({ plugin }) => {
- return databaseManager.forPlugin(plugin.getId());
- };
- },
-});
diff --git a/packages/backend-test-utils/src/next/implementations/mockDiscoveryService.ts b/packages/backend-test-utils/src/next/implementations/mockDiscoveryService.ts
index 3af69187e8..e382d23cbd 100644
--- a/packages/backend-test-utils/src/next/implementations/mockDiscoveryService.ts
+++ b/packages/backend-test-utils/src/next/implementations/mockDiscoveryService.ts
@@ -29,7 +29,7 @@ export const mockDiscoveryFactory = createServiceFactory({
// to provide a better way to create our mockDiscoveryService.
const discovery = SingleHostDiscovery.fromConfig(
new ConfigReader({
- backend: { baseUrl: 'http://localhost:7000', listen: '0.0.0.0:7000' },
+ backend: { baseUrl: 'http://localhost:7007', listen: '0.0.0.0' },
}),
);
diff --git a/packages/backend-test-utils/src/next/wiring/TestBackend.test.ts b/packages/backend-test-utils/src/next/wiring/TestBackend.test.ts
index 9d71005e18..4c7362880e 100644
--- a/packages/backend-test-utils/src/next/wiring/TestBackend.test.ts
+++ b/packages/backend-test-utils/src/next/wiring/TestBackend.test.ts
@@ -171,9 +171,12 @@ describe('TestBackend', () => {
config: coreServices.config,
database: coreServices.database,
discovery: coreServices.discovery,
+ httpRouter: coreServices.httpRouter,
lifecycle: coreServices.lifecycle,
logger: coreServices.logger,
permissions: coreServices.permissions,
+ pluginMetadata: coreServices.pluginMetadata,
+ rootHttpRouter: coreServices.rootHttpRouter,
rootLifecycle: coreServices.rootLifecycle,
rootLogger: coreServices.rootLogger,
scheduler: coreServices.scheduler,
@@ -181,7 +184,7 @@ describe('TestBackend', () => {
urlReader: coreServices.urlReader,
},
async init(deps) {
- expect(Object.keys(deps)).toHaveLength(12);
+ expect(Object.keys(deps)).toHaveLength(14);
expect(Object.values(deps)).not.toContain(undefined);
},
});
diff --git a/packages/backend-test-utils/src/next/wiring/TestBackend.ts b/packages/backend-test-utils/src/next/wiring/TestBackend.ts
index a4ac8be7a2..35f138091d 100644
--- a/packages/backend-test-utils/src/next/wiring/TestBackend.ts
+++ b/packages/backend-test-utils/src/next/wiring/TestBackend.ts
@@ -25,6 +25,9 @@ import {
permissionsFactory,
schedulerFactory,
urlReaderFactory,
+ databaseFactory,
+ rootHttpRouterFactory,
+ httpRouterFactory,
} from '@backstage/backend-app-api';
import {
@@ -37,7 +40,6 @@ import {
import {
mockConfigFactory,
- mockDatabaseFactory,
mockTokenManagerFactory,
mockDiscoveryFactory,
} from '../implementations';
@@ -68,16 +70,18 @@ export interface TestBackendOptions<
const defaultServiceFactories = [
cacheFactory(),
- mockConfigFactory(),
- mockDatabaseFactory(),
- mockDiscoveryFactory(),
+ databaseFactory(),
+ httpRouterFactory(),
lifecycleFactory(),
loggerFactory(),
+ mockConfigFactory(),
+ mockDiscoveryFactory(),
+ mockTokenManagerFactory(),
permissionsFactory(),
+ rootHttpRouterFactory(),
rootLifecycleFactory(),
rootLoggerFactory(),
schedulerFactory(),
- mockTokenManagerFactory(),
urlReaderFactory(),
];
From 8f9d0c8fca689455305ba802bd727a8568c59fb4 Mon Sep 17 00:00:00 2001
From: blam
Date: Wed, 4 Jan 2023 17:16:11 +0100
Subject: [PATCH 17/59] chore: explore some of the options for the httpRouter
and fix the shutdown in mutliple tests
Co-authored-by: Patrik Oldsberg
Co-authored-by: Johan Haals
Signed-off-by: blam
---
packages/backend-test-utils/package.json | 6 +-
.../src/next/implementations/index.ts | 1 -
.../implementations/mockDiscoveryService.ts | 40 ---------
.../src/next/wiring/TestBackend.test.ts | 30 ++++++-
.../src/next/wiring/TestBackend.ts | 89 ++++++++++++++++---
yarn.lock | 4 +
6 files changed, 115 insertions(+), 55 deletions(-)
delete mode 100644 packages/backend-test-utils/src/next/implementations/mockDiscoveryService.ts
diff --git a/packages/backend-test-utils/package.json b/packages/backend-test-utils/package.json
index 38db9d6413..ae96f17b8e 100644
--- a/packages/backend-test-utils/package.json
+++ b/packages/backend-test-utils/package.json
@@ -40,6 +40,8 @@
"@backstage/cli": "workspace:^",
"@backstage/config": "workspace:^",
"better-sqlite3": "^8.0.0",
+ "express": "^4.17.1",
+ "express-promise-router": "^4.1.0",
"knex": "^2.0.0",
"msw": "^0.49.0",
"mysql2": "^2.2.5",
@@ -48,7 +50,9 @@
"uuid": "^8.0.0"
},
"devDependencies": {
- "@backstage/cli": "workspace:^"
+ "@backstage/cli": "workspace:^",
+ "@types/supertest": "^2.0.8",
+ "supertest": "^6.1.3"
},
"files": [
"dist",
diff --git a/packages/backend-test-utils/src/next/implementations/index.ts b/packages/backend-test-utils/src/next/implementations/index.ts
index c248502307..2068aebec5 100644
--- a/packages/backend-test-utils/src/next/implementations/index.ts
+++ b/packages/backend-test-utils/src/next/implementations/index.ts
@@ -15,4 +15,3 @@
*/
export { mockTokenManagerFactory } from './mockTokenManagerService';
export { mockConfigFactory } from './mockConfigService';
-export { mockDiscoveryFactory } from './mockDiscoveryService';
diff --git a/packages/backend-test-utils/src/next/implementations/mockDiscoveryService.ts b/packages/backend-test-utils/src/next/implementations/mockDiscoveryService.ts
deleted file mode 100644
index e382d23cbd..0000000000
--- a/packages/backend-test-utils/src/next/implementations/mockDiscoveryService.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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.
- */
-import { SingleHostDiscovery } from '@backstage/backend-common';
-import {
- coreServices,
- createServiceFactory,
-} from '@backstage/backend-plugin-api';
-import { ConfigReader } from '@backstage/config';
-
-/** @public */
-export const mockDiscoveryFactory = createServiceFactory({
- service: coreServices.discovery,
- deps: {},
- async factory() {
- // todo(blam): we want to grab the port from the httpRouter when that's available here
- // to provide a better way to create our mockDiscoveryService.
- const discovery = SingleHostDiscovery.fromConfig(
- new ConfigReader({
- backend: { baseUrl: 'http://localhost:7007', listen: '0.0.0.0' },
- }),
- );
-
- return async () => {
- return discovery;
- };
- },
-});
diff --git a/packages/backend-test-utils/src/next/wiring/TestBackend.test.ts b/packages/backend-test-utils/src/next/wiring/TestBackend.test.ts
index 4c7362880e..6358051c34 100644
--- a/packages/backend-test-utils/src/next/wiring/TestBackend.test.ts
+++ b/packages/backend-test-utils/src/next/wiring/TestBackend.test.ts
@@ -22,6 +22,8 @@ import {
coreServices,
createBackendPlugin,
} from '@backstage/backend-plugin-api';
+import { Router } from 'express';
+import request from 'supertest';
import { startTestBackend } from './TestBackend';
@@ -184,7 +186,7 @@ describe('TestBackend', () => {
urlReader: coreServices.urlReader,
},
async init(deps) {
- expect(Object.keys(deps)).toHaveLength(14);
+ expect(Object.keys(deps)).toHaveLength(15);
expect(Object.values(deps)).not.toContain(undefined);
},
});
@@ -194,6 +196,30 @@ describe('TestBackend', () => {
await startTestBackend({
services: [],
features: [testPlugin()],
- }).then(backend => backend.stop());
+ });
+ });
+
+ it('should allow making requests via supertest', async () => {
+ const testPlugin = createBackendPlugin({
+ id: 'test',
+ register(env) {
+ env.registerInit({
+ deps: {
+ httpRouter: coreServices.httpRouter,
+ },
+ async init({ httpRouter }) {
+ const router = Router();
+ router.use('/ping-me', (_, res) => res.json({ message: 'pong' }));
+ httpRouter.use(router);
+ },
+ });
+ },
+ });
+
+ const { server } = await startTestBackend({ features: [testPlugin()] });
+
+ const res = await request(server).get('/api/test/ping-me');
+ expect(res.status).toEqual(200);
+ expect(res.body).toEqual({ message: 'pong' });
});
});
diff --git a/packages/backend-test-utils/src/next/wiring/TestBackend.ts b/packages/backend-test-utils/src/next/wiring/TestBackend.ts
index 35f138091d..933257426e 100644
--- a/packages/backend-test-utils/src/next/wiring/TestBackend.ts
+++ b/packages/backend-test-utils/src/next/wiring/TestBackend.ts
@@ -26,23 +26,27 @@ import {
schedulerFactory,
urlReaderFactory,
databaseFactory,
- rootHttpRouterFactory,
httpRouterFactory,
} from '@backstage/backend-app-api';
-
+import {
+ createServiceBuilder,
+ SingleHostDiscovery,
+} from '@backstage/backend-common';
+import { Handler } from 'express';
+import * as http from 'http';
+import Router from 'express-promise-router';
import {
ServiceFactory,
ServiceRef,
createServiceFactory,
BackendFeature,
ExtensionPoint,
+ coreServices,
} from '@backstage/backend-plugin-api';
-import {
- mockConfigFactory,
- mockTokenManagerFactory,
- mockDiscoveryFactory,
-} from '../implementations';
+import { mockConfigFactory, mockTokenManagerFactory } from '../implementations';
+import { AddressInfo } from 'net';
+import { ConfigReader } from '@backstage/config';
/** @alpha */
export interface TestBackendOptions<
@@ -75,10 +79,8 @@ const defaultServiceFactories = [
lifecycleFactory(),
loggerFactory(),
mockConfigFactory(),
- mockDiscoveryFactory(),
mockTokenManagerFactory(),
permissionsFactory(),
- rootHttpRouterFactory(),
rootLifecycleFactory(),
rootLoggerFactory(),
schedulerFactory(),
@@ -99,6 +101,71 @@ export async function startTestBackend<
...otherOptions
} = options;
+ let server: http.Server;
+
+ const rootHttpRouterFactory = createServiceFactory({
+ service: coreServices.rootHttpRouter,
+ deps: {
+ config: coreServices.config,
+ lifecycle: coreServices.rootLifecycle,
+ },
+ async factory({ config, lifecycle }) {
+ const router = Router();
+
+ const service = createServiceBuilder(module)
+ .loadConfig(config)
+ .setPort(0);
+
+ service.addRouter('', router);
+
+ server = await service.start();
+ // Stop method isn't part of the public API, let's fix that once we move the implementation here.
+ const stoppableServer = server as typeof server & {
+ stop: (cb: (error?: Error) => void) => void;
+ };
+
+ lifecycle.addShutdownHook({
+ async fn() {
+ await new Promise((resolve, reject) => {
+ stoppableServer.stop((error?: Error) => {
+ if (error) {
+ reject(error);
+ } else {
+ resolve();
+ }
+ });
+ });
+ },
+ labels: { service: 'rootHttpRouter' },
+ });
+
+ return {
+ use: (path: string, handler: Handler) => {
+ router.use(path, handler);
+ },
+ };
+ },
+ });
+
+ const discoveryFactory = createServiceFactory({
+ service: coreServices.discovery,
+ deps: {
+ rootHttpRouter: coreServices.rootHttpRouter,
+ },
+ async factory() {
+ if (!server) {
+ throw new Error('Test server not started yet');
+ }
+ const { port } = server.address() as AddressInfo;
+ const discovery = SingleHostDiscovery.fromConfig(
+ new ConfigReader({
+ backend: { baseUrl: `http://localhost:${port}`, listen: { port } },
+ }),
+ );
+ return async () => discovery;
+ },
+ });
+
const factories = services.map(serviceDef => {
if (Array.isArray(serviceDef)) {
// if type is ExtensionPoint?
@@ -131,7 +198,7 @@ export async function startTestBackend<
const backend = createSpecializedBackend({
...otherOptions,
- services: factories,
+ services: [...factories, rootHttpRouterFactory, discoveryFactory],
});
backendInstancesToCleanUp.push(backend);
@@ -153,7 +220,7 @@ export async function startTestBackend<
await backend.start();
- return backend;
+ return Object.assign(backend, { server: server! }) as Backend;
}
let registered = false;
diff --git a/yarn.lock b/yarn.lock
index 693b5cc3dd..f8957bfc35 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3558,11 +3558,15 @@ __metadata:
"@backstage/backend-plugin-api": "workspace:^"
"@backstage/cli": "workspace:^"
"@backstage/config": "workspace:^"
+ "@types/supertest": ^2.0.8
better-sqlite3: ^8.0.0
+ express: ^4.17.1
+ express-promise-router: ^4.1.0
knex: ^2.0.0
msw: ^0.49.0
mysql2: ^2.2.5
pg: ^8.3.0
+ supertest: ^6.1.3
testcontainers: ^8.1.2
uuid: ^8.0.0
languageName: unknown
From df6a5a9264868bebc39d5cb329d06685ac190d46 Mon Sep 17 00:00:00 2001
From: Patrik Oldsberg
Date: Tue, 10 Jan 2023 15:06:04 +0100
Subject: [PATCH 18/59] backend-app-api: refactor RestrictedIndexedRouter ->
DefaultRootHttpRouter
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: Fredrik Adelöw
Co-authored-by: blam
Co-authored-by: Johan Haals
Signed-off-by: Patrik Oldsberg
---
packages/backend-app-api/api-report.md | 16 +++++++
....test.ts => DefaultRootHttpRouter.test.ts} | 14 ++++--
...exedRouter.ts => DefaultRootHttpRouter.ts} | 43 +++++++++++++++++--
.../implementations/rootHttpRouter/index.ts | 12 ++++--
.../rootHttpRouter/rootHttpRouterFactory.ts | 8 ++--
5 files changed, 77 insertions(+), 16 deletions(-)
rename packages/backend-app-api/src/services/implementations/rootHttpRouter/{RestrictedIndexedRouter.test.ts => DefaultRootHttpRouter.test.ts} (76%)
rename packages/backend-app-api/src/services/implementations/rootHttpRouter/{RestrictedIndexedRouter.ts => DefaultRootHttpRouter.ts} (62%)
diff --git a/packages/backend-app-api/api-report.md b/packages/backend-app-api/api-report.md
index a8f077b760..b1356e93e3 100644
--- a/packages/backend-app-api/api-report.md
+++ b/packages/backend-app-api/api-report.md
@@ -12,6 +12,7 @@ import { CorsOptions } from 'cors';
import { ErrorRequestHandler } from 'express';
import { Express as Express_2 } from 'express';
import { ExtensionPoint } from '@backstage/backend-plugin-api';
+import { Handler } from 'express';
import { HelmetOptions } from 'helmet';
import * as http from 'http';
import { HttpRouterService } from '@backstage/backend-plugin-api';
@@ -79,6 +80,21 @@ export const databaseFactory: (
options?: undefined,
) => ServiceFactory;
+// @public
+export class DefaultRootHttpRouter implements RootHttpRouterService {
+ // (undocumented)
+ static create(options?: DefaultRootHttpRouterOptions): DefaultRootHttpRouter;
+ // (undocumented)
+ handler(): Handler;
+ // (undocumented)
+ use(path: string, handler: Handler): void;
+}
+
+// @public
+export interface DefaultRootHttpRouterOptions {
+ indexPath?: string | false;
+}
+
// @public (undocumented)
export const discoveryFactory: (
options?: undefined,
diff --git a/packages/backend-app-api/src/services/implementations/rootHttpRouter/RestrictedIndexedRouter.test.ts b/packages/backend-app-api/src/services/implementations/rootHttpRouter/DefaultRootHttpRouter.test.ts
similarity index 76%
rename from packages/backend-app-api/src/services/implementations/rootHttpRouter/RestrictedIndexedRouter.test.ts
rename to packages/backend-app-api/src/services/implementations/rootHttpRouter/DefaultRootHttpRouter.test.ts
index b72e87f77b..b72b30e02e 100644
--- a/packages/backend-app-api/src/services/implementations/rootHttpRouter/RestrictedIndexedRouter.test.ts
+++ b/packages/backend-app-api/src/services/implementations/rootHttpRouter/DefaultRootHttpRouter.test.ts
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-import { RestrictedIndexedRouter } from './RestrictedIndexedRouter';
+import { DefaultRootHttpRouter } from './DefaultRootHttpRouter';
-describe('RestrictedIndexedRouter', () => {
+describe('DefaultRootHttpRouter', () => {
it.each([
[['/b'], '/a'],
[['/a'], '/aa/b'],
@@ -25,7 +25,7 @@ describe('RestrictedIndexedRouter', () => {
[['/b/a'], '/a'],
[['/a'], '/aa'],
])(`with existing paths %s, adds %s without conflict`, (existing, added) => {
- const router = new RestrictedIndexedRouter(false);
+ const router = DefaultRootHttpRouter.create();
for (const path of existing) {
router.use(path, () => {});
}
@@ -39,7 +39,7 @@ describe('RestrictedIndexedRouter', () => {
])(
`find conflict when existing paths %s, adds %s`,
(existing, added, conflict) => {
- const router = new RestrictedIndexedRouter(false);
+ const router = DefaultRootHttpRouter.create();
for (const path of existing) {
router.use(path, () => {});
}
@@ -48,4 +48,10 @@ describe('RestrictedIndexedRouter', () => {
);
},
);
+
+ it('should not be possible to supply an empty indexPath', () => {
+ expect(() => DefaultRootHttpRouter.create({ indexPath: '' })).toThrow(
+ 'indexPath option may not be an empty string',
+ );
+ });
});
diff --git a/packages/backend-app-api/src/services/implementations/rootHttpRouter/RestrictedIndexedRouter.ts b/packages/backend-app-api/src/services/implementations/rootHttpRouter/DefaultRootHttpRouter.ts
similarity index 62%
rename from packages/backend-app-api/src/services/implementations/rootHttpRouter/RestrictedIndexedRouter.ts
rename to packages/backend-app-api/src/services/implementations/rootHttpRouter/DefaultRootHttpRouter.ts
index 961277f34d..2acbb3833a 100644
--- a/packages/backend-app-api/src/services/implementations/rootHttpRouter/RestrictedIndexedRouter.ts
+++ b/packages/backend-app-api/src/services/implementations/rootHttpRouter/DefaultRootHttpRouter.ts
@@ -21,18 +21,53 @@ function normalizePath(path: string): string {
return path.replace(/\/*$/, '/');
}
-export class RestrictedIndexedRouter implements RootHttpRouterService {
- #indexPath?: false | string;
+/**
+ * Options for the {@link DefaultRootHttpRouter} class.
+ *
+ * @public
+ */
+export interface DefaultRootHttpRouterOptions {
+ /**
+ * The path to forward all unmatched requests to. Defaults to '/api/app' if
+ * not given. Disables index path behavior if false is given.
+ */
+ indexPath?: string | false;
+}
+
+/**
+ * The default implementation of the {@link @backstage/backend-plugin-api#RootHttpRouterService} interface for
+ * {@link @backstage/backend-plugin-api#coreServices.rootHttpRouter}.
+ *
+ * @public
+ */
+export class DefaultRootHttpRouter implements RootHttpRouterService {
+ #indexPath?: string;
#router = Router();
#namedRoutes = Router();
#indexRouter = Router();
#existingPaths = new Array();
- constructor(indexPath?: false | string) {
+ static create(options?: DefaultRootHttpRouterOptions) {
+ let indexPath;
+ if (options?.indexPath === false) {
+ indexPath = undefined;
+ } else if (options?.indexPath === undefined) {
+ indexPath = '/api/app';
+ } else if (options?.indexPath === '') {
+ throw new Error('indexPath option may not be an empty string');
+ } else {
+ indexPath = options.indexPath;
+ }
+ return new DefaultRootHttpRouter(indexPath);
+ }
+
+ private constructor(indexPath?: string) {
this.#indexPath = indexPath;
this.#router.use(this.#namedRoutes);
- this.#router.use(this.#indexRouter);
+ if (this.#indexPath) {
+ this.#router.use(this.#indexRouter);
+ }
}
use(path: string, handler: Handler) {
diff --git a/packages/backend-app-api/src/services/implementations/rootHttpRouter/index.ts b/packages/backend-app-api/src/services/implementations/rootHttpRouter/index.ts
index 1dfd72273d..e24662df05 100644
--- a/packages/backend-app-api/src/services/implementations/rootHttpRouter/index.ts
+++ b/packages/backend-app-api/src/services/implementations/rootHttpRouter/index.ts
@@ -14,8 +14,12 @@
* limitations under the License.
*/
-export { rootHttpRouterFactory } from './rootHttpRouterFactory';
-export type {
- RootHttpRouterFactoryOptions,
- RootHttpRouterConfigureOptions,
+export {
+ rootHttpRouterFactory,
+ type RootHttpRouterFactoryOptions,
+ type RootHttpRouterConfigureOptions,
} from './rootHttpRouterFactory';
+export {
+ DefaultRootHttpRouter,
+ type DefaultRootHttpRouterOptions,
+} from './DefaultRootHttpRouter';
diff --git a/packages/backend-app-api/src/services/implementations/rootHttpRouter/rootHttpRouterFactory.ts b/packages/backend-app-api/src/services/implementations/rootHttpRouter/rootHttpRouterFactory.ts
index 45cb826b4d..58f8cc2db1 100644
--- a/packages/backend-app-api/src/services/implementations/rootHttpRouter/rootHttpRouterFactory.ts
+++ b/packages/backend-app-api/src/services/implementations/rootHttpRouter/rootHttpRouterFactory.ts
@@ -27,7 +27,7 @@ import {
MiddlewareFactory,
readHttpServerOptions,
} from '../../../http';
-import { RestrictedIndexedRouter } from './RestrictedIndexedRouter';
+import { DefaultRootHttpRouter } from './DefaultRootHttpRouter';
/**
* @public
@@ -46,7 +46,8 @@ export interface RootHttpRouterConfigureOptions {
*/
export type RootHttpRouterFactoryOptions = {
/**
- * The path to forward all unmatched requests to. Defaults to '/api/app'
+ * The path to forward all unmatched requests to. Defaults to '/api/app' if
+ * not given. Disables index path behavior if false is given.
*/
indexPath?: string | false;
@@ -82,11 +83,10 @@ export const rootHttpRouterFactory = createServiceFactory({
configure = defaultConfigure,
}: RootHttpRouterFactoryOptions = {},
) {
- const router = new RestrictedIndexedRouter(indexPath ?? '/api/app');
const logger = rootLogger.child({ service: 'rootHttpRouter' });
-
const app = express();
+ const router = DefaultRootHttpRouter.create({ indexPath });
const middleware = MiddlewareFactory.create({ config, logger });
configure({
From b4b1bd66433e10a7c8e750d1f5cd2f35e055bcd2 Mon Sep 17 00:00:00 2001
From: Patrik Oldsberg
Date: Tue, 10 Jan 2023 15:09:30 +0100
Subject: [PATCH 19/59] backend-test-utils: refactor startTestBackend to use
new http implementation
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: Fredrik Adelöw
Co-authored-by: blam
Co-authored-by: Johan Haals
Signed-off-by: Patrik Oldsberg
---
packages/backend-test-utils/api-report.md | 10 ++-
.../src/next/wiring/TestBackend.ts | 88 +++++++++++--------
.../src/next/wiring/index.ts | 2 +-
3 files changed, 60 insertions(+), 40 deletions(-)
diff --git a/packages/backend-test-utils/api-report.md b/packages/backend-test-utils/api-report.md
index 3df3f3cb21..ad7ecc04dd 100644
--- a/packages/backend-test-utils/api-report.md
+++ b/packages/backend-test-utils/api-report.md
@@ -5,6 +5,7 @@
```ts
import { Backend } from '@backstage/backend-app-api';
import { BackendFeature } from '@backstage/backend-plugin-api';
+import { ExtendedHttpServer } from '@backstage/backend-app-api';
import { ExtensionPoint } from '@backstage/backend-plugin-api';
import { Knex } from 'knex';
import { ServiceFactory } from '@backstage/backend-plugin-api';
@@ -24,7 +25,14 @@ export function setupRequestMockHandlers(worker: {
export function startTestBackend<
TServices extends any[],
TExtensionPoints extends any[],
->(options: TestBackendOptions): Promise;
+>(
+ options: TestBackendOptions,
+): Promise;
+
+// @alpha (undocumented)
+export interface TestBackend extends Backend {
+ readonly server: ExtendedHttpServer;
+}
// @alpha (undocumented)
export interface TestBackendOptions<
diff --git a/packages/backend-test-utils/src/next/wiring/TestBackend.ts b/packages/backend-test-utils/src/next/wiring/TestBackend.ts
index 933257426e..00c38240a3 100644
--- a/packages/backend-test-utils/src/next/wiring/TestBackend.ts
+++ b/packages/backend-test-utils/src/next/wiring/TestBackend.ts
@@ -27,14 +27,12 @@ import {
urlReaderFactory,
databaseFactory,
httpRouterFactory,
+ MiddlewareFactory,
+ createHttpServer,
+ ExtendedHttpServer,
+ DefaultRootHttpRouter,
} from '@backstage/backend-app-api';
-import {
- createServiceBuilder,
- SingleHostDiscovery,
-} from '@backstage/backend-common';
-import { Handler } from 'express';
-import * as http from 'http';
-import Router from 'express-promise-router';
+import { SingleHostDiscovery } from '@backstage/backend-common';
import {
ServiceFactory,
ServiceRef,
@@ -45,8 +43,8 @@ import {
} from '@backstage/backend-plugin-api';
import { mockConfigFactory, mockTokenManagerFactory } from '../implementations';
-import { AddressInfo } from 'net';
import { ConfigReader } from '@backstage/config';
+import express from 'express';
/** @alpha */
export interface TestBackendOptions<
@@ -72,6 +70,17 @@ export interface TestBackendOptions<
features?: BackendFeature[];
}
+/** @alpha */
+export interface TestBackend extends Backend {
+ /**
+ * Provides access to the underling HTTP server for use with utilities
+ * such as `supertest`.
+ *
+ * If the root http router service has been replaced, this will throw an error.
+ */
+ readonly server: ExtendedHttpServer;
+}
+
const defaultServiceFactories = [
cacheFactory(),
databaseFactory(),
@@ -93,7 +102,9 @@ const backendInstancesToCleanUp = new Array();
export async function startTestBackend<
TServices extends any[],
TExtensionPoints extends any[],
->(options: TestBackendOptions): Promise {
+>(
+ options: TestBackendOptions,
+): Promise {
const {
services = [],
extensionPoints = [],
@@ -101,49 +112,43 @@ export async function startTestBackend<
...otherOptions
} = options;
- let server: http.Server;
+ let server: ExtendedHttpServer;
const rootHttpRouterFactory = createServiceFactory({
service: coreServices.rootHttpRouter,
deps: {
config: coreServices.config,
lifecycle: coreServices.rootLifecycle,
+ rootLogger: coreServices.rootLogger,
},
- async factory({ config, lifecycle }) {
- const router = Router();
+ async factory({ config, lifecycle, rootLogger }) {
+ const router = DefaultRootHttpRouter.create();
+ const logger = rootLogger.child({ service: 'rootHttpRouter' });
- const service = createServiceBuilder(module)
- .loadConfig(config)
- .setPort(0);
+ const app = express();
- service.addRouter('', router);
+ const middleware = MiddlewareFactory.create({ config, logger });
- server = await service.start();
- // Stop method isn't part of the public API, let's fix that once we move the implementation here.
- const stoppableServer = server as typeof server & {
- stop: (cb: (error?: Error) => void) => void;
- };
+ app.use(router.handler());
+ app.use(middleware.notFound());
+ app.use(middleware.error());
+
+ server = await createHttpServer(
+ app,
+ { listen: { host: '', port: 0 } },
+ { logger },
+ );
lifecycle.addShutdownHook({
async fn() {
- await new Promise((resolve, reject) => {
- stoppableServer.stop((error?: Error) => {
- if (error) {
- reject(error);
- } else {
- resolve();
- }
- });
- });
+ await server.stop();
},
- labels: { service: 'rootHttpRouter' },
+ logger,
});
- return {
- use: (path: string, handler: Handler) => {
- router.use(path, handler);
- },
- };
+ await server.start();
+
+ return router;
},
});
@@ -156,7 +161,7 @@ export async function startTestBackend<
if (!server) {
throw new Error('Test server not started yet');
}
- const { port } = server.address() as AddressInfo;
+ const port = server.port();
const discovery = SingleHostDiscovery.fromConfig(
new ConfigReader({
backend: { baseUrl: `http://localhost:${port}`, listen: { port } },
@@ -220,7 +225,14 @@ export async function startTestBackend<
await backend.start();
- return Object.assign(backend, { server: server! }) as Backend;
+ return Object.assign(backend, {
+ get server() {
+ if (!server) {
+ throw new Error('TestBackend server is not available');
+ }
+ return server;
+ },
+ });
}
let registered = false;
diff --git a/packages/backend-test-utils/src/next/wiring/index.ts b/packages/backend-test-utils/src/next/wiring/index.ts
index eb7b773e33..7c39474d4c 100644
--- a/packages/backend-test-utils/src/next/wiring/index.ts
+++ b/packages/backend-test-utils/src/next/wiring/index.ts
@@ -15,4 +15,4 @@
*/
export { startTestBackend } from './TestBackend';
-export type { TestBackendOptions } from './TestBackend';
+export type { TestBackend, TestBackendOptions } from './TestBackend';
From 3fad4ed40a7a710d67fd10f4794d02f09bd6f1fc Mon Sep 17 00:00:00 2001
From: Patrik Oldsberg
Date: Tue, 10 Jan 2023 15:13:01 +0100
Subject: [PATCH 20/59] backend-tasks: update API report + changeset for
forPlugin addition
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: Fredrik Adelöw
Co-authored-by: blam
Co-authored-by: Johan Haals
Signed-off-by: Patrik Oldsberg
---
.changeset/hungry-weeks-flash.md | 5 +++++
packages/backend-tasks/api-report.md | 7 +++++++
2 files changed, 12 insertions(+)
create mode 100644 .changeset/hungry-weeks-flash.md
diff --git a/.changeset/hungry-weeks-flash.md b/.changeset/hungry-weeks-flash.md
new file mode 100644
index 0000000000..19cb6cede8
--- /dev/null
+++ b/.changeset/hungry-weeks-flash.md
@@ -0,0 +1,5 @@
+---
+'@backstage/backend-tasks': patch
+---
+
+Added a new static `TaskScheduler.forPlugin` method.
diff --git a/packages/backend-tasks/api-report.md b/packages/backend-tasks/api-report.md
index f7b4782263..44ec4addbe 100644
--- a/packages/backend-tasks/api-report.md
+++ b/packages/backend-tasks/api-report.md
@@ -8,6 +8,7 @@ import { DatabaseManager } from '@backstage/backend-common';
import { Duration } from 'luxon';
import { HumanDuration as HumanDuration_2 } from '@backstage/types';
import { Logger } from 'winston';
+import { PluginDatabaseManager } from '@backstage/backend-common';
// @public @deprecated
export type HumanDuration = HumanDuration_2;
@@ -74,6 +75,12 @@ export class TaskScheduler {
constructor(databaseManager: DatabaseManager, logger: Logger);
forPlugin(pluginId: string): PluginTaskScheduler;
// (undocumented)
+ static forPlugin(opts: {
+ pluginId: string;
+ databaseManager: PluginDatabaseManager;
+ logger: Logger;
+ }): PluginTaskScheduler;
+ // (undocumented)
static fromConfig(
config: Config,
options?: {
From 51b7a7ed070ce1ebbf444aafcb5d77fb4d43db30 Mon Sep 17 00:00:00 2001
From: Patrik Oldsberg
Date: Tue, 10 Jan 2023 15:15:11 +0100
Subject: [PATCH 21/59] changesets: added changesets for default
implementations for test backend
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: Fredrik Adelöw
Co-authored-by: blam
Co-authored-by: Johan Haals
Signed-off-by: Patrik Oldsberg
---
.changeset/proud-cobras-chew.md | 5 +++++
.changeset/shaggy-apricots-camp.md | 5 +++++
2 files changed, 10 insertions(+)
create mode 100644 .changeset/proud-cobras-chew.md
create mode 100644 .changeset/shaggy-apricots-camp.md
diff --git a/.changeset/proud-cobras-chew.md b/.changeset/proud-cobras-chew.md
new file mode 100644
index 0000000000..ae08378715
--- /dev/null
+++ b/.changeset/proud-cobras-chew.md
@@ -0,0 +1,5 @@
+---
+'@backstage/backend-test-utils': patch
+---
+
+The backend started by `startTestBackend` now has default implementations of all core services. It now also returns a `TestBackend` instance, which provides access to the underlying `server` that can be used with testing libraries such as `supertest`.
diff --git a/.changeset/shaggy-apricots-camp.md b/.changeset/shaggy-apricots-camp.md
new file mode 100644
index 0000000000..705dcef0f0
--- /dev/null
+++ b/.changeset/shaggy-apricots-camp.md
@@ -0,0 +1,5 @@
+---
+'@backstage/backend-app-api': patch
+---
+
+Exported the default root HTTP router implementation as `DefaultRootHttpRouter`. It only implements the routing layer and needs to be exposed via an HTTP server similar to the built-in setup in the `rootHttpRouterFactory`.
From ac993deb18d2dda8668bc89e15ebf60313630bb9 Mon Sep 17 00:00:00 2001
From: Patrik Oldsberg
Date: Tue, 10 Jan 2023 15:17:05 +0100
Subject: [PATCH 22/59] backend-test-utils: tweak mockConfigFactory options
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: Fredrik Adelöw
Co-authored-by: blam
Co-authored-by: Johan Haals
Signed-off-by: Patrik Oldsberg
---
packages/backend-test-utils/package.json | 1 +
.../src/next/implementations/mockConfigService.ts | 7 ++++---
yarn.lock | 1 +
3 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/packages/backend-test-utils/package.json b/packages/backend-test-utils/package.json
index ae96f17b8e..725be0d905 100644
--- a/packages/backend-test-utils/package.json
+++ b/packages/backend-test-utils/package.json
@@ -39,6 +39,7 @@
"@backstage/backend-plugin-api": "workspace:^",
"@backstage/cli": "workspace:^",
"@backstage/config": "workspace:^",
+ "@backstage/types": "workspace:^",
"better-sqlite3": "^8.0.0",
"express": "^4.17.1",
"express-promise-router": "^4.1.0",
diff --git a/packages/backend-test-utils/src/next/implementations/mockConfigService.ts b/packages/backend-test-utils/src/next/implementations/mockConfigService.ts
index 976167b473..78a670585d 100644
--- a/packages/backend-test-utils/src/next/implementations/mockConfigService.ts
+++ b/packages/backend-test-utils/src/next/implementations/mockConfigService.ts
@@ -18,13 +18,14 @@ import {
coreServices,
createServiceFactory,
} from '@backstage/backend-plugin-api';
-import { AppConfig, ConfigReader } from '@backstage/config';
+import { ConfigReader } from '@backstage/config';
+import { JsonObject } from '@backstage/types';
/** @public */
export const mockConfigFactory = createServiceFactory({
service: coreServices.config,
deps: {},
- async factory(_, options?: { config?: AppConfig }) {
- return new ConfigReader(options?.config);
+ async factory(_, options?: { data?: JsonObject }) {
+ return new ConfigReader(options?.data, 'mock-config');
},
});
diff --git a/yarn.lock b/yarn.lock
index f8957bfc35..f973dee489 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3558,6 +3558,7 @@ __metadata:
"@backstage/backend-plugin-api": "workspace:^"
"@backstage/cli": "workspace:^"
"@backstage/config": "workspace:^"
+ "@backstage/types": "workspace:^"
"@types/supertest": ^2.0.8
better-sqlite3: ^8.0.0
express: ^4.17.1
From 5541715237ccba49e44321c375c257a1d92e59d3 Mon Sep 17 00:00:00 2001
From: Patrik Oldsberg
Date: Tue, 10 Jan 2023 15:20:11 +0100
Subject: [PATCH 23/59] backend-test-utils: make mock token manager check for
mock tokens
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: Fredrik Adelöw
Co-authored-by: blam
Co-authored-by: Johan Haals
Signed-off-by: Patrik Oldsberg
---
.../src/next/implementations/mockTokenManagerService.ts | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/packages/backend-test-utils/src/next/implementations/mockTokenManagerService.ts b/packages/backend-test-utils/src/next/implementations/mockTokenManagerService.ts
index f68e910e0c..dd1d6b16f7 100644
--- a/packages/backend-test-utils/src/next/implementations/mockTokenManagerService.ts
+++ b/packages/backend-test-utils/src/next/implementations/mockTokenManagerService.ts
@@ -23,7 +23,11 @@ class TokenManagerMock implements TokenManager {
async getToken(): Promise<{ token: string }> {
return { token: 'mock-token' };
}
- async authenticate(): Promise {}
+ async authenticate(token: string): Promise {
+ if (token !== 'mock-token') {
+ throw new Error('Invalid token');
+ }
+ }
}
export const mockTokenManagerFactory = createServiceFactory({
From 54632b830434e26a093161205da1bd337808e6b6 Mon Sep 17 00:00:00 2001
From: blam
Date: Wed, 11 Jan 2023 14:06:45 +0100
Subject: [PATCH 24/59] chore: fix some of the tests by exporting the
`mockConfigFactory` Signed-off-by: blam
Signed-off-by: blam
---
packages/backend-test-utils/api-report.md | 11 +++++
.../src/next/implementations/index.ts | 1 -
packages/backend-test-utils/src/next/index.ts | 1 +
.../src/next/wiring/TestBackend.ts | 3 +-
...etCloudEntityProviderCatalogModule.test.ts | 46 ++++++++-----------
5 files changed, 33 insertions(+), 29 deletions(-)
diff --git a/packages/backend-test-utils/api-report.md b/packages/backend-test-utils/api-report.md
index ad7ecc04dd..85cdb201ef 100644
--- a/packages/backend-test-utils/api-report.md
+++ b/packages/backend-test-utils/api-report.md
@@ -5,8 +5,10 @@
```ts
import { Backend } from '@backstage/backend-app-api';
import { BackendFeature } from '@backstage/backend-plugin-api';
+import { ConfigService } from '@backstage/backend-plugin-api';
import { ExtendedHttpServer } from '@backstage/backend-app-api';
import { ExtensionPoint } from '@backstage/backend-plugin-api';
+import { JsonObject } from '@backstage/types';
import { Knex } from 'knex';
import { ServiceFactory } from '@backstage/backend-plugin-api';
import { ServiceRef } from '@backstage/backend-plugin-api';
@@ -14,6 +16,15 @@ import { ServiceRef } from '@backstage/backend-plugin-api';
// @public (undocumented)
export function isDockerDisabledForTests(): boolean;
+// @public (undocumented)
+export const mockConfigFactory: (
+ options?:
+ | {
+ data?: JsonObject | undefined;
+ }
+ | undefined,
+) => ServiceFactory;
+
// @public
export function setupRequestMockHandlers(worker: {
listen: (t: any) => void;
diff --git a/packages/backend-test-utils/src/next/implementations/index.ts b/packages/backend-test-utils/src/next/implementations/index.ts
index 2068aebec5..55f417f8df 100644
--- a/packages/backend-test-utils/src/next/implementations/index.ts
+++ b/packages/backend-test-utils/src/next/implementations/index.ts
@@ -13,5 +13,4 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-export { mockTokenManagerFactory } from './mockTokenManagerService';
export { mockConfigFactory } from './mockConfigService';
diff --git a/packages/backend-test-utils/src/next/index.ts b/packages/backend-test-utils/src/next/index.ts
index 9bb5431772..9f9edfd837 100644
--- a/packages/backend-test-utils/src/next/index.ts
+++ b/packages/backend-test-utils/src/next/index.ts
@@ -15,3 +15,4 @@
*/
export * from './wiring';
+export * from './implementations';
diff --git a/packages/backend-test-utils/src/next/wiring/TestBackend.ts b/packages/backend-test-utils/src/next/wiring/TestBackend.ts
index 00c38240a3..8fe489750a 100644
--- a/packages/backend-test-utils/src/next/wiring/TestBackend.ts
+++ b/packages/backend-test-utils/src/next/wiring/TestBackend.ts
@@ -42,7 +42,8 @@ import {
coreServices,
} from '@backstage/backend-plugin-api';
-import { mockConfigFactory, mockTokenManagerFactory } from '../implementations';
+import { mockConfigFactory } from '../implementations/mockConfigService';
+import { mockTokenManagerFactory } from '../implementations/mockTokenManagerService';
import { ConfigReader } from '@backstage/config';
import express from 'express';
diff --git a/plugins/catalog-backend-module-bitbucket-cloud/src/service/BitbucketCloudEntityProviderCatalogModule.test.ts b/plugins/catalog-backend-module-bitbucket-cloud/src/service/BitbucketCloudEntityProviderCatalogModule.test.ts
index 83e657bcfe..d44281600c 100644
--- a/plugins/catalog-backend-module-bitbucket-cloud/src/service/BitbucketCloudEntityProviderCatalogModule.test.ts
+++ b/plugins/catalog-backend-module-bitbucket-cloud/src/service/BitbucketCloudEntityProviderCatalogModule.test.ts
@@ -14,18 +14,15 @@
* limitations under the License.
*/
-import { ConfigReader } from '@backstage/config';
-import {
- getVoidLogger,
- PluginEndpointDiscovery,
- TokenManager,
-} from '@backstage/backend-common';
import { coreServices } from '@backstage/backend-plugin-api';
import {
PluginTaskScheduler,
TaskScheduleDefinition,
} from '@backstage/backend-tasks';
-import { startTestBackend } from '@backstage/backend-test-utils';
+import {
+ startTestBackend,
+ mockConfigFactory,
+} from '@backstage/backend-test-utils';
import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node';
import { eventsExtensionPoint } from '@backstage/plugin-events-node';
import { Duration } from 'luxon';
@@ -55,22 +52,6 @@ describe('bitbucketCloudEntityProviderCatalogModule', () => {
return runner;
},
} as unknown as PluginTaskScheduler;
- const discovery = jest.fn() as any as PluginEndpointDiscovery;
- const tokenManager = jest.fn() as any as TokenManager;
-
- const config = new ConfigReader({
- catalog: {
- providers: {
- bitbucketCloud: {
- schedule: {
- frequency: 'P1M',
- timeout: 'PT3M',
- },
- workspace: 'test-ws',
- },
- },
- },
- });
await startTestBackend({
extensionPoints: [
@@ -78,11 +59,22 @@ describe('bitbucketCloudEntityProviderCatalogModule', () => {
[eventsExtensionPoint, eventsExtensionPointImpl],
],
services: [
- [coreServices.config, config],
- [coreServices.discovery, discovery],
- [coreServices.logger, getVoidLogger()],
+ mockConfigFactory({
+ data: {
+ catalog: {
+ providers: {
+ bitbucketCloud: {
+ schedule: {
+ frequency: 'P1M',
+ timeout: 'PT3M',
+ },
+ workspace: 'test-ws',
+ },
+ },
+ },
+ },
+ }),
[coreServices.scheduler, scheduler],
- [coreServices.tokenManager, tokenManager],
],
features: [bitbucketCloudEntityProviderCatalogModule()],
});
From 8c19b84088176069622ae43511cd267007679129 Mon Sep 17 00:00:00 2001
From: blam
Date: Wed, 11 Jan 2023 14:07:02 +0100
Subject: [PATCH 25/59] chore: fix other tests
Signed-off-by: blam
---
plugins/app-backend/package.json | 1 -
.../app-backend/src/service/appPlugin.test.ts | 21 +++----------------
.../package.json | 3 +--
.../catalog-node/src/catalogService.test.ts | 9 +-------
yarn.lock | 9 --------
5 files changed, 5 insertions(+), 38 deletions(-)
diff --git a/plugins/app-backend/package.json b/plugins/app-backend/package.json
index 1f58f64796..d5fbf9f239 100644
--- a/plugins/app-backend/package.json
+++ b/plugins/app-backend/package.json
@@ -56,7 +56,6 @@
"@backstage/cli": "workspace:^",
"@backstage/types": "workspace:^",
"@types/supertest": "^2.0.8",
- "get-port": "^6.1.2",
"mock-fs": "^5.1.0",
"msw": "^0.49.0",
"node-fetch": "^2.6.7",
diff --git a/plugins/app-backend/src/service/appPlugin.test.ts b/plugins/app-backend/src/service/appPlugin.test.ts
index 80408694d6..7c57a5d685 100644
--- a/plugins/app-backend/src/service/appPlugin.test.ts
+++ b/plugins/app-backend/src/service/appPlugin.test.ts
@@ -17,18 +17,14 @@
import mockFs from 'mock-fs';
import { resolve as resolvePath } from 'path';
import fetch from 'node-fetch';
-import { coreServices } from '@backstage/backend-plugin-api';
import { startTestBackend } from '@backstage/backend-test-utils';
import { appPlugin } from './appPlugin';
import {
databaseFactory,
httpRouterFactory,
- rootHttpRouterFactory,
loggerFactory,
rootLoggerFactory,
} from '@backstage/backend-app-api';
-import { ConfigReader } from '@backstage/config';
-import getPort from 'get-port';
describe('appPlugin', () => {
beforeEach(() => {
@@ -48,23 +44,12 @@ describe('appPlugin', () => {
});
it('boots', async () => {
- const port = await getPort();
- await startTestBackend({
+ const { server } = await startTestBackend({
services: [
- [
- coreServices.config,
- new ConfigReader({
- backend: {
- listen: { port },
- database: { client: 'better-sqlite3', connection: ':memory:' },
- },
- }),
- ],
loggerFactory(),
rootLoggerFactory(),
databaseFactory(),
httpRouterFactory(),
- rootHttpRouterFactory(),
],
features: [
appPlugin({
@@ -75,12 +60,12 @@ describe('appPlugin', () => {
});
await expect(
- fetch(`http://localhost:${port}/api/app/derp.html`).then(res =>
+ fetch(`http://localhost:${server.port()}/api/app/derp.html`).then(res =>
res.text(),
),
).resolves.toBe('winning');
await expect(
- fetch(`http://localhost:${port}`).then(res => res.text()),
+ fetch(`http://localhost:${server.port()}`).then(res => res.text()),
).resolves.toBe('winning');
});
});
diff --git a/plugins/catalog-backend-module-incremental-ingestion/package.json b/plugins/catalog-backend-module-incremental-ingestion/package.json
index 06a0ab1c89..a86e27fae4 100644
--- a/plugins/catalog-backend-module-incremental-ingestion/package.json
+++ b/plugins/catalog-backend-module-incremental-ingestion/package.json
@@ -56,8 +56,7 @@
"devDependencies": {
"@backstage/backend-app-api": "workspace:^",
"@backstage/cli": "workspace:^",
- "@backstage/plugin-catalog-backend": "workspace:^",
- "get-port": "^6.1.2"
+ "@backstage/plugin-catalog-backend": "workspace:^"
},
"files": [
"alpha",
diff --git a/plugins/catalog-node/src/catalogService.test.ts b/plugins/catalog-node/src/catalogService.test.ts
index 230af79a88..ec3e5ccf1b 100644
--- a/plugins/catalog-node/src/catalogService.test.ts
+++ b/plugins/catalog-node/src/catalogService.test.ts
@@ -14,11 +14,7 @@
* limitations under the License.
*/
-import { PluginEndpointDiscovery } from '@backstage/backend-common';
-import {
- createBackendModule,
- coreServices,
-} from '@backstage/backend-plugin-api';
+import { createBackendModule } from '@backstage/backend-plugin-api';
import { startTestBackend } from '@backstage/backend-test-utils';
import { CatalogClient } from '@backstage/catalog-client';
import { catalogServiceRef } from './catalogService';
@@ -42,9 +38,6 @@ describe('catalogServiceRef', () => {
});
await startTestBackend({
- services: [
- [coreServices.discovery, {} as unknown as PluginEndpointDiscovery],
- ],
features: [testModule()],
});
});
diff --git a/yarn.lock b/yarn.lock
index f973dee489..0890ba4386 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -4518,7 +4518,6 @@ __metadata:
express: ^4.17.1
express-promise-router: ^4.1.0
fs-extra: 10.1.0
- get-port: ^6.1.2
globby: ^11.0.0
helmet: ^6.0.0
knex: ^2.0.0
@@ -5117,7 +5116,6 @@ __metadata:
"@types/luxon": ^3.0.0
express: ^4.17.1
express-promise-router: ^4.1.0
- get-port: ^6.1.2
knex: ^2.0.0
lodash: ^4.17.21
luxon: ^3.0.0
@@ -23753,13 +23751,6 @@ __metadata:
languageName: node
linkType: hard
-"get-port@npm:^6.1.2":
- version: 6.1.2
- resolution: "get-port@npm:6.1.2"
- checksum: e3c3d591492a11393455ef220f24c812a28f7da56ec3e4a2512d931a1f196d42850b50ac6138349a44622eda6dc3c0ccd8495cd91376d968e2d9e6f6f849e0a9
- languageName: node
- linkType: hard
-
"get-stdin@npm:^8.0.0":
version: 8.0.0
resolution: "get-stdin@npm:8.0.0"
From 28047b353261c809876650051648334067ffa0f7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Adem=C3=ADlson=20F=2E=20Tonato?=
Date: Wed, 11 Jan 2023 14:55:36 +0000
Subject: [PATCH 26/59] style: update footer width in tablet viewports
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Closes #15700
Signed-off-by: Ademílson F. Tonato
---
microsite/static/css/custom.css | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/microsite/static/css/custom.css b/microsite/static/css/custom.css
index e6a230ee52..59f9571a70 100644
--- a/microsite/static/css/custom.css
+++ b/microsite/static/css/custom.css
@@ -1210,7 +1210,8 @@ code {
}
.nav-footer .copyright {
- width: 600px;
+ width: 100%;
+ padding: 0 8px;
color: #fff;
margin: 0 auto;
font-size: 10pt;
From 82f555ea8cddc643461ff872e24af7d3f5a16e70 Mon Sep 17 00:00:00 2001
From: Andrea Giannantonio
Date: Wed, 11 Jan 2023 16:00:03 +0100
Subject: [PATCH 27/59] chore: gitlab plugin replacement
Signed-off-by: Andrea Giannantonio
---
microsite/data/plugins/gitlab.yaml | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/microsite/data/plugins/gitlab.yaml b/microsite/data/plugins/gitlab.yaml
index 689e8004fd..ff815956b5 100644
--- a/microsite/data/plugins/gitlab.yaml
+++ b/microsite/data/plugins/gitlab.yaml
@@ -1,13 +1,14 @@
---
title: GitLab
-author: Loblaw
-authorUrl: https://github.com/loblaw-sre/backstage-plugin-gitlab
+author: ImmobiliareLabs
+authorUrl: https://github.com/immobiliare
category: CI/CD
description: View GitLab pipelines, merge requests, languages and contributors.
-documentation: https://github.com/loblaw-sre/backstage-plugin-gitlab
+documentation: https://github.com/immobiliare/backstage-plugin-gitlab
iconUrl: https://about.gitlab.com/images/press/logo/png/gitlab-icon-rgb.png
-npmPackageName: '@loblaw/backstage-plugin-gitlab'
+npmPackageName: '@immobiliarelabs/backstage-plugin-gitlab'
tags:
- ci
- cd
+ - gitlab
addedDate: '2021-08-17'
From cebe24ef1d60fe83a981f8b49354b65f2f3a3a7f Mon Sep 17 00:00:00 2001
From: Brian Fletcher
Date: Wed, 11 Jan 2023 15:07:33 +0000
Subject: [PATCH 28/59] add entity labels card
Signed-off-by: Brian Fletcher
---
.changeset/many-books-refuse.md | 5 ++
.../app/src/components/catalog/EntityPage.tsx | 5 ++
.../components/shuffle-api-component.yaml | 3 +
.../EntityLabelsCard/EntityLabelsCard.tsx | 86 +++++++++++++++++++
.../EntityLabelsEmptyState.tsx | 68 +++++++++++++++
.../src/components/EntityLabelsCard/index.ts | 17 ++++
plugins/catalog/src/index.ts | 1 +
plugins/catalog/src/plugin.ts | 11 +++
8 files changed, 196 insertions(+)
create mode 100644 .changeset/many-books-refuse.md
create mode 100644 plugins/catalog/src/components/EntityLabelsCard/EntityLabelsCard.tsx
create mode 100644 plugins/catalog/src/components/EntityLabelsCard/EntityLabelsEmptyState.tsx
create mode 100644 plugins/catalog/src/components/EntityLabelsCard/index.ts
diff --git a/.changeset/many-books-refuse.md b/.changeset/many-books-refuse.md
new file mode 100644
index 0000000000..8455254439
--- /dev/null
+++ b/.changeset/many-books-refuse.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-catalog': patch
+---
+
+Add `EntityLabelsCard` to show the labels for an entity.
diff --git a/packages/app/src/components/catalog/EntityPage.tsx b/packages/app/src/components/catalog/EntityPage.tsx
index 02b00f038c..447183298a 100644
--- a/packages/app/src/components/catalog/EntityPage.tsx
+++ b/packages/app/src/components/catalog/EntityPage.tsx
@@ -52,6 +52,7 @@ import {
EntityHasSystemsCard,
EntityLayout,
EntityLinksCard,
+ EntityLabelsCard,
EntityOrphanWarning,
EntityProcessingErrorsPanel,
EntitySwitch,
@@ -364,6 +365,10 @@ const overviewContent = (
+
+
+
+
{cicdCard}
diff --git a/packages/catalog-model/examples/components/shuffle-api-component.yaml b/packages/catalog-model/examples/components/shuffle-api-component.yaml
index 6328ebdf3b..afac3d472d 100644
--- a/packages/catalog-model/examples/components/shuffle-api-component.yaml
+++ b/packages/catalog-model/examples/components/shuffle-api-component.yaml
@@ -3,6 +3,9 @@ kind: Component
metadata:
name: shuffle-api
description: Shuffle API
+ labels:
+ goVersion: go1.15.3
+ category: music
tags:
- go
spec:
diff --git a/plugins/catalog/src/components/EntityLabelsCard/EntityLabelsCard.tsx b/plugins/catalog/src/components/EntityLabelsCard/EntityLabelsCard.tsx
new file mode 100644
index 0000000000..e3bee02c43
--- /dev/null
+++ b/plugins/catalog/src/components/EntityLabelsCard/EntityLabelsCard.tsx
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2022 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 { useEntity } from '@backstage/plugin-catalog-react';
+import React from 'react';
+import {
+ InfoCard,
+ InfoCardVariants,
+ Table,
+ TableColumn,
+} from '@backstage/core-components';
+import { EntityLabelsEmptyState } from './EntityLabelsEmptyState';
+import { makeStyles, Typography } from '@material-ui/core';
+
+/** @public */
+export interface EntityLabelsCardProps {
+ variant?: InfoCardVariants;
+}
+
+const useStyles = makeStyles(_ => ({
+ key: {
+ fontWeight: 'bold',
+ },
+}));
+
+export const EntityLabelsCard = (props: EntityLabelsCardProps) => {
+ const { variant } = props;
+ const { entity } = useEntity();
+ const classes = useStyles();
+
+ const columns: TableColumn<{ key: string; value: string }>[] = [
+ {
+ render: row => {
+ return (
+
+ {row.key}
+
+ );
+ },
+ },
+ {
+ field: 'value',
+ },
+ ];
+
+ const labels = entity?.metadata?.labels;
+
+ return (
+
+ {!labels || Object.keys(labels).length === 0 ? (
+
+ ) : (
+
({
+ key: labelKey,
+ value: labels[labelKey],
+ }))}
+ options={{
+ search: false,
+ showTitle: true,
+ loadingType: 'linear',
+ header: false,
+ padding: 'dense',
+ pageSize: 5,
+ toolbar: false,
+ paging: Object.keys(labels).length > 5,
+ }}
+ />
+ )}
+
+ );
+};
diff --git a/plugins/catalog/src/components/EntityLabelsCard/EntityLabelsEmptyState.tsx b/plugins/catalog/src/components/EntityLabelsCard/EntityLabelsEmptyState.tsx
new file mode 100644
index 0000000000..9fd9f1d3d0
--- /dev/null
+++ b/plugins/catalog/src/components/EntityLabelsCard/EntityLabelsEmptyState.tsx
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+import { BackstageTheme } from '@backstage/theme';
+import { Button, makeStyles, Typography } from '@material-ui/core';
+import React from 'react';
+import { CodeSnippet } from '@backstage/core-components';
+
+const ENTITY_YAML = `metadata:
+ name: example
+ labels:
+ javaVersion: 1.2.3`;
+/** @public */
+export type EntityLabelsEmptyStateClassKey = 'code';
+
+const useStyles = makeStyles(
+ theme => ({
+ code: {
+ borderRadius: 6,
+ margin: `${theme.spacing(2)}px 0px`,
+ background: theme.palette.type === 'dark' ? '#444' : '#fff',
+ },
+ }),
+ { name: 'PluginCatalogEntityLabelsEmptyState' },
+);
+
+export function EntityLabelsEmptyState() {
+ const classes = useStyles();
+
+ return (
+ <>
+
+ No labels defined for this entity. You can add links to your entity YAML
+ as shown in the highlighted example below:
+
+
+
+
+
+ >
+ );
+}
diff --git a/plugins/catalog/src/components/EntityLabelsCard/index.ts b/plugins/catalog/src/components/EntityLabelsCard/index.ts
new file mode 100644
index 0000000000..f7629a766d
--- /dev/null
+++ b/plugins/catalog/src/components/EntityLabelsCard/index.ts
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2022 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 { EntityLabelsCard } from './EntityLabelsCard';
diff --git a/plugins/catalog/src/index.ts b/plugins/catalog/src/index.ts
index 886039e329..8d32de9a06 100644
--- a/plugins/catalog/src/index.ts
+++ b/plugins/catalog/src/index.ts
@@ -50,6 +50,7 @@ export {
EntityHasSubcomponentsCard,
EntityHasSystemsCard,
EntityLinksCard,
+ EntityLabelsCard,
RelatedEntitiesCard,
} from './plugin';
diff --git a/plugins/catalog/src/plugin.ts b/plugins/catalog/src/plugin.ts
index 5419854cb6..c83657b85a 100644
--- a/plugins/catalog/src/plugin.ts
+++ b/plugins/catalog/src/plugin.ts
@@ -126,6 +126,17 @@ export const EntityLinksCard = catalogPlugin.provide(
}),
);
+/** @public */
+export const EntityLabelsCard = catalogPlugin.provide(
+ createComponentExtension({
+ name: 'EntityLabelsCard',
+ component: {
+ lazy: () =>
+ import('./components/EntityLabelsCard').then(m => m.EntityLabelsCard),
+ },
+ }),
+);
+
/** @public */
export const EntityHasSystemsCard: (props: HasSystemsCardProps) => JSX.Element =
catalogPlugin.provide(
From 9a6263105669a0439c05b80347283ddd3f7db66d Mon Sep 17 00:00:00 2001
From: Jussi Hallila
Date: Wed, 11 Jan 2023 16:21:37 +0100
Subject: [PATCH 29/59] Change name of the type of passed in option object.
Signed-off-by: Jussi Hallila
---
plugins/tech-insights-backend/api-report.md | 12 ++++++------
plugins/tech-insights-backend/src/index.ts | 2 +-
.../src/service/persistence/persistenceContext.ts | 6 +++---
3 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/plugins/tech-insights-backend/api-report.md b/plugins/tech-insights-backend/api-report.md
index 7d1d7583ae..a757f0d67c 100644
--- a/plugins/tech-insights-backend/api-report.md
+++ b/plugins/tech-insights-backend/api-report.md
@@ -30,11 +30,6 @@ export const buildTechInsightsContext: <
options: TechInsightsOptions,
) => Promise>;
-// @public
-export type CreateDatabaseOptions = {
- logger: Logger;
-};
-
// @public
export function createFactRetrieverRegistration(
options: FactRetrieverRegistrationOptions,
@@ -85,7 +80,7 @@ export interface FactRetrieverRegistry {
// @public
export const initializePersistenceContext: (
database: PluginDatabaseManager,
- options?: CreateDatabaseOptions,
+ options?: PersistenceContextOptions,
) => Promise;
// @public
@@ -93,6 +88,11 @@ export type PersistenceContext = {
techInsightsStore: TechInsightsStore;
};
+// @public
+export type PersistenceContextOptions = {
+ logger: Logger;
+};
+
// @public
export interface RouterOptions<
CheckType extends TechInsightCheck,
diff --git a/plugins/tech-insights-backend/src/index.ts b/plugins/tech-insights-backend/src/index.ts
index 2071acd263..e9e037cce1 100644
--- a/plugins/tech-insights-backend/src/index.ts
+++ b/plugins/tech-insights-backend/src/index.ts
@@ -26,7 +26,7 @@ export type {
export type { FactRetrieverEngine } from './service/fact/FactRetrieverEngine';
export type {
PersistenceContext,
- CreateDatabaseOptions,
+ PersistenceContextOptions,
} 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/persistenceContext.ts b/plugins/tech-insights-backend/src/service/persistence/persistenceContext.ts
index 87efcd8a3d..07badb038c 100644
--- a/plugins/tech-insights-backend/src/service/persistence/persistenceContext.ts
+++ b/plugins/tech-insights-backend/src/service/persistence/persistenceContext.ts
@@ -41,11 +41,11 @@ export type PersistenceContext = {
*
* @public
*/
-export type CreateDatabaseOptions = {
+export type PersistenceContextOptions = {
logger: Logger;
};
-const defaultOptions: CreateDatabaseOptions = {
+const defaultOptions: PersistenceContextOptions = {
logger: getVoidLogger(),
};
@@ -56,7 +56,7 @@ const defaultOptions: CreateDatabaseOptions = {
*/
export const initializePersistenceContext = async (
database: PluginDatabaseManager,
- options: CreateDatabaseOptions = defaultOptions,
+ options: PersistenceContextOptions = defaultOptions,
): Promise => {
const client = await database.getClient();
From ee0d9b5c4e14062f055c64420de1648f2d94bcce Mon Sep 17 00:00:00 2001
From: Carlos Esteban Lopez
Date: Wed, 11 Jan 2023 13:52:48 -0500
Subject: [PATCH 30/59] fix: Remove duplicated Typography import from master
merge
Signed-off-by: Carlos Esteban Lopez
---
plugins/fossa/src/components/FossaCard/FossaCard.tsx | 1 -
1 file changed, 1 deletion(-)
diff --git a/plugins/fossa/src/components/FossaCard/FossaCard.tsx b/plugins/fossa/src/components/FossaCard/FossaCard.tsx
index a8dc5f46cc..c31f5b9d0c 100644
--- a/plugins/fossa/src/components/FossaCard/FossaCard.tsx
+++ b/plugins/fossa/src/components/FossaCard/FossaCard.tsx
@@ -16,7 +16,6 @@
import { useEntity } from '@backstage/plugin-catalog-react';
import { Grid, Tooltip } from '@material-ui/core';
-import Typography from '@material-ui/core/Typography';
import { makeStyles } from '@material-ui/core/styles';
import Typography from '@material-ui/core/Typography';
import { DateTime } from 'luxon';
From 9fc65bbc38283f3310e4f22e7f3f695bf68db9f6 Mon Sep 17 00:00:00 2001
From: Brian Fletcher
Date: Thu, 12 Jan 2023 07:45:25 +0000
Subject: [PATCH 31/59] add entity switch case
Signed-off-by: Brian Fletcher
---
.../app/src/components/catalog/EntityPage.tsx | 11 +++++--
.../components/EntityLabelsCard/conditions.ts | 29 +++++++++++++++++++
.../src/components/EntityLabelsCard/index.ts | 1 +
plugins/catalog/src/index.ts | 1 +
4 files changed, 39 insertions(+), 3 deletions(-)
create mode 100644 plugins/catalog/src/components/EntityLabelsCard/conditions.ts
diff --git a/packages/app/src/components/catalog/EntityPage.tsx b/packages/app/src/components/catalog/EntityPage.tsx
index 447183298a..3566800f0b 100644
--- a/packages/app/src/components/catalog/EntityPage.tsx
+++ b/packages/app/src/components/catalog/EntityPage.tsx
@@ -60,6 +60,7 @@ import {
isComponentType,
isKind,
isOrphan,
+ hasLabels,
} from '@internal/plugin-catalog-customized';
import {
Direction,
@@ -365,9 +366,13 @@ const overviewContent = (
-
-
-
+
+
+
+
+
+
+
{cicdCard}
diff --git a/plugins/catalog/src/components/EntityLabelsCard/conditions.ts b/plugins/catalog/src/components/EntityLabelsCard/conditions.ts
new file mode 100644
index 0000000000..fb4678cded
--- /dev/null
+++ b/plugins/catalog/src/components/EntityLabelsCard/conditions.ts
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+import { Entity } from '@backstage/catalog-model';
+
+/**
+ * Returns true if the given entity has labels annotation given by the
+ * catalog. For use by EntitySwitch
+ *
+ * @public
+ */
+export function hasLabels(entity: Entity) {
+ return entity?.metadata?.labels
+ ? Object.keys(entity?.metadata?.labels).some(Boolean)
+ : false;
+}
diff --git a/plugins/catalog/src/components/EntityLabelsCard/index.ts b/plugins/catalog/src/components/EntityLabelsCard/index.ts
index f7629a766d..bb8570d67c 100644
--- a/plugins/catalog/src/components/EntityLabelsCard/index.ts
+++ b/plugins/catalog/src/components/EntityLabelsCard/index.ts
@@ -15,3 +15,4 @@
*/
export { EntityLabelsCard } from './EntityLabelsCard';
+export * from './conditions';
diff --git a/plugins/catalog/src/index.ts b/plugins/catalog/src/index.ts
index 8d32de9a06..7de332cf51 100644
--- a/plugins/catalog/src/index.ts
+++ b/plugins/catalog/src/index.ts
@@ -37,6 +37,7 @@ export * from './components/EntityProcessingErrorsPanel';
export * from './components/EntitySwitch';
export * from './components/FilteredEntityLayout';
export * from './overridableComponents';
+export * from './components/EntityLabelsCard';
export {
CatalogEntityPage,
CatalogIndexPage,
From bd382f2bc2aa2460cc6a9e53c245107825105386 Mon Sep 17 00:00:00 2001
From: Brian Fletcher
Date: Thu, 12 Jan 2023 07:59:25 +0000
Subject: [PATCH 32/59] api reports and changeset
Signed-off-by: Brian Fletcher
---
.changeset/forty-ligers-teach.md | 5 +++++
plugins/catalog/api-report.md | 12 ++++++++++++
.../catalog/src/components/EntityLabelsCard/index.ts | 1 +
3 files changed, 18 insertions(+)
create mode 100644 .changeset/forty-ligers-teach.md
diff --git a/.changeset/forty-ligers-teach.md b/.changeset/forty-ligers-teach.md
new file mode 100644
index 0000000000..31abd1895d
--- /dev/null
+++ b/.changeset/forty-ligers-teach.md
@@ -0,0 +1,5 @@
+---
+'@backstage/catalog-model': patch
+---
+
+Add labels to one of the example entities.
diff --git a/plugins/catalog/api-report.md b/plugins/catalog/api-report.md
index 74f64882a8..ada173fd5d 100644
--- a/plugins/catalog/api-report.md
+++ b/plugins/catalog/api-report.md
@@ -277,6 +277,15 @@ export const EntityHasSubcomponentsCard: (
// @public (undocumented)
export const EntityHasSystemsCard: (props: HasSystemsCardProps) => JSX.Element;
+// @public (undocumented)
+export const EntityLabelsCard: (props: EntityLabelsCardProps) => JSX.Element;
+
+// @public (undocumented)
+export interface EntityLabelsCardProps {
+ // (undocumented)
+ variant?: InfoCardVariants;
+}
+
// @public
export const EntityLayout: {
(props: EntityLayoutProps): JSX.Element;
@@ -385,6 +394,9 @@ export interface HasComponentsCardProps {
variant?: InfoCardVariants;
}
+// @public
+export function hasLabels(entity: Entity): boolean;
+
// @public (undocumented)
export interface HasResourcesCardProps {
// (undocumented)
diff --git a/plugins/catalog/src/components/EntityLabelsCard/index.ts b/plugins/catalog/src/components/EntityLabelsCard/index.ts
index bb8570d67c..870819f9a7 100644
--- a/plugins/catalog/src/components/EntityLabelsCard/index.ts
+++ b/plugins/catalog/src/components/EntityLabelsCard/index.ts
@@ -16,3 +16,4 @@
export { EntityLabelsCard } from './EntityLabelsCard';
export * from './conditions';
+export type { EntityLabelsCardProps } from './EntityLabelsCard';
From 9ef778c4b55582a5f9fd0c2bb66e2ba66f24edb3 Mon Sep 17 00:00:00 2001
From: Brian Fletcher
Date: Thu, 12 Jan 2023 08:13:06 +0000
Subject: [PATCH 33/59] fix missing message
Signed-off-by: Brian Fletcher
---
.../components/EntityLabelsCard/EntityLabelsEmptyState.tsx | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/plugins/catalog/src/components/EntityLabelsCard/EntityLabelsEmptyState.tsx b/plugins/catalog/src/components/EntityLabelsCard/EntityLabelsEmptyState.tsx
index 9fd9f1d3d0..a0d78acb11 100644
--- a/plugins/catalog/src/components/EntityLabelsCard/EntityLabelsEmptyState.tsx
+++ b/plugins/catalog/src/components/EntityLabelsCard/EntityLabelsEmptyState.tsx
@@ -43,8 +43,8 @@ export function EntityLabelsEmptyState() {
return (
<>
- No labels defined for this entity. You can add links to your entity YAML
- as shown in the highlighted example below:
+ No labels defined for this entity. You can add labels to your entity
+ YAML as shown in the highlighted example below: