;
+ 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 014/255] 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 015/255] 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 016/255] 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 a6808b67a777ad43b705017212b5e73fe5f73343 Mon Sep 17 00:00:00 2001
From: Trevor Grieger
Date: Wed, 11 Jan 2023 00:29:48 -0500
Subject: [PATCH 017/255] Add features for "publish:github" action
Implement "Required approving review count", "Restrictions", and "Required commit signing" support for "publish:github" action.
Signed-off-by: Trevor Grieger
---
.changeset/angry-cheetahs-hide.md | 5 +++
plugins/scaffolder-backend/api-report.md | 27 ++++++++++++
.../builtin/github/githubRepoCreate.ts | 10 +++++
.../actions/builtin/github/githubRepoPush.ts | 18 ++++++++
.../actions/builtin/github/helpers.ts | 12 ++++++
.../actions/builtin/github/inputProperties.ts | 43 +++++++++++++++++++
.../src/scaffolder/actions/builtin/helpers.ts | 22 +++++++++-
.../actions/builtin/publish/github.ts | 18 ++++++++
8 files changed, 153 insertions(+), 2 deletions(-)
create mode 100644 .changeset/angry-cheetahs-hide.md
diff --git a/.changeset/angry-cheetahs-hide.md b/.changeset/angry-cheetahs-hide.md
new file mode 100644
index 0000000000..d294c507e9
--- /dev/null
+++ b/.changeset/angry-cheetahs-hide.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-scaffolder-backend': patch
+---
+
+Implement "Required approving review count", "Restrictions", and "Required commit signing" support for "publish:github" action
diff --git a/plugins/scaffolder-backend/api-report.md b/plugins/scaffolder-backend/api-report.md
index c89ead6d2b..3e25311ca6 100644
--- a/plugins/scaffolder-backend/api-report.md
+++ b/plugins/scaffolder-backend/api-report.md
@@ -211,6 +211,14 @@ export function createGithubRepoCreateAction(options: {
apps?: string[] | undefined;
}
| undefined;
+ requiredApprovingReviewCount?: number | undefined;
+ restrictions?:
+ | {
+ users: string[] | undefined;
+ teams: string[] | undefined;
+ apps?: string[] | undefined;
+ }
+ | undefined;
requiredStatusCheckContexts?: string[] | undefined;
requireBranchesToBeUpToDate?: boolean | undefined;
requiredConversationResolution?: boolean | undefined;
@@ -236,6 +244,7 @@ export function createGithubRepoCreateAction(options: {
hasIssues?: boolean | undefined;
token?: string | undefined;
topics?: string[] | undefined;
+ requireCommitSigning?: boolean | undefined;
}>;
// @public
@@ -261,11 +270,20 @@ export function createGithubRepoPushAction(options: {
apps?: string[];
}
| undefined;
+ requiredApprovingReviewCount?: number | undefined;
+ restrictions?:
+ | {
+ users: string[] | undefined;
+ teams: string[] | undefined;
+ apps?: string[] | undefined;
+ }
+ | undefined;
requiredStatusCheckContexts?: string[] | undefined;
requireBranchesToBeUpToDate?: boolean | undefined;
requiredConversationResolution?: boolean | undefined;
sourcePath?: string | undefined;
token?: string | undefined;
+ requireCommitSigning?: boolean | undefined;
}>;
// @public
@@ -405,6 +423,14 @@ export function createPublishGithubAction(options: {
apps?: string[];
}
| undefined;
+ requiredApprovingReviewCount?: number | undefined;
+ restrictions?:
+ | {
+ users: string[] | undefined;
+ teams: string[] | undefined;
+ apps?: string[] | undefined;
+ }
+ | undefined;
requireCodeOwnerReviews?: boolean | undefined;
dismissStaleReviews?: boolean | undefined;
requiredStatusCheckContexts?: string[] | undefined;
@@ -432,6 +458,7 @@ export function createPublishGithubAction(options: {
hasIssues?: boolean | undefined;
token?: string | undefined;
topics?: string[] | undefined;
+ requireCommitSigning?: boolean | undefined;
}>;
// @public
diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoCreate.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoCreate.ts
index f41150b504..835fc79238 100644
--- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoCreate.ts
+++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoCreate.ts
@@ -59,6 +59,12 @@ export function createGithubRepoCreateAction(options: {
teams?: string[];
apps?: string[];
};
+ requiredApprovingReviewCount?: number;
+ restrictions?: {
+ users: string[];
+ teams: string[];
+ apps?: string[];
+ };
requiredStatusCheckContexts?: string[];
requireBranchesToBeUpToDate?: boolean;
requiredConversationResolution?: boolean;
@@ -83,6 +89,7 @@ export function createGithubRepoCreateAction(options: {
hasIssues?: boolean;
token?: string;
topics?: string[];
+ requireCommitSigning?: boolean;
}>({
id: 'github:repo:create',
description: 'Creates a GitHub repository.',
@@ -97,6 +104,8 @@ export function createGithubRepoCreateAction(options: {
access: inputProps.access,
requireCodeOwnerReviews: inputProps.requireCodeOwnerReviews,
bypassPullRequestAllowances: inputProps.bypassPullRequestAllowances,
+ requiredApprovingReviewCount: inputProps.requiredApprovingReviewCount,
+ restrictions: inputProps.restrictions,
requiredStatusCheckContexts: inputProps.requiredStatusCheckContexts,
requireBranchesToBeUpToDate: inputProps.requireBranchesToBeUpToDate,
requiredConversationResolution:
@@ -115,6 +124,7 @@ export function createGithubRepoCreateAction(options: {
hasIssues: inputProps.hasIssues,
token: inputProps.token,
topics: inputProps.topics,
+ requiredCommitSigning: inputProps.requiredCommitSigning,
},
},
output: {
diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoPush.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoPush.ts
index 9d470790fa..5a5ffc015c 100644
--- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoPush.ts
+++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoPush.ts
@@ -57,11 +57,20 @@ export function createGithubRepoPushAction(options: {
apps?: string[];
}
| undefined;
+ requiredApprovingReviewCount?: number;
+ restrictions?:
+ | {
+ users: string[];
+ teams: string[];
+ apps?: string[];
+ }
+ | undefined;
requiredStatusCheckContexts?: string[];
requireBranchesToBeUpToDate?: boolean;
requiredConversationResolution?: boolean;
sourcePath?: string;
token?: string;
+ requiredCommitSigning?: boolean;
}>({
id: 'github:repo:push',
description:
@@ -76,6 +85,8 @@ export function createGithubRepoPushAction(options: {
dismissStaleReviews: inputProps.dismissStaleReviews,
requiredStatusCheckContexts: inputProps.requiredStatusCheckContexts,
bypassPullRequestAllowances: inputProps.bypassPullRequestAllowances,
+ requiredApprovingReviewCount: inputProps.requiredApprovingReviewCount,
+ restrictions: inputProps.restrictions,
requireBranchesToBeUpToDate: inputProps.requireBranchesToBeUpToDate,
requiredConversationResolution:
inputProps.requiredConversationResolution,
@@ -87,6 +98,7 @@ export function createGithubRepoPushAction(options: {
gitAuthorEmail: inputProps.gitAuthorEmail,
sourcePath: inputProps.sourcePath,
token: inputProps.token,
+ requiredCommitSigning: inputProps.requiredCommitSigning,
},
},
output: {
@@ -109,10 +121,13 @@ export function createGithubRepoPushAction(options: {
requireCodeOwnerReviews = false,
dismissStaleReviews = false,
bypassPullRequestAllowances,
+ requiredApprovingReviewCount = 1,
+ restrictions,
requiredStatusCheckContexts = [],
requireBranchesToBeUpToDate = true,
requiredConversationResolution = false,
token: providedToken,
+ requiredCommitSigning = false,
} = ctx.input;
const { owner, repo } = parseRepoUrl(repoUrl, integrations);
@@ -148,6 +163,8 @@ export function createGithubRepoPushAction(options: {
repo,
requireCodeOwnerReviews,
bypassPullRequestAllowances,
+ requiredApprovingReviewCount,
+ restrictions,
requiredStatusCheckContexts,
requireBranchesToBeUpToDate,
requiredConversationResolution,
@@ -157,6 +174,7 @@ export function createGithubRepoPushAction(options: {
gitAuthorName,
gitAuthorEmail,
dismissStaleReviews,
+ requiredCommitSigning,
);
ctx.output('remoteUrl', remoteUrl);
diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/helpers.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/helpers.ts
index 9caee49f98..dae5e16374 100644
--- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/helpers.ts
+++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/helpers.ts
@@ -271,6 +271,14 @@ export async function initRepoPushAndProtect(
apps?: string[];
}
| undefined,
+ requiredApprovingReviewCount: number,
+ restrictions:
+ | {
+ users: string[];
+ teams: string[];
+ apps?: string[];
+ }
+ | undefined,
requiredStatusCheckContexts: string[],
requireBranchesToBeUpToDate: boolean,
requiredConversationResolution: boolean,
@@ -280,6 +288,7 @@ export async function initRepoPushAndProtect(
gitAuthorName?: string,
gitAuthorEmail?: string,
dismissStaleReviews?: boolean,
+ requiredCommitSigning?: boolean,
) {
const gitAuthorInfo = {
name: gitAuthorName
@@ -316,12 +325,15 @@ export async function initRepoPushAndProtect(
logger,
defaultBranch,
bypassPullRequestAllowances,
+ requiredApprovingReviewCount,
+ restrictions,
requireCodeOwnerReviews,
requiredStatusCheckContexts,
requireBranchesToBeUpToDate,
requiredConversationResolution,
enforceAdmins: protectEnforceAdmins,
dismissStaleReviews: dismissStaleReviews,
+ requiredCommitSigning: requiredCommitSigning,
});
} catch (e) {
assertError(e);
diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/inputProperties.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/inputProperties.ts
index 3fc7126754..b1286953a6 100644
--- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/inputProperties.ts
+++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/inputProperties.ts
@@ -225,6 +225,46 @@ const sourcePath = {
type: 'string',
};
+const requiredApprovingReviewCount = {
+ title: 'Required approving review count',
+ type: 'number',
+ description: `Specify the number of reviewers required to approve pull requests. Use a number between 1 and 6 or 0 to not require reviewers. Defaults to 1.`,
+};
+
+const restrictions = {
+ title: 'Restrict who can push to the protected branch',
+ description:
+ 'Restrict who can push to the protected branch. User, app, and team restrictions are only available for organization-owned repositories.',
+ type: 'object',
+ additionalProperties: false,
+ properties: {
+ apps: {
+ type: 'array',
+ items: {
+ type: 'string',
+ },
+ },
+ users: {
+ type: 'array',
+ items: {
+ type: 'string',
+ },
+ },
+ teams: {
+ type: 'array',
+ items: {
+ type: 'string',
+ },
+ },
+ },
+};
+
+const requiredCommitSigning = {
+ title: 'Require commit signing',
+ type: 'boolean',
+ description: `Require commit signing so that you must sign commits on this branch.`,
+};
+
export { access };
export { allowMergeCommit };
export { allowRebaseMerge };
@@ -243,6 +283,8 @@ export { homepage };
export { protectDefaultBranch };
export { protectEnforceAdmins };
export { bypassPullRequestAllowances };
+export { requiredApprovingReviewCount };
+export { restrictions };
export { repoUrl };
export { repoVisibility };
export { requireCodeOwnerReviews };
@@ -256,3 +298,4 @@ export { hasWiki };
export { sourcePath };
export { token };
export { topics };
+export { requiredCommitSigning };
diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/helpers.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/helpers.ts
index 74e5d4580b..8bed279a1b 100644
--- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/helpers.ts
+++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/helpers.ts
@@ -190,11 +190,18 @@ type BranchProtectionOptions = {
teams?: string[];
apps?: string[];
};
+ requiredApprovingReviewCount?: number;
+ restrictions?: {
+ users: string[];
+ teams: string[];
+ apps?: string[];
+ };
requireBranchesToBeUpToDate?: boolean;
requiredConversationResolution?: boolean;
defaultBranch?: string;
enforceAdmins?: boolean;
dismissStaleReviews?: boolean;
+ requiredCommitSigning?: boolean;
};
export const enableBranchProtectionOnDefaultRepoBranch = async ({
@@ -204,12 +211,15 @@ export const enableBranchProtectionOnDefaultRepoBranch = async ({
logger,
requireCodeOwnerReviews,
bypassPullRequestAllowances,
+ requiredApprovingReviewCount,
+ restrictions,
requiredStatusCheckContexts = [],
requireBranchesToBeUpToDate = true,
requiredConversationResolution = false,
defaultBranch = 'master',
enforceAdmins = true,
dismissStaleReviews = false,
+ requiredCommitSigning = false,
}: BranchProtectionOptions): Promise => {
const tryOnce = async () => {
try {
@@ -231,16 +241,24 @@ export const enableBranchProtectionOnDefaultRepoBranch = async ({
strict: requireBranchesToBeUpToDate,
contexts: requiredStatusCheckContexts,
},
- restrictions: null,
+ restrictions: restrictions ?? null,
enforce_admins: enforceAdmins,
required_pull_request_reviews: {
- required_approving_review_count: 1,
+ required_approving_review_count: requiredApprovingReviewCount,
require_code_owner_reviews: requireCodeOwnerReviews,
bypass_pull_request_allowances: bypassPullRequestAllowances,
dismiss_stale_reviews: dismissStaleReviews,
},
required_conversation_resolution: requiredConversationResolution,
});
+
+ if (requiredCommitSigning) {
+ await client.rest.repos.createCommitSignatureProtection({
+ owner,
+ repo: repoName,
+ branch: defaultBranch,
+ });
+ }
} catch (e) {
assertError(e);
if (
diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.ts
index 5430f30657..add6fcc79c 100644
--- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.ts
+++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.ts
@@ -69,6 +69,14 @@ export function createPublishGithubAction(options: {
apps?: string[];
}
| undefined;
+ requiredApprovingReviewCount?: number;
+ restrictions?:
+ | {
+ users: string[];
+ teams: string[];
+ apps?: string[];
+ }
+ | undefined;
requireCodeOwnerReviews?: boolean;
dismissStaleReviews?: boolean;
requiredStatusCheckContexts?: string[];
@@ -95,6 +103,7 @@ export function createPublishGithubAction(options: {
hasIssues?: boolean | undefined;
token?: string;
topics?: string[];
+ requiredCommitSigning?: boolean;
}>({
id: 'publish:github',
description:
@@ -109,6 +118,8 @@ export function createPublishGithubAction(options: {
homepage: inputProps.homepage,
access: inputProps.access,
bypassPullRequestAllowances: inputProps.bypassPullRequestAllowances,
+ requiredApprovingReviewCount: inputProps.requiredApprovingReviewCount,
+ restrictions: inputProps.restrictions,
requireCodeOwnerReviews: inputProps.requireCodeOwnerReviews,
dismissStaleReviews: inputProps.dismissStaleReviews,
requiredStatusCheckContexts: inputProps.requiredStatusCheckContexts,
@@ -136,6 +147,7 @@ export function createPublishGithubAction(options: {
hasIssues: inputProps.hasIssues,
token: inputProps.token,
topics: inputProps.topics,
+ requiredCommitSigning: inputProps.requiredCommitSigning,
},
},
output: {
@@ -155,6 +167,8 @@ export function createPublishGithubAction(options: {
requireCodeOwnerReviews = false,
dismissStaleReviews = false,
bypassPullRequestAllowances,
+ requiredApprovingReviewCount = 1,
+ restrictions,
requiredStatusCheckContexts = [],
requireBranchesToBeUpToDate = true,
requiredConversationResolution = false,
@@ -178,6 +192,7 @@ export function createPublishGithubAction(options: {
hasIssues = undefined,
topics,
token: providedToken,
+ requiredCommitSigning = false,
} = ctx.input;
const octokitOptions = await getOctokitOptions({
@@ -233,6 +248,8 @@ export function createPublishGithubAction(options: {
repo,
requireCodeOwnerReviews,
bypassPullRequestAllowances,
+ requiredApprovingReviewCount,
+ restrictions,
requiredStatusCheckContexts,
requireBranchesToBeUpToDate,
requiredConversationResolution,
@@ -242,6 +259,7 @@ export function createPublishGithubAction(options: {
gitAuthorName,
gitAuthorEmail,
dismissStaleReviews,
+ requiredCommitSigning,
);
ctx.output('remoteUrl', remoteUrl);
From 33de5bd8272cde55bfa567181b3753fbf15958f9 Mon Sep 17 00:00:00 2001
From: Trevor Grieger
Date: Wed, 11 Jan 2023 01:21:47 -0500
Subject: [PATCH 018/255] Update failing mocked tests
Signed-off-by: Trevor Grieger
---
.../builtin/github/githubRepoPush.test.ts | 64 ++++++++++++++++++
.../actions/builtin/publish/github.test.ts | 66 ++++++++++++++++++-
2 files changed, 129 insertions(+), 1 deletion(-)
diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoPush.test.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoPush.test.ts
index f8b45093e6..24777163d4 100644
--- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoPush.test.ts
+++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoPush.test.ts
@@ -287,6 +287,10 @@ describe('github:repo:push', () => {
requiredConversationResolution: false,
enforceAdmins: true,
dismissStaleReviews: false,
+ bypassPullRequestAllowances: undefined,
+ requiredApprovingReviewCount: 1,
+ requiredCommitSigning: false,
+ restrictions: undefined,
});
await action.handler({
@@ -309,6 +313,10 @@ describe('github:repo:push', () => {
requiredConversationResolution: false,
enforceAdmins: true,
dismissStaleReviews: false,
+ bypassPullRequestAllowances: undefined,
+ requiredApprovingReviewCount: 1,
+ requiredCommitSigning: false,
+ restrictions: undefined,
});
await action.handler({
@@ -331,6 +339,10 @@ describe('github:repo:push', () => {
requiredConversationResolution: false,
enforceAdmins: true,
dismissStaleReviews: false,
+ bypassPullRequestAllowances: undefined,
+ requiredApprovingReviewCount: 1,
+ requiredCommitSigning: false,
+ restrictions: undefined,
});
});
@@ -356,6 +368,10 @@ describe('github:repo:push', () => {
requiredConversationResolution: false,
enforceAdmins: true,
dismissStaleReviews: false,
+ bypassPullRequestAllowances: undefined,
+ requiredApprovingReviewCount: 1,
+ requiredCommitSigning: false,
+ restrictions: undefined,
});
await action.handler({
@@ -378,6 +394,10 @@ describe('github:repo:push', () => {
requiredConversationResolution: false,
enforceAdmins: true,
dismissStaleReviews: false,
+ bypassPullRequestAllowances: undefined,
+ requiredApprovingReviewCount: 1,
+ requiredCommitSigning: false,
+ restrictions: undefined,
});
await action.handler({
@@ -400,6 +420,10 @@ describe('github:repo:push', () => {
requiredConversationResolution: false,
enforceAdmins: false,
dismissStaleReviews: false,
+ bypassPullRequestAllowances: undefined,
+ requiredApprovingReviewCount: 1,
+ requiredCommitSigning: false,
+ restrictions: undefined,
});
});
@@ -425,6 +449,10 @@ describe('github:repo:push', () => {
requiredConversationResolution: false,
enforceAdmins: true,
dismissStaleReviews: false,
+ bypassPullRequestAllowances: undefined,
+ requiredApprovingReviewCount: 1,
+ requiredCommitSigning: false,
+ restrictions: undefined,
});
await action.handler({
@@ -449,6 +477,10 @@ describe('github:repo:push', () => {
requiredConversationResolution: false,
enforceAdmins: true,
dismissStaleReviews: false,
+ bypassPullRequestAllowances: undefined,
+ requiredApprovingReviewCount: 1,
+ requiredCommitSigning: false,
+ restrictions: undefined,
});
await action.handler({
@@ -472,6 +504,10 @@ describe('github:repo:push', () => {
requiredConversationResolution: false,
enforceAdmins: true,
dismissStaleReviews: false,
+ bypassPullRequestAllowances: undefined,
+ requiredApprovingReviewCount: 1,
+ requiredCommitSigning: false,
+ restrictions: undefined,
});
await action.handler({
@@ -496,6 +532,10 @@ describe('github:repo:push', () => {
requiredConversationResolution: false,
enforceAdmins: true,
dismissStaleReviews: false,
+ bypassPullRequestAllowances: undefined,
+ requiredApprovingReviewCount: 1,
+ requiredCommitSigning: false,
+ restrictions: undefined,
});
});
@@ -540,6 +580,10 @@ describe('github:repo:push', () => {
requiredConversationResolution: false,
enforceAdmins: true,
dismissStaleReviews: false,
+ bypassPullRequestAllowances: undefined,
+ requiredApprovingReviewCount: 1,
+ requiredCommitSigning: false,
+ restrictions: undefined,
});
await action.handler({
@@ -562,6 +606,10 @@ describe('github:repo:push', () => {
requiredConversationResolution: false,
enforceAdmins: true,
dismissStaleReviews: true,
+ bypassPullRequestAllowances: undefined,
+ requiredApprovingReviewCount: 1,
+ requiredCommitSigning: false,
+ restrictions: undefined,
});
await action.handler({
@@ -584,6 +632,10 @@ describe('github:repo:push', () => {
requiredConversationResolution: false,
enforceAdmins: true,
dismissStaleReviews: false,
+ bypassPullRequestAllowances: undefined,
+ requiredApprovingReviewCount: 1,
+ requiredCommitSigning: false,
+ restrictions: undefined,
});
});
@@ -609,6 +661,10 @@ describe('github:repo:push', () => {
requiredConversationResolution: false,
enforceAdmins: true,
dismissStaleReviews: false,
+ bypassPullRequestAllowances: undefined,
+ requiredApprovingReviewCount: 1,
+ requiredCommitSigning: false,
+ restrictions: undefined,
});
await action.handler({
@@ -631,6 +687,10 @@ describe('github:repo:push', () => {
requiredConversationResolution: true,
enforceAdmins: true,
dismissStaleReviews: false,
+ bypassPullRequestAllowances: undefined,
+ requiredApprovingReviewCount: 1,
+ requiredCommitSigning: false,
+ restrictions: undefined,
});
await action.handler({
@@ -653,6 +713,10 @@ describe('github:repo:push', () => {
requiredConversationResolution: false,
enforceAdmins: true,
dismissStaleReviews: false,
+ bypassPullRequestAllowances: undefined,
+ requiredApprovingReviewCount: 1,
+ requiredCommitSigning: false,
+ restrictions: undefined,
});
});
});
diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.test.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.test.ts
index e4c92c624e..95ad8b5e40 100644
--- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.test.ts
+++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.test.ts
@@ -788,11 +788,15 @@ describe('publish:github', () => {
logger: mockContext.logger,
defaultBranch: 'master',
requireCodeOwnerReviews: false,
+ bypassPullRequestAllowances: undefined,
+ requiredApprovingReviewCount: 1,
+ restrictions: undefined,
requiredStatusCheckContexts: [],
requireBranchesToBeUpToDate: true,
requiredConversationResolution: false,
enforceAdmins: true,
dismissStaleReviews: false,
+ requiredCommitSigning: false,
});
await action.handler({
@@ -810,11 +814,15 @@ describe('publish:github', () => {
logger: mockContext.logger,
defaultBranch: 'master',
requireCodeOwnerReviews: true,
+ bypassPullRequestAllowances: undefined,
+ requiredApprovingReviewCount: 1,
+ restrictions: undefined,
requiredStatusCheckContexts: [],
requireBranchesToBeUpToDate: true,
requiredConversationResolution: false,
enforceAdmins: true,
dismissStaleReviews: false,
+ requiredCommitSigning: false,
});
await action.handler({
@@ -832,11 +840,15 @@ describe('publish:github', () => {
logger: mockContext.logger,
defaultBranch: 'master',
requireCodeOwnerReviews: false,
+ bypassPullRequestAllowances: undefined,
+ requiredApprovingReviewCount: 1,
+ restrictions: undefined,
requiredStatusCheckContexts: [],
requireBranchesToBeUpToDate: true,
requiredConversationResolution: false,
enforceAdmins: true,
dismissStaleReviews: false,
+ requiredCommitSigning: false,
});
});
@@ -860,11 +872,15 @@ describe('publish:github', () => {
logger: mockContext.logger,
defaultBranch: 'master',
requireCodeOwnerReviews: false,
+ bypassPullRequestAllowances: undefined,
+ requiredApprovingReviewCount: 1,
+ restrictions: undefined,
requiredStatusCheckContexts: [],
requireBranchesToBeUpToDate: true,
requiredConversationResolution: false,
enforceAdmins: true,
dismissStaleReviews: false,
+ requiredCommitSigning: false,
});
await action.handler({
@@ -882,11 +898,15 @@ describe('publish:github', () => {
logger: mockContext.logger,
defaultBranch: 'master',
requireCodeOwnerReviews: false,
+ bypassPullRequestAllowances: undefined,
+ requiredApprovingReviewCount: 1,
+ restrictions: undefined,
requiredStatusCheckContexts: [],
requireBranchesToBeUpToDate: true,
requiredConversationResolution: false,
enforceAdmins: false,
dismissStaleReviews: false,
+ requiredCommitSigning: false,
});
await action.handler({
@@ -904,11 +924,15 @@ describe('publish:github', () => {
logger: mockContext.logger,
defaultBranch: 'master',
requireCodeOwnerReviews: false,
+ bypassPullRequestAllowances: undefined,
+ requiredApprovingReviewCount: 1,
+ restrictions: undefined,
requiredStatusCheckContexts: [],
requireBranchesToBeUpToDate: true,
requiredConversationResolution: false,
enforceAdmins: true,
dismissStaleReviews: false,
+ requiredCommitSigning: false,
});
});
@@ -932,11 +956,15 @@ describe('publish:github', () => {
logger: mockContext.logger,
defaultBranch: 'master',
requireCodeOwnerReviews: false,
+ bypassPullRequestAllowances: undefined,
+ requiredApprovingReviewCount: 1,
+ restrictions: undefined,
requiredStatusCheckContexts: [],
requireBranchesToBeUpToDate: true,
requiredConversationResolution: false,
enforceAdmins: true,
dismissStaleReviews: false,
+ requiredCommitSigning: false,
});
await action.handler({
@@ -956,11 +984,15 @@ describe('publish:github', () => {
logger: mockContext.logger,
defaultBranch: 'master',
requireCodeOwnerReviews: false,
- requiredStatusCheckContexts: ['statusCheck'],
+ bypassPullRequestAllowances: undefined,
+ requiredApprovingReviewCount: 1,
+ restrictions: undefined,
+ requiredStatusCheckContexts: [],
requireBranchesToBeUpToDate: true,
requiredConversationResolution: false,
enforceAdmins: true,
dismissStaleReviews: false,
+ requiredCommitSigning: false,
});
await action.handler({
@@ -979,11 +1011,15 @@ describe('publish:github', () => {
logger: mockContext.logger,
defaultBranch: 'master',
requireCodeOwnerReviews: false,
+ bypassPullRequestAllowances: undefined,
+ requiredApprovingReviewCount: 1,
+ restrictions: undefined,
requiredStatusCheckContexts: ['statusCheck'],
requireBranchesToBeUpToDate: false,
requiredConversationResolution: false,
enforceAdmins: true,
dismissStaleReviews: false,
+ requiredCommitSigning: false,
});
await action.handler({
@@ -1001,11 +1037,15 @@ describe('publish:github', () => {
logger: mockContext.logger,
defaultBranch: 'master',
requireCodeOwnerReviews: false,
+ bypassPullRequestAllowances: undefined,
+ requiredApprovingReviewCount: 1,
+ restrictions: undefined,
requiredStatusCheckContexts: [],
requireBranchesToBeUpToDate: true,
requiredConversationResolution: false,
enforceAdmins: true,
dismissStaleReviews: false,
+ requiredCommitSigning: false,
});
});
@@ -1084,11 +1124,15 @@ describe('publish:github', () => {
logger: mockContext.logger,
defaultBranch: 'master',
requireCodeOwnerReviews: false,
+ bypassPullRequestAllowances: undefined,
+ requiredApprovingReviewCount: 1,
+ restrictions: undefined,
requiredStatusCheckContexts: [],
requireBranchesToBeUpToDate: true,
requiredConversationResolution: false,
enforceAdmins: true,
dismissStaleReviews: false,
+ requiredCommitSigning: false,
});
await action.handler({
@@ -1106,11 +1150,15 @@ describe('publish:github', () => {
logger: mockContext.logger,
defaultBranch: 'master',
requireCodeOwnerReviews: false,
+ bypassPullRequestAllowances: undefined,
+ requiredApprovingReviewCount: 1,
+ restrictions: undefined,
requiredStatusCheckContexts: [],
requireBranchesToBeUpToDate: true,
requiredConversationResolution: false,
enforceAdmins: true,
dismissStaleReviews: true,
+ requiredCommitSigning: false,
});
await action.handler({
@@ -1128,11 +1176,15 @@ describe('publish:github', () => {
logger: mockContext.logger,
defaultBranch: 'master',
requireCodeOwnerReviews: false,
+ bypassPullRequestAllowances: undefined,
+ requiredApprovingReviewCount: 1,
+ restrictions: undefined,
requiredStatusCheckContexts: [],
requireBranchesToBeUpToDate: true,
requiredConversationResolution: false,
enforceAdmins: true,
dismissStaleReviews: false,
+ requiredCommitSigning: false,
});
});
it('should call enableBranchProtectionOnDefaultRepoBranch with the correct values of requiredConversationResolution', async () => {
@@ -1155,11 +1207,15 @@ describe('publish:github', () => {
logger: mockContext.logger,
defaultBranch: 'master',
requireCodeOwnerReviews: false,
+ bypassPullRequestAllowances: undefined,
+ requiredApprovingReviewCount: 1,
+ restrictions: undefined,
requiredStatusCheckContexts: [],
requireBranchesToBeUpToDate: true,
requiredConversationResolution: false,
enforceAdmins: true,
dismissStaleReviews: false,
+ requiredCommitSigning: false,
});
await action.handler({
@@ -1177,11 +1233,15 @@ describe('publish:github', () => {
logger: mockContext.logger,
defaultBranch: 'master',
requireCodeOwnerReviews: false,
+ bypassPullRequestAllowances: undefined,
+ requiredApprovingReviewCount: 1,
+ restrictions: undefined,
requiredStatusCheckContexts: [],
requireBranchesToBeUpToDate: true,
requiredConversationResolution: true,
enforceAdmins: true,
dismissStaleReviews: false,
+ requiredCommitSigning: false,
});
await action.handler({
@@ -1199,11 +1259,15 @@ describe('publish:github', () => {
logger: mockContext.logger,
defaultBranch: 'master',
requireCodeOwnerReviews: false,
+ bypassPullRequestAllowances: undefined,
+ requiredApprovingReviewCount: 1,
+ restrictions: undefined,
requiredStatusCheckContexts: [],
requireBranchesToBeUpToDate: true,
requiredConversationResolution: false,
enforceAdmins: true,
dismissStaleReviews: false,
+ requiredCommitSigning: false,
});
});
});
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 019/255] 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 020/255] 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 6e2248abbe8e3080ad694e92b760320f75269b8f Mon Sep 17 00:00:00 2001
From: Patrik Oldsberg
Date: Wed, 11 Jan 2023 12:05:20 +0100
Subject: [PATCH 021/255] backend-common: added compatibility wrapper for
legacy plugins
Co-authored-by: Johan Haals
Signed-off-by: Patrik Oldsberg
---
packages/backend-common/api-report.md | 53 +++++++++++
packages/backend-common/src/compat.ts | 123 ++++++++++++++++++++++++++
packages/backend-common/src/index.ts | 2 +
3 files changed, 178 insertions(+)
create mode 100644 packages/backend-common/src/compat.ts
diff --git a/packages/backend-common/api-report.md b/packages/backend-common/api-report.md
index 915049366c..a97f8b31d8 100644
--- a/packages/backend-common/api-report.md
+++ b/packages/backend-common/api-report.md
@@ -9,6 +9,7 @@
import aws from 'aws-sdk';
import { AwsS3Integration } from '@backstage/integration';
import { AzureIntegration } from '@backstage/integration';
+import { BackendFeature } from '@backstage/backend-plugin-api';
import { BitbucketCloudIntegration } from '@backstage/integration';
import { BitbucketIntegration } from '@backstage/integration';
import { BitbucketServerIntegration } from '@backstage/integration';
@@ -16,6 +17,7 @@ import { CacheClient } from '@backstage/backend-plugin-api';
import { CacheClientOptions } from '@backstage/backend-plugin-api';
import { CacheClientSetOptions } from '@backstage/backend-plugin-api';
import { Config } from '@backstage/config';
+import { ConfigService } from '@backstage/backend-plugin-api';
import cors from 'cors';
import Docker from 'dockerode';
import { Duration } from 'luxon';
@@ -26,6 +28,7 @@ import { GiteaIntegration } from '@backstage/integration';
import { GithubCredentialsProvider } from '@backstage/integration';
import { GithubIntegration } from '@backstage/integration';
import { GitLabIntegration } from '@backstage/integration';
+import { IdentityService } from '@backstage/backend-plugin-api';
import { isChildPath } from '@backstage/cli-common';
import { Knex } from 'knex';
import { KubeConfig } from '@kubernetes/client-node';
@@ -33,6 +36,7 @@ import { LoadConfigOptionsRemote } from '@backstage/config-loader';
import { Logger } from 'winston';
import { LoggerService } from '@backstage/backend-plugin-api';
import { MergeResult } from 'isomorphic-git';
+import { PermissionsService } from '@backstage/backend-plugin-api';
import { CacheService as PluginCacheManager } from '@backstage/backend-plugin-api';
import { DatabaseService as PluginDatabaseManager } from '@backstage/backend-plugin-api';
import { DiscoveryService as PluginEndpointDiscovery } from '@backstage/backend-plugin-api';
@@ -47,10 +51,12 @@ import { ReadUrlOptions } from '@backstage/backend-plugin-api';
import { ReadUrlResponse } from '@backstage/backend-plugin-api';
import { RequestHandler } from 'express';
import { Router } from 'express';
+import { SchedulerService } from '@backstage/backend-plugin-api';
import { SearchOptions } from '@backstage/backend-plugin-api';
import { SearchResponse } from '@backstage/backend-plugin-api';
import { SearchResponseFile } from '@backstage/backend-plugin-api';
import { Server } from 'http';
+import { ServiceRef } from '@backstage/backend-plugin-api';
import { TokenManagerService as TokenManager } from '@backstage/backend-plugin-api';
import { TransportStreamOptions } from 'winston-transport';
import { UrlReaderService as UrlReader } from '@backstage/backend-plugin-api';
@@ -228,6 +234,32 @@ export function createDatabaseClient(
overrides?: Partial,
): Knex;
+// @public
+export const createPluginCompat: (
+ name: string,
+ createRouterImport: Promise<{
+ default: LegacyCreateRouter<
+ TransformedEnv<
+ {
+ cache: PluginCacheManager;
+ config: ConfigService;
+ database: PluginDatabaseManager;
+ discovery: PluginEndpointDiscovery;
+ logger: LoggerService;
+ permissions: PermissionsService;
+ scheduler: SchedulerService;
+ tokenManager: TokenManager;
+ reader: UrlReader;
+ identity: IdentityService;
+ },
+ {
+ logger: (log: LoggerService) => Logger;
+ }
+ >
+ >;
+ }>,
+) => BackendFeature;
+
// @public
export function createRootLogger(
options?: winston.LoggerOptions,
@@ -500,6 +532,9 @@ export type KubernetesContainerRunnerOptions = {
timeoutMs?: number;
};
+// @public (undocumented)
+export type LegacyCreateRouter = (deps: TEnv) => Promise;
+
// @public
export function loadBackendConfig(options: {
logger: LoggerService;
@@ -513,6 +548,24 @@ export function loggerToWinstonLogger(
opts?: TransportStreamOptions,
): Logger;
+// @public
+export function makePluginCompat<
+ TEnv extends Record,
+ TEnvTransforms extends {
+ [key in keyof TEnv]?: (dep: TEnv[key]) => unknown;
+ },
+>(
+ envMapping: {
+ [key in keyof TEnv]: ServiceRef;
+ },
+ envTransforms: TEnvTransforms,
+): (
+ name: string,
+ createRouterImport: Promise<{
+ default: LegacyCreateRouter>;
+ }>,
+) => BackendFeature;
+
// @public
export function notFoundHandler(): RequestHandler;
diff --git a/packages/backend-common/src/compat.ts b/packages/backend-common/src/compat.ts
new file mode 100644
index 0000000000..16fe48dcb7
--- /dev/null
+++ b/packages/backend-common/src/compat.ts
@@ -0,0 +1,123 @@
+/*
+ * 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 {
+ coreServices,
+ createBackendPlugin,
+ ServiceRef,
+} from '@backstage/backend-plugin-api';
+import { RequestHandler } from 'express';
+import { loggerToWinstonLogger } from './logging';
+
+/**
+ * @public
+ */
+export type LegacyCreateRouter = (deps: TEnv) => Promise;
+
+/** @ignore */
+type TransformedEnv<
+ TEnv extends Record,
+ TEnvTransforms extends { [key in keyof TEnv]?: (dep: TEnv[key]) => unknown },
+> = {
+ [key in keyof TEnv]: TEnvTransforms[key] extends (dep: TEnv[key]) => infer R
+ ? R
+ : TEnv[key];
+};
+
+/**
+ * Creates a new custom plugin compatibility wrapper.
+ *
+ * @public
+ * @remarks
+ *
+ * Usually you can use {@link createPluginCompat} directly instead, but you might
+ * need to use this if you have customized the plugin environment in your backend.
+ */
+export function makePluginCompat<
+ TEnv extends Record,
+ TEnvTransforms extends { [key in keyof TEnv]?: (dep: TEnv[key]) => unknown },
+>(
+ envMapping: { [key in keyof TEnv]: ServiceRef },
+ envTransforms: TEnvTransforms,
+) {
+ return (
+ name: string,
+ createRouterImport: Promise<{
+ default: LegacyCreateRouter>;
+ }>,
+ ) => {
+ const compatPlugin = createBackendPlugin({
+ id: name,
+ register(env) {
+ env.registerInit({
+ deps: { ...envMapping, _router: coreServices.httpRouter },
+ async init({ _router, ...envDeps }) {
+ const { default: createRouter } = await createRouterImport;
+ const pluginEnv = Object.fromEntries(
+ Object.entries(envDeps).map(([key, dep]) => {
+ const transform = envTransforms[key];
+ if (transform) {
+ return [key, transform(dep)];
+ }
+ return [key, dep];
+ }),
+ );
+ const router = await createRouter(
+ pluginEnv as TransformedEnv,
+ );
+ _router.use(router);
+ },
+ });
+ },
+ });
+
+ return compatPlugin();
+ };
+}
+
+/**
+ * Helper function to create a plugin from a legacy createRouter function and
+ * register it with the http router based on the plugin id.
+ *
+ * @public
+ * @remarks
+ *
+ * This is intended to be used by plugin authors to ease the transition to the
+ * new backend system.
+ *
+ * @example
+ *
+ *```ts
+ *backend.add(createPluginCompat('kafka', import('./plugins/kafka')));
+ *```
+ */
+export const createPluginCompat = makePluginCompat(
+ {
+ cache: coreServices.cache,
+ config: coreServices.config,
+ database: coreServices.database,
+ discovery: coreServices.discovery,
+ logger: coreServices.logger,
+ permissions: coreServices.permissions,
+ scheduler: coreServices.scheduler,
+ tokenManager: coreServices.tokenManager,
+ reader: coreServices.urlReader,
+ identity: coreServices.identity,
+ },
+ {
+ logger: log => loggerToWinstonLogger(log),
+ },
+);
diff --git a/packages/backend-common/src/index.ts b/packages/backend-common/src/index.ts
index 238e58b2a8..178a064cb9 100644
--- a/packages/backend-common/src/index.ts
+++ b/packages/backend-common/src/index.ts
@@ -20,6 +20,8 @@
* @packageDocumentation
*/
+export { makePluginCompat, createPluginCompat } from './compat';
+export type { LegacyCreateRouter } from './compat';
export * from './cache';
export { loadBackendConfig } from './config';
export * from './context';
From cdabd4eefb35c303da00232dd120df0c813965aa Mon Sep 17 00:00:00 2001
From: Patrik Oldsberg
Date: Wed, 11 Jan 2023 13:09:56 +0100
Subject: [PATCH 022/255] backend-common: rename createPluginCompat ->
legacyPlugin
Signed-off-by: Patrik Oldsberg
---
packages/backend-common/api-report.md | 54 +++++++++----------
packages/backend-common/src/index.ts | 4 +-
.../src/{compat.ts => legacy.ts} | 8 +--
3 files changed, 33 insertions(+), 33 deletions(-)
rename packages/backend-common/src/{compat.ts => legacy.ts} (93%)
diff --git a/packages/backend-common/api-report.md b/packages/backend-common/api-report.md
index a97f8b31d8..b03d6ec866 100644
--- a/packages/backend-common/api-report.md
+++ b/packages/backend-common/api-report.md
@@ -234,32 +234,6 @@ export function createDatabaseClient(
overrides?: Partial,
): Knex;
-// @public
-export const createPluginCompat: (
- name: string,
- createRouterImport: Promise<{
- default: LegacyCreateRouter<
- TransformedEnv<
- {
- cache: PluginCacheManager;
- config: ConfigService;
- database: PluginDatabaseManager;
- discovery: PluginEndpointDiscovery;
- logger: LoggerService;
- permissions: PermissionsService;
- scheduler: SchedulerService;
- tokenManager: TokenManager;
- reader: UrlReader;
- identity: IdentityService;
- },
- {
- logger: (log: LoggerService) => Logger;
- }
- >
- >;
- }>,
-) => BackendFeature;
-
// @public
export function createRootLogger(
options?: winston.LoggerOptions,
@@ -535,6 +509,32 @@ export type KubernetesContainerRunnerOptions = {
// @public (undocumented)
export type LegacyCreateRouter = (deps: TEnv) => Promise;
+// @public
+export const legacyPlugin: (
+ name: string,
+ createRouterImport: Promise<{
+ default: LegacyCreateRouter<
+ TransformedEnv<
+ {
+ cache: PluginCacheManager;
+ config: ConfigService;
+ database: PluginDatabaseManager;
+ discovery: PluginEndpointDiscovery;
+ logger: LoggerService;
+ permissions: PermissionsService;
+ scheduler: SchedulerService;
+ tokenManager: TokenManager;
+ reader: UrlReader;
+ identity: IdentityService;
+ },
+ {
+ logger: (log: LoggerService) => Logger;
+ }
+ >
+ >;
+ }>,
+) => BackendFeature;
+
// @public
export function loadBackendConfig(options: {
logger: LoggerService;
@@ -549,7 +549,7 @@ export function loggerToWinstonLogger(
): Logger;
// @public
-export function makePluginCompat<
+export function makeLegacyPlugin<
TEnv extends Record,
TEnvTransforms extends {
[key in keyof TEnv]?: (dep: TEnv[key]) => unknown;
diff --git a/packages/backend-common/src/index.ts b/packages/backend-common/src/index.ts
index 178a064cb9..46639a1923 100644
--- a/packages/backend-common/src/index.ts
+++ b/packages/backend-common/src/index.ts
@@ -20,8 +20,8 @@
* @packageDocumentation
*/
-export { makePluginCompat, createPluginCompat } from './compat';
-export type { LegacyCreateRouter } from './compat';
+export { legacyPlugin, makeLegacyPlugin } from './legacy';
+export type { LegacyCreateRouter } from './legacy';
export * from './cache';
export { loadBackendConfig } from './config';
export * from './context';
diff --git a/packages/backend-common/src/compat.ts b/packages/backend-common/src/legacy.ts
similarity index 93%
rename from packages/backend-common/src/compat.ts
rename to packages/backend-common/src/legacy.ts
index 16fe48dcb7..30e7dd9dc5 100644
--- a/packages/backend-common/src/compat.ts
+++ b/packages/backend-common/src/legacy.ts
@@ -43,10 +43,10 @@ type TransformedEnv<
* @public
* @remarks
*
- * Usually you can use {@link createPluginCompat} directly instead, but you might
+ * Usually you can use {@link legacyPlugin} directly instead, but you might
* need to use this if you have customized the plugin environment in your backend.
*/
-export function makePluginCompat<
+export function makeLegacyPlugin<
TEnv extends Record,
TEnvTransforms extends { [key in keyof TEnv]?: (dep: TEnv[key]) => unknown },
>(
@@ -101,10 +101,10 @@ export function makePluginCompat<
* @example
*
*```ts
- *backend.add(createPluginCompat('kafka', import('./plugins/kafka')));
+ *backend.add(legacyPlugin('kafka', import('./plugins/kafka')));
*```
*/
-export const createPluginCompat = makePluginCompat(
+export const legacyPlugin = makeLegacyPlugin(
{
cache: coreServices.cache,
config: coreServices.config,
From 31e2309c8cfe15d2c79c8800242fac901a17ebda Mon Sep 17 00:00:00 2001
From: Patrik Oldsberg
Date: Wed, 11 Jan 2023 13:24:39 +0100
Subject: [PATCH 023/255] changesets: added changeset for legacyPlugin wrapper
Signed-off-by: Patrik Oldsberg
---
.changeset/famous-books-matter.md | 5 +++++
1 file changed, 5 insertions(+)
create mode 100644 .changeset/famous-books-matter.md
diff --git a/.changeset/famous-books-matter.md b/.changeset/famous-books-matter.md
new file mode 100644
index 0000000000..550bfecf0b
--- /dev/null
+++ b/.changeset/famous-books-matter.md
@@ -0,0 +1,5 @@
+---
+'@backstage/backend-common': patch
+---
+
+Added `legacyPlugin` and the lower level `makeLegacyPlugin` wrappers that convert legacy plugins to the new backend system. This will be used to ease the future migration to the new backend system, but we discourage use of it for now.
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 024/255] 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 025/255] 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 026/255] 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 027/255] 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 028/255] 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 029/255] 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 030/255] 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 031/255] 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 032/255] 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 033/255] 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 034/255] 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 035/255] 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 036/255] 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 037/255] 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 2f893e9ca3bdc5e79eaa549b6517f3b02c8e864a Mon Sep 17 00:00:00 2001
From: Trevor Grieger
Date: Wed, 11 Jan 2023 09:53:09 -0500
Subject: [PATCH 038/255] Run `yarn build:api-report
plugins/scaffolder-backend`
Signed-off-by: Trevor Grieger
---
plugins/scaffolder-backend/api-report.md | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/plugins/scaffolder-backend/api-report.md b/plugins/scaffolder-backend/api-report.md
index 3e25311ca6..a6f278823f 100644
--- a/plugins/scaffolder-backend/api-report.md
+++ b/plugins/scaffolder-backend/api-report.md
@@ -214,8 +214,8 @@ export function createGithubRepoCreateAction(options: {
requiredApprovingReviewCount?: number | undefined;
restrictions?:
| {
- users: string[] | undefined;
- teams: string[] | undefined;
+ users: string[];
+ teams: string[];
apps?: string[] | undefined;
}
| undefined;
@@ -273,9 +273,9 @@ export function createGithubRepoPushAction(options: {
requiredApprovingReviewCount?: number | undefined;
restrictions?:
| {
- users: string[] | undefined;
- teams: string[] | undefined;
- apps?: string[] | undefined;
+ users: string[];
+ teams: string[];
+ apps?: string[];
}
| undefined;
requiredStatusCheckContexts?: string[] | undefined;
@@ -283,7 +283,7 @@ export function createGithubRepoPushAction(options: {
requiredConversationResolution?: boolean | undefined;
sourcePath?: string | undefined;
token?: string | undefined;
- requireCommitSigning?: boolean | undefined;
+ requiredCommitSigning?: boolean | undefined;
}>;
// @public
@@ -426,9 +426,9 @@ export function createPublishGithubAction(options: {
requiredApprovingReviewCount?: number | undefined;
restrictions?:
| {
- users: string[] | undefined;
- teams: string[] | undefined;
- apps?: string[] | undefined;
+ users: string[];
+ teams: string[];
+ apps?: string[];
}
| undefined;
requireCodeOwnerReviews?: boolean | undefined;
@@ -458,7 +458,7 @@ export function createPublishGithubAction(options: {
hasIssues?: boolean | undefined;
token?: string | undefined;
topics?: string[] | undefined;
- requireCommitSigning?: boolean | undefined;
+ requiredCommitSigning?: boolean | undefined;
}>;
// @public
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 039/255] 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 040/255] 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 041/255] 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:
+
+