From 5a317f59c025cb6522fc277e8377bac799a9f162 Mon Sep 17 00:00:00 2001 From: Antonio Bergas Date: Sat, 23 Sep 2023 11:09:29 +0200 Subject: [PATCH 001/261] =?UTF-8?q?=E2=9C=A8feat(homePlugin):=20changed=20?= =?UTF-8?q?list=20view=20of=20starredEntities=20to=20facilitate=20distingu?= =?UTF-8?q?ish=20entities=20with=20same=20name?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Antonio Bergas --- .changeset/healthy-feet-kick.md | 5 ++ .../StarredEntities/Content.tsx | 80 ++++++++++++------- 2 files changed, 56 insertions(+), 29 deletions(-) create mode 100644 .changeset/healthy-feet-kick.md diff --git a/.changeset/healthy-feet-kick.md b/.changeset/healthy-feet-kick.md new file mode 100644 index 0000000000..732f2164c3 --- /dev/null +++ b/.changeset/healthy-feet-kick.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-home': minor +--- + +Added view of entities grouped by kind to make it easier to distinguish entities with different kind but same name diff --git a/plugins/home/src/homePageComponents/StarredEntities/Content.tsx b/plugins/home/src/homePageComponents/StarredEntities/Content.tsx index 4654a7f860..4818aad809 100644 --- a/plugins/home/src/homePageComponents/StarredEntities/Content.tsx +++ b/plugins/home/src/homePageComponents/StarredEntities/Content.tsx @@ -20,7 +20,11 @@ import { entityRouteParams, entityRouteRef, } from '@backstage/plugin-catalog-react'; -import { parseEntityRef, stringifyEntityRef } from '@backstage/catalog-model'; +import { + Entity, + parseEntityRef, + stringifyEntityRef, +} from '@backstage/catalog-model'; import { useApi, useRouteRef } from '@backstage/core-plugin-api'; import { Link, Progress, ResponseErrorPanel } from '@backstage/core-components'; import { @@ -87,37 +91,55 @@ export const Content = (props: { if (entities.loading) { return ; } + const groupedEntities: { [kind: string]: Entity[] } = {}; + + entities.value?.forEach(entity => { + const kind = entity.kind; + if (!groupedEntities[kind]) { + groupedEntities[kind] = []; + } + groupedEntities[kind].push(entity); + }); + + const entityEntries = Object.entries(groupedEntities); return entities.error ? ( ) : ( - - {entities.value - ?.sort((a, b) => - (a.metadata.title ?? a.metadata.name).localeCompare( - b.metadata.title ?? b.metadata.name, - ), - ) - .map(entity => ( - - - - - - - toggleStarredEntity(entity)} - > - - - - - - ))} - +
+ {entityEntries.map(([kind, entitiesByKind]) => ( +
+ {kind} {/* Kind as Title */} + + {entitiesByKind + ?.sort((a, b) => + (a.metadata.title ?? a.metadata.name).localeCompare( + b.metadata.title ?? b.metadata.name, + ), + ) + .map(entity => ( + + + + + + + toggleStarredEntity(entity)} + > + + + + + + ))} + +
+ ))} +
); }; From 375b6f7d683e7680a0b8a53f97dd2fb98982453d Mon Sep 17 00:00:00 2001 From: Philipp Hugenroth Date: Wed, 8 Nov 2023 16:39:11 +0100 Subject: [PATCH 002/261] CircelCI repository moved Signed-off-by: Philipp Hugenroth --- .changeset/rude-ears-greet.md | 6 ++++ .../configure-app-with-plugins.md | 6 ++-- microsite/data/plugins/circleci.yaml | 8 ++--- packages/app-next/package.json | 2 +- packages/app/package.json | 2 +- .../app/src/components/catalog/EntityPage.tsx | 2 +- packages/create-app/src/lib/versions.ts | 2 -- plugins/circleci/README.md | 7 ++-- yarn.lock | 32 +++++++++++++++++-- 9 files changed, 49 insertions(+), 18 deletions(-) create mode 100644 .changeset/rude-ears-greet.md diff --git a/.changeset/rude-ears-greet.md b/.changeset/rude-ears-greet.md new file mode 100644 index 0000000000..b5dd684c16 --- /dev/null +++ b/.changeset/rude-ears-greet.md @@ -0,0 +1,6 @@ +--- +'@backstage/create-app': patch +'@backstage/plugin-circleci': patch +--- + +CircelCI plugin moved permanently diff --git a/docs/getting-started/configure-app-with-plugins.md b/docs/getting-started/configure-app-with-plugins.md index b44f7877a7..5611117636 100644 --- a/docs/getting-started/configure-app-with-plugins.md +++ b/docs/getting-started/configure-app-with-plugins.md @@ -15,7 +15,7 @@ The following steps assume that you have to it. We are using the -[CircleCI](https://github.com/backstage/backstage/blob/master/plugins/circleci/README.md) +[CircleCI](https://github.com/CircleCI-Public/backstage-plugin/tree/main/plugins/circleci) plugin in this example, which is designed to show CI/CD pipeline information attached to an entity in the software catalog. @@ -23,7 +23,7 @@ to an entity in the software catalog. ```bash # From your Backstage root directory - yarn add --cwd packages/app @backstage/plugin-circleci + yarn add --cwd packages/app @circleci/backstage-plugin ``` Note the plugin is added to the `app` package, rather than the root @@ -38,7 +38,7 @@ to an entity in the software catalog. import { EntityCircleCIContent, isCircleCIAvailable, - } from '@backstage/plugin-circleci'; + } from '@circleci/backstage-plugin'; /* highlight-add-end */ const cicdContent = ( diff --git a/microsite/data/plugins/circleci.yaml b/microsite/data/plugins/circleci.yaml index 5d7978624b..5980f8cf45 100644 --- a/microsite/data/plugins/circleci.yaml +++ b/microsite/data/plugins/circleci.yaml @@ -1,12 +1,12 @@ --- title: CircleCI -author: Spotify -authorUrl: https://github.com/spotify +author: CircleCI +authorUrl: https://circleci.com/ category: CI/CD description: Automate your development process with CI hosted in the cloud or on a private server. -documentation: https://github.com/backstage/backstage/tree/master/plugins/circleci +documentation: https://github.com/CircleCI-Public/backstage-plugin/tree/main/plugins/circleci iconUrl: /img/circleci.png -npmPackageName: '@backstage/plugin-circleci' +npmPackageName: '@circleci/backstage-plugin' tags: - ci - cd diff --git a/packages/app-next/package.json b/packages/app-next/package.json index 90108f9065..7e6df0a955 100644 --- a/packages/app-next/package.json +++ b/packages/app-next/package.json @@ -31,7 +31,6 @@ "@backstage/plugin-catalog-import": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", "@backstage/plugin-catalog-unprocessed-entities": "workspace:^", - "@backstage/plugin-circleci": "workspace:^", "@backstage/plugin-cloudbuild": "workspace:^", "@backstage/plugin-code-coverage": "workspace:^", "@backstage/plugin-cost-insights": "workspace:^", @@ -77,6 +76,7 @@ "@backstage/plugin-todo": "workspace:^", "@backstage/plugin-user-settings": "workspace:^", "@backstage/theme": "workspace:^", + "@circleci/backstage-plugin": "^0.1.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", diff --git a/packages/app/package.json b/packages/app/package.json index 53002d7902..dd6ffdf405 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -35,7 +35,6 @@ "@backstage/plugin-catalog-import": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", "@backstage/plugin-catalog-unprocessed-entities": "workspace:^", - "@backstage/plugin-circleci": "workspace:^", "@backstage/plugin-cloudbuild": "workspace:^", "@backstage/plugin-code-coverage": "workspace:^", "@backstage/plugin-cost-insights": "workspace:^", @@ -84,6 +83,7 @@ "@backstage/plugin-todo": "workspace:^", "@backstage/plugin-user-settings": "workspace:^", "@backstage/theme": "workspace:^", + "@circleci/backstage-plugin": "^0.1.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", diff --git a/packages/app/src/components/catalog/EntityPage.tsx b/packages/app/src/components/catalog/EntityPage.tsx index ecc1f008b5..3bd8869f4f 100644 --- a/packages/app/src/components/catalog/EntityPage.tsx +++ b/packages/app/src/components/catalog/EntityPage.tsx @@ -77,7 +77,7 @@ import { import { EntityCircleCIContent, isCircleCIAvailable, -} from '@backstage/plugin-circleci'; +} from '@circleci/backstage-plugin'; import { EntityCloudbuildContent, isCloudbuildAvailable, diff --git a/packages/create-app/src/lib/versions.ts b/packages/create-app/src/lib/versions.ts index 81bae3c0b8..03ef32d921 100644 --- a/packages/create-app/src/lib/versions.ts +++ b/packages/create-app/src/lib/versions.ts @@ -58,7 +58,6 @@ import { version as pluginCatalogBackend } from '../../../../plugins/catalog-bac import { version as pluginCatalogBackendModuleScaffolderEntityModel } from '../../../../plugins/catalog-backend-module-scaffolder-entity-model/package.json'; import { version as pluginCatalogGraph } from '../../../../plugins/catalog-graph/package.json'; import { version as pluginCatalogImport } from '../../../../plugins/catalog-import/package.json'; -import { version as pluginCircleci } from '../../../../plugins/circleci/package.json'; import { version as pluginExplore } from '../../../../plugins/explore/package.json'; import { version as pluginGithubActions } from '../../../../plugins/github-actions/package.json'; import { version as pluginLighthouse } from '../../../../plugins/lighthouse/package.json'; @@ -111,7 +110,6 @@ export const packageVersions = { pluginCatalogBackendModuleScaffolderEntityModel, '@backstage/plugin-catalog-graph': pluginCatalogGraph, '@backstage/plugin-catalog-import': pluginCatalogImport, - '@backstage/plugin-circleci': pluginCircleci, '@backstage/plugin-explore': pluginExplore, '@backstage/plugin-github-actions': pluginGithubActions, '@backstage/plugin-lighthouse': pluginLighthouse, diff --git a/plugins/circleci/README.md b/plugins/circleci/README.md index f468ab37e2..86af7081c7 100644 --- a/plugins/circleci/README.md +++ b/plugins/circleci/README.md @@ -1,6 +1,7 @@ # CircleCI Plugin -Website: [https://circleci.com/](https://circleci.com/) +> [!IMPORTANT] +> This plugin is now developed & maintained by CircleCI. Please refer to [their up-to-date documentation](https://github.com/CircleCI-Public/backstage-plugin) & [plugin repository](https://github.com/CircleCI-Public/backstage-plugin/) for help. ## Screenshots @@ -14,7 +15,7 @@ Website: [https://circleci.com/](https://circleci.com/) ```bash # From your Backstage root directory -yarn add --cwd packages/app @backstage/plugin-circleci +yarn add --cwd packages/app @circleci/backstage-plugin ``` 2. Add the `EntityCircleCIContent` extension to the entity page in your app: @@ -24,7 +25,7 @@ yarn add --cwd packages/app @backstage/plugin-circleci import { EntityCircleCIContent, isCircleCIAvailable, -} from '@backstage/plugin-circleci'; +} from '@circleci/backstage-plugin'; // For example in the CI/CD section const cicdContent = ( diff --git a/yarn.lock b/yarn.lock index 5eca77c682..7091cbbae6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6251,7 +6251,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-circleci@workspace:^, @backstage/plugin-circleci@workspace:plugins/circleci": +"@backstage/plugin-circleci@workspace:plugins/circleci": version: 0.0.0-use.local resolution: "@backstage/plugin-circleci@workspace:plugins/circleci" dependencies: @@ -10628,6 +10628,32 @@ __metadata: languageName: node linkType: hard +"@circleci/backstage-plugin@npm:^0.1.1": + version: 0.1.1 + resolution: "@circleci/backstage-plugin@npm:0.1.1" + dependencies: + "@backstage/catalog-model": "workspace:^" + "@backstage/core-components": "workspace:^" + "@backstage/core-plugin-api": "workspace:^" + "@backstage/plugin-catalog-react": "workspace:^" + "@backstage/theme": "workspace:^" + "@material-ui/core": ^4.12.2 + "@material-ui/icons": ^4.9.1 + "@material-ui/lab": 4.0.0-alpha.61 + "@types/react": ^16.13.1 || ^17.0.0 + circleci-api: ^4.0.0 + humanize-duration: ^3.27.0 + lodash: ^4.17.21 + luxon: ^3.0.0 + react-use: ^17.2.4 + peerDependencies: + react: ^16.13.1 || ^17.0.0 + react-dom: ^16.13.1 || ^17.0.0 + react-router-dom: 6.0.0-beta.0 || ^6.3.0 + checksum: ded80e2eef1cec3f83f76e62b1362499c1662ae6307bdc829b78aed02101af6fd85134d94716fbbb60e8a0d5b3d2a4653df81fbdfcab576a47f7b59a332e580f + languageName: node + linkType: hard + "@codemirror/autocomplete@npm:^6.0.0": version: 6.3.0 resolution: "@codemirror/autocomplete@npm:6.3.0" @@ -27282,7 +27308,6 @@ __metadata: "@backstage/plugin-catalog-import": "workspace:^" "@backstage/plugin-catalog-react": "workspace:^" "@backstage/plugin-catalog-unprocessed-entities": "workspace:^" - "@backstage/plugin-circleci": "workspace:^" "@backstage/plugin-cloudbuild": "workspace:^" "@backstage/plugin-code-coverage": "workspace:^" "@backstage/plugin-cost-insights": "workspace:^" @@ -27329,6 +27354,7 @@ __metadata: "@backstage/plugin-user-settings": "workspace:^" "@backstage/test-utils": "workspace:^" "@backstage/theme": "workspace:^" + "@circleci/backstage-plugin": ^0.1.1 "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 "@material-ui/lab": 4.0.0-alpha.61 @@ -27391,7 +27417,6 @@ __metadata: "@backstage/plugin-catalog-import": "workspace:^" "@backstage/plugin-catalog-react": "workspace:^" "@backstage/plugin-catalog-unprocessed-entities": "workspace:^" - "@backstage/plugin-circleci": "workspace:^" "@backstage/plugin-cloudbuild": "workspace:^" "@backstage/plugin-code-coverage": "workspace:^" "@backstage/plugin-cost-insights": "workspace:^" @@ -27441,6 +27466,7 @@ __metadata: "@backstage/plugin-user-settings": "workspace:^" "@backstage/test-utils": "workspace:^" "@backstage/theme": "workspace:^" + "@circleci/backstage-plugin": ^0.1.1 "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 "@material-ui/lab": 4.0.0-alpha.61 From e0e10b272be4a870560556bf3d641ab5ee0f4b0b Mon Sep 17 00:00:00 2001 From: Antonio Bergas Date: Sat, 11 Nov 2023 12:21:36 +0100 Subject: [PATCH 003/261] =?UTF-8?q?=E2=9C=A8=20feat(HomePlugin):=20split?= =?UTF-8?q?=20StarredEntities=20groupByKind=20in=20tabs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Antonio Bergas --- .../StarredEntityListItem.tsx | 60 ++++++++++++ .../StarredEntities/Content.tsx | 96 +++++++++++-------- plugins/home/src/plugin.ts | 3 +- 3 files changed, 117 insertions(+), 42 deletions(-) create mode 100644 plugins/home/src/components/StarredEntityListItem/StarredEntityListItem.tsx diff --git a/plugins/home/src/components/StarredEntityListItem/StarredEntityListItem.tsx b/plugins/home/src/components/StarredEntityListItem/StarredEntityListItem.tsx new file mode 100644 index 0000000000..2a8960e469 --- /dev/null +++ b/plugins/home/src/components/StarredEntityListItem/StarredEntityListItem.tsx @@ -0,0 +1,60 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { Entity, stringifyEntityRef } from '@backstage/catalog-model'; +import { entityRouteParams } from '@backstage/plugin-catalog-react'; +import { + ListItem, + ListItemIcon, + Tooltip, + IconButton, + ListItemText, +} from '@material-ui/core'; +import React from 'react'; +import { Link } from 'react-router-dom'; +import { entityRouteRef } from '@backstage/plugin-catalog-react'; +import { useRouteRef } from '@backstage/core-plugin-api'; +import StarIcon from '@material-ui/icons/Star'; + +type EntityListItemProps = { + entity: Entity; + onToggleStarredEntity: (entity: Entity) => void; +}; + +export const StarredEntityListItem = ({ + entity, + onToggleStarredEntity, +}: EntityListItemProps) => { + const catalogEntityRoute = useRouteRef(entityRouteRef); + + return ( + + + + onToggleStarredEntity(entity)} + > + + + + + + + + + ); +}; diff --git a/plugins/home/src/homePageComponents/StarredEntities/Content.tsx b/plugins/home/src/homePageComponents/StarredEntities/Content.tsx index 4818aad809..e98065b392 100644 --- a/plugins/home/src/homePageComponents/StarredEntities/Content.tsx +++ b/plugins/home/src/homePageComponents/StarredEntities/Content.tsx @@ -17,28 +17,18 @@ import { catalogApiRef, useStarredEntities, - entityRouteParams, - entityRouteRef, } from '@backstage/plugin-catalog-react'; import { Entity, parseEntityRef, stringifyEntityRef, } from '@backstage/catalog-model'; -import { useApi, useRouteRef } from '@backstage/core-plugin-api'; -import { Link, Progress, ResponseErrorPanel } from '@backstage/core-components'; -import { - List, - ListItem, - ListItemSecondaryAction, - IconButton, - ListItemText, - Tooltip, - Typography, -} from '@material-ui/core'; -import StarIcon from '@material-ui/icons/Star'; +import { useApi } from '@backstage/core-plugin-api'; +import { Progress, ResponseErrorPanel } from '@backstage/core-components'; +import { List, Typography, Tabs, Tab } from '@material-ui/core'; import React from 'react'; import useAsync from 'react-use/lib/useAsync'; +import { StarredEntityListItem } from '../../components/StarredEntityListItem/StarredEntityListItem'; /** * A component to display a list of starred entities for the user. @@ -46,12 +36,18 @@ import useAsync from 'react-use/lib/useAsync'; * @public */ -export const Content = (props: { +export type StarredEntitiesProps = { noStarredEntitiesMessage?: React.ReactNode | undefined; -}) => { + groupByKind?: boolean; +}; + +export const Content = ({ + noStarredEntitiesMessage, + groupByKind, +}: StarredEntitiesProps) => { const catalogApi = useApi(catalogApiRef); - const catalogEntityRoute = useRouteRef(entityRouteRef); const { starredEntities, toggleStarredEntity } = useStarredEntities(); + const [activeTab, setActiveTab] = React.useState(0); // Grab starred entities from catalog to ensure they still exist and also retrieve display titles const entities = useAsync(async () => { @@ -83,7 +79,7 @@ export const Content = (props: { if (starredEntities.size === 0) return ( - {props.noStarredEntitiesMessage || + {noStarredEntitiesMessage || 'Click the star beside an entity name to add it to this list!'} ); @@ -91,8 +87,8 @@ export const Content = (props: { if (entities.loading) { return ; } - const groupedEntities: { [kind: string]: Entity[] } = {}; + const groupedEntities: { [kind: string]: Entity[] } = {}; entities.value?.forEach(entity => { const kind = entity.kind; if (!groupedEntities[kind]) { @@ -101,15 +97,46 @@ export const Content = (props: { groupedEntities[kind].push(entity); }); - const entityEntries = Object.entries(groupedEntities); + const groupByKindEntries = Object.entries(groupedEntities); return entities.error ? ( ) : (
- {entityEntries.map(([kind, entitiesByKind]) => ( -
- {kind} {/* Kind as Title */} + {!groupByKind && ( + + {entities.value + ?.sort((a, b) => + (a.metadata.title ?? a.metadata.name).localeCompare( + b.metadata.title ?? b.metadata.name, + ), + ) + .map(entity => ( + + ))} + + )} + + {groupByKind && ( + setActiveTab(newValue)} + variant="scrollable" + scrollButtons="auto" + aria-label="entity-tabs" + > + {groupByKindEntries.map(([kind]) => ( + + ))} + + )} + + {groupByKindEntries.map(([kind, entitiesByKind], index) => ( + diff --git a/plugins/home/src/plugin.ts b/plugins/home/src/plugin.ts index ab8c46baa1..ce288a1cb2 100644 --- a/plugins/home/src/plugin.ts +++ b/plugins/home/src/plugin.ts @@ -26,6 +26,7 @@ import { createCardExtension } from '@backstage/plugin-home-react'; import { ToolkitContentProps, VisitedByTypeProps } from './homePageComponents'; import { rootRouteRef } from './routes'; import { VisitsStorageApi, visitsApiRef } from './api'; +import { StarredEntitiesProps } from './homePageComponents/StarredEntities/Content'; /** @public */ export const homePlugin = createPlugin({ @@ -164,7 +165,7 @@ export const HomePageToolkit = homePlugin.provide( * @public */ export const HomePageStarredEntities = homePlugin.provide( - createCardExtension({ + createCardExtension>({ name: 'HomePageStarredEntities', title: 'Your Starred Entities', components: () => import('./homePageComponents/StarredEntities'), From 3181be9f21adfc5659870b75afafa556c50f0657 Mon Sep 17 00:00:00 2001 From: Antonio Bergas Date: Sat, 11 Nov 2023 12:45:25 +0100 Subject: [PATCH 004/261] =?UTF-8?q?=E2=9C=A8=20feat(HomePlugin):=20fix=20S?= =?UTF-8?q?tarredEntitieProps=20export=20for=20report=20api?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Antonio Bergas --- plugins/home/api-report.md | 8 +++++++- .../components/StarredEntityListItem/index.ts | 17 +++++++++++++++++ .../homePageComponents/StarredEntities/index.ts | 2 +- plugins/home/src/homePageComponents/index.ts | 1 + 4 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 plugins/home/src/components/StarredEntityListItem/index.ts diff --git a/plugins/home/api-report.md b/plugins/home/api-report.md index 14f685cfc1..3d947d9641 100644 --- a/plugins/home/api-report.md +++ b/plugins/home/api-report.md @@ -133,7 +133,7 @@ export const HomePageRecentlyVisited: ( // @public export const HomePageStarredEntities: ( - props: CardExtensionProps_2, + props: CardExtensionProps_2>, ) => JSX_2.Element; // @public @@ -177,6 +177,12 @@ export const SettingsModal: (props: { children: JSX.Element; }) => JSX_2.Element; +// @public +export type StarredEntitiesProps = { + noStarredEntitiesMessage?: React_2.ReactNode | undefined; + groupByKind?: boolean; +}; + // @public (undocumented) export const TemplateBackstageLogo: (props: { classes: { diff --git a/plugins/home/src/components/StarredEntityListItem/index.ts b/plugins/home/src/components/StarredEntityListItem/index.ts new file mode 100644 index 0000000000..5419e0cdf7 --- /dev/null +++ b/plugins/home/src/components/StarredEntityListItem/index.ts @@ -0,0 +1,17 @@ +/* + * 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 { StarredEntityListItem } from './StarredEntityListItem'; diff --git a/plugins/home/src/homePageComponents/StarredEntities/index.ts b/plugins/home/src/homePageComponents/StarredEntities/index.ts index 1faa9a2426..32e9213ea6 100644 --- a/plugins/home/src/homePageComponents/StarredEntities/index.ts +++ b/plugins/home/src/homePageComponents/StarredEntities/index.ts @@ -13,5 +13,5 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - export { Content } from './Content'; +export type { StarredEntitiesProps } from './Content'; diff --git a/plugins/home/src/homePageComponents/index.ts b/plugins/home/src/homePageComponents/index.ts index 9149afa295..03902debe4 100644 --- a/plugins/home/src/homePageComponents/index.ts +++ b/plugins/home/src/homePageComponents/index.ts @@ -18,3 +18,4 @@ export type { ToolkitContentProps, Tool } from './Toolkit'; export type { ClockConfig } from './HeaderWorldClock'; export type { WelcomeTitleLanguageProps } from './WelcomeTitle'; export type { VisitedByTypeProps, VisitedByTypeKind } from './VisitedByType'; +export type { StarredEntitiesProps } from './StarredEntities'; From 04e03a4e872f547495545527d8af24588f6fcf7d Mon Sep 17 00:00:00 2001 From: Antonio Bergas Date: Sat, 11 Nov 2023 14:22:17 +0100 Subject: [PATCH 005/261] =?UTF-8?q?=E2=9C=A8=20feat(HomePlugin):=20fix=20s?= =?UTF-8?q?hould=20render=20entities=20list=20test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Antonio Bergas --- .../StarredEntities/Content.tsx | 39 ++++++++++--------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/plugins/home/src/homePageComponents/StarredEntities/Content.tsx b/plugins/home/src/homePageComponents/StarredEntities/Content.tsx index e98065b392..ed5eec857b 100644 --- a/plugins/home/src/homePageComponents/StarredEntities/Content.tsx +++ b/plugins/home/src/homePageComponents/StarredEntities/Content.tsx @@ -135,25 +135,26 @@ export const Content = ({ )} - {groupByKindEntries.map(([kind, entitiesByKind], index) => ( - - ))} + {groupByKind && + groupByKindEntries.map(([kind, entitiesByKind], index) => ( + + ))}
); }; From 844969cd979edccbd0fa0f1b58dcc43ee53d66e8 Mon Sep 17 00:00:00 2001 From: Andre Wanlin <67169551+awanlin@users.noreply.github.com> Date: Fri, 25 Aug 2023 15:17:03 -0500 Subject: [PATCH 006/261] Use AzureDevOpsCredentialsProvider Signed-off-by: Andre Wanlin <67169551+awanlin@users.noreply.github.com> --- .changeset/unlucky-clouds-build.md | 5 ++ plugins/azure-devops-backend/api-report.md | 3 +- plugins/azure-devops-backend/config.d.ts | 2 + plugins/azure-devops-backend/package.json | 1 + .../src/api/AzureDevOpsApi.ts | 72 ++++++++++++++----- .../src/service/router.ts | 15 ++-- yarn.lock | 1 + 7 files changed, 69 insertions(+), 30 deletions(-) create mode 100644 .changeset/unlucky-clouds-build.md diff --git a/.changeset/unlucky-clouds-build.md b/.changeset/unlucky-clouds-build.md new file mode 100644 index 0000000000..7bd1cb0644 --- /dev/null +++ b/.changeset/unlucky-clouds-build.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-azure-devops-backend': patch +--- + +Added support for using `AzureDevOpsCredentialsProvider` and deprecated `azureDevOps.token` configuration value diff --git a/plugins/azure-devops-backend/api-report.md b/plugins/azure-devops-backend/api-report.md index 8c916a1495..4cdccc6ffc 100644 --- a/plugins/azure-devops-backend/api-report.md +++ b/plugins/azure-devops-backend/api-report.md @@ -20,11 +20,10 @@ import { RepoBuild } from '@backstage/plugin-azure-devops-common'; import { Team } from '@backstage/plugin-azure-devops-common'; import { TeamMember } from '@backstage/plugin-azure-devops-common'; import { UrlReader } from '@backstage/backend-common'; -import { WebApi } from 'azure-devops-node-api'; // @public (undocumented) export class AzureDevOpsApi { - constructor(logger: Logger, webApi: WebApi, urlReader: UrlReader); + constructor(logger: Logger, urlReader: UrlReader, config: Config); // (undocumented) getAllTeams(): Promise; // (undocumented) diff --git a/plugins/azure-devops-backend/config.d.ts b/plugins/azure-devops-backend/config.d.ts index 433e4df22f..39523a7a05 100644 --- a/plugins/azure-devops-backend/config.d.ts +++ b/plugins/azure-devops-backend/config.d.ts @@ -24,6 +24,8 @@ export interface Config { /** * Token used to authenticate requests. * @visibility secret + * @deprecated Use `integrations.azure` instead. + * @see https://backstage.io/docs/integrations/azure/locations */ token: string; /** diff --git a/plugins/azure-devops-backend/package.json b/plugins/azure-devops-backend/package.json index 030ac45088..69c278f491 100644 --- a/plugins/azure-devops-backend/package.json +++ b/plugins/azure-devops-backend/package.json @@ -31,6 +31,7 @@ "@backstage/backend-common": "workspace:^", "@backstage/backend-plugin-api": "workspace:^", "@backstage/config": "workspace:^", + "@backstage/integration": "workspace:^", "@backstage/plugin-azure-devops-common": "workspace:^", "@types/express": "^4.17.6", "azure-devops-node-api": "^11.0.1", diff --git a/plugins/azure-devops-backend/src/api/AzureDevOpsApi.ts b/plugins/azure-devops-backend/src/api/AzureDevOpsApi.ts index 87ded2f0e9..ecd0e4704a 100644 --- a/plugins/azure-devops-backend/src/api/AzureDevOpsApi.ts +++ b/plugins/azure-devops-backend/src/api/AzureDevOpsApi.ts @@ -49,23 +49,51 @@ import { import { TeamMember as AdoTeamMember } from 'azure-devops-node-api/interfaces/common/VSSInterfaces'; import { Logger } from 'winston'; import { PolicyEvaluationRecord } from 'azure-devops-node-api/interfaces/PolicyInterfaces'; -import { WebApi } from 'azure-devops-node-api'; +import { WebApi, getPersonalAccessTokenHandler } from 'azure-devops-node-api'; import { TeamProjectReference, WebApiTeam, } from 'azure-devops-node-api/interfaces/CoreInterfaces'; import { UrlReader } from '@backstage/backend-common'; +import { Config } from '@backstage/config'; +import { + DefaultAzureDevOpsCredentialsProvider, + ScmIntegrations, +} from '@backstage/integration'; /** @public */ export class AzureDevOpsApi { public constructor( private readonly logger: Logger, - private readonly webApi: WebApi, private readonly urlReader: UrlReader, + private readonly config: Config, ) {} + private async getWebApi(host?: string, org?: string): Promise { + const validHost = host ?? this.config.getString('azureDevOps.host'); + const validOrg = org ?? this.config.getString('azureDevOps.organization'); + const scmIntegrations = ScmIntegrations.fromConfig(this.config); + const credentialsProvider = + DefaultAzureDevOpsCredentialsProvider.fromIntegrations(scmIntegrations); + const credentials = await credentialsProvider.getCredentials({ + url: `https://${validHost}/${validOrg}`, + }); + + let validToken: string; + if (credentials && credentials.token) { + validToken = credentials.token; + } else { + validToken = this.config.getString('azureDevOps.token'); + } + + const authHandler = getPersonalAccessTokenHandler(validToken); + const webApi = new WebApi(`https://${validHost}/${validOrg}`, authHandler); + return webApi; + } + public async getProjects(): Promise { - const client = await this.webApi.getCoreApi(); + const webApi = await this.getWebApi(); + const client = await webApi.getCoreApi(); const projectList: TeamProjectReference[] = await client.getProjects(); const projects: Project[] = projectList.map(project => ({ @@ -87,7 +115,8 @@ export class AzureDevOpsApi { `Calling Azure DevOps REST API, getting Repository ${repoName} for Project ${projectName}`, ); - const client = await this.webApi.getGitApi(); + const webApi = await this.getWebApi(); + const client = await webApi.getGitApi(); return client.getRepository(repoName, projectName); } @@ -100,7 +129,8 @@ export class AzureDevOpsApi { `Calling Azure DevOps REST API, getting up to ${top} Builds for Repository Id ${repoId} for Project ${projectName}`, ); - const client = await this.webApi.getBuildApi(); + const webApi = await this.getWebApi(); + const client = await webApi.getBuildApi(); return client.getBuilds( projectName, undefined, @@ -158,7 +188,8 @@ export class AzureDevOpsApi { ); const gitRepository = await this.getGitRepository(projectName, repoName); - const client = await this.webApi.getGitApi(); + const webApi = await this.getWebApi(); + const client = await webApi.getGitApi(); const tagRefs: GitRef[] = await client.getRefs( gitRepository.id as string, projectName, @@ -169,10 +200,10 @@ export class AzureDevOpsApi { false, true, ); - const linkBaseUrl = `${this.webApi.serverUrl}/${encodeURIComponent( + const linkBaseUrl = `${webApi.serverUrl}/${encodeURIComponent( projectName, )}/_git/${encodeURIComponent(repoName)}?version=GT`; - const commitBaseUrl = `${this.webApi.serverUrl}/${encodeURIComponent( + const commitBaseUrl = `${webApi.serverUrl}/${encodeURIComponent( projectName, )}/_git/${encodeURIComponent(repoName)}/commit`; const gitTags: GitTag[] = tagRefs.map(tagRef => { @@ -192,7 +223,8 @@ export class AzureDevOpsApi { ); const gitRepository = await this.getGitRepository(projectName, repoName); - const client = await this.webApi.getGitApi(); + const webApi = await this.getWebApi(); + const client = await webApi.getGitApi(); const searchCriteria: GitPullRequestSearchCriteria = { status: options.status, }; @@ -204,7 +236,7 @@ export class AzureDevOpsApi { undefined, options.top, ); - const linkBaseUrl = `${this.webApi.serverUrl}/${encodeURIComponent( + const linkBaseUrl = `${webApi.serverUrl}/${encodeURIComponent( projectName, )}/_git/${encodeURIComponent(repoName)}/pullrequest`; const pullRequests: PullRequest[] = gitPullRequests.map(gitPullRequest => { @@ -222,7 +254,8 @@ export class AzureDevOpsApi { `Getting dashboard pull requests for project '${projectName}'.`, ); - const client = await this.webApi.getGitApi(); + const webApi = await this.getWebApi(); + const client = await webApi.getGitApi(); const searchCriteria: GitPullRequestSearchCriteria = { status: options.status, @@ -254,7 +287,7 @@ export class AzureDevOpsApi { return convertDashboardPullRequest( gitPullRequest, - this.webApi.serverUrl, + webApi.serverUrl, policies, ); }), @@ -270,7 +303,8 @@ export class AzureDevOpsApi { `Getting pull request policies for pull request id '${pullRequestId}'.`, ); - const client = await this.webApi.getPolicyApi(); + const webApi = await this.getWebApi(); + const client = await webApi.getPolicyApi(); const artifactId = getArtifactId(projectId, pullRequestId); @@ -285,7 +319,8 @@ export class AzureDevOpsApi { public async getAllTeams(): Promise { this.logger?.debug('Getting all teams.'); - const client = await this.webApi.getCoreApi(); + const webApi = await this.getWebApi(); + const client = await webApi.getCoreApi(); const webApiTeams: WebApiTeam[] = await client.getAllTeams(); const teams: Team[] = webApiTeams.map(team => ({ @@ -307,7 +342,8 @@ export class AzureDevOpsApi { const { projectId, teamId } = options; this.logger?.debug(`Getting team member ids for team '${teamId}'.`); - const client = await this.webApi.getCoreApi(); + const webApi = await this.getWebApi(); + const client = await webApi.getCoreApi(); const teamMembers: AdoTeamMember[] = await client.getTeamMembersWithExtendedProperties(projectId, teamId); @@ -327,7 +363,8 @@ export class AzureDevOpsApi { `Calling Azure DevOps REST API, getting Build Definitions for ${definitionName} in Project ${projectName}`, ); - const client = await this.webApi.getBuildApi(); + const webApi = await this.getWebApi(); + const client = await webApi.getBuildApi(); return client.getDefinitions(projectName, definitionName); } @@ -341,7 +378,8 @@ export class AzureDevOpsApi { `Calling Azure DevOps REST API, getting up to ${top} Builds for Repository Id ${repoId} for Project ${projectName}`, ); - const client = await this.webApi.getBuildApi(); + const webApi = await this.getWebApi(); + const client = await webApi.getBuildApi(); return client.getBuilds( projectName, definitions, diff --git a/plugins/azure-devops-backend/src/service/router.ts b/plugins/azure-devops-backend/src/service/router.ts index b6b8a6fdea..13d8a78d96 100644 --- a/plugins/azure-devops-backend/src/service/router.ts +++ b/plugins/azure-devops-backend/src/service/router.ts @@ -19,7 +19,6 @@ import { PullRequestOptions, PullRequestStatus, } from '@backstage/plugin-azure-devops-common'; -import { WebApi, getPersonalAccessTokenHandler } from 'azure-devops-node-api'; import { AzureDevOpsApi } from '../api'; import { Config } from '@backstage/config'; @@ -43,18 +42,10 @@ export interface RouterOptions { export async function createRouter( options: RouterOptions, ): Promise { - const { logger, reader } = options; - const config = options.config.getConfig('azureDevOps'); - - const token = config.getString('token'); - const host = config.getString('host'); - const organization = config.getString('organization'); - - const authHandler = getPersonalAccessTokenHandler(token); - const webApi = new WebApi(`https://${host}/${organization}`, authHandler); + const { logger, reader, config } = options; const azureDevOpsApi = - options.azureDevOpsApi || new AzureDevOpsApi(logger, webApi, reader); + options.azureDevOpsApi || new AzureDevOpsApi(logger, reader, config); const pullRequestsDashboardProvider = await PullRequestsDashboardProvider.create(logger, azureDevOpsApi); @@ -195,6 +186,8 @@ export async function createRouter( }); router.get('/readme/:projectName/:repoName', async (req, res) => { + const host = config.getString('azureDevOps.host'); + const organization = config.getString('azureDevOps.organization'); const { projectName, repoName } = req.params; const readme = await azureDevOpsApi.getReadme( host, diff --git a/yarn.lock b/yarn.lock index 0a5ad1d720..89923ecd97 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5077,6 +5077,7 @@ __metadata: "@backstage/backend-plugin-api": "workspace:^" "@backstage/cli": "workspace:^" "@backstage/config": "workspace:^" + "@backstage/integration": "workspace:^" "@backstage/plugin-azure-devops-common": "workspace:^" "@types/express": ^4.17.6 "@types/supertest": ^2.0.8 From 38a8135171385e5f2c60859743aa86dac3db0a31 Mon Sep 17 00:00:00 2001 From: Andre Wanlin Date: Sun, 22 Oct 2023 11:42:01 -0500 Subject: [PATCH 007/261] Use correct authHandler Signed-off-by: Andre Wanlin --- .../src/api/AzureDevOpsApi.ts | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/plugins/azure-devops-backend/src/api/AzureDevOpsApi.ts b/plugins/azure-devops-backend/src/api/AzureDevOpsApi.ts index ecd0e4704a..451d5a9a71 100644 --- a/plugins/azure-devops-backend/src/api/AzureDevOpsApi.ts +++ b/plugins/azure-devops-backend/src/api/AzureDevOpsApi.ts @@ -49,7 +49,11 @@ import { import { TeamMember as AdoTeamMember } from 'azure-devops-node-api/interfaces/common/VSSInterfaces'; import { Logger } from 'winston'; import { PolicyEvaluationRecord } from 'azure-devops-node-api/interfaces/PolicyInterfaces'; -import { WebApi, getPersonalAccessTokenHandler } from 'azure-devops-node-api'; +import { + WebApi, + getBearerHandler, + getPersonalAccessTokenHandler, +} from 'azure-devops-node-api'; import { TeamProjectReference, WebApiTeam, @@ -72,22 +76,22 @@ export class AzureDevOpsApi { private async getWebApi(host?: string, org?: string): Promise { const validHost = host ?? this.config.getString('azureDevOps.host'); const validOrg = org ?? this.config.getString('azureDevOps.organization'); + const url = `https://${validHost}/${validOrg}`; + const scmIntegrations = ScmIntegrations.fromConfig(this.config); const credentialsProvider = DefaultAzureDevOpsCredentialsProvider.fromIntegrations(scmIntegrations); const credentials = await credentialsProvider.getCredentials({ - url: `https://${validHost}/${validOrg}`, + url, }); - let validToken: string; - if (credentials && credentials.token) { - validToken = credentials.token; - } else { - validToken = this.config.getString('azureDevOps.token'); - } - - const authHandler = getPersonalAccessTokenHandler(validToken); - const webApi = new WebApi(`https://${validHost}/${validOrg}`, authHandler); + const authHandler = + this.config.getString('azureDevOps.token') || credentials?.type === 'pat' + ? getPersonalAccessTokenHandler( + credentials!.token ?? this.config.getString('azureDevOps.token'), + ) + : getBearerHandler(credentials!.token); + const webApi = new WebApi(url, authHandler); return webApi; } From cec7146643aa6f77a9bd09e895b22b9caafb3c6f Mon Sep 17 00:00:00 2001 From: Andre Wanlin Date: Sun, 22 Oct 2023 12:14:01 -0500 Subject: [PATCH 008/261] Added factory Signed-off-by: Andre Wanlin --- plugins/azure-devops-backend/api-report.md | 9 +++++++- .../src/api/AzureDevOpsApi.ts | 21 ++++++++++++++----- .../src/service/router.ts | 3 ++- 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/plugins/azure-devops-backend/api-report.md b/plugins/azure-devops-backend/api-report.md index 4cdccc6ffc..35faecd827 100644 --- a/plugins/azure-devops-backend/api-report.md +++ b/plugins/azure-devops-backend/api-report.md @@ -23,7 +23,14 @@ import { UrlReader } from '@backstage/backend-common'; // @public (undocumented) export class AzureDevOpsApi { - constructor(logger: Logger, urlReader: UrlReader, config: Config); + // (undocumented) + static fromConfig( + config: Config, + options: { + logger: Logger; + urlReader: UrlReader; + }, + ): AzureDevOpsApi; // (undocumented) getAllTeams(): Promise; // (undocumented) diff --git a/plugins/azure-devops-backend/src/api/AzureDevOpsApi.ts b/plugins/azure-devops-backend/src/api/AzureDevOpsApi.ts index 451d5a9a71..ffc0fd24d1 100644 --- a/plugins/azure-devops-backend/src/api/AzureDevOpsApi.ts +++ b/plugins/azure-devops-backend/src/api/AzureDevOpsApi.ts @@ -67,11 +67,22 @@ import { /** @public */ export class AzureDevOpsApi { - public constructor( - private readonly logger: Logger, - private readonly urlReader: UrlReader, - private readonly config: Config, - ) {} + private readonly logger: Logger; + private readonly urlReader: UrlReader; + private readonly config: Config; + + private constructor(logger: Logger, urlReader: UrlReader, config: Config) { + this.logger = logger; + this.urlReader = urlReader; + this.config = config; + } + + static fromConfig( + config: Config, + options: { logger: Logger; urlReader: UrlReader }, + ) { + return new AzureDevOpsApi(options.logger, options.urlReader, config); + } private async getWebApi(host?: string, org?: string): Promise { const validHost = host ?? this.config.getString('azureDevOps.host'); diff --git a/plugins/azure-devops-backend/src/service/router.ts b/plugins/azure-devops-backend/src/service/router.ts index 13d8a78d96..9fc762f1a7 100644 --- a/plugins/azure-devops-backend/src/service/router.ts +++ b/plugins/azure-devops-backend/src/service/router.ts @@ -45,7 +45,8 @@ export async function createRouter( const { logger, reader, config } = options; const azureDevOpsApi = - options.azureDevOpsApi || new AzureDevOpsApi(logger, reader, config); + options.azureDevOpsApi || + AzureDevOpsApi.fromConfig(config, { logger, urlReader: reader }); const pullRequestsDashboardProvider = await PullRequestsDashboardProvider.create(logger, azureDevOpsApi); From 9dbebe8f84cd4504695d40029c5004e91fcf9a49 Mon Sep 17 00:00:00 2001 From: Andre Wanlin Date: Mon, 30 Oct 2023 10:10:16 -0500 Subject: [PATCH 009/261] Improved getWebApi based on feedback Signed-off-by: Andre Wanlin --- .../azure-devops-backend/src/api/AzureDevOpsApi.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/plugins/azure-devops-backend/src/api/AzureDevOpsApi.ts b/plugins/azure-devops-backend/src/api/AzureDevOpsApi.ts index ffc0fd24d1..bdfd7b1b82 100644 --- a/plugins/azure-devops-backend/src/api/AzureDevOpsApi.ts +++ b/plugins/azure-devops-backend/src/api/AzureDevOpsApi.ts @@ -70,11 +70,16 @@ export class AzureDevOpsApi { private readonly logger: Logger; private readonly urlReader: UrlReader; private readonly config: Config; + private readonly credentialsProvider: DefaultAzureDevOpsCredentialsProvider; private constructor(logger: Logger, urlReader: UrlReader, config: Config) { this.logger = logger; this.urlReader = urlReader; this.config = config; + + const scmIntegrations = ScmIntegrations.fromConfig(this.config); + this.credentialsProvider = + DefaultAzureDevOpsCredentialsProvider.fromIntegrations(scmIntegrations); } static fromConfig( @@ -89,15 +94,14 @@ export class AzureDevOpsApi { const validOrg = org ?? this.config.getString('azureDevOps.organization'); const url = `https://${validHost}/${validOrg}`; - const scmIntegrations = ScmIntegrations.fromConfig(this.config); - const credentialsProvider = - DefaultAzureDevOpsCredentialsProvider.fromIntegrations(scmIntegrations); - const credentials = await credentialsProvider.getCredentials({ + const credentials = await this.credentialsProvider.getCredentials({ url, }); + // TODO:(awanlin) use `getHandlerFromToken` once we no longer + // need to support the 'azureDevOps.token' fallback config value const authHandler = - this.config.getString('azureDevOps.token') || credentials?.type === 'pat' + credentials?.type === 'pat' ? getPersonalAccessTokenHandler( credentials!.token ?? this.config.getString('azureDevOps.token'), ) From c8f2b807c0573996548e6b9b7edf60f688437673 Mon Sep 17 00:00:00 2001 From: Andre Wanlin Date: Thu, 16 Nov 2023 11:24:11 -0600 Subject: [PATCH 010/261] Changes based on latest feedback Signed-off-by: Andre Wanlin --- .changeset/unlucky-clouds-build.md | 6 ++- plugins/azure-devops-backend/config.d.ts | 9 +++- .../src/api/AzureDevOpsApi.ts | 50 ++++++++++++------- 3 files changed, 45 insertions(+), 20 deletions(-) diff --git a/.changeset/unlucky-clouds-build.md b/.changeset/unlucky-clouds-build.md index 7bd1cb0644..6f7813a8e6 100644 --- a/.changeset/unlucky-clouds-build.md +++ b/.changeset/unlucky-clouds-build.md @@ -1,5 +1,7 @@ --- -'@backstage/plugin-azure-devops-backend': patch +'@backstage/plugin-azure-devops-backend': minor --- -Added support for using `AzureDevOpsCredentialsProvider` and deprecated `azureDevOps.token` configuration value +**BREAKING** New `fromConfig` static method must be used now when created an instance of the `AzureDevOpsApi` + +Added support for using the `AzureDevOpsCredentialsProvider` and deprecated the entire `azureDevOps` configuration section diff --git a/plugins/azure-devops-backend/config.d.ts b/plugins/azure-devops-backend/config.d.ts index 39523a7a05..c973a0595f 100644 --- a/plugins/azure-devops-backend/config.d.ts +++ b/plugins/azure-devops-backend/config.d.ts @@ -15,10 +15,15 @@ */ export interface Config { - /** Configuration options for the azure-devops-backend plugin */ + /** Configuration options for the azure-devops-backend plugin + * @deprecated Use `integrations.azure` instead. + * @see https://backstage.io/docs/integrations/azure/locations + */ azureDevOps: { /** * The hostname of the given Azure instance + * @deprecated Use `integrations.azure` instead. + * @see https://backstage.io/docs/integrations/azure/locations */ host: string; /** @@ -30,6 +35,8 @@ export interface Config { token: string; /** * The organization of the given Azure instance + * @deprecated Use `integrations.azure` instead. + * @see https://backstage.io/docs/integrations/azure/locations */ organization: string; }; diff --git a/plugins/azure-devops-backend/src/api/AzureDevOpsApi.ts b/plugins/azure-devops-backend/src/api/AzureDevOpsApi.ts index bdfd7b1b82..f02d681f56 100644 --- a/plugins/azure-devops-backend/src/api/AzureDevOpsApi.ts +++ b/plugins/azure-devops-backend/src/api/AzureDevOpsApi.ts @@ -51,7 +51,7 @@ import { Logger } from 'winston'; import { PolicyEvaluationRecord } from 'azure-devops-node-api/interfaces/PolicyInterfaces'; import { WebApi, - getBearerHandler, + getHandlerFromToken, getPersonalAccessTokenHandler, } from 'azure-devops-node-api'; import { @@ -61,6 +61,7 @@ import { import { UrlReader } from '@backstage/backend-common'; import { Config } from '@backstage/config'; import { + AzureDevOpsCredentialsProvider, DefaultAzureDevOpsCredentialsProvider, ScmIntegrations, } from '@backstage/integration'; @@ -70,42 +71,57 @@ export class AzureDevOpsApi { private readonly logger: Logger; private readonly urlReader: UrlReader; private readonly config: Config; - private readonly credentialsProvider: DefaultAzureDevOpsCredentialsProvider; + private readonly credentialsProvider: AzureDevOpsCredentialsProvider; - private constructor(logger: Logger, urlReader: UrlReader, config: Config) { + private constructor( + logger: Logger, + urlReader: UrlReader, + config: Config, + credentialsProvider: AzureDevOpsCredentialsProvider, + ) { this.logger = logger; this.urlReader = urlReader; this.config = config; - - const scmIntegrations = ScmIntegrations.fromConfig(this.config); - this.credentialsProvider = - DefaultAzureDevOpsCredentialsProvider.fromIntegrations(scmIntegrations); + this.credentialsProvider = credentialsProvider; } static fromConfig( config: Config, options: { logger: Logger; urlReader: UrlReader }, ) { - return new AzureDevOpsApi(options.logger, options.urlReader, config); + const scmIntegrations = ScmIntegrations.fromConfig(config); + const credentialsProvider = + DefaultAzureDevOpsCredentialsProvider.fromIntegrations(scmIntegrations); + return new AzureDevOpsApi( + options.logger, + options.urlReader, + config, + credentialsProvider, + ); } private async getWebApi(host?: string, org?: string): Promise { + // If no host or org is provided we fall back to the values from the `azureDevOps` config section + // these may have been setup in the `integrations.azure` config section + // which is why use them here and not just falling back on them entirely const validHost = host ?? this.config.getString('azureDevOps.host'); const validOrg = org ?? this.config.getString('azureDevOps.organization'); - const url = `https://${validHost}/${validOrg}`; + const url = `https://${validHost}/${encodeURI(validOrg)}`; const credentials = await this.credentialsProvider.getCredentials({ url, }); - // TODO:(awanlin) use `getHandlerFromToken` once we no longer - // need to support the 'azureDevOps.token' fallback config value - const authHandler = - credentials?.type === 'pat' - ? getPersonalAccessTokenHandler( - credentials!.token ?? this.config.getString('azureDevOps.token'), - ) - : getBearerHandler(credentials!.token); + let authHandler; + if (!credentials) { + // No credentials found for the provided host and org in the `integrations.azure` config section + // use the fall back personal access token from `azureDevOps.token` + const token = this.config.getString('azureDevOps.token'); + authHandler = getPersonalAccessTokenHandler(token); + } else { + authHandler = getHandlerFromToken(credentials.token); + } + const webApi = new WebApi(url, authHandler); return webApi; } From 6c178e1bf28a11232c8d2170b8fef6fafe201d0f Mon Sep 17 00:00:00 2001 From: Andre Wanlin Date: Thu, 16 Nov 2023 11:45:20 -0600 Subject: [PATCH 011/261] Refactored mappers and their tests Signed-off-by: Andre Wanlin --- .../src/api/AzureDevOpsApi.ts | 80 ++------------ ...AzureDevOpsApi.test.ts => mappers.test.ts} | 2 +- .../azure-devops-backend/src/api/mappers.ts | 101 ++++++++++++++++++ 3 files changed, 108 insertions(+), 75 deletions(-) rename plugins/azure-devops-backend/src/api/{AzureDevOpsApi.test.ts => mappers.test.ts} (99%) create mode 100644 plugins/azure-devops-backend/src/api/mappers.ts diff --git a/plugins/azure-devops-backend/src/api/AzureDevOpsApi.ts b/plugins/azure-devops-backend/src/api/AzureDevOpsApi.ts index f02d681f56..6765b54c05 100644 --- a/plugins/azure-devops-backend/src/api/AzureDevOpsApi.ts +++ b/plugins/azure-devops-backend/src/api/AzureDevOpsApi.ts @@ -19,9 +19,7 @@ import { BuildDefinitionReference, } from 'azure-devops-node-api/interfaces/BuildInterfaces'; import { - BuildResult, BuildRun, - BuildStatus, DashboardPullRequest, GitTag, Policy, @@ -65,6 +63,12 @@ import { DefaultAzureDevOpsCredentialsProvider, ScmIntegrations, } from '@backstage/integration'; +import { + mappedBuildRun, + mappedGitTag, + mappedPullRequest, + mappedRepoBuild, +} from './mappers'; /** @public */ export class AzureDevOpsApi { @@ -494,75 +498,3 @@ export class AzureDevOpsApi { return { url, content }; } } - -export function mappedRepoBuild(build: Build): RepoBuild { - return { - id: build.id, - title: [build.definition?.name, build.buildNumber] - .filter(Boolean) - .join(' - '), - link: build._links?.web.href ?? '', - status: build.status ?? BuildStatus.None, - result: build.result ?? BuildResult.None, - queueTime: build.queueTime?.toISOString(), - startTime: build.startTime?.toISOString(), - finishTime: build.finishTime?.toISOString(), - source: `${build.sourceBranch} (${build.sourceVersion?.slice(0, 8)})`, - uniqueName: build.requestedFor?.uniqueName ?? 'N/A', - }; -} - -export function mappedGitTag( - gitRef: GitRef, - linkBaseUrl: string, - commitBaseUrl: string, -): GitTag { - return { - objectId: gitRef.objectId, - peeledObjectId: gitRef.peeledObjectId, - name: gitRef.name?.replace('refs/tags/', ''), - createdBy: gitRef.creator?.displayName ?? 'N/A', - link: `${linkBaseUrl}${encodeURIComponent( - gitRef.name?.replace('refs/tags/', '') ?? '', - )}`, - commitLink: `${commitBaseUrl}/${encodeURIComponent( - gitRef.peeledObjectId ?? '', - )}`, - }; -} - -export function mappedPullRequest( - pullRequest: GitPullRequest, - linkBaseUrl: string, -): PullRequest { - return { - pullRequestId: pullRequest.pullRequestId, - repoName: pullRequest.repository?.name, - title: pullRequest.title, - uniqueName: pullRequest.createdBy?.uniqueName ?? 'N/A', - createdBy: pullRequest.createdBy?.displayName ?? 'N/A', - creationDate: pullRequest.creationDate?.toISOString(), - sourceRefName: pullRequest.sourceRefName, - targetRefName: pullRequest.targetRefName, - status: pullRequest.status, - isDraft: pullRequest.isDraft, - link: `${linkBaseUrl}/${pullRequest.pullRequestId}`, - }; -} - -export function mappedBuildRun(build: Build): BuildRun { - return { - id: build.id, - title: [build.definition?.name, build.buildNumber] - .filter(Boolean) - .join(' - '), - link: build._links?.web.href ?? '', - status: build.status ?? BuildStatus.None, - result: build.result ?? BuildResult.None, - queueTime: build.queueTime?.toISOString(), - startTime: build.startTime?.toISOString(), - finishTime: build.finishTime?.toISOString(), - source: `${build.sourceBranch} (${build.sourceVersion?.slice(0, 8)})`, - uniqueName: build.requestedFor?.uniqueName ?? 'N/A', - }; -} diff --git a/plugins/azure-devops-backend/src/api/AzureDevOpsApi.test.ts b/plugins/azure-devops-backend/src/api/mappers.test.ts similarity index 99% rename from plugins/azure-devops-backend/src/api/AzureDevOpsApi.test.ts rename to plugins/azure-devops-backend/src/api/mappers.test.ts index dade60f1ed..85c82a2a14 100644 --- a/plugins/azure-devops-backend/src/api/AzureDevOpsApi.test.ts +++ b/plugins/azure-devops-backend/src/api/mappers.test.ts @@ -36,7 +36,7 @@ import { mappedGitTag, mappedPullRequest, mappedRepoBuild, -} from './AzureDevOpsApi'; +} from './mappers'; import { IdentityRef } from 'azure-devops-node-api/interfaces/common/VSSInterfaces'; diff --git a/plugins/azure-devops-backend/src/api/mappers.ts b/plugins/azure-devops-backend/src/api/mappers.ts new file mode 100644 index 0000000000..72097a25b8 --- /dev/null +++ b/plugins/azure-devops-backend/src/api/mappers.ts @@ -0,0 +1,101 @@ +/* + * 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 { + RepoBuild, + BuildStatus, + BuildResult, + GitTag, + PullRequest, + BuildRun, +} from '@backstage/plugin-azure-devops-common'; +import { Build } from 'azure-devops-node-api/interfaces/BuildInterfaces'; +import { + GitRef, + GitPullRequest, +} from 'azure-devops-node-api/interfaces/GitInterfaces'; + +export function mappedRepoBuild(build: Build): RepoBuild { + return { + id: build.id, + title: [build.definition?.name, build.buildNumber] + .filter(Boolean) + .join(' - '), + link: build._links?.web.href ?? '', + status: build.status ?? BuildStatus.None, + result: build.result ?? BuildResult.None, + queueTime: build.queueTime?.toISOString(), + startTime: build.startTime?.toISOString(), + finishTime: build.finishTime?.toISOString(), + source: `${build.sourceBranch} (${build.sourceVersion?.slice(0, 8)})`, + uniqueName: build.requestedFor?.uniqueName ?? 'N/A', + }; +} + +export function mappedGitTag( + gitRef: GitRef, + linkBaseUrl: string, + commitBaseUrl: string, +): GitTag { + return { + objectId: gitRef.objectId, + peeledObjectId: gitRef.peeledObjectId, + name: gitRef.name?.replace('refs/tags/', ''), + createdBy: gitRef.creator?.displayName ?? 'N/A', + link: `${linkBaseUrl}${encodeURIComponent( + gitRef.name?.replace('refs/tags/', '') ?? '', + )}`, + commitLink: `${commitBaseUrl}/${encodeURIComponent( + gitRef.peeledObjectId ?? '', + )}`, + }; +} + +export function mappedPullRequest( + pullRequest: GitPullRequest, + linkBaseUrl: string, +): PullRequest { + return { + pullRequestId: pullRequest.pullRequestId, + repoName: pullRequest.repository?.name, + title: pullRequest.title, + uniqueName: pullRequest.createdBy?.uniqueName ?? 'N/A', + createdBy: pullRequest.createdBy?.displayName ?? 'N/A', + creationDate: pullRequest.creationDate?.toISOString(), + sourceRefName: pullRequest.sourceRefName, + targetRefName: pullRequest.targetRefName, + status: pullRequest.status, + isDraft: pullRequest.isDraft, + link: `${linkBaseUrl}/${pullRequest.pullRequestId}`, + }; +} + +export function mappedBuildRun(build: Build): BuildRun { + return { + id: build.id, + title: [build.definition?.name, build.buildNumber] + .filter(Boolean) + .join(' - '), + link: build._links?.web.href ?? '', + status: build.status ?? BuildStatus.None, + result: build.result ?? BuildResult.None, + queueTime: build.queueTime?.toISOString(), + startTime: build.startTime?.toISOString(), + finishTime: build.finishTime?.toISOString(), + source: `${build.sourceBranch} (${build.sourceVersion?.slice(0, 8)})`, + uniqueName: build.requestedFor?.uniqueName ?? 'N/A', + }; +} From 9cdec4837515e45f56dd2cac7c1b154891b6d49d Mon Sep 17 00:00:00 2001 From: Garath620 Date: Fri, 17 Nov 2023 10:25:17 +0100 Subject: [PATCH 012/261] Fix push expression in deploy_docker-image.yml Signed-off-by: Garath620 --- .github/workflows/deploy_docker-image.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy_docker-image.yml b/.github/workflows/deploy_docker-image.yml index 65ded2b19b..db51c1af4c 100644 --- a/.github/workflows/deploy_docker-image.yml +++ b/.github/workflows/deploy_docker-image.yml @@ -61,7 +61,7 @@ jobs: with: context: './example-app' file: ./example-app/packages/backend/Dockerfile - push: ${{ github.event_name == "repository_dispatch" && github.event.action == "release-published" }} + push: ${{ (github.event_name == "repository_dispatch") && (github.event.action == "release-published") }} platforms: linux/amd64,linux/arm64 tags: | ghcr.io/${{ github.repository_owner }}/backstage:latest From 82a42f34a1565028436890b96eb48104b5363cbb Mon Sep 17 00:00:00 2001 From: Philipp Hugenroth Date: Fri, 2 Jun 2023 17:01:00 +0200 Subject: [PATCH 013/261] Add Migrating to v5 Guide in Custom Theme Documentation Signed-off-by: Philipp Hugenroth --- docs/getting-started/app-custom-theme.md | 25 ++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/docs/getting-started/app-custom-theme.md b/docs/getting-started/app-custom-theme.md index 3b042d5eb4..dff7754852 100644 --- a/docs/getting-started/app-custom-theme.md +++ b/docs/getting-started/app-custom-theme.md @@ -484,3 +484,28 @@ You can see more ways to use this in the [Storybook Sidebar examples](https://ba In addition to a custom theme, a custom logo, you can also customize the homepage of your app. Read the full guide on the [next page](homepage.md). + +## Migrating to Material UI v5 + +For supporting Material UI v5 in addition to v4 we introduced a `UnifiedThemeProvider` allowing a step-by-step migration. To use it you have to update your App's `ThemeProvider` in `app/src/App.tsx` like the following: + +```diff + Provider: ({ children }) => ( +- +- {children} +- ++ + ), +``` + +When you are looking for migrating code from v4 to v5 the [Migration Guide provided by MUI](https://mui.com/material-ui/migration/migration-v4/) might be a helpful resource. It is worth mentioning that we are still using `@mui/styles` & thereby `jss`. You might stumble accross the migration to `emotion` for `makeStyles` or `withStyles`. It is not required to move to `emotion` yet. + +### Plugins + +To migrate your plugin to MUI v5 you can build up on the resources available. + +1. Run the migration `codemod` for the path of the specific plug: `npx @mui/codemod v5.0.0/preset-safe ` +2. Manual fix imports to align with linting rules & take a look at potential `TODO:` items the `codemod` could not fix. +3. Remove types & methods from `@backstage/theme`, which are marked as `@deprecated` + +You can follow the [migration of the GraphiQL plugin](https://github.com/backstage/backstage/pull/17696) as an example plugin migration. From ecc4e417e4d7a8be4ea39e80f75741dd37db57ff Mon Sep 17 00:00:00 2001 From: Philipp Hugenroth Date: Tue, 13 Jun 2023 13:04:40 +0200 Subject: [PATCH 014/261] Improve English & add additional information from feedback Signed-off-by: Philipp Hugenroth --- docs/getting-started/app-custom-theme.md | 26 ++++++++++++++---------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/docs/getting-started/app-custom-theme.md b/docs/getting-started/app-custom-theme.md index dff7754852..bbbb878942 100644 --- a/docs/getting-started/app-custom-theme.md +++ b/docs/getting-started/app-custom-theme.md @@ -487,25 +487,29 @@ homepage of your app. Read the full guide on the [next page](homepage.md). ## Migrating to Material UI v5 -For supporting Material UI v5 in addition to v4 we introduced a `UnifiedThemeProvider` allowing a step-by-step migration. To use it you have to update your App's `ThemeProvider` in `app/src/App.tsx` like the following: +To support Material UI v5 in addition to v4, we have introduced a `UnifiedThemeProvider`. This allows a step-by-step migration. To use it, you need to update your app's `ThemeProvider` in `app/src/App.tsx` as follows ```diff - Provider: ({ children }) => ( -- -- {children} -- -+ + provider: ({ children }) => ( +- . +- {children}. +- ), ``` -When you are looking for migrating code from v4 to v5 the [Migration Guide provided by MUI](https://mui.com/material-ui/migration/migration-v4/) might be a helpful resource. It is worth mentioning that we are still using `@mui/styles` & thereby `jss`. You might stumble accross the migration to `emotion` for `makeStyles` or `withStyles`. It is not required to move to `emotion` yet. +In addition, the [Migration Guide provided by MUI](https://mui.com/material-ui/migration/migration-v4/) is a helpful resource that breaks down the differences between v4 & v5. It is worth noting that we are still using `@mui/styles` & `jss`. You may stumble upon documentation for migrating to `emotion` when using `makeStyles` or `withStyles`. It is not necessary to switch to `emotion` yet. + +To comply with MUI recommendations, we are enforcing a new linting rules that favours standard imports over named imports and also restricting 3rd level imports as they are considered private ([Guide: Minimizing Bundle Size](https://mui.com/material-ui/guides/minimizing-bundle-size)). + +For current knonw issues with the MUI v5 migration follow our [Milestone on GitHub](https://github.com/backstage/backstage/milestone/40). Please open a new issue if you run into different problems. ### Plugins -To migrate your plugin to MUI v5 you can build up on the resources available. +To migrate your plugin to MUI v5, you can build on the resources available. -1. Run the migration `codemod` for the path of the specific plug: `npx @mui/codemod v5.0.0/preset-safe ` -2. Manual fix imports to align with linting rules & take a look at potential `TODO:` items the `codemod` could not fix. -3. Remove types & methods from `@backstage/theme`, which are marked as `@deprecated` +1. Run the migration `codemod` for the path of the specific plugin: `npx @mui/codemod v5.0.0/preset-safe `. +2. Manually fix the imports to match the new [linting rules](https://mui.com/material-ui/guides/minimizing-bundle-size). Take a look at possible `TODO:` items the `codemod` could not fix. +3. Removal of types & methods from `@backstage/theme` which are marked as `@deprecated`. You can follow the [migration of the GraphiQL plugin](https://github.com/backstage/backstage/pull/17696) as an example plugin migration. From b4be4e630a7957dd15c346ffda5ac9e21958c042 Mon Sep 17 00:00:00 2001 From: Philipp Hugenroth Date: Tue, 13 Jun 2023 13:17:30 +0200 Subject: [PATCH 015/261] Move migration guides to tutorials Signed-off-by: Philipp Hugenroth --- docs/getting-started/app-custom-theme.md | 27 +------------------ docs/tutorials/migrate-to-mui5.md | 34 ++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 26 deletions(-) create mode 100644 docs/tutorials/migrate-to-mui5.md diff --git a/docs/getting-started/app-custom-theme.md b/docs/getting-started/app-custom-theme.md index bbbb878942..d6a13ca6e3 100644 --- a/docs/getting-started/app-custom-theme.md +++ b/docs/getting-started/app-custom-theme.md @@ -487,29 +487,4 @@ homepage of your app. Read the full guide on the [next page](homepage.md). ## Migrating to Material UI v5 -To support Material UI v5 in addition to v4, we have introduced a `UnifiedThemeProvider`. This allows a step-by-step migration. To use it, you need to update your app's `ThemeProvider` in `app/src/App.tsx` as follows - -```diff - provider: ({ children }) => ( -- . -- {children}. -- - ), -``` - -In addition, the [Migration Guide provided by MUI](https://mui.com/material-ui/migration/migration-v4/) is a helpful resource that breaks down the differences between v4 & v5. It is worth noting that we are still using `@mui/styles` & `jss`. You may stumble upon documentation for migrating to `emotion` when using `makeStyles` or `withStyles`. It is not necessary to switch to `emotion` yet. - -To comply with MUI recommendations, we are enforcing a new linting rules that favours standard imports over named imports and also restricting 3rd level imports as they are considered private ([Guide: Minimizing Bundle Size](https://mui.com/material-ui/guides/minimizing-bundle-size)). - -For current knonw issues with the MUI v5 migration follow our [Milestone on GitHub](https://github.com/backstage/backstage/milestone/40). Please open a new issue if you run into different problems. - -### Plugins - -To migrate your plugin to MUI v5, you can build on the resources available. - -1. Run the migration `codemod` for the path of the specific plugin: `npx @mui/codemod v5.0.0/preset-safe `. -2. Manually fix the imports to match the new [linting rules](https://mui.com/material-ui/guides/minimizing-bundle-size). Take a look at possible `TODO:` items the `codemod` could not fix. -3. Removal of types & methods from `@backstage/theme` which are marked as `@deprecated`. - -You can follow the [migration of the GraphiQL plugin](https://github.com/backstage/backstage/pull/17696) as an example plugin migration. +We now support Material UI v5 in Backstage. Check out our [migration guide](../tutorials/migrate-to-mui5.md) to get started. diff --git a/docs/tutorials/migrate-to-mui5.md b/docs/tutorials/migrate-to-mui5.md new file mode 100644 index 0000000000..f757094d4c --- /dev/null +++ b/docs/tutorials/migrate-to-mui5.md @@ -0,0 +1,34 @@ +--- +id: migrate-to-mui5 +title: Migrating from Material UI v4 to v5 +description: Additionally resources to the Material UI migration guide specifically for Backstage +--- + +Before diving into the specific changes in Backstage, it may be helpful to take a look at the [Migration Guide provided by MUI](https://mui.com/material-ui/migration/migration-v4/). It breaks down the differences between v4, v5 and will make it easier to understand the impact on your Backstage instance & plugins. + +To support Material UI v5 in addition to v4, we have introduced a `UnifiedThemeProvider`. This allows a gradual migration by running both versions in parallel. To use it, you need to update your app's `ThemeProvider` in `app/src/App.tsx` as follows: + +```diff + provider: ({ children }) => ( +- . +- {children}. +- + ), +``` + +It is worth noting that we are still using `@mui/styles` & `jss`. You may stumble upon documentation for migrating to `emotion` when using `makeStyles` or `withStyles`. It is not necessary to switch to `emotion` yet. + +To comply with MUI recommendations, we are enforcing a new linting rules that favours standard imports over named imports and also restricting 3rd level imports as they are considered private ([Guide: Minimizing Bundle Size](https://mui.com/material-ui/guides/minimizing-bundle-size)). + +For current knonw issues with the MUI v5 migration follow our [Milestone on GitHub](https://github.com/backstage/backstage/milestone/40). Please open a new issue if you run into different problems. + +### Plugins + +To migrate your plugin to MUI v5, you can build on the resources available. + +1. Run the migration `codemod` for the path of the specific plugin: `npx @mui/codemod v5.0.0/preset-safe `. +2. Manually fix the imports to match the new [linting rules](https://mui.com/material-ui/guides/minimizing-bundle-size). Take a look at possible `TODO:` items the `codemod` could not fix. +3. Removal of types & methods from `@backstage/theme` which are marked as `@deprecated`. + +You can follow the [migration of the GraphiQL plugin](https://github.com/backstage/backstage/pull/17696) as an example plugin migration. From cc0f489d1cc2a33b3953f43d93b99b423166ce81 Mon Sep 17 00:00:00 2001 From: Philipp Hugenroth Date: Mon, 19 Jun 2023 09:15:28 +0200 Subject: [PATCH 016/261] Update MUI 5 Migration doc Signed-off-by: Philipp Hugenroth --- docs/tutorials/migrate-to-mui5.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/tutorials/migrate-to-mui5.md b/docs/tutorials/migrate-to-mui5.md index f757094d4c..3bbb2b43af 100644 --- a/docs/tutorials/migrate-to-mui5.md +++ b/docs/tutorials/migrate-to-mui5.md @@ -27,8 +27,9 @@ For current knonw issues with the MUI v5 migration follow our [Milestone on GitH To migrate your plugin to MUI v5, you can build on the resources available. -1. Run the migration `codemod` for the path of the specific plugin: `npx @mui/codemod v5.0.0/preset-safe `. -2. Manually fix the imports to match the new [linting rules](https://mui.com/material-ui/guides/minimizing-bundle-size). Take a look at possible `TODO:` items the `codemod` could not fix. -3. Removal of types & methods from `@backstage/theme` which are marked as `@deprecated`. +1. Manually fix the imports from named to default imports to match the new [linting rules for minimizing bundle size](https://mui.com/material-ui/guides/minimizing-bundle-size). +2. Run the migration `codemod` for the path of the specific plugin: `npx @mui/codemod v5.0.0/preset-safe plugins/`. +3. Take a look at possible `TODO:` items the `codemod` could not fix. +4. Remove types & methods from `@backstage/theme` which are marked as `@deprecated`. You can follow the [migration of the GraphiQL plugin](https://github.com/backstage/backstage/pull/17696) as an example plugin migration. From 62c6901fe80a6a9874d0672f275e2f2bc11f6b47 Mon Sep 17 00:00:00 2001 From: Philipp Hugenroth Date: Mon, 19 Jun 2023 09:20:20 +0200 Subject: [PATCH 017/261] Fix spelling issue Signed-off-by: Philipp Hugenroth --- docs/tutorials/migrate-to-mui5.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/migrate-to-mui5.md b/docs/tutorials/migrate-to-mui5.md index 3bbb2b43af..e36c1dc467 100644 --- a/docs/tutorials/migrate-to-mui5.md +++ b/docs/tutorials/migrate-to-mui5.md @@ -21,7 +21,7 @@ It is worth noting that we are still using `@mui/styles` & `jss`. You may stumbl To comply with MUI recommendations, we are enforcing a new linting rules that favours standard imports over named imports and also restricting 3rd level imports as they are considered private ([Guide: Minimizing Bundle Size](https://mui.com/material-ui/guides/minimizing-bundle-size)). -For current knonw issues with the MUI v5 migration follow our [Milestone on GitHub](https://github.com/backstage/backstage/milestone/40). Please open a new issue if you run into different problems. +For current known issues with the MUI v5 migration, follow our [Milestone on GitHub](https://github.com/backstage/backstage/milestone/40). Please open a new issue if you run into different problems. ### Plugins From d1f3e73a8e10e522be6cf979c0732e5c22076572 Mon Sep 17 00:00:00 2001 From: Philipp Hugenroth Date: Thu, 28 Sep 2023 15:24:26 +0200 Subject: [PATCH 018/261] Context on react 17 Signed-off-by: Philipp Hugenroth --- docs/tutorials/migrate-to-mui5.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/tutorials/migrate-to-mui5.md b/docs/tutorials/migrate-to-mui5.md index e36c1dc467..6f1036e4c2 100644 --- a/docs/tutorials/migrate-to-mui5.md +++ b/docs/tutorials/migrate-to-mui5.md @@ -17,10 +17,12 @@ To support Material UI v5 in addition to v4, we have introduced a `UnifiedThemeP ), ``` -It is worth noting that we are still using `@mui/styles` & `jss`. You may stumble upon documentation for migrating to `emotion` when using `makeStyles` or `withStyles`. It is not necessary to switch to `emotion` yet. +It is worth noting that we are still using `@mui/styles` & `jss`. You may stumble upon documentation for migrating to `emotion` when using `makeStyles` or `withStyles`. It is not necessary to switch to `emotion`. To comply with MUI recommendations, we are enforcing a new linting rules that favours standard imports over named imports and also restricting 3rd level imports as they are considered private ([Guide: Minimizing Bundle Size](https://mui.com/material-ui/guides/minimizing-bundle-size)). +Important to keep in mind is, that Material UI v5 is meant to be used with React Version 17 or higher. This means if you intend to use the Material UI v5 components in your plugins you have to enforce React Version to be at least 17. + For current known issues with the MUI v5 migration, follow our [Milestone on GitHub](https://github.com/backstage/backstage/milestone/40). Please open a new issue if you run into different problems. ### Plugins @@ -31,5 +33,6 @@ To migrate your plugin to MUI v5, you can build on the resources available. 2. Run the migration `codemod` for the path of the specific plugin: `npx @mui/codemod v5.0.0/preset-safe plugins/`. 3. Take a look at possible `TODO:` items the `codemod` could not fix. 4. Remove types & methods from `@backstage/theme` which are marked as `@deprecated`. +5. Ensure you are using `"react": "^17.0.0"` (or newer) as a peer dependency You can follow the [migration of the GraphiQL plugin](https://github.com/backstage/backstage/pull/17696) as an example plugin migration. From a647d24d257745a199bd32a7d4e8152a7d515263 Mon Sep 17 00:00:00 2001 From: Philipp Hugenroth Date: Fri, 17 Nov 2023 14:47:41 +0100 Subject: [PATCH 019/261] let's get this in... Signed-off-by: Philipp Hugenroth --- docs/tutorials/migrate-to-mui5.md | 42 ++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/docs/tutorials/migrate-to-mui5.md b/docs/tutorials/migrate-to-mui5.md index 6f1036e4c2..cda662be7d 100644 --- a/docs/tutorials/migrate-to-mui5.md +++ b/docs/tutorials/migrate-to-mui5.md @@ -1,33 +1,45 @@ --- id: migrate-to-mui5 title: Migrating from Material UI v4 to v5 -description: Additionally resources to the Material UI migration guide specifically for Backstage +description: Additional resources for the Material UI v5 migration guide specifically for Backstage --- -Before diving into the specific changes in Backstage, it may be helpful to take a look at the [Migration Guide provided by MUI](https://mui.com/material-ui/migration/migration-v4/). It breaks down the differences between v4, v5 and will make it easier to understand the impact on your Backstage instance & plugins. +Backstage supports developing new plugins or components using Material UI v5. At the same time, large parts of the application as well as existing plugins will still be using Material UI v4. To support Material UI v4 and v5 at the same time, we have introduced a new concept called the `UnifiedTheme`. The goal of the `UnifiedTheme` is to allow gradual migration by running both versions in parallel, applying theme options similarly & supporting potential future versions of Material UI. -To support Material UI v5 in addition to v4, we have introduced a `UnifiedThemeProvider`. This allows a gradual migration by running both versions in parallel. To use it, you need to update your app's `ThemeProvider` in `app/src/App.tsx` as follows: +By default, the `UnifiedThemeProvider` is already used. If you add a custom theme in your `createApp` function, you would need to replace the Material UI `ThemeProvider` with the `UnifiedThemeProvider`: -```diff - provider: ({ children }) => ( -- . -- {children}. -- - ), +```diff ts +const app = createApp({ + // ... + themes: [ + { + // ... + provider: ({ children }) => ( +- . +- {children}. +- + ), + } + ] +}); ``` +Before making specific changes to your Backstage instance, it might be helpful to take a look at the [Migration Guide provided by Material UI](https://mui.com/material-ui/migration/migration-v4/) first. It breaks down the differences between v4 and v5, and will make it easier to understand the impact on your Backstage instance & plugins. + It is worth noting that we are still using `@mui/styles` & `jss`. You may stumble upon documentation for migrating to `emotion` when using `makeStyles` or `withStyles`. It is not necessary to switch to `emotion`. -To comply with MUI recommendations, we are enforcing a new linting rules that favours standard imports over named imports and also restricting 3rd level imports as they are considered private ([Guide: Minimizing Bundle Size](https://mui.com/material-ui/guides/minimizing-bundle-size)). +To comply with Material UI recommendations, we are enforcing a new linting rule that favors standard imports over named imports and also restricts 3rd-level imports as they are considered private ([Guide: Minimizing Bundle Size](https://mui.com/material-ui/guides/minimizing-bundle-size)). -Important to keep in mind is, that Material UI v5 is meant to be used with React Version 17 or higher. This means if you intend to use the Material UI v5 components in your plugins you have to enforce React Version to be at least 17. +Important to keep in mind is that Material UI v5 is meant to be used with React Version 17 or higher. This means if you intend to use the Material UI v5 components in your plugins, you have to enforce React Version to be at least 17 for these plugins as well. -For current known issues with the MUI v5 migration, follow our [Milestone on GitHub](https://github.com/backstage/backstage/milestone/40). Please open a new issue if you run into different problems. +There are `core-components` as well as components exported from `*-react` plugins written in Material UI v4, which expect Material UI components as props. In these cases you will still be forced to import Material UI v4 components. + +For current known issues with the Material UI v5 migration, follow our [Milestone on GitHub](https://github.com/backstage/backstage/milestone/40). Please open a new issue if you run into different problems. ### Plugins -To migrate your plugin to MUI v5, you can build on the resources available. +To migrate your plugin to Material UI v5, you can build on the resources available. 1. Manually fix the imports from named to default imports to match the new [linting rules for minimizing bundle size](https://mui.com/material-ui/guides/minimizing-bundle-size). 2. Run the migration `codemod` for the path of the specific plugin: `npx @mui/codemod v5.0.0/preset-safe plugins/`. @@ -35,4 +47,4 @@ To migrate your plugin to MUI v5, you can build on the resources available. 4. Remove types & methods from `@backstage/theme` which are marked as `@deprecated`. 5. Ensure you are using `"react": "^17.0.0"` (or newer) as a peer dependency -You can follow the [migration of the GraphiQL plugin](https://github.com/backstage/backstage/pull/17696) as an example plugin migration. +You can follow the [migration of the GraphiQL plugin](https://github.com/backstage/backstage/pull/17696) as an example of a plugin migration. From 64b2f1e9bf04bc83ec1caa0f4582e04407c3e284 Mon Sep 17 00:00:00 2001 From: Andre Wanlin Date: Fri, 17 Nov 2023 11:45:56 -0600 Subject: [PATCH 020/261] Removed deprecated for now Signed-off-by: Andre Wanlin --- .changeset/unlucky-clouds-build.md | 4 ++-- plugins/azure-devops-backend/config.d.ts | 11 ++--------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/.changeset/unlucky-clouds-build.md b/.changeset/unlucky-clouds-build.md index 6f7813a8e6..35aa277653 100644 --- a/.changeset/unlucky-clouds-build.md +++ b/.changeset/unlucky-clouds-build.md @@ -2,6 +2,6 @@ '@backstage/plugin-azure-devops-backend': minor --- -**BREAKING** New `fromConfig` static method must be used now when created an instance of the `AzureDevOpsApi` +**BREAKING** New `fromConfig` static method must be used now when creating an instance of the `AzureDevOpsApi` -Added support for using the `AzureDevOpsCredentialsProvider` and deprecated the entire `azureDevOps` configuration section +Added support for using the `AzureDevOpsCredentialsProvider` diff --git a/plugins/azure-devops-backend/config.d.ts b/plugins/azure-devops-backend/config.d.ts index c973a0595f..86fefeeef9 100644 --- a/plugins/azure-devops-backend/config.d.ts +++ b/plugins/azure-devops-backend/config.d.ts @@ -15,28 +15,21 @@ */ export interface Config { - /** Configuration options for the azure-devops-backend plugin - * @deprecated Use `integrations.azure` instead. - * @see https://backstage.io/docs/integrations/azure/locations + /** + * Configuration options for the azure-devops-backend plugin */ azureDevOps: { /** * The hostname of the given Azure instance - * @deprecated Use `integrations.azure` instead. - * @see https://backstage.io/docs/integrations/azure/locations */ host: string; /** * Token used to authenticate requests. * @visibility secret - * @deprecated Use `integrations.azure` instead. - * @see https://backstage.io/docs/integrations/azure/locations */ token: string; /** * The organization of the given Azure instance - * @deprecated Use `integrations.azure` instead. - * @see https://backstage.io/docs/integrations/azure/locations */ organization: string; }; From 38340678c3f457d9a9d2c6fd05da501c1e33fd2a Mon Sep 17 00:00:00 2001 From: Aramis Sennyey Date: Thu, 20 Apr 2023 11:22:19 -0400 Subject: [PATCH 021/261] feat(openapi): Create Backstage plugins through generator tooling. Signed-off-by: Aramis Sennyey Signed-off-by: Aramis Sennyey Signed-off-by: Aramis Sennyey --- .changeset/five-feet-call.md | 5 + .changeset/forty-clocks-hug.md | 5 + .changeset/proud-seahorses-explain.md | 5 + .changeset/silent-rats-reflect.md | 5 + docs/openapi/generate-client.md | 25 + packages/catalog-client/package.json | 3 +- .../catalog-client/src/CatalogClient.test.ts | 26 +- packages/catalog-client/src/CatalogClient.ts | 394 +++++------ .../src/generated/apis/DefaultApi.client.ts | 611 ++++++++++++++++++ .../src/generated/apis/index.ts | 17 + .../catalog-client/src/generated/index.ts | 17 + .../AnalyzeLocationEntityField.model.ts | 36 ++ .../AnalyzeLocationExistingEntity.model.ts | 27 + .../AnalyzeLocationGenerateEntity.model.ts | 26 + .../models/AnalyzeLocationRequest.model.ts | 22 + .../models/AnalyzeLocationResponse.model.ts | 23 + .../models/CreateLocation201Response.model.ts | 24 + .../models/CreateLocationRequest.model.ts | 20 + .../models/EntitiesBatchResponse.model.ts | 24 + .../models/EntitiesQueryResponse.model.ts | 27 + .../EntitiesQueryResponsePageInfo.model.ts | 26 + .../src/generated/models/Entity.model.ts | 41 ++ .../models/EntityAncestryResponse.model.ts | 22 + .../EntityAncestryResponseItemsInner.model.ts | 22 + .../src/generated/models/EntityFacet.model.ts | 20 + .../models/EntityFacetsResponse.model.ts | 21 + .../src/generated/models/EntityLink.model.ts | 37 ++ .../src/generated/models/EntityMeta.model.ts | 64 ++ .../generated/models/EntityRelation.model.ts | 29 + .../src/generated/models/ErrorError.model.ts | 22 + .../generated/models/ErrorRequest.model.ts | 20 + .../generated/models/ErrorResponse.model.ts | 19 + .../models/GetEntitiesByRefsRequest.model.ts | 20 + .../GetLocations200ResponseInner.model.ts | 21 + .../src/generated/models/Location.model.ts | 24 + .../generated/models/LocationInput.model.ts | 20 + .../generated/models/LocationSpec.model.ts | 23 + .../src/generated/models/ModelError.model.ts | 26 + .../generated/models/NullableEntity.model.ts | 41 ++ .../models/RecursivePartialEntity.model.ts | 41 ++ .../RecursivePartialEntityMeta.model.ts | 60 ++ .../RecursivePartialEntityMetaAllOf.model.ts | 63 ++ .../RecursivePartialEntityRelation.model.ts | 29 + .../models/RefreshEntityRequest.model.ts | 26 + .../models/ValidateEntity400Response.model.ts | 21 + ...idateEntity400ResponseErrorsInner.model.ts | 21 + .../models/ValidateEntityRequest.model.ts | 20 + .../catalog-client/src/generated/pluginId.ts | 17 + .../src/generated/types/discovery.ts | 22 + .../src/generated/types/fetch.ts | 22 + packages/cli/config/eslint-factory.js | 19 +- packages/cli/package.json | 1 + packages/errors/src/errors/ResponseError.ts | 25 +- packages/errors/src/serialization/response.ts | 14 +- packages/repo-tools/openapitools.json | 7 + packages/repo-tools/package.json | 1 + packages/repo-tools/src/commands/index.ts | 18 +- .../src/commands/openapi/client/generate.ts | 97 +++ .../src/commands/openapi/constants.ts | 41 ++ .../commands/openapi/{ => schema}/generate.ts | 6 +- .../commands/openapi/{ => schema}/verify.ts | 6 +- .../templates/typescript-backstage.yaml | 18 + .../typescript-backstage/api.mustache | 120 ++++ .../typescript-backstage/apis/index.mustache | 3 + .../typescript-backstage/index.mustache | 3 + .../typescript-backstage/model.mustache | 43 ++ .../models/models_all.mustache | 7 + .../typescript-backstage/pluginId.mustache | 6 + .../typescript-backstage/types/discovery.ts | 22 + .../typescript-backstage/types/fetch.ts | 22 + .../src/schema/openapi.generated.ts | 177 ++--- .../catalog-backend/src/schema/openapi.yaml | 202 +++--- .../src/service/createRouter.test.ts | 39 ++ yarn.lock | 49 +- 74 files changed, 2658 insertions(+), 490 deletions(-) create mode 100644 .changeset/five-feet-call.md create mode 100644 .changeset/forty-clocks-hug.md create mode 100644 .changeset/proud-seahorses-explain.md create mode 100644 .changeset/silent-rats-reflect.md create mode 100644 docs/openapi/generate-client.md create mode 100644 packages/catalog-client/src/generated/apis/DefaultApi.client.ts create mode 100644 packages/catalog-client/src/generated/apis/index.ts create mode 100644 packages/catalog-client/src/generated/index.ts create mode 100644 packages/catalog-client/src/generated/models/AnalyzeLocationEntityField.model.ts create mode 100644 packages/catalog-client/src/generated/models/AnalyzeLocationExistingEntity.model.ts create mode 100644 packages/catalog-client/src/generated/models/AnalyzeLocationGenerateEntity.model.ts create mode 100644 packages/catalog-client/src/generated/models/AnalyzeLocationRequest.model.ts create mode 100644 packages/catalog-client/src/generated/models/AnalyzeLocationResponse.model.ts create mode 100644 packages/catalog-client/src/generated/models/CreateLocation201Response.model.ts create mode 100644 packages/catalog-client/src/generated/models/CreateLocationRequest.model.ts create mode 100644 packages/catalog-client/src/generated/models/EntitiesBatchResponse.model.ts create mode 100644 packages/catalog-client/src/generated/models/EntitiesQueryResponse.model.ts create mode 100644 packages/catalog-client/src/generated/models/EntitiesQueryResponsePageInfo.model.ts create mode 100644 packages/catalog-client/src/generated/models/Entity.model.ts create mode 100644 packages/catalog-client/src/generated/models/EntityAncestryResponse.model.ts create mode 100644 packages/catalog-client/src/generated/models/EntityAncestryResponseItemsInner.model.ts create mode 100644 packages/catalog-client/src/generated/models/EntityFacet.model.ts create mode 100644 packages/catalog-client/src/generated/models/EntityFacetsResponse.model.ts create mode 100644 packages/catalog-client/src/generated/models/EntityLink.model.ts create mode 100644 packages/catalog-client/src/generated/models/EntityMeta.model.ts create mode 100644 packages/catalog-client/src/generated/models/EntityRelation.model.ts create mode 100644 packages/catalog-client/src/generated/models/ErrorError.model.ts create mode 100644 packages/catalog-client/src/generated/models/ErrorRequest.model.ts create mode 100644 packages/catalog-client/src/generated/models/ErrorResponse.model.ts create mode 100644 packages/catalog-client/src/generated/models/GetEntitiesByRefsRequest.model.ts create mode 100644 packages/catalog-client/src/generated/models/GetLocations200ResponseInner.model.ts create mode 100644 packages/catalog-client/src/generated/models/Location.model.ts create mode 100644 packages/catalog-client/src/generated/models/LocationInput.model.ts create mode 100644 packages/catalog-client/src/generated/models/LocationSpec.model.ts create mode 100644 packages/catalog-client/src/generated/models/ModelError.model.ts create mode 100644 packages/catalog-client/src/generated/models/NullableEntity.model.ts create mode 100644 packages/catalog-client/src/generated/models/RecursivePartialEntity.model.ts create mode 100644 packages/catalog-client/src/generated/models/RecursivePartialEntityMeta.model.ts create mode 100644 packages/catalog-client/src/generated/models/RecursivePartialEntityMetaAllOf.model.ts create mode 100644 packages/catalog-client/src/generated/models/RecursivePartialEntityRelation.model.ts create mode 100644 packages/catalog-client/src/generated/models/RefreshEntityRequest.model.ts create mode 100644 packages/catalog-client/src/generated/models/ValidateEntity400Response.model.ts create mode 100644 packages/catalog-client/src/generated/models/ValidateEntity400ResponseErrorsInner.model.ts create mode 100644 packages/catalog-client/src/generated/models/ValidateEntityRequest.model.ts create mode 100644 packages/catalog-client/src/generated/pluginId.ts create mode 100644 packages/catalog-client/src/generated/types/discovery.ts create mode 100644 packages/catalog-client/src/generated/types/fetch.ts create mode 100644 packages/repo-tools/openapitools.json create mode 100644 packages/repo-tools/src/commands/openapi/client/generate.ts rename packages/repo-tools/src/commands/openapi/{ => schema}/generate.ts (95%) rename packages/repo-tools/src/commands/openapi/{ => schema}/verify.ts (93%) create mode 100644 packages/repo-tools/templates/typescript-backstage.yaml create mode 100644 packages/repo-tools/templates/typescript-backstage/api.mustache create mode 100644 packages/repo-tools/templates/typescript-backstage/apis/index.mustache create mode 100644 packages/repo-tools/templates/typescript-backstage/index.mustache create mode 100644 packages/repo-tools/templates/typescript-backstage/model.mustache create mode 100644 packages/repo-tools/templates/typescript-backstage/models/models_all.mustache create mode 100644 packages/repo-tools/templates/typescript-backstage/pluginId.mustache create mode 100644 packages/repo-tools/templates/typescript-backstage/types/discovery.ts create mode 100644 packages/repo-tools/templates/typescript-backstage/types/fetch.ts diff --git a/.changeset/five-feet-call.md b/.changeset/five-feet-call.md new file mode 100644 index 0000000000..528c21a932 --- /dev/null +++ b/.changeset/five-feet-call.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': patch +--- + +Update the OpenAPI spec to support the use of `openapi-generator`. diff --git a/.changeset/forty-clocks-hug.md b/.changeset/forty-clocks-hug.md new file mode 100644 index 0000000000..ea0fd2480f --- /dev/null +++ b/.changeset/forty-clocks-hug.md @@ -0,0 +1,5 @@ +--- +'@backstage/catalog-client': minor +--- + +The internals of `CatalogClient` are now auto-generated using the `backstage-repo-tools schema openapi generate-client` command. diff --git a/.changeset/proud-seahorses-explain.md b/.changeset/proud-seahorses-explain.md new file mode 100644 index 0000000000..328e4bf838 --- /dev/null +++ b/.changeset/proud-seahorses-explain.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': minor +--- + +Updates the ESLint config to ignore issues created by generated files in `**/src/generated/**`. diff --git a/.changeset/silent-rats-reflect.md b/.changeset/silent-rats-reflect.md new file mode 100644 index 0000000000..b7884f06d0 --- /dev/null +++ b/.changeset/silent-rats-reflect.md @@ -0,0 +1,5 @@ +--- +'@backstage/repo-tools': minor +--- + +Adds a new command `schema openapi generate-client` that creates a Typescript client with Backstage flavor, including the discovery API and fetch API. This command doesn't currently generate a complete client and needs to be wrapped or exported manually by a separate Backstage plugin. See `@backstage/catalog-client/src/generated` for example output. diff --git a/docs/openapi/generate-client.md b/docs/openapi/generate-client.md new file mode 100644 index 0000000000..10e6ec3b2f --- /dev/null +++ b/docs/openapi/generate-client.md @@ -0,0 +1,25 @@ +## How to generate a client with `repo-tools schema openapi generate-client`? + +### Prerequisites + +1. Add your plugin ID as the last `servers` item, like this, + +```yaml +servers: + # first value, used for OpenAPI router validation. + - url: / + + # final value, pluginId. + - url: catalog +``` + +2. Find or create a new plugin to house your new generated client. Currently, we do not support generating an entirely new plugin and instead just generate client files. + +### Generating your client + +1. Run `yarn backstage-repo-tools schema openapi generate-client --input-spec --output-directory `. This will create a new folder in `/src/generated` to house the generated content. +2. You should use the generated files as follows, + +- `apis/DefaultApi.client.ts` - this is the client that you should use. It has types for all of the various operations on your API. +- `models/*` - These are the types generated from your OpenAPI file, ideally you should not need to use these directly and can instead use the inferred types from `apis/DefaultApi.client.ts`. +- everything else is directory specific and shouldn't be touched. diff --git a/packages/catalog-client/package.json b/packages/catalog-client/package.json index 02c30ee19b..4f545262c3 100644 --- a/packages/catalog-client/package.json +++ b/packages/catalog-client/package.json @@ -35,7 +35,8 @@ "dependencies": { "@backstage/catalog-model": "workspace:^", "@backstage/errors": "workspace:^", - "cross-fetch": "^4.0.0" + "cross-fetch": "^4.0.0", + "uri-template": "^2.0.0" }, "devDependencies": { "@backstage/cli": "workspace:^", diff --git a/packages/catalog-client/src/CatalogClient.test.ts b/packages/catalog-client/src/CatalogClient.test.ts index f5c221569d..4892017032 100644 --- a/packages/catalog-client/src/CatalogClient.test.ts +++ b/packages/catalog-client/src/CatalogClient.test.ts @@ -86,7 +86,7 @@ describe('CatalogClient', () => { server.use( rest.get(`${mockBaseUrl}/entities`, (req, res, ctx) => { - expect(req.url.search).toBe( + expect(decodeURIComponent(req.url.search)).toBe( '?filter=a=1,b=2,b=3,%C3%B6=%3D&filter=a=2&filter=c', ); return res(ctx.json([])); @@ -120,7 +120,9 @@ describe('CatalogClient', () => { server.use( rest.get(`${mockBaseUrl}/entities`, (req, res, ctx) => { - expect(req.url.search).toBe('?filter=a=1,b=2,b=3,%C3%B6=%3D,c'); + expect(decodeURIComponent(req.url.search)).toBe( + '?filter=a=1,b=2,b=3,%C3%B6=%3D,c', + ); return res(ctx.json([])); }), ); @@ -145,7 +147,7 @@ describe('CatalogClient', () => { server.use( rest.get(`${mockBaseUrl}/entities`, (req, res, ctx) => { - expect(req.url.search).toBe('?fields=a.b,%C3%B6'); + expect(decodeURIComponent(req.url.search)).toBe('?fields=a.b,%C3%B6'); return res(ctx.json([])); }), ); @@ -185,7 +187,7 @@ describe('CatalogClient', () => { server.use( rest.get(`${mockBaseUrl}/entities`, (req, res, ctx) => { - expect(req.url.search).toBe('?offset=1&limit=2&after=%3D'); + expect(req.url.search).toBe('?limit=2&offset=1&after=%3D'); return res(ctx.json([])); }), ); @@ -203,7 +205,7 @@ describe('CatalogClient', () => { server.use( rest.get(`${mockBaseUrl}/entities`, (req, res, ctx) => { - expect(req.url.search).toBe( + expect(decodeURIComponent(req.url.search)).toBe( '?order=asc:kind&order=desc:metadata.name', ); return res(ctx.json([])); @@ -326,9 +328,9 @@ describe('CatalogClient', () => { expect(response).toEqual({ items: [], totalItems: 0 }); expect(mockedEndpoint).toHaveBeenCalledTimes(1); - expect(mockedEndpoint.mock.calls[0][0].url.search).toBe( - '?filter=a=1,b=2,b=3,%C3%B6=%3D&filter=a=2&filter=c', - ); + expect( + decodeURIComponent(mockedEndpoint.mock.calls[0][0].url.search), + ).toBe('?filter=a=1,b=2,b=3,%C3%B6=%3D&filter=a=2&filter=c'); }); it('should send query params correctly on initial request', async () => { @@ -351,8 +353,10 @@ describe('CatalogClient', () => { { field: 'metadata.uid', order: 'desc' }, ], }); - expect(mockedEndpoint.mock.calls[0][0].url.search).toBe( - '?limit=100&orderField=metadata.name,asc&orderField=metadata.uid,desc&fields=a,b&fullTextFilterTerm=query', + expect( + decodeURIComponent(mockedEndpoint.mock.calls[0][0].url.search), + ).toBe( + '?fields=a,b&limit=100&orderField=metadata.name%2Casc&orderField=metadata.uid%2Cdesc&fullTextFilterTerm=query', ); }); @@ -375,7 +379,7 @@ describe('CatalogClient', () => { cursor: 'cursor', }); expect(mockedEndpoint.mock.calls[0][0].url.search).toBe( - '?cursor=cursor&limit=100&fields=a,b', + '?fields=a,b&limit=100&cursor=cursor', ); }); diff --git a/packages/catalog-client/src/CatalogClient.ts b/packages/catalog-client/src/CatalogClient.ts index c388519e05..dd22a44d59 100644 --- a/packages/catalog-client/src/CatalogClient.ts +++ b/packages/catalog-client/src/CatalogClient.ts @@ -22,7 +22,6 @@ import { stringifyLocationRef, } from '@backstage/catalog-model'; import { ResponseError } from '@backstage/errors'; -import crossFetch from 'cross-fetch'; import { CATALOG_FILTER_EXISTS, AddLocationRequest, @@ -43,9 +42,21 @@ import { QueryEntitiesResponse, EntityFilterQuery, } from './types/api'; -import { DiscoveryApi } from './types/discovery'; -import { FetchApi } from './types/fetch'; +import { DefaultApiClient } from './generated/apis/DefaultApi.client'; import { isQueryEntitiesInitialRequest } from './utils'; +import { ValidateEntity400Response } from './generated/models/ValidateEntity400Response.model'; + +const isResponseError = (e: Error): e is ResponseError => { + return (e as any).response; +}; + +const ignore404 = (responseError: Error) => { + if (!isResponseError(responseError)) throw responseError; + if (responseError.response.status === 404) { + return undefined; + } + throw responseError; +}; /** * A frontend and backend compatible client for communicating with the Backstage @@ -54,15 +65,13 @@ import { isQueryEntitiesInitialRequest } from './utils'; * @public */ export class CatalogClient implements CatalogApi { - private readonly discoveryApi: DiscoveryApi; - private readonly fetchApi: FetchApi; + private readonly apiClient: DefaultApiClient; constructor(options: { discoveryApi: { getBaseUrl(pluginId: string): Promise }; fetchApi?: { fetch: typeof fetch }; }) { - this.discoveryApi = options.discoveryApi; - this.fetchApi = options.fetchApi || { fetch: crossFetch }; + this.apiClient = new DefaultApiClient(options); } /** @@ -73,13 +82,9 @@ export class CatalogClient implements CatalogApi { options?: CatalogRequestOptions, ): Promise { const { kind, namespace, name } = parseEntityRef(request.entityRef); - return await this.requestRequired( - 'GET', - `/entities/by-name/${encodeURIComponent(kind)}/${encodeURIComponent( - namespace, - )}/${encodeURIComponent(name)}/ancestry`, - options, - ); + return await this.apiClient + .getEntityAncestryByName({ path: { kind, namespace, name } }, options) + .then(r => r.json()); } /** @@ -89,11 +94,13 @@ export class CatalogClient implements CatalogApi { id: string, options?: CatalogRequestOptions, ): Promise { - return await this.requestOptional( - 'GET', - `/locations/${encodeURIComponent(id)}`, - options, - ); + try { + return await this.apiClient + .getLocation({ path: { id } }, options) + .then(r => r.json()); + } catch (e) { + return ignore404(e); + } } /** @@ -111,17 +118,12 @@ export class CatalogClient implements CatalogApi { limit, after, } = request ?? {}; - const params = this.getParams(filter); - - if (fields.length) { - params.push(`fields=${fields.map(encodeURIComponent).join(',')}`); - } - + const encodedOrder = []; if (order) { for (const directive of [order].flat()) { if (directive) { - params.push( - `order=${encodeURIComponent(directive.order)}:${encodeURIComponent( + encodedOrder.push( + `${encodeURIComponent(directive.order)}:${encodeURIComponent( directive.field, )}`, ); @@ -129,22 +131,21 @@ export class CatalogClient implements CatalogApi { } } - if (offset !== undefined) { - params.push(`offset=${offset}`); - } - if (limit !== undefined) { - params.push(`limit=${limit}`); - } - if (after !== undefined) { - params.push(`after=${encodeURIComponent(after)}`); - } - - const query = params.length ? `?${params.join('&')}` : ''; - const entities: Entity[] = await this.requestRequired( - 'GET', - `/entities${query}`, - options, - ); + const entities: Entity[] = await this.apiClient + .getEntities( + { + query: { + fields: fields.map(encodeURIComponent), + limit, + filter: this.getFilterValue(filter), + offset, + after, + order: order ? encodedOrder : undefined, + }, + }, + options, + ) + .then(r => r.json()); const refCompare = (a: Entity, b: Entity) => { // in case field filtering is used, these fields might not be part of the response @@ -178,30 +179,9 @@ export class CatalogClient implements CatalogApi { request: GetEntitiesByRefsRequest, options?: CatalogRequestOptions, ): Promise { - const body: any = { entityRefs: request.entityRefs }; - if (request.fields?.length) { - body.fields = request.fields; - } - - const baseUrl = await this.discoveryApi.getBaseUrl('catalog'); - const url = `${baseUrl}/entities/by-refs`; - - const response = await this.fetchApi.fetch(url, { - headers: { - 'Content-Type': 'application/json', - ...(options?.token && { Authorization: `Bearer ${options?.token}` }), - }, - method: 'POST', - body: JSON.stringify(body), - }); - - if (!response.ok) { - throw await ResponseError.fromResponse(response); - } - - const { items } = (await response.json()) as { - items: Array; - }; + const { items } = await this.apiClient + .getEntitiesByRefs({ body: request }, options) + .then(r => r.json()); return { items: items.map(i => i ?? undefined) }; } @@ -212,8 +192,10 @@ export class CatalogClient implements CatalogApi { async queryEntities( request: QueryEntitiesRequest = {}, options?: CatalogRequestOptions, - ) { - const params: string[] = []; + ): Promise { + const params: Partial< + Parameters[0]['query'] + > = {}; if (isQueryEntitiesInitialRequest(request)) { const { @@ -223,45 +205,42 @@ export class CatalogClient implements CatalogApi { orderFields, fullTextFilter, } = request; - params.push(...this.getParams(filter)); + params.filter = this.getFilterValue(filter); if (limit !== undefined) { - params.push(`limit=${limit}`); + params.limit = limit; } if (orderFields !== undefined) { - (Array.isArray(orderFields) ? orderFields : [orderFields]).forEach( - ({ field, order }) => params.push(`orderField=${field},${order}`), - ); + params.orderField = ( + Array.isArray(orderFields) ? orderFields : [orderFields] + ).map(({ field, order }) => encodeURIComponent(`${field},${order}`)); } if (fields.length) { - params.push(`fields=${fields.map(encodeURIComponent).join(',')}`); + params.fields = fields.map(encodeURIComponent); } const normalizedFullTextFilterTerm = fullTextFilter?.term?.trim(); if (normalizedFullTextFilterTerm) { - params.push(`fullTextFilterTerm=${normalizedFullTextFilterTerm}`); + params.fullTextFilterTerm = normalizedFullTextFilterTerm; } if (fullTextFilter?.fields?.length) { - params.push(`fullTextFilterFields=${fullTextFilter.fields.join(',')}`); + params.fullTextFilterFields = fullTextFilter.fields; } } else { const { fields = [], limit, cursor } = request; - params.push(`cursor=${cursor}`); + params.cursor = cursor; if (limit !== undefined) { - params.push(`limit=${limit}`); + params.limit = limit; } if (fields.length) { - params.push(`fields=${fields.map(encodeURIComponent).join(',')}`); + params.fields = fields.map(encodeURIComponent); } } - const query = params.length ? `?${params.join('&')}` : ''; - return this.requestRequired( - 'GET', - `/entities/by-query${query}`, - options, - ); + return await this.apiClient + .getEntitiesByQuery({ query: params }, options) + .then(r => r.json()); } /** @@ -271,14 +250,13 @@ export class CatalogClient implements CatalogApi { entityRef: string | CompoundEntityRef, options?: CatalogRequestOptions, ): Promise { - const { kind, namespace, name } = parseEntityRef(entityRef); - return this.requestOptional( - 'GET', - `/entities/by-name/${encodeURIComponent(kind)}/${encodeURIComponent( - namespace, - )}/${encodeURIComponent(name)}`, - options, - ); + try { + return await this.apiClient + .getEntityByName({ path: { ...parseEntityRef(entityRef) } }, options) + .then(r => r.json()); + } catch (e) { + return ignore404(e); + } } // NOTE(freben): When we deprecate getEntityByName from the interface, we may @@ -293,34 +271,36 @@ export class CatalogClient implements CatalogApi { options?: CatalogRequestOptions, ): Promise { const { kind, namespace = 'default', name } = compoundName; - return this.requestOptional( - 'GET', - `/entities/by-name/${encodeURIComponent(kind)}/${encodeURIComponent( - namespace, - )}/${encodeURIComponent(name)}`, - options, - ); + try { + return await this.apiClient + .getEntityByName( + { + path: { + kind, + namespace, + name, + }, + }, + options, + ) + .then(r => r.json()); + } catch (e) { + return ignore404(e); + } } /** * {@inheritdoc CatalogApi.refreshEntity} */ async refreshEntity(entityRef: string, options?: CatalogRequestOptions) { - const response = await this.fetchApi.fetch( - `${await this.discoveryApi.getBaseUrl('catalog')}/refresh`, + await this.apiClient.refreshEntity( { - headers: { - 'Content-Type': 'application/json', - ...(options?.token && { Authorization: `Bearer ${options?.token}` }), + body: { + entityRef, }, - method: 'POST', - body: JSON.stringify({ entityRef }), }, + options, ); - - if (response.status !== 200) { - throw new Error(await response.text()); - } } /** @@ -331,14 +311,22 @@ export class CatalogClient implements CatalogApi { options?: CatalogRequestOptions, ): Promise { const { filter = [], facets } = request; - const params = this.getParams(filter); - for (const facet of facets) { - params.push(`facet=${encodeURIComponent(facet)}`); + try { + return await this.apiClient + .getEntityFacets( + { + query: { + facet: facets, + filter: this.getFilterValue(filter), + }, + }, + options, + ) + .then(r => r.json()); + } catch (e) { + return ignore404(e) as any; } - - const query = params.length ? `?${params.join('&')}` : ''; - return await this.requestOptional('GET', `/entity-facets${query}`, options); } /** @@ -350,25 +338,18 @@ export class CatalogClient implements CatalogApi { ): Promise { const { type = 'url', target, dryRun } = request; - const response = await this.fetchApi.fetch( - `${await this.discoveryApi.getBaseUrl('catalog')}/locations${ - dryRun ? '?dryRun=true' : '' - }`, - { - headers: { - 'Content-Type': 'application/json', - ...(options?.token && { Authorization: `Bearer ${options?.token}` }), + const { location, entities, exists } = await this.apiClient + .createLocation( + { + body: { + type, + target, + }, + query: { dryRun: dryRun ? 'true' : undefined }, }, - method: 'POST', - body: JSON.stringify({ type, target }), - }, - ); - - if (response.status !== 201) { - throw new Error(await response.text()); - } - - const { location, entities, exists } = await response.json(); + options, + ) + .then(r => r.json()); if (!location) { throw new Error(`Location wasn't added: ${target}`); @@ -388,11 +369,9 @@ export class CatalogClient implements CatalogApi { locationRef: string, options?: CatalogRequestOptions, ): Promise { - const all: { data: Location }[] = await this.requestRequired( - 'GET', - '/locations', - options, - ); + const all: { data: Location }[] = await this.apiClient + .getLocations({}, options) + .then(r => r.json()); return all .map(r => r.data) .find(l => locationRef === stringifyLocationRef(l)); @@ -405,11 +384,11 @@ export class CatalogClient implements CatalogApi { id: string, options?: CatalogRequestOptions, ): Promise { - await this.requestIgnored( - 'DELETE', - `/locations/${encodeURIComponent(id)}`, - options, - ); + try { + await this.apiClient.deleteLocation({ path: { id } }, options); + } catch (e) { + ignore404(e); + } } /** @@ -419,11 +398,11 @@ export class CatalogClient implements CatalogApi { uid: string, options?: CatalogRequestOptions, ): Promise { - await this.requestIgnored( - 'DELETE', - `/entities/by-uid/${encodeURIComponent(uid)}`, - options, - ); + try { + await this.apiClient.deleteEntityByUid({ path: { uid } }, options); + } catch (e) { + ignore404(e); + } } /** @@ -434,101 +413,38 @@ export class CatalogClient implements CatalogApi { locationRef: string, options?: CatalogRequestOptions, ): Promise { - const response = await this.fetchApi.fetch( - `${await this.discoveryApi.getBaseUrl('catalog')}/validate-entity`, - { - headers: { - 'Content-Type': 'application/json', - ...(options?.token && { Authorization: `Bearer ${options?.token}` }), + try { + await this.apiClient.validateEntity( + { + body: { + entity, + location: locationRef, + }, }, - method: 'POST', - body: JSON.stringify({ entity, location: locationRef }), - }, - ); + options, + ); - if (response.ok) { return { valid: true, }; - } - - if (response.status !== 400) { - throw await ResponseError.fromResponse(response); - } - - const { errors = [] } = await response.json(); - - return { - valid: false, - errors, - }; - } - - // - // Private methods - // - - private async requestIgnored( - method: string, - path: string, - options?: CatalogRequestOptions, - ): Promise { - const url = `${await this.discoveryApi.getBaseUrl('catalog')}${path}`; - const headers: Record = options?.token - ? { Authorization: `Bearer ${options.token}` } - : {}; - const response = await this.fetchApi.fetch(url, { method, headers }); - - if (!response.ok) { - throw await ResponseError.fromResponse(response); - } - } - - private async requestRequired( - method: string, - path: string, - options?: CatalogRequestOptions, - ): Promise { - const url = `${await this.discoveryApi.getBaseUrl('catalog')}${path}`; - const headers: Record = options?.token - ? { Authorization: `Bearer ${options.token}` } - : {}; - const response = await this.fetchApi.fetch(url, { method, headers }); - - if (!response.ok) { - throw await ResponseError.fromResponse(response); - } - - return response.json(); - } - - private async requestOptional( - method: string, - path: string, - options?: CatalogRequestOptions, - ): Promise { - const url = `${await this.discoveryApi.getBaseUrl('catalog')}${path}`; - const headers: Record = options?.token - ? { Authorization: `Bearer ${options.token}` } - : {}; - const response = await this.fetchApi.fetch(url, { method, headers }); - - if (!response.ok) { - if (response.status === 404) { - return undefined; + } catch (e) { + if (!isResponseError(e)) throw e; + const { response, rawBody } = e; + if (response.status !== 400) { + throw e; } - throw await ResponseError.fromResponse(response); - } + // TODO: This needs to be fixed as is, this won't actually do anything. + const { errors = [] } = JSON.parse(rawBody) as ValidateEntity400Response; - return await response.json(); + return { + valid: false, + errors, + }; + } } - private getParams(filter: EntityFilterQuery = []) { - const params: string[] = []; - // filter param can occur multiple times, for example - // /api/catalog/entities?filter=metadata.name=wayback-search,kind=component&filter=metadata.name=www-artist,kind=component' - // the "outer array" defined by `filter` occurrences corresponds to "anyOf" filters - // the "inner array" defined within a `filter` param corresponds to "allOf" filters + private getFilterValue(filter: EntityFilterQuery = []) { + const values: string[] = []; for (const filterItem of [filter].flat()) { const filterParts: string[] = []; for (const [key, value] of Object.entries(filterItem)) { @@ -544,9 +460,9 @@ export class CatalogClient implements CatalogApi { } if (filterParts.length) { - params.push(`filter=${filterParts.join(',')}`); + values.push(filterParts.join(',')); } } - return params; + return values; } } diff --git a/packages/catalog-client/src/generated/apis/DefaultApi.client.ts b/packages/catalog-client/src/generated/apis/DefaultApi.client.ts new file mode 100644 index 0000000000..11a0b33bc8 --- /dev/null +++ b/packages/catalog-client/src/generated/apis/DefaultApi.client.ts @@ -0,0 +1,611 @@ +/* + * 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 { DiscoveryApi } from '../types/discovery'; +import { FetchApi } from '../types/fetch'; +import crossFetch from 'cross-fetch'; +import { pluginId } from '../pluginId'; +import * as parser from 'uri-template'; +import { ResponseError } from '@backstage/errors'; + +import { AnalyzeLocationRequest } from '../models/AnalyzeLocationRequest.model'; +import { AnalyzeLocationResponse } from '../models/AnalyzeLocationResponse.model'; +import { CreateLocation201Response } from '../models/CreateLocation201Response.model'; +import { CreateLocationRequest } from '../models/CreateLocationRequest.model'; +import { EntitiesBatchResponse } from '../models/EntitiesBatchResponse.model'; +import { EntitiesQueryResponse } from '../models/EntitiesQueryResponse.model'; +import { Entity } from '../models/Entity.model'; +import { EntityAncestryResponse } from '../models/EntityAncestryResponse.model'; +import { EntityFacetsResponse } from '../models/EntityFacetsResponse.model'; +import { GetEntitiesByRefsRequest } from '../models/GetEntitiesByRefsRequest.model'; +import { GetLocations200ResponseInner } from '../models/GetLocations200ResponseInner.model'; +import { Location } from '../models/Location.model'; +import { RefreshEntityRequest } from '../models/RefreshEntityRequest.model'; +import { ValidateEntityRequest } from '../models/ValidateEntityRequest.model'; + +type TypedResponse = Omit & { + json: () => Promise; +}; + +/** + * Options you can pass into a request for additional information. + * + * @public + */ +export interface RequestOptions { + token?: string; +} + +/** + * no description + */ +export class DefaultApiClient { + private readonly discoveryApi: DiscoveryApi; + private readonly fetchApi: FetchApi; + + constructor(options: { + discoveryApi: { getBaseUrl(pluginId: string): Promise }; + fetchApi?: { fetch: typeof fetch }; + }) { + this.discoveryApi = options.discoveryApi; + this.fetchApi = options.fetchApi || { fetch: crossFetch }; + } + + /** + * Validate a given location. + * @param analyzeLocationRequest + */ + public async analyzeLocation( + // @ts-ignore + request: { + body: AnalyzeLocationRequest; + }, + options?: RequestOptions, + ): Promise> { + const baseUrl = await this.discoveryApi.getBaseUrl(pluginId); + + const uriTemplate = `/analyze-location`; + + const uri = parser.parse(uriTemplate).expand({}); + + const url = `${baseUrl}${uri}`; + const response = await this.fetchApi.fetch(url, { + headers: { + 'Content-Type': 'application/json', + ...(options?.token && { Authorization: `Bearer ${options?.token}` }), + }, + method: 'POST', + body: JSON.stringify(request.body), + }); + if (response.ok) { + return response; + } + throw await ResponseError.fromResponse(response); + } + + /** + * Create a location for a given target. + * @param createLocationRequest + * @param dryRun + */ + public async createLocation( + // @ts-ignore + request: { + body: CreateLocationRequest; + query: { + dryRun?: string; + }; + }, + options?: RequestOptions, + ): Promise> { + const baseUrl = await this.discoveryApi.getBaseUrl(pluginId); + + const uriTemplate = `/locations{?dryRun}`; + + const uri = parser.parse(uriTemplate).expand({ + ...request.query, + }); + + const url = `${baseUrl}${uri}`; + const response = await this.fetchApi.fetch(url, { + headers: { + 'Content-Type': 'application/json', + ...(options?.token && { Authorization: `Bearer ${options?.token}` }), + }, + method: 'POST', + body: JSON.stringify(request.body), + }); + if (response.ok) { + return response; + } + throw await ResponseError.fromResponse(response); + } + + /** + * Delete a single entity by UID. + * @param uid + */ + public async deleteEntityByUid( + // @ts-ignore + request: { + path: { + uid: string; + }; + }, + options?: RequestOptions, + ): Promise> { + const baseUrl = await this.discoveryApi.getBaseUrl(pluginId); + + const uriTemplate = `/entities/by-uid/{uid}`; + + const uri = parser.parse(uriTemplate).expand({ + uid: request.path.uid, + }); + + const url = `${baseUrl}${uri}`; + const response = await this.fetchApi.fetch(url, { + headers: { + 'Content-Type': 'application/json', + ...(options?.token && { Authorization: `Bearer ${options?.token}` }), + }, + method: 'DELETE', + }); + if (response.ok) { + return response; + } + throw await ResponseError.fromResponse(response); + } + + /** + * Delete a location by id. + * @param id + */ + public async deleteLocation( + // @ts-ignore + request: { + path: { + id: string; + }; + }, + options?: RequestOptions, + ): Promise> { + const baseUrl = await this.discoveryApi.getBaseUrl(pluginId); + + const uriTemplate = `/locations/{id}`; + + const uri = parser.parse(uriTemplate).expand({ + id: request.path.id, + }); + + const url = `${baseUrl}${uri}`; + const response = await this.fetchApi.fetch(url, { + headers: { + 'Content-Type': 'application/json', + ...(options?.token && { Authorization: `Bearer ${options?.token}` }), + }, + method: 'DELETE', + }); + if (response.ok) { + return response; + } + throw await ResponseError.fromResponse(response); + } + + /** + * Get all entities matching a given filter. + * @param fields Restrict to just these fields in the response. + * @param limit Number of records to return in the response. + * @param filter Filter for just the entities defined by this filter. + * @param offset Number of records to skip in the query page. + * @param after Pointer to the previous page of results. + * @param order + */ + public async getEntities( + // @ts-ignore + request: { + query: { + fields?: Array; + limit?: number; + filter?: Array; + offset?: number; + after?: string; + order?: Array; + }; + }, + options?: RequestOptions, + ): Promise>> { + const baseUrl = await this.discoveryApi.getBaseUrl(pluginId); + + const uriTemplate = `/entities{?fields,limit,filter*,offset,after,order*}`; + + const uri = parser.parse(uriTemplate).expand({ + ...request.query, + }); + + const url = `${baseUrl}${uri}`; + const response = await this.fetchApi.fetch(url, { + headers: { + 'Content-Type': 'application/json', + ...(options?.token && { Authorization: `Bearer ${options?.token}` }), + }, + method: 'GET', + }); + if (response.ok) { + return response; + } + throw await ResponseError.fromResponse(response); + } + + /** + * Search for entities by a given query. + * @param fields Restrict to just these fields in the response. + * @param limit Number of records to return in the response. + * @param orderField The fields to sort returned results by. + * @param cursor Cursor to a set page of results. + * @param filter Filter for just the entities defined by this filter. + * @param fullTextFilterTerm Text search term. + * @param fullTextFilterFields A comma separated list of fields to sort returned results by. + */ + public async getEntitiesByQuery( + // @ts-ignore + request: { + query: { + fields?: Array; + limit?: number; + orderField?: Array; + cursor?: string; + filter?: Array; + fullTextFilterTerm?: string; + fullTextFilterFields?: Array; + }; + }, + options?: RequestOptions, + ): Promise> { + const baseUrl = await this.discoveryApi.getBaseUrl(pluginId); + + const uriTemplate = `/entities/by-query{?fields,limit,orderField*,cursor,filter*,fullTextFilterTerm,fullTextFilterFields}`; + + const uri = parser.parse(uriTemplate).expand({ + ...request.query, + }); + + const url = `${baseUrl}${uri}`; + const response = await this.fetchApi.fetch(url, { + headers: { + 'Content-Type': 'application/json', + ...(options?.token && { Authorization: `Bearer ${options?.token}` }), + }, + method: 'GET', + }); + if (response.ok) { + return response; + } + throw await ResponseError.fromResponse(response); + } + + /** + * Get a batch set of entities given an array of entityRefs. + * @param getEntitiesByRefsRequest + */ + public async getEntitiesByRefs( + // @ts-ignore + request: { + body: GetEntitiesByRefsRequest; + }, + options?: RequestOptions, + ): Promise> { + const baseUrl = await this.discoveryApi.getBaseUrl(pluginId); + + const uriTemplate = `/entities/by-refs`; + + const uri = parser.parse(uriTemplate).expand({}); + + const url = `${baseUrl}${uri}`; + const response = await this.fetchApi.fetch(url, { + headers: { + 'Content-Type': 'application/json', + ...(options?.token && { Authorization: `Bearer ${options?.token}` }), + }, + method: 'POST', + body: JSON.stringify(request.body), + }); + if (response.ok) { + return response; + } + throw await ResponseError.fromResponse(response); + } + + /** + * Get an entity's ancestry by entity ref. + * @param kind + * @param namespace + * @param name + */ + public async getEntityAncestryByName( + // @ts-ignore + request: { + path: { + kind: string; + namespace: string; + name: string; + }; + }, + options?: RequestOptions, + ): Promise> { + const baseUrl = await this.discoveryApi.getBaseUrl(pluginId); + + const uriTemplate = `/entities/by-name/{kind}/{namespace}/{name}/ancestry`; + + const uri = parser.parse(uriTemplate).expand({ + kind: request.path.kind, + namespace: request.path.namespace, + name: request.path.name, + }); + + const url = `${baseUrl}${uri}`; + const response = await this.fetchApi.fetch(url, { + headers: { + 'Content-Type': 'application/json', + ...(options?.token && { Authorization: `Bearer ${options?.token}` }), + }, + method: 'GET', + }); + if (response.ok) { + return response; + } + throw await ResponseError.fromResponse(response); + } + + /** + * Get an entity by an entity ref. + * @param kind + * @param namespace + * @param name + */ + public async getEntityByName( + // @ts-ignore + request: { + path: { + kind: string; + namespace: string; + name: string; + }; + }, + options?: RequestOptions, + ): Promise> { + const baseUrl = await this.discoveryApi.getBaseUrl(pluginId); + + const uriTemplate = `/entities/by-name/{kind}/{namespace}/{name}`; + + const uri = parser.parse(uriTemplate).expand({ + kind: request.path.kind, + namespace: request.path.namespace, + name: request.path.name, + }); + + const url = `${baseUrl}${uri}`; + const response = await this.fetchApi.fetch(url, { + headers: { + 'Content-Type': 'application/json', + ...(options?.token && { Authorization: `Bearer ${options?.token}` }), + }, + method: 'GET', + }); + if (response.ok) { + return response; + } + throw await ResponseError.fromResponse(response); + } + + /** + * Get a single entity by the UID. + * @param uid + */ + public async getEntityByUid( + // @ts-ignore + request: { + path: { + uid: string; + }; + }, + options?: RequestOptions, + ): Promise> { + const baseUrl = await this.discoveryApi.getBaseUrl(pluginId); + + const uriTemplate = `/entities/by-uid/{uid}`; + + const uri = parser.parse(uriTemplate).expand({ + uid: request.path.uid, + }); + + const url = `${baseUrl}${uri}`; + const response = await this.fetchApi.fetch(url, { + headers: { + 'Content-Type': 'application/json', + ...(options?.token && { Authorization: `Bearer ${options?.token}` }), + }, + method: 'GET', + }); + if (response.ok) { + return response; + } + throw await ResponseError.fromResponse(response); + } + + /** + * Get all entity facets that match the given filters. + * @param facet + * @param filter Filter for just the entities defined by this filter. + */ + public async getEntityFacets( + // @ts-ignore + request: { + query: { + facet: Array; + filter?: Array; + }; + }, + options?: RequestOptions, + ): Promise> { + const baseUrl = await this.discoveryApi.getBaseUrl(pluginId); + + const uriTemplate = `/entity-facets{?facet*,filter*}`; + + const uri = parser.parse(uriTemplate).expand({ + ...request.query, + }); + + const url = `${baseUrl}${uri}`; + const response = await this.fetchApi.fetch(url, { + headers: { + 'Content-Type': 'application/json', + ...(options?.token && { Authorization: `Bearer ${options?.token}` }), + }, + method: 'GET', + }); + if (response.ok) { + return response; + } + throw await ResponseError.fromResponse(response); + } + + /** + * Get a location by id. + * @param id + */ + public async getLocation( + // @ts-ignore + request: { + path: { + id: string; + }; + }, + options?: RequestOptions, + ): Promise> { + const baseUrl = await this.discoveryApi.getBaseUrl(pluginId); + + const uriTemplate = `/locations/{id}`; + + const uri = parser.parse(uriTemplate).expand({ + id: request.path.id, + }); + + const url = `${baseUrl}${uri}`; + const response = await this.fetchApi.fetch(url, { + headers: { + 'Content-Type': 'application/json', + ...(options?.token && { Authorization: `Bearer ${options?.token}` }), + }, + method: 'GET', + }); + if (response.ok) { + return response; + } + throw await ResponseError.fromResponse(response); + } + + /** + * Get all locations + */ + public async getLocations( + // @ts-ignore + request: {}, + options?: RequestOptions, + ): Promise>> { + const baseUrl = await this.discoveryApi.getBaseUrl(pluginId); + + const uriTemplate = `/locations`; + + const uri = parser.parse(uriTemplate).expand({}); + + const url = `${baseUrl}${uri}`; + const response = await this.fetchApi.fetch(url, { + headers: { + 'Content-Type': 'application/json', + ...(options?.token && { Authorization: `Bearer ${options?.token}` }), + }, + method: 'GET', + }); + if (response.ok) { + return response; + } + throw await ResponseError.fromResponse(response); + } + + /** + * Refresh the entity related to entityRef. + * @param refreshEntityRequest + */ + public async refreshEntity( + // @ts-ignore + request: { + body: RefreshEntityRequest; + }, + options?: RequestOptions, + ): Promise> { + const baseUrl = await this.discoveryApi.getBaseUrl(pluginId); + + const uriTemplate = `/refresh`; + + const uri = parser.parse(uriTemplate).expand({}); + + const url = `${baseUrl}${uri}`; + const response = await this.fetchApi.fetch(url, { + headers: { + 'Content-Type': 'application/json', + ...(options?.token && { Authorization: `Bearer ${options?.token}` }), + }, + method: 'POST', + body: JSON.stringify(request.body), + }); + if (response.ok) { + return response; + } + throw await ResponseError.fromResponse(response); + } + + /** + * Validate that a passed in entity has no errors in schema. + * @param validateEntityRequest + */ + public async validateEntity( + // @ts-ignore + request: { + body: ValidateEntityRequest; + }, + options?: RequestOptions, + ): Promise> { + const baseUrl = await this.discoveryApi.getBaseUrl(pluginId); + + const uriTemplate = `/validate-entity`; + + const uri = parser.parse(uriTemplate).expand({}); + + const url = `${baseUrl}${uri}`; + const response = await this.fetchApi.fetch(url, { + headers: { + 'Content-Type': 'application/json', + ...(options?.token && { Authorization: `Bearer ${options?.token}` }), + }, + method: 'POST', + body: JSON.stringify(request.body), + }); + if (response.ok) { + return response; + } + throw await ResponseError.fromResponse(response); + } +} diff --git a/packages/catalog-client/src/generated/apis/index.ts b/packages/catalog-client/src/generated/apis/index.ts new file mode 100644 index 0000000000..ad2f72c5b2 --- /dev/null +++ b/packages/catalog-client/src/generated/apis/index.ts @@ -0,0 +1,17 @@ +/* + * 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 * from './DefaultApi.client'; diff --git a/packages/catalog-client/src/generated/index.ts b/packages/catalog-client/src/generated/index.ts new file mode 100644 index 0000000000..7df0cfd292 --- /dev/null +++ b/packages/catalog-client/src/generated/index.ts @@ -0,0 +1,17 @@ +/* + * 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 * from './apis'; diff --git a/packages/catalog-client/src/generated/models/AnalyzeLocationEntityField.model.ts b/packages/catalog-client/src/generated/models/AnalyzeLocationEntityField.model.ts new file mode 100644 index 0000000000..a1c1e1f669 --- /dev/null +++ b/packages/catalog-client/src/generated/models/AnalyzeLocationEntityField.model.ts @@ -0,0 +1,36 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface AnalyzeLocationEntityField { + /** + * A text to show to the user to inform about the choices made. Like, it could say \"Found a CODEOWNERS file that covers this target, so we suggest leaving this field empty; which would currently make it owned by X\" where X is taken from the codeowners file. + */ + description: string; + value: string | null; + /** + * The outcome of the analysis for this particular field + */ + state: AnalyzeLocationEntityFieldStateEnum; + /** + * e.g. \"spec.owner\"? The frontend needs to know how to \"inject\" the field into the entity again if the user wants to change it + */ + field: string; +} + +export type AnalyzeLocationEntityFieldStateEnum = + | 'analysisSuggestedValue' + | 'analysisSuggestedNoValue' + | 'needsUserInput'; diff --git a/packages/catalog-client/src/generated/models/AnalyzeLocationExistingEntity.model.ts b/packages/catalog-client/src/generated/models/AnalyzeLocationExistingEntity.model.ts new file mode 100644 index 0000000000..5ede0fb60b --- /dev/null +++ b/packages/catalog-client/src/generated/models/AnalyzeLocationExistingEntity.model.ts @@ -0,0 +1,27 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Entity } from '../models/Entity.model'; +import { LocationSpec } from '../models/LocationSpec.model'; + +/** + * If the folder pointed to already contained catalog info yaml files, they are read and emitted like this so that the frontend can inform the user that it located them and can make sure to register them as well if they weren't already + */ +export interface AnalyzeLocationExistingEntity { + entity: Entity; + isRegistered: boolean; + location: LocationSpec; +} diff --git a/packages/catalog-client/src/generated/models/AnalyzeLocationGenerateEntity.model.ts b/packages/catalog-client/src/generated/models/AnalyzeLocationGenerateEntity.model.ts new file mode 100644 index 0000000000..886aac05d9 --- /dev/null +++ b/packages/catalog-client/src/generated/models/AnalyzeLocationGenerateEntity.model.ts @@ -0,0 +1,26 @@ +/* + * 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 { AnalyzeLocationEntityField } from '../models/AnalyzeLocationEntityField.model'; +import { RecursivePartialEntity } from '../models/RecursivePartialEntity.model'; + +/** + * This is some form of representation of what the analyzer could deduce. We should probably have a chat about how this can best be conveyed to the frontend. It'll probably contain a (possibly incomplete) entity, plus enough info for the frontend to know what form data to show to the user for overriding/completing the info. + */ +export interface AnalyzeLocationGenerateEntity { + fields: Array; + entity: RecursivePartialEntity; +} diff --git a/packages/catalog-client/src/generated/models/AnalyzeLocationRequest.model.ts b/packages/catalog-client/src/generated/models/AnalyzeLocationRequest.model.ts new file mode 100644 index 0000000000..e8e9542f5a --- /dev/null +++ b/packages/catalog-client/src/generated/models/AnalyzeLocationRequest.model.ts @@ -0,0 +1,22 @@ +/* + * 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 { LocationInput } from '../models/LocationInput.model'; + +export interface AnalyzeLocationRequest { + catalogFileName?: string; + location: LocationInput; +} diff --git a/packages/catalog-client/src/generated/models/AnalyzeLocationResponse.model.ts b/packages/catalog-client/src/generated/models/AnalyzeLocationResponse.model.ts new file mode 100644 index 0000000000..bf60aa8018 --- /dev/null +++ b/packages/catalog-client/src/generated/models/AnalyzeLocationResponse.model.ts @@ -0,0 +1,23 @@ +/* + * 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 { AnalyzeLocationExistingEntity } from '../models/AnalyzeLocationExistingEntity.model'; +import { AnalyzeLocationGenerateEntity } from '../models/AnalyzeLocationGenerateEntity.model'; + +export interface AnalyzeLocationResponse { + generateEntities: Array; + existingEntityFiles: Array; +} diff --git a/packages/catalog-client/src/generated/models/CreateLocation201Response.model.ts b/packages/catalog-client/src/generated/models/CreateLocation201Response.model.ts new file mode 100644 index 0000000000..d090d80bf2 --- /dev/null +++ b/packages/catalog-client/src/generated/models/CreateLocation201Response.model.ts @@ -0,0 +1,24 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Entity } from '../models/Entity.model'; +import { Location } from '../models/Location.model'; + +export interface CreateLocation201Response { + exists?: boolean; + entities: Array; + location: Location; +} diff --git a/packages/catalog-client/src/generated/models/CreateLocationRequest.model.ts b/packages/catalog-client/src/generated/models/CreateLocationRequest.model.ts new file mode 100644 index 0000000000..6ef950072e --- /dev/null +++ b/packages/catalog-client/src/generated/models/CreateLocationRequest.model.ts @@ -0,0 +1,20 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface CreateLocationRequest { + target: string; + type: string; +} diff --git a/packages/catalog-client/src/generated/models/EntitiesBatchResponse.model.ts b/packages/catalog-client/src/generated/models/EntitiesBatchResponse.model.ts new file mode 100644 index 0000000000..d09b2cc086 --- /dev/null +++ b/packages/catalog-client/src/generated/models/EntitiesBatchResponse.model.ts @@ -0,0 +1,24 @@ +/* + * 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 { NullableEntity } from '../models/NullableEntity.model'; + +export interface EntitiesBatchResponse { + /** + * The list of entities, in the same order as the refs in the request. Entries that are null signify that no entity existed with that ref. + */ + items: Array; +} diff --git a/packages/catalog-client/src/generated/models/EntitiesQueryResponse.model.ts b/packages/catalog-client/src/generated/models/EntitiesQueryResponse.model.ts new file mode 100644 index 0000000000..10d4747caf --- /dev/null +++ b/packages/catalog-client/src/generated/models/EntitiesQueryResponse.model.ts @@ -0,0 +1,27 @@ +/* + * 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 { EntitiesQueryResponsePageInfo } from '../models/EntitiesQueryResponsePageInfo.model'; +import { Entity } from '../models/Entity.model'; + +export interface EntitiesQueryResponse { + /** + * The list of entities paginated by a specific filter. + */ + items: Array; + totalItems: number; + pageInfo: EntitiesQueryResponsePageInfo; +} diff --git a/packages/catalog-client/src/generated/models/EntitiesQueryResponsePageInfo.model.ts b/packages/catalog-client/src/generated/models/EntitiesQueryResponsePageInfo.model.ts new file mode 100644 index 0000000000..8a7d5b39bb --- /dev/null +++ b/packages/catalog-client/src/generated/models/EntitiesQueryResponsePageInfo.model.ts @@ -0,0 +1,26 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface EntitiesQueryResponsePageInfo { + /** + * The cursor for the next batch of entities. + */ + nextCursor?: string; + /** + * The cursor for the previous batch of entities. + */ + prevCursor?: string; +} diff --git a/packages/catalog-client/src/generated/models/Entity.model.ts b/packages/catalog-client/src/generated/models/Entity.model.ts new file mode 100644 index 0000000000..59ef9bc741 --- /dev/null +++ b/packages/catalog-client/src/generated/models/Entity.model.ts @@ -0,0 +1,41 @@ +/* + * 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 { EntityMeta } from '../models/EntityMeta.model'; +import { EntityRelation } from '../models/EntityRelation.model'; + +/** + * The parts of the format that's common to all versions/kinds of entity. + */ +export interface Entity { + /** + * The relations that this entity has with other entities. + */ + relations?: Array; + /** + * A type representing all allowed JSON object values. + */ + spec?: { [key: string]: any }; + metadata: EntityMeta; + /** + * The high level entity type being described. + */ + kind: string; + /** + * The version of specification format for this particular entity that this is written against. + */ + apiVersion: string; +} diff --git a/packages/catalog-client/src/generated/models/EntityAncestryResponse.model.ts b/packages/catalog-client/src/generated/models/EntityAncestryResponse.model.ts new file mode 100644 index 0000000000..08076fcf36 --- /dev/null +++ b/packages/catalog-client/src/generated/models/EntityAncestryResponse.model.ts @@ -0,0 +1,22 @@ +/* + * 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 { EntityAncestryResponseItemsInner } from '../models/EntityAncestryResponseItemsInner.model'; + +export interface EntityAncestryResponse { + items: Array; + rootEntityRef: string; +} diff --git a/packages/catalog-client/src/generated/models/EntityAncestryResponseItemsInner.model.ts b/packages/catalog-client/src/generated/models/EntityAncestryResponseItemsInner.model.ts new file mode 100644 index 0000000000..7713c21295 --- /dev/null +++ b/packages/catalog-client/src/generated/models/EntityAncestryResponseItemsInner.model.ts @@ -0,0 +1,22 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Entity } from '../models/Entity.model'; + +export interface EntityAncestryResponseItemsInner { + parentEntityRefs: Array; + entity: Entity; +} diff --git a/packages/catalog-client/src/generated/models/EntityFacet.model.ts b/packages/catalog-client/src/generated/models/EntityFacet.model.ts new file mode 100644 index 0000000000..3872091d77 --- /dev/null +++ b/packages/catalog-client/src/generated/models/EntityFacet.model.ts @@ -0,0 +1,20 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface EntityFacet { + value: string; + count: number; +} diff --git a/packages/catalog-client/src/generated/models/EntityFacetsResponse.model.ts b/packages/catalog-client/src/generated/models/EntityFacetsResponse.model.ts new file mode 100644 index 0000000000..0ff37e4f2f --- /dev/null +++ b/packages/catalog-client/src/generated/models/EntityFacetsResponse.model.ts @@ -0,0 +1,21 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { EntityFacet } from '../models/EntityFacet.model'; + +export interface EntityFacetsResponse { + facets: { [key: string]: Array }; +} diff --git a/packages/catalog-client/src/generated/models/EntityLink.model.ts b/packages/catalog-client/src/generated/models/EntityLink.model.ts new file mode 100644 index 0000000000..f52f9f2df0 --- /dev/null +++ b/packages/catalog-client/src/generated/models/EntityLink.model.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. + */ + +/** + * A link to external information that is related to the entity. + */ +export interface EntityLink { + /** + * An optional value to categorize links into specific groups + */ + type?: string; + /** + * An optional semantic key that represents a visual icon. + */ + icon?: string; + /** + * An optional descriptive title for the link. + */ + title?: string; + /** + * The url to the external site, document, etc. + */ + url: string; +} diff --git a/packages/catalog-client/src/generated/models/EntityMeta.model.ts b/packages/catalog-client/src/generated/models/EntityMeta.model.ts new file mode 100644 index 0000000000..cb0fd28fdc --- /dev/null +++ b/packages/catalog-client/src/generated/models/EntityMeta.model.ts @@ -0,0 +1,64 @@ +/* + * 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 { EntityLink } from '../models/EntityLink.model'; + +/** + * Metadata fields common to all versions/kinds of entity. + */ +export interface EntityMeta { + [key: string]: any; + /** + * A list of external hyperlinks related to the entity. + */ + links?: Array; + /** + * A list of single-valued strings, to for example classify catalog entities in various ways. + */ + tags?: Array; + /** + * Construct a type with a set of properties K of type T + */ + annotations?: { [key: string]: string }; + /** + * Construct a type with a set of properties K of type T + */ + labels?: { [key: string]: string }; + /** + * A short (typically relatively few words, on one line) description of the entity. + */ + description?: string; + /** + * A display name of the entity, to be presented in user interfaces instead of the `name` property above, when available. This field is sometimes useful when the `name` is cumbersome or ends up being perceived as overly technical. The title generally does not have as stringent format requirements on it, so it may contain special characters and be more explanatory. Do keep it very short though, and avoid situations where a title can be confused with the name of another entity, or where two entities share a title. Note that this is only for display purposes, and may be ignored by some parts of the code. Entity references still always make use of the `name` property, not the title. + */ + title?: string; + /** + * The namespace that the entity belongs to. + */ + namespace?: string; + /** + * The name of the entity. Must be unique within the catalog at any given point in time, for any given namespace + kind pair. This value is part of the technical identifier of the entity, and as such it will appear in URLs, database tables, entity references, and similar. It is subject to restrictions regarding what characters are allowed. If you want to use a different, more human readable string with fewer restrictions on it in user interfaces, see the `title` field below. + */ + name: string; + /** + * An opaque string that changes for each update operation to any part of the entity, including metadata. This field can not be set by the user at creation time, and the server will reject an attempt to do so. The field will be populated in read operations. The field can (optionally) be specified when performing update or delete operations, and the server will then reject the operation if it does not match the current stored value. + */ + etag?: string; + /** + * A globally unique ID for the entity. This field can not be set by the user at creation time, and the server will reject an attempt to do so. The field will be populated in read operations. The field can (optionally) be specified when performing update or delete operations, but the server is free to reject requests that do so in such a way that it breaks semantics. + */ + uid?: string; +} diff --git a/packages/catalog-client/src/generated/models/EntityRelation.model.ts b/packages/catalog-client/src/generated/models/EntityRelation.model.ts new file mode 100644 index 0000000000..1107f7563c --- /dev/null +++ b/packages/catalog-client/src/generated/models/EntityRelation.model.ts @@ -0,0 +1,29 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * A relation of a specific type to another entity in the catalog. + */ +export interface EntityRelation { + /** + * The entity ref of the target of this relation. + */ + targetRef: string; + /** + * The type of the relation. + */ + type: string; +} diff --git a/packages/catalog-client/src/generated/models/ErrorError.model.ts b/packages/catalog-client/src/generated/models/ErrorError.model.ts new file mode 100644 index 0000000000..9dbfa22813 --- /dev/null +++ b/packages/catalog-client/src/generated/models/ErrorError.model.ts @@ -0,0 +1,22 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface ErrorError { + name: string; + message: string; + stack?: string; + code?: string; +} diff --git a/packages/catalog-client/src/generated/models/ErrorRequest.model.ts b/packages/catalog-client/src/generated/models/ErrorRequest.model.ts new file mode 100644 index 0000000000..e6306b87f5 --- /dev/null +++ b/packages/catalog-client/src/generated/models/ErrorRequest.model.ts @@ -0,0 +1,20 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface ErrorRequest { + method: string; + url: string; +} diff --git a/packages/catalog-client/src/generated/models/ErrorResponse.model.ts b/packages/catalog-client/src/generated/models/ErrorResponse.model.ts new file mode 100644 index 0000000000..1f55c34b4a --- /dev/null +++ b/packages/catalog-client/src/generated/models/ErrorResponse.model.ts @@ -0,0 +1,19 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface ErrorResponse { + statusCode: number; +} diff --git a/packages/catalog-client/src/generated/models/GetEntitiesByRefsRequest.model.ts b/packages/catalog-client/src/generated/models/GetEntitiesByRefsRequest.model.ts new file mode 100644 index 0000000000..bdda7c2fa6 --- /dev/null +++ b/packages/catalog-client/src/generated/models/GetEntitiesByRefsRequest.model.ts @@ -0,0 +1,20 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface GetEntitiesByRefsRequest { + entityRefs: Array; + fields?: Array; +} diff --git a/packages/catalog-client/src/generated/models/GetLocations200ResponseInner.model.ts b/packages/catalog-client/src/generated/models/GetLocations200ResponseInner.model.ts new file mode 100644 index 0000000000..134306cce7 --- /dev/null +++ b/packages/catalog-client/src/generated/models/GetLocations200ResponseInner.model.ts @@ -0,0 +1,21 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Location } from '../models/Location.model'; + +export interface GetLocations200ResponseInner { + data: Location; +} diff --git a/packages/catalog-client/src/generated/models/Location.model.ts b/packages/catalog-client/src/generated/models/Location.model.ts new file mode 100644 index 0000000000..27e47a5a25 --- /dev/null +++ b/packages/catalog-client/src/generated/models/Location.model.ts @@ -0,0 +1,24 @@ +/* + * 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. + */ + +/** + * Entity location for a specific entity. + */ +export interface Location { + target: string; + type: string; + id: string; +} diff --git a/packages/catalog-client/src/generated/models/LocationInput.model.ts b/packages/catalog-client/src/generated/models/LocationInput.model.ts new file mode 100644 index 0000000000..8de7e3e6c9 --- /dev/null +++ b/packages/catalog-client/src/generated/models/LocationInput.model.ts @@ -0,0 +1,20 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface LocationInput { + type: string; + target: string; +} diff --git a/packages/catalog-client/src/generated/models/LocationSpec.model.ts b/packages/catalog-client/src/generated/models/LocationSpec.model.ts new file mode 100644 index 0000000000..80db2cadf2 --- /dev/null +++ b/packages/catalog-client/src/generated/models/LocationSpec.model.ts @@ -0,0 +1,23 @@ +/* + * 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. + */ + +/** + * Holds the entity location information. + */ +export interface LocationSpec { + target: string; + type: string; +} diff --git a/packages/catalog-client/src/generated/models/ModelError.model.ts b/packages/catalog-client/src/generated/models/ModelError.model.ts new file mode 100644 index 0000000000..989e755c9a --- /dev/null +++ b/packages/catalog-client/src/generated/models/ModelError.model.ts @@ -0,0 +1,26 @@ +/* + * 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 { ErrorError } from '../models/ErrorError.model'; +import { ErrorRequest } from '../models/ErrorRequest.model'; +import { ErrorResponse } from '../models/ErrorResponse.model'; + +export interface ModelError { + [key: string]: any; + error: ErrorError; + request?: ErrorRequest; + response: ErrorResponse; +} diff --git a/packages/catalog-client/src/generated/models/NullableEntity.model.ts b/packages/catalog-client/src/generated/models/NullableEntity.model.ts new file mode 100644 index 0000000000..36aff86ba8 --- /dev/null +++ b/packages/catalog-client/src/generated/models/NullableEntity.model.ts @@ -0,0 +1,41 @@ +/* + * 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 { EntityMeta } from '../models/EntityMeta.model'; +import { EntityRelation } from '../models/EntityRelation.model'; + +/** + * The parts of the format that's common to all versions/kinds of entity. + */ +export interface NullableEntity { + /** + * The relations that this entity has with other entities. + */ + relations?: Array; + /** + * A type representing all allowed JSON object values. + */ + spec?: { [key: string]: any }; + metadata: EntityMeta; + /** + * The high level entity type being described. + */ + kind: string; + /** + * The version of specification format for this particular entity that this is written against. + */ + apiVersion: string; +} diff --git a/packages/catalog-client/src/generated/models/RecursivePartialEntity.model.ts b/packages/catalog-client/src/generated/models/RecursivePartialEntity.model.ts new file mode 100644 index 0000000000..8de7824550 --- /dev/null +++ b/packages/catalog-client/src/generated/models/RecursivePartialEntity.model.ts @@ -0,0 +1,41 @@ +/* + * 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 { RecursivePartialEntityMeta } from '../models/RecursivePartialEntityMeta.model'; +import { RecursivePartialEntityRelation } from '../models/RecursivePartialEntityRelation.model'; + +/** + * Makes all keys of an entire hierarchy optional. + */ +export interface RecursivePartialEntity { + /** + * The version of specification format for this particular entity that this is written against. + */ + apiVersion?: string; + /** + * The high level entity type being described. + */ + kind?: string; + metadata?: RecursivePartialEntityMeta; + /** + * A type representing all allowed JSON object values. + */ + spec?: { [key: string]: any }; + /** + * The relations that this entity has with other entities. + */ + relations?: Array; +} diff --git a/packages/catalog-client/src/generated/models/RecursivePartialEntityMeta.model.ts b/packages/catalog-client/src/generated/models/RecursivePartialEntityMeta.model.ts new file mode 100644 index 0000000000..b21cc1bb21 --- /dev/null +++ b/packages/catalog-client/src/generated/models/RecursivePartialEntityMeta.model.ts @@ -0,0 +1,60 @@ +/* + * 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 { EntityLink } from '../models/EntityLink.model'; + +export interface RecursivePartialEntityMeta { + /** + * A list of external hyperlinks related to the entity. + */ + links?: Array; + /** + * A list of single-valued strings, to for example classify catalog entities in various ways. + */ + tags?: Array; + /** + * Construct a type with a set of properties K of type T + */ + annotations?: { [key: string]: string }; + /** + * Construct a type with a set of properties K of type T + */ + labels?: { [key: string]: string }; + /** + * A short (typically relatively few words, on one line) description of the entity. + */ + description?: string; + /** + * A display name of the entity, to be presented in user interfaces instead of the `name` property above, when available. This field is sometimes useful when the `name` is cumbersome or ends up being perceived as overly technical. The title generally does not have as stringent format requirements on it, so it may contain special characters and be more explanatory. Do keep it very short though, and avoid situations where a title can be confused with the name of another entity, or where two entities share a title. Note that this is only for display purposes, and may be ignored by some parts of the code. Entity references still always make use of the `name` property, not the title. + */ + title?: string; + /** + * The namespace that the entity belongs to. + */ + namespace?: string; + /** + * The name of the entity. Must be unique within the catalog at any given point in time, for any given namespace + kind pair. This value is part of the technical identifier of the entity, and as such it will appear in URLs, database tables, entity references, and similar. It is subject to restrictions regarding what characters are allowed. If you want to use a different, more human readable string with fewer restrictions on it in user interfaces, see the `title` field below. + */ + name?: string; + /** + * An opaque string that changes for each update operation to any part of the entity, including metadata. This field can not be set by the user at creation time, and the server will reject an attempt to do so. The field will be populated in read operations. The field can (optionally) be specified when performing update or delete operations, and the server will then reject the operation if it does not match the current stored value. + */ + etag?: string; + /** + * A globally unique ID for the entity. This field can not be set by the user at creation time, and the server will reject an attempt to do so. The field will be populated in read operations. The field can (optionally) be specified when performing update or delete operations, but the server is free to reject requests that do so in such a way that it breaks semantics. + */ + uid?: string; +} diff --git a/packages/catalog-client/src/generated/models/RecursivePartialEntityMetaAllOf.model.ts b/packages/catalog-client/src/generated/models/RecursivePartialEntityMetaAllOf.model.ts new file mode 100644 index 0000000000..5111cd7f9f --- /dev/null +++ b/packages/catalog-client/src/generated/models/RecursivePartialEntityMetaAllOf.model.ts @@ -0,0 +1,63 @@ +/* + * 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 { EntityLink } from '../models/EntityLink.model'; + +/** + * Metadata fields common to all versions/kinds of entity. + */ +export interface RecursivePartialEntityMetaAllOf { + /** + * A list of external hyperlinks related to the entity. + */ + links?: Array; + /** + * A list of single-valued strings, to for example classify catalog entities in various ways. + */ + tags?: Array; + /** + * Construct a type with a set of properties K of type T + */ + annotations?: { [key: string]: string }; + /** + * Construct a type with a set of properties K of type T + */ + labels?: { [key: string]: string }; + /** + * A short (typically relatively few words, on one line) description of the entity. + */ + description?: string; + /** + * A display name of the entity, to be presented in user interfaces instead of the `name` property above, when available. This field is sometimes useful when the `name` is cumbersome or ends up being perceived as overly technical. The title generally does not have as stringent format requirements on it, so it may contain special characters and be more explanatory. Do keep it very short though, and avoid situations where a title can be confused with the name of another entity, or where two entities share a title. Note that this is only for display purposes, and may be ignored by some parts of the code. Entity references still always make use of the `name` property, not the title. + */ + title?: string; + /** + * The namespace that the entity belongs to. + */ + namespace?: string; + /** + * The name of the entity. Must be unique within the catalog at any given point in time, for any given namespace + kind pair. This value is part of the technical identifier of the entity, and as such it will appear in URLs, database tables, entity references, and similar. It is subject to restrictions regarding what characters are allowed. If you want to use a different, more human readable string with fewer restrictions on it in user interfaces, see the `title` field below. + */ + name?: string; + /** + * An opaque string that changes for each update operation to any part of the entity, including metadata. This field can not be set by the user at creation time, and the server will reject an attempt to do so. The field will be populated in read operations. The field can (optionally) be specified when performing update or delete operations, and the server will then reject the operation if it does not match the current stored value. + */ + etag?: string; + /** + * A globally unique ID for the entity. This field can not be set by the user at creation time, and the server will reject an attempt to do so. The field will be populated in read operations. The field can (optionally) be specified when performing update or delete operations, but the server is free to reject requests that do so in such a way that it breaks semantics. + */ + uid?: string; +} diff --git a/packages/catalog-client/src/generated/models/RecursivePartialEntityRelation.model.ts b/packages/catalog-client/src/generated/models/RecursivePartialEntityRelation.model.ts new file mode 100644 index 0000000000..50635b69f4 --- /dev/null +++ b/packages/catalog-client/src/generated/models/RecursivePartialEntityRelation.model.ts @@ -0,0 +1,29 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * A relation of a specific type to another entity in the catalog. + */ +export interface RecursivePartialEntityRelation { + /** + * The entity ref of the target of this relation. + */ + targetRef?: string; + /** + * The type of the relation. + */ + type?: string; +} diff --git a/packages/catalog-client/src/generated/models/RefreshEntityRequest.model.ts b/packages/catalog-client/src/generated/models/RefreshEntityRequest.model.ts new file mode 100644 index 0000000000..573523385b --- /dev/null +++ b/packages/catalog-client/src/generated/models/RefreshEntityRequest.model.ts @@ -0,0 +1,26 @@ +/* + * 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. + */ + +/** + * Options for requesting a refresh of entities in the catalog. + */ +export interface RefreshEntityRequest { + authorizationToken?: string; + /** + * The reference to a single entity that should be refreshed + */ + entityRef: string; +} diff --git a/packages/catalog-client/src/generated/models/ValidateEntity400Response.model.ts b/packages/catalog-client/src/generated/models/ValidateEntity400Response.model.ts new file mode 100644 index 0000000000..0031b2edc2 --- /dev/null +++ b/packages/catalog-client/src/generated/models/ValidateEntity400Response.model.ts @@ -0,0 +1,21 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ValidateEntity400ResponseErrorsInner } from '../models/ValidateEntity400ResponseErrorsInner.model'; + +export interface ValidateEntity400Response { + errors: Array; +} diff --git a/packages/catalog-client/src/generated/models/ValidateEntity400ResponseErrorsInner.model.ts b/packages/catalog-client/src/generated/models/ValidateEntity400ResponseErrorsInner.model.ts new file mode 100644 index 0000000000..6223df27af --- /dev/null +++ b/packages/catalog-client/src/generated/models/ValidateEntity400ResponseErrorsInner.model.ts @@ -0,0 +1,21 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface ValidateEntity400ResponseErrorsInner { + [key: string]: any; + name: string; + message: string; +} diff --git a/packages/catalog-client/src/generated/models/ValidateEntityRequest.model.ts b/packages/catalog-client/src/generated/models/ValidateEntityRequest.model.ts new file mode 100644 index 0000000000..d5ce1be5c9 --- /dev/null +++ b/packages/catalog-client/src/generated/models/ValidateEntityRequest.model.ts @@ -0,0 +1,20 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface ValidateEntityRequest { + location: string; + entity: { [key: string]: any }; +} diff --git a/packages/catalog-client/src/generated/pluginId.ts b/packages/catalog-client/src/generated/pluginId.ts new file mode 100644 index 0000000000..c8c8ce1ca3 --- /dev/null +++ b/packages/catalog-client/src/generated/pluginId.ts @@ -0,0 +1,17 @@ +/* + * 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 const pluginId = 'catalog'; diff --git a/packages/catalog-client/src/generated/types/discovery.ts b/packages/catalog-client/src/generated/types/discovery.ts new file mode 100644 index 0000000000..a7f87d3780 --- /dev/null +++ b/packages/catalog-client/src/generated/types/discovery.ts @@ -0,0 +1,22 @@ +/* + * 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. + */ + +/** + * This is a copy of the DiscoveryApi, to avoid importing core-plugin-api. + */ +export type DiscoveryApi = { + getBaseUrl(pluginId: string): Promise; +}; diff --git a/packages/catalog-client/src/generated/types/fetch.ts b/packages/catalog-client/src/generated/types/fetch.ts new file mode 100644 index 0000000000..3de56c028e --- /dev/null +++ b/packages/catalog-client/src/generated/types/fetch.ts @@ -0,0 +1,22 @@ +/* + * 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. + */ + +/** + * This is a copy of FetchApi, to avoid importing core-plugin-api. + */ +export type FetchApi = { + fetch: typeof fetch; +}; diff --git a/packages/cli/config/eslint-factory.js b/packages/cli/config/eslint-factory.js index 58a9362051..3717943427 100644 --- a/packages/cli/config/eslint-factory.js +++ b/packages/cli/config/eslint-factory.js @@ -66,7 +66,7 @@ function createConfig(dir, extraConfig = {}) { ...(extraExtends ?? []), ], parser: '@typescript-eslint/parser', - plugins: ['import', ...(plugins ?? [])], + plugins: ['import', 'unused-imports', ...(plugins ?? [])], env: { jest: true, ...env, @@ -165,6 +165,23 @@ function createConfig(dir, extraConfig = {}) { ], }, }, + { + files: ['**/src/generated/**/*.ts'], + rules: { + ...tsRules, + 'no-unused-vars': 'off', + 'unused-imports/no-unused-imports': 'error', + 'unused-imports/no-unused-vars': [ + 'warn', + { + vars: 'all', + varsIgnorePattern: '^_', + args: 'none', + argsIgnorePattern: '^_', + }, + ], + }, + }, ...(overrides ?? []), ], }; diff --git a/packages/cli/package.json b/packages/cli/package.json index 2dece07ade..ad3d2f1b45 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -89,6 +89,7 @@ "eslint-plugin-jsx-a11y": "^6.5.1", "eslint-plugin-react": "^7.28.0", "eslint-plugin-react-hooks": "^4.3.0", + "eslint-plugin-unused-imports": "^3.0.0", "eslint-webpack-plugin": "^3.1.1", "express": "^4.17.1", "fork-ts-checker-webpack-plugin": "^7.0.0-alpha.8", diff --git a/packages/errors/src/errors/ResponseError.ts b/packages/errors/src/errors/ResponseError.ts index f8ba0a1ba1..fa086561ed 100644 --- a/packages/errors/src/errors/ResponseError.ts +++ b/packages/errors/src/errors/ResponseError.ts @@ -42,6 +42,11 @@ export class ResponseError extends Error { */ readonly body: ErrorResponseBody; + /** + * The unparsed possibly JSON error body. Will be set even if the returned error doesn't match {@link ErrorResponseBody}. + */ + readonly rawBody: string; + /** * The Error cause, as seen by the remote server. This is parsed out of the * JSON error body. @@ -61,9 +66,22 @@ export class ResponseError extends Error { * been consumed before. */ static async fromResponse( - response: ConsumedResponse & { text(): Promise }, + response: ConsumedResponse & { text(): Promise; bodyUsed: boolean }, ): Promise { - const data = await parseErrorResponseBody(response); + let rawBody = ''; + try { + rawBody = await response.text(); + } catch { + // ignore + } + + const data = await parseErrorResponseBody( + // TS isn't smart enough to know that this is done under the hood, + response as ConsumedResponse & { + bodyUsed: true; + }, + rawBody, + ); const status = data.response.statusCode || response.status; const statusText = data.error.name || response.statusText; @@ -75,6 +93,7 @@ export class ResponseError extends Error { response, data, cause, + rawBody, }); } @@ -82,6 +101,7 @@ export class ResponseError extends Error { message: string; response: ConsumedResponse; data: ErrorResponseBody; + rawBody: string; cause: Error; }) { super(props.message); @@ -89,5 +109,6 @@ export class ResponseError extends Error { this.response = props.response; this.body = props.data; this.cause = props.cause; + this.rawBody = props.rawBody; } } diff --git a/packages/errors/src/serialization/response.ts b/packages/errors/src/serialization/response.ts index 60894b243e..522913be83 100644 --- a/packages/errors/src/serialization/response.ts +++ b/packages/errors/src/serialization/response.ts @@ -54,10 +54,20 @@ export type ErrorResponseBody = { * @param response - The response of a failed request */ export async function parseErrorResponseBody( - response: ConsumedResponse & { text(): Promise }, + response: ConsumedResponse & { bodyUsed: true }, + rawBody: string, +): Promise; +export async function parseErrorResponseBody( + response: ConsumedResponse & { text(): Promise; bodyUsed: false }, +): Promise; +export async function parseErrorResponseBody( + response: + | (ConsumedResponse & { bodyUsed: true }) + | (ConsumedResponse & { text(): Promise; bodyUsed: false }), + rawBody?: string, ): Promise { try { - const text = await response.text(); + const text = !response.bodyUsed ? await response.text() : rawBody; if (text) { if ( response.headers.get('content-type')?.startsWith('application/json') diff --git a/packages/repo-tools/openapitools.json b/packages/repo-tools/openapitools.json new file mode 100644 index 0000000000..65c0d8ead7 --- /dev/null +++ b/packages/repo-tools/openapitools.json @@ -0,0 +1,7 @@ +{ + "$schema": "../../node_modules/@openapitools/openapi-generator-cli/config.schema.json", + "spaces": 2, + "generator-cli": { + "version": "6.5.0" + } +} diff --git a/packages/repo-tools/package.json b/packages/repo-tools/package.json index 3bd76a6e60..9dad92966b 100644 --- a/packages/repo-tools/package.json +++ b/packages/repo-tools/package.json @@ -39,6 +39,7 @@ "@manypkg/get-packages": "^1.1.3", "@microsoft/api-documenter": "^7.22.33", "@microsoft/api-extractor": "^7.36.4", + "@openapitools/openapi-generator-cli": "^2.7.0", "@stoplight/spectral-core": "^1.18.0", "@stoplight/spectral-formatters": "^1.1.0", "@stoplight/spectral-functions": "^1.7.2", diff --git a/packages/repo-tools/src/commands/index.ts b/packages/repo-tools/src/commands/index.ts index 4f9ea87708..d9c6d892f5 100644 --- a/packages/repo-tools/src/commands/index.ts +++ b/packages/repo-tools/src/commands/index.ts @@ -32,14 +32,18 @@ function registerSchemaCommand(program: Command) { .description( 'Verify that all OpenAPI schemas are valid and have a matching `schemas/openapi.generated.ts` file.', ) - .action(lazy(() => import('./openapi/verify').then(m => m.bulkCommand))); + .action( + lazy(() => import('./openapi/schema/verify').then(m => m.bulkCommand)), + ); openApiCommand .command('generate [paths...]') .description( 'Generates a Typescript file from an OpenAPI yaml spec. For use with the `@backstage/backend-openapi-utils` ApiRouter type.', ) - .action(lazy(() => import('./openapi/generate').then(m => m.bulkCommand))); + .action( + lazy(() => import('./openapi/schema/generate').then(m => m.bulkCommand)), + ); openApiCommand .command('lint [paths...]') @@ -60,6 +64,16 @@ function registerSchemaCommand(program: Command) { .command('init ') .description('Creates any config needed for the test command.') .action(lazy(() => import('./openapi/test/init').then(m => m.default))); + + openApiCommand + .command('generate-client') + .requiredOption('--input-spec ') + .requiredOption('--output-directory ') + .action( + lazy(() => + import('./openapi/client/generate').then(m => m.singleCommand), + ), + ); } export function registerCommands(program: Command) { diff --git a/packages/repo-tools/src/commands/openapi/client/generate.ts b/packages/repo-tools/src/commands/openapi/client/generate.ts new file mode 100644 index 0000000000..baa7845436 --- /dev/null +++ b/packages/repo-tools/src/commands/openapi/client/generate.ts @@ -0,0 +1,97 @@ +/* + * 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 chalk from 'chalk'; +import { resolve } from 'path'; +import { OPENAPI_IGNORE_FILES, OUTPUT_PATH } from '../constants'; +import { paths as cliPaths } from '../../../lib/paths'; +import { mkdirpSync } from 'fs-extra'; +import fs from 'fs-extra'; +import { exec } from '../../../lib/exec'; + +async function generate(spec: string, outputDirectory: string) { + const resolvedOpenapiPath = resolve(spec); + const resolvedOutputDirectory = resolve(outputDirectory, OUTPUT_PATH); + mkdirpSync(resolvedOutputDirectory); + + await fs.mkdirp(resolvedOutputDirectory); + + await fs.writeFile( + resolve(resolvedOutputDirectory, '.openapi-generator-ignore'), + OPENAPI_IGNORE_FILES.join('\n'), + ); + + await exec( + // The actual main.js file for the binary isn't executable but yarn does _something_ to make it executable. + // TODO (sennyeya@): Make this use the actual binary + `yarn openapi-generator-cli`, + [ + 'generate', + '-i', + resolvedOpenapiPath, + '-o', + resolvedOutputDirectory, + '-g', + 'typescript', + '-c', + 'templates/typescript-backstage.yaml', + '--generator-key', + 'v3.0', + ], + { + maxBuffer: Number.MAX_VALUE, + cwd: cliPaths.ownDir, + env: { + ...process.env, + // PWD: outputDirectory, + }, + }, + ); + + await exec( + `yarn backstage-cli package lint --fix ${resolvedOutputDirectory}`, + ); + + if (cliPaths.resolveTargetRoot('node_modules/.bin/prettier')) { + await exec(`yarn prettier --write ${resolvedOutputDirectory}`); + } + + fs.removeSync(resolve(resolvedOutputDirectory, '.openapi-generator-ignore')); + + fs.rmSync(resolve(resolvedOutputDirectory, '.openapi-generator'), { + recursive: true, + force: true, + }); +} + +export async function singleCommand({ + inputSpec, + outputDirectory, +}: { + inputSpec: string; + outputDirectory: string; +}): Promise { + try { + await generate(inputSpec, outputDirectory); + console.log(chalk.green(`Generated client for ${inputSpec}`)); + } catch (err) { + console.log(); + console.log(chalk.red(`Client generation failed in ${outputDirectory}:`)); + console.log(err); + + process.exit(1); + } +} diff --git a/packages/repo-tools/src/commands/openapi/constants.ts b/packages/repo-tools/src/commands/openapi/constants.ts index defef4ab53..2e7a57522a 100644 --- a/packages/repo-tools/src/commands/openapi/constants.ts +++ b/packages/repo-tools/src/commands/openapi/constants.ts @@ -19,3 +19,44 @@ export const YAML_SCHEMA_PATH = 'src/schema/openapi.yaml'; export const TS_MODULE = 'src/schema/openapi.generated'; export const TS_SCHEMA_PATH = `${TS_MODULE}.ts`; + +export const GENERATOR_VERSION = `1.0.0`; +export const GENERATOR_NAME = 'typescript-backstage'; +export const GENERATOR_FILE = `packages/template-openapi-plugin-client/generator/target/${GENERATOR_NAME}-openapi-generator-${GENERATOR_VERSION}.jar`; + +export const OUTPUT_PATH = 'src/generated'; + +export const OPENAPI_IGNORE_FILES = [ + // Get rid of the default files. + '*.md', + // The rest of these have to be explicit, otherwise they get added if this was a *.* + 'apis/baseapi.ts', + 'apis/exception.ts', + 'auth/*', + 'http/*', + 'middleware.ts', + 'servers.ts', + 'util.ts', + 'configuration.ts', + 'rxjsStub.ts', + '.gitignore', + + // Override the created version. + 'apis/*.ts', + '!apis/*.client.ts', + 'models/*.ts', + '!models/*.model.ts', + + // Always include index.ts files. + '!index.ts', + '!**/index.ts', + + // Weird API typings. + 'types/ObjectParamAPI.ts', + 'types/ObservableAPI.ts', + 'types/PromiseAPI.ts', + + 'git_push.sh', + 'package.json', + 'tsconfig.json', +]; diff --git a/packages/repo-tools/src/commands/openapi/generate.ts b/packages/repo-tools/src/commands/openapi/schema/generate.ts similarity index 95% rename from packages/repo-tools/src/commands/openapi/generate.ts rename to packages/repo-tools/src/commands/openapi/schema/generate.ts index 52b8e5b840..cd9f572f2d 100644 --- a/packages/repo-tools/src/commands/openapi/generate.ts +++ b/packages/repo-tools/src/commands/openapi/schema/generate.ts @@ -18,9 +18,9 @@ import fs from 'fs-extra'; import YAML from 'js-yaml'; import chalk from 'chalk'; import { resolve } from 'path'; -import { paths as cliPaths } from '../../lib/paths'; -import { runner } from './runner'; -import { TS_SCHEMA_PATH, YAML_SCHEMA_PATH } from './constants'; +import { paths as cliPaths } from '../../../lib/paths'; +import { runner } from '../runner'; +import { TS_SCHEMA_PATH, YAML_SCHEMA_PATH } from '../constants'; import { promisify } from 'util'; import { exec as execCb } from 'child_process'; diff --git a/packages/repo-tools/src/commands/openapi/verify.ts b/packages/repo-tools/src/commands/openapi/schema/verify.ts similarity index 93% rename from packages/repo-tools/src/commands/openapi/verify.ts rename to packages/repo-tools/src/commands/openapi/schema/verify.ts index 2808e72702..7120dd67ad 100644 --- a/packages/repo-tools/src/commands/openapi/verify.ts +++ b/packages/repo-tools/src/commands/openapi/schema/verify.ts @@ -21,9 +21,9 @@ import { join } from 'path'; import chalk from 'chalk'; import { relative as relativePath, resolve as resolvePath } from 'path'; import Parser from '@apidevtools/swagger-parser'; -import { runner } from './runner'; -import { paths as cliPaths } from '../../lib/paths'; -import { TS_MODULE, TS_SCHEMA_PATH, YAML_SCHEMA_PATH } from './constants'; +import { runner } from '../runner'; +import { paths as cliPaths } from '../../../lib/paths'; +import { TS_MODULE, TS_SCHEMA_PATH, YAML_SCHEMA_PATH } from '../constants'; async function verify(directoryPath: string) { const openapiPath = join(directoryPath, YAML_SCHEMA_PATH); diff --git a/packages/repo-tools/templates/typescript-backstage.yaml b/packages/repo-tools/templates/typescript-backstage.yaml new file mode 100644 index 0000000000..eaa72d7179 --- /dev/null +++ b/packages/repo-tools/templates/typescript-backstage.yaml @@ -0,0 +1,18 @@ +templateDir: templates/typescript-backstage + +files: + api.mustache: + templateType: API + # For some reason, they check for destinationFilename differences. We have to change the ending to override the file. + destinationFilename: .client.ts + model.mustache: + templateType: Model + destinationFilename: .model.ts + types/fetch.ts: {} + types/discovery.ts: {} + apis/index.mustache: + templateType: SupportingFiles + destinationFilename: apis/index.ts + pluginId.mustache: + templateType: SupportingFiles + destinationFilename: pluginId.ts \ No newline at end of file diff --git a/packages/repo-tools/templates/typescript-backstage/api.mustache b/packages/repo-tools/templates/typescript-backstage/api.mustache new file mode 100644 index 0000000000..e2e1ae4b3b --- /dev/null +++ b/packages/repo-tools/templates/typescript-backstage/api.mustache @@ -0,0 +1,120 @@ +{{>licenseInfo}} +import { DiscoveryApi } from '../types/discovery'; +import { FetchApi } from '../types/fetch'; +import crossFetch from 'cross-fetch'; +import {pluginId} from '../pluginId'; +import * as parser from 'uri-template'; +import {ResponseError} from '@backstage/errors'; + +{{#imports}} +import { {{classname}} } from '{{filename}}.model{{importFileExtension}}'; +{{/imports}} + +type TypedResponse = Omit & { + json: () => Promise; +}; + +{{#operations}} + +/** + * Options you can pass into a request for additional information. + * + * @public + */ +export interface RequestOptions { + token?: string; +} + +/** + * {{{description}}}{{^description}}no description{{/description}} + */ +export class {{classname}}Client { + private readonly discoveryApi: DiscoveryApi; + private readonly fetchApi: FetchApi; + + constructor(options: { + discoveryApi: { getBaseUrl(pluginId: string): Promise }; + fetchApi?: { fetch: typeof fetch }; + }) { + this.discoveryApi = options.discoveryApi; + this.fetchApi = options.fetchApi || { fetch: crossFetch }; + } + + {{#operation}} + /** + {{#notes}} + * {{¬es}} + {{/notes}} + {{#summary}} + * {{&summary}} + {{/summary}} + {{#allParams}} + * @param {{paramName}} {{description}} + {{/allParams}} + */ + public async {{nickname}}( + // @ts-ignore + request: { + {{#hasPathParams}} + path: { + {{#pathParams}} + {{paramName}}{{^required}}?{{/required}}: {{{dataType}}}, + {{/pathParams}} + }, + {{/hasPathParams}} + {{#hasBodyParam}} + {{#bodyParam}} + body: {{{dataType}}}, + {{/bodyParam}} + {{/hasBodyParam}} + {{#hasQueryParams}} + query: { + {{#queryParams}} + {{paramName}}{{^required}}?{{/required}}: {{{dataType}}}, + {{/queryParams}} + }, + {{/hasQueryParams}} + {{#hasHeaderParams}} + header: { + {{#headerParams}} + {{paramName}}{{^required}}?{{/required}}: {{{dataType}}}, + {{/headerParams}} + }, + {{/hasHeaderParams}} + }, + options?: RequestOptions + ): Promise> { + const baseUrl = await this.discoveryApi.getBaseUrl(pluginId); + + const uriTemplate = `{{{path}}}{{#hasQueryParams}}{?{{#queryParams}}{{baseName}}{{#isArray}}{{#isExplode}}*{{/isExplode}}{{/isArray}}{{^-last}},{{/-last}}{{/queryParams}}}{{/hasQueryParams}}`; + + const uri = parser.parse(uriTemplate).expand({ + {{#pathParams}} + {{baseName}}: request.path.{{paramName}}, + {{/pathParams}} + {{#hasQueryParams}} + ...request.query, + {{/hasQueryParams}} + }) + + const url = `${baseUrl}${uri}`; + const response = await this.fetchApi.fetch(url, { + headers: { + {{#hasHeaderParams}} + ...request.header, + {{/hasHeaderParams}} + 'Content-Type': 'application/json', + ...(options?.token && { Authorization: `Bearer ${options?.token}` }), + }, + method: '{{httpMethod}}', + {{#hasBodyParam}} body: JSON.stringify(request.body), {{/hasBodyParam}} + }); + if(response.ok){ + return response; + }; + throw await ResponseError.fromResponse(response); + } + + {{/operation}} +} +{{/operations}} diff --git a/packages/repo-tools/templates/typescript-backstage/apis/index.mustache b/packages/repo-tools/templates/typescript-backstage/apis/index.mustache new file mode 100644 index 0000000000..4c8996c5ee --- /dev/null +++ b/packages/repo-tools/templates/typescript-backstage/apis/index.mustache @@ -0,0 +1,3 @@ +// + +export * from './DefaultApi.client'; diff --git a/packages/repo-tools/templates/typescript-backstage/index.mustache b/packages/repo-tools/templates/typescript-backstage/index.mustache new file mode 100644 index 0000000000..8436cce60b --- /dev/null +++ b/packages/repo-tools/templates/typescript-backstage/index.mustache @@ -0,0 +1,3 @@ +// + +export * from './apis' diff --git a/packages/repo-tools/templates/typescript-backstage/model.mustache b/packages/repo-tools/templates/typescript-backstage/model.mustache new file mode 100644 index 0000000000..1f288380e0 --- /dev/null +++ b/packages/repo-tools/templates/typescript-backstage/model.mustache @@ -0,0 +1,43 @@ +// + +{{#models}} +{{#model}} +{{#tsImports}} +import { {{classname}} } from '{{filename}}.model{{importFileExtension}}'; +{{/tsImports}} + +{{#description}} +/** +* {{{.}}} +*/ +{{/description}} +{{^isEnum}} +export interface {{classname}} { +{{#additionalPropertiesType}} + [key: string]: {{{additionalPropertiesType}}}; +{{/additionalPropertiesType}} +{{#vars}} +{{#description}} + /** + * {{{.}}} + */ +{{/description}} + '{{name}}'{{^required}}?{{/required}}: {{#isEnum}}{{{datatypeWithEnum}}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}{{#isNullable}} | null{{/isNullable}}; +{{/vars}} +} + +{{#hasEnums}} + +{{#vars}} +{{#isEnum}} +export type {{classname}}{{enumName}} ={{#allowableValues}}{{#values}} "{{.}}" {{^-last}}|{{/-last}}{{/values}}{{/allowableValues}}; +{{/isEnum}} +{{/vars}} + +{{/hasEnums}} +{{/isEnum}} +{{#isEnum}} +export type {{classname}} ={{#allowableValues}}{{#values}} "{{.}}" {{^-last}}|{{/-last}}{{/values}}{{/allowableValues}}; +{{/isEnum}} +{{/model}} +{{/models}} \ No newline at end of file diff --git a/packages/repo-tools/templates/typescript-backstage/models/models_all.mustache b/packages/repo-tools/templates/typescript-backstage/models/models_all.mustache new file mode 100644 index 0000000000..d076cfb3ff --- /dev/null +++ b/packages/repo-tools/templates/typescript-backstage/models/models_all.mustache @@ -0,0 +1,7 @@ +// + +{{#models}} +{{#model}} +export * from '{{{ importPath }}}.model{{importFileExtension}}' +{{/model}} +{{/models}} \ No newline at end of file diff --git a/packages/repo-tools/templates/typescript-backstage/pluginId.mustache b/packages/repo-tools/templates/typescript-backstage/pluginId.mustache new file mode 100644 index 0000000000..8bc8461cc9 --- /dev/null +++ b/packages/repo-tools/templates/typescript-backstage/pluginId.mustache @@ -0,0 +1,6 @@ + +{{#servers}} +{{#-last}} +export const pluginId = "{{url}}"; +{{/-last}} +{{/servers}} \ No newline at end of file diff --git a/packages/repo-tools/templates/typescript-backstage/types/discovery.ts b/packages/repo-tools/templates/typescript-backstage/types/discovery.ts new file mode 100644 index 0000000000..a7f87d3780 --- /dev/null +++ b/packages/repo-tools/templates/typescript-backstage/types/discovery.ts @@ -0,0 +1,22 @@ +/* + * 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. + */ + +/** + * This is a copy of the DiscoveryApi, to avoid importing core-plugin-api. + */ +export type DiscoveryApi = { + getBaseUrl(pluginId: string): Promise; +}; diff --git a/packages/repo-tools/templates/typescript-backstage/types/fetch.ts b/packages/repo-tools/templates/typescript-backstage/types/fetch.ts new file mode 100644 index 0000000000..3de56c028e --- /dev/null +++ b/packages/repo-tools/templates/typescript-backstage/types/fetch.ts @@ -0,0 +1,22 @@ +/* + * 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. + */ + +/** + * This is a copy of FetchApi, to avoid importing core-plugin-api. + */ +export type FetchApi = { + fetch: typeof fetch; +}; diff --git a/plugins/catalog-backend/src/schema/openapi.generated.ts b/plugins/catalog-backend/src/schema/openapi.generated.ts index a31615dfc6..fe64c75373 100644 --- a/plugins/catalog-backend/src/schema/openapi.generated.ts +++ b/plugins/catalog-backend/src/schema/openapi.generated.ts @@ -36,6 +36,9 @@ export const spec = { { url: '/', }, + { + url: 'catalog', + }, ], components: { examples: {}, @@ -105,6 +108,7 @@ export const spec = { description: 'Restrict to just these fields in the response.', required: false, allowReserved: true, + explode: false, schema: { type: 'array', items: { @@ -248,12 +252,13 @@ export const spec = { }, }, required: ['error', 'response'], + additionalProperties: {}, }, JsonObject: { type: 'object', properties: {}, description: 'A type representing all allowed JSON object values.', - additionalProperties: true, + additionalProperties: {}, }, MapStringString: { type: 'object', @@ -291,70 +296,62 @@ export const spec = { additionalProperties: false, }, EntityMeta: { - allOf: [ - { - $ref: '#/components/schemas/JsonObject', - }, - { - type: 'object', - properties: { - links: { - type: 'array', - items: { - $ref: '#/components/schemas/EntityLink', - }, - description: - 'A list of external hyperlinks related to the entity.', - }, - tags: { - type: 'array', - items: { - type: 'string', - }, - description: - 'A list of single-valued strings, to for example classify catalog entities in\nvarious ways.', - }, - annotations: { - $ref: '#/components/schemas/MapStringString', - }, - labels: { - $ref: '#/components/schemas/MapStringString', - }, - description: { - type: 'string', - description: - 'A short (typically relatively few words, on one line) description of the\nentity.', - }, - title: { - type: 'string', - description: - 'A display name of the entity, to be presented in user interfaces instead\nof the `name` property above, when available.\nThis field is sometimes useful when the `name` is cumbersome or ends up\nbeing perceived as overly technical. The title generally does not have\nas stringent format requirements on it, so it may contain special\ncharacters and be more explanatory. Do keep it very short though, and\navoid situations where a title can be confused with the name of another\nentity, or where two entities share a title.\nNote that this is only for display purposes, and may be ignored by some\nparts of the code. Entity references still always make use of the `name`\nproperty, not the title.', - }, - namespace: { - type: 'string', - description: 'The namespace that the entity belongs to.', - }, - name: { - type: 'string', - description: - 'The name of the entity.\nMust be unique within the catalog at any given point in time, for any\ngiven namespace + kind pair. This value is part of the technical\nidentifier of the entity, and as such it will appear in URLs, database\ntables, entity references, and similar. It is subject to restrictions\nregarding what characters are allowed.\nIf you want to use a different, more human readable string with fewer\nrestrictions on it in user interfaces, see the `title` field below.', - }, - etag: { - type: 'string', - description: - 'An opaque string that changes for each update operation to any part of\nthe entity, including metadata.\nThis field can not be set by the user at creation time, and the server\nwill reject an attempt to do so. The field will be populated in read\noperations. The field can (optionally) be specified when performing\nupdate or delete operations, and the server will then reject the\noperation if it does not match the current stored value.', - }, - uid: { - type: 'string', - description: - 'A globally unique ID for the entity.\nThis field can not be set by the user at creation time, and the server\nwill reject an attempt to do so. The field will be populated in read\noperations. The field can (optionally) be specified when performing\nupdate or delete operations, but the server is free to reject requests\nthat do so in such a way that it breaks semantics.', - }, + type: 'object', + properties: { + links: { + type: 'array', + items: { + $ref: '#/components/schemas/EntityLink', }, - required: ['name'], + description: 'A list of external hyperlinks related to the entity.', }, - ], + tags: { + type: 'array', + items: { + type: 'string', + }, + description: + 'A list of single-valued strings, to for example classify catalog entities in\nvarious ways.', + }, + annotations: { + $ref: '#/components/schemas/MapStringString', + }, + labels: { + $ref: '#/components/schemas/MapStringString', + }, + description: { + type: 'string', + description: + 'A short (typically relatively few words, on one line) description of the\nentity.', + }, + title: { + type: 'string', + description: + 'A display name of the entity, to be presented in user interfaces instead\nof the `name` property above, when available.\nThis field is sometimes useful when the `name` is cumbersome or ends up\nbeing perceived as overly technical. The title generally does not have\nas stringent format requirements on it, so it may contain special\ncharacters and be more explanatory. Do keep it very short though, and\navoid situations where a title can be confused with the name of another\nentity, or where two entities share a title.\nNote that this is only for display purposes, and may be ignored by some\nparts of the code. Entity references still always make use of the `name`\nproperty, not the title.', + }, + namespace: { + type: 'string', + description: 'The namespace that the entity belongs to.', + }, + name: { + type: 'string', + description: + 'The name of the entity.\nMust be unique within the catalog at any given point in time, for any\ngiven namespace + kind pair. This value is part of the technical\nidentifier of the entity, and as such it will appear in URLs, database\ntables, entity references, and similar. It is subject to restrictions\nregarding what characters are allowed.\nIf you want to use a different, more human readable string with fewer\nrestrictions on it in user interfaces, see the `title` field below.', + }, + etag: { + type: 'string', + description: + 'An opaque string that changes for each update operation to any part of\nthe entity, including metadata.\nThis field can not be set by the user at creation time, and the server\nwill reject an attempt to do so. The field will be populated in read\noperations. The field can (optionally) be specified when performing\nupdate or delete operations, and the server will then reject the\noperation if it does not match the current stored value.', + }, + uid: { + type: 'string', + description: + 'A globally unique ID for the entity.\nThis field can not be set by the user at creation time, and the server\nwill reject an attempt to do so. The field will be populated in read\noperations. The field can (optionally) be specified when performing\nupdate or delete operations, but the server is free to reject requests\nthat do so in such a way that it breaks semantics.', + }, + }, + required: ['name'], description: 'Metadata fields common to all versions/kinds of entity.', - additionalProperties: true, + additionalProperties: {}, }, EntityRelation: { type: 'object', @@ -403,7 +400,6 @@ export const spec = { required: ['metadata', 'kind', 'apiVersion'], description: "The parts of the format that's common to all versions/kinds of entity.", - additionalProperties: true, }, NullableEntity: { type: 'object', @@ -435,7 +431,6 @@ export const spec = { required: ['metadata', 'kind', 'apiVersion'], description: "The parts of the format that's common to all versions/kinds of entity.", - additionalProperties: true, nullable: true, }, EntityAncestryResponse: { @@ -472,11 +467,7 @@ export const spec = { items: { type: 'array', items: { - anyOf: [ - { - $ref: '#/components/schemas/NullableEntity', - }, - ], + $ref: '#/components/schemas/NullableEntity', }, description: 'The list of entities, in the same order as the refs in the request. Entries\nthat are null signify that no entity existed with that ref.', @@ -495,6 +486,7 @@ export const spec = { type: 'number', }, }, + required: ['value', 'count'], additionalProperties: false, }, EntityFacetsResponse: { @@ -782,6 +774,7 @@ export const spec = { }, }, }, + required: ['items', 'totalItems', 'pageInfo'], additionalProperties: false, }, }, @@ -1076,11 +1069,6 @@ export const spec = { JWT: [], }, ], - parameters: [ - { - $ref: '#/components/parameters/fields', - }, - ], requestBody: { required: false, content: { @@ -1257,8 +1245,8 @@ export const spec = { operationId: 'CreateLocation', description: 'Create a location for a given target.', responses: { - '200': { - description: 'Ok', + '201': { + description: 'Created', content: { 'application/json': { schema: { @@ -1282,38 +1270,6 @@ export const spec = { }, }, }, - '201': { - description: '201 response', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - location: { - type: 'object', - properties: { - id: { - type: 'string', - }, - type: { - type: 'string', - }, - target: { - type: 'string', - }, - }, - required: ['id', 'type', 'target'], - }, - entities: { - type: 'array', - items: {}, - }, - }, - required: ['location', 'entities'], - }, - }, - }, - }, '400': { $ref: '#/components/responses/ErrorResponse', }, @@ -1524,7 +1480,7 @@ export const spec = { description: 'Ok', }, '400': { - description: '400 response', + description: 'Validation errors.', content: { 'application/json; charset=utf-8': { schema: { @@ -1543,6 +1499,7 @@ export const spec = { }, }, required: ['name', 'message'], + additionalProperties: {}, }, }, }, @@ -1571,7 +1528,7 @@ export const spec = { }, entity: { type: 'object', - additionalProperties: true, + additionalProperties: {}, }, }, required: ['location', 'entity'], diff --git a/plugins/catalog-backend/src/schema/openapi.yaml b/plugins/catalog-backend/src/schema/openapi.yaml index 3375f7fe15..d3ef718286 100644 --- a/plugins/catalog-backend/src/schema/openapi.yaml +++ b/plugins/catalog-backend/src/schema/openapi.yaml @@ -9,6 +9,7 @@ info: contact: {} servers: - url: / + - url: catalog components: examples: {} headers: {} @@ -65,6 +66,7 @@ components: description: Restrict to just these fields in the response. required: false allowReserved: true + explode: false schema: type: array items: @@ -180,11 +182,12 @@ components: required: - error - response + additionalProperties: {} JsonObject: type: object properties: {} description: A type representing all allowed JSON object values. - additionalProperties: true + additionalProperties: {} MapStringString: type: object properties: {} @@ -211,82 +214,80 @@ components: description: A link to external information that is related to the entity. additionalProperties: false EntityMeta: - allOf: - - $ref: '#/components/schemas/JsonObject' - - type: object - properties: - links: - type: array - items: - $ref: '#/components/schemas/EntityLink' - description: A list of external hyperlinks related to the entity. - tags: - type: array - items: - type: string - description: |- - A list of single-valued strings, to for example classify catalog entities in - various ways. - annotations: - $ref: '#/components/schemas/MapStringString' - labels: - $ref: '#/components/schemas/MapStringString' - description: - type: string - description: |- - A short (typically relatively few words, on one line) description of the - entity. - title: - type: string - description: |- - A display name of the entity, to be presented in user interfaces instead - of the `name` property above, when available. - This field is sometimes useful when the `name` is cumbersome or ends up - being perceived as overly technical. The title generally does not have - as stringent format requirements on it, so it may contain special - characters and be more explanatory. Do keep it very short though, and - avoid situations where a title can be confused with the name of another - entity, or where two entities share a title. - Note that this is only for display purposes, and may be ignored by some - parts of the code. Entity references still always make use of the `name` - property, not the title. - namespace: - type: string - description: The namespace that the entity belongs to. - name: - type: string - description: |- - The name of the entity. - Must be unique within the catalog at any given point in time, for any - given namespace + kind pair. This value is part of the technical - identifier of the entity, and as such it will appear in URLs, database - tables, entity references, and similar. It is subject to restrictions - regarding what characters are allowed. - If you want to use a different, more human readable string with fewer - restrictions on it in user interfaces, see the `title` field below. - etag: - type: string - description: |- - An opaque string that changes for each update operation to any part of - the entity, including metadata. - This field can not be set by the user at creation time, and the server - will reject an attempt to do so. The field will be populated in read - operations. The field can (optionally) be specified when performing - update or delete operations, and the server will then reject the - operation if it does not match the current stored value. - uid: - type: string - description: |- - A globally unique ID for the entity. - This field can not be set by the user at creation time, and the server - will reject an attempt to do so. The field will be populated in read - operations. The field can (optionally) be specified when performing - update or delete operations, but the server is free to reject requests - that do so in such a way that it breaks semantics. - required: - - name + type: object + properties: + links: + type: array + items: + $ref: '#/components/schemas/EntityLink' + description: A list of external hyperlinks related to the entity. + tags: + type: array + items: + type: string + description: |- + A list of single-valued strings, to for example classify catalog entities in + various ways. + annotations: + $ref: '#/components/schemas/MapStringString' + labels: + $ref: '#/components/schemas/MapStringString' + description: + type: string + description: |- + A short (typically relatively few words, on one line) description of the + entity. + title: + type: string + description: |- + A display name of the entity, to be presented in user interfaces instead + of the `name` property above, when available. + This field is sometimes useful when the `name` is cumbersome or ends up + being perceived as overly technical. The title generally does not have + as stringent format requirements on it, so it may contain special + characters and be more explanatory. Do keep it very short though, and + avoid situations where a title can be confused with the name of another + entity, or where two entities share a title. + Note that this is only for display purposes, and may be ignored by some + parts of the code. Entity references still always make use of the `name` + property, not the title. + namespace: + type: string + description: The namespace that the entity belongs to. + name: + type: string + description: |- + The name of the entity. + Must be unique within the catalog at any given point in time, for any + given namespace + kind pair. This value is part of the technical + identifier of the entity, and as such it will appear in URLs, database + tables, entity references, and similar. It is subject to restrictions + regarding what characters are allowed. + If you want to use a different, more human readable string with fewer + restrictions on it in user interfaces, see the `title` field below. + etag: + type: string + description: |- + An opaque string that changes for each update operation to any part of + the entity, including metadata. + This field can not be set by the user at creation time, and the server + will reject an attempt to do so. The field will be populated in read + operations. The field can (optionally) be specified when performing + update or delete operations, and the server will then reject the + operation if it does not match the current stored value. + uid: + type: string + description: |- + A globally unique ID for the entity. + This field can not be set by the user at creation time, and the server + will reject an attempt to do so. The field will be populated in read + operations. The field can (optionally) be specified when performing + update or delete operations, but the server is free to reject requests + that do so in such a way that it breaks semantics. + required: + - name description: Metadata fields common to all versions/kinds of entity. - additionalProperties: true + additionalProperties: {} EntityRelation: type: object properties: @@ -326,7 +327,6 @@ components: - kind - apiVersion description: The parts of the format that's common to all versions/kinds of entity. - additionalProperties: true NullableEntity: type: object properties: @@ -352,7 +352,6 @@ components: - kind - apiVersion description: The parts of the format that's common to all versions/kinds of entity. - additionalProperties: true nullable: true EntityAncestryResponse: type: object @@ -383,8 +382,7 @@ components: items: type: array items: - anyOf: - - $ref: '#/components/schemas/NullableEntity' + $ref: '#/components/schemas/NullableEntity' description: |- The list of entities, in the same order as the refs in the request. Entries that are null signify that no entity existed with that ref. @@ -398,6 +396,9 @@ components: type: string count: type: number + required: + - value + - count additionalProperties: false EntityFacetsResponse: type: object @@ -660,6 +661,10 @@ components: prevCursor: type: string description: The cursor for the previous batch of entities. + required: + - items + - totalItems + - pageInfo additionalProperties: false securitySchemes: JWT: @@ -829,8 +834,6 @@ paths: security: - {} - JWT: [] - parameters: - - $ref: '#/components/parameters/fields' requestBody: required: false content: @@ -942,8 +945,8 @@ paths: operationId: CreateLocation description: Create a location for a given target. responses: - '200': - description: Ok + '201': + description: Created content: application/json: schema: @@ -960,32 +963,6 @@ paths: required: - entities - location - '201': - description: 201 response - content: - application/json: - schema: - type: object - properties: - location: - type: object - properties: - id: - type: string - type: - type: string - target: - type: string - required: - - id - - type - - target - entities: - type: array - items: {} - required: - - location - - entities '400': $ref: '#/components/responses/ErrorResponse' default: @@ -1120,7 +1097,7 @@ paths: '200': description: Ok '400': - description: 400 response + description: Validation errors. content: application/json; charset=utf-8: schema: @@ -1138,6 +1115,7 @@ paths: required: - name - message + additionalProperties: {} required: - errors security: @@ -1155,7 +1133,7 @@ paths: type: string entity: type: object - additionalProperties: true + additionalProperties: {} required: - location - entity diff --git a/plugins/catalog-backend/src/service/createRouter.test.ts b/plugins/catalog-backend/src/service/createRouter.test.ts index 700e35edc1..05ebf6e1a9 100644 --- a/plugins/catalog-backend/src/service/createRouter.test.ts +++ b/plugins/catalog-backend/src/service/createRouter.test.ts @@ -198,6 +198,45 @@ describe('createRouter readonly disabled', () => { }); }); + it('parses encoded params request', async () => { + entitiesCatalog.queryEntities.mockResolvedValueOnce({ + items: [], + pageInfo: {}, + totalItems: 0, + }); + const response = await request(app).get( + `/entities/by-query?filter=${encodeURIComponent( + 'a=1,a=2,b=3', + )}&filter=c=4&orderField=${encodeURIComponent( + 'metadata.name,asc', + )}&orderField=metadata.uid,desc`, + ); + + expect(response.status).toEqual(200); + expect(entitiesCatalog.queryEntities).toHaveBeenCalledTimes(1); + expect(entitiesCatalog.queryEntities).toHaveBeenCalledWith({ + filter: { + anyOf: [ + { + allOf: [ + { key: 'a', values: ['1', '2'] }, + { key: 'b', values: ['3'] }, + ], + }, + { allOf: [{ key: 'c', values: ['4'] }] }, + ], + }, + orderFields: [ + { field: 'metadata.name', order: 'asc' }, + { field: 'metadata.uid', order: 'desc' }, + ], + fullTextFilter: { + fields: undefined, + term: '', + }, + }); + }); + it('parses cursor request', async () => { const items: Entity[] = [ { apiVersion: 'a', kind: 'b', metadata: { name: 'n' } }, diff --git a/yarn.lock b/yarn.lock index 10fa191082..f770ce192f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3454,6 +3454,7 @@ __metadata: "@backstage/errors": "workspace:^" cross-fetch: ^4.0.0 msw: ^1.0.0 + uri-template: ^2.0.0 languageName: unknown linkType: soft @@ -3588,6 +3589,7 @@ __metadata: eslint-plugin-jsx-a11y: ^6.5.1 eslint-plugin-react: ^7.28.0 eslint-plugin-react-hooks: ^4.3.0 + eslint-plugin-unused-imports: ^3.0.0 eslint-webpack-plugin: ^3.1.1 express: ^4.17.1 fork-ts-checker-webpack-plugin: ^7.0.0-alpha.8 @@ -9733,6 +9735,7 @@ __metadata: "@manypkg/get-packages": ^1.1.3 "@microsoft/api-documenter": ^7.22.33 "@microsoft/api-extractor": ^7.36.4 + "@openapitools/openapi-generator-cli": ^2.7.0 "@stoplight/spectral-core": ^1.18.0 "@stoplight/spectral-formatters": ^1.1.0 "@stoplight/spectral-functions": ^1.7.2 @@ -13773,7 +13776,7 @@ __metadata: languageName: node linkType: hard -"@openapitools/openapi-generator-cli@npm:^2.4.26": +"@openapitools/openapi-generator-cli@npm:^2.4.26, @openapitools/openapi-generator-cli@npm:^2.7.0": version: 2.7.0 resolution: "@openapitools/openapi-generator-cli@npm:2.7.0" dependencies: @@ -25759,6 +25762,28 @@ __metadata: languageName: node linkType: hard +"eslint-plugin-unused-imports@npm:^3.0.0": + version: 3.0.0 + resolution: "eslint-plugin-unused-imports@npm:3.0.0" + dependencies: + eslint-rule-composer: ^0.3.0 + peerDependencies: + "@typescript-eslint/eslint-plugin": ^6.0.0 + eslint: ^8.0.0 + peerDependenciesMeta: + "@typescript-eslint/eslint-plugin": + optional: true + checksum: 51666f62cc8dccba2895ced83f3c1e0b78b68c357e17360e156c4db548bfdeda34cbd8725192fb4903f22d5069400fb22ded6039631df01ee82fd618dc307247 + languageName: node + linkType: hard + +"eslint-rule-composer@npm:^0.3.0": + version: 0.3.0 + resolution: "eslint-rule-composer@npm:0.3.0" + checksum: c2f57cded8d1c8f82483e0ce28861214347e24fd79fd4144667974cd334d718f4ba05080aaef2399e3bbe36f7d6632865110227e6b176ed6daa2d676df9281b1 + languageName: node + linkType: hard + "eslint-scope@npm:5.1.1, eslint-scope@npm:^5.1.1": version: 5.1.1 resolution: "eslint-scope@npm:5.1.1" @@ -36282,6 +36307,13 @@ __metadata: languageName: node linkType: hard +"pct-encode@npm:~1.0.0": + version: 1.0.2 + resolution: "pct-encode@npm:1.0.2" + checksum: 11edce15c8a9012cf5fdee006a05f10e3668a755a15aa25b6afbb8cc20d67f600702eb83e5eaca7a98ee78f9b362fb7d9ada9745428dceb6cdc44e0143851509 + languageName: node + linkType: hard + "peek-readable@npm:^4.0.1": version: 4.0.1 resolution: "peek-readable@npm:4.0.1" @@ -43177,6 +43209,15 @@ __metadata: languageName: node linkType: hard +"uri-template@npm:^2.0.0": + version: 2.0.0 + resolution: "uri-template@npm:2.0.0" + dependencies: + pct-encode: ~1.0.0 + checksum: 6eb3254368ca11330502525c6c0ab42af3cb646bfc96a4021666d6ac6653ede1ac0df7fde84a2e35e7f03f42d91b41251963122cfb3de9b54b84bc0ef3583ffc + languageName: node + linkType: hard + "urijs@npm:^1.19.10, urijs@npm:^1.19.11": version: 1.19.11 resolution: "urijs@npm:1.19.11" @@ -44086,9 +44127,9 @@ __metadata: linkType: hard "whatwg-fetch@npm:>=0.10.0": - version: 3.6.2 - resolution: "whatwg-fetch@npm:3.6.2" - checksum: ee976b7249e7791edb0d0a62cd806b29006ad7ec3a3d89145921ad8c00a3a67e4be8f3fb3ec6bc7b58498724fd568d11aeeeea1f7827e7e1e5eae6c8a275afed + version: 3.6.19 + resolution: "whatwg-fetch@npm:3.6.19" + checksum: 2896bc9ca867ea514392c73e2a272f65d5c4916248fe0837a9df5b1b92f247047bc76cf7c29c28a01ac6c5fb4314021d2718958c8a08292a96d56f72b2f56806 languageName: node linkType: hard From 63dfae0e967c3f7bc2f7ce422b2715d2b010b217 Mon Sep 17 00:00:00 2001 From: Aramis Sennyey Date: Fri, 17 Nov 2023 14:34:59 -0500 Subject: [PATCH 022/261] fix types Signed-off-by: Aramis Sennyey --- packages/errors/src/errors/ResponseError.ts | 4 +--- packages/errors/src/errors/types.ts | 1 + packages/errors/src/serialization/response.ts | 13 +++++++------ 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/errors/src/errors/ResponseError.ts b/packages/errors/src/errors/ResponseError.ts index fa086561ed..0fff541218 100644 --- a/packages/errors/src/errors/ResponseError.ts +++ b/packages/errors/src/errors/ResponseError.ts @@ -77,9 +77,7 @@ export class ResponseError extends Error { const data = await parseErrorResponseBody( // TS isn't smart enough to know that this is done under the hood, - response as ConsumedResponse & { - bodyUsed: true; - }, + response, rawBody, ); diff --git a/packages/errors/src/errors/types.ts b/packages/errors/src/errors/types.ts index b0e86fd19a..b4b00f2707 100644 --- a/packages/errors/src/errors/types.ts +++ b/packages/errors/src/errors/types.ts @@ -34,6 +34,7 @@ export type ConsumedResponse = { values(): IterableIterator; [Symbol.iterator](): Iterator<[string, string]>; }; + readonly bodyUsed: boolean; readonly ok: boolean; readonly redirected: boolean; readonly status: number; diff --git a/packages/errors/src/serialization/response.ts b/packages/errors/src/serialization/response.ts index 522913be83..b956830278 100644 --- a/packages/errors/src/serialization/response.ts +++ b/packages/errors/src/serialization/response.ts @@ -54,20 +54,21 @@ export type ErrorResponseBody = { * @param response - The response of a failed request */ export async function parseErrorResponseBody( - response: ConsumedResponse & { bodyUsed: true }, + response: ConsumedResponse, rawBody: string, ): Promise; export async function parseErrorResponseBody( - response: ConsumedResponse & { text(): Promise; bodyUsed: false }, + response: ConsumedResponse & { text(): Promise }, ): Promise; export async function parseErrorResponseBody( - response: - | (ConsumedResponse & { bodyUsed: true }) - | (ConsumedResponse & { text(): Promise; bodyUsed: false }), + response: ConsumedResponse | (ConsumedResponse & { text(): Promise }), rawBody?: string, ): Promise { try { - const text = !response.bodyUsed ? await response.text() : rawBody; + const text = + !response.bodyUsed && 'text' in response + ? await response.text() + : rawBody; if (text) { if ( response.headers.get('content-type')?.startsWith('application/json') From ea2e5f8e551a2ebf14af81d2e1dff75d6a38703d Mon Sep 17 00:00:00 2001 From: Aramis Sennyey Date: Fri, 17 Nov 2023 14:45:48 -0500 Subject: [PATCH 023/261] fix api report Signed-off-by: Aramis Sennyey --- packages/errors/api-report.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/errors/api-report.md b/packages/errors/api-report.md index 3ece63035b..b62e7a2053 100644 --- a/packages/errors/api-report.md +++ b/packages/errors/api-report.md @@ -34,6 +34,7 @@ export type ConsumedResponse = { values(): IterableIterator; [Symbol.iterator](): Iterator<[string, string]>; }; + readonly bodyUsed: boolean; readonly ok: boolean; readonly redirected: boolean; readonly status: number; @@ -111,7 +112,15 @@ export class NotModifiedError extends CustomErrorBase { name: 'NotModifiedError'; } +// Warning: (ae-missing-release-tag) "parseErrorResponseBody" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public +export function parseErrorResponseBody( + response: ConsumedResponse, + rawBody: string, +): Promise; + +// @public (undocumented) export function parseErrorResponseBody( response: ConsumedResponse & { text(): Promise; @@ -125,8 +134,10 @@ export class ResponseError extends Error { static fromResponse( response: ConsumedResponse & { text(): Promise; + bodyUsed: boolean; }, ): Promise; + readonly rawBody: string; readonly response: ConsumedResponse; } From ffddac5a5669ae024beb611c751c2446ed1b9f3a Mon Sep 17 00:00:00 2001 From: Aramis Sennyey Date: Fri, 17 Nov 2023 14:56:09 -0500 Subject: [PATCH 024/261] fix warning in api report Signed-off-by: Aramis Sennyey --- packages/errors/api-report.md | 4 +--- packages/errors/src/serialization/response.ts | 17 +++++++++++++---- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/packages/errors/api-report.md b/packages/errors/api-report.md index b62e7a2053..42da6e28a6 100644 --- a/packages/errors/api-report.md +++ b/packages/errors/api-report.md @@ -112,15 +112,13 @@ export class NotModifiedError extends CustomErrorBase { name: 'NotModifiedError'; } -// Warning: (ae-missing-release-tag) "parseErrorResponseBody" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// // @public export function parseErrorResponseBody( response: ConsumedResponse, rawBody: string, ): Promise; -// @public (undocumented) +// @public export function parseErrorResponseBody( response: ConsumedResponse & { text(): Promise; diff --git a/packages/errors/src/serialization/response.ts b/packages/errors/src/serialization/response.ts index b956830278..c7d45465db 100644 --- a/packages/errors/src/serialization/response.ts +++ b/packages/errors/src/serialization/response.ts @@ -41,6 +41,19 @@ export type ErrorResponseBody = { }; }; +/** + * Attempts to construct an ErrorResponseBody out of a failed server request. + * Assumes that the response has already been checked to be not ok. This function + * expects that rawBody is the body of the response and will not attempt to + * parse the body from the response again. + * + * @public + * @param response - The response of a failed request + */ +export async function parseErrorResponseBody( + response: ConsumedResponse, + rawBody: string, +): Promise; /** * Attempts to construct an ErrorResponseBody out of a failed server request. * Assumes that the response has already been checked to be not ok. This @@ -53,10 +66,6 @@ export type ErrorResponseBody = { * @public * @param response - The response of a failed request */ -export async function parseErrorResponseBody( - response: ConsumedResponse, - rawBody: string, -): Promise; export async function parseErrorResponseBody( response: ConsumedResponse & { text(): Promise }, ): Promise; From 59709286b3ae2bfce40b92229e1a5e3cbf7d11d8 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Fri, 17 Nov 2023 13:04:26 +0100 Subject: [PATCH 025/261] frontend-*-api: add initial support for feature flags MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Camila Belo Co-authored-by: Fredrik Adelöw Co-authored-by: Vincenzo Scamporlino Co-authored-by: Philipp Hugenroth Signed-off-by: Patrik Oldsberg --- .changeset/gold-humans-tease.md | 5 +++ .changeset/green-seals-play.md | 5 +++ .../src/collectLegacyRoutes.test.tsx | 4 +- .../src/tree/resolveAppNodeSpecs.ts | 7 ++- .../frontend-app-api/src/wiring/createApp.tsx | 24 ++++++++++ packages/frontend-plugin-api/api-report.md | 21 ++++++--- .../wiring/createExtensionOverrides.test.ts | 2 + .../src/wiring/createExtensionOverrides.ts | 14 +++--- .../src/wiring/createPlugin.ts | 45 +++++++++++++++---- .../frontend-plugin-api/src/wiring/index.ts | 1 + .../frontend-plugin-api/src/wiring/types.ts | 25 +++++++++++ 11 files changed, 131 insertions(+), 22 deletions(-) create mode 100644 .changeset/gold-humans-tease.md create mode 100644 .changeset/green-seals-play.md create mode 100644 packages/frontend-plugin-api/src/wiring/types.ts diff --git a/.changeset/gold-humans-tease.md b/.changeset/gold-humans-tease.md new file mode 100644 index 0000000000..b3b40d0a7f --- /dev/null +++ b/.changeset/gold-humans-tease.md @@ -0,0 +1,5 @@ +--- +'@backstage/frontend-plugin-api': patch +--- + +Add feature flags to plugins and extension overrides. diff --git a/.changeset/green-seals-play.md b/.changeset/green-seals-play.md new file mode 100644 index 0000000000..5c5a31afcd --- /dev/null +++ b/.changeset/green-seals-play.md @@ -0,0 +1,5 @@ +--- +'@backstage/frontend-app-api': patch +--- + +Collect and register feature flags from plugins and extension overrides. diff --git a/packages/core-compat-api/src/collectLegacyRoutes.test.tsx b/packages/core-compat-api/src/collectLegacyRoutes.test.tsx index 85fed83e8c..d09911b39d 100644 --- a/packages/core-compat-api/src/collectLegacyRoutes.test.tsx +++ b/packages/core-compat-api/src/collectLegacyRoutes.test.tsx @@ -22,6 +22,8 @@ import React from 'react'; import { Route } from 'react-router-dom'; import { collectLegacyRoutes } from './collectLegacyRoutes'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { toInternalBackstagePlugin } from '../../frontend-plugin-api/src/wiring/createPlugin'; describe('collectLegacyRoutes', () => { it('should collect legacy routes', () => { @@ -37,7 +39,7 @@ describe('collectLegacyRoutes', () => { expect( collected.map(p => ({ id: p.id, - extensions: p.extensions.map(e => ({ + extensions: toInternalBackstagePlugin(p).extensions.map(e => ({ id: e.id, attachTo: e.attachTo, disabled: e.disabled, diff --git a/packages/frontend-app-api/src/tree/resolveAppNodeSpecs.ts b/packages/frontend-app-api/src/tree/resolveAppNodeSpecs.ts index 0a024c0a3f..34ec29b8f7 100644 --- a/packages/frontend-app-api/src/tree/resolveAppNodeSpecs.ts +++ b/packages/frontend-app-api/src/tree/resolveAppNodeSpecs.ts @@ -23,6 +23,8 @@ import { import { toInternalExtensionOverrides } from '../../../frontend-plugin-api/src/wiring/createExtensionOverrides'; import { ExtensionParameters } from './readAppExtensionsConfig'; import { AppNodeSpec } from '@backstage/frontend-plugin-api'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { toInternalBackstagePlugin } from '../../../frontend-plugin-api/src/wiring/createPlugin'; /** @internal */ export function resolveAppNodeSpecs(options: { @@ -42,7 +44,10 @@ export function resolveAppNodeSpecs(options: { ); const pluginExtensions = plugins.flatMap(source => { - return source.extensions.map(extension => ({ ...extension, source })); + return toInternalBackstagePlugin(source).extensions.map(extension => ({ + ...extension, + source, + })); }); const overrideExtensions = overrides.flatMap( override => toInternalExtensionOverrides(override).extensions, diff --git a/packages/frontend-app-api/src/wiring/createApp.tsx b/packages/frontend-app-api/src/wiring/createApp.tsx index 1858bd4884..a9400d3ba4 100644 --- a/packages/frontend-app-api/src/wiring/createApp.tsx +++ b/packages/frontend-app-api/src/wiring/createApp.tsx @@ -93,6 +93,10 @@ import { AppNode } from '@backstage/frontend-plugin-api'; import { toLegacyPlugin } from '../routing/toLegacyPlugin'; import { InternalAppContext } from './InternalAppContext'; import { CoreRouter } from '../extensions/CoreRouter'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { toInternalBackstagePlugin } from '../../../frontend-plugin-api/src/wiring/createPlugin'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { toInternalExtensionOverrides } from '../../../frontend-plugin-api/src/wiring/createExtensionOverrides'; const builtinExtensions = [ Core, @@ -304,6 +308,26 @@ export function createSpecializedApp(options?: { const appIdentityProxy = new AppIdentityProxy(); const apiHolder = createApiHolder(tree, config, appIdentityProxy); + + const featureFlagApi = apiHolder.get(featureFlagsApiRef); + if (featureFlagApi) { + for (const feature of features) { + if (feature.$$type === '@backstage/BackstagePlugin') { + toInternalBackstagePlugin(feature).featureFlags.forEach(flag => + featureFlagApi.registerFlag({ + name: flag.name, + pluginId: feature.id, + }), + ); + } + if (feature.$$type === '@backstage/ExtensionOverrides') { + toInternalExtensionOverrides(feature).featureFlags.forEach(flag => + featureFlagApi.registerFlag({ name: flag.name, pluginId: '' }), + ); + } + } + } + const routeInfo = extractRouteInfoFromAppNode(tree.root); const routeBindings = resolveRouteBindings( options?.bindRoutes, diff --git a/packages/frontend-plugin-api/api-report.md b/packages/frontend-plugin-api/api-report.md index 68aa34dff5..1b7731f95b 100644 --- a/packages/frontend-plugin-api/api-report.md +++ b/packages/frontend-plugin-api/api-report.md @@ -218,15 +218,13 @@ export interface BackstagePlugin< ExternalRoutes extends AnyExternalRoutes = AnyExternalRoutes, > { // (undocumented) - $$type: '@backstage/BackstagePlugin'; + readonly $$type: '@backstage/BackstagePlugin'; // (undocumented) - extensions: Extension[]; + readonly externalRoutes: ExternalRoutes; // (undocumented) - externalRoutes: ExternalRoutes; + readonly id: string; // (undocumented) - id: string; - // (undocumented) - routes: Routes; + readonly routes: Routes; } export { BackstageUserIdentity }; @@ -607,13 +605,15 @@ export type ExtensionInputValues< // @public (undocumented) export interface ExtensionOverrides { // (undocumented) - $$type: '@backstage/ExtensionOverrides'; + readonly $$type: '@backstage/ExtensionOverrides'; } // @public (undocumented) export interface ExtensionOverridesOptions { // (undocumented) extensions: Extension[]; + // (undocumented) + featureFlags?: FeatureFlagConfig[]; } // @public @@ -631,6 +631,11 @@ export interface ExternalRouteRef< export { FeatureFlag }; +// @public +export type FeatureFlagConfig = { + name: string; +}; + export { FeatureFlagsApi }; export { featureFlagsApiRef }; @@ -702,6 +707,8 @@ export interface PluginOptions< // (undocumented) externalRoutes?: ExternalRoutes; // (undocumented) + featureFlags?: FeatureFlagConfig[]; + // (undocumented) id: string; // (undocumented) routes?: Routes; diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionOverrides.test.ts b/packages/frontend-plugin-api/src/wiring/createExtensionOverrides.test.ts index eb69f954e4..90f878ceaa 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtensionOverrides.test.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtensionOverrides.test.ts @@ -26,6 +26,7 @@ describe('createExtensionOverrides', () => { { "$$type": "@backstage/ExtensionOverrides", "extensions": [], + "featureFlags": [], "version": "v1", } `); @@ -60,6 +61,7 @@ describe('createExtensionOverrides', () => { "output": {}, }, ], + "featureFlags": [], "version": "v1", } `); diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionOverrides.ts b/packages/frontend-plugin-api/src/wiring/createExtensionOverrides.ts index 2c64229eb9..3902654db7 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtensionOverrides.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtensionOverrides.ts @@ -15,21 +15,24 @@ */ import { Extension } from './createExtension'; +import { FeatureFlagConfig } from './types'; /** @public */ export interface ExtensionOverridesOptions { extensions: Extension[]; + featureFlags?: FeatureFlagConfig[]; } /** @public */ export interface ExtensionOverrides { - $$type: '@backstage/ExtensionOverrides'; + readonly $$type: '@backstage/ExtensionOverrides'; } /** @internal */ export interface InternalExtensionOverrides extends ExtensionOverrides { - version: string; - extensions: Extension[]; + readonly version: 'v1'; + readonly extensions: Extension[]; + readonly featureFlags: FeatureFlagConfig[]; } /** @public */ @@ -40,6 +43,7 @@ export function createExtensionOverrides( $$type: '@backstage/ExtensionOverrides', version: 'v1', extensions: options.extensions, + featureFlags: options.featureFlags ?? [], } as InternalExtensionOverrides; } @@ -50,12 +54,12 @@ export function toInternalExtensionOverrides( const internal = overrides as InternalExtensionOverrides; if (internal.$$type !== '@backstage/ExtensionOverrides') { throw new Error( - `Invalid translation resource, bad type '${internal.$$type}'`, + `Invalid extension overrides instance, bad type '${internal.$$type}'`, ); } if (internal.version !== 'v1') { throw new Error( - `Invalid translation resource, bad version '${internal.version}'`, + `Invalid extension overrides instance, bad version '${internal.version}'`, ); } return internal; diff --git a/packages/frontend-plugin-api/src/wiring/createPlugin.ts b/packages/frontend-plugin-api/src/wiring/createPlugin.ts index 84edd954ef..5e2a55ab88 100644 --- a/packages/frontend-plugin-api/src/wiring/createPlugin.ts +++ b/packages/frontend-plugin-api/src/wiring/createPlugin.ts @@ -16,6 +16,7 @@ import { Extension } from './createExtension'; import { ExternalRouteRef, RouteRef } from '../routing'; +import { FeatureFlagConfig } from './types'; /** @public */ export type AnyRoutes = { [name in string]: RouteRef }; @@ -32,6 +33,7 @@ export interface PluginOptions< routes?: Routes; externalRoutes?: ExternalRoutes; extensions?: Extension[]; + featureFlags?: FeatureFlagConfig[]; } /** @public */ @@ -39,11 +41,20 @@ export interface BackstagePlugin< Routes extends AnyRoutes = AnyRoutes, ExternalRoutes extends AnyExternalRoutes = AnyExternalRoutes, > { - $$type: '@backstage/BackstagePlugin'; - id: string; - extensions: Extension[]; - routes: Routes; - externalRoutes: ExternalRoutes; + readonly $$type: '@backstage/BackstagePlugin'; + readonly id: string; + readonly routes: Routes; + readonly externalRoutes: ExternalRoutes; +} + +/** @public */ +export interface InternalBackstagePlugin< + Routes extends AnyRoutes = AnyRoutes, + ExternalRoutes extends AnyExternalRoutes = AnyExternalRoutes, +> extends BackstagePlugin { + readonly version: 'v1'; + readonly extensions: Extension[]; + readonly featureFlags: FeatureFlagConfig[]; } /** @public */ @@ -54,10 +65,28 @@ export function createPlugin< options: PluginOptions, ): BackstagePlugin { return { - ...options, + $$type: '@backstage/BackstagePlugin', + version: 'v1', + id: options.id, routes: options.routes ?? ({} as Routes), externalRoutes: options.externalRoutes ?? ({} as ExternalRoutes), extensions: options.extensions ?? [], - $$type: '@backstage/BackstagePlugin', - }; + featureFlags: options.featureFlags ?? [], + } as InternalBackstagePlugin; +} + +/** @internal */ +export function toInternalBackstagePlugin( + plugin: BackstagePlugin, +): InternalBackstagePlugin { + const internal = plugin as InternalBackstagePlugin; + if (internal.$$type !== '@backstage/BackstagePlugin') { + throw new Error(`Invalid plugin instance, bad type '${internal.$$type}'`); + } + if (internal.version !== 'v1') { + throw new Error( + `Invalid plugin instance, bad version '${internal.version}'`, + ); + } + return internal; } diff --git a/packages/frontend-plugin-api/src/wiring/index.ts b/packages/frontend-plugin-api/src/wiring/index.ts index ec685d6c81..ace7c28076 100644 --- a/packages/frontend-plugin-api/src/wiring/index.ts +++ b/packages/frontend-plugin-api/src/wiring/index.ts @@ -45,3 +45,4 @@ export { type ExtensionOverrides, type ExtensionOverridesOptions, } from './createExtensionOverrides'; +export type { FeatureFlagConfig } from './types'; diff --git a/packages/frontend-plugin-api/src/wiring/types.ts b/packages/frontend-plugin-api/src/wiring/types.ts new file mode 100644 index 0000000000..ab9f07b35e --- /dev/null +++ b/packages/frontend-plugin-api/src/wiring/types.ts @@ -0,0 +1,25 @@ +/* + * 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. + */ + +/** + * Feature flag configuration. + * + * @public + */ +export type FeatureFlagConfig = { + /** Feature flag name */ + name: string; +}; From 393d3d77db446ddf853487914c228e808b295140 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Fri, 17 Nov 2023 13:20:50 +0100 Subject: [PATCH 026/261] frontend-app-api: add test for feature flag discovery Signed-off-by: Patrik Oldsberg --- .../src/wiring/createApp.test.tsx | 57 ++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/packages/frontend-app-api/src/wiring/createApp.test.tsx b/packages/frontend-app-api/src/wiring/createApp.test.tsx index 52186a5029..41d722a68e 100644 --- a/packages/frontend-app-api/src/wiring/createApp.test.tsx +++ b/packages/frontend-app-api/src/wiring/createApp.test.tsx @@ -17,6 +17,9 @@ import { AppTreeApi, appTreeApiRef, + coreExtensionData, + createExtension, + createExtensionOverrides, createPageExtension, createPlugin, createThemeExtension, @@ -25,7 +28,7 @@ import { screen, waitFor } from '@testing-library/react'; import { createApp } from './createApp'; import { MockConfigApi, renderWithEffects } from '@backstage/test-utils'; import React from 'react'; -import { useApi } from '@backstage/core-plugin-api'; +import { featureFlagsApiRef, useApi } from '@backstage/core-plugin-api'; describe('createApp', () => { it('should allow themes to be installed', async () => { @@ -94,6 +97,58 @@ describe('createApp', () => { ); }); + it('should register feature flags', async () => { + const app = createApp({ + configLoader: async () => new MockConfigApi({}), + features: [ + createPlugin({ + id: 'test', + featureFlags: [{ name: 'test-1' }], + extensions: [ + createExtension({ + id: 'test.page.first', + attachTo: { id: 'core', input: 'root' }, + output: { element: coreExtensionData.reactElement }, + factory() { + const Component = () => { + const flagsApi = useApi(featureFlagsApiRef); + return ( +
+ Flags:{' '} + {flagsApi + .getRegisteredFlags() + .map(flag => `${flag.name} from '${flag.pluginId}'`) + .join(', ')} +
+ ); + }; + return { element: }; + }, + }), + ], + }), + createExtensionOverrides({ + featureFlags: [{ name: 'test-2' }], + extensions: [ + createExtension({ + id: 'core.router', + attachTo: { id: 'core', input: 'root' }, + disabled: true, + output: {}, + factory: () => ({}), + }), + ], + }), + ], + }); + + await renderWithEffects(app.createRoot()); + + await expect( + screen.findByText("Flags: test-1 from 'test', test-2 from ''"), + ).resolves.toBeInTheDocument(); + }); + it('should make the app structure available through the AppTreeApi', async () => { let appTreeApi: AppTreeApi | undefined = undefined; From d3b4b632ddf2dea4c5081bfea3bdb56c469b5786 Mon Sep 17 00:00:00 2001 From: djamaile Date: Thu, 12 Oct 2023 15:05:03 +0200 Subject: [PATCH 027/261] chore: add oauth2 proxy provider backend module Signed-off-by: djamaile --- packages/backend/package.json | 1 + .../.eslintrc.js | 1 + .../README.md | 5 ++ .../package.json | 40 ++++++++++++ .../src/authenticator.ts | 62 +++++++++++++++++++ .../src/index.ts | 22 +++++++ .../src/module.ts | 49 +++++++++++++++ .../src/resolvers.ts | 41 ++++++++++++ plugins/auth-node/src/proxy/types.ts | 2 +- yarn.lock | 16 +++++ 10 files changed, 238 insertions(+), 1 deletion(-) create mode 100644 plugins/auth-backend-module-oauth2-proxy-provider/.eslintrc.js create mode 100644 plugins/auth-backend-module-oauth2-proxy-provider/README.md create mode 100644 plugins/auth-backend-module-oauth2-proxy-provider/package.json create mode 100644 plugins/auth-backend-module-oauth2-proxy-provider/src/authenticator.ts create mode 100644 plugins/auth-backend-module-oauth2-proxy-provider/src/index.ts create mode 100644 plugins/auth-backend-module-oauth2-proxy-provider/src/module.ts create mode 100644 plugins/auth-backend-module-oauth2-proxy-provider/src/resolvers.ts diff --git a/packages/backend/package.json b/packages/backend/package.json index e3b4fdb39d..ebfd5795fd 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -35,6 +35,7 @@ "@backstage/plugin-adr-backend": "workspace:^", "@backstage/plugin-app-backend": "workspace:^", "@backstage/plugin-auth-backend": "workspace:^", + "@backstage/plugin-auth-backend-module-oauth2-proxy-provider": "^0.0.0", "@backstage/plugin-auth-node": "workspace:^", "@backstage/plugin-azure-devops-backend": "workspace:^", "@backstage/plugin-azure-sites-backend": "workspace:^", diff --git a/plugins/auth-backend-module-oauth2-proxy-provider/.eslintrc.js b/plugins/auth-backend-module-oauth2-proxy-provider/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/auth-backend-module-oauth2-proxy-provider/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/auth-backend-module-oauth2-proxy-provider/README.md b/plugins/auth-backend-module-oauth2-proxy-provider/README.md new file mode 100644 index 0000000000..edec8fb3c2 --- /dev/null +++ b/plugins/auth-backend-module-oauth2-proxy-provider/README.md @@ -0,0 +1,5 @@ +# @backstage/plugin-auth-backend-module-oauth2-proxy-provider + +The oauth2-proxy-provider backend module for the auth plugin. + +_This plugin was created through the Backstage CLI_ diff --git a/plugins/auth-backend-module-oauth2-proxy-provider/package.json b/plugins/auth-backend-module-oauth2-proxy-provider/package.json new file mode 100644 index 0000000000..086de08222 --- /dev/null +++ b/plugins/auth-backend-module-oauth2-proxy-provider/package.json @@ -0,0 +1,40 @@ +{ + "name": "@backstage/plugin-auth-backend-module-oauth2-proxy-provider", + "description": "The oauth2-proxy-provider backend module for the auth plugin.", + "version": "0.0.0", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "publishConfig": { + "access": "public", + "main": "dist/index.cjs.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "backend-plugin-module" + }, + "scripts": { + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "clean": "backstage-cli package clean", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack" + }, + "dependencies": { + "@backstage/backend-common": "workspace:^", + "@backstage/backend-plugin-api": "workspace:^", + "@backstage/errors": "workspace:^", + "@backstage/plugin-auth-backend": "workspace:^", + "@backstage/plugin-auth-node": "workspace:^", + "jose": "^4.6.0" + }, + "devDependencies": { + "@backstage/backend-test-utils": "workspace:^", + "@backstage/cli": "workspace:^" + }, + "files": [ + "dist" + ] +} diff --git a/plugins/auth-backend-module-oauth2-proxy-provider/src/authenticator.ts b/plugins/auth-backend-module-oauth2-proxy-provider/src/authenticator.ts new file mode 100644 index 0000000000..3b94b6d404 --- /dev/null +++ b/plugins/auth-backend-module-oauth2-proxy-provider/src/authenticator.ts @@ -0,0 +1,62 @@ +/* + * 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 { AuthenticationError } from '@backstage/errors'; +import { OAuth2ProxyResult } from '@backstage/plugin-auth-backend'; +import { + createProxyAuthenticator, + getBearerTokenFromAuthorizationHeader, +} from '@backstage/plugin-auth-node'; +import { decodeJwt } from 'jose'; + +// NOTE: This may come in handy if you're doing work on this provider: +// plugins/auth-backend/examples/docker-compose.oauth2-proxy.yaml +export const OAUTH2_PROXY_JWT_HEADER = 'X-OAUTH2-PROXY-ID-TOKEN'; + +export const oauth2ProxyAuthenticator = createProxyAuthenticator({ + defaultProfileTransform: async (result: OAuth2ProxyResult) => { + return { + profile: { + email: result.getHeader('x-forwarded-email'), + displayName: + result.getHeader('x-forwarded-preferred-username') || + result.getHeader('x-forwarded-user'), + }, + }; + }, + async authenticate({ req }) { + try { + const authHeader = req.header(OAUTH2_PROXY_JWT_HEADER); + const jwt = getBearerTokenFromAuthorizationHeader(authHeader); + const decodedJWT = jwt && decodeJwt(jwt); + + const result = { + fullProfile: decodedJWT || {}, + accessToken: jwt || '', + headers: req.headers, + getHeader(name: string) { + if (name.toLocaleLowerCase('en-US') === 'set-cookie') { + throw new Error('Access Set-Cookie via the headers object instead'); + } + return req.get(name); + }, + }; + return { result }; + } catch (e) { + throw new AuthenticationError('Authentication failed', e); + } + }, +}); diff --git a/plugins/auth-backend-module-oauth2-proxy-provider/src/index.ts b/plugins/auth-backend-module-oauth2-proxy-provider/src/index.ts new file mode 100644 index 0000000000..93bb11ca1e --- /dev/null +++ b/plugins/auth-backend-module-oauth2-proxy-provider/src/index.ts @@ -0,0 +1,22 @@ +/* + * 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. + */ + +/** + * The oauth2-proxy-provider backend module for the auth plugin. + * + * @packageDocumentation + */ +export { authModuleOauth2ProxyProvider } from './module'; diff --git a/plugins/auth-backend-module-oauth2-proxy-provider/src/module.ts b/plugins/auth-backend-module-oauth2-proxy-provider/src/module.ts new file mode 100644 index 0000000000..0d9b9ae74f --- /dev/null +++ b/plugins/auth-backend-module-oauth2-proxy-provider/src/module.ts @@ -0,0 +1,49 @@ +/* + * 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 { createBackendModule } from '@backstage/backend-plugin-api'; +import { + authProvidersExtensionPoint, + createProxyAuthProviderFactory, + commonSignInResolvers, +} from '@backstage/plugin-auth-node'; +import { oauth2ProxyAuthenticator } from './authenticator'; +import { oauth2ProxySignInResolvers } from './resolvers'; + +/** @public */ +export const authModuleOauth2ProxyProvider = createBackendModule({ + pluginId: 'auth', + moduleId: 'oauth2ProxyProvider', + register(reg) { + reg.registerInit({ + deps: { + providers: authProvidersExtensionPoint, + }, + async init({ providers }) { + providers.registerProvider({ + providerId: 'oauth2ProxyProvider', + factory: createProxyAuthProviderFactory({ + authenticator: oauth2ProxyAuthenticator, + signInResolverFactories: { + ...commonSignInResolvers, + ...oauth2ProxySignInResolvers, + }, + }), + }); + }, + }); + }, +}); diff --git a/plugins/auth-backend-module-oauth2-proxy-provider/src/resolvers.ts b/plugins/auth-backend-module-oauth2-proxy-provider/src/resolvers.ts new file mode 100644 index 0000000000..dd8e7edc1e --- /dev/null +++ b/plugins/auth-backend-module-oauth2-proxy-provider/src/resolvers.ts @@ -0,0 +1,41 @@ +/* + * 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 { + createSignInResolverFactory, + SignInInfo, +} from '@backstage/plugin-auth-node'; +import { OAuth2ProxyResult } from '@backstage/plugin-auth-backend'; + +/** + * @public + */ +export namespace oauth2ProxySignInResolvers { + export const forwardedUserMarchingUserEntityName = + createSignInResolverFactory({ + create() { + return async (info: SignInInfo, ctx) => { + const name = info.result.getHeader('x-forwarded-user'); + if (!name) { + throw new Error('Request did not contain a user'); + } + return ctx.signInWithCatalogUser({ + entityRef: { name }, + }); + }; + }, + }); +} diff --git a/plugins/auth-node/src/proxy/types.ts b/plugins/auth-node/src/proxy/types.ts index 0f52feaac4..9c1bc78dfd 100644 --- a/plugins/auth-node/src/proxy/types.ts +++ b/plugins/auth-node/src/proxy/types.ts @@ -21,7 +21,7 @@ import { ProfileTransform } from '../types'; /** @public */ export interface ProxyAuthenticator { defaultProfileTransform: ProfileTransform; - initialize(ctx: { config: Config }): TContext; + initialize?(ctx: { config: Config }): TContext; authenticate( options: { req: Request }, ctx: TContext, diff --git a/yarn.lock b/yarn.lock index cd533fe68d..c52f6b7009 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4672,6 +4672,21 @@ __metadata: languageName: unknown linkType: soft +"@backstage/plugin-auth-backend-module-oauth2-proxy-provider@^0.0.0, @backstage/plugin-auth-backend-module-oauth2-proxy-provider@workspace:plugins/auth-backend-module-oauth2-proxy-provider": + version: 0.0.0-use.local + resolution: "@backstage/plugin-auth-backend-module-oauth2-proxy-provider@workspace:plugins/auth-backend-module-oauth2-proxy-provider" + dependencies: + "@backstage/backend-common": "workspace:^" + "@backstage/backend-plugin-api": "workspace:^" + "@backstage/backend-test-utils": "workspace:^" + "@backstage/cli": "workspace:^" + "@backstage/errors": "workspace:^" + "@backstage/plugin-auth-backend": "workspace:^" + "@backstage/plugin-auth-node": "workspace:^" + jose: ^4.6.0 + languageName: unknown + linkType: soft + "@backstage/plugin-auth-backend-module-okta-provider@workspace:^, @backstage/plugin-auth-backend-module-okta-provider@workspace:plugins/auth-backend-module-okta-provider": version: 0.0.0-use.local resolution: "@backstage/plugin-auth-backend-module-okta-provider@workspace:plugins/auth-backend-module-okta-provider" @@ -26327,6 +26342,7 @@ __metadata: "@backstage/plugin-adr-backend": "workspace:^" "@backstage/plugin-app-backend": "workspace:^" "@backstage/plugin-auth-backend": "workspace:^" + "@backstage/plugin-auth-backend-module-oauth2-proxy-provider": ^0.0.0 "@backstage/plugin-auth-node": "workspace:^" "@backstage/plugin-azure-devops-backend": "workspace:^" "@backstage/plugin-azure-sites-backend": "workspace:^" From 271aa12c7cc41e74c583f1d02a8fa3a3b3d6de01 Mon Sep 17 00:00:00 2001 From: djamaile Date: Thu, 19 Oct 2023 16:51:03 +0200 Subject: [PATCH 028/261] chore: add changeset Signed-off-by: djamaile --- .changeset/cool-knives-argue.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/cool-knives-argue.md diff --git a/.changeset/cool-knives-argue.md b/.changeset/cool-knives-argue.md new file mode 100644 index 0000000000..74890a0a9b --- /dev/null +++ b/.changeset/cool-knives-argue.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-auth-backend-module-oauth2-proxy-provider': minor +--- + +Release of `oauth2-proxy-provider` plugin From 2c5b9909cd9b86756b527968f4adbcdc98cc0ec7 Mon Sep 17 00:00:00 2001 From: djamaile Date: Thu, 19 Oct 2023 16:57:10 +0200 Subject: [PATCH 029/261] fix: dont make init optional Signed-off-by: djamaile --- .../src/authenticator.ts | 1 + plugins/auth-node/src/proxy/types.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/auth-backend-module-oauth2-proxy-provider/src/authenticator.ts b/plugins/auth-backend-module-oauth2-proxy-provider/src/authenticator.ts index 3b94b6d404..de12eb4d4c 100644 --- a/plugins/auth-backend-module-oauth2-proxy-provider/src/authenticator.ts +++ b/plugins/auth-backend-module-oauth2-proxy-provider/src/authenticator.ts @@ -37,6 +37,7 @@ export const oauth2ProxyAuthenticator = createProxyAuthenticator({ }, }; }, + async initialize() {}, async authenticate({ req }) { try { const authHeader = req.header(OAUTH2_PROXY_JWT_HEADER); diff --git a/plugins/auth-node/src/proxy/types.ts b/plugins/auth-node/src/proxy/types.ts index 9c1bc78dfd..0f52feaac4 100644 --- a/plugins/auth-node/src/proxy/types.ts +++ b/plugins/auth-node/src/proxy/types.ts @@ -21,7 +21,7 @@ import { ProfileTransform } from '../types'; /** @public */ export interface ProxyAuthenticator { defaultProfileTransform: ProfileTransform; - initialize?(ctx: { config: Config }): TContext; + initialize(ctx: { config: Config }): TContext; authenticate( options: { req: Request }, ctx: TContext, From 62cc3fbc2092c15c01e3cedb49d7e52a08bcdf9c Mon Sep 17 00:00:00 2001 From: djamaile Date: Fri, 20 Oct 2023 12:17:08 +0200 Subject: [PATCH 030/261] fix: run script Signed-off-by: djamaile --- packages/backend/package.json | 2 +- yarn.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/backend/package.json b/packages/backend/package.json index ebfd5795fd..e1e6184a77 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -35,7 +35,7 @@ "@backstage/plugin-adr-backend": "workspace:^", "@backstage/plugin-app-backend": "workspace:^", "@backstage/plugin-auth-backend": "workspace:^", - "@backstage/plugin-auth-backend-module-oauth2-proxy-provider": "^0.0.0", + "@backstage/plugin-auth-backend-module-oauth2-proxy-provider": "workspace:^", "@backstage/plugin-auth-node": "workspace:^", "@backstage/plugin-azure-devops-backend": "workspace:^", "@backstage/plugin-azure-sites-backend": "workspace:^", diff --git a/yarn.lock b/yarn.lock index c52f6b7009..e4a77e2388 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4672,7 +4672,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-auth-backend-module-oauth2-proxy-provider@^0.0.0, @backstage/plugin-auth-backend-module-oauth2-proxy-provider@workspace:plugins/auth-backend-module-oauth2-proxy-provider": +"@backstage/plugin-auth-backend-module-oauth2-proxy-provider@workspace:^, @backstage/plugin-auth-backend-module-oauth2-proxy-provider@workspace:plugins/auth-backend-module-oauth2-proxy-provider": version: 0.0.0-use.local resolution: "@backstage/plugin-auth-backend-module-oauth2-proxy-provider@workspace:plugins/auth-backend-module-oauth2-proxy-provider" dependencies: @@ -26342,7 +26342,7 @@ __metadata: "@backstage/plugin-adr-backend": "workspace:^" "@backstage/plugin-app-backend": "workspace:^" "@backstage/plugin-auth-backend": "workspace:^" - "@backstage/plugin-auth-backend-module-oauth2-proxy-provider": ^0.0.0 + "@backstage/plugin-auth-backend-module-oauth2-proxy-provider": "workspace:^" "@backstage/plugin-auth-node": "workspace:^" "@backstage/plugin-azure-devops-backend": "workspace:^" "@backstage/plugin-azure-sites-backend": "workspace:^" From eb3cddbec533096818d31edb5cde73116c10947f Mon Sep 17 00:00:00 2001 From: Djam Date: Mon, 20 Nov 2023 10:06:40 +0100 Subject: [PATCH 031/261] Update plugins/auth-backend-module-oauth2-proxy-provider/src/resolvers.ts Co-authored-by: Patrik Oldsberg Signed-off-by: Djam --- .../auth-backend-module-oauth2-proxy-provider/src/resolvers.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/auth-backend-module-oauth2-proxy-provider/src/resolvers.ts b/plugins/auth-backend-module-oauth2-proxy-provider/src/resolvers.ts index dd8e7edc1e..9b337fc80a 100644 --- a/plugins/auth-backend-module-oauth2-proxy-provider/src/resolvers.ts +++ b/plugins/auth-backend-module-oauth2-proxy-provider/src/resolvers.ts @@ -24,7 +24,7 @@ import { OAuth2ProxyResult } from '@backstage/plugin-auth-backend'; * @public */ export namespace oauth2ProxySignInResolvers { - export const forwardedUserMarchingUserEntityName = + export const forwardedUserMatchingUserEntityName = createSignInResolverFactory({ create() { return async (info: SignInInfo, ctx) => { From 07e668952d06679cad39a21fa782aea026cea581 Mon Sep 17 00:00:00 2001 From: Philipp Hugenroth Date: Mon, 20 Nov 2023 11:16:31 +0100 Subject: [PATCH 032/261] Add guide to sidebar Signed-off-by: Philipp Hugenroth --- mkdocs.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/mkdocs.yml b/mkdocs.yml index de66c97884..d4735c63fc 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -193,6 +193,7 @@ nav: - Switching Backstage from SQLite to PostgreSQL: 'tutorials/switching-sqlite-postgres.md' - Using the Backstage Proxy from Within a Plugin: 'tutorials/using-backstage-proxy-within-plugin.md' - Migration to Yarn 3: 'tutorials/yarn-migration.md' + - Migration to Material UI v5: 'tutorials/migrate-to-mui5.md' - Architecture Decision Records (ADRs): - Overview: 'architecture-decisions/index.md' - ADR001 - Architecture Decision Record (ADR) log: 'architecture-decisions/adr001-add-adr-log.md' From 5c269df42496039555dfc30040697f8dba4f59ae Mon Sep 17 00:00:00 2001 From: hainenber Date: Sun, 19 Nov 2023 16:32:27 +0700 Subject: [PATCH 033/261] feat(pkg/techdocs-cli): support passing additional mkdocs-server CLI parameters when run in containerized mode Signed-off-by: hainenber --- packages/techdocs-cli/src/commands/serve/serve.ts | 2 ++ .../techdocs-cli/src/lib/mkdocsServer.test.ts | 15 +++++++++++++++ packages/techdocs-cli/src/lib/mkdocsServer.ts | 3 +++ 3 files changed, 20 insertions(+) diff --git a/packages/techdocs-cli/src/commands/serve/serve.ts b/packages/techdocs-cli/src/commands/serve/serve.ts index 98c9982b21..04a8cff2f6 100644 --- a/packages/techdocs-cli/src/commands/serve/serve.ts +++ b/packages/techdocs-cli/src/commands/serve/serve.ts @@ -67,6 +67,7 @@ export default async function serve(opts: OptionValues) { ? mkdocsDockerAddr : mkdocsLocalAddr; const mkdocsConfigFileName = opts.mkdocsConfigFileName; + const mkdocsConfigs = opts.mkdocsConfig.split(' '); const siteName = opts.siteName; const { path: mkdocsYmlPath, configIsTemporary } = await getMkdocsYml('./', { @@ -116,6 +117,7 @@ export default async function serve(opts: OptionValues) { stdoutLogFunc: mkdocsLogFunc, stderrLogFunc: mkdocsLogFunc, mkdocsConfigFileName: mkdocsYmlPath, + mkdocsConfigs: mkdocsConfigs, }); // Wait until mkdocs server has started so that Backstage starts with docs loaded diff --git a/packages/techdocs-cli/src/lib/mkdocsServer.test.ts b/packages/techdocs-cli/src/lib/mkdocsServer.test.ts index 8484c4e242..73203a69e9 100644 --- a/packages/techdocs-cli/src/lib/mkdocsServer.test.ts +++ b/packages/techdocs-cli/src/lib/mkdocsServer.test.ts @@ -97,6 +97,21 @@ describe('runMkdocsServer', () => { expect.objectContaining({}), ); }); + + it('should accept additinoal mkdocs CLI parameters', async () => { + await runMkdocsServer({ mkdocsConfigs: ['--clean', '--strict'] }); + expect(run).toHaveBeenCalledWith( + 'docker', + expect.arrayContaining([ + 'serve', + '--dev-addr', + '0.0.0.0:8000', + '--clean', + '--strict', + ]), + expect.objectContaining({}), + ); + }); }); describe('mkdocs', () => { diff --git a/packages/techdocs-cli/src/lib/mkdocsServer.ts b/packages/techdocs-cli/src/lib/mkdocsServer.ts index 42409acb46..ff412bd87f 100644 --- a/packages/techdocs-cli/src/lib/mkdocsServer.ts +++ b/packages/techdocs-cli/src/lib/mkdocsServer.ts @@ -26,6 +26,7 @@ export const runMkdocsServer = async (options: { stdoutLogFunc?: LogFunc; stderrLogFunc?: LogFunc; mkdocsConfigFileName?: string; + mkdocsConfigs?: string[]; }): Promise => { const port = options.port ?? '8000'; const useDocker = options.useDocker ?? true; @@ -55,6 +56,7 @@ export const runMkdocsServer = async (options: { ...(options.mkdocsConfigFileName ? ['--config-file', options.mkdocsConfigFileName] : []), + ...(options.mkdocsConfigs ?? []), ], { stdoutLogFunc: options.stdoutLogFunc, @@ -72,6 +74,7 @@ export const runMkdocsServer = async (options: { ...(options.mkdocsConfigFileName ? ['--config-file', options.mkdocsConfigFileName] : []), + ...(options.mkdocsConfigs ?? []), ], { stdoutLogFunc: options.stdoutLogFunc, From b2dccad7b3dd9cbb20fc2635a973e302954902d8 Mon Sep 17 00:00:00 2001 From: hainenber Date: Sun, 19 Nov 2023 16:33:27 +0700 Subject: [PATCH 034/261] chore: add changeset Signed-off-by: hainenber --- .changeset/tricky-donkeys-do.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/tricky-donkeys-do.md diff --git a/.changeset/tricky-donkeys-do.md b/.changeset/tricky-donkeys-do.md new file mode 100644 index 0000000000..8859f012ba --- /dev/null +++ b/.changeset/tricky-donkeys-do.md @@ -0,0 +1,5 @@ +--- +'@techdocs/cli': minor +--- + +support passing additional mkdocs-server CLI parameters when run in containerized mode From 549ca5e3c4e50fa6f81155d12125d26cd9e91cc7 Mon Sep 17 00:00:00 2001 From: hainenber Date: Sun, 19 Nov 2023 16:40:45 +0700 Subject: [PATCH 035/261] fix(pkg/techdocs-cli): specify new opt Signed-off-by: hainenber --- docs/features/techdocs/cli.md | 1 + packages/techdocs-cli/src/commands/index.ts | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/docs/features/techdocs/cli.md b/docs/features/techdocs/cli.md index 9704b9b21b..6a2407372f 100644 --- a/docs/features/techdocs/cli.md +++ b/docs/features/techdocs/cli.md @@ -91,6 +91,7 @@ Options: --docker-option Extra options to pass to the docker run command, e.g. "--add-host=internal.host:192.168.11.12" (can be added multiple times). --no-docker Do not use Docker, use MkDocs executable in current user environment. + --mkdocs-configs Extra mkdocs server to pass to mkdocs running in containerized environment. --mkdocs-port Port for MkDocs server to use (default: "8000") --preview-app-bundle-path Preview documentation using a web app other than the included one. --preview-app-port Port where the preview will be served. diff --git a/packages/techdocs-cli/src/commands/index.ts b/packages/techdocs-cli/src/commands/index.ts index 10a00da513..3052575366 100644 --- a/packages/techdocs-cli/src/commands/index.ts +++ b/packages/techdocs-cli/src/commands/index.ts @@ -289,6 +289,10 @@ export function registerCommands(program: Command) { '-c, --mkdocs-config-file-name ', 'Mkdocs config file name', ) + .option( + '--mkdocs-configs', + 'Additional parameters to pass to containerized mkdocs', + ) .hook('preAction', command => { if ( command.opts().previewAppPort !== defaultPreviewAppPort && From e75937670cef4b0ded7ea37533d8fa9f56e63f81 Mon Sep 17 00:00:00 2001 From: Philipp Hugenroth Date: Mon, 20 Nov 2023 15:30:32 +0100 Subject: [PATCH 036/261] always forget this one Signed-off-by: Philipp Hugenroth --- microsite/sidebars.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/microsite/sidebars.json b/microsite/sidebars.json index c9b1c99eba..c33bf37785 100644 --- a/microsite/sidebars.json +++ b/microsite/sidebars.json @@ -408,7 +408,8 @@ "tutorials/configuring-plugin-databases", "tutorials/switching-sqlite-postgres", "tutorials/using-backstage-proxy-within-plugin", - "tutorials/yarn-migration" + "tutorials/yarn-migration", + "tutorials/migrate-to-mui5.md" ], "Architecture Decision Records (ADRs)": [ "architecture-decisions/adrs-overview", From 69b2f7bf3bb9f437c3c71b4d40f4d81149462eb4 Mon Sep 17 00:00:00 2001 From: hainenber Date: Mon, 20 Nov 2023 21:46:41 +0700 Subject: [PATCH 037/261] fix(techdocs-cli): limit supported mkdocs flags Signed-off-by: hainenber --- docs/features/techdocs/cli.md | 4 +++- packages/techdocs-cli/cli-report.md | 3 +++ packages/techdocs-cli/src/commands/index.ts | 15 +++++++++++++-- packages/techdocs-cli/src/commands/serve/serve.ts | 5 +++-- .../techdocs-cli/src/lib/mkdocsServer.test.ts | 5 ++++- packages/techdocs-cli/src/lib/mkdocsServer.ts | 12 +++++++++--- 6 files changed, 35 insertions(+), 9 deletions(-) diff --git a/docs/features/techdocs/cli.md b/docs/features/techdocs/cli.md index 6a2407372f..e7b3aff057 100644 --- a/docs/features/techdocs/cli.md +++ b/docs/features/techdocs/cli.md @@ -91,7 +91,9 @@ Options: --docker-option Extra options to pass to the docker run command, e.g. "--add-host=internal.host:192.168.11.12" (can be added multiple times). --no-docker Do not use Docker, use MkDocs executable in current user environment. - --mkdocs-configs Extra mkdocs server to pass to mkdocs running in containerized environment. + --mkdocs-parameter-clean Pass "--clean" parameter to mkdocs server running in containerized environment. + --mkdocs-parameter-dirty Pass "--dirty" parameter to mkdocs server running in containerized environment. + --mkdocs-parameter-strict Pass "--strict" parameter to mkdocs server running in containerized environment. --mkdocs-port Port for MkDocs server to use (default: "8000") --preview-app-bundle-path Preview documentation using a web app other than the included one. --preview-app-port Port where the preview will be served. diff --git a/packages/techdocs-cli/cli-report.md b/packages/techdocs-cli/cli-report.md index 890718b0d2..9c155473ef 100644 --- a/packages/techdocs-cli/cli-report.md +++ b/packages/techdocs-cli/cli-report.md @@ -107,6 +107,9 @@ Options: --preview-app-bundle-path --preview-app-port -c, --mkdocs-config-file-name + --mkdocs-parameter-clean + --mkdocs-parameter-dirty + --mkdocs-parameter-strict -h, --help ``` diff --git a/packages/techdocs-cli/src/commands/index.ts b/packages/techdocs-cli/src/commands/index.ts index 3052575366..2d5ff98e77 100644 --- a/packages/techdocs-cli/src/commands/index.ts +++ b/packages/techdocs-cli/src/commands/index.ts @@ -290,8 +290,19 @@ export function registerCommands(program: Command) { 'Mkdocs config file name', ) .option( - '--mkdocs-configs', - 'Additional parameters to pass to containerized mkdocs', + '--mkdocs-parameter-clean', + 'Pass "--clean" parameter to mkdocs server running in containerized environment', + false, + ) + .option( + '--mkdocs-parameter-dirty', + 'Pass "--dirty" parameter to mkdocs server running in containerized environment', + false, + ) + .option( + '--mkdocs-parameter-strict', + 'Pass "--strict" parameter to mkdocs server running in containerized environment', + false, ) .hook('preAction', command => { if ( diff --git a/packages/techdocs-cli/src/commands/serve/serve.ts b/packages/techdocs-cli/src/commands/serve/serve.ts index 04a8cff2f6..47cfbe8a22 100644 --- a/packages/techdocs-cli/src/commands/serve/serve.ts +++ b/packages/techdocs-cli/src/commands/serve/serve.ts @@ -67,7 +67,6 @@ export default async function serve(opts: OptionValues) { ? mkdocsDockerAddr : mkdocsLocalAddr; const mkdocsConfigFileName = opts.mkdocsConfigFileName; - const mkdocsConfigs = opts.mkdocsConfig.split(' '); const siteName = opts.siteName; const { path: mkdocsYmlPath, configIsTemporary } = await getMkdocsYml('./', { @@ -117,7 +116,9 @@ export default async function serve(opts: OptionValues) { stdoutLogFunc: mkdocsLogFunc, stderrLogFunc: mkdocsLogFunc, mkdocsConfigFileName: mkdocsYmlPath, - mkdocsConfigs: mkdocsConfigs, + mkdocsParameterClean: opts.mkdocsParameterClean, + mkdocsParameterDirty: opts.mkdocsParameterDirty, + mkdocsParameterStrict: opts.mkdocsParameterStrict, }); // Wait until mkdocs server has started so that Backstage starts with docs loaded diff --git a/packages/techdocs-cli/src/lib/mkdocsServer.test.ts b/packages/techdocs-cli/src/lib/mkdocsServer.test.ts index 73203a69e9..83f9c9f382 100644 --- a/packages/techdocs-cli/src/lib/mkdocsServer.test.ts +++ b/packages/techdocs-cli/src/lib/mkdocsServer.test.ts @@ -99,7 +99,10 @@ describe('runMkdocsServer', () => { }); it('should accept additinoal mkdocs CLI parameters', async () => { - await runMkdocsServer({ mkdocsConfigs: ['--clean', '--strict'] }); + await runMkdocsServer({ + mkdocsParameterClean: true, + mkdocsParameterStrict: true, + }); expect(run).toHaveBeenCalledWith( 'docker', expect.arrayContaining([ diff --git a/packages/techdocs-cli/src/lib/mkdocsServer.ts b/packages/techdocs-cli/src/lib/mkdocsServer.ts index ff412bd87f..dced19cb7a 100644 --- a/packages/techdocs-cli/src/lib/mkdocsServer.ts +++ b/packages/techdocs-cli/src/lib/mkdocsServer.ts @@ -26,7 +26,9 @@ export const runMkdocsServer = async (options: { stdoutLogFunc?: LogFunc; stderrLogFunc?: LogFunc; mkdocsConfigFileName?: string; - mkdocsConfigs?: string[]; + mkdocsParameterClean?: boolean; + mkdocsParameterDirty?: boolean; + mkdocsParameterStrict?: boolean; }): Promise => { const port = options.port ?? '8000'; const useDocker = options.useDocker ?? true; @@ -56,7 +58,9 @@ export const runMkdocsServer = async (options: { ...(options.mkdocsConfigFileName ? ['--config-file', options.mkdocsConfigFileName] : []), - ...(options.mkdocsConfigs ?? []), + ...(options.mkdocsParameterClean ? '--clean' : []), + ...(options.mkdocsParameterDirty ? '--dirty' : []), + ...(options.mkdocsParameterStrict ? '--strict' : []), ], { stdoutLogFunc: options.stdoutLogFunc, @@ -74,7 +78,9 @@ export const runMkdocsServer = async (options: { ...(options.mkdocsConfigFileName ? ['--config-file', options.mkdocsConfigFileName] : []), - ...(options.mkdocsConfigs ?? []), + ...(options.mkdocsParameterClean ? '--clean' : []), + ...(options.mkdocsParameterDirty ? '--dirty' : []), + ...(options.mkdocsParameterStrict ? '--strict' : []), ], { stdoutLogFunc: options.stdoutLogFunc, From 5fca16fdf6054a4e996f9924f42f275dafe66bb0 Mon Sep 17 00:00:00 2001 From: Tiago Barbosa Date: Mon, 20 Nov 2023 16:35:39 +0000 Subject: [PATCH 038/261] refactor(pagerduty plugin): :wastebasket: deprecate PagerDuty plugin maintained by Backstage deprecate PagerDuty plugin maintained by Backstage and redirect to the one maintained by PagerDuty Signed-off-by: Tiago Barbosa --- .changeset/tame-pants-end.md | 5 + plugins/pagerduty/README.md | 216 +-------------------------------- plugins/pagerduty/package.json | 2 +- 3 files changed, 7 insertions(+), 216 deletions(-) create mode 100644 .changeset/tame-pants-end.md diff --git a/.changeset/tame-pants-end.md b/.changeset/tame-pants-end.md new file mode 100644 index 0000000000..b80fcb7fe3 --- /dev/null +++ b/.changeset/tame-pants-end.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-pagerduty': minor +--- + +This package has been deprecated, consider using [@pagerduty/backstage-plugin](https://github.com/pagerduty/backstage-plugin) instead. diff --git a/plugins/pagerduty/README.md b/plugins/pagerduty/README.md index bf748439c9..c1079004e3 100644 --- a/plugins/pagerduty/README.md +++ b/plugins/pagerduty/README.md @@ -1,217 +1,3 @@ # PagerDuty + Backstage Integration Benefits -- Display relevant PagerDuty information about an entity within Backstage, such as the escalation policy, if there are any active incidents, and recent changes -- Trigger an incident to the currently on-call responder(s) for a service - -## How it Works - -- The Backstage PagerDuty plugin allows PagerDuty information about a Backstage entity to be displayed within Backstage. This includes active incidents, recent change events, as well as the current on-call responders' names, email addresses, and links to their profiles in PagerDuty. -- Incidents can be manually triggered via the plugin with a user-provided description, which will in turn notify the current on-call responders (Alternatively, the plugin can be configured with an optional `readOnly` property to suppress the ability to trigger incidents from the plugin). - - _Note: This feature is only available when providing the `pagerduty.com/integration-key` annotation_ -- Change events will be displayed in a separate tab. If the change event payload has additional links the first link only will be rendered. - -## Requirements - -- Setup of the PagerDuty plugin for Backstage requires a PagerDuty Admin role in order to generate the necessary authorizations, such as the API token. If you do not have this role, please reach out to an Admin or Account Owner within your organization to request configuration of this plugin. - -## Feature Overview - -### View any open incidents - -![PagerDuty plugin showing no incidents and the on-call rotation](doc/pd1.png) - -### Email link, and view contact information for staff on call - -![PagerDuty plugin showing on-call rotation contact information](doc/pd2.png) - -### Trigger an incident for a service - -![PagerDuty plugin popup modal for creating an incident](doc/pd3.png) - -![PagerDuty plugin showing an active incident](doc/pd4.png) - -## Support - -If you need help with this plugin, please reach out on the [Backstage Discord server](https://discord.gg/backstage-687207715902193673). - -## Integration Walk-through - -### In PagerDuty - -#### Integrating With a PagerDuty Service - -1. From the **Configuration** menu, select **Services**. -2. There are two ways to add an integration to a service: - - **If you are adding your integration to an existing service**: Click the **name** of the service you want to add the integration to. Then, select the **Integrations** tab and click the **New Integration** button. - - **If you are creating a new service for your integration**: Please read the documentation in section [Configuring Services and Integrations](https://support.pagerduty.com/docs/services-and-integrations#section-configuring-services-and-integrations) and follow the steps outlined in the [Create a New Service](https://support.pagerduty.com/docs/services-and-integrations#section-create-a-new-service) section, selecting **Backstage** as the **Integration Type** in step 4. Continue with the **In Backstage** section (below) once you have finished these steps. -3. Enter an **Integration Name** in the format `monitoring-tool-service-name` (e.g. `Backstage-Shopping-Cart`) and select **Backstage** from the Integration Type menu. -4. Click the **Add Integration** button to save your new integration. You will be redirected to the Integrations tab for your service. -5. An **Integration Key** will be generated on this screen. Keep this key saved in a safe place, as it will be used when you configure the integration with **Backstage** in the next section. - ![](https://pdpartner.s3.amazonaws.com/ig-template-copy-integration-key.png) - -### In Backstage - -#### Install the plugin - -The file paths mentioned in the following steps are relative to your app's root directory — for example, the directory created by following the [Getting Started](https://backstage.io/docs/getting-started/) guide and creating your app with `npx @backstage/create-app`. - -First, install the PagerDuty plugin via a CLI: - -```bash -# From your Backstage root directory -yarn add --cwd packages/app @backstage/plugin-pagerduty -``` - -Next, add the plugin to `EntityPage.tsx` in `packages/app/src/components/catalog` by adding the following code snippets. - -Add the following imports to the top of the file: - -```ts -import { - isPluginApplicableToEntity as isPagerDutyAvailable, - EntityPagerDutyCard, -} from '@backstage/plugin-pagerduty'; -``` - -Find `const overviewContent` in `EntityPage.tsx`, and add the following snippet inside the outermost `Grid` defined there, just before the closing `` tag: - -```ts - - - - - - - -``` - -When you're done, the `overviewContent` definition should look something like this: - -```ts -const overviewContent = ( - - ... - - - - - - - - -); -``` - -#### Configure the plugin - -First, [annotate](https://backstage.io/docs/features/software-catalog/descriptor-format#annotations-optional) the appropriate entity with the PagerDuty integration key in its `.yaml` configuration file: - -```yaml -annotations: - pagerduty.com/integration-key: [INTEGRATION_KEY] -``` - -#### The homepage component - -You may also add the component to the homepage of Backstage. Edit the `HomePage.tsx` file, import `PagerDutyHomepageCard` and add it to the home page. e.g. - -```typescript jsx -... -export const homePage = ( - - ... - - - ... - - - - -); -``` - -Next, provide the [API token](https://support.pagerduty.com/docs/generating-api-keys#generating-a-general-access-rest-api-key) that the client will use to make requests to the [PagerDuty API](https://developer.pagerduty.com/docs/rest-api-v2/rest-api/). - -Add the proxy configuration in `app-config.yaml`: - -```yaml -proxy: - ... - '/pagerduty': - target: https://api.pagerduty.com - headers: - Authorization: Token token=${PAGERDUTY_TOKEN} -``` - -Then, start the backend, passing the PagerDuty API token as an environment variable: - -```bash -$ PAGERDUTY_TOKEN='' yarn start -``` - -This will proxy the request by adding an `Authorization` header with the provided token. - -#### Optional configuration - -##### Annotating with Service ID - -If you want to integrate a PagerDuty service with Backstage but don't want to use an integration key, you can also [annotate](https://backstage.io/docs/features/software-catalog/descriptor-format#annotations-optional) the appropriate entity with a PagerDuty Service ID instead - -```yaml -annotations: - pagerduty.com/service-id: [SERVICE_ID] -``` - -This service ID can be found by navigating to a Service within PagerDuty and pulling the ID value out of the URL. - -1. From the **Configuration** menu within PagerDuty, select **Services**. -2. Click the **name** of the service you want to represent for your Entity. - -Your browser URL should now be located at `https://pagerduty.com/service-directory/[SERVICE_ID]`. - -_Note: When annotating with `pagerduty.com/service-id`, the feature to Create Incidents is not currently supported_ - -##### Custom Events URL - -If you want to override the default URL used for events, you can add it to `app-config.yaml`: - -```yaml -pagerDuty: - eventsBaseUrl: 'https://events.pagerduty.com/v2' -``` - -To suppress the rendering of the actionable incident-creation button, the `PagerDutyCard` can also be instantiated in `readOnly` mode: - -```ts - -``` - -**WARNING**: In current implementation, the PagerDuty plugin requires the `/pagerduty` proxy endpoint be exposed by the Backstage backend as an unprotected endpoint, in effect enabling PagerDuty API access using the configured `PAGERDUTY_TOKEN` for any user or process with access to the `/pagerduty` Backstage backend endpoint. If you regard this as problematic, consider using the plugin in `readOnly` mode (``) using the following proxy configuration: - -```yaml -proxy: - '/pagerduty': - target: https://api.pagerduty.com - headers: - Authorization: Token token=${PAGERDUTY_TOKEN} - # prohibit the `/pagerduty` proxy endpoint from servicing non-GET requests - allowedMethods: ['GET'] -``` - -## How to Uninstall - -1. Remove any configuration added in Backstage yaml files, such as the proxy configuration in `app-config.yaml` and the integration key in an entity's annotations. -2. Remove the added code snippets from `EntityPage.tsx` -3. Remove the plugin package: - -```bash -# From your Backstage root directory -yarn remove --cwd packages/app @backstage/plugin-pagerduty -``` - -4. [Delete the integration](https://support.pagerduty.com/docs/services-and-integrations#delete-an-integration-from-a-service) from the service in PagerDuty +This package has been deprecated, consider using [@pagerduty/backstage-plugin](https://github.com/pagerduty/backstage-plugin) instead. diff --git a/plugins/pagerduty/package.json b/plugins/pagerduty/package.json index e56e4d2d8d..04326b2ec3 100644 --- a/plugins/pagerduty/package.json +++ b/plugins/pagerduty/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-pagerduty", - "description": "A Backstage plugin that integrates towards PagerDuty", + "description": "This package has been deprecated, consider using [@pagerduty/backstage-plugin](https://github.com/pagerduty/backstage-plugin) instead.", "version": "0.6.7", "main": "src/index.ts", "types": "src/index.ts", From cea6e2ce66489746aae8f9a1e6891095bee9609c Mon Sep 17 00:00:00 2001 From: Tiago Barbosa Date: Mon, 20 Nov 2023 16:47:57 +0000 Subject: [PATCH 039/261] refactor(pagerduty plugin): :recycle: update example apps with the new package update example apps with the new package Signed-off-by: Tiago Barbosa --- packages/app-next/package.json | 2 +- packages/app-next/src/HomePage.tsx | 2 +- packages/app/package.json | 2 +- packages/app/src/components/catalog/EntityPage.tsx | 2 +- packages/app/src/components/home/HomePage.tsx | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/app-next/package.json b/packages/app-next/package.json index 6e0581d034..78e15a9ad0 100644 --- a/packages/app-next/package.json +++ b/packages/app-next/package.json @@ -56,7 +56,6 @@ "@backstage/plugin-newrelic-dashboard": "workspace:^", "@backstage/plugin-octopus-deploy": "workspace:^", "@backstage/plugin-org": "workspace:^", - "@backstage/plugin-pagerduty": "workspace:^", "@backstage/plugin-permission-react": "workspace:^", "@backstage/plugin-playlist": "workspace:^", "@backstage/plugin-puppetdb": "workspace:^", @@ -82,6 +81,7 @@ "@material-ui/lab": "4.0.0-alpha.61", "@octokit/rest": "^19.0.3", "@oriflame/backstage-plugin-score-card": "^0.7.0", + "@pagerduty/backstage-plugin": "^0.7.1", "@roadiehq/backstage-plugin-buildkite": "^2.0.8", "@roadiehq/backstage-plugin-github-insights": "^2.0.5", "@roadiehq/backstage-plugin-github-pull-requests": "^2.2.7", diff --git a/packages/app-next/src/HomePage.tsx b/packages/app-next/src/HomePage.tsx index cb31beb34a..8850e27190 100644 --- a/packages/app-next/src/HomePage.tsx +++ b/packages/app-next/src/HomePage.tsx @@ -31,7 +31,7 @@ import { HomePageCalendar } from '@backstage/plugin-gcalendar'; import { MicrosoftCalendarCard } from '@backstage/plugin-microsoft-calendar'; import React from 'react'; import HomeIcon from '@material-ui/icons/Home'; -import { HomePagePagerDutyCard } from '@backstage/plugin-pagerduty'; +import { HomePagePagerDutyCard } from '@pagerduty/backstage-plugin'; const clockConfigs: ClockConfig[] = [ { diff --git a/packages/app/package.json b/packages/app/package.json index 245b645ddc..e647e166c4 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -62,7 +62,6 @@ "@backstage/plugin-nomad": "workspace:^", "@backstage/plugin-octopus-deploy": "workspace:^", "@backstage/plugin-org": "workspace:^", - "@backstage/plugin-pagerduty": "workspace:^", "@backstage/plugin-permission-react": "workspace:^", "@backstage/plugin-playlist": "workspace:^", "@backstage/plugin-puppetdb": "workspace:^", @@ -89,6 +88,7 @@ "@material-ui/lab": "4.0.0-alpha.61", "@octokit/rest": "^19.0.3", "@oriflame/backstage-plugin-score-card": "^0.7.0", + "@pagerduty/backstage-plugin": "^0.7.1", "@roadiehq/backstage-plugin-buildkite": "^2.0.8", "@roadiehq/backstage-plugin-github-insights": "^2.0.5", "@roadiehq/backstage-plugin-github-pull-requests": "^2.2.7", diff --git a/packages/app/src/components/catalog/EntityPage.tsx b/packages/app/src/components/catalog/EntityPage.tsx index ecc1f008b5..7fe73f2222 100644 --- a/packages/app/src/components/catalog/EntityPage.tsx +++ b/packages/app/src/components/catalog/EntityPage.tsx @@ -128,7 +128,7 @@ import { import { EntityPagerDutyCard, isPagerDutyAvailable, -} from '@backstage/plugin-pagerduty'; +} from '@pagerduty/backstage-plugin'; import { EntityPlaylistDialog } from '@backstage/plugin-playlist'; import { EntityRollbarContent, diff --git a/packages/app/src/components/home/HomePage.tsx b/packages/app/src/components/home/HomePage.tsx index 5940b0ac6c..f1cf0248ab 100644 --- a/packages/app/src/components/home/HomePage.tsx +++ b/packages/app/src/components/home/HomePage.tsx @@ -32,7 +32,7 @@ import { HomePageCalendar } from '@backstage/plugin-gcalendar'; import { MicrosoftCalendarCard } from '@backstage/plugin-microsoft-calendar'; import React from 'react'; import HomeIcon from '@material-ui/icons/Home'; -import { HomePagePagerDutyCard } from '@backstage/plugin-pagerduty'; +import { HomePagePagerDutyCard } from '@pagerduty/backstage-plugin'; const clockConfigs: ClockConfig[] = [ { From 7ac25759a54520fb2e4fa0431340642d9d04217a Mon Sep 17 00:00:00 2001 From: djamaile Date: Mon, 20 Nov 2023 20:01:15 +0100 Subject: [PATCH 040/261] chore: move implementation to new plugin Signed-off-by: djamaile --- .changeset/blue-meals-chew.md | 5 + .../src/authenticator.ts | 7 +- .../src/index.ts | 5 + .../src/types.ts | 60 +++++ plugins/auth-backend/package.json | 1 + .../src/providers/oauth2-proxy/index.ts | 8 +- .../providers/oauth2-proxy/provider.test.ts | 205 ------------------ .../src/providers/oauth2-proxy/provider.ts | 183 ++-------------- 8 files changed, 97 insertions(+), 377 deletions(-) create mode 100644 .changeset/blue-meals-chew.md create mode 100644 plugins/auth-backend-module-oauth2-proxy-provider/src/types.ts delete mode 100644 plugins/auth-backend/src/providers/oauth2-proxy/provider.test.ts diff --git a/.changeset/blue-meals-chew.md b/.changeset/blue-meals-chew.md new file mode 100644 index 0000000000..479e77a982 --- /dev/null +++ b/.changeset/blue-meals-chew.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-auth-backend': patch +--- + +`oauth2-proxy` auth implementation has been moved to `@backstage/plugin-auth-backend-module-oauth2-proxy-provider` diff --git a/plugins/auth-backend-module-oauth2-proxy-provider/src/authenticator.ts b/plugins/auth-backend-module-oauth2-proxy-provider/src/authenticator.ts index de12eb4d4c..1857509002 100644 --- a/plugins/auth-backend-module-oauth2-proxy-provider/src/authenticator.ts +++ b/plugins/auth-backend-module-oauth2-proxy-provider/src/authenticator.ts @@ -15,18 +15,21 @@ */ import { AuthenticationError } from '@backstage/errors'; -import { OAuth2ProxyResult } from '@backstage/plugin-auth-backend'; import { createProxyAuthenticator, getBearerTokenFromAuthorizationHeader, } from '@backstage/plugin-auth-node'; import { decodeJwt } from 'jose'; +import { OAuth2ProxyResult } from './types'; // NOTE: This may come in handy if you're doing work on this provider: // plugins/auth-backend/examples/docker-compose.oauth2-proxy.yaml export const OAUTH2_PROXY_JWT_HEADER = 'X-OAUTH2-PROXY-ID-TOKEN'; -export const oauth2ProxyAuthenticator = createProxyAuthenticator({ +export const oauth2ProxyAuthenticator = createProxyAuthenticator< + unknown, + OAuth2ProxyResult +>({ defaultProfileTransform: async (result: OAuth2ProxyResult) => { return { profile: { diff --git a/plugins/auth-backend-module-oauth2-proxy-provider/src/index.ts b/plugins/auth-backend-module-oauth2-proxy-provider/src/index.ts index 93bb11ca1e..db0da00a16 100644 --- a/plugins/auth-backend-module-oauth2-proxy-provider/src/index.ts +++ b/plugins/auth-backend-module-oauth2-proxy-provider/src/index.ts @@ -20,3 +20,8 @@ * @packageDocumentation */ export { authModuleOauth2ProxyProvider } from './module'; +export { + oauth2ProxyAuthenticator, + OAUTH2_PROXY_JWT_HEADER, +} from './authenticator'; +export type { OAuth2ProxyResult } from './types'; diff --git a/plugins/auth-backend-module-oauth2-proxy-provider/src/types.ts b/plugins/auth-backend-module-oauth2-proxy-provider/src/types.ts new file mode 100644 index 0000000000..5b9e97ab05 --- /dev/null +++ b/plugins/auth-backend-module-oauth2-proxy-provider/src/types.ts @@ -0,0 +1,60 @@ +/* + * 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 { IncomingHttpHeaders } from 'http'; + +/** + * JWT header extraction result, containing the raw value and the parsed JWT + * payload. + * + * @public + */ +export type OAuth2ProxyResult = { + /** + * The parsed payload of the `accessToken`. The token is only parsed, not verified. + * + * @deprecated Access through the `headers` instead. This will be removed in a future release. + */ + fullProfile: JWTPayload; + + /** + * The token received via the X-OAUTH2-PROXY-ID-TOKEN header. Will be an empty string + * if the header is not set. Note the this is typically an OpenID Connect token. + * + * @deprecated Access through the `headers` instead. This will be removed in a future release. + */ + accessToken: string; + + /** + * The headers of the incoming request from the OAuth2 proxy. This will include + * both the headers set by the client as well as the ones added by the OAuth2 proxy. + * You should only trust the headers that are injected by the OAuth2 proxy. + * + * Useful headers to use to complete the sign-in are for example `x-forwarded-user` + * and `x-forwarded-email`. See the OAuth2 proxy documentation for more information + * about the available headers and how to enable them. In particular it is possible + * to forward access and identity tokens, which can be user for additional verification + * and lookups. + */ + headers: IncomingHttpHeaders; + + /** + * Provides convenient access to the request headers. + * + * This call is simply forwarded to `req.get(name)`. + */ + getHeader(name: string): string | undefined; +}; diff --git a/plugins/auth-backend/package.json b/plugins/auth-backend/package.json index c788d74df0..1a9a4447d1 100644 --- a/plugins/auth-backend/package.json +++ b/plugins/auth-backend/package.json @@ -45,6 +45,7 @@ "@backstage/plugin-auth-backend-module-google-provider": "workspace:^", "@backstage/plugin-auth-backend-module-oauth2-provider": "workspace:^", "@backstage/plugin-auth-backend-module-okta-provider": "workspace:^", + "@backstage/plugin-auth-backend-module-oauth2-proxy-provider": "workspace:^", "@backstage/plugin-auth-node": "workspace:^", "@backstage/plugin-catalog-node": "workspace:^", "@backstage/types": "workspace:^", diff --git a/plugins/auth-backend/src/providers/oauth2-proxy/index.ts b/plugins/auth-backend/src/providers/oauth2-proxy/index.ts index d3004f31e4..2e4e7d016f 100644 --- a/plugins/auth-backend/src/providers/oauth2-proxy/index.ts +++ b/plugins/auth-backend/src/providers/oauth2-proxy/index.ts @@ -15,4 +15,10 @@ */ export { oauth2Proxy } from './provider'; -export type { OAuth2ProxyResult } from './provider'; +import { OAuth2ProxyResult as _OAuth2ProxyResult } from '@backstage/plugin-auth-backend-module-oauth2-proxy-provider'; + +/** + * @public + * @deprecated import from `@backstage/plugin-auth-backend-module-oauth2-proxy-provider` instead + */ +export type OAuth2ProxyResult = _OAuth2ProxyResult; diff --git a/plugins/auth-backend/src/providers/oauth2-proxy/provider.test.ts b/plugins/auth-backend/src/providers/oauth2-proxy/provider.test.ts deleted file mode 100644 index f585d4831f..0000000000 --- a/plugins/auth-backend/src/providers/oauth2-proxy/provider.test.ts +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright 2021 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -jest.mock('jose', () => ({ - decodeJwt: jest.fn(), -})); -jest.mock('@backstage/catalog-client'); - -import { AuthenticationError } from '@backstage/errors'; -import express from 'express'; -import * as jose from 'jose'; -import { LoggerService } from '@backstage/backend-plugin-api'; -import { AuthHandler, AuthResolverContext, SignInResolver } from '../types'; -import { - oauth2Proxy, - Oauth2ProxyAuthProvider, - OAuth2ProxyResult, - OAUTH2_PROXY_JWT_HEADER, -} from './provider'; - -describe('Oauth2ProxyAuthProvider', () => { - const mockToken = - 'eyblob.eyJzdWIiOiJ1c2VyOmRlZmF1bHQvamltbXltYXJrdW0iLCJlbnQiOlsidXNlcjpkZWZhdWx0L2ppbW15bWFya3VtIl19.eyblob'; - - let provider: Oauth2ProxyAuthProvider; - let logger: jest.Mocked; - let signInResolver: jest.MockedFunction< - SignInResolver> - >; - let authHandler: jest.MockedFunction>>; - let mockResponse: jest.Mocked; - let mockRequest: jest.Mocked; - let mockJwtDecode: jest.MockedFunction; - - beforeEach(() => { - jest.resetAllMocks(); - - mockJwtDecode = jose.decodeJwt as jest.MockedFunction< - typeof jose.decodeJwt - >; - authHandler = jest.fn(); - signInResolver = jest.fn(); - logger = { error: jest.fn() } as unknown as jest.Mocked; - - mockResponse = { - status: jest.fn(), - end: jest.fn(), - json: jest.fn(), - } as unknown as jest.Mocked; - - mockRequest = { - body: {}, - header: jest.fn(), - headers: { - 'x-mock': 'mock', - }, - } as unknown as jest.Mocked; - - provider = new Oauth2ProxyAuthProvider({ - authHandler, - signInResolver, - resolverContext: { - _: 'resolver-context', - } as unknown as AuthResolverContext, - }); - }); - - describe('frameHandler()', () => { - it('should do nothing and return undefined', async () => { - const result = await provider.frameHandler(); - - expect(result).toBeUndefined(); - }); - }); - - describe('start()', () => { - it('should do nothing and return undefined', async () => { - const result = await provider.start(); - - expect(result).toBeUndefined(); - }); - }); - - describe('refresh()', () => { - it('should throw an error when auth header is missing', async () => { - mockRequest.header.mockReturnValue(undefined); - - await expect(provider.refresh(mockRequest, mockResponse)).rejects.toThrow( - AuthenticationError, - ); - }); - - it('should throw an error if the bearer token is invalid', async () => { - mockRequest.header.mockReturnValue('Basic asdf='); - - await expect(provider.refresh(mockRequest, mockResponse)).rejects.toThrow( - AuthenticationError, - ); - }); - - it('should return if auth header is set and valid', async () => { - mockRequest.header.mockReturnValue(`Bearer token`); - authHandler.mockResolvedValue({ - profile: {}, - }); - signInResolver.mockResolvedValue({ - token: mockToken, - }); - - await provider.refresh(mockRequest, mockResponse); - - expect(mockRequest.header).toHaveBeenCalledWith(OAUTH2_PROXY_JWT_HEADER); - expect(mockJwtDecode).toHaveBeenCalledWith('token'); - expect(mockResponse.json).toHaveBeenCalled(); - }); - - it('should load profile from authHandler and backstage identity from signInResolver', async () => { - const decodedToken = { - oid: 'oid', - name: 'name', - upn: 'john.doe@example.com', - }; - const profile = { displayName: 'some value' }; - mockRequest.header.mockReturnValue(`Bearer token`); - signInResolver.mockResolvedValue({ - token: mockToken, - }); - authHandler.mockResolvedValue({ profile: profile }); - mockJwtDecode.mockReturnValue(decodedToken as any); - - await provider.refresh(mockRequest, mockResponse); - - expect(signInResolver).toHaveBeenCalledWith( - { - profile: profile, - result: { - accessToken: 'token', - fullProfile: decodedToken, - getHeader: expect.any(Function), - headers: { - 'x-mock': 'mock', - }, - }, - }, - { _: 'resolver-context' }, - ); - expect(mockResponse.json).toHaveBeenCalledWith({ - backstageIdentity: { - identity: { - type: 'user', - userEntityRef: 'user:default/jimmymarkum', - ownershipEntityRefs: ['user:default/jimmymarkum'], - }, - token: mockToken, - }, - profile: { displayName: 'some value' }, - providerInfo: { - accessToken: 'token', - }, - }); - }); - }); - - describe('oauth2Proxy.create()', () => { - beforeEach(() => { - mockRequest.header.mockReturnValue(`Bearer token`); - authHandler.mockResolvedValue({ - profile: {}, - }); - signInResolver.mockResolvedValue({ - token: mockToken, - }); - }); - - it('should create a valid provider', async () => { - const factory = oauth2Proxy.create({ - authHandler, - signIn: { resolver: signInResolver }, - }); - const handler = factory({ - logger, - catalogApi: {}, - tokenIssuer: {}, - } as any); - await handler.refresh!(mockRequest, mockResponse); - - expect(mockRequest.header).toHaveBeenCalledWith(OAUTH2_PROXY_JWT_HEADER); - expect(mockJwtDecode).toHaveBeenCalledWith('token'); - expect(mockResponse.json).toHaveBeenCalled(); - }); - }); -}); diff --git a/plugins/auth-backend/src/providers/oauth2-proxy/provider.ts b/plugins/auth-backend/src/providers/oauth2-proxy/provider.ts index 3ac7d09000..5d75167e84 100644 --- a/plugins/auth-backend/src/providers/oauth2-proxy/provider.ts +++ b/plugins/auth-backend/src/providers/oauth2-proxy/provider.ts @@ -14,164 +14,13 @@ * limitations under the License. */ -import express from 'express'; -import { AuthenticationError } from '@backstage/errors'; -import { getBearerTokenFromAuthorizationHeader } from '@backstage/plugin-auth-node'; -import { - AuthHandler, - SignInResolver, - AuthProviderRouteHandlers, - AuthResponse, - AuthResolverContext, - AuthHandlerResult, -} from '../types'; -import { decodeJwt } from 'jose'; -import { prepareBackstageIdentityResponse } from '../prepareBackstageIdentityResponse'; +import { createProxyAuthProviderFactory } from '@backstage/plugin-auth-node'; +import { AuthHandler, SignInResolver } from '../types'; import { createAuthProviderIntegration } from '../createAuthProviderIntegration'; -import { IncomingHttpHeaders } from 'http'; - -// NOTE: This may come in handy if you're doing work on this provider: -// -// plugins/auth-backend/examples/docker-compose.oauth2-proxy.yaml -// - -export const OAUTH2_PROXY_JWT_HEADER = 'X-OAUTH2-PROXY-ID-TOKEN'; - -/** - * JWT header extraction result, containing the raw value and the parsed JWT - * payload. - * - * @public - */ -export type OAuth2ProxyResult = { - /** - * The parsed payload of the `accessToken`. The token is only parsed, not verified. - * - * @deprecated Access through the `headers` instead. This will be removed in a future release. - */ - fullProfile: JWTPayload; - - /** - * The token received via the X-OAUTH2-PROXY-ID-TOKEN header. Will be an empty string - * if the header is not set. Note the this is typically an OpenID Connect token. - * - * @deprecated Access through the `headers` instead. This will be removed in a future release. - */ - accessToken: string; - - /** - * The headers of the incoming request from the OAuth2 proxy. This will include - * both the headers set by the client as well as the ones added by the OAuth2 proxy. - * You should only trust the headers that are injected by the OAuth2 proxy. - * - * Useful headers to use to complete the sign-in are for example `x-forwarded-user` - * and `x-forwarded-email`. See the OAuth2 proxy documentation for more information - * about the available headers and how to enable them. In particular it is possible - * to forward access and identity tokens, which can be user for additional verification - * and lookups. - */ - headers: IncomingHttpHeaders; - - /** - * Provides convenient access to the request headers. - * - * This call is simply forwarded to `req.get(name)`. - */ - getHeader(name: string): string | undefined; -}; - -interface Options { - resolverContext: AuthResolverContext; - signInResolver: SignInResolver>; - authHandler: AuthHandler>; -} - -export class Oauth2ProxyAuthProvider - implements AuthProviderRouteHandlers -{ - private readonly resolverContext: AuthResolverContext; - private readonly signInResolver: SignInResolver< - OAuth2ProxyResult - >; - private readonly authHandler: AuthHandler>; - - constructor(options: Options) { - this.resolverContext = options.resolverContext; - this.signInResolver = options.signInResolver; - this.authHandler = options.authHandler; - } - - frameHandler(): Promise { - return Promise.resolve(undefined); - } - - async refresh(req: express.Request, res: express.Response): Promise { - try { - // TODO(Rugvip): This parsing was deprecated in 1.2 and should be removed in a future release. - const authHeader = req.header(OAUTH2_PROXY_JWT_HEADER); - const jwt = getBearerTokenFromAuthorizationHeader(authHeader); - const decodedJWT = jwt && (decodeJwt(jwt) as unknown as JWTPayload); - - const result = { - fullProfile: decodedJWT || ({} as JWTPayload), - accessToken: jwt || '', - headers: req.headers, - getHeader(name: string) { - if (name.toLocaleLowerCase('en-US') === 'set-cookie') { - throw new Error('Access Set-Cookie via the headers object instead'); - } - return req.get(name); - }, - }; - - const response = await this.handleResult(result); - res.json(response); - } catch (e) { - throw new AuthenticationError('Refresh failed', e); - } - } - - start(): Promise { - return Promise.resolve(undefined); - } - - private async handleResult( - result: OAuth2ProxyResult, - ): Promise> { - const { profile } = await this.authHandler(result, this.resolverContext); - - const backstageSignInResult = await this.signInResolver( - { - result, - profile, - }, - this.resolverContext, - ); - - return { - providerInfo: { - accessToken: result.accessToken, - }, - backstageIdentity: prepareBackstageIdentityResponse( - backstageSignInResult, - ), - profile, - }; - } -} - -async function defaultAuthHandler( - result: OAuth2ProxyResult, -): Promise { - return { - profile: { - email: result.getHeader('x-forwarded-email'), - displayName: - result.getHeader('x-forwarded-preferred-username') || - result.getHeader('x-forwarded-user'), - }, - }; -} +import { + type OAuth2ProxyResult, + oauth2ProxyAuthenticator, +} from '@backstage/plugin-auth-backend-module-oauth2-proxy-provider'; /** * Auth provider integration for oauth2-proxy auth @@ -179,7 +28,7 @@ async function defaultAuthHandler( * @public */ export const oauth2Proxy = createAuthProviderIntegration({ - create(options: { + create(options: { /** * Configure an auth handler to generate a profile for the user. * @@ -187,7 +36,7 @@ export const oauth2Proxy = createAuthProviderIntegration({ * header as the display name, falling back to `X-Forwarded-User`, and the value of * the `X-Forwarded-Email` header as the email address. */ - authHandler?: AuthHandler>; + authHandler?: AuthHandler; /** * Configure sign-in for this provider, without it the provider can not be used to sign users in. @@ -196,17 +45,13 @@ export const oauth2Proxy = createAuthProviderIntegration({ /** * Maps an auth result to a Backstage identity for the user. */ - resolver: SignInResolver>; + resolver: SignInResolver; }; }) { - return ({ resolverContext }) => { - const signInResolver = options.signIn.resolver; - const authHandler = options.authHandler; - return new Oauth2ProxyAuthProvider({ - resolverContext, - signInResolver, - authHandler: authHandler ?? defaultAuthHandler, - }); - }; + return createProxyAuthProviderFactory({ + authenticator: oauth2ProxyAuthenticator, + profileTransform: options?.authHandler, + signInResolver: options?.signIn?.resolver, + }); }, }); From 37ad2a80c063e58f8bbd581ee4d598b882ddff26 Mon Sep 17 00:00:00 2001 From: djamaile Date: Mon, 20 Nov 2023 20:58:16 +0100 Subject: [PATCH 041/261] chore: run api reports command Signed-off-by: djamaile --- .../api-report.md | 31 +++++++++++++++++++ .../catalog-info.yaml | 10 ++++++ .../src/authenticator.ts | 9 ++++-- plugins/auth-backend/api-report.md | 17 +++------- 4 files changed, 53 insertions(+), 14 deletions(-) create mode 100644 plugins/auth-backend-module-oauth2-proxy-provider/api-report.md create mode 100644 plugins/auth-backend-module-oauth2-proxy-provider/catalog-info.yaml diff --git a/plugins/auth-backend-module-oauth2-proxy-provider/api-report.md b/plugins/auth-backend-module-oauth2-proxy-provider/api-report.md new file mode 100644 index 0000000000..a07db4ce11 --- /dev/null +++ b/plugins/auth-backend-module-oauth2-proxy-provider/api-report.md @@ -0,0 +1,31 @@ +## API Report File for "@backstage/plugin-auth-backend-module-oauth2-proxy-provider" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +/// + +import { BackendFeature } from '@backstage/backend-plugin-api'; +import { IncomingHttpHeaders } from 'http'; +import { ProxyAuthenticator } from '@backstage/plugin-auth-node'; + +// @public (undocumented) +export const authModuleOauth2ProxyProvider: () => BackendFeature; + +// @public +export const OAUTH2_PROXY_JWT_HEADER = 'X-OAUTH2-PROXY-ID-TOKEN'; + +// @public (undocumented) +export const oauth2ProxyAuthenticator: ProxyAuthenticator< + unknown, + OAuth2ProxyResult +>; + +// @public +export type OAuth2ProxyResult = { + fullProfile: JWTPayload; + accessToken: string; + headers: IncomingHttpHeaders; + getHeader(name: string): string | undefined; +}; +``` diff --git a/plugins/auth-backend-module-oauth2-proxy-provider/catalog-info.yaml b/plugins/auth-backend-module-oauth2-proxy-provider/catalog-info.yaml new file mode 100644 index 0000000000..c26202c97d --- /dev/null +++ b/plugins/auth-backend-module-oauth2-proxy-provider/catalog-info.yaml @@ -0,0 +1,10 @@ +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: backstage-plugin-auth-backend-module-oauth2-proxy-provider + title: '@backstage/plugin-auth-backend-module-oauth2-proxy-provider' + description: The oauth2-proxy-provider backend module for the auth plugin. +spec: + lifecycle: experimental + type: backstage-backend-plugin-module + owner: maintainers diff --git a/plugins/auth-backend-module-oauth2-proxy-provider/src/authenticator.ts b/plugins/auth-backend-module-oauth2-proxy-provider/src/authenticator.ts index 1857509002..a3da83791a 100644 --- a/plugins/auth-backend-module-oauth2-proxy-provider/src/authenticator.ts +++ b/plugins/auth-backend-module-oauth2-proxy-provider/src/authenticator.ts @@ -22,10 +22,15 @@ import { import { decodeJwt } from 'jose'; import { OAuth2ProxyResult } from './types'; -// NOTE: This may come in handy if you're doing work on this provider: -// plugins/auth-backend/examples/docker-compose.oauth2-proxy.yaml +/** + * NOTE: This may come in handy if you're doing work on this provider: + * plugins/auth-backend/examples/docker-compose.oauth2-proxy.yaml + * + * @public + */ export const OAUTH2_PROXY_JWT_HEADER = 'X-OAUTH2-PROXY-ID-TOKEN'; +/** @public */ export const oauth2ProxyAuthenticator = createProxyAuthenticator< unknown, OAuth2ProxyResult diff --git a/plugins/auth-backend/api-report.md b/plugins/auth-backend/api-report.md index c20ddbe5a8..c269a09d2c 100644 --- a/plugins/auth-backend/api-report.md +++ b/plugins/auth-backend/api-report.md @@ -3,8 +3,6 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts -/// - import { AuthProviderConfig as AuthProviderConfig_2 } from '@backstage/plugin-auth-node'; import { AuthProviderFactory as AuthProviderFactory_2 } from '@backstage/plugin-auth-node'; import { AuthProviderRouteHandlers as AuthProviderRouteHandlers_2 } from '@backstage/plugin-auth-node'; @@ -23,8 +21,8 @@ import { Entity } from '@backstage/catalog-model'; import express from 'express'; import { GcpIapResult as GcpIapResult_2 } from '@backstage/plugin-auth-backend-module-gcp-iap-provider'; import { GcpIapTokenInfo as GcpIapTokenInfo_2 } from '@backstage/plugin-auth-backend-module-gcp-iap-provider'; -import { IncomingHttpHeaders } from 'http'; import { LoggerService } from '@backstage/backend-plugin-api'; +import { OAuth2ProxyResult as OAuth2ProxyResult_2 } from '@backstage/plugin-auth-backend-module-oauth2-proxy-provider'; import { OAuthEnvironmentHandler as OAuthEnvironmentHandler_2 } from '@backstage/plugin-auth-node'; import { OAuthState as OAuthState_2 } from '@backstage/plugin-auth-node'; import { PluginDatabaseManager } from '@backstage/backend-common'; @@ -228,13 +226,8 @@ export type GithubOAuthResult = { refreshToken?: string; }; -// @public -export type OAuth2ProxyResult = { - fullProfile: JWTPayload; - accessToken: string; - headers: IncomingHttpHeaders; - getHeader(name: string): string | undefined; -}; +// @public @deprecated (undocumented) +export type OAuth2ProxyResult = OAuth2ProxyResult_2; // @public @deprecated (undocumented) export class OAuthAdapter implements AuthProviderRouteHandlers { @@ -560,9 +553,9 @@ export const providers: Readonly<{ }>; oauth2Proxy: Readonly<{ create: (options: { - authHandler?: AuthHandler> | undefined; + authHandler?: AuthHandler | undefined; signIn: { - resolver: SignInResolver>; + resolver: SignInResolver; }; }) => AuthProviderFactory_2; resolvers: never; From ec5ca0a1716837587aeb18d1dd6d369a9ed0b6bd Mon Sep 17 00:00:00 2001 From: djamaile Date: Mon, 20 Nov 2023 21:01:27 +0100 Subject: [PATCH 042/261] chore: run yarn install Signed-off-by: djamaile --- plugins/auth-backend/package.json | 2 +- yarn.lock | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/auth-backend/package.json b/plugins/auth-backend/package.json index 1a9a4447d1..7dad25fe1c 100644 --- a/plugins/auth-backend/package.json +++ b/plugins/auth-backend/package.json @@ -44,8 +44,8 @@ "@backstage/plugin-auth-backend-module-gitlab-provider": "workspace:^", "@backstage/plugin-auth-backend-module-google-provider": "workspace:^", "@backstage/plugin-auth-backend-module-oauth2-provider": "workspace:^", - "@backstage/plugin-auth-backend-module-okta-provider": "workspace:^", "@backstage/plugin-auth-backend-module-oauth2-proxy-provider": "workspace:^", + "@backstage/plugin-auth-backend-module-okta-provider": "workspace:^", "@backstage/plugin-auth-node": "workspace:^", "@backstage/plugin-catalog-node": "workspace:^", "@backstage/types": "workspace:^", diff --git a/yarn.lock b/yarn.lock index e4a77e2388..8c3ccd6c87 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4749,6 +4749,7 @@ __metadata: "@backstage/plugin-auth-backend-module-gitlab-provider": "workspace:^" "@backstage/plugin-auth-backend-module-google-provider": "workspace:^" "@backstage/plugin-auth-backend-module-oauth2-provider": "workspace:^" + "@backstage/plugin-auth-backend-module-oauth2-proxy-provider": "workspace:^" "@backstage/plugin-auth-backend-module-okta-provider": "workspace:^" "@backstage/plugin-auth-node": "workspace:^" "@backstage/plugin-catalog-node": "workspace:^" From ba240bf8a00d8374810b86a16878a713fcf9a8dd Mon Sep 17 00:00:00 2001 From: Tiago Barbosa Date: Mon, 20 Nov 2023 22:58:24 +0000 Subject: [PATCH 043/261] build(pagerduty plugin): :green_heart: adding yarn lock file adding yarn lock file Signed-off-by: Tiago Barbosa --- yarn.lock | 53 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 39 insertions(+), 14 deletions(-) diff --git a/yarn.lock b/yarn.lock index 20bd578d42..495a54959f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3457,7 +3457,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/catalog-model@^1.1.5, @backstage/catalog-model@^1.4.3, @backstage/catalog-model@workspace:^, @backstage/catalog-model@workspace:packages/catalog-model": +"@backstage/catalog-model@^1.1.5, @backstage/catalog-model@^1.4.1, @backstage/catalog-model@^1.4.3, @backstage/catalog-model@workspace:^, @backstage/catalog-model@workspace:packages/catalog-model": version: 0.0.0-use.local resolution: "@backstage/catalog-model@workspace:packages/catalog-model" dependencies: @@ -3773,7 +3773,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/core-components@^0.13.7, @backstage/core-components@workspace:^, @backstage/core-components@workspace:packages/core-components": +"@backstage/core-components@^0.13.4, @backstage/core-components@^0.13.7, @backstage/core-components@workspace:^, @backstage/core-components@workspace:packages/core-components": version: 0.0.0-use.local resolution: "@backstage/core-components@workspace:packages/core-components" dependencies: @@ -3896,7 +3896,7 @@ __metadata: languageName: node linkType: hard -"@backstage/core-plugin-api@^1.3.0, @backstage/core-plugin-api@^1.5.0, @backstage/core-plugin-api@^1.7.0, @backstage/core-plugin-api@workspace:^, @backstage/core-plugin-api@workspace:packages/core-plugin-api": +"@backstage/core-plugin-api@^1.3.0, @backstage/core-plugin-api@^1.5.0, @backstage/core-plugin-api@^1.5.3, @backstage/core-plugin-api@^1.7.0, @backstage/core-plugin-api@workspace:^, @backstage/core-plugin-api@workspace:packages/core-plugin-api": version: 0.0.0-use.local resolution: "@backstage/core-plugin-api@workspace:packages/core-plugin-api" dependencies: @@ -3994,7 +3994,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/errors@^1.1.5, @backstage/errors@workspace:^, @backstage/errors@workspace:packages/errors": +"@backstage/errors@^1.1.5, @backstage/errors@^1.2.1, @backstage/errors@workspace:^, @backstage/errors@workspace:packages/errors": version: 0.0.0-use.local resolution: "@backstage/errors@workspace:packages/errors" dependencies: @@ -5688,7 +5688,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-catalog-react@^1.2.4, @backstage/plugin-catalog-react@^1.8.5, @backstage/plugin-catalog-react@workspace:^, @backstage/plugin-catalog-react@workspace:plugins/catalog-react": +"@backstage/plugin-catalog-react@^1.2.4, @backstage/plugin-catalog-react@^1.8.3, @backstage/plugin-catalog-react@^1.8.5, @backstage/plugin-catalog-react@workspace:^, @backstage/plugin-catalog-react@workspace:plugins/catalog-react": version: 0.0.0-use.local resolution: "@backstage/plugin-catalog-react@workspace:plugins/catalog-react" dependencies: @@ -7026,7 +7026,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-home-react@^0.1.4, @backstage/plugin-home-react@workspace:^, @backstage/plugin-home-react@workspace:plugins/home-react": +"@backstage/plugin-home-react@^0.1.2, @backstage/plugin-home-react@^0.1.4, @backstage/plugin-home-react@workspace:^, @backstage/plugin-home-react@workspace:plugins/home-react": version: 0.0.0-use.local resolution: "@backstage/plugin-home-react@workspace:plugins/home-react" dependencies: @@ -7888,7 +7888,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-pagerduty@workspace:^, @backstage/plugin-pagerduty@workspace:plugins/pagerduty": +"@backstage/plugin-pagerduty@workspace:plugins/pagerduty": version: 0.0.0-use.local resolution: "@backstage/plugin-pagerduty@workspace:plugins/pagerduty" dependencies: @@ -9819,7 +9819,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/theme@^0.4.3, @backstage/theme@workspace:^, @backstage/theme@workspace:packages/theme": +"@backstage/theme@^0.4.1, @backstage/theme@^0.4.3, @backstage/theme@workspace:^, @backstage/theme@workspace:packages/theme": version: 0.0.0-use.local resolution: "@backstage/theme@workspace:packages/theme" dependencies: @@ -13917,6 +13917,31 @@ __metadata: languageName: node linkType: hard +"@pagerduty/backstage-plugin@npm:^0.7.2-next.1": + version: 0.7.2-next.1 + resolution: "@pagerduty/backstage-plugin@npm:0.7.2-next.1" + dependencies: + "@backstage/catalog-model": ^1.4.1 + "@backstage/core-components": ^0.13.4 + "@backstage/core-plugin-api": ^1.5.3 + "@backstage/errors": ^1.2.1 + "@backstage/plugin-catalog-react": ^1.8.3 + "@backstage/plugin-home-react": ^0.1.2 + "@backstage/theme": ^0.4.1 + "@material-ui/core": ^4.12.2 + "@material-ui/icons": ^4.9.1 + "@material-ui/lab": 4.0.0-alpha.61 + "@types/react": ^16.13.1 || ^17.0.0 || ^18.0.0 + classnames: ^2.2.6 + luxon: ^3.4.1 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-router-dom: 6.0.0-beta.0 || ^6.3.0 + react-use: ^17.2.4 + checksum: da1c06472a32fcd611066c9ec153d6195ae1ebb767b420cf00c0de74705ce2e0aea6cc34bce0cae01281c1138ce965bd4d428bf854c273558c145ba686a47f3b + languageName: node + linkType: hard + "@pkgjs/parseargs@npm:^0.11.0": version: 0.11.0 resolution: "@pkgjs/parseargs@npm:0.11.0" @@ -26103,7 +26128,6 @@ __metadata: "@backstage/plugin-newrelic-dashboard": "workspace:^" "@backstage/plugin-octopus-deploy": "workspace:^" "@backstage/plugin-org": "workspace:^" - "@backstage/plugin-pagerduty": "workspace:^" "@backstage/plugin-permission-react": "workspace:^" "@backstage/plugin-playlist": "workspace:^" "@backstage/plugin-puppetdb": "workspace:^" @@ -26130,6 +26154,7 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@octokit/rest": ^19.0.3 "@oriflame/backstage-plugin-score-card": ^0.7.0 + "@pagerduty/backstage-plugin": ^0.7.2-next.1 "@roadiehq/backstage-plugin-buildkite": ^2.0.8 "@roadiehq/backstage-plugin-github-insights": ^2.0.5 "@roadiehq/backstage-plugin-github-pull-requests": ^2.2.7 @@ -26214,7 +26239,6 @@ __metadata: "@backstage/plugin-nomad": "workspace:^" "@backstage/plugin-octopus-deploy": "workspace:^" "@backstage/plugin-org": "workspace:^" - "@backstage/plugin-pagerduty": "workspace:^" "@backstage/plugin-permission-react": "workspace:^" "@backstage/plugin-playlist": "workspace:^" "@backstage/plugin-puppetdb": "workspace:^" @@ -26242,6 +26266,7 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@octokit/rest": ^19.0.3 "@oriflame/backstage-plugin-score-card": ^0.7.0 + "@pagerduty/backstage-plugin": ^0.7.2-next.1 "@playwright/test": ^1.32.3 "@roadiehq/backstage-plugin-buildkite": ^2.0.8 "@roadiehq/backstage-plugin-github-insights": ^2.0.5 @@ -32824,7 +32849,7 @@ __metadata: languageName: node linkType: hard -"luxon@npm:^3.0.0, luxon@npm:^3.3.0, luxon@npm:^3.4.3": +"luxon@npm:^3.0.0, luxon@npm:^3.3.0, luxon@npm:^3.4.1, luxon@npm:^3.4.3": version: 3.4.4 resolution: "luxon@npm:3.4.4" checksum: 36c1f99c4796ee4bfddf7dc94fa87815add43ebc44c8934c924946260a58512f0fd2743a629302885df7f35ccbd2d13f178c15df046d0e3b6eb71db178f1c60c @@ -38044,7 +38069,7 @@ __metadata: languageName: node linkType: hard -"react-dom@npm:^18.0.2": +"react-dom@npm:^16.13.1 || ^17.0.0 || ^18.0.0, react-dom@npm:^18.0.2": version: 18.2.0 resolution: "react-dom@npm:18.2.0" dependencies: @@ -38428,7 +38453,7 @@ __metadata: languageName: node linkType: hard -"react-router-dom@npm:^6.3.0": +"react-router-dom@npm:6.0.0-beta.0 || ^6.3.0, react-router-dom@npm:^6.3.0": version: 6.19.0 resolution: "react-router-dom@npm:6.19.0" dependencies: @@ -38657,7 +38682,7 @@ __metadata: languageName: node linkType: hard -"react@npm:^18.0.2": +"react@npm:^16.13.1 || ^17.0.0 || ^18.0.0, react@npm:^18.0.2": version: 18.2.0 resolution: "react@npm:18.2.0" dependencies: From db0ad26db41aa2798a2246dec0fa52b35662fbdb Mon Sep 17 00:00:00 2001 From: Tiago Barbosa Date: Tue, 21 Nov 2023 00:07:40 +0000 Subject: [PATCH 044/261] Revert "build(pagerduty plugin): :green_heart: adding yarn lock file" This reverts commit ba240bf8a00d8374810b86a16878a713fcf9a8dd. Signed-off-by: Tiago Barbosa --- packages/app-next/package.json | 2 +- packages/app-next/src/HomePage.tsx | 2 +- packages/app/package.json | 2 +- .../app/src/components/catalog/EntityPage.tsx | 2 +- packages/app/src/components/home/HomePage.tsx | 2 +- yarn.lock | 53 +++++-------------- 6 files changed, 19 insertions(+), 44 deletions(-) diff --git a/packages/app-next/package.json b/packages/app-next/package.json index 78e15a9ad0..6e0581d034 100644 --- a/packages/app-next/package.json +++ b/packages/app-next/package.json @@ -56,6 +56,7 @@ "@backstage/plugin-newrelic-dashboard": "workspace:^", "@backstage/plugin-octopus-deploy": "workspace:^", "@backstage/plugin-org": "workspace:^", + "@backstage/plugin-pagerduty": "workspace:^", "@backstage/plugin-permission-react": "workspace:^", "@backstage/plugin-playlist": "workspace:^", "@backstage/plugin-puppetdb": "workspace:^", @@ -81,7 +82,6 @@ "@material-ui/lab": "4.0.0-alpha.61", "@octokit/rest": "^19.0.3", "@oriflame/backstage-plugin-score-card": "^0.7.0", - "@pagerduty/backstage-plugin": "^0.7.1", "@roadiehq/backstage-plugin-buildkite": "^2.0.8", "@roadiehq/backstage-plugin-github-insights": "^2.0.5", "@roadiehq/backstage-plugin-github-pull-requests": "^2.2.7", diff --git a/packages/app-next/src/HomePage.tsx b/packages/app-next/src/HomePage.tsx index 8850e27190..cb31beb34a 100644 --- a/packages/app-next/src/HomePage.tsx +++ b/packages/app-next/src/HomePage.tsx @@ -31,7 +31,7 @@ import { HomePageCalendar } from '@backstage/plugin-gcalendar'; import { MicrosoftCalendarCard } from '@backstage/plugin-microsoft-calendar'; import React from 'react'; import HomeIcon from '@material-ui/icons/Home'; -import { HomePagePagerDutyCard } from '@pagerduty/backstage-plugin'; +import { HomePagePagerDutyCard } from '@backstage/plugin-pagerduty'; const clockConfigs: ClockConfig[] = [ { diff --git a/packages/app/package.json b/packages/app/package.json index e647e166c4..245b645ddc 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -62,6 +62,7 @@ "@backstage/plugin-nomad": "workspace:^", "@backstage/plugin-octopus-deploy": "workspace:^", "@backstage/plugin-org": "workspace:^", + "@backstage/plugin-pagerduty": "workspace:^", "@backstage/plugin-permission-react": "workspace:^", "@backstage/plugin-playlist": "workspace:^", "@backstage/plugin-puppetdb": "workspace:^", @@ -88,7 +89,6 @@ "@material-ui/lab": "4.0.0-alpha.61", "@octokit/rest": "^19.0.3", "@oriflame/backstage-plugin-score-card": "^0.7.0", - "@pagerduty/backstage-plugin": "^0.7.1", "@roadiehq/backstage-plugin-buildkite": "^2.0.8", "@roadiehq/backstage-plugin-github-insights": "^2.0.5", "@roadiehq/backstage-plugin-github-pull-requests": "^2.2.7", diff --git a/packages/app/src/components/catalog/EntityPage.tsx b/packages/app/src/components/catalog/EntityPage.tsx index 7fe73f2222..ecc1f008b5 100644 --- a/packages/app/src/components/catalog/EntityPage.tsx +++ b/packages/app/src/components/catalog/EntityPage.tsx @@ -128,7 +128,7 @@ import { import { EntityPagerDutyCard, isPagerDutyAvailable, -} from '@pagerduty/backstage-plugin'; +} from '@backstage/plugin-pagerduty'; import { EntityPlaylistDialog } from '@backstage/plugin-playlist'; import { EntityRollbarContent, diff --git a/packages/app/src/components/home/HomePage.tsx b/packages/app/src/components/home/HomePage.tsx index f1cf0248ab..5940b0ac6c 100644 --- a/packages/app/src/components/home/HomePage.tsx +++ b/packages/app/src/components/home/HomePage.tsx @@ -32,7 +32,7 @@ import { HomePageCalendar } from '@backstage/plugin-gcalendar'; import { MicrosoftCalendarCard } from '@backstage/plugin-microsoft-calendar'; import React from 'react'; import HomeIcon from '@material-ui/icons/Home'; -import { HomePagePagerDutyCard } from '@pagerduty/backstage-plugin'; +import { HomePagePagerDutyCard } from '@backstage/plugin-pagerduty'; const clockConfigs: ClockConfig[] = [ { diff --git a/yarn.lock b/yarn.lock index 495a54959f..20bd578d42 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3457,7 +3457,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/catalog-model@^1.1.5, @backstage/catalog-model@^1.4.1, @backstage/catalog-model@^1.4.3, @backstage/catalog-model@workspace:^, @backstage/catalog-model@workspace:packages/catalog-model": +"@backstage/catalog-model@^1.1.5, @backstage/catalog-model@^1.4.3, @backstage/catalog-model@workspace:^, @backstage/catalog-model@workspace:packages/catalog-model": version: 0.0.0-use.local resolution: "@backstage/catalog-model@workspace:packages/catalog-model" dependencies: @@ -3773,7 +3773,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/core-components@^0.13.4, @backstage/core-components@^0.13.7, @backstage/core-components@workspace:^, @backstage/core-components@workspace:packages/core-components": +"@backstage/core-components@^0.13.7, @backstage/core-components@workspace:^, @backstage/core-components@workspace:packages/core-components": version: 0.0.0-use.local resolution: "@backstage/core-components@workspace:packages/core-components" dependencies: @@ -3896,7 +3896,7 @@ __metadata: languageName: node linkType: hard -"@backstage/core-plugin-api@^1.3.0, @backstage/core-plugin-api@^1.5.0, @backstage/core-plugin-api@^1.5.3, @backstage/core-plugin-api@^1.7.0, @backstage/core-plugin-api@workspace:^, @backstage/core-plugin-api@workspace:packages/core-plugin-api": +"@backstage/core-plugin-api@^1.3.0, @backstage/core-plugin-api@^1.5.0, @backstage/core-plugin-api@^1.7.0, @backstage/core-plugin-api@workspace:^, @backstage/core-plugin-api@workspace:packages/core-plugin-api": version: 0.0.0-use.local resolution: "@backstage/core-plugin-api@workspace:packages/core-plugin-api" dependencies: @@ -3994,7 +3994,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/errors@^1.1.5, @backstage/errors@^1.2.1, @backstage/errors@workspace:^, @backstage/errors@workspace:packages/errors": +"@backstage/errors@^1.1.5, @backstage/errors@workspace:^, @backstage/errors@workspace:packages/errors": version: 0.0.0-use.local resolution: "@backstage/errors@workspace:packages/errors" dependencies: @@ -5688,7 +5688,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-catalog-react@^1.2.4, @backstage/plugin-catalog-react@^1.8.3, @backstage/plugin-catalog-react@^1.8.5, @backstage/plugin-catalog-react@workspace:^, @backstage/plugin-catalog-react@workspace:plugins/catalog-react": +"@backstage/plugin-catalog-react@^1.2.4, @backstage/plugin-catalog-react@^1.8.5, @backstage/plugin-catalog-react@workspace:^, @backstage/plugin-catalog-react@workspace:plugins/catalog-react": version: 0.0.0-use.local resolution: "@backstage/plugin-catalog-react@workspace:plugins/catalog-react" dependencies: @@ -7026,7 +7026,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-home-react@^0.1.2, @backstage/plugin-home-react@^0.1.4, @backstage/plugin-home-react@workspace:^, @backstage/plugin-home-react@workspace:plugins/home-react": +"@backstage/plugin-home-react@^0.1.4, @backstage/plugin-home-react@workspace:^, @backstage/plugin-home-react@workspace:plugins/home-react": version: 0.0.0-use.local resolution: "@backstage/plugin-home-react@workspace:plugins/home-react" dependencies: @@ -7888,7 +7888,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-pagerduty@workspace:plugins/pagerduty": +"@backstage/plugin-pagerduty@workspace:^, @backstage/plugin-pagerduty@workspace:plugins/pagerduty": version: 0.0.0-use.local resolution: "@backstage/plugin-pagerduty@workspace:plugins/pagerduty" dependencies: @@ -9819,7 +9819,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/theme@^0.4.1, @backstage/theme@^0.4.3, @backstage/theme@workspace:^, @backstage/theme@workspace:packages/theme": +"@backstage/theme@^0.4.3, @backstage/theme@workspace:^, @backstage/theme@workspace:packages/theme": version: 0.0.0-use.local resolution: "@backstage/theme@workspace:packages/theme" dependencies: @@ -13917,31 +13917,6 @@ __metadata: languageName: node linkType: hard -"@pagerduty/backstage-plugin@npm:^0.7.2-next.1": - version: 0.7.2-next.1 - resolution: "@pagerduty/backstage-plugin@npm:0.7.2-next.1" - dependencies: - "@backstage/catalog-model": ^1.4.1 - "@backstage/core-components": ^0.13.4 - "@backstage/core-plugin-api": ^1.5.3 - "@backstage/errors": ^1.2.1 - "@backstage/plugin-catalog-react": ^1.8.3 - "@backstage/plugin-home-react": ^0.1.2 - "@backstage/theme": ^0.4.1 - "@material-ui/core": ^4.12.2 - "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.61 - "@types/react": ^16.13.1 || ^17.0.0 || ^18.0.0 - classnames: ^2.2.6 - luxon: ^3.4.1 - react: ^16.13.1 || ^17.0.0 || ^18.0.0 - react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 - react-router-dom: 6.0.0-beta.0 || ^6.3.0 - react-use: ^17.2.4 - checksum: da1c06472a32fcd611066c9ec153d6195ae1ebb767b420cf00c0de74705ce2e0aea6cc34bce0cae01281c1138ce965bd4d428bf854c273558c145ba686a47f3b - languageName: node - linkType: hard - "@pkgjs/parseargs@npm:^0.11.0": version: 0.11.0 resolution: "@pkgjs/parseargs@npm:0.11.0" @@ -26128,6 +26103,7 @@ __metadata: "@backstage/plugin-newrelic-dashboard": "workspace:^" "@backstage/plugin-octopus-deploy": "workspace:^" "@backstage/plugin-org": "workspace:^" + "@backstage/plugin-pagerduty": "workspace:^" "@backstage/plugin-permission-react": "workspace:^" "@backstage/plugin-playlist": "workspace:^" "@backstage/plugin-puppetdb": "workspace:^" @@ -26154,7 +26130,6 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@octokit/rest": ^19.0.3 "@oriflame/backstage-plugin-score-card": ^0.7.0 - "@pagerduty/backstage-plugin": ^0.7.2-next.1 "@roadiehq/backstage-plugin-buildkite": ^2.0.8 "@roadiehq/backstage-plugin-github-insights": ^2.0.5 "@roadiehq/backstage-plugin-github-pull-requests": ^2.2.7 @@ -26239,6 +26214,7 @@ __metadata: "@backstage/plugin-nomad": "workspace:^" "@backstage/plugin-octopus-deploy": "workspace:^" "@backstage/plugin-org": "workspace:^" + "@backstage/plugin-pagerduty": "workspace:^" "@backstage/plugin-permission-react": "workspace:^" "@backstage/plugin-playlist": "workspace:^" "@backstage/plugin-puppetdb": "workspace:^" @@ -26266,7 +26242,6 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@octokit/rest": ^19.0.3 "@oriflame/backstage-plugin-score-card": ^0.7.0 - "@pagerduty/backstage-plugin": ^0.7.2-next.1 "@playwright/test": ^1.32.3 "@roadiehq/backstage-plugin-buildkite": ^2.0.8 "@roadiehq/backstage-plugin-github-insights": ^2.0.5 @@ -32849,7 +32824,7 @@ __metadata: languageName: node linkType: hard -"luxon@npm:^3.0.0, luxon@npm:^3.3.0, luxon@npm:^3.4.1, luxon@npm:^3.4.3": +"luxon@npm:^3.0.0, luxon@npm:^3.3.0, luxon@npm:^3.4.3": version: 3.4.4 resolution: "luxon@npm:3.4.4" checksum: 36c1f99c4796ee4bfddf7dc94fa87815add43ebc44c8934c924946260a58512f0fd2743a629302885df7f35ccbd2d13f178c15df046d0e3b6eb71db178f1c60c @@ -38069,7 +38044,7 @@ __metadata: languageName: node linkType: hard -"react-dom@npm:^16.13.1 || ^17.0.0 || ^18.0.0, react-dom@npm:^18.0.2": +"react-dom@npm:^18.0.2": version: 18.2.0 resolution: "react-dom@npm:18.2.0" dependencies: @@ -38453,7 +38428,7 @@ __metadata: languageName: node linkType: hard -"react-router-dom@npm:6.0.0-beta.0 || ^6.3.0, react-router-dom@npm:^6.3.0": +"react-router-dom@npm:^6.3.0": version: 6.19.0 resolution: "react-router-dom@npm:6.19.0" dependencies: @@ -38682,7 +38657,7 @@ __metadata: languageName: node linkType: hard -"react@npm:^16.13.1 || ^17.0.0 || ^18.0.0, react@npm:^18.0.2": +"react@npm:^18.0.2": version: 18.2.0 resolution: "react@npm:18.2.0" dependencies: From 716dd37404b4560821cb5daa7ca23897957ec45b Mon Sep 17 00:00:00 2001 From: hainenber Date: Tue, 21 Nov 2023 22:37:02 +0700 Subject: [PATCH 045/261] fix(pkg/techdocs): correct dirtyreload arg for mkdocs Also correct array-like elements for rest operator Signed-off-by: hainenber --- .changeset/tricky-donkeys-do.md | 2 +- docs/features/techdocs/cli.md | 2 +- packages/techdocs-cli/cli-report.md | 2 +- packages/techdocs-cli/src/commands/index.ts | 4 ++-- packages/techdocs-cli/src/commands/serve/serve.ts | 2 +- packages/techdocs-cli/src/lib/mkdocsServer.ts | 14 +++++++------- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.changeset/tricky-donkeys-do.md b/.changeset/tricky-donkeys-do.md index 8859f012ba..573aa53135 100644 --- a/.changeset/tricky-donkeys-do.md +++ b/.changeset/tricky-donkeys-do.md @@ -2,4 +2,4 @@ '@techdocs/cli': minor --- -support passing additional mkdocs-server CLI parameters when run in containerized mode +support passing additional mkdocs-server CLI parameters (--dirtyreload, --strict and --clean) when run in containerized mode diff --git a/docs/features/techdocs/cli.md b/docs/features/techdocs/cli.md index e7b3aff057..97ed881922 100644 --- a/docs/features/techdocs/cli.md +++ b/docs/features/techdocs/cli.md @@ -92,7 +92,7 @@ Options: (can be added multiple times). --no-docker Do not use Docker, use MkDocs executable in current user environment. --mkdocs-parameter-clean Pass "--clean" parameter to mkdocs server running in containerized environment. - --mkdocs-parameter-dirty Pass "--dirty" parameter to mkdocs server running in containerized environment. + --mkdocs-parameter-dirtyreload Pass "--dirtyreload" parameter to mkdocs server running in containerized environment. --mkdocs-parameter-strict Pass "--strict" parameter to mkdocs server running in containerized environment. --mkdocs-port Port for MkDocs server to use (default: "8000") --preview-app-bundle-path Preview documentation using a web app other than the included one. diff --git a/packages/techdocs-cli/cli-report.md b/packages/techdocs-cli/cli-report.md index 9c155473ef..c50a320868 100644 --- a/packages/techdocs-cli/cli-report.md +++ b/packages/techdocs-cli/cli-report.md @@ -108,7 +108,7 @@ Options: --preview-app-port -c, --mkdocs-config-file-name --mkdocs-parameter-clean - --mkdocs-parameter-dirty + --mkdocs-parameter-dirtyreload --mkdocs-parameter-strict -h, --help ``` diff --git a/packages/techdocs-cli/src/commands/index.ts b/packages/techdocs-cli/src/commands/index.ts index 2d5ff98e77..d7c98db37c 100644 --- a/packages/techdocs-cli/src/commands/index.ts +++ b/packages/techdocs-cli/src/commands/index.ts @@ -295,8 +295,8 @@ export function registerCommands(program: Command) { false, ) .option( - '--mkdocs-parameter-dirty', - 'Pass "--dirty" parameter to mkdocs server running in containerized environment', + '--mkdocs-parameter-dirtyreload', + 'Pass "--dirtyreload" parameter to mkdocs server running in containerized environment', false, ) .option( diff --git a/packages/techdocs-cli/src/commands/serve/serve.ts b/packages/techdocs-cli/src/commands/serve/serve.ts index 47cfbe8a22..de681c2de4 100644 --- a/packages/techdocs-cli/src/commands/serve/serve.ts +++ b/packages/techdocs-cli/src/commands/serve/serve.ts @@ -117,7 +117,7 @@ export default async function serve(opts: OptionValues) { stderrLogFunc: mkdocsLogFunc, mkdocsConfigFileName: mkdocsYmlPath, mkdocsParameterClean: opts.mkdocsParameterClean, - mkdocsParameterDirty: opts.mkdocsParameterDirty, + mkdocsParameterDirtyReload: opts.mkdocsParameterDirtyReload, mkdocsParameterStrict: opts.mkdocsParameterStrict, }); diff --git a/packages/techdocs-cli/src/lib/mkdocsServer.ts b/packages/techdocs-cli/src/lib/mkdocsServer.ts index dced19cb7a..3c7f9ea5ec 100644 --- a/packages/techdocs-cli/src/lib/mkdocsServer.ts +++ b/packages/techdocs-cli/src/lib/mkdocsServer.ts @@ -27,7 +27,7 @@ export const runMkdocsServer = async (options: { stderrLogFunc?: LogFunc; mkdocsConfigFileName?: string; mkdocsParameterClean?: boolean; - mkdocsParameterDirty?: boolean; + mkdocsParameterDirtyReload?: boolean; mkdocsParameterStrict?: boolean; }): Promise => { const port = options.port ?? '8000'; @@ -58,9 +58,9 @@ export const runMkdocsServer = async (options: { ...(options.mkdocsConfigFileName ? ['--config-file', options.mkdocsConfigFileName] : []), - ...(options.mkdocsParameterClean ? '--clean' : []), - ...(options.mkdocsParameterDirty ? '--dirty' : []), - ...(options.mkdocsParameterStrict ? '--strict' : []), + ...(options.mkdocsParameterClean ? ['--clean'] : []), + ...(options.mkdocsParameterDirtyReload ? ['--dirty'] : []), + ...(options.mkdocsParameterStrict ? ['--strict'] : []), ], { stdoutLogFunc: options.stdoutLogFunc, @@ -78,9 +78,9 @@ export const runMkdocsServer = async (options: { ...(options.mkdocsConfigFileName ? ['--config-file', options.mkdocsConfigFileName] : []), - ...(options.mkdocsParameterClean ? '--clean' : []), - ...(options.mkdocsParameterDirty ? '--dirty' : []), - ...(options.mkdocsParameterStrict ? '--strict' : []), + ...(options.mkdocsParameterClean ? ['--clean'] : []), + ...(options.mkdocsParameterDirtyReload ? ['--dirtyreload'] : []), + ...(options.mkdocsParameterStrict ? ['--strict'] : []), ], { stdoutLogFunc: options.stdoutLogFunc, From 68ae3df03936cefadf50773de7a453b69795ef0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=90=E1=BB=97=20Tr=E1=BB=8Dng=20H=E1=BA=A3i?= <41283691+hainenber@users.noreply.github.com> Date: Wed, 22 Nov 2023 00:57:58 +0700 Subject: [PATCH 046/261] Update mkdocsServer.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Andre Wanlin <67169551+awanlin@users.noreply.github.com> Signed-off-by: Đỗ Trọng Hải <41283691+hainenber@users.noreply.github.com> --- packages/techdocs-cli/src/lib/mkdocsServer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/techdocs-cli/src/lib/mkdocsServer.ts b/packages/techdocs-cli/src/lib/mkdocsServer.ts index 3c7f9ea5ec..a793643367 100644 --- a/packages/techdocs-cli/src/lib/mkdocsServer.ts +++ b/packages/techdocs-cli/src/lib/mkdocsServer.ts @@ -59,7 +59,7 @@ export const runMkdocsServer = async (options: { ? ['--config-file', options.mkdocsConfigFileName] : []), ...(options.mkdocsParameterClean ? ['--clean'] : []), - ...(options.mkdocsParameterDirtyReload ? ['--dirty'] : []), + ...(options.mkdocsParameterDirtyReload ? ['--dirtyreload'] : []), ...(options.mkdocsParameterStrict ? ['--strict'] : []), ], { From fa66d1b5b31841ef04bdaa6d6ef646919d2076e6 Mon Sep 17 00:00:00 2001 From: nabiltntn Date: Mon, 20 Nov 2023 18:34:27 +0100 Subject: [PATCH 047/261] Display enum label from enumNames in review if used Signed-off-by: nabiltntn --- .changeset/funny-bobcats-try.md | 5 ++ .../ReviewState/ReviewState.test.tsx | 66 +++++++++++++++++++ .../components/ReviewState/ReviewState.tsx | 9 +++ 3 files changed, 80 insertions(+) create mode 100644 .changeset/funny-bobcats-try.md diff --git a/.changeset/funny-bobcats-try.md b/.changeset/funny-bobcats-try.md new file mode 100644 index 0000000000..c8dd2384a6 --- /dev/null +++ b/.changeset/funny-bobcats-try.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-react': patch +--- + +Fixed bug in `ReviewState` where `enum` value was displayed in step review instead of the corresponding label when using `enumNames` diff --git a/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.test.tsx b/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.test.tsx index 0f56a32d1d..7493a3fdbe 100644 --- a/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.test.tsx +++ b/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.test.tsx @@ -136,4 +136,70 @@ describe('ReviewState', () => { expect(getByRole('row', { name: 'Name lols' })).toBeInTheDocument(); }); + + it('should display enum label from enumNames', async () => { + const formState = { + name: 'type2', + }; + + const schemas: ParsedTemplateSchema[] = [ + { + mergedSchema: { + type: 'object', + properties: { + name: { + type: 'string', + default: 'type1', + enum: ['type1', 'type2', 'type3'], + enumNames: ['Label-type1', 'Label-type2', 'Label-type3'], + }, + }, + }, + schema: {}, + title: 'test', + uiSchema: {}, + description: 'asd', + }, + ]; + + const { queryByRole } = render( + , + ); + + expect( + queryByRole('row', { name: 'Name Label-type2' }), + ).toBeInTheDocument(); + }); + + it('should display enum value if no corresponding enumNames', async () => { + const formState = { + name: 'type4', + }; + + const schemas: ParsedTemplateSchema[] = [ + { + mergedSchema: { + type: 'object', + properties: { + name: { + type: 'string', + default: 'type1', + enum: ['type1', 'type2', 'type3', 'type4'], + enumNames: ['Label-type1', 'Label-type2', 'Label-type3'], + }, + }, + }, + schema: {}, + title: 'test', + uiSchema: {}, + description: 'asd', + }, + ]; + + const { queryByRole } = render( + , + ); + + expect(queryByRole('row', { name: 'Name type4' })).toBeInTheDocument(); + }); }); diff --git a/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.tsx b/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.tsx index 52ad80c4c2..38f1913ced 100644 --- a/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.tsx +++ b/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.tsx @@ -57,6 +57,15 @@ export const ReviewState = (props: ReviewStateProps) => { if (definitionInSchema['ui:widget'] === 'password') { return [key, '******']; } + + if (definitionInSchema.enum && definitionInSchema.enumNames) { + return [ + key, + definitionInSchema.enumNames[ + definitionInSchema.enum.indexOf(value) + ] || value, + ]; + } } } return [key, value]; From 78a10bb0855afa4109ea11392b2e3bf928ab90ec Mon Sep 17 00:00:00 2001 From: Jordan Snow Date: Tue, 21 Nov 2023 16:17:29 -0500 Subject: [PATCH 048/261] Adding in type chip to search results Signed-off-by: Jordan Snow --- .changeset/real-bees-thank.md | 5 +++++ .../CatalogSearchResultListItem.tsx | 1 + 2 files changed, 6 insertions(+) create mode 100644 .changeset/real-bees-thank.md diff --git a/.changeset/real-bees-thank.md b/.changeset/real-bees-thank.md new file mode 100644 index 0000000000..0c4c5a32bb --- /dev/null +++ b/.changeset/real-bees-thank.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog': patch +--- + +Adding in component type chip to search results for clarity diff --git a/plugins/catalog/src/components/CatalogSearchResultListItem/CatalogSearchResultListItem.tsx b/plugins/catalog/src/components/CatalogSearchResultListItem/CatalogSearchResultListItem.tsx index 06906aecc1..4c6b567d8a 100644 --- a/plugins/catalog/src/components/CatalogSearchResultListItem/CatalogSearchResultListItem.tsx +++ b/plugins/catalog/src/components/CatalogSearchResultListItem/CatalogSearchResultListItem.tsx @@ -107,6 +107,7 @@ export function CatalogSearchResultListItem( /> {result.kind && } + {result.type && } {result.lifecycle && ( )} From c59a046a1c0b41dc46e53a0229a31daa10269d24 Mon Sep 17 00:00:00 2001 From: Jordan Snow Date: Wed, 22 Nov 2023 10:34:02 -0500 Subject: [PATCH 049/261] Updating changeset for clarity Signed-off-by: Jordan Snow --- .changeset/real-bees-thank.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/real-bees-thank.md b/.changeset/real-bees-thank.md index 0c4c5a32bb..e89dfc7a68 100644 --- a/.changeset/real-bees-thank.md +++ b/.changeset/real-bees-thank.md @@ -2,4 +2,4 @@ '@backstage/plugin-catalog': patch --- -Adding in component type chip to search results for clarity +Adding in spec.type chip to search results for clarity From 364765cca03d40a4e1d4c130d6ecba04a81dba98 Mon Sep 17 00:00:00 2001 From: Aramis Sennyey Date: Wed, 22 Nov 2023 14:16:03 -0500 Subject: [PATCH 050/261] remove response error from template and keep parsing at the client level Signed-off-by: Aramis Sennyey --- packages/catalog-client/src/CatalogClient.ts | 268 +++++++++--------- .../src/generated/apis/DefaultApi.client.ts | 106 +------ .../typescript-backstage/api.mustache | 8 +- 3 files changed, 152 insertions(+), 230 deletions(-) diff --git a/packages/catalog-client/src/CatalogClient.ts b/packages/catalog-client/src/CatalogClient.ts index dd22a44d59..b1a50b5f07 100644 --- a/packages/catalog-client/src/CatalogClient.ts +++ b/packages/catalog-client/src/CatalogClient.ts @@ -39,24 +39,10 @@ import { GetEntitiesByRefsRequest, GetEntitiesByRefsResponse, QueryEntitiesRequest, - QueryEntitiesResponse, EntityFilterQuery, } from './types/api'; -import { DefaultApiClient } from './generated/apis/DefaultApi.client'; import { isQueryEntitiesInitialRequest } from './utils'; -import { ValidateEntity400Response } from './generated/models/ValidateEntity400Response.model'; - -const isResponseError = (e: Error): e is ResponseError => { - return (e as any).response; -}; - -const ignore404 = (responseError: Error) => { - if (!isResponseError(responseError)) throw responseError; - if (responseError.response.status === 404) { - return undefined; - } - throw responseError; -}; +import { DefaultApiClient } from './generated'; /** * A frontend and backend compatible client for communicating with the Backstage @@ -81,10 +67,12 @@ export class CatalogClient implements CatalogApi { request: GetEntityAncestorsRequest, options?: CatalogRequestOptions, ): Promise { - const { kind, namespace, name } = parseEntityRef(request.entityRef); - return await this.apiClient - .getEntityAncestryByName({ path: { kind, namespace, name } }, options) - .then(r => r.json()); + return await this.requestRequired( + await this.apiClient.getEntityAncestryByName( + { path: parseEntityRef(request.entityRef) }, + options, + ), + ); } /** @@ -94,13 +82,9 @@ export class CatalogClient implements CatalogApi { id: string, options?: CatalogRequestOptions, ): Promise { - try { - return await this.apiClient - .getLocation({ path: { id } }, options) - .then(r => r.json()); - } catch (e) { - return ignore404(e); - } + return await this.requestOptional( + await this.apiClient.getLocation({ path: { id } }, options), + ); } /** @@ -131,21 +115,21 @@ export class CatalogClient implements CatalogApi { } } - const entities: Entity[] = await this.apiClient - .getEntities( + const entities: Entity[] = await this.requestRequired( + await this.apiClient.getEntities( { query: { - fields: fields.map(encodeURIComponent), limit, - filter: this.getFilterValue(filter), offset, after, + filter: this.getFilterValue(filter), + fields, order: order ? encodedOrder : undefined, }, }, options, - ) - .then(r => r.json()); + ), + ); const refCompare = (a: Entity, b: Entity) => { // in case field filtering is used, these fields might not be part of the response @@ -179,9 +163,23 @@ export class CatalogClient implements CatalogApi { request: GetEntitiesByRefsRequest, options?: CatalogRequestOptions, ): Promise { - const { items } = await this.apiClient - .getEntitiesByRefs({ body: request }, options) - .then(r => r.json()); + const response = await this.apiClient.getEntitiesByRefs( + { + body: { + entityRefs: request.entityRefs, + fields: request.fields?.length ? request.fields : undefined, + }, + }, + options, + ); + + if (!response.ok) { + throw await ResponseError.fromResponse(response); + } + + const { items } = (await response.json()) as { + items: Array; + }; return { items: items.map(i => i ?? undefined) }; } @@ -192,7 +190,7 @@ export class CatalogClient implements CatalogApi { async queryEntities( request: QueryEntitiesRequest = {}, options?: CatalogRequestOptions, - ): Promise { + ) { const params: Partial< Parameters[0]['query'] > = {}; @@ -238,7 +236,7 @@ export class CatalogClient implements CatalogApi { } } - return await this.apiClient + return this.apiClient .getEntitiesByQuery({ query: params }, options) .then(r => r.json()); } @@ -250,13 +248,14 @@ export class CatalogClient implements CatalogApi { entityRef: string | CompoundEntityRef, options?: CatalogRequestOptions, ): Promise { - try { - return await this.apiClient - .getEntityByName({ path: { ...parseEntityRef(entityRef) } }, options) - .then(r => r.json()); - } catch (e) { - return ignore404(e); - } + return this.requestOptional( + await this.apiClient.getEntityByName( + { + path: parseEntityRef(entityRef), + }, + options, + ), + ); } // NOTE(freben): When we deprecate getEntityByName from the interface, we may @@ -271,36 +270,26 @@ export class CatalogClient implements CatalogApi { options?: CatalogRequestOptions, ): Promise { const { kind, namespace = 'default', name } = compoundName; - try { - return await this.apiClient - .getEntityByName( - { - path: { - kind, - namespace, - name, - }, - }, - options, - ) - .then(r => r.json()); - } catch (e) { - return ignore404(e); - } + return this.requestOptional( + await this.apiClient.getEntityByName( + { path: { kind, namespace, name } }, + options, + ), + ); } /** * {@inheritdoc CatalogApi.refreshEntity} */ async refreshEntity(entityRef: string, options?: CatalogRequestOptions) { - await this.apiClient.refreshEntity( - { - body: { - entityRef, - }, - }, + const response = await this.apiClient.refreshEntity( + { body: { entityRef } }, options, ); + + if (response.status !== 200) { + throw new Error(await response.text()); + } } /** @@ -311,22 +300,14 @@ export class CatalogClient implements CatalogApi { options?: CatalogRequestOptions, ): Promise { const { filter = [], facets } = request; - - try { - return await this.apiClient - .getEntityFacets( - { - query: { - facet: facets, - filter: this.getFilterValue(filter), - }, - }, - options, - ) - .then(r => r.json()); - } catch (e) { - return ignore404(e) as any; - } + return await this.requestOptional( + await this.apiClient.getEntityFacets( + { + query: { facet: facets, filter: this.getFilterValue(filter) }, + }, + options, + ), + ); } /** @@ -338,18 +319,19 @@ export class CatalogClient implements CatalogApi { ): Promise { const { type = 'url', target, dryRun } = request; - const { location, entities, exists } = await this.apiClient - .createLocation( - { - body: { - type, - target, - }, - query: { dryRun: dryRun ? 'true' : undefined }, - }, - options, - ) - .then(r => r.json()); + const response = await this.apiClient.createLocation( + { + body: { type, target }, + query: { dryRun: dryRun ? 'true' : undefined }, + }, + options, + ); + + if (response.status !== 201) { + throw new Error(await response.text()); + } + + const { location, entities, exists } = await response.json(); if (!location) { throw new Error(`Location wasn't added: ${target}`); @@ -369,9 +351,9 @@ export class CatalogClient implements CatalogApi { locationRef: string, options?: CatalogRequestOptions, ): Promise { - const all: { data: Location }[] = await this.apiClient - .getLocations({}, options) - .then(r => r.json()); + const all: { data: Location }[] = await this.requestRequired( + await this.apiClient.getLocation({ path: { id: locationRef } }, options), + ); return all .map(r => r.data) .find(l => locationRef === stringifyLocationRef(l)); @@ -384,11 +366,9 @@ export class CatalogClient implements CatalogApi { id: string, options?: CatalogRequestOptions, ): Promise { - try { - await this.apiClient.deleteLocation({ path: { id } }, options); - } catch (e) { - ignore404(e); - } + await this.requestIgnored( + await this.apiClient.deleteLocation({ path: { id } }, options), + ); } /** @@ -398,11 +378,9 @@ export class CatalogClient implements CatalogApi { uid: string, options?: CatalogRequestOptions, ): Promise { - try { - await this.apiClient.deleteEntityByUid({ path: { uid } }, options); - } catch (e) { - ignore404(e); - } + await this.requestIgnored( + await this.apiClient.deleteEntityByUid({ path: { uid } }, options), + ); } /** @@ -413,38 +391,64 @@ export class CatalogClient implements CatalogApi { locationRef: string, options?: CatalogRequestOptions, ): Promise { - try { - await this.apiClient.validateEntity( - { - body: { - entity, - location: locationRef, - }, - }, - options, - ); + const response = await this.apiClient.validateEntity( + { body: { entity, location: locationRef } }, + options, + ); + if (response.ok) { return { valid: true, }; - } catch (e) { - if (!isResponseError(e)) throw e; - const { response, rawBody } = e; - if (response.status !== 400) { - throw e; - } - // TODO: This needs to be fixed as is, this won't actually do anything. - const { errors = [] } = JSON.parse(rawBody) as ValidateEntity400Response; + } - return { - valid: false, - errors, - }; + if (response.status !== 400) { + throw await ResponseError.fromResponse(response); + } + + const { errors = [] } = (await response.json()) as any; + + return { + valid: false, + errors, + }; + } + + // + // Private methods + // + + private async requestIgnored(response: Response): Promise { + if (!response.ok) { + throw await ResponseError.fromResponse(response); } } + private async requestRequired(response: Response): Promise { + if (!response.ok) { + throw await ResponseError.fromResponse(response); + } + + return response.json(); + } + + private async requestOptional(response: Response): Promise { + if (!response.ok) { + if (response.status === 404) { + return undefined; + } + throw await ResponseError.fromResponse(response); + } + + return await response.json(); + } + private getFilterValue(filter: EntityFilterQuery = []) { - const values: string[] = []; + const filters: string[] = []; + // filter param can occur multiple times, for example + // /api/catalog/entities?filter=metadata.name=wayback-search,kind=component&filter=metadata.name=www-artist,kind=component' + // the "outer array" defined by `filter` occurrences corresponds to "anyOf" filters + // the "inner array" defined within a `filter` param corresponds to "allOf" filters for (const filterItem of [filter].flat()) { const filterParts: string[] = []; for (const [key, value] of Object.entries(filterItem)) { @@ -460,9 +464,9 @@ export class CatalogClient implements CatalogApi { } if (filterParts.length) { - values.push(filterParts.join(',')); + filters.push(filterParts.join(',')); } } - return values; + return filters; } } diff --git a/packages/catalog-client/src/generated/apis/DefaultApi.client.ts b/packages/catalog-client/src/generated/apis/DefaultApi.client.ts index 11a0b33bc8..260f7c9fc8 100644 --- a/packages/catalog-client/src/generated/apis/DefaultApi.client.ts +++ b/packages/catalog-client/src/generated/apis/DefaultApi.client.ts @@ -19,7 +19,6 @@ import { FetchApi } from '../types/fetch'; import crossFetch from 'cross-fetch'; import { pluginId } from '../pluginId'; import * as parser from 'uri-template'; -import { ResponseError } from '@backstage/errors'; import { AnalyzeLocationRequest } from '../models/AnalyzeLocationRequest.model'; import { AnalyzeLocationResponse } from '../models/AnalyzeLocationResponse.model'; @@ -81,8 +80,7 @@ export class DefaultApiClient { const uri = parser.parse(uriTemplate).expand({}); - const url = `${baseUrl}${uri}`; - const response = await this.fetchApi.fetch(url, { + return await this.fetchApi.fetch(`${baseUrl}${uri}`, { headers: { 'Content-Type': 'application/json', ...(options?.token && { Authorization: `Bearer ${options?.token}` }), @@ -90,10 +88,6 @@ export class DefaultApiClient { method: 'POST', body: JSON.stringify(request.body), }); - if (response.ok) { - return response; - } - throw await ResponseError.fromResponse(response); } /** @@ -119,8 +113,7 @@ export class DefaultApiClient { ...request.query, }); - const url = `${baseUrl}${uri}`; - const response = await this.fetchApi.fetch(url, { + return await this.fetchApi.fetch(`${baseUrl}${uri}`, { headers: { 'Content-Type': 'application/json', ...(options?.token && { Authorization: `Bearer ${options?.token}` }), @@ -128,10 +121,6 @@ export class DefaultApiClient { method: 'POST', body: JSON.stringify(request.body), }); - if (response.ok) { - return response; - } - throw await ResponseError.fromResponse(response); } /** @@ -155,18 +144,13 @@ export class DefaultApiClient { uid: request.path.uid, }); - const url = `${baseUrl}${uri}`; - const response = await this.fetchApi.fetch(url, { + return await this.fetchApi.fetch(`${baseUrl}${uri}`, { headers: { 'Content-Type': 'application/json', ...(options?.token && { Authorization: `Bearer ${options?.token}` }), }, method: 'DELETE', }); - if (response.ok) { - return response; - } - throw await ResponseError.fromResponse(response); } /** @@ -190,18 +174,13 @@ export class DefaultApiClient { id: request.path.id, }); - const url = `${baseUrl}${uri}`; - const response = await this.fetchApi.fetch(url, { + return await this.fetchApi.fetch(`${baseUrl}${uri}`, { headers: { 'Content-Type': 'application/json', ...(options?.token && { Authorization: `Bearer ${options?.token}` }), }, method: 'DELETE', }); - if (response.ok) { - return response; - } - throw await ResponseError.fromResponse(response); } /** @@ -235,18 +214,13 @@ export class DefaultApiClient { ...request.query, }); - const url = `${baseUrl}${uri}`; - const response = await this.fetchApi.fetch(url, { + return await this.fetchApi.fetch(`${baseUrl}${uri}`, { headers: { 'Content-Type': 'application/json', ...(options?.token && { Authorization: `Bearer ${options?.token}` }), }, method: 'GET', }); - if (response.ok) { - return response; - } - throw await ResponseError.fromResponse(response); } /** @@ -282,18 +256,13 @@ export class DefaultApiClient { ...request.query, }); - const url = `${baseUrl}${uri}`; - const response = await this.fetchApi.fetch(url, { + return await this.fetchApi.fetch(`${baseUrl}${uri}`, { headers: { 'Content-Type': 'application/json', ...(options?.token && { Authorization: `Bearer ${options?.token}` }), }, method: 'GET', }); - if (response.ok) { - return response; - } - throw await ResponseError.fromResponse(response); } /** @@ -313,8 +282,7 @@ export class DefaultApiClient { const uri = parser.parse(uriTemplate).expand({}); - const url = `${baseUrl}${uri}`; - const response = await this.fetchApi.fetch(url, { + return await this.fetchApi.fetch(`${baseUrl}${uri}`, { headers: { 'Content-Type': 'application/json', ...(options?.token && { Authorization: `Bearer ${options?.token}` }), @@ -322,10 +290,6 @@ export class DefaultApiClient { method: 'POST', body: JSON.stringify(request.body), }); - if (response.ok) { - return response; - } - throw await ResponseError.fromResponse(response); } /** @@ -355,18 +319,13 @@ export class DefaultApiClient { name: request.path.name, }); - const url = `${baseUrl}${uri}`; - const response = await this.fetchApi.fetch(url, { + return await this.fetchApi.fetch(`${baseUrl}${uri}`, { headers: { 'Content-Type': 'application/json', ...(options?.token && { Authorization: `Bearer ${options?.token}` }), }, method: 'GET', }); - if (response.ok) { - return response; - } - throw await ResponseError.fromResponse(response); } /** @@ -396,18 +355,13 @@ export class DefaultApiClient { name: request.path.name, }); - const url = `${baseUrl}${uri}`; - const response = await this.fetchApi.fetch(url, { + return await this.fetchApi.fetch(`${baseUrl}${uri}`, { headers: { 'Content-Type': 'application/json', ...(options?.token && { Authorization: `Bearer ${options?.token}` }), }, method: 'GET', }); - if (response.ok) { - return response; - } - throw await ResponseError.fromResponse(response); } /** @@ -431,18 +385,13 @@ export class DefaultApiClient { uid: request.path.uid, }); - const url = `${baseUrl}${uri}`; - const response = await this.fetchApi.fetch(url, { + return await this.fetchApi.fetch(`${baseUrl}${uri}`, { headers: { 'Content-Type': 'application/json', ...(options?.token && { Authorization: `Bearer ${options?.token}` }), }, method: 'GET', }); - if (response.ok) { - return response; - } - throw await ResponseError.fromResponse(response); } /** @@ -468,18 +417,13 @@ export class DefaultApiClient { ...request.query, }); - const url = `${baseUrl}${uri}`; - const response = await this.fetchApi.fetch(url, { + return await this.fetchApi.fetch(`${baseUrl}${uri}`, { headers: { 'Content-Type': 'application/json', ...(options?.token && { Authorization: `Bearer ${options?.token}` }), }, method: 'GET', }); - if (response.ok) { - return response; - } - throw await ResponseError.fromResponse(response); } /** @@ -503,18 +447,13 @@ export class DefaultApiClient { id: request.path.id, }); - const url = `${baseUrl}${uri}`; - const response = await this.fetchApi.fetch(url, { + return await this.fetchApi.fetch(`${baseUrl}${uri}`, { headers: { 'Content-Type': 'application/json', ...(options?.token && { Authorization: `Bearer ${options?.token}` }), }, method: 'GET', }); - if (response.ok) { - return response; - } - throw await ResponseError.fromResponse(response); } /** @@ -531,18 +470,13 @@ export class DefaultApiClient { const uri = parser.parse(uriTemplate).expand({}); - const url = `${baseUrl}${uri}`; - const response = await this.fetchApi.fetch(url, { + return await this.fetchApi.fetch(`${baseUrl}${uri}`, { headers: { 'Content-Type': 'application/json', ...(options?.token && { Authorization: `Bearer ${options?.token}` }), }, method: 'GET', }); - if (response.ok) { - return response; - } - throw await ResponseError.fromResponse(response); } /** @@ -562,8 +496,7 @@ export class DefaultApiClient { const uri = parser.parse(uriTemplate).expand({}); - const url = `${baseUrl}${uri}`; - const response = await this.fetchApi.fetch(url, { + return await this.fetchApi.fetch(`${baseUrl}${uri}`, { headers: { 'Content-Type': 'application/json', ...(options?.token && { Authorization: `Bearer ${options?.token}` }), @@ -571,10 +504,6 @@ export class DefaultApiClient { method: 'POST', body: JSON.stringify(request.body), }); - if (response.ok) { - return response; - } - throw await ResponseError.fromResponse(response); } /** @@ -594,8 +523,7 @@ export class DefaultApiClient { const uri = parser.parse(uriTemplate).expand({}); - const url = `${baseUrl}${uri}`; - const response = await this.fetchApi.fetch(url, { + return await this.fetchApi.fetch(`${baseUrl}${uri}`, { headers: { 'Content-Type': 'application/json', ...(options?.token && { Authorization: `Bearer ${options?.token}` }), @@ -603,9 +531,5 @@ export class DefaultApiClient { method: 'POST', body: JSON.stringify(request.body), }); - if (response.ok) { - return response; - } - throw await ResponseError.fromResponse(response); } } diff --git a/packages/repo-tools/templates/typescript-backstage/api.mustache b/packages/repo-tools/templates/typescript-backstage/api.mustache index e2e1ae4b3b..1b8739ba57 100644 --- a/packages/repo-tools/templates/typescript-backstage/api.mustache +++ b/packages/repo-tools/templates/typescript-backstage/api.mustache @@ -4,7 +4,6 @@ import { FetchApi } from '../types/fetch'; import crossFetch from 'cross-fetch'; import {pluginId} from '../pluginId'; import * as parser from 'uri-template'; -import {ResponseError} from '@backstage/errors'; {{#imports}} import { {{classname}} } from '{{filename}}.model{{importFileExtension}}'; @@ -97,8 +96,7 @@ export class {{classname}}Client { {{/hasQueryParams}} }) - const url = `${baseUrl}${uri}`; - const response = await this.fetchApi.fetch(url, { + return await this.fetchApi.fetch(`${baseUrl}${uri}`, { headers: { {{#hasHeaderParams}} ...request.header, @@ -109,10 +107,6 @@ export class {{classname}}Client { method: '{{httpMethod}}', {{#hasBodyParam}} body: JSON.stringify(request.body), {{/hasBodyParam}} }); - if(response.ok){ - return response; - }; - throw await ResponseError.fromResponse(response); } {{/operation}} From 004f74eb48c48d61638ecc6ac0922d6de4c2feb5 Mon Sep 17 00:00:00 2001 From: Aramis Sennyey Date: Wed, 22 Nov 2023 14:17:05 -0500 Subject: [PATCH 051/261] remove packages/errors changes Signed-off-by: Aramis Sennyey --- packages/errors/api-report.md | 9 -------- packages/errors/src/errors/ResponseError.ts | 23 ++----------------- packages/errors/src/errors/types.ts | 1 - packages/errors/src/serialization/response.ts | 22 +----------------- 4 files changed, 3 insertions(+), 52 deletions(-) diff --git a/packages/errors/api-report.md b/packages/errors/api-report.md index 42da6e28a6..3ece63035b 100644 --- a/packages/errors/api-report.md +++ b/packages/errors/api-report.md @@ -34,7 +34,6 @@ export type ConsumedResponse = { values(): IterableIterator; [Symbol.iterator](): Iterator<[string, string]>; }; - readonly bodyUsed: boolean; readonly ok: boolean; readonly redirected: boolean; readonly status: number; @@ -112,12 +111,6 @@ export class NotModifiedError extends CustomErrorBase { name: 'NotModifiedError'; } -// @public -export function parseErrorResponseBody( - response: ConsumedResponse, - rawBody: string, -): Promise; - // @public export function parseErrorResponseBody( response: ConsumedResponse & { @@ -132,10 +125,8 @@ export class ResponseError extends Error { static fromResponse( response: ConsumedResponse & { text(): Promise; - bodyUsed: boolean; }, ): Promise; - readonly rawBody: string; readonly response: ConsumedResponse; } diff --git a/packages/errors/src/errors/ResponseError.ts b/packages/errors/src/errors/ResponseError.ts index 0fff541218..f8ba0a1ba1 100644 --- a/packages/errors/src/errors/ResponseError.ts +++ b/packages/errors/src/errors/ResponseError.ts @@ -42,11 +42,6 @@ export class ResponseError extends Error { */ readonly body: ErrorResponseBody; - /** - * The unparsed possibly JSON error body. Will be set even if the returned error doesn't match {@link ErrorResponseBody}. - */ - readonly rawBody: string; - /** * The Error cause, as seen by the remote server. This is parsed out of the * JSON error body. @@ -66,20 +61,9 @@ export class ResponseError extends Error { * been consumed before. */ static async fromResponse( - response: ConsumedResponse & { text(): Promise; bodyUsed: boolean }, + response: ConsumedResponse & { text(): Promise }, ): Promise { - let rawBody = ''; - try { - rawBody = await response.text(); - } catch { - // ignore - } - - const data = await parseErrorResponseBody( - // TS isn't smart enough to know that this is done under the hood, - response, - rawBody, - ); + const data = await parseErrorResponseBody(response); const status = data.response.statusCode || response.status; const statusText = data.error.name || response.statusText; @@ -91,7 +75,6 @@ export class ResponseError extends Error { response, data, cause, - rawBody, }); } @@ -99,7 +82,6 @@ export class ResponseError extends Error { message: string; response: ConsumedResponse; data: ErrorResponseBody; - rawBody: string; cause: Error; }) { super(props.message); @@ -107,6 +89,5 @@ export class ResponseError extends Error { this.response = props.response; this.body = props.data; this.cause = props.cause; - this.rawBody = props.rawBody; } } diff --git a/packages/errors/src/errors/types.ts b/packages/errors/src/errors/types.ts index b4b00f2707..b0e86fd19a 100644 --- a/packages/errors/src/errors/types.ts +++ b/packages/errors/src/errors/types.ts @@ -34,7 +34,6 @@ export type ConsumedResponse = { values(): IterableIterator; [Symbol.iterator](): Iterator<[string, string]>; }; - readonly bodyUsed: boolean; readonly ok: boolean; readonly redirected: boolean; readonly status: number; diff --git a/packages/errors/src/serialization/response.ts b/packages/errors/src/serialization/response.ts index c7d45465db..60894b243e 100644 --- a/packages/errors/src/serialization/response.ts +++ b/packages/errors/src/serialization/response.ts @@ -41,19 +41,6 @@ export type ErrorResponseBody = { }; }; -/** - * Attempts to construct an ErrorResponseBody out of a failed server request. - * Assumes that the response has already been checked to be not ok. This function - * expects that rawBody is the body of the response and will not attempt to - * parse the body from the response again. - * - * @public - * @param response - The response of a failed request - */ -export async function parseErrorResponseBody( - response: ConsumedResponse, - rawBody: string, -): Promise; /** * Attempts to construct an ErrorResponseBody out of a failed server request. * Assumes that the response has already been checked to be not ok. This @@ -68,16 +55,9 @@ export async function parseErrorResponseBody( */ export async function parseErrorResponseBody( response: ConsumedResponse & { text(): Promise }, -): Promise; -export async function parseErrorResponseBody( - response: ConsumedResponse | (ConsumedResponse & { text(): Promise }), - rawBody?: string, ): Promise { try { - const text = - !response.bodyUsed && 'text' in response - ? await response.text() - : rawBody; + const text = await response.text(); if (text) { if ( response.headers.get('content-type')?.startsWith('application/json') From 77e7ccde8136880b4c14e1d1de03fd0e09f4b3d0 Mon Sep 17 00:00:00 2001 From: Aramis Sennyey Date: Wed, 22 Nov 2023 14:48:08 -0500 Subject: [PATCH 052/261] add return type for queryEntities Signed-off-by: Aramis Sennyey --- packages/catalog-client/src/CatalogClient.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/catalog-client/src/CatalogClient.ts b/packages/catalog-client/src/CatalogClient.ts index b1a50b5f07..f5849503e7 100644 --- a/packages/catalog-client/src/CatalogClient.ts +++ b/packages/catalog-client/src/CatalogClient.ts @@ -40,6 +40,7 @@ import { GetEntitiesByRefsResponse, QueryEntitiesRequest, EntityFilterQuery, + QueryEntitiesResponse, } from './types/api'; import { isQueryEntitiesInitialRequest } from './utils'; import { DefaultApiClient } from './generated'; @@ -190,7 +191,7 @@ export class CatalogClient implements CatalogApi { async queryEntities( request: QueryEntitiesRequest = {}, options?: CatalogRequestOptions, - ) { + ): Promise { const params: Partial< Parameters[0]['query'] > = {}; From a10b5bb164a50071febc393da47c4fb34202d83d Mon Sep 17 00:00:00 2001 From: Aramis Sennyey Date: Wed, 22 Nov 2023 15:11:17 -0500 Subject: [PATCH 053/261] fix encoding issue Signed-off-by: Aramis Sennyey --- packages/catalog-client/src/CatalogClient.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/catalog-client/src/CatalogClient.ts b/packages/catalog-client/src/CatalogClient.ts index f5849503e7..965690cc8c 100644 --- a/packages/catalog-client/src/CatalogClient.ts +++ b/packages/catalog-client/src/CatalogClient.ts @@ -120,11 +120,11 @@ export class CatalogClient implements CatalogApi { await this.apiClient.getEntities( { query: { + fields: fields.map(encodeURIComponent), limit, + filter: this.getFilterValue(filter), offset, after, - filter: this.getFilterValue(filter), - fields, order: order ? encodedOrder : undefined, }, }, From d80662d86e66d9664f12d6658883825d31703811 Mon Sep 17 00:00:00 2001 From: Aramis Sennyey Date: Wed, 22 Nov 2023 15:11:47 -0500 Subject: [PATCH 054/261] update to just be request Signed-off-by: Aramis Sennyey --- packages/catalog-client/src/CatalogClient.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/catalog-client/src/CatalogClient.ts b/packages/catalog-client/src/CatalogClient.ts index 965690cc8c..511bf45c51 100644 --- a/packages/catalog-client/src/CatalogClient.ts +++ b/packages/catalog-client/src/CatalogClient.ts @@ -166,10 +166,7 @@ export class CatalogClient implements CatalogApi { ): Promise { const response = await this.apiClient.getEntitiesByRefs( { - body: { - entityRefs: request.entityRefs, - fields: request.fields?.length ? request.fields : undefined, - }, + body: request, }, options, ); From f88b2da6c9741d35234d31cdfef9e305a4f0b624 Mon Sep 17 00:00:00 2001 From: Djam Date: Thu, 23 Nov 2023 09:59:27 +0100 Subject: [PATCH 055/261] Update packages/backend/package.json Co-authored-by: Vincenzo Scamporlino Signed-off-by: Djam --- packages/backend/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/backend/package.json b/packages/backend/package.json index e1e6184a77..e3b4fdb39d 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -35,7 +35,6 @@ "@backstage/plugin-adr-backend": "workspace:^", "@backstage/plugin-app-backend": "workspace:^", "@backstage/plugin-auth-backend": "workspace:^", - "@backstage/plugin-auth-backend-module-oauth2-proxy-provider": "workspace:^", "@backstage/plugin-auth-node": "workspace:^", "@backstage/plugin-azure-devops-backend": "workspace:^", "@backstage/plugin-azure-sites-backend": "workspace:^", From 84ea519a28e0191a25957edc62dfa8cb27c36ca8 Mon Sep 17 00:00:00 2001 From: djamaile Date: Thu, 23 Nov 2023 10:00:57 +0100 Subject: [PATCH 056/261] chore: update package.json Signed-off-by: djamaile --- plugins/auth-backend-module-oauth2-proxy-provider/package.json | 1 - yarn.lock | 2 -- 2 files changed, 3 deletions(-) diff --git a/plugins/auth-backend-module-oauth2-proxy-provider/package.json b/plugins/auth-backend-module-oauth2-proxy-provider/package.json index 086de08222..be5617eb69 100644 --- a/plugins/auth-backend-module-oauth2-proxy-provider/package.json +++ b/plugins/auth-backend-module-oauth2-proxy-provider/package.json @@ -26,7 +26,6 @@ "@backstage/backend-common": "workspace:^", "@backstage/backend-plugin-api": "workspace:^", "@backstage/errors": "workspace:^", - "@backstage/plugin-auth-backend": "workspace:^", "@backstage/plugin-auth-node": "workspace:^", "jose": "^4.6.0" }, diff --git a/yarn.lock b/yarn.lock index 8c3ccd6c87..2da94ee04f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4681,7 +4681,6 @@ __metadata: "@backstage/backend-test-utils": "workspace:^" "@backstage/cli": "workspace:^" "@backstage/errors": "workspace:^" - "@backstage/plugin-auth-backend": "workspace:^" "@backstage/plugin-auth-node": "workspace:^" jose: ^4.6.0 languageName: unknown @@ -26343,7 +26342,6 @@ __metadata: "@backstage/plugin-adr-backend": "workspace:^" "@backstage/plugin-app-backend": "workspace:^" "@backstage/plugin-auth-backend": "workspace:^" - "@backstage/plugin-auth-backend-module-oauth2-proxy-provider": "workspace:^" "@backstage/plugin-auth-node": "workspace:^" "@backstage/plugin-azure-devops-backend": "workspace:^" "@backstage/plugin-azure-sites-backend": "workspace:^" From 8591bf489cd5eb4a8bc465b3deb012a2cc622f3e Mon Sep 17 00:00:00 2001 From: djamaile Date: Thu, 23 Nov 2023 10:12:12 +0100 Subject: [PATCH 057/261] chore: update import Signed-off-by: djamaile --- .../auth-backend-module-oauth2-proxy-provider/src/resolvers.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/auth-backend-module-oauth2-proxy-provider/src/resolvers.ts b/plugins/auth-backend-module-oauth2-proxy-provider/src/resolvers.ts index 9b337fc80a..99ca8bc156 100644 --- a/plugins/auth-backend-module-oauth2-proxy-provider/src/resolvers.ts +++ b/plugins/auth-backend-module-oauth2-proxy-provider/src/resolvers.ts @@ -18,7 +18,7 @@ import { createSignInResolverFactory, SignInInfo, } from '@backstage/plugin-auth-node'; -import { OAuth2ProxyResult } from '@backstage/plugin-auth-backend'; +import { OAuth2ProxyResult } from './types'; /** * @public From 2717528ddb12798915ee002a587ba59ee9977f8e Mon Sep 17 00:00:00 2001 From: Philipp Hugenroth Date: Thu, 23 Nov 2023 14:24:00 +0100 Subject: [PATCH 058/261] Update microsite/sidebars.json Co-authored-by: Camila Belo Signed-off-by: Philipp Hugenroth --- microsite/sidebars.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/microsite/sidebars.json b/microsite/sidebars.json index c33bf37785..fb513697cb 100644 --- a/microsite/sidebars.json +++ b/microsite/sidebars.json @@ -409,7 +409,7 @@ "tutorials/switching-sqlite-postgres", "tutorials/using-backstage-proxy-within-plugin", "tutorials/yarn-migration", - "tutorials/migrate-to-mui5.md" + "tutorials/migrate-to-mui5" ], "Architecture Decision Records (ADRs)": [ "architecture-decisions/adrs-overview", From d8133b281d8febefa17ccc613ee5b770f78408a4 Mon Sep 17 00:00:00 2001 From: Andre Wanlin Date: Thu, 23 Nov 2023 13:18:13 -0600 Subject: [PATCH 059/261] Added Plugin Directory Submission Tips Signed-off-by: Andre Wanlin --- REVIEWING.md | 10 ++++++++++ docs/plugins/add-to-directory.md | 11 +++++++++++ 2 files changed, 21 insertions(+) diff --git a/REVIEWING.md b/REVIEWING.md index 7ed3fcda57..c443c15d77 100644 --- a/REVIEWING.md +++ b/REVIEWING.md @@ -349,3 +349,13 @@ type LabelStyle = 'normal' | 'thin'; // Output, since it's an exported constant const LABEL_SIZE: number; ``` + +## Plugin Directory Submissions + +When reviewing Plugin Directory submissions please consider the following: + +- Check to make sure they have the rights for any icon being used. This is mostly for clearly copyrighted logos, for example the Microsoft Azure DevOps logo +- Make sure the package has been published on the NPM registry. +- Make sure the package on NPM has a link back to the code repo, this helps provide confidence that it's the right package. +- If they use an [NPM scope](https://docs.npmjs.com/about-scopes) make sure it that matches either the Organization name or user name, this provides trust in the plugin +- If the plugin has both a frontend and backend make sure that the documentation notes that. diff --git a/docs/plugins/add-to-directory.md b/docs/plugins/add-to-directory.md index dfa43c2ed7..518d557140 100644 --- a/docs/plugins/add-to-directory.md +++ b/docs/plugins/add-to-directory.md @@ -25,3 +25,14 @@ iconUrl: # Used as the src attribute for your logo. npmPackageName: # Your npm package name E.g. '@backstage/plugin-' quotes are required addedDate: # The date plugin added to directory E.g. '2022-10-01' quotes are required ``` + +## Submission Tips + +Here are a few tips to help speed up the review process when you submit your plugin: + +- For any icon that you use make sure you have the proper rights to use it. +- Make sure that your package had been published on the NPM registry and that it's public. +- Make sure your package on NPM has a link back to your code repo, this helps provide confidence that it's the right package. +- Where possible, please use an [NPM scope](https://docs.npmjs.com/about-scopes) that matches either your Organization name or user name, this provides trust in the plugin +- If your plugin has both a frontend and backend link the documentation to the frontend package but make sure it mentioned needing to install the backend package. +- Where possible include a screenshot of the features in you plugin documentation, it really does help when deciding to use a plugin. From 4f773c15f6dc18d86445e82df59551149e239899 Mon Sep 17 00:00:00 2001 From: Andre Wanlin Date: Thu, 23 Nov 2023 11:58:28 -0600 Subject: [PATCH 060/261] Bumped the default TechDocs docker image version Signed-off-by: Andre Wanlin --- .changeset/stale-bats-end.md | 5 +++++ plugins/techdocs-node/src/stages/generate/techdocs.ts | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 .changeset/stale-bats-end.md diff --git a/.changeset/stale-bats-end.md b/.changeset/stale-bats-end.md new file mode 100644 index 0000000000..e6715deba9 --- /dev/null +++ b/.changeset/stale-bats-end.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs-node': patch +--- + +Bumped the default TechDocs docker image version to the latest which was released several month ago diff --git a/plugins/techdocs-node/src/stages/generate/techdocs.ts b/plugins/techdocs-node/src/stages/generate/techdocs.ts index a4671f24a5..c5130a3f8f 100644 --- a/plugins/techdocs-node/src/stages/generate/techdocs.ts +++ b/plugins/techdocs-node/src/stages/generate/techdocs.ts @@ -53,7 +53,7 @@ export class TechdocsGenerator implements GeneratorBase { * The default docker image (and version) used to generate content. Public * and static so that techdocs-node consumers can use the same version. */ - public static readonly defaultDockerImage = 'spotify/techdocs:v1.2.1'; + public static readonly defaultDockerImage = 'spotify/techdocs:v1.2.3'; private readonly logger: Logger; private readonly containerRunner?: ContainerRunner; private readonly options: GeneratorConfig; From 684bb833f98a63ae3c730681926a98d6559cc21b Mon Sep 17 00:00:00 2001 From: Andre Wanlin Date: Thu, 23 Nov 2023 14:19:29 -0600 Subject: [PATCH 061/261] Updated API Report Signed-off-by: Andre Wanlin --- plugins/techdocs-node/api-report.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/techdocs-node/api-report.md b/plugins/techdocs-node/api-report.md index de5b5b21b8..5203d30faa 100644 --- a/plugins/techdocs-node/api-report.md +++ b/plugins/techdocs-node/api-report.md @@ -264,7 +264,7 @@ export class TechdocsGenerator implements GeneratorBase { config: Config; scmIntegrations: ScmIntegrationRegistry; }); - static readonly defaultDockerImage = 'spotify/techdocs:v1.2.1'; + static readonly defaultDockerImage = 'spotify/techdocs:v1.2.3'; static fromConfig( config: Config, options: GeneratorOptions, From 960a311375875fa6334102cd2b239ec08fd52cf2 Mon Sep 17 00:00:00 2001 From: Frank Kong Date: Thu, 23 Nov 2023 21:50:07 -0500 Subject: [PATCH 062/261] chore(backend-app-api): added redacting of secrets for stack traces that appear in logs Signed-off-by: Frank Kong --- .../src/logging/WinstonLogger.test.ts | 32 +++++++++++++------ .../src/logging/WinstonLogger.ts | 3 ++ 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/packages/backend-app-api/src/logging/WinstonLogger.test.ts b/packages/backend-app-api/src/logging/WinstonLogger.test.ts index 5d8cfc9c90..e05e47ee1d 100644 --- a/packages/backend-app-api/src/logging/WinstonLogger.test.ts +++ b/packages/backend-app-api/src/logging/WinstonLogger.test.ts @@ -14,25 +14,37 @@ * limitations under the License. */ +import { TransformableInfo } from 'logform'; import { WinstonLogger } from './WinstonLogger'; -function msg(message: string) { - return { message, level: 'info' }; +function msg(info: TransformableInfo): TransformableInfo { + return { message: info.message, level: info.level, stack: info.stack }; } describe('WinstonLogger', () => { it('redacter should redact and escape regex', () => { const redacter = WinstonLogger.redacter(); - expect(redacter.format.transform(msg('hello (world)'))).toEqual( - msg('hello (world)'), - ); + const log = { + level: 'error', + message: 'hello (world)', + stack: 'hello (world) from this file', + }; + expect(redacter.format.transform(msg(log))).toEqual(msg(log)); redacter.add(['hello']); - expect(redacter.format.transform(msg('hello (world)'))).toEqual( - msg('[REDACTED] (world)'), + expect(redacter.format.transform(msg(log))).toEqual( + msg({ + ...log, + message: '[REDACTED] (world)', + stack: '[REDACTED] (world) from this file', + }), ); - redacter.add(['(world)']); - expect(redacter.format.transform(msg('hello (world)'))).toEqual( - msg('[REDACTED] [REDACTED]'), + redacter.add(['(world']); + expect(redacter.format.transform(msg(log))).toEqual( + msg({ + ...log, + message: '[REDACTED] [REDACTED])', + stack: '[REDACTED] [REDACTED]) from this file', + }), ); }); }); diff --git a/packages/backend-app-api/src/logging/WinstonLogger.ts b/packages/backend-app-api/src/logging/WinstonLogger.ts index 06a189508b..bfceb5b2f2 100644 --- a/packages/backend-app-api/src/logging/WinstonLogger.ts +++ b/packages/backend-app-api/src/logging/WinstonLogger.ts @@ -82,6 +82,9 @@ export class WinstonLogger implements RootLoggerService { if (redactionPattern && typeof info.message === 'string') { info.message = info.message.replace(redactionPattern, '[REDACTED]'); } + if (redactionPattern && typeof info.stack === 'string') { + info.stack = info.stack.replace(redactionPattern, '[REDACTED]'); + } return info; })(), add(newRedactions) { From 9f8f266ff44ded625a9ca237b8a70b409a6e7517 Mon Sep 17 00:00:00 2001 From: Frank Kong Date: Thu, 23 Nov 2023 21:56:41 -0500 Subject: [PATCH 063/261] chore: add changeset Signed-off-by: Frank Kong --- .changeset/khaki-clocks-happen.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/khaki-clocks-happen.md diff --git a/.changeset/khaki-clocks-happen.md b/.changeset/khaki-clocks-happen.md new file mode 100644 index 0000000000..ac20e42dfa --- /dev/null +++ b/.changeset/khaki-clocks-happen.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-app-api': patch +--- + +Add redacting for secrets in stack traces of logs From cee1420eb727e8e81600dd7a3bc7fb4a2b4624f8 Mon Sep 17 00:00:00 2001 From: Abhishek Date: Fri, 24 Nov 2023 12:37:25 +0530 Subject: [PATCH 064/261] Added hcp-consul to the microsite Signed-off-by: Abhishek --- microsite/data/plugins/hcp-consul.yaml | 10 ++++++++++ microsite/static/img/hcp-consul.svg | 17 +++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 microsite/data/plugins/hcp-consul.yaml create mode 100644 microsite/static/img/hcp-consul.svg diff --git a/microsite/data/plugins/hcp-consul.yaml b/microsite/data/plugins/hcp-consul.yaml new file mode 100644 index 0000000000..46af49e63d --- /dev/null +++ b/microsite/data/plugins/hcp-consul.yaml @@ -0,0 +1,10 @@ +--- +title: HCP Consul +author: Hashicorp +authorUrl: https://www.hashicorp.com/ +category: Infrastructure +description: View your HCP Consul clusters, services, instances in Backstage. +documentation: https://github.com/hashicorp-forge/backstage-plugin-hcp-consul/tree/main +iconUrl: img/hcp-consul.svg +npmPackageName: '@hashicorp/plugin-hcp-consul' +addedDate: '2023-11-24' diff --git a/microsite/static/img/hcp-consul.svg b/microsite/static/img/hcp-consul.svg new file mode 100644 index 0000000000..d84972585c --- /dev/null +++ b/microsite/static/img/hcp-consul.svg @@ -0,0 +1,17 @@ + +Consul Logo + + + + + + + + + + + + + + + From dd6716b43df69bfad50a922a2a20c4fe036d7421 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 24 Nov 2023 09:01:33 +0000 Subject: [PATCH 065/261] chore(deps): update dependency @types/semver to v7.5.6 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 6ba418bf3d..08b8175a5b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -19075,9 +19075,9 @@ __metadata: linkType: hard "@types/semver@npm:^7.3.12, @types/semver@npm:^7.3.8, @types/semver@npm:^7.5.0": - version: 7.5.5 - resolution: "@types/semver@npm:7.5.5" - checksum: 533e6c93d1262d65f449423d94a445f7f3db0672e7429f21b6a1636d6051dbab3a2989ddcda9b79c69bb37830931d09fc958a65305a891357f5cea3257c297f5 + version: 7.5.6 + resolution: "@types/semver@npm:7.5.6" + checksum: 563a0120ec0efcc326567db2ed920d5d98346f3638b6324ea6b50222b96f02a8add3c51a916b6897b51523aad8ac227d21d3dcf8913559f1bfc6c15b14d23037 languageName: node linkType: hard From 5acb524e9c334d0ee4016b4a234460c9df5f52aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Fri, 24 Nov 2023 11:15:01 +0100 Subject: [PATCH 066/261] make sure that local dev logs in vscode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- docs/local-dev/debugging.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/local-dev/debugging.md b/docs/local-dev/debugging.md index 68e37374f6..17a98b1c1c 100644 --- a/docs/local-dev/debugging.md +++ b/docs/local-dev/debugging.md @@ -57,6 +57,7 @@ In your `launch.json`, add a new entry with the following, ```jsonc { "name": "Start Backend", + "type": "node", "request": "launch", "args": [ "package", @@ -67,8 +68,6 @@ In your `launch.json`, add a new entry with the following, "skipFiles": [ "/**" ], - "type": "node" + "console": "integratedTerminal" }, ``` - -You may notice that the normal logs mentioned above do not get logged, this is an issue with the logging library we're using, `winston`, and is not easily solved. See [this thread](https://github.com/winstonjs/winston/issues/1544) for more information. From 07dfdf3702508b1f540add25b054988b704af26f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 24 Nov 2023 11:53:12 +0000 Subject: [PATCH 067/261] fix(deps): update dependency linkifyjs to v4.1.3 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .changeset/renovate-8d8b90d.md | 5 +++++ packages/core-components/package.json | 2 +- yarn.lock | 9 ++++++++- 3 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 .changeset/renovate-8d8b90d.md diff --git a/.changeset/renovate-8d8b90d.md b/.changeset/renovate-8d8b90d.md new file mode 100644 index 0000000000..169d480dec --- /dev/null +++ b/.changeset/renovate-8d8b90d.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-components': patch +--- + +Updated dependency `linkifyjs` to `4.1.3`. diff --git a/packages/core-components/package.json b/packages/core-components/package.json index 1c1201a320..5e3f034494 100644 --- a/packages/core-components/package.json +++ b/packages/core-components/package.json @@ -56,7 +56,7 @@ "history": "^5.0.0", "immer": "^9.0.1", "linkify-react": "4.1.3", - "linkifyjs": "4.1.2", + "linkifyjs": "4.1.3", "lodash": "^4.17.21", "pluralize": "^8.0.0", "qs": "^6.9.4", diff --git a/yarn.lock b/yarn.lock index ac8c50cc20..b3a16ed350 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4000,7 +4000,7 @@ __metadata: history: ^5.0.0 immer: ^9.0.1 linkify-react: 4.1.3 - linkifyjs: 4.1.2 + linkifyjs: 4.1.3 lodash: ^4.17.21 msw: ^1.0.0 pluralize: ^8.0.0 @@ -32604,6 +32604,13 @@ __metadata: languageName: node linkType: hard +"linkifyjs@npm:4.1.3": + version: 4.1.3 + resolution: "linkifyjs@npm:4.1.3" + checksum: 023d467499a717a49ebbfa256a80cb2811a3b038ff2593e5be0fb8a4715b0a63bf80c571838e19e120833d5b9874464f3a1448965c8eebbde8c19458b3a6c6e4 + languageName: node + linkType: hard + "lint-staged@npm:^15.0.0": version: 15.1.0 resolution: "lint-staged@npm:15.1.0" From 87dcb2a6c1a46032c77cfaa113a83d3d0075135f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 24 Nov 2023 11:59:05 +0000 Subject: [PATCH 068/261] fix(deps): update dependency react-window to v1.8.10 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index ac8c50cc20..63cef06ab4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -38991,15 +38991,15 @@ __metadata: linkType: hard "react-window@npm:^1.8.6": - version: 1.8.9 - resolution: "react-window@npm:1.8.9" + version: 1.8.10 + resolution: "react-window@npm:1.8.10" dependencies: "@babel/runtime": ^7.0.0 memoize-one: ">=3.1.1 <6" peerDependencies: react: ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 react-dom: ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 - checksum: cefa232f4f37269d292529ef15780fb108123d6bb5beee19eeac657e75cf8d4664be66f2da04baf0cb1bc64c5ab3d83a88199c3358f023b78940acd37b0673b2 + checksum: e8830f32e3ad4bf91af9cdc5cead84148c7694ce6abd9fdb447fb609da6cd4bbd0bbc75ff985f78828f4bbbd3ba4cbc98235cc9c056b5e5787578518f7fafbb9 languageName: node linkType: hard From 39db2c6d729c1349949da782bf2dcdd2af8c0cf1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 24 Nov 2023 12:07:13 +0000 Subject: [PATCH 069/261] fix(deps): update dependency swagger-ui-react to v5.10.3 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index ac8c50cc20..680ae4240d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -41983,8 +41983,8 @@ __metadata: linkType: hard "swagger-ui-react@npm:^5.0.0": - version: 5.10.0 - resolution: "swagger-ui-react@npm:5.10.0" + version: 5.10.3 + resolution: "swagger-ui-react@npm:5.10.3" dependencies: "@babel/runtime-corejs3": ^7.23.2 "@braintree/sanitize-url": =6.0.4 @@ -42023,7 +42023,7 @@ __metadata: peerDependencies: react: ">=17.0.0" react-dom: ">=17.0.0" - checksum: 71aa42a8f3218eb264ea330122b483583830ca30db9dfb6eacee16210db0c4c529602dda607b3860315a3fe42e56e1142d49c4659c41bdfe675d6ae05e1bcdea + checksum: 505dfb7b6f09b75bd637ac89796a6c4c8f3833b3907463f6824c37732cb4d19d045408fd92070dd1d93416996063bd97749de4397b2fca978df8025f2243b60c languageName: node linkType: hard From 0c93dc37b24cad06d3bfe870dc24e9e15b97361c Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Fri, 24 Nov 2023 13:46:42 +0100 Subject: [PATCH 070/261] core-plugin-api: add support for nested default translation message declarations Signed-off-by: Patrik Oldsberg --- .changeset/famous-flies-kick.md | 5 ++ packages/core-plugin-api/alpha-api-report.md | 18 ++--- .../src/translation/TranslationRef.test.ts | 34 +++++++++ .../src/translation/TranslationRef.ts | 74 +++++++++++++++---- 4 files changed, 107 insertions(+), 24 deletions(-) create mode 100644 .changeset/famous-flies-kick.md diff --git a/.changeset/famous-flies-kick.md b/.changeset/famous-flies-kick.md new file mode 100644 index 0000000000..abbd18f9c3 --- /dev/null +++ b/.changeset/famous-flies-kick.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-plugin-api': patch +--- + +The `createTranslationRef` function from the `/alpha` subpath can now also accept a nested object structure of default translation messages, which will be flatted using `.` separators. diff --git a/packages/core-plugin-api/alpha-api-report.md b/packages/core-plugin-api/alpha-api-report.md index ba3583142f..c0f0d02535 100644 --- a/packages/core-plugin-api/alpha-api-report.md +++ b/packages/core-plugin-api/alpha-api-report.md @@ -39,19 +39,17 @@ export function createTranslationMessages< // @alpha (undocumented) export function createTranslationRef< TId extends string, - const TMessages extends { - [key in string]: string; - }, + const TNestedMessages extends AnyNestedMessages, TTranslations extends { [language in string]: () => Promise<{ default: { - [key in keyof TMessages]: string | null; + [key in keyof FlattenedMessages]: string | null; }; }>; }, >( - config: TranslationRefOptions, -): TranslationRef; + config: TranslationRefOptions, +): TranslationRef>; // @alpha (undocumented) export function createTranslationResource< @@ -169,13 +167,11 @@ export interface TranslationRef< // @alpha (undocumented) export interface TranslationRefOptions< TId extends string, - TMessages extends { - [key in string]: string; - }, + TNestedMessages extends AnyNestedMessages, TTranslations extends { [language in string]: () => Promise<{ default: { - [key in keyof TMessages]: string | null; + [key in keyof FlattenedMessages]: string | null; }; }>; }, @@ -183,7 +179,7 @@ export interface TranslationRefOptions< // (undocumented) id: TId; // (undocumented) - messages: TMessages; + messages: TNestedMessages; // (undocumented) translations?: TTranslations; } diff --git a/packages/core-plugin-api/src/translation/TranslationRef.test.ts b/packages/core-plugin-api/src/translation/TranslationRef.test.ts index b73b521774..d1fde0810f 100644 --- a/packages/core-plugin-api/src/translation/TranslationRef.test.ts +++ b/packages/core-plugin-api/src/translation/TranslationRef.test.ts @@ -34,6 +34,40 @@ describe('TranslationRefImpl', () => { expect(internalRef.getDefaultMessages()).toEqual({ key: 'value' }); }); + it('should create a TranslationRef instance with nested messages', () => { + const ref = createTranslationRef({ + id: 'test', + messages: { + key: 'value', + 'nested.conflict1': 'outer conflict1', + nested: { + key: 'nested value', + key2: 'nested value2', + conflict1: 'inner conflict1', + conflict2: 'inner conflict2', + inner: { + key: 'inner value', + }, + }, + 'nested.conflict2': 'outer conflict2', + }, + }); + + const internalRef = toInternalTranslationRef(ref); + + expect(internalRef.$$type).toBe('@backstage/TranslationRef'); + expect(internalRef.version).toBe('v1'); + expect(internalRef.id).toBe('test'); + expect(internalRef.getDefaultMessages()).toEqual({ + key: 'value', + 'nested.key': 'nested value', + 'nested.key2': 'nested value2', + 'nested.conflict1': 'inner conflict1', + 'nested.inner.key': 'inner value', + 'nested.conflict2': 'outer conflict2', + }); + }); + it('should be created with lazy translations', async () => { const ref = createTranslationRef({ id: 'test', diff --git a/packages/core-plugin-api/src/translation/TranslationRef.ts b/packages/core-plugin-api/src/translation/TranslationRef.ts index 345a9c3f65..5711273915 100644 --- a/packages/core-plugin-api/src/translation/TranslationRef.ts +++ b/packages/core-plugin-api/src/translation/TranslationRef.ts @@ -34,6 +34,30 @@ export interface TranslationRef< /** @internal */ type AnyMessages = { [key in string]: string }; +/** @ignore */ +type AnyNestedMessages = { [key in string]: AnyNestedMessages | string }; + +/** + * Flattens a nested message declaration into a flat object with dot-separated keys. + * + * @ignore + */ +type FlattenedMessages = { + [K in keyof T]: ( + x: T[K] extends infer V + ? V extends AnyNestedMessages + ? FlattenedMessages extends infer FV + ? { + [P in keyof FV as `${K & string}.${P & string}`]: FV[P]; + } + : never + : Pick + : never, + ) => void; +} extends Record void> + ? { [K in keyof O]: O[K] } + : never; + /** @internal */ export interface InternalTranslationRef< TId extends string = string, @@ -49,31 +73,53 @@ export interface InternalTranslationRef< /** @alpha */ export interface TranslationRefOptions< TId extends string, - TMessages extends { [key in string]: string }, + TNestedMessages extends AnyNestedMessages, TTranslations extends { [language in string]: () => Promise<{ - default: { [key in keyof TMessages]: string | null }; + default: { + [key in keyof FlattenedMessages]: string | null; + }; }>; }, > { id: TId; - messages: TMessages; + messages: TNestedMessages; translations?: TTranslations; } +function flattenMessages(nested: AnyNestedMessages): AnyMessages { + const entries = new Array<[string, string]>(); + + function visit(obj: AnyNestedMessages, prefix: string): void { + for (const [key, value] of Object.entries(obj)) { + if (typeof value === 'string') { + entries.push([prefix + key, value]); + } else { + visit(value, `${prefix}${key}.`); + } + } + } + + visit(nested, ''); + + return Object.fromEntries(entries); +} + /** @internal */ class TranslationRefImpl< TId extends string, - TMessages extends { [key in string]: string }, -> implements InternalTranslationRef + TNestedMessages extends AnyNestedMessages, +> implements InternalTranslationRef> { #id: TId; - #messages: TMessages; + #messages: FlattenedMessages; #resources: TranslationResource | undefined; - constructor(options: TranslationRefOptions) { + constructor(options: TranslationRefOptions) { this.#id = options.id; - this.#messages = options.messages; + this.#messages = flattenMessages( + options.messages, + ) as FlattenedMessages; } $$type = '@backstage/TranslationRef' as const; @@ -108,15 +154,17 @@ class TranslationRefImpl< /** @alpha */ export function createTranslationRef< TId extends string, - const TMessages extends { [key in string]: string }, + const TNestedMessages extends AnyNestedMessages, TTranslations extends { [language in string]: () => Promise<{ - default: { [key in keyof TMessages]: string | null }; + default: { + [key in keyof FlattenedMessages]: string | null; + }; }>; }, >( - config: TranslationRefOptions, -): TranslationRef { + config: TranslationRefOptions, +): TranslationRef> { const ref = new TranslationRefImpl(config); if (config.translations) { ref.setDefaultResource( @@ -132,7 +180,7 @@ export function createTranslationRef< /** @internal */ export function toInternalTranslationRef< TId extends string, - TMessages extends { [key in string]: string }, + TMessages extends AnyMessages, >(ref: TranslationRef): InternalTranslationRef { const r = ref as InternalTranslationRef; if (r.$$type !== '@backstage/TranslationRef') { From 772f4982cb134564722c75431b2ee35c523976ec Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Fri, 24 Nov 2023 13:47:15 +0100 Subject: [PATCH 071/261] docs: update internationalization to use camelCase and nested message declarations Signed-off-by: Patrik Oldsberg --- docs/plugins/internationalization.md | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/docs/plugins/internationalization.md b/docs/plugins/internationalization.md index 78b7de6342..13bb098262 100644 --- a/docs/plugins/internationalization.md +++ b/docs/plugins/internationalization.md @@ -10,7 +10,7 @@ The Backstage core function provides internationalization for plugins ## For a plugin developer -When you are creating your plugin, you have the possibility to use `createTranslationRef` to define all messages for your plugin. For example +When you are creating your plugin, you have the possibility to use `createTranslationRef` to define all messages for your plugin. For example: ```ts import { createTranslationRef } from '@backstage/core-plugin-api/alpha'; @@ -19,8 +19,13 @@ import { createTranslationRef } from '@backstage/core-plugin-api/alpha'; export const myPluginTranslationRef = createTranslationRef({ id: 'plugin.my-plugin', messages: { - index_page_title: 'All your components', - create_component_button_label: 'Create new component', + indexPage: { + title: 'All your components', + createButtonTitle: 'Create new component', + }, + entityPage: { + notFound: 'Entity not found', + }, }, }); ``` @@ -33,9 +38,9 @@ import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; const { t } = useTranslationRef(myPluginTranslationRef); return ( - + ); @@ -53,7 +58,7 @@ In an app you can both override the default messages, as well as register transl + createTranslationMessages({ + ref: myPluginTranslationRef, + messages: { -+ create_component_button_label: 'Create new entity', ++ 'indexPage.createButtonTitle': 'Create new entity', + }, + }), + createTranslationResource({ From fb8f3bdbc23160a988ab479ecab1b967cead8811 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Fri, 24 Nov 2023 13:50:20 +0100 Subject: [PATCH 072/261] plugins: update translation messages to use nested structure and camelCase Signed-off-by: Patrik Oldsberg --- .changeset/silver-rocks-deliver.md | 7 +++++ plugins/adr/alpha-api-report.md | 6 ++--- .../EntityAdrContent/EntityAdrContent.tsx | 6 ++--- plugins/adr/src/translations.ts | 6 ++--- .../CatalogPage/DefaultCatalogPage.tsx | 4 +-- plugins/catalog/src/translation.ts | 6 +++-- plugins/user-settings/alpha-api-report.md | 20 +++++++------- .../General/UserSettingsLanguageToggle.tsx | 6 ++--- .../General/UserSettingsThemeToggle.tsx | 12 ++++----- plugins/user-settings/src/translation.ts | 26 ++++++++++++------- 10 files changed, 57 insertions(+), 42 deletions(-) create mode 100644 .changeset/silver-rocks-deliver.md diff --git a/.changeset/silver-rocks-deliver.md b/.changeset/silver-rocks-deliver.md new file mode 100644 index 0000000000..eb132199f3 --- /dev/null +++ b/.changeset/silver-rocks-deliver.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-user-settings': patch +'@backstage/plugin-catalog': patch +'@backstage/plugin-adr': patch +--- + +Updated alpha translation message keys to use nested format and camel case. diff --git a/plugins/adr/alpha-api-report.md b/plugins/adr/alpha-api-report.md index 5740556904..3864c85697 100644 --- a/plugins/adr/alpha-api-report.md +++ b/plugins/adr/alpha-api-report.md @@ -17,9 +17,9 @@ export const AdrSearchResultListItemExtension: Extension<{ export const adrTranslationRef: TranslationRef< 'adr', { - readonly content_header_title: 'Architecture Decision Records'; - readonly failed_to_fetch: 'Failed to fetch ADRs'; - readonly no_adrs: 'No ADRs found'; + readonly contentHeaderTitle: 'Architecture Decision Records'; + readonly failedToFetch: 'Failed to fetch ADRs'; + readonly notFound: 'No ADRs found'; } >; diff --git a/plugins/adr/src/components/EntityAdrContent/EntityAdrContent.tsx b/plugins/adr/src/components/EntityAdrContent/EntityAdrContent.tsx index 261dd994fb..5c8d244d26 100644 --- a/plugins/adr/src/components/EntityAdrContent/EntityAdrContent.tsx +++ b/plugins/adr/src/components/EntityAdrContent/EntityAdrContent.tsx @@ -219,7 +219,7 @@ export const EntityAdrContent = (props: { return ( - + {appSupportConfigured && } @@ -230,7 +230,7 @@ export const EntityAdrContent = (props: { {loading && } {entityHasAdrs && !loading && error && ( - + )} {entityHasAdrs && @@ -257,7 +257,7 @@ export const EntityAdrContent = (props: { ) : ( - {t('no_adrs')} + {t('notFound')} ))} ); diff --git a/plugins/adr/src/translations.ts b/plugins/adr/src/translations.ts index cc0995f597..038b0fd064 100644 --- a/plugins/adr/src/translations.ts +++ b/plugins/adr/src/translations.ts @@ -19,8 +19,8 @@ import { createTranslationRef } from '@backstage/core-plugin-api/alpha'; export const adrTranslationRef = createTranslationRef({ id: 'adr', messages: { - content_header_title: 'Architecture Decision Records', - failed_to_fetch: 'Failed to fetch ADRs', - no_adrs: 'No ADRs found', + contentHeaderTitle: 'Architecture Decision Records', + failedToFetch: 'Failed to fetch ADRs', + notFound: 'No ADRs found', }, }); diff --git a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx index 1f724d10fc..8dfc29f87f 100644 --- a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx +++ b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx @@ -62,11 +62,11 @@ export function BaseCatalogPage(props: BaseCatalogPageProps) { const { t } = useTranslationRef(catalogTranslationRef); return ( - + All your software catalog entities diff --git a/plugins/catalog/src/translation.ts b/plugins/catalog/src/translation.ts index 2d1e3f2c8a..bd27069fde 100644 --- a/plugins/catalog/src/translation.ts +++ b/plugins/catalog/src/translation.ts @@ -20,7 +20,9 @@ import { createTranslationRef } from '@backstage/core-plugin-api/alpha'; export const catalogTranslationRef = createTranslationRef({ id: 'catalog', messages: { - catalog_page_title: `{{orgName}} Catalog`, - catalog_page_create_button_title: 'Create', + indexPage: { + title: `{{orgName}} Catalog`, + createButtonTitle: 'Create', + }, }, }); diff --git a/plugins/user-settings/alpha-api-report.md b/plugins/user-settings/alpha-api-report.md index f375eadbee..adb609a2cb 100644 --- a/plugins/user-settings/alpha-api-report.md +++ b/plugins/user-settings/alpha-api-report.md @@ -20,16 +20,16 @@ export default _default; export const userSettingsTranslationRef: TranslationRef< 'user-settings', { - readonly language: 'Language'; - readonly change_the_language: 'Change the language'; - readonly theme: 'Theme'; - readonly theme_light: 'Light'; - readonly theme_dark: 'Dark'; - readonly theme_auto: 'Auto'; - readonly change_the_theme_mode: 'Change the theme mode'; - readonly select_theme: 'Select {{theme}}'; - readonly select_theme_auto: 'Select Auto Theme'; - readonly select_lng: 'Select language {{language}}'; + readonly 'languageToggle.select': 'Select language {{language}}'; + readonly 'languageToggle.title': 'Language'; + readonly 'languageToggle.description': 'Change the language'; + readonly 'themeToggle.select': 'Select theme {{theme}}'; + readonly 'themeToggle.title': 'Theme'; + readonly 'themeToggle.description': 'Change the theme mode'; + readonly 'themeToggle.names.auto': 'Auto'; + readonly 'themeToggle.names.dark': 'Dark'; + readonly 'themeToggle.names.light': 'Light'; + readonly 'themeToggle.selectAuto': 'Select Auto Theme'; } >; diff --git a/plugins/user-settings/src/components/General/UserSettingsLanguageToggle.tsx b/plugins/user-settings/src/components/General/UserSettingsLanguageToggle.tsx index 56756b2248..67519d24ae 100644 --- a/plugins/user-settings/src/components/General/UserSettingsLanguageToggle.tsx +++ b/plugins/user-settings/src/components/General/UserSettingsLanguageToggle.tsx @@ -118,8 +118,8 @@ export const UserSettingsLanguageToggle = () => { > { return ( <>{language} diff --git a/plugins/user-settings/src/components/General/UserSettingsThemeToggle.tsx b/plugins/user-settings/src/components/General/UserSettingsThemeToggle.tsx index ca57de3a78..37d91ecae0 100644 --- a/plugins/user-settings/src/components/General/UserSettingsThemeToggle.tsx +++ b/plugins/user-settings/src/components/General/UserSettingsThemeToggle.tsx @@ -130,8 +130,8 @@ export const UserSettingsThemeToggle = () => { > { const themeTitle = theme.title || (themeId === 'light' || themeId === 'dark' - ? t(`theme_${themeId}`) + ? t(`themeToggle.names.${themeId}`) : themeId); return ( <> @@ -165,9 +165,9 @@ export const UserSettingsThemeToggle = () => { ); })} - + - {t('theme_auto')}  + {t('themeToggle.names.auto')}  diff --git a/plugins/user-settings/src/translation.ts b/plugins/user-settings/src/translation.ts index 42fd8311e2..411ca1af51 100644 --- a/plugins/user-settings/src/translation.ts +++ b/plugins/user-settings/src/translation.ts @@ -20,15 +20,21 @@ import { createTranslationRef } from '@backstage/core-plugin-api/alpha'; export const userSettingsTranslationRef = createTranslationRef({ id: 'user-settings', messages: { - language: 'Language', - change_the_language: 'Change the language', - theme: 'Theme', - theme_light: 'Light', - theme_dark: 'Dark', - theme_auto: 'Auto', - change_the_theme_mode: 'Change the theme mode', - select_theme: 'Select {{theme}}', - select_theme_auto: 'Select Auto Theme', - select_lng: 'Select language {{language}}', + languageToggle: { + title: 'Language', + description: 'Change the language', + select: 'Select language {{language}}', + }, + themeToggle: { + title: 'Theme', + description: 'Change the theme mode', + select: 'Select theme {{theme}}', + selectAuto: 'Select Auto Theme', + names: { + light: 'Light', + dark: 'Dark', + auto: 'Auto', + }, + }, }, }); From 16409583575cb0b371e5dbfd734ebc99603f12d9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 24 Nov 2023 13:18:35 +0000 Subject: [PATCH 073/261] chore(deps): update dependency eslint-plugin-testing-library to v6.2.0 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 8d0b1b2280..a009de4f1c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -26152,13 +26152,13 @@ __metadata: linkType: hard "eslint-plugin-testing-library@npm:^6.0.0": - version: 6.1.2 - resolution: "eslint-plugin-testing-library@npm:6.1.2" + version: 6.2.0 + resolution: "eslint-plugin-testing-library@npm:6.2.0" dependencies: "@typescript-eslint/utils": ^5.58.0 peerDependencies: eslint: ^7.5.0 || ^8.0.0 - checksum: 74e6b1bdff52e9a3937be1ae0e3ddb6cfedcd97044ac5275be6e7472c77cf8ae0f6e29fd7d3b90aac1318e22850086e73ee8dde7de8d9034be59cdfed9ba7bd7 + checksum: 7af7e0a1eee44c6ba65ce2ae99f8e46ce709a319f4cce778bb0af2dda5828d78f3a81e8989c7b691a8b9b9fef102b56136209aac700038b9e64794600b0d12db languageName: node linkType: hard From 53600976bbdb17a2c59dfc2dc774db7c4e816747 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Fri, 24 Nov 2023 13:45:47 +0100 Subject: [PATCH 074/261] fix presentation icon passing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .changeset/fifty-cameras-share.md | 6 ++++ .../defaultEntityPresentation.ts | 31 +------------------ .../DefaultEntityPresentationApi.ts | 21 +++++++------ .../apis/EntityPresentationApi/defaults.tsx | 2 ++ 4 files changed, 20 insertions(+), 40 deletions(-) create mode 100644 .changeset/fifty-cameras-share.md diff --git a/.changeset/fifty-cameras-share.md b/.changeset/fifty-cameras-share.md new file mode 100644 index 0000000000..8aa103b218 --- /dev/null +++ b/.changeset/fifty-cameras-share.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-catalog-react': patch +'@backstage/plugin-catalog': patch +--- + +Ensure that passed-in icons are taken advantage of in the presentation API diff --git a/plugins/catalog-react/src/apis/EntityPresentationApi/defaultEntityPresentation.ts b/plugins/catalog-react/src/apis/EntityPresentationApi/defaultEntityPresentation.ts index 4ba18e35d1..8d841f3c3c 100644 --- a/plugins/catalog-react/src/apis/EntityPresentationApi/defaultEntityPresentation.ts +++ b/plugins/catalog-react/src/apis/EntityPresentationApi/defaultEntityPresentation.ts @@ -20,34 +20,9 @@ import { Entity, stringifyEntityRef, } from '@backstage/catalog-model'; -import { IconComponent } from '@backstage/core-plugin-api'; -import ApartmentIcon from '@material-ui/icons/Apartment'; -import BusinessIcon from '@material-ui/icons/Business'; -import ExtensionIcon from '@material-ui/icons/Extension'; -import HelpIcon from '@material-ui/icons/Help'; -import LibraryAddIcon from '@material-ui/icons/LibraryAdd'; -import LocationOnIcon from '@material-ui/icons/LocationOn'; -import MemoryIcon from '@material-ui/icons/Memory'; -import PeopleIcon from '@material-ui/icons/People'; -import PersonIcon from '@material-ui/icons/Person'; -import WorkIcon from '@material-ui/icons/Work'; import get from 'lodash/get'; import { EntityRefPresentationSnapshot } from './EntityPresentationApi'; -const UNKNOWN_KIND_ICON: IconComponent = HelpIcon; - -const DEFAULT_ICONS: Record = { - api: ExtensionIcon, - component: MemoryIcon, - system: BusinessIcon, - resource: WorkIcon, - domain: ApartmentIcon, - location: LocationOnIcon, - user: PersonIcon, - group: PeopleIcon, - template: LibraryAddIcon, -}; - /** * This returns the default representation of an entity. * @@ -68,10 +43,6 @@ export function defaultEntityPresentation( const { kind, namespace, name, title, description, displayName, type } = getParts(entityOrRef); - const Icon = - (kind && DEFAULT_ICONS[kind.toLocaleLowerCase('en-US')]) || - UNKNOWN_KIND_ICON; - const entityRef: string = stringifyEntityRef({ kind: kind || 'unknown', namespace: namespace || DEFAULT_NAMESPACE, @@ -96,7 +67,7 @@ export function defaultEntityPresentation( entityRef, primaryTitle: primary, secondaryTitle: secondary || undefined, - Icon, + Icon: undefined, // leave it up to the presentation API to handle }; } diff --git a/plugins/catalog/src/apis/EntityPresentationApi/DefaultEntityPresentationApi.ts b/plugins/catalog/src/apis/EntityPresentationApi/DefaultEntityPresentationApi.ts index 5f1119e598..b610173421 100644 --- a/plugins/catalog/src/apis/EntityPresentationApi/DefaultEntityPresentationApi.ts +++ b/plugins/catalog/src/apis/EntityPresentationApi/DefaultEntityPresentationApi.ts @@ -34,6 +34,7 @@ import { DEFAULT_BATCH_DELAY, DEFAULT_CACHE_TTL, DEFAULT_ICONS, + UNKNOWN_KIND_ICON, createDefaultRenderer, } from './defaults'; @@ -134,10 +135,7 @@ export interface DefaultEntityPresentationApiOptions { * @remarks * * The keys are kinds (case insensitive) that map to icon values to represent - * kinds by. - * - * If you do not supply a set of icons here, a set of fallback icons will be - * used. If you supply the empty object, no fallback icons will be used. + * kinds by. These are merged with the default set of icons. */ kindIcons?: Record; @@ -194,11 +192,12 @@ export class DefaultEntityPresentationApi implements EntityPresentationApi { const renderer = options.renderer ?? createDefaultRenderer({ async: true }); const kindIcons: Record = {}; - Object.entries(options.kindIcons ?? DEFAULT_ICONS).forEach( - ([kind, icon]) => { - kindIcons[kind.toLocaleLowerCase('en-US')] = icon; - }, - ); + Object.entries(DEFAULT_ICONS).forEach(([kind, icon]) => { + kindIcons[kind.toLocaleLowerCase('en-US')] = icon; + }); + Object.entries(options.kindIcons ?? {}).forEach(([kind, icon]) => { + kindIcons[kind.toLocaleLowerCase('en-US')] = icon; + }); if (renderer.async) { if (!options.catalogApi) { @@ -396,6 +395,8 @@ export class DefaultEntityPresentationApi implements EntityPresentationApi { return false; } - return this.#kindIcons[kind.toLocaleLowerCase('en-US')]; + return ( + this.#kindIcons[kind.toLocaleLowerCase('en-US')] ?? UNKNOWN_KIND_ICON + ); } } diff --git a/plugins/catalog/src/apis/EntityPresentationApi/defaults.tsx b/plugins/catalog/src/apis/EntityPresentationApi/defaults.tsx index afcd1f5464..84f04c6f83 100644 --- a/plugins/catalog/src/apis/EntityPresentationApi/defaults.tsx +++ b/plugins/catalog/src/apis/EntityPresentationApi/defaults.tsx @@ -26,6 +26,7 @@ import LocationOnIcon from '@material-ui/icons/LocationOn'; import MemoryIcon from '@material-ui/icons/Memory'; import PeopleIcon from '@material-ui/icons/People'; import PersonIcon from '@material-ui/icons/Person'; +import WorkIcon from '@material-ui/icons/Work'; import { DefaultEntityPresentationApiRenderer } from './DefaultEntityPresentationApi'; export const DEFAULT_CACHE_TTL: HumanDuration = { seconds: 10 }; @@ -38,6 +39,7 @@ export const DEFAULT_ICONS: Record = { api: ExtensionIcon, component: MemoryIcon, system: BusinessIcon, + resource: WorkIcon, domain: ApartmentIcon, location: LocationOnIcon, user: PersonIcon, From 01f67198f36eccb553b0e8d2196293dfd82768e7 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Fri, 24 Nov 2023 15:05:59 +0100 Subject: [PATCH 075/261] cli: show legacy warning when starting standalone plugin Signed-off-by: Vincenzo Scamporlino --- packages/cli/src/commands/start/command.ts | 5 +- .../cli/src/commands/start/startBackend.ts | 54 +++++++++++++++---- 2 files changed, 46 insertions(+), 13 deletions(-) diff --git a/packages/cli/src/commands/start/command.ts b/packages/cli/src/commands/start/command.ts index 48122d5ac0..427f8b6efb 100644 --- a/packages/cli/src/commands/start/command.ts +++ b/packages/cli/src/commands/start/command.ts @@ -16,7 +16,7 @@ import { OptionValues } from 'commander'; import { findRoleFromCommand } from '../../lib/role'; -import { startBackend } from './startBackend'; +import { startBackend, startBackendPlugin } from './startBackend'; import { startFrontend } from './startFrontend'; export async function command(opts: OptionValues): Promise { @@ -31,10 +31,11 @@ export async function command(opts: OptionValues): Promise { switch (role) { case 'backend': + return startBackend(options); case 'backend-plugin': case 'backend-plugin-module': case 'node-library': - return startBackend(options); + return startBackendPlugin(options); case 'frontend': return startFrontend({ ...options, diff --git a/packages/cli/src/commands/start/startBackend.ts b/packages/cli/src/commands/start/startBackend.ts index 967a1108a0..acbcbe6b7a 100644 --- a/packages/cli/src/commands/start/startBackend.ts +++ b/packages/cli/src/commands/start/startBackend.ts @@ -26,17 +26,7 @@ interface StartBackendOptions { } export async function startBackend(options: StartBackendOptions) { - const hasDev = await fs.pathExists(paths.resolveTarget('dev')); - if (hasDev) { - const waitForExit = await startBackendExperimental({ - entry: 'dev/index', - checksEnabled: false, // not supported - inspectEnabled: options.inspectEnabled, - inspectBrkEnabled: options.inspectBrkEnabled, - }); - - await waitForExit(); - } else if (!process.env.LEGACY_BACKEND_START) { + if (!process.env.LEGACY_BACKEND_START) { const waitForExit = await startBackendExperimental({ entry: 'src/index', checksEnabled: false, // not supported @@ -61,3 +51,45 @@ export async function startBackend(options: StartBackendOptions) { await waitForExit(); } } + +export async function startBackendPlugin(options: StartBackendOptions) { + if (!process.env.LEGACY_BACKEND_START) { + const hasEntry = await fs.pathExists(paths.resolveTarget('dev')); + if (!hasEntry) { + console.warn( + `dev directory doesn't exist. \ +It looks like this plugin hasn't been migrated to the new backend system. \ +Please run "LEGACY_BACKEND_START=1 yarn start" instead.`, + ); + return; + } + + const waitForExit = await startBackendExperimental({ + entry: 'dev/index', + checksEnabled: false, // not supported + inspectEnabled: options.inspectEnabled, + inspectBrkEnabled: options.inspectBrkEnabled, + }); + + await waitForExit(); + } else { + const hasEntry = await fs.pathExists(paths.resolveTarget('src', 'run.ts')); + if (!hasEntry) { + console.log(`src/run.ts is missing.`); + return; + } + // Cleaning dist/ before we start the dev process helps work around an issue + // where we end up with the entrypoint executing multiple times, causing + // a port bind conflict among other things. + await fs.remove(paths.resolveTarget('dist')); + + const waitForExit = await serveBackend({ + entry: 'src/run', + checksEnabled: options.checksEnabled, + inspectEnabled: options.inspectEnabled, + inspectBrkEnabled: options.inspectBrkEnabled, + }); + + await waitForExit(); + } +} From 6cd245bfcade20960a9cfa25957fd17cdc023724 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Fri, 24 Nov 2023 15:06:32 +0100 Subject: [PATCH 076/261] cli: refactor clean dist directory Signed-off-by: Vincenzo Scamporlino --- .../cli/src/commands/start/startBackend.ts | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/packages/cli/src/commands/start/startBackend.ts b/packages/cli/src/commands/start/startBackend.ts index acbcbe6b7a..a87d40fe76 100644 --- a/packages/cli/src/commands/start/startBackend.ts +++ b/packages/cli/src/commands/start/startBackend.ts @@ -36,12 +36,7 @@ export async function startBackend(options: StartBackendOptions) { await waitForExit(); } else { - // Cleaning dist/ before we start the dev process helps work around an issue - // where we end up with the entrypoint executing multiple times, causing - // a port bind conflict among other things. - await fs.remove(paths.resolveTarget('dist')); - - const waitForExit = await serveBackend({ + const waitForExit = await cleanDistAndServeBackend({ entry: 'src/index', checksEnabled: options.checksEnabled, inspectEnabled: options.inspectEnabled, @@ -78,12 +73,8 @@ Please run "LEGACY_BACKEND_START=1 yarn start" instead.`, console.log(`src/run.ts is missing.`); return; } - // Cleaning dist/ before we start the dev process helps work around an issue - // where we end up with the entrypoint executing multiple times, causing - // a port bind conflict among other things. - await fs.remove(paths.resolveTarget('dist')); - const waitForExit = await serveBackend({ + const waitForExit = await cleanDistAndServeBackend({ entry: 'src/run', checksEnabled: options.checksEnabled, inspectEnabled: options.inspectEnabled, @@ -93,3 +84,17 @@ Please run "LEGACY_BACKEND_START=1 yarn start" instead.`, await waitForExit(); } } + +async function cleanDistAndServeBackend(options: { + entry: string; + checksEnabled: boolean; + inspectEnabled: boolean; + inspectBrkEnabled: boolean; +}) { + // Cleaning dist/ before we start the dev process helps work around an issue + // where we end up with the entrypoint executing multiple times, causing + // a port bind conflict among other things. + await fs.remove(paths.resolveTarget('dist')); + + return serveBackend(options); +} From c6f3743172d6c30e33bea0256e70e23173d89f0d Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Fri, 24 Nov 2023 15:09:00 +0100 Subject: [PATCH 077/261] cli: add warning changeset Signed-off-by: Vincenzo Scamporlino --- .changeset/honest-houses-hide.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/honest-houses-hide.md diff --git a/.changeset/honest-houses-hide.md b/.changeset/honest-houses-hide.md new file mode 100644 index 0000000000..7f2508184f --- /dev/null +++ b/.changeset/honest-houses-hide.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Added a warning when starting a standalone backend plugin that hasn't been updated to the new backend system. From 0555cc9d002c549c0e88a38e405d72af6c064c2b Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Fri, 24 Nov 2023 15:19:34 +0100 Subject: [PATCH 078/261] cli: improve log message Signed-off-by: Vincenzo Scamporlino --- packages/cli/src/commands/start/startBackend.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/cli/src/commands/start/startBackend.ts b/packages/cli/src/commands/start/startBackend.ts index a87d40fe76..36218fe70c 100644 --- a/packages/cli/src/commands/start/startBackend.ts +++ b/packages/cli/src/commands/start/startBackend.ts @@ -52,9 +52,7 @@ export async function startBackendPlugin(options: StartBackendOptions) { const hasEntry = await fs.pathExists(paths.resolveTarget('dev')); if (!hasEntry) { console.warn( - `dev directory doesn't exist. \ -It looks like this plugin hasn't been migrated to the new backend system. \ -Please run "LEGACY_BACKEND_START=1 yarn start" instead.`, + `The 'dev' directory is missing. This plugin might not be updated for the new backend system. To run, use "LEGACY_BACKEND_START=1 yarn start".`, ); return; } From bf9104d91119816c125135bf6e9f5757c9f605db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Fri, 24 Nov 2023 15:25:52 +0100 Subject: [PATCH 079/261] Update microsite/data/plugins/hcp-consul.yaml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- microsite/data/plugins/hcp-consul.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/microsite/data/plugins/hcp-consul.yaml b/microsite/data/plugins/hcp-consul.yaml index 46af49e63d..6dabad582e 100644 --- a/microsite/data/plugins/hcp-consul.yaml +++ b/microsite/data/plugins/hcp-consul.yaml @@ -5,6 +5,6 @@ authorUrl: https://www.hashicorp.com/ category: Infrastructure description: View your HCP Consul clusters, services, instances in Backstage. documentation: https://github.com/hashicorp-forge/backstage-plugin-hcp-consul/tree/main -iconUrl: img/hcp-consul.svg +iconUrl: /img/hcp-consul.svg npmPackageName: '@hashicorp/plugin-hcp-consul' addedDate: '2023-11-24' From 306e6058cb92d3ff1bca18079510c2dc377511e9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 24 Nov 2023 14:28:05 +0000 Subject: [PATCH 080/261] fix(deps): update aws-sdk-js-v3 monorepo to v3.456.0 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/yarn.lock b/yarn.lock index a009de4f1c..16facb318c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -541,8 +541,8 @@ __metadata: linkType: hard "@aws-sdk/client-s3@npm:^3.350.0": - version: 3.454.0 - resolution: "@aws-sdk/client-s3@npm:3.454.0" + version: 3.456.0 + resolution: "@aws-sdk/client-s3@npm:3.456.0" dependencies: "@aws-crypto/sha1-browser": 3.0.0 "@aws-crypto/sha256-browser": 3.0.0 @@ -601,7 +601,7 @@ __metadata: "@smithy/util-waiter": ^2.0.13 fast-xml-parser: 4.2.5 tslib: ^2.5.0 - checksum: 1317ab80b8457e6ac83f335390c98489be35c6edebaed9132121fcd3e905d7ee98b6a5fd7d03ba0b8aee1a9a93f8ce2abfa97d6ced9d1c0fde210c0385a7efa8 + checksum: e77542547c7f30c39380fa8558d9917f2d989583b66ed9ee9200108e96bf675b72136f4f8985c299867f0414b44203c4d51b10f8243079eaff519666c58dbbb4 languageName: node linkType: hard @@ -921,8 +921,8 @@ __metadata: linkType: hard "@aws-sdk/lib-storage@npm:^3.350.0": - version: 3.454.0 - resolution: "@aws-sdk/lib-storage@npm:3.454.0" + version: 3.456.0 + resolution: "@aws-sdk/lib-storage@npm:3.456.0" dependencies: "@smithy/abort-controller": ^2.0.1 "@smithy/middleware-endpoint": ^2.2.0 @@ -933,7 +933,7 @@ __metadata: tslib: ^2.5.0 peerDependencies: "@aws-sdk/client-s3": ^3.0.0 - checksum: b8d7dd7a333e5d1d13de449269f1295e2d4835aa3e6fcef01e262a551ec0968591ce669f46fd988b678323cfae86dd5d92528282aa4bf772c980feefe3420e8e + checksum: 001f9fa653e22edc3c95635b570df05d0c34ce456fd7bc15d6daa36102b988835764efc646e5232888be1a3f0f877dc8d68934b246089b8e7ba795606d10cab6 languageName: node linkType: hard From 8583f1127338745d19ad897435958419dd517fad Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 24 Nov 2023 14:28:40 +0000 Subject: [PATCH 081/261] fix(deps): update dependency @azure/arm-appservice to v14.1.0 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/yarn.lock b/yarn.lock index a009de4f1c..967d6cbbcc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1434,17 +1434,17 @@ __metadata: linkType: hard "@azure/arm-appservice@npm:^14.0.0": - version: 14.0.0 - resolution: "@azure/arm-appservice@npm:14.0.0" + version: 14.1.0 + resolution: "@azure/arm-appservice@npm:14.1.0" dependencies: "@azure/abort-controller": ^1.0.0 "@azure/core-auth": ^1.3.0 "@azure/core-client": ^1.7.0 - "@azure/core-lro": ^2.5.0 + "@azure/core-lro": ^2.5.4 "@azure/core-paging": ^1.2.0 - "@azure/core-rest-pipeline": ^1.8.0 + "@azure/core-rest-pipeline": ^1.12.0 tslib: ^2.2.0 - checksum: a34776202f28808237a00958e6498f74547ed61cb284b681ac69fbd62fc9c174b12570ac8a02224162d4c9a2f066736ca40c4e31d12098fa630f9a9eef87d8ab + checksum: b989bc26d94056e0f02d2ede9981ebbf90ebefdc8b35c8f66531d3220c4ce52484d49c0a15b7056b79898a76533b0de0edf141b7736aadfabf2c33305804b884 languageName: node linkType: hard @@ -1508,7 +1508,7 @@ __metadata: languageName: node linkType: hard -"@azure/core-lro@npm:^2.2.0, @azure/core-lro@npm:^2.5.0": +"@azure/core-lro@npm:^2.2.0, @azure/core-lro@npm:^2.5.4": version: 2.5.4 resolution: "@azure/core-lro@npm:2.5.4" dependencies: @@ -1529,21 +1529,20 @@ __metadata: languageName: node linkType: hard -"@azure/core-rest-pipeline@npm:^1.1.0, @azure/core-rest-pipeline@npm:^1.8.0, @azure/core-rest-pipeline@npm:^1.9.1": - version: 1.9.2 - resolution: "@azure/core-rest-pipeline@npm:1.9.2" +"@azure/core-rest-pipeline@npm:^1.1.0, @azure/core-rest-pipeline@npm:^1.12.0, @azure/core-rest-pipeline@npm:^1.9.1": + version: 1.12.2 + resolution: "@azure/core-rest-pipeline@npm:1.12.2" dependencies: "@azure/abort-controller": ^1.0.0 "@azure/core-auth": ^1.4.0 "@azure/core-tracing": ^1.0.1 - "@azure/core-util": ^1.0.0 + "@azure/core-util": ^1.3.0 "@azure/logger": ^1.0.0 form-data: ^4.0.0 http-proxy-agent: ^5.0.0 https-proxy-agent: ^5.0.0 tslib: ^2.2.0 - uuid: ^8.3.0 - checksum: cdfdaf8bdb0778f40ecfeb8b5da0b4f8643d641b75bb5869485afd38f7c3127ab088ac2fe2980df03d28fb6715928e04560343ee6416246aebe75443c4dd2906 + checksum: a774ab2e87ff56d7f3ef1844a814bbd76264ea1c33534081d38ce6df1098d803d0b13b15912f9053d0695ca2669b0dd104c8feec8dbf24df80a3608ea784fc9e languageName: node linkType: hard @@ -1566,7 +1565,7 @@ __metadata: languageName: node linkType: hard -"@azure/core-util@npm:^1.0.0, @azure/core-util@npm:^1.1.0, @azure/core-util@npm:^1.1.1, @azure/core-util@npm:^1.2.0, @azure/core-util@npm:^1.6.1": +"@azure/core-util@npm:^1.0.0, @azure/core-util@npm:^1.1.0, @azure/core-util@npm:^1.1.1, @azure/core-util@npm:^1.2.0, @azure/core-util@npm:^1.3.0, @azure/core-util@npm:^1.6.1": version: 1.6.1 resolution: "@azure/core-util@npm:1.6.1" dependencies: From f511b8a8f3b9e0349f2098e4fa9b1dcf849a17e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Fri, 24 Nov 2023 15:28:48 +0100 Subject: [PATCH 082/261] fix test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .../defaultEntityPresentation.test.ts | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/plugins/catalog-react/src/apis/EntityPresentationApi/defaultEntityPresentation.test.ts b/plugins/catalog-react/src/apis/EntityPresentationApi/defaultEntityPresentation.test.ts index ea755dfebc..5985a50b0d 100644 --- a/plugins/catalog-react/src/apis/EntityPresentationApi/defaultEntityPresentation.test.ts +++ b/plugins/catalog-react/src/apis/EntityPresentationApi/defaultEntityPresentation.test.ts @@ -37,7 +37,7 @@ describe('defaultEntityPresentation', () => { entityRef: 'component:default/test', primaryTitle: 'test', secondaryTitle: 'component:default/test | type | desc', - Icon: expect.anything(), + Icon: undefined, }); expect( @@ -58,7 +58,7 @@ describe('defaultEntityPresentation', () => { entityRef: 'component:default/test', primaryTitle: 'title', secondaryTitle: 'component:default/test | type | desc', - Icon: expect.anything(), + Icon: undefined, }); expect( @@ -82,7 +82,7 @@ describe('defaultEntityPresentation', () => { entityRef: 'component:default/test', primaryTitle: 'displayName', secondaryTitle: 'component:default/test | type | desc', - Icon: expect.anything(), + Icon: undefined, }); }); @@ -96,7 +96,7 @@ describe('defaultEntityPresentation', () => { entityRef: 'component:default/test', primaryTitle: 'test', secondaryTitle: 'component:default/test', - Icon: expect.anything(), + Icon: undefined, }); }); @@ -107,7 +107,7 @@ describe('defaultEntityPresentation', () => { entityRef: 'unknown:default/unknown', primaryTitle: 'unknown', secondaryTitle: 'unknown:default/unknown', - Icon: expect.anything(), + Icon: undefined, }); }); }); @@ -118,7 +118,7 @@ describe('defaultEntityPresentation', () => { entityRef: 'component:default/test', primaryTitle: 'test', secondaryTitle: 'component:default/test', - Icon: expect.anything(), + Icon: undefined, }); expect( @@ -129,7 +129,7 @@ describe('defaultEntityPresentation', () => { entityRef: 'component:default/test', primaryTitle: 'component:test', secondaryTitle: 'component:default/test', - Icon: expect.anything(), + Icon: undefined, }); expect( @@ -140,7 +140,7 @@ describe('defaultEntityPresentation', () => { entityRef: 'component:default/test', primaryTitle: 'default/test', secondaryTitle: 'component:default/test', - Icon: expect.anything(), + Icon: undefined, }); }); @@ -149,14 +149,14 @@ describe('defaultEntityPresentation', () => { entityRef: 'unknown:default/unknown', primaryTitle: 'unknown', secondaryTitle: 'unknown:default/unknown', - Icon: expect.anything(), + Icon: undefined, }); expect(defaultEntityPresentation('name')).toEqual({ entityRef: 'unknown:default/name', primaryTitle: 'name', secondaryTitle: 'unknown:default/name', - Icon: expect.anything(), + Icon: undefined, }); }); }); @@ -173,7 +173,7 @@ describe('defaultEntityPresentation', () => { entityRef: 'component:default/test', primaryTitle: 'test', secondaryTitle: 'component:default/test', - Icon: expect.anything(), + Icon: undefined, }); expect( @@ -187,7 +187,7 @@ describe('defaultEntityPresentation', () => { entityRef: 'component:default/test', primaryTitle: 'component:test', secondaryTitle: 'component:default/test', - Icon: expect.anything(), + Icon: undefined, }); expect( @@ -201,7 +201,7 @@ describe('defaultEntityPresentation', () => { entityRef: 'component:default/test', primaryTitle: 'default/test', secondaryTitle: 'component:default/test', - Icon: expect.anything(), + Icon: undefined, }); }); @@ -217,14 +217,14 @@ describe('defaultEntityPresentation', () => { entityRef: 'component:default/test', primaryTitle: 'default/test', secondaryTitle: 'component:default/test', - Icon: expect.anything(), + Icon: undefined, }); expect(defaultEntityPresentation('')).toEqual({ entityRef: 'unknown:default/unknown', primaryTitle: 'unknown', secondaryTitle: 'unknown:default/unknown', - Icon: expect.anything(), + Icon: undefined, }); }); }); @@ -235,7 +235,7 @@ describe('defaultEntityPresentation', () => { entityRef: 'unknown:default/unknown', primaryTitle: 'unknown', secondaryTitle: 'unknown:default/unknown', - Icon: expect.anything(), + Icon: undefined, }); expect(defaultEntityPresentation(undefined as unknown as Entity)).toEqual( @@ -243,7 +243,7 @@ describe('defaultEntityPresentation', () => { entityRef: 'unknown:default/unknown', primaryTitle: 'unknown', secondaryTitle: 'unknown:default/unknown', - Icon: expect.anything(), + Icon: undefined, }, ); @@ -253,7 +253,7 @@ describe('defaultEntityPresentation', () => { entityRef: 'unknown:default/unknown', primaryTitle: 'unknown', secondaryTitle: 'unknown:default/unknown', - Icon: expect.anything(), + Icon: undefined, }); }); }); From 9cfa7010d1d9f3e9ac52b85bb254fe3984684352 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Fri, 24 Nov 2023 15:30:22 +0100 Subject: [PATCH 083/261] fix two more img links in the microsite MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- microsite/data/plugins/scaffolder-backend-slack.yaml | 2 +- .../data/plugins/search-backend-module-azure-devops-wiki.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/microsite/data/plugins/scaffolder-backend-slack.yaml b/microsite/data/plugins/scaffolder-backend-slack.yaml index dce7b60eb7..a726751eaf 100644 --- a/microsite/data/plugins/scaffolder-backend-slack.yaml +++ b/microsite/data/plugins/scaffolder-backend-slack.yaml @@ -5,6 +5,6 @@ authorUrl: https://github.com/arhill05 category: Scaffolder description: Interact with Slack from scaffolder templates documentation: https://github.com/arhill05/backstage-plugin-scaffolder-backend-module-slack#readme -iconUrl: img/Slack-mark-RGB.png +iconUrl: /img/Slack-mark-RGB.png npmPackageName: '@mdude2314/backstage-plugin-scaffolder-backend-module-slack' addedDate: '2023-08-04' diff --git a/microsite/data/plugins/search-backend-module-azure-devops-wiki.yaml b/microsite/data/plugins/search-backend-module-azure-devops-wiki.yaml index 02d4131cce..cc8849ee08 100644 --- a/microsite/data/plugins/search-backend-module-azure-devops-wiki.yaml +++ b/microsite/data/plugins/search-backend-module-azure-devops-wiki.yaml @@ -5,6 +5,6 @@ authorUrl: https://github.com/arhill05 category: Search description: Index wiki articles from an Azure DevOps wiki into Backstage to allow you to search them with the Backstage Search feature. documentation: https://github.com/arhill05/backstage-plugin-search-backend-module-azure-devops-wiki#readme -iconUrl: img/ado-wiki-search-icon.png +iconUrl: /img/ado-wiki-search-icon.png npmPackageName: '@mdude2314/backstage-plugin-search-backend-module-azure-devops-wiki' addedDate: '2023-06-13' From 1ee1ad371b3c35caac222ae130af72eba685b135 Mon Sep 17 00:00:00 2001 From: Andre Wanlin Date: Fri, 24 Nov 2023 09:01:05 -0600 Subject: [PATCH 084/261] Added slash to example Signed-off-by: Andre Wanlin --- docs/plugins/add-to-directory.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/plugins/add-to-directory.md b/docs/plugins/add-to-directory.md index 518d557140..8be0d764dd 100644 --- a/docs/plugins/add-to-directory.md +++ b/docs/plugins/add-to-directory.md @@ -21,7 +21,7 @@ description: A brief description of the plugin. # Max 170 characters documentation: # A link to your documentation E.g. Your github README iconUrl: # Used as the src attribute for your logo. # You can provide an external url or add your logo under static/img and provide a path -# relative to static/ e.g. img/my-logo.png +# relative to static/ e.g. /img/my-logo.png npmPackageName: # Your npm package name E.g. '@backstage/plugin-' quotes are required addedDate: # The date plugin added to directory E.g. '2022-10-01' quotes are required ``` From 2cf033f655702b84ebd607642568c318abe45ef7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 24 Nov 2023 15:06:38 +0000 Subject: [PATCH 085/261] fix(deps): update dependency @microsoft/microsoft-graph-types to v2.40.0 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 2b13e10715..e6829e94ef 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13090,9 +13090,9 @@ __metadata: linkType: hard "@microsoft/microsoft-graph-types@npm:^2.25.0, @microsoft/microsoft-graph-types@npm:^2.6.0": - version: 2.38.0 - resolution: "@microsoft/microsoft-graph-types@npm:2.38.0" - checksum: f5778650655034a6d92fbb932376002aefcf0cd358de323267b65fbec59284e8c0208e895c5523dcbbe79c4b583f3822c6beea01b70c687da26929c92de93c92 + version: 2.40.0 + resolution: "@microsoft/microsoft-graph-types@npm:2.40.0" + checksum: 3892e910baf4fcf2d1bcee4c71683e3707818be6ff1b4b9dbc29b9e2eab942ea0b171b3023d4620213f10d93d03611e6615706a3d1af4ca44028491a0544ccaf languageName: node linkType: hard From 2be3d465f833e9e0ddc2540f462a3ae55ca776ca Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Fri, 24 Nov 2023 16:53:37 +0100 Subject: [PATCH 086/261] cli: add more warnings Signed-off-by: Vincenzo Scamporlino --- packages/cli/src/commands/start/startBackend.ts | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/cli/src/commands/start/startBackend.ts b/packages/cli/src/commands/start/startBackend.ts index 36218fe70c..f5dfecdd21 100644 --- a/packages/cli/src/commands/start/startBackend.ts +++ b/packages/cli/src/commands/start/startBackend.ts @@ -49,10 +49,16 @@ export async function startBackend(options: StartBackendOptions) { export async function startBackendPlugin(options: StartBackendOptions) { if (!process.env.LEGACY_BACKEND_START) { - const hasEntry = await fs.pathExists(paths.resolveTarget('dev')); - if (!hasEntry) { + const hasDevEntry = await fs.pathExists(paths.resolveTarget('dev')); + const hasSrcIndexEntry = await fs.pathExists( + paths.resolveTarget('src', 'run.ts'), + ); + + if (!hasDevEntry && !hasSrcIndexEntry) { console.warn( - `The 'dev' directory is missing. This plugin might not be updated for the new backend system. To run, use "LEGACY_BACKEND_START=1 yarn start".`, + hasSrcIndexEntry + ? `The 'dev' directory is missing. The plugin might not be updated for the new backend system. To run, use "LEGACY_BACKEND_START=1 yarn start".` + : `The 'dev' directory is missing. Please create a proper dev/index.ts in order to start the plugin.`, ); return; } @@ -68,7 +74,9 @@ export async function startBackendPlugin(options: StartBackendOptions) { } else { const hasEntry = await fs.pathExists(paths.resolveTarget('src', 'run.ts')); if (!hasEntry) { - console.log(`src/run.ts is missing.`); + console.warn( + `src/run.ts is missing. Please create the file or run the command without LEGACY_BACKEND_START`, + ); return; } From 4665709122cffcc5d757cc3e696f1b371c73ad5f Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Fri, 24 Nov 2023 16:55:48 +0100 Subject: [PATCH 087/261] cli: check for dev/index.ts Signed-off-by: Vincenzo Scamporlino --- packages/cli/src/commands/start/startBackend.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/cli/src/commands/start/startBackend.ts b/packages/cli/src/commands/start/startBackend.ts index f5dfecdd21..25758a0939 100644 --- a/packages/cli/src/commands/start/startBackend.ts +++ b/packages/cli/src/commands/start/startBackend.ts @@ -49,12 +49,14 @@ export async function startBackend(options: StartBackendOptions) { export async function startBackendPlugin(options: StartBackendOptions) { if (!process.env.LEGACY_BACKEND_START) { - const hasDevEntry = await fs.pathExists(paths.resolveTarget('dev')); + const hasDevIndexEntry = await fs.pathExists( + paths.resolveTarget('dev', 'index.ts'), + ); const hasSrcIndexEntry = await fs.pathExists( paths.resolveTarget('src', 'run.ts'), ); - if (!hasDevEntry && !hasSrcIndexEntry) { + if (!hasDevIndexEntry && !hasSrcIndexEntry) { console.warn( hasSrcIndexEntry ? `The 'dev' directory is missing. The plugin might not be updated for the new backend system. To run, use "LEGACY_BACKEND_START=1 yarn start".` From 7123c58b3d10023a563e3db78267009d0f5dfb3e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 24 Nov 2023 16:40:23 +0000 Subject: [PATCH 088/261] chore(deps): update dependency @types/glob to v8 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .changeset/renovate-522261c.md | 5 +++++ plugins/catalog-backend/package.json | 2 +- yarn.lock | 26 +++++++++++++------------- 3 files changed, 19 insertions(+), 14 deletions(-) create mode 100644 .changeset/renovate-522261c.md diff --git a/.changeset/renovate-522261c.md b/.changeset/renovate-522261c.md new file mode 100644 index 0000000000..fb25fe0078 --- /dev/null +++ b/.changeset/renovate-522261c.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': patch +--- + +Updated dependency `@types/glob` to `^8.0.0`. diff --git a/plugins/catalog-backend/package.json b/plugins/catalog-backend/package.json index f20cbd86a9..682d293086 100644 --- a/plugins/catalog-backend/package.json +++ b/plugins/catalog-backend/package.json @@ -90,7 +90,7 @@ "@backstage/plugin-permission-common": "workspace:^", "@types/core-js": "^2.5.4", "@types/git-url-parse": "^9.0.0", - "@types/glob": "^7.1.1", + "@types/glob": "^8.0.0", "@types/lodash": "^4.14.151", "@types/supertest": "^2.0.8", "@types/uuid": "^8.0.0", diff --git a/yarn.lock b/yarn.lock index 08bf17efec..0e07c0288d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5775,7 +5775,7 @@ __metadata: "@types/core-js": ^2.5.4 "@types/express": ^4.17.6 "@types/git-url-parse": ^9.0.0 - "@types/glob": ^7.1.1 + "@types/glob": ^8.0.0 "@types/lodash": ^4.14.151 "@types/supertest": ^2.0.8 "@types/uuid": ^8.0.0 @@ -18117,13 +18117,13 @@ __metadata: languageName: node linkType: hard -"@types/glob@npm:^7.1.1": - version: 7.2.0 - resolution: "@types/glob@npm:7.2.0" +"@types/glob@npm:^8.0.0": + version: 8.1.0 + resolution: "@types/glob@npm:8.1.0" dependencies: - "@types/minimatch": "*" + "@types/minimatch": ^5.1.2 "@types/node": "*" - checksum: 6ae717fedfdfdad25f3d5a568323926c64f52ef35897bcac8aca8e19bc50c0bd84630bbd063e5d52078b2137d8e7d3c26eabebd1a2f03ff350fff8a91e79fc19 + checksum: 9101f3a9061e40137190f70626aa0e202369b5ec4012c3fabe6f5d229cce04772db9a94fa5a0eb39655e2e4ad105c38afbb4af56a56c0996a8c7d4fc72350e3d languageName: node linkType: hard @@ -18501,13 +18501,6 @@ __metadata: languageName: node linkType: hard -"@types/minimatch@npm:*, @types/minimatch@npm:^5.0.0": - version: 5.1.2 - resolution: "@types/minimatch@npm:5.1.2" - checksum: 0391a282860c7cb6fe262c12b99564732401bdaa5e395bee9ca323c312c1a0f45efbf34dce974682036e857db59a5c9b1da522f3d6055aeead7097264c8705a8 - languageName: node - linkType: hard - "@types/minimatch@npm:^3.0.3, @types/minimatch@npm:^3.0.5": version: 3.0.5 resolution: "@types/minimatch@npm:3.0.5" @@ -18515,6 +18508,13 @@ __metadata: languageName: node linkType: hard +"@types/minimatch@npm:^5.0.0, @types/minimatch@npm:^5.1.2": + version: 5.1.2 + resolution: "@types/minimatch@npm:5.1.2" + checksum: 0391a282860c7cb6fe262c12b99564732401bdaa5e395bee9ca323c312c1a0f45efbf34dce974682036e857db59a5c9b1da522f3d6055aeead7097264c8705a8 + languageName: node + linkType: hard + "@types/minimist@npm:^1.2.0": version: 1.2.5 resolution: "@types/minimist@npm:1.2.5" From 7bc3a2e282f695624cbff582408d2b613cc433f1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 24 Nov 2023 16:48:41 +0000 Subject: [PATCH 089/261] fix(deps): update typescript-eslint monorepo to v6.12.0 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 59 ++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 52 insertions(+), 7 deletions(-) diff --git a/yarn.lock b/yarn.lock index 08bf17efec..419a5b6cbc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -19475,20 +19475,20 @@ __metadata: linkType: hard "@typescript-eslint/parser@npm:^6.7.2": - version: 6.11.0 - resolution: "@typescript-eslint/parser@npm:6.11.0" + version: 6.12.0 + resolution: "@typescript-eslint/parser@npm:6.12.0" dependencies: - "@typescript-eslint/scope-manager": 6.11.0 - "@typescript-eslint/types": 6.11.0 - "@typescript-eslint/typescript-estree": 6.11.0 - "@typescript-eslint/visitor-keys": 6.11.0 + "@typescript-eslint/scope-manager": 6.12.0 + "@typescript-eslint/types": 6.12.0 + "@typescript-eslint/typescript-estree": 6.12.0 + "@typescript-eslint/visitor-keys": 6.12.0 debug: ^4.3.4 peerDependencies: eslint: ^7.0.0 || ^8.0.0 peerDependenciesMeta: typescript: optional: true - checksum: e9cb175e3537b82aa8cd39641ecb4e656586f89f8365cf05400b5aa8794dac0c8c10c6aa2fd7c13a684f62c1493f5e41c5534df49d377abe9dc89d861a51195c + checksum: 92923b7ee61f52d6b74f515640fe6bbb6b0a922d20dabeb6b59bc73f3c132bf750a2b706bb40fbe6d233c6ecc1abe905c99aa062280bb78e5724334f5b6c4ac5 languageName: node linkType: hard @@ -19512,6 +19512,16 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/scope-manager@npm:6.12.0": + version: 6.12.0 + resolution: "@typescript-eslint/scope-manager@npm:6.12.0" + dependencies: + "@typescript-eslint/types": 6.12.0 + "@typescript-eslint/visitor-keys": 6.12.0 + checksum: 4cc4eb1bcd04ba7b0a1de4284521cde5f3f25f2530f78dfcb3f098396b142fd30a45f615a87dc7a3adddbd131a6255cb12b1df19aacff71a3f766992ddef183f + languageName: node + linkType: hard + "@typescript-eslint/type-utils@npm:6.11.0": version: 6.11.0 resolution: "@typescript-eslint/type-utils@npm:6.11.0" @@ -19543,6 +19553,13 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/types@npm:6.12.0": + version: 6.12.0 + resolution: "@typescript-eslint/types@npm:6.12.0" + checksum: d3b40f9d400f6455ce5ae610651597c9e9ec85d46ca6d3c1025597a76305c557ebc5b88340ec6db0e694c9c79f1299d375b87a1a5b9314b22231dbbb5ce54695 + languageName: node + linkType: hard + "@typescript-eslint/typescript-estree@npm:5.59.8": version: 5.59.8 resolution: "@typescript-eslint/typescript-estree@npm:5.59.8" @@ -19579,6 +19596,24 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/typescript-estree@npm:6.12.0": + version: 6.12.0 + resolution: "@typescript-eslint/typescript-estree@npm:6.12.0" + dependencies: + "@typescript-eslint/types": 6.12.0 + "@typescript-eslint/visitor-keys": 6.12.0 + debug: ^4.3.4 + globby: ^11.1.0 + is-glob: ^4.0.3 + semver: ^7.5.4 + ts-api-utils: ^1.0.1 + peerDependenciesMeta: + typescript: + optional: true + checksum: 943f7ff2e164d812f6ae0a2d5096836aff00b1fda39937b03f126f266f03f3655794f5fc4643b49b71c312126d9422dfd764744bd1ba41ee6821a5bac1511aa2 + languageName: node + linkType: hard + "@typescript-eslint/utils@npm:6.11.0": version: 6.11.0 resolution: "@typescript-eslint/utils@npm:6.11.0" @@ -19634,6 +19669,16 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/visitor-keys@npm:6.12.0": + version: 6.12.0 + resolution: "@typescript-eslint/visitor-keys@npm:6.12.0" + dependencies: + "@typescript-eslint/types": 6.12.0 + eslint-visitor-keys: ^3.4.1 + checksum: 3d8dc74ae748a95fe60b48dbaecca8d9c0c8df344d8034e3843057251fba24f06a3d29dbb9f525c9540b538d8c24221d3cf119ac483e9de38149a978051c72f3 + languageName: node + linkType: hard + "@uiw/codemirror-extensions-basic-setup@npm:4.21.20": version: 4.21.20 resolution: "@uiw/codemirror-extensions-basic-setup@npm:4.21.20" From e35179ca3ea38749fab0dabcbea289ee52f8d464 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 24 Nov 2023 17:22:12 +0000 Subject: [PATCH 090/261] chore(deps): update dependency msw to v2.0.9 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 419a5b6cbc..1b42d4915a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -34765,8 +34765,8 @@ __metadata: linkType: hard "msw@npm:^2.0.8": - version: 2.0.8 - resolution: "msw@npm:2.0.8" + version: 2.0.9 + resolution: "msw@npm:2.0.9" dependencies: "@bundled-es-modules/cookie": ^2.0.0 "@bundled-es-modules/js-levenshtein": ^2.0.1 @@ -34796,7 +34796,7 @@ __metadata: optional: true bin: msw: cli/index.js - checksum: 8737dae4cf516d8c591ad8d3751cef2f8f07d10a1f995b8cd7d19d8e955a29352dd6fc092f04bc0e1d0025663ccc3c64ae7e56e29c8d4a4b13699e3ee4747c46 + checksum: 77bdb10a019f1d382bfc66b3005752e722f2891e9f8a4f9d3d17f5641ca4d8afb02bc67c9325dfd25708702443e0f9b8e48fbc580faa37c21e090425df93089e languageName: node linkType: hard From 8056425e094f619b4778bdbf8b0256d5336a9ed6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 24 Nov 2023 17:22:39 +0000 Subject: [PATCH 091/261] fix(deps): update dependency @typescript-eslint/eslint-plugin to v6.12.0 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .changeset/renovate-796bd6f.md | 5 ++ packages/cli/package.json | 2 +- yarn.lock | 89 +++++++++------------------------- 3 files changed, 28 insertions(+), 68 deletions(-) create mode 100644 .changeset/renovate-796bd6f.md diff --git a/.changeset/renovate-796bd6f.md b/.changeset/renovate-796bd6f.md new file mode 100644 index 0000000000..561f6b8b03 --- /dev/null +++ b/.changeset/renovate-796bd6f.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Updated dependency `@typescript-eslint/eslint-plugin` to `6.12.0`. diff --git a/packages/cli/package.json b/packages/cli/package.json index 490325296c..cb7d4d9697 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -64,7 +64,7 @@ "@swc/jest": "^0.2.22", "@types/jest": "^29.0.0", "@types/webpack-env": "^1.15.2", - "@typescript-eslint/eslint-plugin": "6.11.0", + "@typescript-eslint/eslint-plugin": "6.12.0", "@typescript-eslint/parser": "^6.7.2", "@yarnpkg/lockfile": "^1.1.0", "@yarnpkg/parsers": "^3.0.0-rc.4", diff --git a/yarn.lock b/yarn.lock index 419a5b6cbc..35722d25f7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3637,7 +3637,7 @@ __metadata: "@types/terser-webpack-plugin": ^5.0.4 "@types/webpack-env": ^1.15.2 "@types/yarnpkg__lockfile": ^1.1.4 - "@typescript-eslint/eslint-plugin": 6.11.0 + "@typescript-eslint/eslint-plugin": 6.12.0 "@typescript-eslint/parser": ^6.7.2 "@yarnpkg/lockfile": ^1.1.0 "@yarnpkg/parsers": ^3.0.0-rc.4 @@ -19449,15 +19449,15 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/eslint-plugin@npm:6.11.0": - version: 6.11.0 - resolution: "@typescript-eslint/eslint-plugin@npm:6.11.0" +"@typescript-eslint/eslint-plugin@npm:6.12.0": + version: 6.12.0 + resolution: "@typescript-eslint/eslint-plugin@npm:6.12.0" dependencies: "@eslint-community/regexpp": ^4.5.1 - "@typescript-eslint/scope-manager": 6.11.0 - "@typescript-eslint/type-utils": 6.11.0 - "@typescript-eslint/utils": 6.11.0 - "@typescript-eslint/visitor-keys": 6.11.0 + "@typescript-eslint/scope-manager": 6.12.0 + "@typescript-eslint/type-utils": 6.12.0 + "@typescript-eslint/utils": 6.12.0 + "@typescript-eslint/visitor-keys": 6.12.0 debug: ^4.3.4 graphemer: ^1.4.0 ignore: ^5.2.4 @@ -19470,7 +19470,7 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 8ba9ce7ce8609a044e405baf57cc84d6973d7676950c870288d7eae2dba44b36664e3f4d90b94a4de08e17259fe8baa7790750cd4e5391dbe2a2743497d7fae2 + checksum: a791ebe432a6cac50a15c9e98502b62e874de0c7e35fd320b9bdca21afd4ae88c88cff45ee50a95362da14e98965d946e57b15965f5522f1153568a3fe45db8a languageName: node linkType: hard @@ -19502,16 +19502,6 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:6.11.0": - version: 6.11.0 - resolution: "@typescript-eslint/scope-manager@npm:6.11.0" - dependencies: - "@typescript-eslint/types": 6.11.0 - "@typescript-eslint/visitor-keys": 6.11.0 - checksum: d219a96fd80fb14176cdcc47b070e870c73ccc0dfb32a8657f6ceaefb613dc0ea240a77250dcfc437d9c9360ca165c2765d4cf8fe689dae7e9eee2c0d6a98a50 - languageName: node - linkType: hard - "@typescript-eslint/scope-manager@npm:6.12.0": version: 6.12.0 resolution: "@typescript-eslint/scope-manager@npm:6.12.0" @@ -19522,12 +19512,12 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/type-utils@npm:6.11.0": - version: 6.11.0 - resolution: "@typescript-eslint/type-utils@npm:6.11.0" +"@typescript-eslint/type-utils@npm:6.12.0": + version: 6.12.0 + resolution: "@typescript-eslint/type-utils@npm:6.12.0" dependencies: - "@typescript-eslint/typescript-estree": 6.11.0 - "@typescript-eslint/utils": 6.11.0 + "@typescript-eslint/typescript-estree": 6.12.0 + "@typescript-eslint/utils": 6.12.0 debug: ^4.3.4 ts-api-utils: ^1.0.1 peerDependencies: @@ -19535,7 +19525,7 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 2effbe62ae3b12f8a88663072f68a5dcb1135d9ee3c09a0d9fcf49b943837c0a5966e907d4a1a15c27ddf82af2fcf7f6e004655d3e1f7a17c21596469771ff7d + checksum: c345c45f1262eee4b9f6960a59b3aba960643d0004094a3d8fb9682ab79af2fae864695029246dc9e0d4fdb2f3d017a56b7dc034e551d263deba75c2ef048d39 languageName: node linkType: hard @@ -19546,13 +19536,6 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/types@npm:6.11.0": - version: 6.11.0 - resolution: "@typescript-eslint/types@npm:6.11.0" - checksum: ca8a11320286c9b0759a70ec83b9fd99937c9686fafdd41d8ea09ed7b2fa12e6b342bf65547efe5495926cd04cfc6488315920e3caffd27f12d42cb9a8cf88c8 - languageName: node - linkType: hard - "@typescript-eslint/types@npm:6.12.0": version: 6.12.0 resolution: "@typescript-eslint/types@npm:6.12.0" @@ -19578,24 +19561,6 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:6.11.0": - version: 6.11.0 - resolution: "@typescript-eslint/typescript-estree@npm:6.11.0" - dependencies: - "@typescript-eslint/types": 6.11.0 - "@typescript-eslint/visitor-keys": 6.11.0 - debug: ^4.3.4 - globby: ^11.1.0 - is-glob: ^4.0.3 - semver: ^7.5.4 - ts-api-utils: ^1.0.1 - peerDependenciesMeta: - typescript: - optional: true - checksum: e137ba7c4cad08853a44d9c40072496ca5f2d440828be9fd2d207a59db56b05a6dcb4756f3ba341ee2ae714de45df80114477946d30801c5a46eed67314fd9c6 - languageName: node - linkType: hard - "@typescript-eslint/typescript-estree@npm:6.12.0": version: 6.12.0 resolution: "@typescript-eslint/typescript-estree@npm:6.12.0" @@ -19614,20 +19579,20 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/utils@npm:6.11.0": - version: 6.11.0 - resolution: "@typescript-eslint/utils@npm:6.11.0" +"@typescript-eslint/utils@npm:6.12.0": + version: 6.12.0 + resolution: "@typescript-eslint/utils@npm:6.12.0" dependencies: "@eslint-community/eslint-utils": ^4.4.0 "@types/json-schema": ^7.0.12 "@types/semver": ^7.5.0 - "@typescript-eslint/scope-manager": 6.11.0 - "@typescript-eslint/types": 6.11.0 - "@typescript-eslint/typescript-estree": 6.11.0 + "@typescript-eslint/scope-manager": 6.12.0 + "@typescript-eslint/types": 6.12.0 + "@typescript-eslint/typescript-estree": 6.12.0 semver: ^7.5.4 peerDependencies: eslint: ^7.0.0 || ^8.0.0 - checksum: e90aa2c8c56038a48de65a5303f9e4a4a70bb0d4d0a05cfcd28157fc0f06b2fc186c2e76a495f4540a903ea37577daa1403bab923d940114ec27a6326153d60f + checksum: dad05bd0e4db7a88c2716f9ee83c7c28c30d71e57392e58dc0db66b5f5c4c86b9db14142c6a1a82cf1650da294d31980c56a118015d3a2a645acb8b8a5ebc315 languageName: node linkType: hard @@ -19659,16 +19624,6 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:6.11.0": - version: 6.11.0 - resolution: "@typescript-eslint/visitor-keys@npm:6.11.0" - dependencies: - "@typescript-eslint/types": 6.11.0 - eslint-visitor-keys: ^3.4.1 - checksum: 6aae9dd79963bbefbf2e310015b909627da541a13ab4d8359eea3c86c34fdbb91e583f65b5a99dee1959f7c5d67b21b45e5a05c63ddb4b82dacd60c890ce8b25 - languageName: node - linkType: hard - "@typescript-eslint/visitor-keys@npm:6.12.0": version: 6.12.0 resolution: "@typescript-eslint/visitor-keys@npm:6.12.0" From a518c5a25badbe5968644e9e87d3e14fb11d3958 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 24 Nov 2023 21:36:54 +0000 Subject: [PATCH 092/261] fix(deps): update dependency @react-hookz/web to v23 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .changeset/renovate-c4e012c.md | 10 ++++++++++ packages/core-components/package.json | 2 +- plugins/entity-validation/package.json | 2 +- plugins/gcp-projects/package.json | 2 +- plugins/scaffolder-react/package.json | 2 +- plugins/scaffolder/package.json | 2 +- plugins/techdocs-module-addons-contrib/package.json | 2 +- yarn.lock | 12 ++++++------ 8 files changed, 22 insertions(+), 12 deletions(-) create mode 100644 .changeset/renovate-c4e012c.md diff --git a/.changeset/renovate-c4e012c.md b/.changeset/renovate-c4e012c.md new file mode 100644 index 0000000000..eb26b9fb58 --- /dev/null +++ b/.changeset/renovate-c4e012c.md @@ -0,0 +1,10 @@ +--- +'@backstage/core-components': patch +'@backstage/plugin-entity-validation': patch +'@backstage/plugin-gcp-projects': patch +'@backstage/plugin-scaffolder-react': patch +'@backstage/plugin-scaffolder': patch +'@backstage/plugin-techdocs-module-addons-contrib': patch +--- + +Updated dependency `@react-hookz/web` to `^23.0.0`. diff --git a/packages/core-components/package.json b/packages/core-components/package.json index 5e3f034494..7670a5792d 100644 --- a/packages/core-components/package.json +++ b/packages/core-components/package.json @@ -43,7 +43,7 @@ "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", - "@react-hookz/web": "^20.0.0", + "@react-hookz/web": "^23.0.0", "@types/react": "^16.13.1 || ^17.0.0", "@types/react-sparklines": "^1.7.0", "@types/react-text-truncate": "^0.14.0", diff --git a/plugins/entity-validation/package.json b/plugins/entity-validation/package.json index 8657c2cbdc..ce040e0c0c 100644 --- a/plugins/entity-validation/package.json +++ b/plugins/entity-validation/package.json @@ -43,7 +43,7 @@ "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", - "@react-hookz/web": "^20.0.0", + "@react-hookz/web": "^23.0.0", "@types/react": "^16.13.1 || ^17.0.0", "@uiw/react-codemirror": "^4.9.3", "lodash": "^4.17.21", diff --git a/plugins/gcp-projects/package.json b/plugins/gcp-projects/package.json index 1fde4908fa..73fdba578d 100644 --- a/plugins/gcp-projects/package.json +++ b/plugins/gcp-projects/package.json @@ -40,7 +40,7 @@ "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", - "@react-hookz/web": "^20.0.0", + "@react-hookz/web": "^23.0.0", "@types/react": "^16.13.1 || ^17.0.0" }, "peerDependencies": { diff --git a/plugins/scaffolder-react/package.json b/plugins/scaffolder-react/package.json index 22cf4ba5a2..4a5f619882 100644 --- a/plugins/scaffolder-react/package.json +++ b/plugins/scaffolder-react/package.json @@ -59,7 +59,7 @@ "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", - "@react-hookz/web": "^20.0.0", + "@react-hookz/web": "^23.0.0", "@rjsf/core": "5.14.2", "@rjsf/material-ui": "5.14.2", "@rjsf/utils": "5.14.2", diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index 17d4b131b9..d02220059d 100644 --- a/plugins/scaffolder/package.json +++ b/plugins/scaffolder/package.json @@ -67,7 +67,7 @@ "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", - "@react-hookz/web": "^20.0.0", + "@react-hookz/web": "^23.0.0", "@rjsf/core": "5.14.2", "@rjsf/material-ui": "5.14.2", "@rjsf/utils": "5.14.2", diff --git a/plugins/techdocs-module-addons-contrib/package.json b/plugins/techdocs-module-addons-contrib/package.json index 53ff762126..a8d73b0913 100644 --- a/plugins/techdocs-module-addons-contrib/package.json +++ b/plugins/techdocs-module-addons-contrib/package.json @@ -43,7 +43,7 @@ "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", - "@react-hookz/web": "^20.0.0", + "@react-hookz/web": "^23.0.0", "git-url-parse": "^13.0.0", "photoswipe": "^5.3.7", "react-use": "^17.2.4" diff --git a/yarn.lock b/yarn.lock index 1b42d4915a..4414a8f7dc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3969,7 +3969,7 @@ __metadata: "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 "@material-ui/lab": 4.0.0-alpha.61 - "@react-hookz/web": ^20.0.0 + "@react-hookz/web": ^23.0.0 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 "@testing-library/react": ^14.0.0 @@ -6607,7 +6607,7 @@ __metadata: "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 "@material-ui/lab": 4.0.0-alpha.61 - "@react-hookz/web": ^20.0.0 + "@react-hookz/web": ^23.0.0 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 "@testing-library/react": ^14.0.0 @@ -6969,7 +6969,7 @@ __metadata: "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 "@material-ui/lab": 4.0.0-alpha.61 - "@react-hookz/web": ^20.0.0 + "@react-hookz/web": ^23.0.0 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 "@testing-library/react": ^14.0.0 @@ -8808,7 +8808,7 @@ __metadata: "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 "@material-ui/lab": 4.0.0-alpha.61 - "@react-hookz/web": ^20.0.0 + "@react-hookz/web": ^23.0.0 "@rjsf/core": 5.14.2 "@rjsf/material-ui": 5.14.2 "@rjsf/utils": 5.14.2 @@ -8871,7 +8871,7 @@ __metadata: "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 "@material-ui/lab": 4.0.0-alpha.61 - "@react-hookz/web": ^20.0.0 + "@react-hookz/web": ^23.0.0 "@rjsf/core": 5.14.2 "@rjsf/material-ui": 5.14.2 "@rjsf/utils": 5.14.2 @@ -9662,7 +9662,7 @@ __metadata: "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 "@material-ui/lab": 4.0.0-alpha.61 - "@react-hookz/web": ^20.0.0 + "@react-hookz/web": ^23.0.0 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 "@testing-library/react": ^14.0.0 From 043b724c568ab6ae4d1ec87587293aedc69cfe97 Mon Sep 17 00:00:00 2001 From: Andre Wanlin Date: Thu, 23 Nov 2023 18:10:40 -0600 Subject: [PATCH 093/261] initial changes Signed-off-by: Andre Wanlin Signed-off-by: Andre Wanlin Signed-off-by: Andre Wanlin Signed-off-by: Andre Wanlin --- .changeset/pretty-onions-knock.md | 7 + plugins/azure-devops-backend/README.md | 23 ++ plugins/azure-devops-backend/api-report.md | 23 ++ plugins/azure-devops-backend/package.json | 5 + plugins/azure-devops-backend/src/index.ts | 1 + .../AzureDevOpsAnnotatorProcessor.test.ts | 271 ++++++++++++++++++ .../AzureDevOpsAnnotatorProcessor.ts | 127 ++++++++ .../src/processor/index.ts | 17 ++ .../src/utils/azure-devops-utils.test.ts | 36 +++ .../src/utils/azure-devops-utils.ts | 26 ++ plugins/azure-devops-common/api-report.md | 16 ++ .../src/constants.ts | 5 + plugins/azure-devops-common/src/index.ts | 1 + .../azure-devops/src/hooks/useBuildRuns.ts | 2 +- .../azure-devops/src/hooks/usePullRequests.ts | 2 +- plugins/azure-devops/src/plugin.ts | 10 +- .../utils/getAnnotationValuesFromEntity.ts | 13 +- yarn.lock | 5 + 18 files changed, 576 insertions(+), 14 deletions(-) create mode 100644 .changeset/pretty-onions-knock.md create mode 100644 plugins/azure-devops-backend/src/processor/AzureDevOpsAnnotatorProcessor.test.ts create mode 100644 plugins/azure-devops-backend/src/processor/AzureDevOpsAnnotatorProcessor.ts create mode 100644 plugins/azure-devops-backend/src/processor/index.ts rename plugins/{azure-devops => azure-devops-common}/src/constants.ts (92%) diff --git a/.changeset/pretty-onions-knock.md b/.changeset/pretty-onions-knock.md new file mode 100644 index 0000000000..701024cba4 --- /dev/null +++ b/.changeset/pretty-onions-knock.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-azure-devops-backend': patch +'@backstage/plugin-azure-devops-common': patch +'@backstage/plugin-azure-devops': patch +--- + +Introduced new `AzureDevOpsAnnotatorProcessor` that adds the needed annotations automatically. Also, moved constants to common package so they can be shared more easily diff --git a/plugins/azure-devops-backend/README.md b/plugins/azure-devops-backend/README.md index e892b84dd1..6810112bdb 100644 --- a/plugins/azure-devops-backend/README.md +++ b/plugins/azure-devops-backend/README.md @@ -89,6 +89,29 @@ In your `packages/backend/src/index.ts` make the following changes: backend.start(); ``` +## Processor + +The Azure DevOps backend plugin includes the `AzureDevOpsAnnotatorProcessor` which will automatically add the needed annotations for you. Here's how to install it: + +```diff + import { CatalogBuilder } from '@backstage/plugin-catalog-backend'; + import { ScaffolderEntitiesProcessor } from '@backstage/plugin-catalog-backend-module-scaffolder-entity-model'; + import { Router } from 'express'; + import { PluginEnvironment } from '../types'; ++ import { AzureDevOpsAnnotatorProcessor } from '@backstage/plugin-azure-devops-backend'; + + export default async function createPlugin( + env: PluginEnvironment, + ): Promise { + const builder = await CatalogBuilder.create(env); + builder.addProcessor(new ScaffolderEntitiesProcessor()); ++ builder.addProcessor(AzureDevOpsAnnotatorProcessor.fromConfig(env.config)); + const { processingEngine, router } = await builder.build(); + await processingEngine.start(); + return router; + } +``` + ## Links - [Frontend part of the plugin](https://github.com/backstage/backstage/tree/master/plugins/azure-devops) diff --git a/plugins/azure-devops-backend/api-report.md b/plugins/azure-devops-backend/api-report.md index 8c916a1495..82a0875798 100644 --- a/plugins/azure-devops-backend/api-report.md +++ b/plugins/azure-devops-backend/api-report.md @@ -7,21 +7,44 @@ import { BackendFeature } from '@backstage/backend-plugin-api'; import { Build } from 'azure-devops-node-api/interfaces/BuildInterfaces'; import { BuildDefinitionReference } from 'azure-devops-node-api/interfaces/BuildInterfaces'; import { BuildRun } from '@backstage/plugin-azure-devops-common'; +import { CatalogProcessor } from '@backstage/plugin-catalog-node'; import { Config } from '@backstage/config'; import { DashboardPullRequest } from '@backstage/plugin-azure-devops-common'; +import { Entity } from '@backstage/catalog-model'; import express from 'express'; import { GitRepository } from 'azure-devops-node-api/interfaces/GitInterfaces'; import { GitTag } from '@backstage/plugin-azure-devops-common'; +import { LocationSpec } from '@backstage/plugin-catalog-common'; import { Logger } from 'winston'; import { Project } from '@backstage/plugin-azure-devops-common'; import { PullRequest } from '@backstage/plugin-azure-devops-common'; import { PullRequestOptions } from '@backstage/plugin-azure-devops-common'; import { RepoBuild } from '@backstage/plugin-azure-devops-common'; +import { ScmIntegrationRegistry } from '@backstage/integration'; import { Team } from '@backstage/plugin-azure-devops-common'; import { TeamMember } from '@backstage/plugin-azure-devops-common'; import { UrlReader } from '@backstage/backend-common'; import { WebApi } from 'azure-devops-node-api'; +// @public (undocumented) +export class AzureDevOpsAnnotatorProcessor implements CatalogProcessor { + constructor(opts: { + scmIntegrationRegistry: ScmIntegrationRegistry; + kinds?: string[]; + }); + // (undocumented) + static fromConfig( + config: Config, + options?: { + kinds?: string[]; + }, + ): AzureDevOpsAnnotatorProcessor; + // (undocumented) + getProcessorName(): string; + // (undocumented) + preProcessEntity(entity: Entity, location: LocationSpec): Promise; +} + // @public (undocumented) export class AzureDevOpsApi { constructor(logger: Logger, webApi: WebApi, urlReader: UrlReader); diff --git a/plugins/azure-devops-backend/package.json b/plugins/azure-devops-backend/package.json index 5bf6b9b39f..5b8bcda31c 100644 --- a/plugins/azure-devops-backend/package.json +++ b/plugins/azure-devops-backend/package.json @@ -30,12 +30,17 @@ "dependencies": { "@backstage/backend-common": "workspace:^", "@backstage/backend-plugin-api": "workspace:^", + "@backstage/catalog-model": "workspace:^", "@backstage/config": "workspace:^", + "@backstage/integration": "workspace:^", "@backstage/plugin-azure-devops-common": "workspace:^", + "@backstage/plugin-catalog-common": "workspace:^", + "@backstage/plugin-catalog-node": "workspace:^", "@types/express": "^4.17.6", "azure-devops-node-api": "^11.0.1", "express": "^4.17.1", "express-promise-router": "^4.1.0", + "lodash": "^4.17.21", "mime-types": "^2.1.27", "p-limit": "^3.1.0", "winston": "^3.2.1", diff --git a/plugins/azure-devops-backend/src/index.ts b/plugins/azure-devops-backend/src/index.ts index 3c802e7144..61cf7c7a6f 100644 --- a/plugins/azure-devops-backend/src/index.ts +++ b/plugins/azure-devops-backend/src/index.ts @@ -23,3 +23,4 @@ export { AzureDevOpsApi } from './api'; export * from './service/router'; export { azureDevOpsPlugin as default } from './plugin'; +export { AzureDevOpsAnnotatorProcessor } from './processor'; diff --git a/plugins/azure-devops-backend/src/processor/AzureDevOpsAnnotatorProcessor.test.ts b/plugins/azure-devops-backend/src/processor/AzureDevOpsAnnotatorProcessor.test.ts new file mode 100644 index 0000000000..dd83c56f70 --- /dev/null +++ b/plugins/azure-devops-backend/src/processor/AzureDevOpsAnnotatorProcessor.test.ts @@ -0,0 +1,271 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { Entity } from '@backstage/catalog-model'; +import { ConfigReader } from '@backstage/config'; +import { AzureDevOpsAnnotatorProcessor } from './AzureDevOpsAnnotatorProcessor'; +import { LocationSpec } from '@backstage/plugin-catalog-common'; + +describe('AzureDevOpsAnnotatorProcessor', () => { + it('adds annotation', async () => { + const entity: Entity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'my-component', + }, + }; + const location: LocationSpec = { + type: 'url', + target: + 'https://dev.azure.com/organization/project/_git/repository?path=%2Fcatalog-info.yaml', + }; + + const processor = AzureDevOpsAnnotatorProcessor.fromConfig( + new ConfigReader({}), + ); + + expect(await processor.preProcessEntity(entity, location)).toEqual({ + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'my-component', + annotations: { + 'dev.azure.com/host-org': 'dev.azure.com/organization', + 'dev.azure.com/project-repo': 'project/repository', + }, + }, + }); + }); + + it('adds annotation for Azure DevOps Server url', async () => { + const entity: Entity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'my-component', + }, + }; + const location: LocationSpec = { + type: 'url', + target: + 'https://example.com/organization/project/_git/repository?path=%2Fcatalog-info.yaml', + }; + + const processor = AzureDevOpsAnnotatorProcessor.fromConfig( + new ConfigReader({ + integrations: { + azure: [ + { + host: 'example.com', + credentials: [ + { + personalAccessToken: 'pat', + }, + ], + }, + ], + }, + }), + ); + + expect(await processor.preProcessEntity(entity, location)).toEqual({ + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'my-component', + annotations: { + 'dev.azure.com/host-org': 'example.com/organization', + 'dev.azure.com/project-repo': 'project/repository', + }, + }, + }); + }); + + it('adds annotation for TFS subpath url', async () => { + const entity: Entity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'my-component', + }, + }; + const location: LocationSpec = { + type: 'url', + target: + 'https://example.com/tfs/organization/project/_git/repository?path=%2Fcatalog-info.yaml', + }; + + const processor = AzureDevOpsAnnotatorProcessor.fromConfig( + new ConfigReader({ + integrations: { + azure: [ + { + host: 'example.com', + credentials: [ + { + personalAccessToken: 'pat', + }, + ], + }, + ], + }, + }), + ); + + expect(await processor.preProcessEntity(entity, location)).toEqual({ + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'my-component', + annotations: { + 'dev.azure.com/host-org': 'example.com/tfs/organization', + 'dev.azure.com/project-repo': 'project/repository', + }, + }, + }); + }); + + it('does not override existing annotation', async () => { + const entity: Entity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'my-component', + annotations: { + 'dev.azure.com/host-org': 'myhost/myorg', + 'dev.azure.com/project-repo': 'myproj/myrepo', + }, + }, + }; + const location: LocationSpec = { + type: 'url', + target: + 'https://dev.azure.com/organization/project/_git/repository?path=%2Fcatalog-info.yaml', + }; + + const processor = AzureDevOpsAnnotatorProcessor.fromConfig( + new ConfigReader({}), + ); + + expect(await processor.preProcessEntity(entity, location)).toEqual({ + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'my-component', + annotations: { + 'dev.azure.com/host-org': 'myhost/myorg', + 'dev.azure.com/project-repo': 'myproj/myrepo', + }, + }, + }); + }); + + it('should not add annotation for other providers', async () => { + const entity: Entity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'my-component', + }, + }; + const location: LocationSpec = { + type: 'url', + target: + 'https://not-in-mock-config.example.com/backstage/backstage/-/blob/master/catalog-info.yaml', + }; + + const processor = AzureDevOpsAnnotatorProcessor.fromConfig( + new ConfigReader({}), + ); + + expect(await processor.preProcessEntity(entity, location)).toEqual({ + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'my-component', + }, + }); + }); + + it('should only process applicable kinds', async () => { + const component: Entity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'my-component', + }, + }; + + const api: Entity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'API', + metadata: { + name: 'my-component', + }, + }; + + const system: Entity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'System', + metadata: { + name: 'my-component', + }, + }; + + const location: LocationSpec = { + type: 'url', + target: + 'https://dev.azure.com/organization/project/_git/repository?path=%2Fcatalog-info.yaml', + }; + + const processor = AzureDevOpsAnnotatorProcessor.fromConfig( + new ConfigReader({}), + { kinds: ['API', 'Component'] }, + ); + + expect(await processor.preProcessEntity(component, location)).toEqual({ + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'my-component', + annotations: { + 'dev.azure.com/host-org': 'dev.azure.com/organization', + 'dev.azure.com/project-repo': 'project/repository', + }, + }, + }); + + expect(await processor.preProcessEntity(api, location)).toEqual({ + apiVersion: 'backstage.io/v1alpha1', + kind: 'API', + metadata: { + name: 'my-component', + annotations: { + 'dev.azure.com/host-org': 'dev.azure.com/organization', + 'dev.azure.com/project-repo': 'project/repository', + }, + }, + }); + + expect(await processor.preProcessEntity(system, location)).toEqual({ + apiVersion: 'backstage.io/v1alpha1', + kind: 'System', + metadata: { + name: 'my-component', + }, + }); + }); +}); diff --git a/plugins/azure-devops-backend/src/processor/AzureDevOpsAnnotatorProcessor.ts b/plugins/azure-devops-backend/src/processor/AzureDevOpsAnnotatorProcessor.ts new file mode 100644 index 0000000000..c27195b8ac --- /dev/null +++ b/plugins/azure-devops-backend/src/processor/AzureDevOpsAnnotatorProcessor.ts @@ -0,0 +1,127 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Entity } from '@backstage/catalog-model'; +import { Config } from '@backstage/config'; +import { + ScmIntegrationRegistry, + ScmIntegrations, +} from '@backstage/integration'; +import { identity, merge, pickBy } from 'lodash'; +import { LocationSpec } from '@backstage/plugin-catalog-common'; +import { CatalogProcessor } from '@backstage/plugin-catalog-node'; +import { + AZURE_DEVOPS_HOST_ORG_ANNOTATION, + AZURE_DEVOPS_REPO_ANNOTATION, +} from '@backstage/plugin-azure-devops-common'; +import { parseAzureDevOpsUrl } from '../utils'; + +/** @public */ +export class AzureDevOpsAnnotatorProcessor implements CatalogProcessor { + constructor( + private readonly opts: { + scmIntegrationRegistry: ScmIntegrationRegistry; + kinds?: string[]; + }, + ) {} + + getProcessorName(): string { + return 'AzureDevOpsAnnotatorProcessor'; + } + + static fromConfig( + config: Config, + options?: { kinds?: string[] }, + ): AzureDevOpsAnnotatorProcessor { + return new AzureDevOpsAnnotatorProcessor({ + scmIntegrationRegistry: ScmIntegrations.fromConfig(config), + kinds: options?.kinds, + }); + } + + async preProcessEntity( + entity: Entity, + location: LocationSpec, + ): Promise { + const applicableKinds = (this.opts.kinds ?? ['Component']).map(k => + k.toLocaleLowerCase('en-US'), + ); + if ( + !applicableKinds.includes(entity.kind.toLocaleLowerCase('en-US')) || + location.type !== 'url' + ) { + return entity; + } + + const scmIntegration = this.opts.scmIntegrationRegistry.byUrl( + location.target, + ); + + if (!scmIntegration) { + return entity; + } + + if (scmIntegration.type !== 'azure') { + return entity; + } + + const { host, org, project, repo } = parseAzureDevOpsUrl(location.target); + + if (!org || !project || !repo) { + return entity; + } + + const hostOrgAnnotation = AZURE_DEVOPS_HOST_ORG_ANNOTATION; + let hostOrgValue = entity.metadata.annotations?.[hostOrgAnnotation]; + if (!hostOrgValue) { + hostOrgValue = `${host}/${org}`; + } + + const projectRepoAnnotation = AZURE_DEVOPS_REPO_ANNOTATION; + let projectRepoValue = entity.metadata.annotations?.[projectRepoAnnotation]; + if (!projectRepoValue) { + projectRepoValue = `${project}/${repo}`; + } + + const result = merge( + { + metadata: { + annotations: pickBy( + { + [hostOrgAnnotation]: hostOrgValue, + }, + identity, + ), + }, + }, + entity, + ); + + return merge( + { + metadata: { + annotations: pickBy( + { + [projectRepoAnnotation]: projectRepoValue, + }, + identity, + ), + }, + }, + result, + ); + } +} diff --git a/plugins/azure-devops-backend/src/processor/index.ts b/plugins/azure-devops-backend/src/processor/index.ts new file mode 100644 index 0000000000..46747c4802 --- /dev/null +++ b/plugins/azure-devops-backend/src/processor/index.ts @@ -0,0 +1,17 @@ +/* + * 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 { AzureDevOpsAnnotatorProcessor } from './AzureDevOpsAnnotatorProcessor'; diff --git a/plugins/azure-devops-backend/src/utils/azure-devops-utils.test.ts b/plugins/azure-devops-backend/src/utils/azure-devops-utils.test.ts index 427980be14..86a06b7b0b 100644 --- a/plugins/azure-devops-backend/src/utils/azure-devops-utils.test.ts +++ b/plugins/azure-devops-backend/src/utils/azure-devops-utils.test.ts @@ -28,6 +28,7 @@ import { getPullRequestLink, replaceReadme, buildEncodedUrl, + parseAzureDevOpsUrl, } from './azure-devops-utils'; import { GitPullRequest } from 'azure-devops-node-api/interfaces/GitInterfaces'; import { UrlReader } from '@backstage/backend-common'; @@ -295,3 +296,38 @@ describe('buildEncodedUrl', () => { ); }); }); + +describe('parseAzureDevOpsUrl', () => { + it('parses Azure DevOps Cloud url', async () => { + const result = parseAzureDevOpsUrl( + 'https://dev.azure.com/organization/project/_git/repository?path=%2Fcatalog-info.yaml', + ); + + expect(result.host).toEqual('dev.azure.com'); + expect(result.org).toEqual('organization'); + expect(result.project).toEqual('project'); + expect(result.repo).toEqual('repository'); + }); + + it('parses Azure DevOps Server url', async () => { + const result = parseAzureDevOpsUrl( + 'https://server.com/organization/project/_git/repository?path=%2Fcatalog-info.yaml', + ); + + expect(result.host).toEqual('server.com'); + expect(result.org).toEqual('organization'); + expect(result.project).toEqual('project'); + expect(result.repo).toEqual('repository'); + }); + + it('parses TFS subpath Url', async () => { + const result = parseAzureDevOpsUrl( + 'https://server.com/tfs/organization/project/_git/repository?path=%2Fcatalog-info.yaml', + ); + + expect(result.host).toEqual('server.com/tfs'); + expect(result.org).toEqual('organization'); + expect(result.project).toEqual('project'); + expect(result.repo).toEqual('repository'); + }); +}); diff --git a/plugins/azure-devops-backend/src/utils/azure-devops-utils.ts b/plugins/azure-devops-backend/src/utils/azure-devops-utils.ts index aa946e7a74..7f5bf39ac4 100644 --- a/plugins/azure-devops-backend/src/utils/azure-devops-utils.ts +++ b/plugins/azure-devops-backend/src/utils/azure-devops-utils.ts @@ -328,3 +328,29 @@ export function extractPartsFromAsset(content: string): { path: path.startsWith('.') ? path.substring(1, path.length) : path, }; } + +export function parseAzureDevOpsUrl(sourceUrl: string) { + const url = new URL(sourceUrl); + + let host = url.host; + let org; + let project; + let repo; + + const parts = url.pathname.split('/').map(part => decodeURIComponent(part)); + if (parts[2] === '_git') { + org = parts[1]; + project = repo = parts[3]; + } else if (parts[3] === '_git') { + org = parts[1]; + project = parts[2]; + repo = parts[4]; + } else if (parts[4] === '_git') { + host = `${host}/${parts[1]}`; + org = parts[2]; + project = parts[3]; + repo = parts[5]; + } + + return { host, org, project, repo }; +} diff --git a/plugins/azure-devops-common/api-report.md b/plugins/azure-devops-common/api-report.md index ea9f7130c0..262d5c8136 100644 --- a/plugins/azure-devops-common/api-report.md +++ b/plugins/azure-devops-common/api-report.md @@ -3,6 +3,22 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +// @public (undocumented) +export const AZURE_DEVOPS_BUILD_DEFINITION_ANNOTATION = + 'dev.azure.com/build-definition'; + +// @public (undocumented) +export const AZURE_DEVOPS_DEFAULT_TOP: number; + +// @public (undocumented) +export const AZURE_DEVOPS_HOST_ORG_ANNOTATION = 'dev.azure.com/host-org'; + +// @public (undocumented) +export const AZURE_DEVOPS_PROJECT_ANNOTATION = 'dev.azure.com/project'; + +// @public (undocumented) +export const AZURE_DEVOPS_REPO_ANNOTATION = 'dev.azure.com/project-repo'; + // @public (undocumented) export enum BuildResult { Canceled = 32, diff --git a/plugins/azure-devops/src/constants.ts b/plugins/azure-devops-common/src/constants.ts similarity index 92% rename from plugins/azure-devops/src/constants.ts rename to plugins/azure-devops-common/src/constants.ts index aba0ec093a..5cc6b54592 100644 --- a/plugins/azure-devops/src/constants.ts +++ b/plugins/azure-devops-common/src/constants.ts @@ -14,9 +14,14 @@ * limitations under the License. */ +/** @public */ export const AZURE_DEVOPS_BUILD_DEFINITION_ANNOTATION = 'dev.azure.com/build-definition'; +/** @public */ export const AZURE_DEVOPS_HOST_ORG_ANNOTATION = 'dev.azure.com/host-org'; +/** @public */ export const AZURE_DEVOPS_PROJECT_ANNOTATION = 'dev.azure.com/project'; +/** @public */ export const AZURE_DEVOPS_REPO_ANNOTATION = 'dev.azure.com/project-repo'; +/** @public */ export const AZURE_DEVOPS_DEFAULT_TOP: number = 10; diff --git a/plugins/azure-devops-common/src/index.ts b/plugins/azure-devops-common/src/index.ts index 26a854de89..9a4a007317 100644 --- a/plugins/azure-devops-common/src/index.ts +++ b/plugins/azure-devops-common/src/index.ts @@ -15,3 +15,4 @@ */ export * from './types'; +export * from './constants'; diff --git a/plugins/azure-devops/src/hooks/useBuildRuns.ts b/plugins/azure-devops/src/hooks/useBuildRuns.ts index 2b70ea63a5..0c10dc8db8 100644 --- a/plugins/azure-devops/src/hooks/useBuildRuns.ts +++ b/plugins/azure-devops/src/hooks/useBuildRuns.ts @@ -15,11 +15,11 @@ */ import { + AZURE_DEVOPS_DEFAULT_TOP, BuildRun, BuildRunOptions, } from '@backstage/plugin-azure-devops-common'; -import { AZURE_DEVOPS_DEFAULT_TOP } from '../constants'; import { azureDevOpsApiRef } from '../api'; import { useApi } from '@backstage/core-plugin-api'; import useAsync from 'react-use/lib/useAsync'; diff --git a/plugins/azure-devops/src/hooks/usePullRequests.ts b/plugins/azure-devops/src/hooks/usePullRequests.ts index de886919eb..1ac6afae24 100644 --- a/plugins/azure-devops/src/hooks/usePullRequests.ts +++ b/plugins/azure-devops/src/hooks/usePullRequests.ts @@ -15,12 +15,12 @@ */ import { + AZURE_DEVOPS_DEFAULT_TOP, PullRequest, PullRequestOptions, PullRequestStatus, } from '@backstage/plugin-azure-devops-common'; -import { AZURE_DEVOPS_DEFAULT_TOP } from '../constants'; import { Entity } from '@backstage/catalog-model'; import { azureDevOpsApiRef } from '../api'; import { useApi } from '@backstage/core-plugin-api'; diff --git a/plugins/azure-devops/src/plugin.ts b/plugins/azure-devops/src/plugin.ts index 4dd423f35a..1e76c9e53a 100644 --- a/plugins/azure-devops/src/plugin.ts +++ b/plugins/azure-devops/src/plugin.ts @@ -14,11 +14,6 @@ * limitations under the License. */ -import { - AZURE_DEVOPS_BUILD_DEFINITION_ANNOTATION, - AZURE_DEVOPS_PROJECT_ANNOTATION, - AZURE_DEVOPS_REPO_ANNOTATION, -} from './constants'; import { azurePipelinesEntityContentRouteRef, azurePullRequestDashboardRouteRef, @@ -37,6 +32,11 @@ import { import { AzureDevOpsClient } from './api/AzureDevOpsClient'; import { Entity } from '@backstage/catalog-model'; import { azureDevOpsApiRef } from './api/AzureDevOpsApi'; +import { + AZURE_DEVOPS_REPO_ANNOTATION, + AZURE_DEVOPS_PROJECT_ANNOTATION, + AZURE_DEVOPS_BUILD_DEFINITION_ANNOTATION, +} from '@backstage/plugin-azure-devops-common'; /** @public */ export const isAzureDevOpsAvailable = (entity: Entity) => diff --git a/plugins/azure-devops/src/utils/getAnnotationValuesFromEntity.ts b/plugins/azure-devops/src/utils/getAnnotationValuesFromEntity.ts index 9feec8bf95..dec140706c 100644 --- a/plugins/azure-devops/src/utils/getAnnotationValuesFromEntity.ts +++ b/plugins/azure-devops/src/utils/getAnnotationValuesFromEntity.ts @@ -14,14 +14,13 @@ * limitations under the License. */ -import { - AZURE_DEVOPS_BUILD_DEFINITION_ANNOTATION, - AZURE_DEVOPS_HOST_ORG_ANNOTATION, - AZURE_DEVOPS_PROJECT_ANNOTATION, - AZURE_DEVOPS_REPO_ANNOTATION, -} from '../constants'; - import { Entity } from '@backstage/catalog-model'; +import { + AZURE_DEVOPS_PROJECT_ANNOTATION, + AZURE_DEVOPS_BUILD_DEFINITION_ANNOTATION, + AZURE_DEVOPS_REPO_ANNOTATION, + AZURE_DEVOPS_HOST_ORG_ANNOTATION, +} from '@backstage/plugin-azure-devops-common'; export function getAnnotationValuesFromEntity(entity: Entity): { project: string; diff --git a/yarn.lock b/yarn.lock index 1b42d4915a..7c124c371d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5049,14 +5049,19 @@ __metadata: dependencies: "@backstage/backend-common": "workspace:^" "@backstage/backend-plugin-api": "workspace:^" + "@backstage/catalog-model": "workspace:^" "@backstage/cli": "workspace:^" "@backstage/config": "workspace:^" + "@backstage/integration": "workspace:^" "@backstage/plugin-azure-devops-common": "workspace:^" + "@backstage/plugin-catalog-common": "workspace:^" + "@backstage/plugin-catalog-node": "workspace:^" "@types/express": ^4.17.6 "@types/supertest": ^2.0.8 azure-devops-node-api: ^11.0.1 express: ^4.17.1 express-promise-router: ^4.1.0 + lodash: ^4.17.21 mime-types: ^2.1.27 msw: ^1.0.0 p-limit: ^3.1.0 From 43b2eb8f7050373bf7c6d0192cbfa164d9a4d35a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Sat, 25 Nov 2023 11:06:17 +0100 Subject: [PATCH 094/261] ensure that incremental ingestion cursors are json decoded MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .changeset/rich-singers-join.md | 5 ++ ...ncrementalIngestionDatabaseManager.test.ts | 79 +++++++++++++++++++ .../IncrementalIngestionDatabaseManager.ts | 19 ++++- .../src/database/tables.ts | 2 +- 4 files changed, 101 insertions(+), 4 deletions(-) create mode 100644 .changeset/rich-singers-join.md create mode 100644 plugins/catalog-backend-module-incremental-ingestion/src/database/IncrementalIngestionDatabaseManager.test.ts diff --git a/.changeset/rich-singers-join.md b/.changeset/rich-singers-join.md new file mode 100644 index 0000000000..1a21fa9fc8 --- /dev/null +++ b/.changeset/rich-singers-join.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend-module-incremental-ingestion': patch +--- + +Ensure that cursors always come back as JSON on sqlite too diff --git a/plugins/catalog-backend-module-incremental-ingestion/src/database/IncrementalIngestionDatabaseManager.test.ts b/plugins/catalog-backend-module-incremental-ingestion/src/database/IncrementalIngestionDatabaseManager.test.ts new file mode 100644 index 0000000000..a8862cfc2a --- /dev/null +++ b/plugins/catalog-backend-module-incremental-ingestion/src/database/IncrementalIngestionDatabaseManager.test.ts @@ -0,0 +1,79 @@ +/* + * 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 { TestDatabases } from '@backstage/backend-test-utils'; +import { IncrementalIngestionDatabaseManager } from './IncrementalIngestionDatabaseManager'; +import { v4 as uuid } from 'uuid'; + +const migrationsDir = `${__dirname}/../../migrations`; + +jest.setTimeout(60_000); + +describe('IncrementalIngestionDatabaseManager', () => { + const databases = TestDatabases.create({ + ids: ['POSTGRES_13', 'POSTGRES_9', 'SQLITE_3'], + }); + + it.each(databases.eachSupportedId())( + 'stores and retrieves marks, %p', + async databaseId => { + const knex = await databases.init(databaseId); + await knex.migrate.latest({ directory: migrationsDir }); + + const manager = new IncrementalIngestionDatabaseManager({ client: knex }); + const { ingestionId } = (await manager.createProviderIngestionRecord( + 'myProvider', + ))!; + + const cursorId = uuid(); + + await manager.createMark({ + record: { + id: cursorId, + ingestion_id: ingestionId, + sequence: 1, + cursor: { data: 1 }, + }, + }); + + await expect(manager.getFirstMark(ingestionId)).resolves.toEqual({ + created_at: expect.anything(), + cursor: { data: 1 }, + id: cursorId, + ingestion_id: ingestionId, + sequence: 1, + }); + + await expect(manager.getLastMark(ingestionId)).resolves.toEqual({ + created_at: expect.anything(), + cursor: { data: 1 }, + id: cursorId, + ingestion_id: ingestionId, + sequence: 1, + }); + + await expect(manager.getAllMarks(ingestionId)).resolves.toEqual([ + { + created_at: expect.anything(), + cursor: { data: 1 }, + id: cursorId, + ingestion_id: ingestionId, + sequence: 1, + }, + ]); + }, + ); +}); diff --git a/plugins/catalog-backend-module-incremental-ingestion/src/database/IncrementalIngestionDatabaseManager.ts b/plugins/catalog-backend-module-incremental-ingestion/src/database/IncrementalIngestionDatabaseManager.ts index 527d345706..e47954f47e 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/src/database/IncrementalIngestionDatabaseManager.ts +++ b/plugins/catalog-backend-module-incremental-ingestion/src/database/IncrementalIngestionDatabaseManager.ts @@ -542,7 +542,7 @@ export class IncrementalIngestionDatabaseManager { .where('ingestion_id', ingestionId) .orderBy('sequence', 'desc') .first(); - return mark; + return this.#decodeMark(this.client, mark); }); } @@ -557,7 +557,7 @@ export class IncrementalIngestionDatabaseManager { .where('ingestion_id', ingestionId) .orderBy('sequence', 'asc') .first(); - return mark; + return this.#decodeMark(this.client, mark); }); } @@ -566,7 +566,7 @@ export class IncrementalIngestionDatabaseManager { const marks = await tx('ingestion_marks') .where('ingestion_id', ingestionId) .orderBy('sequence', 'desc'); - return marks; + return marks.map(m => this.#decodeMark(this.client, m)); }); } @@ -580,6 +580,19 @@ export class IncrementalIngestionDatabaseManager { await tx('ingestion_marks').insert(record); }); } + + // Handles the fact that sqlite does not support json columns; they just + // persist the stringified data instead + #decodeMark(knex: Knex, record: T): T { + if (record && knex.client.config.client.includes('sqlite3')) { + return { + ...record, + cursor: JSON.parse(record.cursor as string), + }; + } + return record; + } + /** * Performs an upsert to the `ingestion_mark_entities` table for all deferred entities. * @param markId - string diff --git a/plugins/catalog-backend-module-incremental-ingestion/src/database/tables.ts b/plugins/catalog-backend-module-incremental-ingestion/src/database/tables.ts index 00d40fb4a1..e1a47c040c 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/src/database/tables.ts +++ b/plugins/catalog-backend-module-incremental-ingestion/src/database/tables.ts @@ -89,7 +89,7 @@ export interface MarkRecord { id: string; sequence: number; ingestion_id: string; - cursor: string; + cursor: unknown; created_at: string; } From 7f8a801e6d72d1fc132b4babc447ed3afd6b08e8 Mon Sep 17 00:00:00 2001 From: Diego Mondragon Date: Mon, 16 Oct 2023 12:00:24 -0700 Subject: [PATCH 095/261] Added examples for `sentry:project:create` action and unit tests. Signed-off-by: Diego Mondragon --- .changeset/tender-peas-smoke.md | 5 + .../package.json | 6 +- .../src/actions/createProject.examples.ts | 53 +++++ .../src/actions/createProject.test.ts | 207 ++++++++++++++++++ .../src/actions/createProject.ts | 6 +- 5 files changed, 273 insertions(+), 4 deletions(-) create mode 100644 .changeset/tender-peas-smoke.md create mode 100644 plugins/scaffolder-backend-module-sentry/src/actions/createProject.examples.ts create mode 100644 plugins/scaffolder-backend-module-sentry/src/actions/createProject.test.ts diff --git a/.changeset/tender-peas-smoke.md b/.changeset/tender-peas-smoke.md new file mode 100644 index 0000000000..5c84e1a131 --- /dev/null +++ b/.changeset/tender-peas-smoke.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend-module-sentry': patch +--- + +Added examples for `sentry:project:create` scaffolder action and unit tests. diff --git a/plugins/scaffolder-backend-module-sentry/package.json b/plugins/scaffolder-backend-module-sentry/package.json index 58b39a6b5c..0aa4b5b1c8 100644 --- a/plugins/scaffolder-backend-module-sentry/package.json +++ b/plugins/scaffolder-backend-module-sentry/package.json @@ -30,10 +30,12 @@ "dependencies": { "@backstage/config": "workspace:^", "@backstage/errors": "workspace:^", - "@backstage/plugin-scaffolder-node": "workspace:^" + "@backstage/plugin-scaffolder-node": "workspace:^", + "yaml": "^2.3.3" }, "devDependencies": { - "@backstage/cli": "workspace:^" + "@backstage/cli": "workspace:^", + "@backstage/types": "workspace:^" }, "files": [ "dist" diff --git a/plugins/scaffolder-backend-module-sentry/src/actions/createProject.examples.ts b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.examples.ts new file mode 100644 index 0000000000..9d4551c1b5 --- /dev/null +++ b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.examples.ts @@ -0,0 +1,53 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { TemplateExample } from '@backstage/plugin-scaffolder-node'; +import yaml from 'yaml'; + +export const examples: TemplateExample[] = [ + { + description: 'Creates a Sentry project with the specified parameters.', + example: yaml.stringify({ + steps: [ + { + id: 'create-sentry-project', + action: 'sentry:project:create', + name: 'Create a Sentry project with provided project slug.', + input: { + organizationSlug: 'my-org', + teamSlug: 'team-a', + name: 'Scaffolded project A', + slug: 'scaff-proj-a', + authToken: + 'a14711beb516e1e910d2ede554dc1bf725654ef3c75e5a9106de9aec13d5df96', + }, + }, + { + id: 'create-sentry-project', + action: 'sentry:project:create', + name: 'Create a Sentry project without providing a project slug.', + input: { + organizationSlug: 'my-org', + teamSlug: 'team-b', + name: 'Scaffolded project B', + authToken: + 'b15711beb516e1e910d2ede554dc1bf725654ef3c75e5a9106de9aec13d4gf93', + }, + }, + ], + }), + }, +]; diff --git a/plugins/scaffolder-backend-module-sentry/src/actions/createProject.test.ts b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.test.ts new file mode 100644 index 0000000000..e58f2dc177 --- /dev/null +++ b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.test.ts @@ -0,0 +1,207 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { ConfigReader } from '@backstage/config'; +import { JsonObject } from '@backstage/types'; +import { createSentryCreateProjectAction } from './createProject'; +import { ActionContext } from '@backstage/plugin-scaffolder-node'; +import { InputError } from '@backstage/errors'; + +describe('sentry:project:create action', () => { + const createScaffolderConfig = (configData: JsonObject = {}) => ({ + config: new ConfigReader({ + scaffolder: { + ...configData, + }, + }), + }); + + const mockFetch = (response = {}) => { + const mockedResponse = { + status: 201, + headers: { + get: () => 'application/json', + }, + json: async () => + Promise.resolve({ + detail: 'project creation mocked result', + }), + text: async () => Promise.resolve('Unexpected error.'), + ...response, + }; + global.fetch = jest + .fn() + .mockImplementation(() => Promise.resolve(mockedResponse)); + + return mockedResponse; + }; + + const getActionContext = (): ActionContext<{ + organizationSlug: string; + teamSlug: string; + name: string; + slug?: string; + authToken?: string; + }> => ({ + workspacePath: './dev/proj', + createTemporaryDirectory: jest.fn(), + logger: jest.createMockFromModule('winston'), + logStream: jest.createMockFromModule('stream'), + input: { + organizationSlug: 'org', + teamSlug: 'team', + name: 'test project', + authToken: '008hsd7f7123hhdsfhfds7123123881239889fdsaf1g', + }, + output: jest.fn(), + }); + + beforeEach(() => { + mockFetch(); + }); + + test('should request sentry project create with specified parameters.', async () => { + const action = createSentryCreateProjectAction(createScaffolderConfig()); + const actionContext = getActionContext(); + + await action.handler(actionContext); + + expect(fetch).toHaveBeenNthCalledWith( + 1, + `https://sentry.io/api/0/teams/${actionContext.input.organizationSlug}/${actionContext.input.teamSlug}/projects/`, + { + method: 'POST', + headers: { + Authorization: `Bearer ${actionContext.input.authToken}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + name: actionContext.input.name, + }), + }, + ); + }); + + test('should request sentry project create with added optional specified project slug', async () => { + const action = createSentryCreateProjectAction(createScaffolderConfig()); + const actionContext = getActionContext(); + + actionContext.input = { ...actionContext.input, slug: 'project-slug' }; + + await action.handler(actionContext); + + expect(global.fetch).toHaveBeenNthCalledWith( + 1, + `https://sentry.io/api/0/teams/${actionContext.input.organizationSlug}/${actionContext.input.teamSlug}/projects/`, + { + method: 'POST', + headers: { + Authorization: `Bearer ${actionContext.input.authToken}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + name: actionContext.input.name, + slug: actionContext.input.slug, + }), + }, + ); + }); + + test('should take Sentry auth token from scaffolder config when input authToken is missing.', async () => { + const sentryScaffolderConfigToken = + 'scaffolder app-config.yaml scaffolder token'; + const action = createSentryCreateProjectAction( + createScaffolderConfig({ + sentry: { + token: sentryScaffolderConfigToken, + }, + }), + ); + + const actionContext = getActionContext(); + + actionContext.input.authToken = undefined; + + await action.handler(actionContext); + + expect(fetch).toHaveBeenNthCalledWith( + 1, + `https://sentry.io/api/0/teams/${actionContext.input.organizationSlug}/${actionContext.input.teamSlug}/projects/`, + { + method: 'POST', + headers: { + Authorization: `Bearer ${sentryScaffolderConfigToken}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + name: actionContext.input.name, + }), + }, + ); + }); + + test('should throw InputError when auth token is missing from input parameters and scaffolder config.', async () => { + const action = createSentryCreateProjectAction(createScaffolderConfig()); + const actionContext = getActionContext(); + + actionContext.input.authToken = undefined; + + expect.assertions(1); + + await expect(async () => { + await action.handler(actionContext); + }).rejects.toThrow(new InputError('No valid sentry token given')); + }); + + test('should throw InputError when sentry API returns unexpected content-type.', async () => { + const action = createSentryCreateProjectAction(createScaffolderConfig()); + const actionContext = getActionContext(); + + const mockedFetchResponse = mockFetch({ + headers: { + get: () => 'text/html', + }, + }); + + expect.assertions(1); + + await expect(async () => { + await action.handler(actionContext); + }).rejects.toThrow( + new InputError( + `Unexpected Sentry Response Type: ${await mockedFetchResponse.text()}`, + ), + ); + }); + + test('should throw InputError when sentry API returns unexpected status code.', async () => { + const action = createSentryCreateProjectAction(createScaffolderConfig()); + const actionContext = getActionContext(); + + const mockedFetchResponse = mockFetch({ + status: 400, + }); + + expect.assertions(1); + + await expect(async () => { + await action.handler(actionContext); + }).rejects.toThrow( + new InputError( + `Sentry Response was: ${(await mockedFetchResponse.json()).detail}`, + ), + ); + }); +}); diff --git a/plugins/scaffolder-backend-module-sentry/src/actions/createProject.ts b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.ts index 85a74eda07..504084b9df 100644 --- a/plugins/scaffolder-backend-module-sentry/src/actions/createProject.ts +++ b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.ts @@ -17,9 +17,10 @@ import { createTemplateAction } from '@backstage/plugin-scaffolder-node'; import { InputError } from '@backstage/errors'; import { Config } from '@backstage/config'; +import { examples } from './createProject.examples'; /** - * Creates the `sentry:craete-project` Scaffolder action. + * Creates the `sentry:create-project` Scaffolder action. * * @remarks * @@ -39,6 +40,7 @@ export function createSentryCreateProjectAction(options: { config: Config }) { authToken?: string; }>({ id: 'sentry:project:create', + examples, schema: { input: { required: ['organizationSlug', 'teamSlug', 'name'], @@ -112,7 +114,7 @@ export function createSentryCreateProjectAction(options: { config: Config }) { const result = await response.json(); if (code !== 201) { - throw new InputError(`Sentry Response was: ${await result.detail}`); + throw new InputError(`Sentry Response was: ${result.detail}`); } ctx.output('id', result.id); From f35b34d10d770f973b8f71059889d4fa3b0eba23 Mon Sep 17 00:00:00 2001 From: Diego Mondragon Date: Thu, 19 Oct 2023 10:10:23 -0700 Subject: [PATCH 096/261] Fixed deps install yarn.lock file Signed-off-by: Diego Mondragon --- yarn.lock | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/yarn.lock b/yarn.lock index 1b42d4915a..968acd6f80 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8662,6 +8662,8 @@ __metadata: "@backstage/config": "workspace:^" "@backstage/errors": "workspace:^" "@backstage/plugin-scaffolder-node": "workspace:^" + "@backstage/types": "workspace:^" + yaml: ^2.3.3 languageName: unknown linkType: soft @@ -45031,7 +45033,7 @@ __metadata: languageName: node linkType: hard -"yaml@npm:2.3.4, yaml@npm:^2.0.0, yaml@npm:^2.0.0-10, yaml@npm:^2.1.1, yaml@npm:^2.2.1, yaml@npm:^2.2.2, yaml@npm:^2.3.2": +"yaml@npm:2.3.4, yaml@npm:^2.0.0, yaml@npm:^2.0.0-10, yaml@npm:^2.1.1, yaml@npm:^2.2.1, yaml@npm:^2.2.2, yaml@npm:^2.3.2, yaml@npm:^2.3.3": version: 2.3.4 resolution: "yaml@npm:2.3.4" checksum: e6d1dae1c6383bcc8ba11796eef3b8c02d5082911c6723efeeb5ba50fc8e881df18d645e64de68e421b577296000bea9c75d6d9097c2f6699da3ae0406c030d8 From d58984cc484f7347b5f58780bd7a34793dbfc0fa Mon Sep 17 00:00:00 2001 From: Diego Mondragon Date: Thu, 19 Oct 2023 13:19:30 -0700 Subject: [PATCH 097/261] Generate fake tokens for tests. Signed-off-by: Diego Mondragon --- .../src/actions/createProject.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/scaffolder-backend-module-sentry/src/actions/createProject.test.ts b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.test.ts index e58f2dc177..ea892882ea 100644 --- a/plugins/scaffolder-backend-module-sentry/src/actions/createProject.test.ts +++ b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.test.ts @@ -18,6 +18,7 @@ import { JsonObject } from '@backstage/types'; import { createSentryCreateProjectAction } from './createProject'; import { ActionContext } from '@backstage/plugin-scaffolder-node'; import { InputError } from '@backstage/errors'; +import { randomBytes } from 'crypto'; describe('sentry:project:create action', () => { const createScaffolderConfig = (configData: JsonObject = {}) => ({ @@ -63,7 +64,7 @@ describe('sentry:project:create action', () => { organizationSlug: 'org', teamSlug: 'team', name: 'test project', - authToken: '008hsd7f7123hhdsfhfds7123123881239889fdsaf1g', + authToken: randomBytes(5).toString('hex'), }, output: jest.fn(), }); @@ -120,8 +121,7 @@ describe('sentry:project:create action', () => { }); test('should take Sentry auth token from scaffolder config when input authToken is missing.', async () => { - const sentryScaffolderConfigToken = - 'scaffolder app-config.yaml scaffolder token'; + const sentryScaffolderConfigToken = randomBytes(5).toString('hex'); const action = createSentryCreateProjectAction( createScaffolderConfig({ sentry: { From 15b9fbf89c29baa6b7d59d8e4dba5749a8de2ff2 Mon Sep 17 00:00:00 2001 From: Diego Mondragon Date: Mon, 23 Oct 2023 15:00:43 -0700 Subject: [PATCH 098/261] Added fetchApi param to enable passing fetch function implementation Signed-off-by: Diego Mondragon --- .../package.json | 1 + .../src/actions/createProject.test.ts | 33 ++++++++++++++----- .../src/actions/createProject.ts | 9 +++-- yarn.lock | 1 + 4 files changed, 33 insertions(+), 11 deletions(-) diff --git a/plugins/scaffolder-backend-module-sentry/package.json b/plugins/scaffolder-backend-module-sentry/package.json index 0aa4b5b1c8..eccae89620 100644 --- a/plugins/scaffolder-backend-module-sentry/package.json +++ b/plugins/scaffolder-backend-module-sentry/package.json @@ -29,6 +29,7 @@ }, "dependencies": { "@backstage/config": "workspace:^", + "@backstage/core-plugin-api": "workspace:^", "@backstage/errors": "workspace:^", "@backstage/plugin-scaffolder-node": "workspace:^", "yaml": "^2.3.3" diff --git a/plugins/scaffolder-backend-module-sentry/src/actions/createProject.test.ts b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.test.ts index ea892882ea..b66f842688 100644 --- a/plugins/scaffolder-backend-module-sentry/src/actions/createProject.test.ts +++ b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.test.ts @@ -29,6 +29,8 @@ describe('sentry:project:create action', () => { }), }); + let fetch: jest.Func; + const mockFetch = (response = {}) => { const mockedResponse = { status: 201, @@ -42,10 +44,8 @@ describe('sentry:project:create action', () => { text: async () => Promise.resolve('Unexpected error.'), ...response, }; - global.fetch = jest - .fn() - .mockImplementation(() => Promise.resolve(mockedResponse)); + fetch = jest.fn().mockImplementation(() => Promise.resolve(mockedResponse)); return mockedResponse; }; @@ -74,7 +74,10 @@ describe('sentry:project:create action', () => { }); test('should request sentry project create with specified parameters.', async () => { - const action = createSentryCreateProjectAction(createScaffolderConfig()); + const action = createSentryCreateProjectAction(createScaffolderConfig(), { + fetch, + }); + const actionContext = getActionContext(); await action.handler(actionContext); @@ -96,14 +99,17 @@ describe('sentry:project:create action', () => { }); test('should request sentry project create with added optional specified project slug', async () => { - const action = createSentryCreateProjectAction(createScaffolderConfig()); + const action = createSentryCreateProjectAction(createScaffolderConfig(), { + fetch, + }); + const actionContext = getActionContext(); actionContext.input = { ...actionContext.input, slug: 'project-slug' }; await action.handler(actionContext); - expect(global.fetch).toHaveBeenNthCalledWith( + expect(fetch).toHaveBeenNthCalledWith( 1, `https://sentry.io/api/0/teams/${actionContext.input.organizationSlug}/${actionContext.input.teamSlug}/projects/`, { @@ -128,6 +134,7 @@ describe('sentry:project:create action', () => { token: sentryScaffolderConfigToken, }, }), + { fetch }, ); const actionContext = getActionContext(); @@ -153,7 +160,9 @@ describe('sentry:project:create action', () => { }); test('should throw InputError when auth token is missing from input parameters and scaffolder config.', async () => { - const action = createSentryCreateProjectAction(createScaffolderConfig()); + const action = createSentryCreateProjectAction(createScaffolderConfig(), { + fetch, + }); const actionContext = getActionContext(); actionContext.input.authToken = undefined; @@ -166,7 +175,6 @@ describe('sentry:project:create action', () => { }); test('should throw InputError when sentry API returns unexpected content-type.', async () => { - const action = createSentryCreateProjectAction(createScaffolderConfig()); const actionContext = getActionContext(); const mockedFetchResponse = mockFetch({ @@ -175,6 +183,10 @@ describe('sentry:project:create action', () => { }, }); + const action = createSentryCreateProjectAction(createScaffolderConfig(), { + fetch, + }); + expect.assertions(1); await expect(async () => { @@ -187,13 +199,16 @@ describe('sentry:project:create action', () => { }); test('should throw InputError when sentry API returns unexpected status code.', async () => { - const action = createSentryCreateProjectAction(createScaffolderConfig()); const actionContext = getActionContext(); const mockedFetchResponse = mockFetch({ status: 400, }); + const action = createSentryCreateProjectAction(createScaffolderConfig(), { + fetch, + }); + expect.assertions(1); await expect(async () => { diff --git a/plugins/scaffolder-backend-module-sentry/src/actions/createProject.ts b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.ts index 504084b9df..bb2ee6039e 100644 --- a/plugins/scaffolder-backend-module-sentry/src/actions/createProject.ts +++ b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.ts @@ -18,6 +18,7 @@ import { createTemplateAction } from '@backstage/plugin-scaffolder-node'; import { InputError } from '@backstage/errors'; import { Config } from '@backstage/config'; import { examples } from './createProject.examples'; +import { FetchApi } from '@backstage/core-plugin-api'; /** * Creates the `sentry:create-project` Scaffolder action. @@ -27,9 +28,13 @@ import { examples } from './createProject.examples'; * See {@link https://backstage.io/docs/features/software-templates/writing-custom-actions}. * * @param options - Configuration of the Sentry API. + * @param fetchApi - fetch implementation to use for calling Sentry service. * @public */ -export function createSentryCreateProjectAction(options: { config: Config }) { +export function createSentryCreateProjectAction( + options: { config: Config }, + fetchApi?: FetchApi, +) { const { config } = options; return createTemplateAction<{ @@ -90,7 +95,7 @@ export function createSentryCreateProjectAction(options: { config: Config }) { throw new InputError(`No valid sentry token given`); } - const response = await fetch( + const response = await (fetchApi?.fetch ?? fetch)( `https://sentry.io/api/0/teams/${organizationSlug}/${teamSlug}/projects/`, { method: 'POST', diff --git a/yarn.lock b/yarn.lock index 968acd6f80..7a0ca3c78a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8660,6 +8660,7 @@ __metadata: dependencies: "@backstage/cli": "workspace:^" "@backstage/config": "workspace:^" + "@backstage/core-plugin-api": "workspace:^" "@backstage/errors": "workspace:^" "@backstage/plugin-scaffolder-node": "workspace:^" "@backstage/types": "workspace:^" From 9b90f94c908ba1e3ba53f25a05e2d7034e0996fb Mon Sep 17 00:00:00 2001 From: Diego Mondragon Date: Mon, 23 Oct 2023 16:30:20 -0700 Subject: [PATCH 099/261] Updated api-report.md Signed-off-by: Diego Mondragon --- plugins/scaffolder-backend-module-sentry/api-report.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/plugins/scaffolder-backend-module-sentry/api-report.md b/plugins/scaffolder-backend-module-sentry/api-report.md index 746cce1348..e850c0f1c9 100644 --- a/plugins/scaffolder-backend-module-sentry/api-report.md +++ b/plugins/scaffolder-backend-module-sentry/api-report.md @@ -4,13 +4,17 @@ ```ts import { Config } from '@backstage/config'; +import { FetchApi } from '@backstage/core-plugin-api'; import { JsonObject } from '@backstage/types'; import { TemplateAction } from '@backstage/plugin-scaffolder-node'; // @public -export function createSentryCreateProjectAction(options: { - config: Config; -}): TemplateAction< +export function createSentryCreateProjectAction( + options: { + config: Config; + }, + fetchApi?: FetchApi, +): TemplateAction< { organizationSlug: string; teamSlug: string; From 2c776eb0246fd50beaae9178c8a97d10b6f16f7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Thu, 16 Nov 2023 13:54:44 +0100 Subject: [PATCH 100/261] fix test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .../api-report.md | 10 +- .../package.json | 5 +- .../src/actions/createProject.test.ts | 268 +++++++++--------- .../src/actions/createProject.ts | 15 +- yarn.lock | 3 +- 5 files changed, 147 insertions(+), 154 deletions(-) diff --git a/plugins/scaffolder-backend-module-sentry/api-report.md b/plugins/scaffolder-backend-module-sentry/api-report.md index e850c0f1c9..746cce1348 100644 --- a/plugins/scaffolder-backend-module-sentry/api-report.md +++ b/plugins/scaffolder-backend-module-sentry/api-report.md @@ -4,17 +4,13 @@ ```ts import { Config } from '@backstage/config'; -import { FetchApi } from '@backstage/core-plugin-api'; import { JsonObject } from '@backstage/types'; import { TemplateAction } from '@backstage/plugin-scaffolder-node'; // @public -export function createSentryCreateProjectAction( - options: { - config: Config; - }, - fetchApi?: FetchApi, -): TemplateAction< +export function createSentryCreateProjectAction(options: { + config: Config; +}): TemplateAction< { organizationSlug: string; teamSlug: string; diff --git a/plugins/scaffolder-backend-module-sentry/package.json b/plugins/scaffolder-backend-module-sentry/package.json index eccae89620..999cc7114c 100644 --- a/plugins/scaffolder-backend-module-sentry/package.json +++ b/plugins/scaffolder-backend-module-sentry/package.json @@ -29,14 +29,15 @@ }, "dependencies": { "@backstage/config": "workspace:^", - "@backstage/core-plugin-api": "workspace:^", "@backstage/errors": "workspace:^", "@backstage/plugin-scaffolder-node": "workspace:^", "yaml": "^2.3.3" }, "devDependencies": { + "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", - "@backstage/types": "workspace:^" + "@backstage/types": "workspace:^", + "msw": "^1.0.0" }, "files": [ "dist" diff --git a/plugins/scaffolder-backend-module-sentry/src/actions/createProject.test.ts b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.test.ts index b66f842688..0486012760 100644 --- a/plugins/scaffolder-backend-module-sentry/src/actions/createProject.test.ts +++ b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.test.ts @@ -13,14 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; -import { JsonObject } from '@backstage/types'; -import { createSentryCreateProjectAction } from './createProject'; -import { ActionContext } from '@backstage/plugin-scaffolder-node'; import { InputError } from '@backstage/errors'; +import { ActionContext } from '@backstage/plugin-scaffolder-node'; +import { JsonObject } from '@backstage/types'; import { randomBytes } from 'crypto'; +import { rest } from 'msw'; +import { setupServer } from 'msw/node'; +import { createSentryCreateProjectAction } from './createProject'; describe('sentry:project:create action', () => { + const worker = setupServer(); + setupRequestMockHandlers(worker); + const createScaffolderConfig = (configData: JsonObject = {}) => ({ config: new ConfigReader({ scaffolder: { @@ -29,26 +35,6 @@ describe('sentry:project:create action', () => { }), }); - let fetch: jest.Func; - - const mockFetch = (response = {}) => { - const mockedResponse = { - status: 201, - headers: { - get: () => 'application/json', - }, - json: async () => - Promise.resolve({ - detail: 'project creation mocked result', - }), - text: async () => Promise.resolve('Unexpected error.'), - ...response, - }; - - fetch = jest.fn().mockImplementation(() => Promise.resolve(mockedResponse)); - return mockedResponse; - }; - const getActionContext = (): ActionContext<{ organizationSlug: string; teamSlug: string; @@ -69,64 +55,71 @@ describe('sentry:project:create action', () => { output: jest.fn(), }); - beforeEach(() => { - mockFetch(); - }); - - test('should request sentry project create with specified parameters.', async () => { - const action = createSentryCreateProjectAction(createScaffolderConfig(), { - fetch, - }); + it('should request sentry project create with specified parameters.', async () => { + expect.assertions(3); + const action = createSentryCreateProjectAction(createScaffolderConfig()); const actionContext = getActionContext(); + worker.use( + rest.post( + `https://sentry.io/api/0/teams/${actionContext.input.organizationSlug}/${actionContext.input.teamSlug}/projects/`, + async (req, res, ctx) => { + expect(req.headers.get('Authorization')).toBe( + `Bearer ${actionContext.input.authToken}`, + ); + expect(req.headers.get('Content-Type')).toBe(`application/json`); + await expect(req.json()).resolves.toEqual({ + name: actionContext.input.name, + }); + return res( + ctx.status(201), + ctx.json({ + detail: 'project creation mocked result', + }), + ); + }, + ), + ); + await action.handler(actionContext); - - expect(fetch).toHaveBeenNthCalledWith( - 1, - `https://sentry.io/api/0/teams/${actionContext.input.organizationSlug}/${actionContext.input.teamSlug}/projects/`, - { - method: 'POST', - headers: { - Authorization: `Bearer ${actionContext.input.authToken}`, - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - name: actionContext.input.name, - }), - }, - ); }); - test('should request sentry project create with added optional specified project slug', async () => { - const action = createSentryCreateProjectAction(createScaffolderConfig(), { - fetch, - }); + it('should request sentry project create with added optional specified project slug', async () => { + expect.assertions(3); + const action = createSentryCreateProjectAction(createScaffolderConfig()); const actionContext = getActionContext(); - actionContext.input = { ...actionContext.input, slug: 'project-slug' }; - await action.handler(actionContext); - - expect(fetch).toHaveBeenNthCalledWith( - 1, - `https://sentry.io/api/0/teams/${actionContext.input.organizationSlug}/${actionContext.input.teamSlug}/projects/`, - { - method: 'POST', - headers: { - Authorization: `Bearer ${actionContext.input.authToken}`, - 'Content-Type': 'application/json', + worker.use( + rest.post( + `https://sentry.io/api/0/teams/${actionContext.input.organizationSlug}/${actionContext.input.teamSlug}/projects/`, + async (req, res, ctx) => { + expect(req.headers.get('Authorization')).toBe( + `Bearer ${actionContext.input.authToken}`, + ); + expect(req.headers.get('Content-Type')).toBe(`application/json`); + await expect(req.json()).resolves.toEqual({ + name: actionContext.input.name, + slug: actionContext.input.slug, + }); + return res( + ctx.status(201), + ctx.json({ + detail: 'project creation mocked result', + }), + ); }, - body: JSON.stringify({ - name: actionContext.input.name, - slug: actionContext.input.slug, - }), - }, + ), ); + + await action.handler(actionContext); }); - test('should take Sentry auth token from scaffolder config when input authToken is missing.', async () => { + it('should take Sentry auth token from scaffolder config when input authToken is missing.', async () => { + expect.assertions(3); + const sentryScaffolderConfigToken = randomBytes(5).toString('hex'); const action = createSentryCreateProjectAction( createScaffolderConfig({ @@ -134,89 +127,98 @@ describe('sentry:project:create action', () => { token: sentryScaffolderConfigToken, }, }), - { fetch }, ); - const actionContext = getActionContext(); - actionContext.input.authToken = undefined; + worker.use( + rest.post( + `https://sentry.io/api/0/teams/${actionContext.input.organizationSlug}/${actionContext.input.teamSlug}/projects/`, + async (req, res, ctx) => { + expect(req.headers.get('Authorization')).toBe( + `Bearer ${sentryScaffolderConfigToken}`, + ); + expect(req.headers.get('Content-Type')).toBe(`application/json`); + await expect(req.json()).resolves.toEqual({ + name: actionContext.input.name, + }); + return res( + ctx.status(201), + ctx.json({ + detail: 'project creation mocked result', + }), + ); + }, + ), + ); + await action.handler(actionContext); - - expect(fetch).toHaveBeenNthCalledWith( - 1, - `https://sentry.io/api/0/teams/${actionContext.input.organizationSlug}/${actionContext.input.teamSlug}/projects/`, - { - method: 'POST', - headers: { - Authorization: `Bearer ${sentryScaffolderConfigToken}`, - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - name: actionContext.input.name, - }), - }, - ); }); - test('should throw InputError when auth token is missing from input parameters and scaffolder config.', async () => { - const action = createSentryCreateProjectAction(createScaffolderConfig(), { - fetch, - }); + it('should throw InputError when auth token is missing from input parameters and scaffolder config.', async () => { + const action = createSentryCreateProjectAction(createScaffolderConfig()); const actionContext = getActionContext(); - actionContext.input.authToken = undefined; - expect.assertions(1); - - await expect(async () => { - await action.handler(actionContext); - }).rejects.toThrow(new InputError('No valid sentry token given')); - }); - - test('should throw InputError when sentry API returns unexpected content-type.', async () => { - const actionContext = getActionContext(); - - const mockedFetchResponse = mockFetch({ - headers: { - get: () => 'text/html', - }, - }); - - const action = createSentryCreateProjectAction(createScaffolderConfig(), { - fetch, - }); - - expect.assertions(1); - - await expect(async () => { - await action.handler(actionContext); - }).rejects.toThrow( - new InputError( - `Unexpected Sentry Response Type: ${await mockedFetchResponse.text()}`, + worker.use( + rest.post( + `https://sentry.io/api/0/teams/${actionContext.input.organizationSlug}/${actionContext.input.teamSlug}/projects/`, + async (req, res, ctx) => { + expect(req.headers.get('Authorization')).toBe( + `Bearer ${actionContext.input.authToken}`, + ); + expect(req.headers.get('Content-Type')).toBe(`application/json`); + await expect(req.json()).resolves.toEqual({ + name: actionContext.input.name, + }); + return res( + ctx.status(201), + ctx.json({ + detail: 'project creation mocked result', + }), + ); + }, ), ); + + await expect(() => action.handler(actionContext)).rejects.toThrow( + new InputError('No valid sentry token given'), + ); }); - test('should throw InputError when sentry API returns unexpected status code.', async () => { + it('should throw InputError when sentry API returns unexpected content-type.', async () => { + const action = createSentryCreateProjectAction(createScaffolderConfig()); const actionContext = getActionContext(); - const mockedFetchResponse = mockFetch({ - status: 400, - }); - - const action = createSentryCreateProjectAction(createScaffolderConfig(), { - fetch, - }); - - expect.assertions(1); - - await expect(async () => { - await action.handler(actionContext); - }).rejects.toThrow( - new InputError( - `Sentry Response was: ${(await mockedFetchResponse.json()).detail}`, + worker.use( + rest.post( + `https://sentry.io/api/0/teams/${actionContext.input.organizationSlug}/${actionContext.input.teamSlug}/projects/`, + async (_, res, ctx) => { + return res(ctx.status(201), ctx.text('Bad response')); + }, ), ); + + await expect(() => action.handler(actionContext)).rejects.toThrow( + new InputError(`Unexpected Sentry Response Type: Bad response`), + ); + }); + + it('should throw InputError when sentry API returns unexpected status code.', async () => { + const action = createSentryCreateProjectAction(createScaffolderConfig()); + const actionContext = getActionContext(); + + worker.use( + rest.post( + `https://sentry.io/api/0/teams/${actionContext.input.organizationSlug}/${actionContext.input.teamSlug}/projects/`, + async (_, res, ctx) => { + return res(ctx.status(400), ctx.json({ detail: 'OUCH' })); + }, + ), + ); + + await expect(() => action.handler(actionContext)).rejects.toThrow( + new InputError(`Sentry Response was: OUCH`), + ); }); }); diff --git a/plugins/scaffolder-backend-module-sentry/src/actions/createProject.ts b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.ts index bb2ee6039e..259b670f9e 100644 --- a/plugins/scaffolder-backend-module-sentry/src/actions/createProject.ts +++ b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.ts @@ -17,24 +17,18 @@ import { createTemplateAction } from '@backstage/plugin-scaffolder-node'; import { InputError } from '@backstage/errors'; import { Config } from '@backstage/config'; -import { examples } from './createProject.examples'; -import { FetchApi } from '@backstage/core-plugin-api'; /** - * Creates the `sentry:create-project` Scaffolder action. + * Creates the `sentry:project:create` Scaffolder action. * * @remarks * * See {@link https://backstage.io/docs/features/software-templates/writing-custom-actions}. * * @param options - Configuration of the Sentry API. - * @param fetchApi - fetch implementation to use for calling Sentry service. * @public */ -export function createSentryCreateProjectAction( - options: { config: Config }, - fetchApi?: FetchApi, -) { +export function createSentryCreateProjectAction(options: { config: Config }) { const { config } = options; return createTemplateAction<{ @@ -45,7 +39,6 @@ export function createSentryCreateProjectAction( authToken?: string; }>({ id: 'sentry:project:create', - examples, schema: { input: { required: ['organizationSlug', 'teamSlug', 'name'], @@ -95,7 +88,7 @@ export function createSentryCreateProjectAction( throw new InputError(`No valid sentry token given`); } - const response = await (fetchApi?.fetch ?? fetch)( + const response = await fetch( `https://sentry.io/api/0/teams/${organizationSlug}/${teamSlug}/projects/`, { method: 'POST', @@ -119,7 +112,7 @@ export function createSentryCreateProjectAction( const result = await response.json(); if (code !== 201) { - throw new InputError(`Sentry Response was: ${result.detail}`); + throw new InputError(`Sentry Response was: ${await result.detail}`); } ctx.output('id', result.id); diff --git a/yarn.lock b/yarn.lock index 7a0ca3c78a..3000d86b7f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8658,12 +8658,13 @@ __metadata: version: 0.0.0-use.local resolution: "@backstage/plugin-scaffolder-backend-module-sentry@workspace:plugins/scaffolder-backend-module-sentry" dependencies: + "@backstage/backend-test-utils": "workspace:^" "@backstage/cli": "workspace:^" "@backstage/config": "workspace:^" - "@backstage/core-plugin-api": "workspace:^" "@backstage/errors": "workspace:^" "@backstage/plugin-scaffolder-node": "workspace:^" "@backstage/types": "workspace:^" + msw: ^1.0.0 yaml: ^2.3.3 languageName: unknown linkType: soft From 88c4747ce6298c28d46b198363b75b9f47861474 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Fri, 24 Nov 2023 15:50:29 +0100 Subject: [PATCH 101/261] ok try msw2 then MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .../package.json | 2 +- .../src/actions/createProject.test.ts | 87 +++++++++---------- yarn.lock | 4 +- 3 files changed, 43 insertions(+), 50 deletions(-) diff --git a/plugins/scaffolder-backend-module-sentry/package.json b/plugins/scaffolder-backend-module-sentry/package.json index 999cc7114c..9429fd0252 100644 --- a/plugins/scaffolder-backend-module-sentry/package.json +++ b/plugins/scaffolder-backend-module-sentry/package.json @@ -37,7 +37,7 @@ "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", "@backstage/types": "workspace:^", - "msw": "^1.0.0" + "msw": "^2.0.0" }, "files": [ "dist" diff --git a/plugins/scaffolder-backend-module-sentry/src/actions/createProject.test.ts b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.test.ts index 0486012760..972b0f1e8e 100644 --- a/plugins/scaffolder-backend-module-sentry/src/actions/createProject.test.ts +++ b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.test.ts @@ -13,14 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; import { InputError } from '@backstage/errors'; import { ActionContext } from '@backstage/plugin-scaffolder-node'; import { JsonObject } from '@backstage/types'; import { randomBytes } from 'crypto'; -import { rest } from 'msw'; import { setupServer } from 'msw/node'; +import { HttpResponse, http } from 'msw'; import { createSentryCreateProjectAction } from './createProject'; describe('sentry:project:create action', () => { @@ -62,21 +63,19 @@ describe('sentry:project:create action', () => { const actionContext = getActionContext(); worker.use( - rest.post( + http.post( `https://sentry.io/api/0/teams/${actionContext.input.organizationSlug}/${actionContext.input.teamSlug}/projects/`, - async (req, res, ctx) => { - expect(req.headers.get('Authorization')).toBe( + async ({ request }) => { + expect(request.headers.get('Authorization')).toBe( `Bearer ${actionContext.input.authToken}`, ); - expect(req.headers.get('Content-Type')).toBe(`application/json`); - await expect(req.json()).resolves.toEqual({ + expect(request.headers.get('Content-Type')).toBe(`application/json`); + await expect(request.json()).resolves.toEqual({ name: actionContext.input.name, }); - return res( - ctx.status(201), - ctx.json({ - detail: 'project creation mocked result', - }), + return HttpResponse.json( + { detail: 'project creation mocked result' }, + { status: 201 }, ); }, ), @@ -93,22 +92,20 @@ describe('sentry:project:create action', () => { actionContext.input = { ...actionContext.input, slug: 'project-slug' }; worker.use( - rest.post( + http.post( `https://sentry.io/api/0/teams/${actionContext.input.organizationSlug}/${actionContext.input.teamSlug}/projects/`, - async (req, res, ctx) => { - expect(req.headers.get('Authorization')).toBe( + async ({ request }) => { + expect(request.headers.get('Authorization')).toBe( `Bearer ${actionContext.input.authToken}`, ); - expect(req.headers.get('Content-Type')).toBe(`application/json`); - await expect(req.json()).resolves.toEqual({ + expect(request.headers.get('Content-Type')).toBe(`application/json`); + await expect(request.json()).resolves.toEqual({ name: actionContext.input.name, slug: actionContext.input.slug, }); - return res( - ctx.status(201), - ctx.json({ - detail: 'project creation mocked result', - }), + return HttpResponse.json( + { detail: 'project creation mocked result' }, + { status: 201 }, ); }, ), @@ -132,21 +129,19 @@ describe('sentry:project:create action', () => { actionContext.input.authToken = undefined; worker.use( - rest.post( + http.post( `https://sentry.io/api/0/teams/${actionContext.input.organizationSlug}/${actionContext.input.teamSlug}/projects/`, - async (req, res, ctx) => { - expect(req.headers.get('Authorization')).toBe( + async ({ request }) => { + expect(request.headers.get('Authorization')).toBe( `Bearer ${sentryScaffolderConfigToken}`, ); - expect(req.headers.get('Content-Type')).toBe(`application/json`); - await expect(req.json()).resolves.toEqual({ + expect(request.headers.get('Content-Type')).toBe(`application/json`); + await expect(request.json()).resolves.toEqual({ name: actionContext.input.name, }); - return res( - ctx.status(201), - ctx.json({ - detail: 'project creation mocked result', - }), + return HttpResponse.json( + { detail: 'project creation mocked result' }, + { status: 201 }, ); }, ), @@ -161,21 +156,19 @@ describe('sentry:project:create action', () => { actionContext.input.authToken = undefined; worker.use( - rest.post( + http.post( `https://sentry.io/api/0/teams/${actionContext.input.organizationSlug}/${actionContext.input.teamSlug}/projects/`, - async (req, res, ctx) => { - expect(req.headers.get('Authorization')).toBe( + async ({ request }) => { + expect(request.headers.get('Authorization')).toBe( `Bearer ${actionContext.input.authToken}`, ); - expect(req.headers.get('Content-Type')).toBe(`application/json`); - await expect(req.json()).resolves.toEqual({ + expect(request.headers.get('Content-Type')).toBe(`application/json`); + await expect(request.json()).resolves.toEqual({ name: actionContext.input.name, }); - return res( - ctx.status(201), - ctx.json({ - detail: 'project creation mocked result', - }), + return HttpResponse.json( + { detail: 'project creation mocked result' }, + { status: 201 }, ); }, ), @@ -191,10 +184,10 @@ describe('sentry:project:create action', () => { const actionContext = getActionContext(); worker.use( - rest.post( + http.post( `https://sentry.io/api/0/teams/${actionContext.input.organizationSlug}/${actionContext.input.teamSlug}/projects/`, - async (_, res, ctx) => { - return res(ctx.status(201), ctx.text('Bad response')); + async () => { + return HttpResponse.text('Bad response', { status: 201 }); }, ), ); @@ -209,10 +202,10 @@ describe('sentry:project:create action', () => { const actionContext = getActionContext(); worker.use( - rest.post( + http.post( `https://sentry.io/api/0/teams/${actionContext.input.organizationSlug}/${actionContext.input.teamSlug}/projects/`, - async (_, res, ctx) => { - return res(ctx.status(400), ctx.json({ detail: 'OUCH' })); + async () => { + return HttpResponse.json({ detail: 'OUCH' }, { status: 400 }); }, ), ); diff --git a/yarn.lock b/yarn.lock index 3000d86b7f..8690082630 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8664,7 +8664,7 @@ __metadata: "@backstage/errors": "workspace:^" "@backstage/plugin-scaffolder-node": "workspace:^" "@backstage/types": "workspace:^" - msw: ^1.0.0 + msw: ^2.0.0 yaml: ^2.3.3 languageName: unknown linkType: soft @@ -34768,7 +34768,7 @@ __metadata: languageName: node linkType: hard -"msw@npm:^2.0.8": +"msw@npm:^2.0.0, msw@npm:^2.0.8": version: 2.0.9 resolution: "msw@npm:2.0.9" dependencies: From 2f57070f7976e737853775ef879af4038bc8455b Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Fri, 24 Nov 2023 15:57:13 +0100 Subject: [PATCH 102/261] core-plugin-api: refactor and more comments for FlattenedMessages Signed-off-by: Patrik Oldsberg --- .../src/translation/TranslationRef.ts | 43 ++++++++++++------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/packages/core-plugin-api/src/translation/TranslationRef.ts b/packages/core-plugin-api/src/translation/TranslationRef.ts index 5711273915..c2ac7a5ce3 100644 --- a/packages/core-plugin-api/src/translation/TranslationRef.ts +++ b/packages/core-plugin-api/src/translation/TranslationRef.ts @@ -42,21 +42,34 @@ type AnyNestedMessages = { [key in string]: AnyNestedMessages | string }; * * @ignore */ -type FlattenedMessages = { - [K in keyof T]: ( - x: T[K] extends infer V - ? V extends AnyNestedMessages - ? FlattenedMessages extends infer FV - ? { - [P in keyof FV as `${K & string}.${P & string}`]: FV[P]; - } - : never - : Pick - : never, - ) => void; -} extends Record void> - ? { [K in keyof O]: O[K] } - : never; +type FlattenedMessages = + // Flatten out object keys into a union structure of objects, e.g. { a: 'a', b: 'b' } -> { a: 'a' } | { b: 'b' } + // Any nested object will be flattened into the individual unions, e.g. { a: 'a', b: { x: 'x', y: 'y' } } -> { a: 'a' } | { 'b.x': 'x', 'b.y': 'y' } + // We create this structure by first nesting the desired union types into the original object, and + // then extract them by indexing with `keyof TMessages` to form the union. + // Throughout this the objects are wrapped up in a function parameter, which allows us to have the + // final step of flipping this unions around to an intersection by inferring the function parameter. + { + [TKey in keyof TMessages]: ( + _: TMessages[TKey] extends infer TValue // "local variable" for the value + ? TValue extends AnyNestedMessages + ? FlattenedMessages extends infer TNested // Recurse into nested messages, "local variable" for the result + ? { + [TNestedKey in keyof TNested as `${TKey & string}.${TNestedKey & + string}`]: TNested[TNestedKey]; + } + : never + : { [_ in TKey]: TValue } // Primitive object values are passed through with the same key + : never, + ) => void; + // The `[keyof TMessages]` extracts the object values union from our flattened structure, still wrapped up in function parameters. + // The `extends (_: infer TIntersection) => void` flips the union to an intersection, at which point we have the correct type. + }[keyof TMessages] extends (_: infer TIntersection) => void + ? // This object mapping just expands similar to the Expand<> utility type, providing nicer type hints + { + readonly [TExpandKey in keyof TIntersection]: TIntersection[TExpandKey]; + } + : never; /** @internal */ export interface InternalTranslationRef< From 7f0dbfd35a93cb5c586acb95e96ef0e1d89f2c11 Mon Sep 17 00:00:00 2001 From: Florian JUDITH Date: Tue, 21 Nov 2023 23:50:25 -0500 Subject: [PATCH 103/261] Fixed crash when leveraging custom Lighthouse config Signed-off-by: Florian JUDITH --- .changeset/ninety-otters-report.md | 5 +++ plugins/lighthouse-backend/README.md | 9 ++-- plugins/lighthouse-backend/src/config.ts | 42 +++++++++---------- .../src/service/createScheduler.ts | 4 +- 4 files changed, 32 insertions(+), 28 deletions(-) create mode 100644 .changeset/ninety-otters-report.md diff --git a/.changeset/ninety-otters-report.md b/.changeset/ninety-otters-report.md new file mode 100644 index 0000000000..2b70822042 --- /dev/null +++ b/.changeset/ninety-otters-report.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-lighthouse-backend': major +--- + +Updated Ligthouse schedule configuration to fix crashes when using custom confinguration diff --git a/plugins/lighthouse-backend/README.md b/plugins/lighthouse-backend/README.md index 28845d3c73..cde9135c23 100644 --- a/plugins/lighthouse-backend/README.md +++ b/plugins/lighthouse-backend/README.md @@ -19,13 +19,13 @@ import { PluginEnvironment } from '../types'; import { CatalogClient } from '@backstage/catalog-client'; export default async function createPlugin(env: PluginEnvironment) { - const { logger, scheduler, config } = env; + const { logger, scheduler, config, tokenManager } = env; const catalogClient = new CatalogClient({ discoveryApi: env.discovery, }); - await createScheduler({ logger, scheduler, config, catalogClient }); + await createScheduler({ logger, scheduler, config, catalogClient tokenManager }); } ``` @@ -80,5 +80,8 @@ You can define how often and when the scheduler should run the audits: ```yaml lighthouse: schedule: - days: 1 + frequency: + hours: 12 # Default: days 1 + timeout: + minutes: 30 # Default: null ``` diff --git a/plugins/lighthouse-backend/src/config.ts b/plugins/lighthouse-backend/src/config.ts index bea1c35661..91b4fb1a52 100644 --- a/plugins/lighthouse-backend/src/config.ts +++ b/plugins/lighthouse-backend/src/config.ts @@ -14,52 +14,48 @@ * limitations under the License. */ +import { readTaskScheduleDefinitionFromConfig } from '@backstage/backend-tasks'; import { Config } from '@backstage/config'; import { HumanDuration as HumanDuration } from '@backstage/types'; export interface LighthouseAuditScheduleConfig { - schedule: HumanDuration; + frequency: HumanDuration; timeout: HumanDuration; auditDetail: HumanDuration; } /** @public */ export type LighthouseAuditSchedule = { - getSchedule: () => HumanDuration; + getFrequency: () => HumanDuration; getTimeout: () => HumanDuration; }; /** @public */ export class LighthouseAuditScheduleImpl implements LighthouseAuditSchedule { - static fromConfig(config: Config) { - const lighthouse = config.getOptionalConfig('lighthouse'); + static fromConfig(config: Config): LighthouseAuditScheduleImpl { + // const lighthouse = config.getOptionalConfig('lighthouse'); + const lighthouse = config.has('lighthouse.schedule') + ? readTaskScheduleDefinitionFromConfig( + config.getConfig('lighthouse.schedule'), + ) + : { + frequency: { days: 1 }, + timeout: {}, + }; - let schedule: HumanDuration = { days: 1 }; - let timeout: HumanDuration = {}; + const frequency = lighthouse.frequency as HumanDuration; + const timeout = lighthouse.timeout as HumanDuration; - if (lighthouse) { - const scheduleConfig = lighthouse.getOptionalConfig('schedule'); - const timeoutConfig = lighthouse.getOptionalConfig('timeout'); - - if (scheduleConfig) { - schedule = scheduleConfig as HumanDuration; - } - - if (timeoutConfig) { - timeout = timeoutConfig as HumanDuration; - } - } - - return new LighthouseAuditScheduleImpl(schedule, timeout); + return new LighthouseAuditScheduleImpl(frequency, timeout); } constructor( - private schedule: HumanDuration, + private frequency: HumanDuration, private timeout: HumanDuration, ) {} - getSchedule(): HumanDuration { - return this.schedule; + getFrequency(): HumanDuration { + return this.frequency; } getTimeout(): HumanDuration { diff --git a/plugins/lighthouse-backend/src/service/createScheduler.ts b/plugins/lighthouse-backend/src/service/createScheduler.ts index 498e459a09..33df1226b7 100644 --- a/plugins/lighthouse-backend/src/service/createScheduler.ts +++ b/plugins/lighthouse-backend/src/service/createScheduler.ts @@ -56,14 +56,14 @@ export async function createScheduler( logger.info( `Running with Scheduler Config ${JSON.stringify( - lighthouseAuditConfig.getSchedule(), + lighthouseAuditConfig.getFrequency(), )} and timeout ${JSON.stringify(lighthouseAuditConfig.getTimeout())}`, ); if (scheduler) { await scheduler.scheduleTask({ id: 'lighthouse_audit', - frequency: lighthouseAuditConfig.getSchedule(), + frequency: lighthouseAuditConfig.getFrequency(), timeout: lighthouseAuditConfig.getTimeout(), initialDelay: { minutes: 15 }, fn: async () => { From 7515a338abf09712f0328ad8a9f93247073e5a2a Mon Sep 17 00:00:00 2001 From: Florian JUDITH Date: Tue, 21 Nov 2023 23:58:44 -0500 Subject: [PATCH 104/261] Added required frame-src to display Lighthouse dashboards Signed-off-by: Florian JUDITH --- plugins/lighthouse/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/lighthouse/README.md b/plugins/lighthouse/README.md index 1d2385e4c4..e834ad39c1 100644 --- a/plugins/lighthouse/README.md +++ b/plugins/lighthouse/README.md @@ -47,6 +47,10 @@ const routes = ( Then configure the `lighthouse-audit-service` URL in your [`app-config.yaml`](https://github.com/backstage/backstage/blob/master/app-config.yaml). ```yaml +backend: + csp: + frame-src: + - http://your-service-url lighthouse: baseUrl: http://your-service-url ``` From 623fee149ac12fb054977fbe1d806af58cd6c17a Mon Sep 17 00:00:00 2001 From: Florian JUDITH Date: Wed, 22 Nov 2023 00:52:01 -0500 Subject: [PATCH 105/261] Fixed typo Signed-off-by: Florian JUDITH --- .changeset/ninety-otters-report.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/ninety-otters-report.md b/.changeset/ninety-otters-report.md index 2b70822042..a047ac8187 100644 --- a/.changeset/ninety-otters-report.md +++ b/.changeset/ninety-otters-report.md @@ -2,4 +2,4 @@ '@backstage/plugin-lighthouse-backend': major --- -Updated Ligthouse schedule configuration to fix crashes when using custom confinguration +Updated Lighthouse schedule configuration to fix crashes when using custom confinguration From 49fccefda912736541203a4bfbbf3ae04d21a94d Mon Sep 17 00:00:00 2001 From: Florian JUDITH Date: Wed, 22 Nov 2023 08:04:28 -0500 Subject: [PATCH 106/261] Update .changeset/ninety-otters-report.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Fredrik Adelöw Signed-off-by: Florian JUDITH --- .changeset/ninety-otters-report.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/ninety-otters-report.md b/.changeset/ninety-otters-report.md index a047ac8187..9011e37ea8 100644 --- a/.changeset/ninety-otters-report.md +++ b/.changeset/ninety-otters-report.md @@ -2,4 +2,4 @@ '@backstage/plugin-lighthouse-backend': major --- -Updated Lighthouse schedule configuration to fix crashes when using custom confinguration +Updated Lighthouse schedule configuration to fix crashes when using custom configuration From 22cf1c55944fb8ece8bac900ea7b9f65ce75b061 Mon Sep 17 00:00:00 2001 From: Florian JUDITH Date: Wed, 22 Nov 2023 08:04:49 -0500 Subject: [PATCH 107/261] Update plugins/lighthouse-backend/README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Fredrik Adelöw Signed-off-by: Florian JUDITH --- plugins/lighthouse-backend/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/lighthouse-backend/README.md b/plugins/lighthouse-backend/README.md index cde9135c23..04be817248 100644 --- a/plugins/lighthouse-backend/README.md +++ b/plugins/lighthouse-backend/README.md @@ -25,7 +25,7 @@ export default async function createPlugin(env: PluginEnvironment) { discoveryApi: env.discovery, }); - await createScheduler({ logger, scheduler, config, catalogClient tokenManager }); + await createScheduler({ logger, scheduler, config, catalogClient, tokenManager }); } ``` From 63b050345a494abe23e249fb77c5ac203839c4fa Mon Sep 17 00:00:00 2001 From: Florian JUDITH Date: Thu, 23 Nov 2023 23:06:35 -0500 Subject: [PATCH 108/261] Enabled backward config compatibility Signed-off-by: Florian JUDITH --- .changeset/ninety-otters-report.md | 2 +- plugins/lighthouse-backend/src/config.ts | 90 +++++++++++-------- .../src/service/createScheduler.ts | 14 +-- 3 files changed, 61 insertions(+), 45 deletions(-) diff --git a/.changeset/ninety-otters-report.md b/.changeset/ninety-otters-report.md index 9011e37ea8..9b47097f73 100644 --- a/.changeset/ninety-otters-report.md +++ b/.changeset/ninety-otters-report.md @@ -1,5 +1,5 @@ --- -'@backstage/plugin-lighthouse-backend': major +'@backstage/plugin-lighthouse-backend': minor --- Updated Lighthouse schedule configuration to fix crashes when using custom configuration diff --git a/plugins/lighthouse-backend/src/config.ts b/plugins/lighthouse-backend/src/config.ts index 91b4fb1a52..cf52d86107 100644 --- a/plugins/lighthouse-backend/src/config.ts +++ b/plugins/lighthouse-backend/src/config.ts @@ -13,52 +13,66 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { LoggerService } from '@backstage/backend-plugin-api'; +import { + TaskScheduleDefinition, + readTaskScheduleDefinitionFromConfig, +} from '@backstage/backend-tasks'; +import { Config, readDurationFromConfig } from '@backstage/config'; +import { HumanDuration } from '@backstage/types'; -import { readTaskScheduleDefinitionFromConfig } from '@backstage/backend-tasks'; -import { Config } from '@backstage/config'; -import { HumanDuration as HumanDuration } from '@backstage/types'; - -export interface LighthouseAuditScheduleConfig { - frequency: HumanDuration; - timeout: HumanDuration; - auditDetail: HumanDuration; -} - -/** @public */ -export type LighthouseAuditSchedule = { - getFrequency: () => HumanDuration; - getTimeout: () => HumanDuration; +type Options = { + logger: LoggerService; }; /** @public */ -export class LighthouseAuditScheduleImpl implements LighthouseAuditSchedule { - static fromConfig(config: Config): LighthouseAuditScheduleImpl { - // const lighthouse = config.getOptionalConfig('lighthouse'); - const lighthouse = config.has('lighthouse.schedule') - ? readTaskScheduleDefinitionFromConfig( - config.getConfig('lighthouse.schedule'), - ) - : { - frequency: { days: 1 }, - timeout: {}, - }; +export class LighthouseAuditScheduleImpl implements TaskScheduleDefinition { + /** + * Looks at the `lighthouse.schedule` section in the application configuration + * and returns a TaskScheduleDefinition. + * Defaults to `{ frequency: { days: 1 }, timeout: {}, initialDelay: { minutes; 15 } }` + * + * @returns a TaskScheduleDefinition + */ + static fromConfig(config: Config, options: Options): TaskScheduleDefinition { + const { logger } = options; - const frequency = lighthouse.frequency as HumanDuration; - const timeout = lighthouse.timeout as HumanDuration; + let lighthouse: TaskScheduleDefinition = { + frequency: { days: 1 }, + timeout: {}, + initialDelay: { minutes: 15 }, + }; - return new LighthouseAuditScheduleImpl(frequency, timeout); + if (config.has('lighthouse.schedule.frequency')) { + lighthouse = readTaskScheduleDefinitionFromConfig( + config.getConfig('lighthouse.schedule'), + ); + } else if (config.has('lighthouse.schedule')) { + logger.warn( + `[Deprecation] Please migrate the schedule configuration to 'lighthouse.schedule.frequency' in ${config.config.context}`, + ); + + lighthouse.frequency = readDurationFromConfig( + config.getConfig('lighthouse.schedule'), + ); + } + + if (config.has('lighthouse.timeout')) { + logger.warn( + `[Deprecation] Please migrate the timeout configuration to 'lighthouse.schedule.timeout' in ${config.config.context}`, + ); + + lighthouse.timeout = readDurationFromConfig( + config.getConfig('lighthouse.timeout'), + ); + } + + return lighthouse; } constructor( - private frequency: HumanDuration, - private timeout: HumanDuration, + public frequency: HumanDuration, + public timeout: HumanDuration, + public initialDelay: HumanDuration, ) {} - - getFrequency(): HumanDuration { - return this.frequency; - } - - getTimeout(): HumanDuration { - return this.timeout; - } } diff --git a/plugins/lighthouse-backend/src/service/createScheduler.ts b/plugins/lighthouse-backend/src/service/createScheduler.ts index 33df1226b7..45a3e88149 100644 --- a/plugins/lighthouse-backend/src/service/createScheduler.ts +++ b/plugins/lighthouse-backend/src/service/createScheduler.ts @@ -39,7 +39,9 @@ export async function createScheduler( const { logger, scheduler, catalogClient, config, tokenManager } = options; const lighthouseApi = LighthouseRestApi.fromConfig(config); - const lighthouseAuditConfig = LighthouseAuditScheduleImpl.fromConfig(config); + const lighthouseAuditConfig = LighthouseAuditScheduleImpl.fromConfig(config, { + logger, + }); const formFactorToScreenEmulationMap = { // the default is mobile, so no need to override mobile: undefined, @@ -56,16 +58,16 @@ export async function createScheduler( logger.info( `Running with Scheduler Config ${JSON.stringify( - lighthouseAuditConfig.getFrequency(), - )} and timeout ${JSON.stringify(lighthouseAuditConfig.getTimeout())}`, + lighthouseAuditConfig.frequency, + )} and timeout ${JSON.stringify(lighthouseAuditConfig.timeout)}`, ); if (scheduler) { await scheduler.scheduleTask({ id: 'lighthouse_audit', - frequency: lighthouseAuditConfig.getFrequency(), - timeout: lighthouseAuditConfig.getTimeout(), - initialDelay: { minutes: 15 }, + frequency: lighthouseAuditConfig.frequency, + timeout: lighthouseAuditConfig.timeout, + initialDelay: lighthouseAuditConfig.initialDelay, fn: async () => { const filter: Record = { kind: 'Component', From 3c72e85d85aaa78404c2477966c14e29eaae5083 Mon Sep 17 00:00:00 2001 From: Florian JUDITH Date: Thu, 23 Nov 2023 23:34:16 -0500 Subject: [PATCH 109/261] Removed reference to app-config file in deprecation message Signed-off-by: Florian JUDITH --- plugins/lighthouse-backend/README.md | 8 +++++++- plugins/lighthouse-backend/src/config.ts | 4 ++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/plugins/lighthouse-backend/README.md b/plugins/lighthouse-backend/README.md index 04be817248..e2d1917f22 100644 --- a/plugins/lighthouse-backend/README.md +++ b/plugins/lighthouse-backend/README.md @@ -25,7 +25,13 @@ export default async function createPlugin(env: PluginEnvironment) { discoveryApi: env.discovery, }); - await createScheduler({ logger, scheduler, config, catalogClient, tokenManager }); + await createScheduler({ + logger, + scheduler, + config, + catalogClient, + tokenManager, + }); } ``` diff --git a/plugins/lighthouse-backend/src/config.ts b/plugins/lighthouse-backend/src/config.ts index cf52d86107..5b17bd6ec0 100644 --- a/plugins/lighthouse-backend/src/config.ts +++ b/plugins/lighthouse-backend/src/config.ts @@ -49,7 +49,7 @@ export class LighthouseAuditScheduleImpl implements TaskScheduleDefinition { ); } else if (config.has('lighthouse.schedule')) { logger.warn( - `[Deprecation] Please migrate the schedule configuration to 'lighthouse.schedule.frequency' in ${config.config.context}`, + `[Deprecation] Please migrate the schedule configuration to 'lighthouse.schedule.frequency'`, ); lighthouse.frequency = readDurationFromConfig( @@ -59,7 +59,7 @@ export class LighthouseAuditScheduleImpl implements TaskScheduleDefinition { if (config.has('lighthouse.timeout')) { logger.warn( - `[Deprecation] Please migrate the timeout configuration to 'lighthouse.schedule.timeout' in ${config.config.context}`, + `[Deprecation] Please migrate the timeout configuration to 'lighthouse.schedule.timeout'`, ); lighthouse.timeout = readDurationFromConfig( From 19b3c34248326245dc46e1df11802df3060a68ae Mon Sep 17 00:00:00 2001 From: Florian JUDITH Date: Sat, 25 Nov 2023 10:15:02 -0500 Subject: [PATCH 110/261] Added default timeout Signed-off-by: Florian JUDITH --- plugins/lighthouse-backend/src/config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/lighthouse-backend/src/config.ts b/plugins/lighthouse-backend/src/config.ts index 5b17bd6ec0..736a4e569d 100644 --- a/plugins/lighthouse-backend/src/config.ts +++ b/plugins/lighthouse-backend/src/config.ts @@ -39,7 +39,7 @@ export class LighthouseAuditScheduleImpl implements TaskScheduleDefinition { let lighthouse: TaskScheduleDefinition = { frequency: { days: 1 }, - timeout: {}, + timeout: { minutes: 10 }, initialDelay: { minutes: 15 }, }; From ffbf656299dc2a65a21926c29323a85d251d0196 Mon Sep 17 00:00:00 2001 From: Florian JUDITH Date: Sat, 25 Nov 2023 10:25:56 -0500 Subject: [PATCH 111/261] Added changeset related to Lighthouse plugin documentation Signed-off-by: Florian JUDITH --- .changeset/long-cycles-grow.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/long-cycles-grow.md diff --git a/.changeset/long-cycles-grow.md b/.changeset/long-cycles-grow.md new file mode 100644 index 0000000000..4edc1905fe --- /dev/null +++ b/.changeset/long-cycles-grow.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-lighthouse': patch +--- + +Updated README From 41ea6dfcb16d2da16282174d5afddf3312442375 Mon Sep 17 00:00:00 2001 From: Florian JUDITH Date: Sat, 25 Nov 2023 11:01:48 -0500 Subject: [PATCH 112/261] Added config definition file Signed-off-by: Florian JUDITH --- plugins/lighthouse-backend/config.d.ts | 30 +++++++++++++++++++++++++ plugins/lighthouse-backend/package.json | 3 ++- 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 plugins/lighthouse-backend/config.d.ts diff --git a/plugins/lighthouse-backend/config.d.ts b/plugins/lighthouse-backend/config.d.ts new file mode 100644 index 0000000000..2d49f188b6 --- /dev/null +++ b/plugins/lighthouse-backend/config.d.ts @@ -0,0 +1,30 @@ +/* + * 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 { TaskScheduleDefinitionConfig } from '@backstage/backend-tasks'; +import { HumanDuration } from '@backstage/types'; + +export interface Config { + /** + * Configuration options for the Lighthouse backend plugin. + */ + lighthouse?: { + /** + * Schedule of the audit + */ + schedule?: HumanDuration | TaskScheduleDefinitionConfig; + }; +} diff --git a/plugins/lighthouse-backend/package.json b/plugins/lighthouse-backend/package.json index 84cff5b8eb..89d9b2f8ec 100644 --- a/plugins/lighthouse-backend/package.json +++ b/plugins/lighthouse-backend/package.json @@ -24,7 +24,8 @@ "lighthouse" ], "files": [ - "dist" + "dist", + "config.d.ts" ], "scripts": { "build": "backstage-cli package build", From 8cd4422216125928dc42e437e1cb4fd155cf77c2 Mon Sep 17 00:00:00 2001 From: Andre Wanlin Date: Sat, 25 Nov 2023 16:09:49 -0600 Subject: [PATCH 113/261] Signed-off-by: Andre Wanlin --- plugins/azure-devops-backend/src/api/mappers.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/azure-devops-backend/src/api/mappers.test.ts b/plugins/azure-devops-backend/src/api/mappers.test.ts index 85c82a2a14..5f7fe5eb28 100644 --- a/plugins/azure-devops-backend/src/api/mappers.test.ts +++ b/plugins/azure-devops-backend/src/api/mappers.test.ts @@ -40,7 +40,7 @@ import { import { IdentityRef } from 'azure-devops-node-api/interfaces/common/VSSInterfaces'; -describe('AzureDevOpsApi', () => { +describe('mappers', () => { describe('mappedRepoBuild', () => { describe('mappedRepoBuild happy path', () => { it('should return RepoBuild from Build', () => { From 1953874ee548606149e8b9aab72265f03c68ddd9 Mon Sep 17 00:00:00 2001 From: Andre Wanlin Date: Sat, 25 Nov 2023 18:40:57 -0600 Subject: [PATCH 114/261] Signed-off-by: Andre Wanlin --- .../src/api/AzureDevOpsApi.test.ts | 764 ++++++++++++++++++ 1 file changed, 764 insertions(+) create mode 100644 plugins/azure-devops-backend/src/api/AzureDevOpsApi.test.ts diff --git a/plugins/azure-devops-backend/src/api/AzureDevOpsApi.test.ts b/plugins/azure-devops-backend/src/api/AzureDevOpsApi.test.ts new file mode 100644 index 0000000000..174c5ff6cd --- /dev/null +++ b/plugins/azure-devops-backend/src/api/AzureDevOpsApi.test.ts @@ -0,0 +1,764 @@ +/* + * 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. + */ + +jest.mock('azure-devops-node-api', () => ({ + WebApi: jest.fn(), + getHandlerFromToken: jest.fn().mockReturnValue(() => {}), +})); + +import { UrlReader, getVoidLogger } from '@backstage/backend-common'; +import { ConfigReader } from '@backstage/config'; +import { AzureDevOpsApi } from './AzureDevOpsApi'; +import { WebApi } from 'azure-devops-node-api'; +import { TeamProjectReference } from 'azure-devops-node-api/interfaces/CoreInterfaces'; +import { GitRepository } from 'azure-devops-node-api/interfaces/TfvcInterfaces'; +import { + Build, + BuildResult, + BuildStatus, +} from 'azure-devops-node-api/interfaces/BuildInterfaces'; +import { + GitPullRequest, + GitRef, + PullRequestStatus, +} from 'azure-devops-node-api/interfaces/GitInterfaces'; +import { PullRequestOptions } from '@backstage/plugin-azure-devops-common'; + +describe('AzureDevOpsApi', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + const mockConfig = new ConfigReader({ + azureDevOps: { + host: 'dev.azure.com', + token: 'token', + organization: 'org', + }, + integrations: { + azure: [ + { + host: 'dev.azure.com', + credentials: [ + { + personalAccessToken: 'pat', + }, + ], + }, + ], + }, + }); + + const mockLogger = getVoidLogger(); + + const mockUrlReader: UrlReader = { + readUrl: url => + Promise.resolve({ + buffer: async () => Buffer.from(url), + etag: 'buffer', + stream: jest.fn(), + }), + readTree: jest.fn(), + search: jest.fn(), + }; + + it('should get projects', async () => { + const mockProjects: TeamProjectReference[] = [ + { + id: 'one', + name: 'one', + description: 'one', + }, + { + id: 'two', + name: 'two', + description: 'two', + }, + { + id: 'three', + name: 'three', + description: 'three', + }, + ]; + + const mockCoreApiClient = { + getProjects: jest.fn().mockResolvedValue(mockProjects), + }; + + const mockCoreApi = { + getCoreApi: jest.fn().mockResolvedValue(mockCoreApiClient), + }; + + (WebApi as unknown as jest.Mock).mockImplementation(() => mockCoreApi); + + const api = AzureDevOpsApi.fromConfig(mockConfig, { + logger: mockLogger, + urlReader: mockUrlReader, + }); + + const result = await api.getProjects(); + + expect(result).toEqual([ + { + id: 'one', + name: 'one', + description: 'one', + }, + { + id: 'three', + name: 'three', + description: 'three', + }, + { + id: 'two', + name: 'two', + description: 'two', + }, + ]); + }); + + it('should get git repository', async () => { + const mockGitRepository: GitRepository = { + id: 'repo', + }; + + const mockGitClient = { + getRepository: jest.fn().mockResolvedValue(mockGitRepository), + }; + const mockGitApi = { + getGitApi: jest.fn().mockReturnValue(mockGitClient), + }; + + (WebApi as unknown as jest.Mock).mockImplementation(() => mockGitApi); + + const api = AzureDevOpsApi.fromConfig(mockConfig, { + logger: mockLogger, + urlReader: mockUrlReader, + }); + + const result = await api.getGitRepository('project', 'repo'); + + expect(result).toEqual({ id: 'repo' }); + }); + + it('should get build list', async () => { + const mockBuilds: Build[] = [ + { + id: 1, + }, + { + id: 2, + }, + { + id: 3, + }, + ]; + + const mockBuildClient = { + getBuilds: jest.fn().mockResolvedValue(mockBuilds), + }; + const mockBuildApi = { + getBuildApi: jest.fn().mockReturnValue(mockBuildClient), + }; + + (WebApi as unknown as jest.Mock).mockImplementation(() => mockBuildApi); + + const api = AzureDevOpsApi.fromConfig(mockConfig, { + logger: mockLogger, + urlReader: mockUrlReader, + }); + + const result = await api.getBuildList('project', 'repo', 10); + + expect(result).toEqual([{ id: 1 }, { id: 2 }, { id: 3 }]); + }); + + it('should get repo builds', async () => { + const mockGitRepository: GitRepository = { + id: 'repo', + }; + + const mockBuilds: Build[] = [ + { + id: 1, + buildNumber: 'Build-1', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: new Date('2020-09-12T06:10:23.932Z'), + startTime: new Date('2020-09-12T06:15:23.932Z'), + finishTime: new Date('2020-09-12T06:20:23.932Z'), + sourceBranch: 'main', + sourceVersion: 'abcd', + }, + { + id: 2, + buildNumber: 'Build-2', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: new Date('2020-09-12T06:10:23.932Z'), + startTime: new Date('2020-09-12T06:15:23.932Z'), + finishTime: new Date('2020-09-12T06:20:23.932Z'), + sourceBranch: 'main', + sourceVersion: 'abcd', + }, + { + id: 3, + buildNumber: 'Build-3', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: new Date('2020-09-12T06:10:23.932Z'), + startTime: new Date('2020-09-12T06:15:23.932Z'), + finishTime: new Date('2020-09-12T06:20:23.932Z'), + sourceBranch: 'main', + sourceVersion: 'abcd', + }, + ]; + + const mockBuildClient = { + getBuilds: jest.fn().mockResolvedValue(mockBuilds), + }; + const mockGitClient = { + getRepository: jest.fn().mockResolvedValue(mockGitRepository), + }; + const mockApi = { + getGitApi: jest.fn().mockReturnValue(mockGitClient), + getBuildApi: jest.fn().mockReturnValue(mockBuildClient), + }; + + (WebApi as unknown as jest.Mock).mockImplementation(() => mockApi); + + const api = AzureDevOpsApi.fromConfig(mockConfig, { + logger: mockLogger, + urlReader: mockUrlReader, + }); + + const result = await api.getRepoBuilds('project', 'repo', 10); + + expect(result).toEqual([ + { + id: 1, + title: 'Build-1', + link: '', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: '2020-09-12T06:10:23.932Z', + startTime: '2020-09-12T06:15:23.932Z', + finishTime: '2020-09-12T06:20:23.932Z', + source: 'main (abcd)', + uniqueName: 'N/A', + }, + { + id: 2, + title: 'Build-2', + link: '', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: '2020-09-12T06:10:23.932Z', + startTime: '2020-09-12T06:15:23.932Z', + finishTime: '2020-09-12T06:20:23.932Z', + source: 'main (abcd)', + uniqueName: 'N/A', + }, + { + id: 3, + title: 'Build-3', + link: '', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: '2020-09-12T06:10:23.932Z', + startTime: '2020-09-12T06:15:23.932Z', + finishTime: '2020-09-12T06:20:23.932Z', + source: 'main (abcd)', + uniqueName: 'N/A', + }, + ]); + }); + + it('should get git tags', async () => { + const mockGitRepository: GitRepository = { + id: 'repo', + }; + + const mockGitRefs: GitRef[] = [ + { + objectId: '1.0', + peeledObjectId: '1.0', + name: 'v1.0', + }, + { + objectId: '2.0', + peeledObjectId: '2.0', + name: 'v2.0', + }, + { + objectId: '3.0', + peeledObjectId: '3.0', + name: 'v3.0', + }, + ]; + + const mockGitClient = { + getRepository: jest.fn().mockResolvedValue(mockGitRepository), + getRefs: jest.fn().mockResolvedValue(mockGitRefs), + }; + const mockApi = { + getGitApi: jest.fn().mockReturnValue(mockGitClient), + serverUrl: 'serverUrl', + }; + + (WebApi as unknown as jest.Mock).mockImplementation(() => mockApi); + + const api = AzureDevOpsApi.fromConfig(mockConfig, { + logger: mockLogger, + urlReader: mockUrlReader, + }); + + const result = await api.getGitTags('project', 'repo'); + + expect(result).toEqual([ + { + objectId: '1.0', + peeledObjectId: '1.0', + name: 'v1.0', + commitLink: 'serverUrl/project/_git/repo/commit/1.0', + createdBy: 'N/A', + link: 'serverUrl/project/_git/repo?version=GTv1.0', + }, + { + objectId: '2.0', + peeledObjectId: '2.0', + name: 'v2.0', + commitLink: 'serverUrl/project/_git/repo/commit/2.0', + createdBy: 'N/A', + link: 'serverUrl/project/_git/repo?version=GTv2.0', + }, + { + objectId: '3.0', + peeledObjectId: '3.0', + name: 'v3.0', + commitLink: 'serverUrl/project/_git/repo/commit/3.0', + createdBy: 'N/A', + link: 'serverUrl/project/_git/repo?version=GTv3.0', + }, + ]); + }); + + it('should get pull requests', async () => { + const mockGitRepository: GitRepository = { + id: 'repo', + name: 'repo', + }; + + const mockGitPullRequests: GitPullRequest[] = [ + { + pullRequestId: 1, + repository: mockGitRepository, + title: 'PR1', + creationDate: new Date('2020-09-12T06:10:23.932Z'), + sourceRefName: 'refs/heads/topic/pr1', + targetRefName: 'refs/heads/main', + status: PullRequestStatus.Active, + isDraft: false, + }, + { + pullRequestId: 2, + repository: mockGitRepository, + title: 'PR2', + creationDate: new Date('2020-09-12T06:10:23.932Z'), + sourceRefName: 'refs/heads/topic/pr2', + targetRefName: 'refs/heads/main', + status: PullRequestStatus.Active, + isDraft: false, + }, + { + pullRequestId: 3, + repository: mockGitRepository, + title: 'PR3', + creationDate: new Date('2020-09-12T06:10:23.932Z'), + sourceRefName: 'refs/heads/topic/pr3', + targetRefName: 'refs/heads/main', + status: PullRequestStatus.Active, + isDraft: false, + }, + ]; + + const mockGitClient = { + getRepository: jest.fn().mockResolvedValue(mockGitRepository), + getPullRequests: jest.fn().mockResolvedValue(mockGitPullRequests), + }; + const mockApi = { + getGitApi: jest.fn().mockReturnValue(mockGitClient), + serverUrl: 'serverUrl', + }; + + (WebApi as unknown as jest.Mock).mockImplementation(() => mockApi); + + const api = AzureDevOpsApi.fromConfig(mockConfig, { + logger: mockLogger, + urlReader: mockUrlReader, + }); + + const pullRequestOptions: PullRequestOptions = { + top: 10, + status: PullRequestStatus.Active, + }; + + const result = await api.getPullRequests( + 'project', + 'repo', + pullRequestOptions, + ); + + expect(result).toEqual([ + { + pullRequestId: 1, + repoName: 'repo', + title: 'PR1', + uniqueName: 'N/A', + createdBy: 'N/A', + creationDate: '2020-09-12T06:10:23.932Z', + sourceRefName: 'refs/heads/topic/pr1', + targetRefName: 'refs/heads/main', + status: PullRequestStatus.Active, + isDraft: false, + link: 'serverUrl/project/_git/repo/pullrequest/1', + }, + { + pullRequestId: 2, + repoName: 'repo', + title: 'PR2', + uniqueName: 'N/A', + createdBy: 'N/A', + creationDate: '2020-09-12T06:10:23.932Z', + sourceRefName: 'refs/heads/topic/pr2', + targetRefName: 'refs/heads/main', + status: PullRequestStatus.Active, + isDraft: false, + link: 'serverUrl/project/_git/repo/pullrequest/2', + }, + { + pullRequestId: 3, + repoName: 'repo', + title: 'PR3', + uniqueName: 'N/A', + createdBy: 'N/A', + creationDate: '2020-09-12T06:10:23.932Z', + sourceRefName: 'refs/heads/topic/pr3', + targetRefName: 'refs/heads/main', + status: PullRequestStatus.Active, + isDraft: false, + link: 'serverUrl/project/_git/repo/pullrequest/3', + }, + ]); + }); + + it('should get build definitions', async () => { + const mockBuilds: Build[] = [ + { + id: 1, + }, + { + id: 2, + }, + { + id: 3, + }, + ]; + + const mockBuildClient = { + getDefinitions: jest.fn().mockResolvedValue(mockBuilds), + }; + const mockBuildApi = { + getBuildApi: jest.fn().mockReturnValue(mockBuildClient), + }; + + (WebApi as unknown as jest.Mock).mockImplementation(() => mockBuildApi); + + const api = AzureDevOpsApi.fromConfig(mockConfig, { + logger: mockLogger, + urlReader: mockUrlReader, + }); + + const result = await api.getBuildDefinitions('project', 'definition'); + + expect(result).toEqual([{ id: 1 }, { id: 2 }, { id: 3 }]); + }); + + it('should get build builds with repoId', async () => { + const mockBuilds: Build[] = [ + { + id: 1, + }, + { + id: 2, + }, + { + id: 3, + }, + ]; + + const mockBuildClient = { + getBuilds: jest.fn().mockResolvedValue(mockBuilds), + }; + const mockBuildApi = { + getBuildApi: jest.fn().mockReturnValue(mockBuildClient), + }; + + (WebApi as unknown as jest.Mock).mockImplementation(() => mockBuildApi); + + const api = AzureDevOpsApi.fromConfig(mockConfig, { + logger: mockLogger, + urlReader: mockUrlReader, + }); + + const result = await api.getBuilds('project', 10, 'repo', undefined); + + expect(result).toEqual([{ id: 1 }, { id: 2 }, { id: 3 }]); + }); + + it('should get build builds with definitions', async () => { + const mockBuilds: Build[] = [ + { + id: 1, + }, + { + id: 2, + }, + { + id: 3, + }, + ]; + + const mockBuildClient = { + getBuilds: jest.fn().mockResolvedValue(mockBuilds), + }; + const mockBuildApi = { + getBuildApi: jest.fn().mockReturnValue(mockBuildClient), + }; + + (WebApi as unknown as jest.Mock).mockImplementation(() => mockBuildApi); + + const api = AzureDevOpsApi.fromConfig(mockConfig, { + logger: mockLogger, + urlReader: mockUrlReader, + }); + + const result = await api.getBuilds('project', 10, undefined, [1, 2, 3]); + + expect(result).toEqual([{ id: 1 }, { id: 2 }, { id: 3 }]); + }); + + it('should get build runs with repoName', async () => { + const mockGitRepository: GitRepository = { + id: 'repo', + }; + + const mockBuilds: Build[] = [ + { + id: 1, + buildNumber: 'Build-1', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: new Date('2020-09-12T06:10:23.932Z'), + startTime: new Date('2020-09-12T06:15:23.932Z'), + finishTime: new Date('2020-09-12T06:20:23.932Z'), + sourceBranch: 'main', + sourceVersion: 'abcd', + }, + { + id: 2, + buildNumber: 'Build-2', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: new Date('2020-09-12T06:10:23.932Z'), + startTime: new Date('2020-09-12T06:15:23.932Z'), + finishTime: new Date('2020-09-12T06:20:23.932Z'), + sourceBranch: 'main', + sourceVersion: 'abcd', + }, + { + id: 3, + buildNumber: 'Build-3', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: new Date('2020-09-12T06:10:23.932Z'), + startTime: new Date('2020-09-12T06:15:23.932Z'), + finishTime: new Date('2020-09-12T06:20:23.932Z'), + sourceBranch: 'main', + sourceVersion: 'abcd', + }, + ]; + + const mockBuildClient = { + getBuilds: jest.fn().mockResolvedValue(mockBuilds), + }; + const mockGitClient = { + getRepository: jest.fn().mockResolvedValue(mockGitRepository), + }; + const mockApi = { + getGitApi: jest.fn().mockReturnValue(mockGitClient), + getBuildApi: jest.fn().mockReturnValue(mockBuildClient), + }; + + (WebApi as unknown as jest.Mock).mockImplementation(() => mockApi); + + const api = AzureDevOpsApi.fromConfig(mockConfig, { + logger: mockLogger, + urlReader: mockUrlReader, + }); + + const result = await api.getBuildRuns('project', 10, 'repo', undefined); + + expect(result).toEqual([ + { + id: 1, + title: 'Build-1', + link: '', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: '2020-09-12T06:10:23.932Z', + startTime: '2020-09-12T06:15:23.932Z', + finishTime: '2020-09-12T06:20:23.932Z', + source: 'main (abcd)', + uniqueName: 'N/A', + }, + { + id: 2, + title: 'Build-2', + link: '', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: '2020-09-12T06:10:23.932Z', + startTime: '2020-09-12T06:15:23.932Z', + finishTime: '2020-09-12T06:20:23.932Z', + source: 'main (abcd)', + uniqueName: 'N/A', + }, + { + id: 3, + title: 'Build-3', + link: '', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: '2020-09-12T06:10:23.932Z', + startTime: '2020-09-12T06:15:23.932Z', + finishTime: '2020-09-12T06:20:23.932Z', + source: 'main (abcd)', + uniqueName: 'N/A', + }, + ]); + }); + + it('should get build runs with definitionName', async () => { + const mockBuilds: Build[] = [ + { + id: 1, + buildNumber: 'Build-1', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: new Date('2020-09-12T06:10:23.932Z'), + startTime: new Date('2020-09-12T06:15:23.932Z'), + finishTime: new Date('2020-09-12T06:20:23.932Z'), + sourceBranch: 'main', + sourceVersion: 'abcd', + }, + { + id: 2, + buildNumber: 'Build-2', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: new Date('2020-09-12T06:10:23.932Z'), + startTime: new Date('2020-09-12T06:15:23.932Z'), + finishTime: new Date('2020-09-12T06:20:23.932Z'), + sourceBranch: 'main', + sourceVersion: 'abcd', + }, + { + id: 3, + buildNumber: 'Build-3', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: new Date('2020-09-12T06:10:23.932Z'), + startTime: new Date('2020-09-12T06:15:23.932Z'), + finishTime: new Date('2020-09-12T06:20:23.932Z'), + sourceBranch: 'main', + sourceVersion: 'abcd', + }, + ]; + + const mockBuildClient = { + getBuilds: jest.fn().mockResolvedValue(mockBuilds), + getDefinitions: jest.fn().mockResolvedValue(mockBuilds), + }; + + const mockApi = { + getBuildApi: jest.fn().mockReturnValue(mockBuildClient), + }; + + (WebApi as unknown as jest.Mock).mockImplementation(() => mockApi); + + const api = AzureDevOpsApi.fromConfig(mockConfig, { + logger: mockLogger, + urlReader: mockUrlReader, + }); + + const result = await api.getBuildRuns( + 'project', + 10, + undefined, + 'definition', + ); + + expect(result).toEqual([ + { + id: 1, + title: 'Build-1', + link: '', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: '2020-09-12T06:10:23.932Z', + startTime: '2020-09-12T06:15:23.932Z', + finishTime: '2020-09-12T06:20:23.932Z', + source: 'main (abcd)', + uniqueName: 'N/A', + }, + { + id: 2, + title: 'Build-2', + link: '', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: '2020-09-12T06:10:23.932Z', + startTime: '2020-09-12T06:15:23.932Z', + finishTime: '2020-09-12T06:20:23.932Z', + source: 'main (abcd)', + uniqueName: 'N/A', + }, + { + id: 3, + title: 'Build-3', + link: '', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: '2020-09-12T06:10:23.932Z', + startTime: '2020-09-12T06:15:23.932Z', + finishTime: '2020-09-12T06:20:23.932Z', + source: 'main (abcd)', + uniqueName: 'N/A', + }, + ]); + }); +}); From bc3fba1f0bfbd343a555853a28b7468ef19da731 Mon Sep 17 00:00:00 2001 From: Florian JUDITH Date: Sat, 25 Nov 2023 20:14:46 -0500 Subject: [PATCH 115/261] Updated changeset details Signed-off-by: Florian JUDITH --- .changeset/ninety-otters-report.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/ninety-otters-report.md b/.changeset/ninety-otters-report.md index 9b47097f73..fbccc481f4 100644 --- a/.changeset/ninety-otters-report.md +++ b/.changeset/ninety-otters-report.md @@ -2,4 +2,4 @@ '@backstage/plugin-lighthouse-backend': minor --- -Updated Lighthouse schedule configuration to fix crashes when using custom configuration +Fixed crashes faced with custom schedule configuration. The configuration schema has been update to leverage the TaskScheduleDefinition interface. It is highly recommended to move the `lighthouse.shedule` and `lighthouse.timeout` respectively to `lighthouse.schedule.frequency` and `lighthouse.schedule.timeout`. From 6e32443ebd473ff37253801537aff3ab0e82ba56 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Wed, 8 Nov 2023 09:58:30 +0100 Subject: [PATCH 116/261] feat: copy analytics context files Signed-off-by: Camila Belo --- .../src/analytics/AnalyticsContext.test.tsx | 85 +++++ .../src/analytics/AnalyticsContext.tsx | 109 +++++++ .../src/analytics/Tracker.test.ts | 306 ++++++++++++++++++ .../src/analytics/Tracker.ts | 180 +++++++++++ .../src/analytics/index.ts | 19 ++ .../src/analytics/types.ts | 46 +++ .../src/analytics/useAnalytics.test.tsx | 67 ++++ .../src/analytics/useAnalytics.tsx | 57 ++++ .../src/apis/definitions/AnalyticsApi.ts | 131 ++++++++ .../src/apis/definitions/index.ts | 1 + packages/frontend-plugin-api/src/index.ts | 1 + 11 files changed, 1002 insertions(+) create mode 100644 packages/frontend-plugin-api/src/analytics/AnalyticsContext.test.tsx create mode 100644 packages/frontend-plugin-api/src/analytics/AnalyticsContext.tsx create mode 100644 packages/frontend-plugin-api/src/analytics/Tracker.test.ts create mode 100644 packages/frontend-plugin-api/src/analytics/Tracker.ts create mode 100644 packages/frontend-plugin-api/src/analytics/index.ts create mode 100644 packages/frontend-plugin-api/src/analytics/types.ts create mode 100644 packages/frontend-plugin-api/src/analytics/useAnalytics.test.tsx create mode 100644 packages/frontend-plugin-api/src/analytics/useAnalytics.tsx create mode 100644 packages/frontend-plugin-api/src/apis/definitions/AnalyticsApi.ts diff --git a/packages/frontend-plugin-api/src/analytics/AnalyticsContext.test.tsx b/packages/frontend-plugin-api/src/analytics/AnalyticsContext.test.tsx new file mode 100644 index 0000000000..c29ec5b3ca --- /dev/null +++ b/packages/frontend-plugin-api/src/analytics/AnalyticsContext.test.tsx @@ -0,0 +1,85 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { render } from '@testing-library/react'; +import { renderHook } from '@testing-library/react'; +import { AnalyticsContext, useAnalyticsContext } from './AnalyticsContext'; + +const AnalyticsSpy = () => { + const context = useAnalyticsContext(); + return ( + <> +
{context.routeRef}
+
{context.pluginId}
+
{context.extension}
+
{context.custom}
+ + ); +}; + +describe('AnalyticsContext', () => { + describe('useAnalyticsContext', () => { + it('returns default values', () => { + const { result } = renderHook(() => useAnalyticsContext()); + expect(result.current).toEqual({ + extension: 'App', + pluginId: 'root', + routeRef: 'unknown', + }); + }); + }); + + describe('AnalyticsContext', () => { + it('uses default analytics context', () => { + const result = render( + + + , + ); + + expect(result.getByTestId('extension')).toHaveTextContent('App'); + expect(result.getByTestId('plugin-id')).toHaveTextContent('root'); + expect(result.getByTestId('route-ref')).toHaveTextContent('unknown'); + }); + + it('uses provided analytics context', () => { + const result = render( + + + , + ); + + expect(result.getByTestId('extension')).toHaveTextContent('App'); + expect(result.getByTestId('plugin-id')).toHaveTextContent('custom'); + expect(result.getByTestId('route-ref')).toHaveTextContent('unknown'); + }); + + it('uses nested analytics context', () => { + const result = render( + + + + + , + ); + + expect(result.getByTestId('extension')).toHaveTextContent('AnalyticsSpy'); + expect(result.getByTestId('plugin-id')).toHaveTextContent('custom'); + expect(result.getByTestId('route-ref')).toHaveTextContent('unknown'); + }); + }); +}); diff --git a/packages/frontend-plugin-api/src/analytics/AnalyticsContext.tsx b/packages/frontend-plugin-api/src/analytics/AnalyticsContext.tsx new file mode 100644 index 0000000000..105be8e2b5 --- /dev/null +++ b/packages/frontend-plugin-api/src/analytics/AnalyticsContext.tsx @@ -0,0 +1,109 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + createVersionedContext, + createVersionedValueMap, +} from '@backstage/version-bridge'; +import React, { ReactNode, useContext } from 'react'; +import { AnalyticsContextValue } from './types'; + +const AnalyticsReactContext = createVersionedContext<{ + 1: AnalyticsContextValue; +}>('analytics-context'); + +/** + * A "private" (to this package) hook that enables context inheritance and a + * way to read Analytics Context values at event capture-time. + * + * @internal + */ +export const useAnalyticsContext = (): AnalyticsContextValue => { + const theContext = useContext(AnalyticsReactContext); + + // Provide a default value if no value exists. + if (theContext === undefined) { + return { + routeRef: 'unknown', + pluginId: 'root', + extension: 'App', + }; + } + + // This should probably never happen, but check for it. + const theValue = theContext.atVersion(1); + if (theValue === undefined) { + throw new Error('No context found for version 1.'); + } + + return theValue; +}; + +/** + * Provides components in the child react tree an Analytics Context, ensuring + * all analytics events captured within the context have relevant attributes. + * + * @remarks + * + * Analytics contexts are additive, meaning the context ultimately emitted with + * an event is the combination of all contexts in the parent tree. + * + * @public + */ +export const AnalyticsContext = (options: { + attributes: Partial; + children: ReactNode; +}) => { + const { attributes, children } = options; + + const parentValues = useAnalyticsContext(); + const combinedValue = { + ...parentValues, + ...attributes, + }; + + const versionedCombinedValue = createVersionedValueMap({ 1: combinedValue }); + return ( + + {children} + + ); +}; + +/** + * Returns an HOC wrapping the provided component in an Analytics context with + * the given values. + * + * @param Component - Component to be wrapped with analytics context attributes + * @param values - Analytics context key/value pairs. + * @internal + */ +export function withAnalyticsContext( + Component: React.ComponentType, + values: AnalyticsContextValue, +) { + const ComponentWithAnalyticsContext = (props: TProps) => { + return ( + + + + ); + }; + ComponentWithAnalyticsContext.displayName = `WithAnalyticsContext(${ + Component.displayName || Component.name || 'Component' + })`; + return ComponentWithAnalyticsContext; +} diff --git a/packages/frontend-plugin-api/src/analytics/Tracker.test.ts b/packages/frontend-plugin-api/src/analytics/Tracker.test.ts new file mode 100644 index 0000000000..e0e3a87f6d --- /dev/null +++ b/packages/frontend-plugin-api/src/analytics/Tracker.test.ts @@ -0,0 +1,306 @@ +/* + * 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 { getOrCreateGlobalSingleton } from '@backstage/version-bridge'; +import { Tracker, routableExtensionRenderedEvent } from './Tracker'; + +describe('Tracker', () => { + const defaultContext = { + routeRef: 'unknown', + pluginId: 'root', + extension: 'App', + }; + const globalEvents = getOrCreateGlobalSingleton( + 'core-plugin-api:analytics-tracker-events', + () => ({}), + ); + const analyticsApiSpy = { + captureEvent: jest.fn(), + }; + let trackerUnderTest: Tracker; + + beforeEach(() => { + // Reset mocks and global state + jest.resetAllMocks(); + globalEvents.mostRecentGatheredNavigation = undefined; + globalEvents.mostRecentRoutableExtensionRender = undefined; + + // Set up a new tracker to test. + trackerUnderTest = new Tracker(analyticsApiSpy); + }); + + it('captures simple event with default context', () => { + trackerUnderTest.captureEvent('click', 'test 1'); + + expect(analyticsApiSpy.captureEvent).toHaveBeenCalledWith( + expect.objectContaining({ + action: 'click', + subject: 'test 1', + context: defaultContext, + }), + ); + }); + + it('captures simple event with set context', () => { + trackerUnderTest.setContext({ + routeRef: 'catalog:entity', + pluginId: 'catalog', + extension: 'App', + }); + trackerUnderTest.captureEvent('click', 'test 2', { + value: 2, + attributes: { to: '/page-2' }, + }); + + expect(analyticsApiSpy.captureEvent).toHaveBeenCalledWith( + expect.objectContaining({ + action: 'click', + subject: 'test 2', + value: 2, + attributes: { to: '/page-2' }, + context: { + routeRef: 'catalog:entity', + pluginId: 'catalog', + extension: 'App', + }, + }), + ); + }); + + describe('accurate navigate events', () => { + it('never captures _routeNodeType context key on navigate event', () => { + trackerUnderTest.setContext({ + routeRef: 'catalog:entity', + pluginId: 'catalog', + extension: 'App', + _routeNodeType: 'mounted', + }); + trackerUnderTest.captureEvent('navigate', '/page-3'); + + const receivedContext = + analyticsApiSpy.captureEvent.mock.calls[0][0].context; + expect(receivedContext.pluginId).toBe('catalog'); + expect(receivedContext._routeNodeType).toBe(undefined); + }); + + it('never immediately captures navigate event with _routeNodeType "gathered"', () => { + trackerUnderTest.setContext({ + ...defaultContext, + _routeNodeType: 'gathered', + }); + trackerUnderTest.captureEvent('navigate', '/page-4'); + + expect(analyticsApiSpy.captureEvent).not.toHaveBeenCalled(); + }); + + it('never captures "routable-extension-rendered" events', () => { + trackerUnderTest.captureEvent(routableExtensionRenderedEvent, ''); + + expect(analyticsApiSpy.captureEvent).not.toHaveBeenCalled(); + }); + + it('captures deferred navigate event with expected context', () => { + // User navigates to a gathered mountpoint with multiple plugins + trackerUnderTest.setContext({ + ...defaultContext, + _routeNodeType: 'gathered', + }); + trackerUnderTest.captureEvent('navigate', '/page-5'); + + // A routable extension is rendered with specific plugin context + trackerUnderTest.setContext({ + routeRef: 'some:ref', + pluginId: 'some-plugin', + extension: 'App', + }); + trackerUnderTest.captureEvent(routableExtensionRenderedEvent, ''); + + // A non-navigate event + trackerUnderTest.captureEvent('click', 'test 5'); + + expect(analyticsApiSpy.captureEvent).toHaveBeenCalledTimes(2); + expect(analyticsApiSpy.captureEvent).toHaveBeenNthCalledWith( + 1, + expect.objectContaining({ + action: 'navigate', + subject: '/page-5', + context: { + routeRef: 'some:ref', + pluginId: 'some-plugin', + extension: 'App', + }, + }), + ); + expect(analyticsApiSpy.captureEvent).toHaveBeenNthCalledWith( + 2, + expect.objectContaining({ + action: 'click', + subject: 'test 5', + context: { + routeRef: 'some:ref', + pluginId: 'some-plugin', + extension: 'App', + }, + }), + ); + }); + + it('captures deferred navigate event with expected context when second event is also deferrable', () => { + // User navigates to a gathered mountpoint with multiple plugins + trackerUnderTest.setContext({ + ...defaultContext, + _routeNodeType: 'gathered', + }); + trackerUnderTest.captureEvent('navigate', '/page-6'); + + // A routable extension is rendered with specific plugin context + trackerUnderTest.setContext({ + routeRef: 'another:ref', + pluginId: 'another-plugin', + extension: 'App', + }); + trackerUnderTest.captureEvent(routableExtensionRenderedEvent, ''); + + // User navigates to another gathered mountpoint with multiple plugins + trackerUnderTest.setContext({ + ...defaultContext, + _routeNodeType: 'gathered', + }); + trackerUnderTest.captureEvent('navigate', '/page-6-2'); + + expect(analyticsApiSpy.captureEvent).toHaveBeenCalledTimes(1); + expect(analyticsApiSpy.captureEvent).toHaveBeenNthCalledWith( + 1, + expect.objectContaining({ + action: 'navigate', + subject: '/page-6', + context: { + routeRef: 'another:ref', + pluginId: 'another-plugin', + extension: 'App', + }, + }), + ); + }); + + it('captures deferred navigate event with default context when no extension is rendered in between', () => { + // User navigates to a gathered mountpoint with multiple plugins + trackerUnderTest.setContext({ + ...defaultContext, + _routeNodeType: 'gathered', + }); + trackerUnderTest.captureEvent('navigate', '/page-7'); + + // A non-navigate event with no routable extension render in between + trackerUnderTest.captureEvent('click', 'test 7'); + + expect(analyticsApiSpy.captureEvent).toHaveBeenCalledTimes(2); + expect(analyticsApiSpy.captureEvent).toHaveBeenNthCalledWith( + 1, + expect.objectContaining({ + action: 'navigate', + subject: '/page-7', + context: defaultContext, + }), + ); + expect(analyticsApiSpy.captureEvent).toHaveBeenNthCalledWith( + 2, + expect.objectContaining({ + action: 'click', + subject: 'test 7', + context: defaultContext, + }), + ); + }); + + it('captures deferred navigate event with expected context across separate trackers', () => { + // User navigates to a gathered mountpoint with multiple plugins + trackerUnderTest.setContext({ + ...defaultContext, + _routeNodeType: 'gathered', + }); + trackerUnderTest.captureEvent('navigate', '/page-8'); + + // A routable extension is rendered with specific plugin context and + // captured via a separate tracker instance. + const anotherTracker = new Tracker(analyticsApiSpy, { + routeRef: 'the:ref', + pluginId: 'the-plugin', + extension: 'App', + }); + anotherTracker.captureEvent(routableExtensionRenderedEvent, ''); + + // A non-navigate event is captured + const aThirdTracker = new Tracker(analyticsApiSpy); + aThirdTracker.captureEvent('click', 'test 8'); + + expect(analyticsApiSpy.captureEvent).toHaveBeenCalledTimes(2); + expect(analyticsApiSpy.captureEvent).toHaveBeenNthCalledWith( + 1, + expect.objectContaining({ + action: 'navigate', + subject: '/page-8', + context: { + routeRef: 'the:ref', + pluginId: 'the-plugin', + extension: 'App', + }, + }), + ); + expect(analyticsApiSpy.captureEvent).toHaveBeenNthCalledWith( + 2, + expect.objectContaining({ + action: 'click', + subject: 'test 8', + }), + ); + }); + + it('replaces extension context with "App" when capturing deferred events', () => { + // User navigates to a gathered mountpoint with multiple plugins + trackerUnderTest.setContext({ + ...defaultContext, + _routeNodeType: 'gathered', + }); + trackerUnderTest.captureEvent('navigate', '/page-9'); + + // A routable extension is rendered with specific plugin context + trackerUnderTest.setContext({ + routeRef: 'very:ref', + pluginId: 'very-plugin', + extension: 'ShouldBeReplaced', + }); + trackerUnderTest.captureEvent(routableExtensionRenderedEvent, ''); + + // A non-navigate event + trackerUnderTest.captureEvent('click', 'test 9'); + + // Extension context should have been replaced with just "App" + expect(analyticsApiSpy.captureEvent).toHaveBeenNthCalledWith( + 1, + expect.objectContaining({ + action: 'navigate', + subject: '/page-9', + context: { + routeRef: 'very:ref', + pluginId: 'very-plugin', + extension: 'App', + }, + }), + ); + }); + }); +}); diff --git a/packages/frontend-plugin-api/src/analytics/Tracker.ts b/packages/frontend-plugin-api/src/analytics/Tracker.ts new file mode 100644 index 0000000000..130410e2a2 --- /dev/null +++ b/packages/frontend-plugin-api/src/analytics/Tracker.ts @@ -0,0 +1,180 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { getOrCreateGlobalSingleton } from '@backstage/version-bridge'; +import { + AnalyticsApi, + AnalyticsEventAttributes, + AnalyticsTracker, +} from '../apis'; +import { AnalyticsContextValue } from './'; + +type TempGlobalEvents = { + /** + * Stores the most recent "gathered" mountpoint navigation. + */ + mostRecentGatheredNavigation?: { + action: string; + subject: string; + value?: number; + attributes?: AnalyticsEventAttributes; + context: AnalyticsContextValue; + }; + /** + * Stores the most recent routable extension render. + */ + mostRecentRoutableExtensionRender?: { + context: AnalyticsContextValue; + }; + /** + * Tracks whether or not a beforeunload event listener has already been + * registered. + */ + beforeUnloadRegistered: boolean; +}; + +/** + * Temporary global store for select event data. Used to make `navigate` events + * more accurate when gathered mountpoints are used. + */ +const globalEvents = getOrCreateGlobalSingleton( + 'core-plugin-api:analytics-tracker-events', + () => ({ + mostRecentGatheredNavigation: undefined, + mostRecentRoutableExtensionRender: undefined, + beforeUnloadRegistered: false, + }), +); + +/** + * Internal-only event representing when a routable extension is rendered. + */ +export const routableExtensionRenderedEvent = '_ROUTABLE-EXTENSION-RENDERED'; + +export class Tracker implements AnalyticsTracker { + constructor( + private readonly analyticsApi: AnalyticsApi, + private context: AnalyticsContextValue = { + routeRef: 'unknown', + pluginId: 'root', + extension: 'App', + }, + ) { + // Only register a single beforeunload event across all trackers. + if (!globalEvents.beforeUnloadRegistered) { + // Before the page unloads, attempt to capture any deferred navigation + // events that haven't yet been captured. + addEventListener( + 'beforeunload', + () => { + if (globalEvents.mostRecentGatheredNavigation) { + this.analyticsApi.captureEvent({ + ...globalEvents.mostRecentGatheredNavigation, + ...globalEvents.mostRecentRoutableExtensionRender, + }); + globalEvents.mostRecentGatheredNavigation = undefined; + globalEvents.mostRecentRoutableExtensionRender = undefined; + } + }, + { once: true, passive: true }, + ); + + // Prevent duplicate handlers from being registered. + globalEvents.beforeUnloadRegistered = true; + } + } + + setContext(context: AnalyticsContextValue) { + this.context = context; + } + + captureEvent( + action: string, + subject: string, + { + value, + attributes, + }: { value?: number; attributes?: AnalyticsEventAttributes } = {}, + ) { + // Never pass internal "_routeNodeType" context value. + const { _routeNodeType, ...context } = this.context; + + // Never fire the special "_routable-extension-rendered" internal event. + if (action === routableExtensionRenderedEvent) { + // But keep track of it if we're delaying a `navigate` event for a + // a gathered route node type. + if (globalEvents.mostRecentGatheredNavigation) { + globalEvents.mostRecentRoutableExtensionRender = { + context: { + ...context, + extension: 'App', + }, + }; + } + return; + } + + // If we are about to fire a real event, and we have an un-fired gathered + // mountpoint navigation on the global store, we need to fire the navigate + // event first, so this real event happens accurately after the navigation. + if (globalEvents.mostRecentGatheredNavigation) { + try { + this.analyticsApi.captureEvent({ + ...globalEvents.mostRecentGatheredNavigation, + ...globalEvents.mostRecentRoutableExtensionRender, + }); + } catch (e) { + // eslint-disable-next-line no-console + console.warn('Error during analytics event capture. %o', e); + } + + // Clear the global stores. + globalEvents.mostRecentGatheredNavigation = undefined; + globalEvents.mostRecentRoutableExtensionRender = undefined; + } + + // Never directly fire a navigation event on a gathered route with default + // contextual details. + if ( + action === 'navigate' && + _routeNodeType === 'gathered' && + context.pluginId === 'root' + ) { + // Instead, set it on the global store. + globalEvents.mostRecentGatheredNavigation = { + action, + subject, + value, + attributes, + context, + }; + return; + } + + try { + this.analyticsApi.captureEvent({ + action, + subject, + value, + attributes, + context, + }); + } catch (e) { + // eslint-disable-next-line no-console + console.warn('Error during analytics event capture. %o', e); + } + } +} diff --git a/packages/frontend-plugin-api/src/analytics/index.ts b/packages/frontend-plugin-api/src/analytics/index.ts new file mode 100644 index 0000000000..651e8e105e --- /dev/null +++ b/packages/frontend-plugin-api/src/analytics/index.ts @@ -0,0 +1,19 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { AnalyticsContext } from './AnalyticsContext'; +export type { AnalyticsContextValue, CommonAnalyticsContext } from './types'; +export { useAnalytics } from './useAnalytics'; diff --git a/packages/frontend-plugin-api/src/analytics/types.ts b/packages/frontend-plugin-api/src/analytics/types.ts new file mode 100644 index 0000000000..ed5dcd588d --- /dev/null +++ b/packages/frontend-plugin-api/src/analytics/types.ts @@ -0,0 +1,46 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Common analytics context attributes. + * + * @public + */ +export type CommonAnalyticsContext = { + /** + * The nearest known parent plugin where the event was captured. + */ + pluginId: string; + + /** + * The ID of the routeRef that was active when the event was captured. + */ + routeRef: string; + + /** + * The nearest known parent extension where the event was captured. + */ + extension: string; +}; + +/** + * Analytics context envelope. + * + * @public + */ +export type AnalyticsContextValue = CommonAnalyticsContext & { + [param in string]: string | boolean | number | undefined; +}; diff --git a/packages/frontend-plugin-api/src/analytics/useAnalytics.test.tsx b/packages/frontend-plugin-api/src/analytics/useAnalytics.test.tsx new file mode 100644 index 0000000000..e83826991a --- /dev/null +++ b/packages/frontend-plugin-api/src/analytics/useAnalytics.test.tsx @@ -0,0 +1,67 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { renderHook } from '@testing-library/react'; +import { useAnalytics } from './useAnalytics'; +import { useApi } from '@backstage/core-plugin-api'; + +jest.mock('@backstage/core-plugin-api', () => ({ + ...jest.requireActual('@backstage/core-plugin-api'), + useApi: jest.fn(), +})); + +const mocked = (f: Function) => f as jest.Mock; + +describe('useAnalytics', () => { + it('returns tracker with no implementation defined', () => { + // Simulate useApi() throwing an error. + mocked(useApi).mockImplementation(() => { + throw new Error(); + }); + + // Result should still have a captureEvent method. + const { result } = renderHook(() => useAnalytics()); + expect(result.current.captureEvent).toBeDefined(); + }); + + it('returns tracker from defined analytics api', () => { + const captureEvent = jest.fn(); + + // Simulate useApi returning a valid tracker. + mocked(useApi).mockReturnValue({ captureEvent }); + + // Calling the captureEvent method of the underlying implementation should + // pass along the given event as well as the default context. + const { result } = renderHook(() => useAnalytics()); + result.current.captureEvent('an action', 'a subject', { + value: 42, + attributes: { some: 'value' }, + }); + expect(captureEvent).toHaveBeenCalledWith({ + action: 'an action', + subject: 'a subject', + value: 42, + attributes: { + some: 'value', + }, + context: { + extension: 'App', + pluginId: 'root', + routeRef: 'unknown', + }, + }); + }); +}); diff --git a/packages/frontend-plugin-api/src/analytics/useAnalytics.tsx b/packages/frontend-plugin-api/src/analytics/useAnalytics.tsx new file mode 100644 index 0000000000..f3b5998de4 --- /dev/null +++ b/packages/frontend-plugin-api/src/analytics/useAnalytics.tsx @@ -0,0 +1,57 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { useApi } from '@backstage/core-plugin-api'; +import { useAnalyticsContext } from './AnalyticsContext'; +import { analyticsApiRef, AnalyticsTracker, AnalyticsApi } from '../apis'; +import { useRef } from 'react'; +import { Tracker } from './Tracker'; + +function useAnalyticsApi(): AnalyticsApi { + try { + return useApi(analyticsApiRef); + } catch { + return { captureEvent: () => {} }; + } +} + +/** + * Gets a pre-configured analytics tracker. + * + * @public + */ +export function useAnalytics(): AnalyticsTracker { + const trackerRef = useRef(null); + const context = useAnalyticsContext(); + // Our goal is to make this API truly optional for any/all consuming code + // (including tests). This hook runs last to ensure hook order is, as much as + // possible, maintained. + const analyticsApi = useAnalyticsApi(); + + function getTracker(): Tracker { + if (trackerRef.current === null) { + trackerRef.current = new Tracker(analyticsApi); + } + return trackerRef.current; + } + + const tracker = getTracker(); + // this is not ideal, but it allows to memoize the tracker + // without explicitly set the context as dependency. + tracker.setContext(context); + + return tracker; +} diff --git a/packages/frontend-plugin-api/src/apis/definitions/AnalyticsApi.ts b/packages/frontend-plugin-api/src/apis/definitions/AnalyticsApi.ts new file mode 100644 index 0000000000..15b09482b7 --- /dev/null +++ b/packages/frontend-plugin-api/src/apis/definitions/AnalyticsApi.ts @@ -0,0 +1,131 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ApiRef, createApiRef } from '@backstage/core-plugin-api'; +import { AnalyticsContextValue } from '../../analytics/types'; + +/** + * Represents an event worth tracking in an analytics system that could inform + * how users of a Backstage instance are using its features. + * + * @public + */ +export type AnalyticsEvent = { + /** + * A string that identifies the event being tracked by the type of action the + * event represents. Be careful not to encode extra metadata in this string + * that should instead be placed in the Analytics Context or attributes. + * Examples include: + * + * - view + * - click + * - filter + * - search + * - hover + * - scroll + */ + action: string; + + /** + * A string that uniquely identifies the object that the action is being + * taken on. Examples include: + * + * - The path of the page viewed + * - The url of the link clicked + * - The value that was filtered by + * - The text that was searched for + */ + subject: string; + + /** + * An optional numeric value relevant to the event that could be aggregated + * by analytics tools. Examples include: + * + * - The index or position of the clicked element in an ordered list + * - The percentage of an element that has been scrolled through + * - The amount of time that has elapsed since a fixed point + * - A satisfaction score on a fixed scale + */ + value?: number; + + /** + * Optional, additional attributes (representing dimensions or metrics) + * specific to the event that could be forwarded on to analytics systems. + */ + attributes?: AnalyticsEventAttributes; + + /** + * Contextual metadata relating to where the event was captured and by whom. + * This could include information about the route, plugin, or extension in + * which an event was captured. + */ + context: AnalyticsContextValue; +}; + +/** + * A structure allowing other arbitrary metadata to be provided by analytics + * event emitters. + * + * @public + */ +export type AnalyticsEventAttributes = { + [attribute in string]: string | boolean | number; +}; + +/** + * Represents a tracker with methods that can be called to track events in a + * configured analytics service. + * + * @public + */ +export type AnalyticsTracker = { + captureEvent: ( + action: string, + subject: string, + options?: { + value?: number; + attributes?: AnalyticsEventAttributes; + }, + ) => void; +}; + +/** + * The Analytics API is used to track user behavior in a Backstage instance. + * + * @remarks + * + * To instrument your App or Plugin, retrieve an analytics tracker using the + * useAnalytics() hook. This will return a pre-configured AnalyticsTracker + * with relevant methods for instrumentation. + * + * @public + */ +export type AnalyticsApi = { + /** + * Primary event handler responsible for compiling and forwarding events to + * an analytics system. + */ + captureEvent(event: AnalyticsEvent): void; +}; + +/** + * The API reference of {@link AnalyticsApi}. + * + * @public + */ +export const analyticsApiRef: ApiRef = createApiRef({ + id: 'core.analytics', +}); diff --git a/packages/frontend-plugin-api/src/apis/definitions/index.ts b/packages/frontend-plugin-api/src/apis/definitions/index.ts index 420942cb19..8791912e4a 100644 --- a/packages/frontend-plugin-api/src/apis/definitions/index.ts +++ b/packages/frontend-plugin-api/src/apis/definitions/index.ts @@ -42,3 +42,4 @@ export * from './FetchApi'; export * from './IdentityApi'; export * from './OAuthRequestApi'; export * from './StorageApi'; +export * from './AnalyticsApi'; diff --git a/packages/frontend-plugin-api/src/index.ts b/packages/frontend-plugin-api/src/index.ts index 3248e79945..10f89b81b5 100644 --- a/packages/frontend-plugin-api/src/index.ts +++ b/packages/frontend-plugin-api/src/index.ts @@ -20,6 +20,7 @@ * @packageDocumentation */ +export * from './analytics'; export * from './apis'; export * from './components'; export * from './extensions'; From 9f07394a999922d9b15991806a14d2633d714bd5 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Wed, 8 Nov 2023 14:09:33 +0100 Subject: [PATCH 117/261] feat: use analytics tracker on routing provider Signed-off-by: Camila Belo --- .../src/routing/RouteTracker.test.tsx | 228 ++++++++++++++++++ .../src/routing/RouteTracker.tsx | 141 +++++++++++ .../frontend-app-api/src/wiring/createApp.tsx | 2 + 3 files changed, 371 insertions(+) create mode 100644 packages/frontend-app-api/src/routing/RouteTracker.test.tsx create mode 100644 packages/frontend-app-api/src/routing/RouteTracker.tsx diff --git a/packages/frontend-app-api/src/routing/RouteTracker.test.tsx b/packages/frontend-app-api/src/routing/RouteTracker.test.tsx new file mode 100644 index 0000000000..fa5a4f633a --- /dev/null +++ b/packages/frontend-app-api/src/routing/RouteTracker.test.tsx @@ -0,0 +1,228 @@ +/* + * 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 { TestApiProvider } from '@backstage/test-utils'; +import React from 'react'; +import { BackstageRouteObject } from './types'; +import { fireEvent, render } from '@testing-library/react'; +import { RouteTracker } from './RouteTracker'; +import { Link, MemoryRouter, Route, Routes } from 'react-router-dom'; +import { createPlugin } from '@backstage/core-plugin-api'; +import { + createRouteRef, + AnalyticsApi, + analyticsApiRef, +} from '@backstage/frontend-plugin-api'; +import { MATCH_ALL_ROUTE } from './extractRouteInfoFromAppNode'; + +describe('RouteTracker', () => { + const routeRef0 = createRouteRef(); + const routeRef1 = createRouteRef(); + const routeRef2 = createRouteRef(); + const plugin0 = createPlugin({ id: 'home' }); + const plugin1 = createPlugin({ id: 'plugin1' }); + const plugin2 = createPlugin({ id: 'plugin2' }); + + const routeObjects: BackstageRouteObject[] = [ + { + path: '', + element:
home page
, + routeRefs: new Set([routeRef0]), + plugins: new Set([plugin0]), + caseSensitive: false, + children: [MATCH_ALL_ROUTE], + }, + { + path: '/path/:p1/:p2', + element: go, + routeRefs: new Set([routeRef1]), + plugins: new Set([plugin1]), + caseSensitive: false, + children: [MATCH_ALL_ROUTE], + }, + { + path: '/path2/:param', + element:
hi there
, + routeRefs: new Set([routeRef2]), + plugins: new Set([plugin2]), + caseSensitive: false, + children: [MATCH_ALL_ROUTE], + }, + ]; + + const mockedAnalytics: jest.Mocked = { + captureEvent: jest.fn(), + }; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should capture the navigate event on load', async () => { + render( + + + + + , + ); + + expect(mockedAnalytics.captureEvent).toHaveBeenCalledWith({ + action: 'navigate', + attributes: { + p1: 'foo', + p2: 'bar', + }, + context: { + extension: 'App', + pluginId: 'plugin1', + routeRef: undefined, + }, + subject: '/path/foo/bar', + value: undefined, + }); + }); + + it('should capture the navigate event on route change', async () => { + const { getByText } = render( + + + + + + {routeObjects.map(({ path, element }) => ( + + ))} + + + , + ); + + fireEvent.click(getByText('go')); + + expect(mockedAnalytics.captureEvent).toHaveBeenCalledWith({ + action: 'navigate', + attributes: { + param: 'hello', + }, + context: { + extension: 'App', + pluginId: 'plugin2', + routeRef: undefined, + }, + subject: '/path2/hello', + value: undefined, + }); + }); + + it('should capture path query and hash', async () => { + render( + + + + + , + ); + + expect(mockedAnalytics.captureEvent).toHaveBeenCalledWith({ + action: 'navigate', + attributes: { + p1: 'foo', + p2: 'bar', + }, + context: { + extension: 'App', + pluginId: 'plugin1', + routeRef: undefined, + }, + subject: '/path/foo/bar?q=1#header-1', + value: undefined, + }); + }); + + it('should match the root path and send relevant context', async () => { + render( + + + + + , + ); + + expect(mockedAnalytics.captureEvent).toHaveBeenCalledWith({ + action: 'navigate', + attributes: {}, + context: { + extension: 'App', + pluginId: 'home', + routeRef: undefined, + }, + subject: '/', + value: undefined, + }); + }); + + it('should return default context when it would have otherwise matched on the root path', async () => { + render( + + + + + Non-extension} + /> + + + , + ); + + expect(mockedAnalytics.captureEvent).toHaveBeenCalledWith({ + action: 'navigate', + attributes: {}, + context: { + extension: 'App', + pluginId: 'root', + routeRef: 'unknown', + }, + subject: '/not-routable-extension', + value: undefined, + }); + }); + + it('should return parent route context on navigating to a sub-route', async () => { + render( + + + + + , + ); + + expect(mockedAnalytics.captureEvent).toHaveBeenCalledWith({ + action: 'navigate', + attributes: { + param: 'param-value', + }, + context: { + extension: 'App', + pluginId: 'plugin2', + routeRef: undefined, + }, + subject: '/path2/param-value/sub-route', + value: undefined, + }); + }); +}); diff --git a/packages/frontend-app-api/src/routing/RouteTracker.tsx b/packages/frontend-app-api/src/routing/RouteTracker.tsx new file mode 100644 index 0000000000..a25a12fae2 --- /dev/null +++ b/packages/frontend-app-api/src/routing/RouteTracker.tsx @@ -0,0 +1,141 @@ +/* + * 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 React, { useEffect } from 'react'; +import { matchRoutes, useLocation } from 'react-router-dom'; +import { RouteRef, BackstagePlugin } from '@backstage/core-plugin-api'; +import { + useAnalytics, + AnalyticsContext, + AnalyticsEventAttributes, +} from '@backstage/core-plugin-api'; +import { BackstageRouteObject } from './types'; + +/** + * Returns an extension context given the current pathname and a list of + * Backstage route objects. + */ +const getExtensionContext = ( + pathname: string, + routes: BackstageRouteObject[], +) => { + try { + // Find matching routes for the given path name. + const matches = matchRoutes(routes, { pathname }); + + // Of the matching routes, get the last (e.g. most specific) instance of + // the BackstageRouteObject that contains a routeRef. Filtering by routeRef + // ensures subRouteRefs are aligned to their parent routes' context. + const routeMatch = matches + ?.filter(match => match?.route.routeRefs?.size > 0) + .pop(); + const routeObject = routeMatch?.route; + + // If there is no route object, then allow inheritance of default context. + if (!routeObject) { + return undefined; + } + + // If the matched route is the root route (no path), and the pathname is + // not the path of the homepage, then inherit from the default context. + if (routeObject.path === '' && pathname !== '/') { + return undefined; + } + + // If there is a single route ref, use it. + let routeRef: RouteRef | undefined; + if (routeObject.routeRefs.size === 1) { + routeRef = routeObject.routeRefs.values().next().value; + } + + // If there is a single plugin, use it. + let plugin: BackstagePlugin | undefined; + if (routeObject.plugins.size === 1) { + plugin = routeObject.plugins.values().next().value; + } + + const params = Object.entries( + routeMatch?.params || {}, + ).reduce((acc, [key, value]) => { + if (value !== undefined && key !== '*') { + acc[key] = value; + } + return acc; + }, {}); + + return { + extension: 'App', + pluginId: plugin?.getId() || 'root', + ...(routeRef ? { routeRef: (routeRef as { id?: string }).id } : {}), + _routeNodeType: routeObject.element as string, + params, + }; + } catch { + return undefined; + } +}; + +/** + * Performs the actual event capture on render. + */ +const TrackNavigation = ({ + pathname, + search, + hash, + attributes, +}: { + pathname: string; + search: string; + hash: string; + attributes?: AnalyticsEventAttributes; +}) => { + const analytics = useAnalytics(); + useEffect(() => { + analytics.captureEvent('navigate', `${pathname}${search}${hash}`, { + attributes, + }); + }, [analytics, pathname, search, hash, attributes]); + + return null; +}; + +/** + * Logs a "navigate" event with appropriate plugin-level analytics context + * attributes each time the user navigates to a page. + */ +export const RouteTracker = ({ + routeObjects, +}: { + routeObjects: BackstageRouteObject[]; +}) => { + const { pathname, search, hash } = useLocation(); + + const { params, ...attributes } = getExtensionContext( + pathname, + routeObjects, + ) || { params: {} }; + + return ( + + + + ); +}; diff --git a/packages/frontend-app-api/src/wiring/createApp.tsx b/packages/frontend-app-api/src/wiring/createApp.tsx index a9400d3ba4..6f5a1592c2 100644 --- a/packages/frontend-app-api/src/wiring/createApp.tsx +++ b/packages/frontend-app-api/src/wiring/createApp.tsx @@ -97,6 +97,7 @@ import { CoreRouter } from '../extensions/CoreRouter'; import { toInternalBackstagePlugin } from '../../../frontend-plugin-api/src/wiring/createPlugin'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports import { toInternalExtensionOverrides } from '../../../frontend-plugin-api/src/wiring/createExtensionOverrides'; +import { RouteTracker } from '../routing/RouteTracker'; const builtinExtensions = [ Core, @@ -342,6 +343,7 @@ export function createSpecializedApp(options?: { + {rootEl} From 6ee84d8fdcaf884d201c23a11f3df48754107151 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Mon, 13 Nov 2023 10:09:56 +0100 Subject: [PATCH 118/261] docs: update api reports Signed-off-by: Camila Belo --- packages/frontend-plugin-api/api-report.md | 55 ++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/packages/frontend-plugin-api/api-report.md b/packages/frontend-plugin-api/api-report.md index c5005d34ac..d4acc4b5b7 100644 --- a/packages/frontend-plugin-api/api-report.md +++ b/packages/frontend-plugin-api/api-report.md @@ -86,6 +86,51 @@ export { alertApiRef }; export { AlertMessage }; +// @public +export type AnalyticsApi = { + captureEvent(event: AnalyticsEvent): void; +}; + +// @public +export const analyticsApiRef: ApiRef; + +// @public +export const AnalyticsContext: (options: { + attributes: Partial; + children: ReactNode; +}) => React_2.JSX.Element; + +// @public +export type AnalyticsContextValue = CommonAnalyticsContext & { + [param in string]: string | boolean | number | undefined; +}; + +// @public +export type AnalyticsEvent = { + action: string; + subject: string; + value?: number; + attributes?: AnalyticsEventAttributes; + context: AnalyticsContextValue; +}; + +// @public +export type AnalyticsEventAttributes = { + [attribute in string]: string | boolean | number; +}; + +// @public +export type AnalyticsTracker = { + captureEvent: ( + action: string, + subject: string, + options?: { + value?: number; + attributes?: AnalyticsEventAttributes; + }, + ) => void; +}; + export { AnyApiFactory }; export { AnyApiRef }; @@ -233,6 +278,13 @@ export { bitbucketAuthApiRef }; export { bitbucketServerAuthApiRef }; +// @public +export type CommonAnalyticsContext = { + pluginId: string; + routeRef: string; + extension: string; +}; + export { ConfigApi }; export { configApiRef }; @@ -770,6 +822,9 @@ export interface SubRouteRef< export { TypesToApiRefs }; +// @public +export function useAnalytics(): AnalyticsTracker; + export { useApi }; export { useApiHolder }; From f27ee7d937a17e135b8ec864dfa87bf44df2538e Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Mon, 13 Nov 2023 09:58:18 +0100 Subject: [PATCH 119/261] docs: add changeset files Signed-off-by: Camila Belo --- .changeset/pretty-ravens-serve.md | 5 +++++ .changeset/smooth-frogs-decide.md | 5 +++++ 2 files changed, 10 insertions(+) create mode 100644 .changeset/pretty-ravens-serve.md create mode 100644 .changeset/smooth-frogs-decide.md diff --git a/.changeset/pretty-ravens-serve.md b/.changeset/pretty-ravens-serve.md new file mode 100644 index 0000000000..95d1b629fd --- /dev/null +++ b/.changeset/pretty-ravens-serve.md @@ -0,0 +1,5 @@ +--- +'@backstage/frontend-app-api': patch +--- + +Migrate analytics route tracker component. diff --git a/.changeset/smooth-frogs-decide.md b/.changeset/smooth-frogs-decide.md new file mode 100644 index 0000000000..942a3a80bf --- /dev/null +++ b/.changeset/smooth-frogs-decide.md @@ -0,0 +1,5 @@ +--- +'@backstage/frontend-plugin-api': patch +--- + +Migrate analytics api and context files. From 3a3c3b8206de63debcd3a23ab7fc7223499e14c5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 27 Nov 2023 09:38:36 +0000 Subject: [PATCH 120/261] chore(deps): update dependency esbuild to v0.19.8 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 182 +++++++++++++++++++++++++++--------------------------- 1 file changed, 91 insertions(+), 91 deletions(-) diff --git a/yarn.lock b/yarn.lock index 2b6c46008f..92d0468880 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10878,9 +10878,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/android-arm64@npm:0.19.7": - version: 0.19.7 - resolution: "@esbuild/android-arm64@npm:0.19.7" +"@esbuild/android-arm64@npm:0.19.8": + version: 0.19.8 + resolution: "@esbuild/android-arm64@npm:0.19.8" conditions: os=android & cpu=arm64 languageName: node linkType: hard @@ -10899,9 +10899,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/android-arm@npm:0.19.7": - version: 0.19.7 - resolution: "@esbuild/android-arm@npm:0.19.7" +"@esbuild/android-arm@npm:0.19.8": + version: 0.19.8 + resolution: "@esbuild/android-arm@npm:0.19.8" conditions: os=android & cpu=arm languageName: node linkType: hard @@ -10920,9 +10920,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/android-x64@npm:0.19.7": - version: 0.19.7 - resolution: "@esbuild/android-x64@npm:0.19.7" +"@esbuild/android-x64@npm:0.19.8": + version: 0.19.8 + resolution: "@esbuild/android-x64@npm:0.19.8" conditions: os=android & cpu=x64 languageName: node linkType: hard @@ -10941,9 +10941,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/darwin-arm64@npm:0.19.7": - version: 0.19.7 - resolution: "@esbuild/darwin-arm64@npm:0.19.7" +"@esbuild/darwin-arm64@npm:0.19.8": + version: 0.19.8 + resolution: "@esbuild/darwin-arm64@npm:0.19.8" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard @@ -10962,9 +10962,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/darwin-x64@npm:0.19.7": - version: 0.19.7 - resolution: "@esbuild/darwin-x64@npm:0.19.7" +"@esbuild/darwin-x64@npm:0.19.8": + version: 0.19.8 + resolution: "@esbuild/darwin-x64@npm:0.19.8" conditions: os=darwin & cpu=x64 languageName: node linkType: hard @@ -10983,9 +10983,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/freebsd-arm64@npm:0.19.7": - version: 0.19.7 - resolution: "@esbuild/freebsd-arm64@npm:0.19.7" +"@esbuild/freebsd-arm64@npm:0.19.8": + version: 0.19.8 + resolution: "@esbuild/freebsd-arm64@npm:0.19.8" conditions: os=freebsd & cpu=arm64 languageName: node linkType: hard @@ -11004,9 +11004,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/freebsd-x64@npm:0.19.7": - version: 0.19.7 - resolution: "@esbuild/freebsd-x64@npm:0.19.7" +"@esbuild/freebsd-x64@npm:0.19.8": + version: 0.19.8 + resolution: "@esbuild/freebsd-x64@npm:0.19.8" conditions: os=freebsd & cpu=x64 languageName: node linkType: hard @@ -11025,9 +11025,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-arm64@npm:0.19.7": - version: 0.19.7 - resolution: "@esbuild/linux-arm64@npm:0.19.7" +"@esbuild/linux-arm64@npm:0.19.8": + version: 0.19.8 + resolution: "@esbuild/linux-arm64@npm:0.19.8" conditions: os=linux & cpu=arm64 languageName: node linkType: hard @@ -11046,9 +11046,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-arm@npm:0.19.7": - version: 0.19.7 - resolution: "@esbuild/linux-arm@npm:0.19.7" +"@esbuild/linux-arm@npm:0.19.8": + version: 0.19.8 + resolution: "@esbuild/linux-arm@npm:0.19.8" conditions: os=linux & cpu=arm languageName: node linkType: hard @@ -11067,9 +11067,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-ia32@npm:0.19.7": - version: 0.19.7 - resolution: "@esbuild/linux-ia32@npm:0.19.7" +"@esbuild/linux-ia32@npm:0.19.8": + version: 0.19.8 + resolution: "@esbuild/linux-ia32@npm:0.19.8" conditions: os=linux & cpu=ia32 languageName: node linkType: hard @@ -11088,9 +11088,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-loong64@npm:0.19.7": - version: 0.19.7 - resolution: "@esbuild/linux-loong64@npm:0.19.7" +"@esbuild/linux-loong64@npm:0.19.8": + version: 0.19.8 + resolution: "@esbuild/linux-loong64@npm:0.19.8" conditions: os=linux & cpu=loong64 languageName: node linkType: hard @@ -11109,9 +11109,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-mips64el@npm:0.19.7": - version: 0.19.7 - resolution: "@esbuild/linux-mips64el@npm:0.19.7" +"@esbuild/linux-mips64el@npm:0.19.8": + version: 0.19.8 + resolution: "@esbuild/linux-mips64el@npm:0.19.8" conditions: os=linux & cpu=mips64el languageName: node linkType: hard @@ -11130,9 +11130,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-ppc64@npm:0.19.7": - version: 0.19.7 - resolution: "@esbuild/linux-ppc64@npm:0.19.7" +"@esbuild/linux-ppc64@npm:0.19.8": + version: 0.19.8 + resolution: "@esbuild/linux-ppc64@npm:0.19.8" conditions: os=linux & cpu=ppc64 languageName: node linkType: hard @@ -11151,9 +11151,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-riscv64@npm:0.19.7": - version: 0.19.7 - resolution: "@esbuild/linux-riscv64@npm:0.19.7" +"@esbuild/linux-riscv64@npm:0.19.8": + version: 0.19.8 + resolution: "@esbuild/linux-riscv64@npm:0.19.8" conditions: os=linux & cpu=riscv64 languageName: node linkType: hard @@ -11172,9 +11172,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-s390x@npm:0.19.7": - version: 0.19.7 - resolution: "@esbuild/linux-s390x@npm:0.19.7" +"@esbuild/linux-s390x@npm:0.19.8": + version: 0.19.8 + resolution: "@esbuild/linux-s390x@npm:0.19.8" conditions: os=linux & cpu=s390x languageName: node linkType: hard @@ -11193,9 +11193,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-x64@npm:0.19.7": - version: 0.19.7 - resolution: "@esbuild/linux-x64@npm:0.19.7" +"@esbuild/linux-x64@npm:0.19.8": + version: 0.19.8 + resolution: "@esbuild/linux-x64@npm:0.19.8" conditions: os=linux & cpu=x64 languageName: node linkType: hard @@ -11214,9 +11214,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/netbsd-x64@npm:0.19.7": - version: 0.19.7 - resolution: "@esbuild/netbsd-x64@npm:0.19.7" +"@esbuild/netbsd-x64@npm:0.19.8": + version: 0.19.8 + resolution: "@esbuild/netbsd-x64@npm:0.19.8" conditions: os=netbsd & cpu=x64 languageName: node linkType: hard @@ -11235,9 +11235,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/openbsd-x64@npm:0.19.7": - version: 0.19.7 - resolution: "@esbuild/openbsd-x64@npm:0.19.7" +"@esbuild/openbsd-x64@npm:0.19.8": + version: 0.19.8 + resolution: "@esbuild/openbsd-x64@npm:0.19.8" conditions: os=openbsd & cpu=x64 languageName: node linkType: hard @@ -11256,9 +11256,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/sunos-x64@npm:0.19.7": - version: 0.19.7 - resolution: "@esbuild/sunos-x64@npm:0.19.7" +"@esbuild/sunos-x64@npm:0.19.8": + version: 0.19.8 + resolution: "@esbuild/sunos-x64@npm:0.19.8" conditions: os=sunos & cpu=x64 languageName: node linkType: hard @@ -11277,9 +11277,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/win32-arm64@npm:0.19.7": - version: 0.19.7 - resolution: "@esbuild/win32-arm64@npm:0.19.7" +"@esbuild/win32-arm64@npm:0.19.8": + version: 0.19.8 + resolution: "@esbuild/win32-arm64@npm:0.19.8" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard @@ -11298,9 +11298,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/win32-ia32@npm:0.19.7": - version: 0.19.7 - resolution: "@esbuild/win32-ia32@npm:0.19.7" +"@esbuild/win32-ia32@npm:0.19.8": + version: 0.19.8 + resolution: "@esbuild/win32-ia32@npm:0.19.8" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard @@ -11319,9 +11319,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/win32-x64@npm:0.19.7": - version: 0.19.7 - resolution: "@esbuild/win32-x64@npm:0.19.7" +"@esbuild/win32-x64@npm:0.19.8": + version: 0.19.8 + resolution: "@esbuild/win32-x64@npm:0.19.8" conditions: os=win32 & cpu=x64 languageName: node linkType: hard @@ -25858,31 +25858,31 @@ __metadata: linkType: hard "esbuild@npm:^0.19.0": - version: 0.19.7 - resolution: "esbuild@npm:0.19.7" + version: 0.19.8 + resolution: "esbuild@npm:0.19.8" dependencies: - "@esbuild/android-arm": 0.19.7 - "@esbuild/android-arm64": 0.19.7 - "@esbuild/android-x64": 0.19.7 - "@esbuild/darwin-arm64": 0.19.7 - "@esbuild/darwin-x64": 0.19.7 - "@esbuild/freebsd-arm64": 0.19.7 - "@esbuild/freebsd-x64": 0.19.7 - "@esbuild/linux-arm": 0.19.7 - "@esbuild/linux-arm64": 0.19.7 - "@esbuild/linux-ia32": 0.19.7 - "@esbuild/linux-loong64": 0.19.7 - "@esbuild/linux-mips64el": 0.19.7 - "@esbuild/linux-ppc64": 0.19.7 - "@esbuild/linux-riscv64": 0.19.7 - "@esbuild/linux-s390x": 0.19.7 - "@esbuild/linux-x64": 0.19.7 - "@esbuild/netbsd-x64": 0.19.7 - "@esbuild/openbsd-x64": 0.19.7 - "@esbuild/sunos-x64": 0.19.7 - "@esbuild/win32-arm64": 0.19.7 - "@esbuild/win32-ia32": 0.19.7 - "@esbuild/win32-x64": 0.19.7 + "@esbuild/android-arm": 0.19.8 + "@esbuild/android-arm64": 0.19.8 + "@esbuild/android-x64": 0.19.8 + "@esbuild/darwin-arm64": 0.19.8 + "@esbuild/darwin-x64": 0.19.8 + "@esbuild/freebsd-arm64": 0.19.8 + "@esbuild/freebsd-x64": 0.19.8 + "@esbuild/linux-arm": 0.19.8 + "@esbuild/linux-arm64": 0.19.8 + "@esbuild/linux-ia32": 0.19.8 + "@esbuild/linux-loong64": 0.19.8 + "@esbuild/linux-mips64el": 0.19.8 + "@esbuild/linux-ppc64": 0.19.8 + "@esbuild/linux-riscv64": 0.19.8 + "@esbuild/linux-s390x": 0.19.8 + "@esbuild/linux-x64": 0.19.8 + "@esbuild/netbsd-x64": 0.19.8 + "@esbuild/openbsd-x64": 0.19.8 + "@esbuild/sunos-x64": 0.19.8 + "@esbuild/win32-arm64": 0.19.8 + "@esbuild/win32-ia32": 0.19.8 + "@esbuild/win32-x64": 0.19.8 dependenciesMeta: "@esbuild/android-arm": optional: true @@ -25930,7 +25930,7 @@ __metadata: optional: true bin: esbuild: bin/esbuild - checksum: a5d979224d47ae0cc6685447eb8f1ceaf7b67f5eaeaac0246f4d589ff7d81b08e4502a6245298d948f13e9b571ac8556a6d83b084af24954f762b1cfe59dbe55 + checksum: 1dff99482ecbfcc642ec66c71e4dc5c73ce6aef68e8158a4937890b570e86a95959ac47e0f14785ba70df5a673ae4289df88a162e9759b02367ed28074cee8ba languageName: node linkType: hard From 33e96e59e73ec01dc3b33258df19156f5aa98d98 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 27 Nov 2023 11:23:17 +0100 Subject: [PATCH 121/261] cli: switch ts-eslint plugin backe to ^ range Signed-off-by: Patrik Oldsberg --- .changeset/strange-suits-glow.md | 5 +++++ packages/cli/package.json | 2 +- yarn.lock | 4 ++-- 3 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 .changeset/strange-suits-glow.md diff --git a/.changeset/strange-suits-glow.md b/.changeset/strange-suits-glow.md new file mode 100644 index 0000000000..6f1ba31127 --- /dev/null +++ b/.changeset/strange-suits-glow.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Switched the `@typescript-eslint/eslint-plugin` dependency back to using a `^` version range. diff --git a/packages/cli/package.json b/packages/cli/package.json index cb7d4d9697..40880607e5 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -64,7 +64,7 @@ "@swc/jest": "^0.2.22", "@types/jest": "^29.0.0", "@types/webpack-env": "^1.15.2", - "@typescript-eslint/eslint-plugin": "6.12.0", + "@typescript-eslint/eslint-plugin": "^6.12.0", "@typescript-eslint/parser": "^6.7.2", "@yarnpkg/lockfile": "^1.1.0", "@yarnpkg/parsers": "^3.0.0-rc.4", diff --git a/yarn.lock b/yarn.lock index 7bb12c03db..3df09f3795 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3637,7 +3637,7 @@ __metadata: "@types/terser-webpack-plugin": ^5.0.4 "@types/webpack-env": ^1.15.2 "@types/yarnpkg__lockfile": ^1.1.4 - "@typescript-eslint/eslint-plugin": 6.12.0 + "@typescript-eslint/eslint-plugin": ^6.12.0 "@typescript-eslint/parser": ^6.7.2 "@yarnpkg/lockfile": ^1.1.0 "@yarnpkg/parsers": ^3.0.0-rc.4 @@ -19454,7 +19454,7 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/eslint-plugin@npm:6.12.0": +"@typescript-eslint/eslint-plugin@npm:^6.12.0": version: 6.12.0 resolution: "@typescript-eslint/eslint-plugin@npm:6.12.0" dependencies: From 67d63b3dbc3a16f8c0456aba4eb59839fc142554 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 27 Nov 2023 11:25:26 +0100 Subject: [PATCH 122/261] changesets: clean up tricky donkeys Signed-off-by: Patrik Oldsberg --- .changeset/tricky-donkeys-do.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/tricky-donkeys-do.md b/.changeset/tricky-donkeys-do.md index 573aa53135..1a810e9f3b 100644 --- a/.changeset/tricky-donkeys-do.md +++ b/.changeset/tricky-donkeys-do.md @@ -2,4 +2,4 @@ '@techdocs/cli': minor --- -support passing additional mkdocs-server CLI parameters (--dirtyreload, --strict and --clean) when run in containerized mode +Support passing additional `mkdocs-server` CLI parameters (`--dirtyreload`, `--strict` and `--clean`) when run in containerized mode. From 01e8ffe57b186d54a0946eb651087deff67b51c3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 27 Nov 2023 11:09:16 +0000 Subject: [PATCH 123/261] fix(deps): update codemirror to v6.9.3 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/yarn.lock b/yarn.lock index 3df09f3795..050fdff3e8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10509,8 +10509,8 @@ __metadata: linkType: hard "@codemirror/language@npm:^6.0.0": - version: 6.9.2 - resolution: "@codemirror/language@npm:6.9.2" + version: 6.9.3 + resolution: "@codemirror/language@npm:6.9.3" dependencies: "@codemirror/state": ^6.0.0 "@codemirror/view": ^6.0.0 @@ -10518,7 +10518,7 @@ __metadata: "@lezer/highlight": ^1.0.0 "@lezer/lr": ^1.0.0 style-mod: ^4.0.0 - checksum: eee7b861b5591114cac7502cd532d5b923639740081a4cd7e28696c252af8d759b14686aaf6d5eee7e0969ff647b7aaf03a5eea7235fb6d9858ee19433f1c74d + checksum: 774a40bc91c748d418a9a774161a5b083061124e4439bb753072bc657ec4c4784f595161c10c7c3935154b22291bf6dc74c9abe827033db32e217ac3963478f3 languageName: node linkType: hard @@ -10573,13 +10573,13 @@ __metadata: linkType: hard "@codemirror/view@npm:^6.0.0": - version: 6.22.0 - resolution: "@codemirror/view@npm:6.22.0" + version: 6.22.1 + resolution: "@codemirror/view@npm:6.22.1" dependencies: "@codemirror/state": ^6.1.4 style-mod: ^4.1.0 w3c-keyname: ^2.2.4 - checksum: 2a24674687fbde06898d0a131abe5f86a812d79e111cf8dc94110dac86eed8c20a2094b547c1b3c379fe8edf0c66318d03a7594158e4f6628ee060a03a5d1bab + checksum: 8643d86cf8c34433a410b28b1339c9a333c519e815890bf6494ca35a47d6ed38b51a13480cf4f6bea319ab2a17991e1ba47cd1b4a2c5a99fb76bad014682925a languageName: node linkType: hard From 5410722f866c0dbaa646b18bba7faf33cedb96f0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 27 Nov 2023 11:09:45 +0000 Subject: [PATCH 124/261] fix(deps): update dependency @uiw/react-codemirror to v4.21.21 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/yarn.lock b/yarn.lock index 3df09f3795..a3fad57271 100644 --- a/yarn.lock +++ b/yarn.lock @@ -19639,9 +19639,9 @@ __metadata: languageName: node linkType: hard -"@uiw/codemirror-extensions-basic-setup@npm:4.21.20": - version: 4.21.20 - resolution: "@uiw/codemirror-extensions-basic-setup@npm:4.21.20" +"@uiw/codemirror-extensions-basic-setup@npm:4.21.21": + version: 4.21.21 + resolution: "@uiw/codemirror-extensions-basic-setup@npm:4.21.21" dependencies: "@codemirror/autocomplete": ^6.0.0 "@codemirror/commands": ^6.0.0 @@ -19658,19 +19658,19 @@ __metadata: "@codemirror/search": ">=6.0.0" "@codemirror/state": ">=6.0.0" "@codemirror/view": ">=6.0.0" - checksum: 76a6caf05bbcf06c515c680ab952e79b8470ca10c9d8c3166fdb05310232239782b170da276b1dbf33900ca894332fc2aba3bd6955665b2c2580548c7e17cbc0 + checksum: 5d96ec930be286b5e324ee8dd57128171c72a8e333b4b991a5c4f33a05420a638def3776bd1a77c5b88184f7d3cbc6828b5c9a42b3b490f51908bedf69eaa0f0 languageName: node linkType: hard "@uiw/react-codemirror@npm:^4.9.3": - version: 4.21.20 - resolution: "@uiw/react-codemirror@npm:4.21.20" + version: 4.21.21 + resolution: "@uiw/react-codemirror@npm:4.21.21" dependencies: "@babel/runtime": ^7.18.6 "@codemirror/commands": ^6.1.0 "@codemirror/state": ^6.1.1 "@codemirror/theme-one-dark": ^6.0.0 - "@uiw/codemirror-extensions-basic-setup": 4.21.20 + "@uiw/codemirror-extensions-basic-setup": 4.21.21 codemirror: ^6.0.0 peerDependencies: "@babel/runtime": ">=7.11.0" @@ -19680,7 +19680,7 @@ __metadata: codemirror: ">=6.0.0" react: ">=16.8.0" react-dom: ">=16.8.0" - checksum: 63ea348a922c535ff91c8bff1c1dac40ced0227d1c17139142dbc28017bb254cc32428a15686660ec4f4cd6935c574d627b6a4872910357af51da8e90faaf4da + checksum: 6a8500290bf0a739fd345221465b10112e0f758914bc8aa28ce0b9904b76489ae018d390f6a2d7dd7752b21f0ed87ba3fedb45b4185d04e4985abf0eb22e6d75 languageName: node linkType: hard From 17955ad4c74261320eff790cb6ba5b539190f73c Mon Sep 17 00:00:00 2001 From: Tiago Barbosa Date: Mon, 27 Nov 2023 11:13:33 +0000 Subject: [PATCH 125/261] refactor(pagerduty plugin): :wastebasket: adding deprecating annotations on Cards and Types exposed by the plugin adding deprecating annotations on Cards and Types exposed by the plugin Signed-off-by: Tiago Barbosa --- plugins/pagerduty/src/plugin.ts | 15 ++++++++++++--- plugins/pagerduty/src/types.ts | 5 ++++- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/plugins/pagerduty/src/plugin.ts b/plugins/pagerduty/src/plugin.ts index 59cc5cd8cc..22f8ae60ee 100644 --- a/plugins/pagerduty/src/plugin.ts +++ b/plugins/pagerduty/src/plugin.ts @@ -30,7 +30,10 @@ export const rootRouteRef = createRouteRef({ id: 'pagerduty', }); -/** @public */ +/** + * @public + * @deprecated This plugin will be removed in a future release. Please use @pagerduty/backstage-plugin plugin instead (https://www.npmjs.com/package/@pagerduty/backstage-plugin). + */ export const pagerDutyPlugin = createPlugin({ id: 'pagerduty', apis: [ @@ -47,7 +50,10 @@ export const pagerDutyPlugin = createPlugin({ ], }); -/** @public */ +/** + * @public + * @deprecated This plugin and it's cards will be removed in a future release. Please use @pagerduty/backstage-plugin plugin instead (https://www.npmjs.com/package/@pagerduty/backstage-plugin). + */ export const EntityPagerDutyCard = pagerDutyPlugin.provide( createComponentExtension({ name: 'EntityPagerDutyCard', @@ -60,7 +66,10 @@ export const EntityPagerDutyCard = pagerDutyPlugin.provide( }), ); -/** @public */ +/** + * @public + * @deprecated This plugin and it's cards will be removed in a future release. Please use @pagerduty/backstage-plugin plugin instead (https://www.npmjs.com/package/@pagerduty/backstage-plugin). + */ export const HomePagePagerDutyCard = pagerDutyPlugin.provide( createCardExtension({ name: 'HomePagePagerDutyCard', diff --git a/plugins/pagerduty/src/types.ts b/plugins/pagerduty/src/types.ts index 9f38b429ef..3ecfb4e745 100644 --- a/plugins/pagerduty/src/types.ts +++ b/plugins/pagerduty/src/types.ts @@ -14,7 +14,10 @@ * limitations under the License. */ -/** @public */ +/** + * @public + * @deprecated This plugin and it's types will be removed in a future release. Please use @pagerduty/backstage-plugin plugin instead (https://www.npmjs.com/package/@pagerduty/backstage-plugin). + */ export type PagerDutyEntity = { integrationKey?: string; serviceId?: string; From 404fcb7f51c1f3328de1bd114078d61b2a511ff0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 27 Nov 2023 12:07:46 +0000 Subject: [PATCH 126/261] fix(deps): update aws-sdk-js-v3 monorepo to v3.458.0 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 138 +++++++++++++++++++++++++++--------------------------- 1 file changed, 69 insertions(+), 69 deletions(-) diff --git a/yarn.lock b/yarn.lock index 3df09f3795..6b043a52f9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -397,15 +397,15 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/client-cognito-identity@npm:3.454.0": - version: 3.454.0 - resolution: "@aws-sdk/client-cognito-identity@npm:3.454.0" +"@aws-sdk/client-cognito-identity@npm:3.458.0": + version: 3.458.0 + resolution: "@aws-sdk/client-cognito-identity@npm:3.458.0" dependencies: "@aws-crypto/sha256-browser": 3.0.0 "@aws-crypto/sha256-js": 3.0.0 - "@aws-sdk/client-sts": 3.454.0 + "@aws-sdk/client-sts": 3.458.0 "@aws-sdk/core": 3.451.0 - "@aws-sdk/credential-provider-node": 3.451.0 + "@aws-sdk/credential-provider-node": 3.458.0 "@aws-sdk/middleware-host-header": 3.451.0 "@aws-sdk/middleware-logger": 3.451.0 "@aws-sdk/middleware-recursion-detection": 3.451.0 @@ -440,19 +440,19 @@ __metadata: "@smithy/util-retry": ^2.0.6 "@smithy/util-utf8": ^2.0.2 tslib: ^2.5.0 - checksum: 277d664aeaaf3b053949ca96d26c09d4bafc3afbd93a35bbd3a9b9b05c742e82fcc2398b1c63422de049ddbf45b80272427f444721b3e72435ffa40cf7519942 + checksum: 2376be696bfabf2ebb1d868af8bbd9d49a0a8962ec0d49b8adb156b9c45313db066af4339967d3d572d0ccc55b3a1a993665ffc7627c5b0a2f4639ab352f27cd languageName: node linkType: hard "@aws-sdk/client-eks@npm:^3.350.0": - version: 3.454.0 - resolution: "@aws-sdk/client-eks@npm:3.454.0" + version: 3.458.0 + resolution: "@aws-sdk/client-eks@npm:3.458.0" dependencies: "@aws-crypto/sha256-browser": 3.0.0 "@aws-crypto/sha256-js": 3.0.0 - "@aws-sdk/client-sts": 3.454.0 + "@aws-sdk/client-sts": 3.458.0 "@aws-sdk/core": 3.451.0 - "@aws-sdk/credential-provider-node": 3.451.0 + "@aws-sdk/credential-provider-node": 3.458.0 "@aws-sdk/middleware-host-header": 3.451.0 "@aws-sdk/middleware-logger": 3.451.0 "@aws-sdk/middleware-recursion-detection": 3.451.0 @@ -489,19 +489,19 @@ __metadata: "@smithy/util-waiter": ^2.0.13 tslib: ^2.5.0 uuid: ^8.3.2 - checksum: 5a7cf06e2f516ef9dfff82d4097144fcf1b5477dd1277b9ebba22f38fa8108c029fc7c89e62f420daf51c575e52ed6f97c38b64a81770d9f26b367a5f212a446 + checksum: 7bbafbab55c92633f19d6e53abc9e3d76f36533b68eee7c367c21c8ca72e43e7a4bae4bc33a102228bdc773d0d6fb8633855bc2034c3cbf539befe6d4c30996c languageName: node linkType: hard "@aws-sdk/client-organizations@npm:^3.350.0": - version: 3.454.0 - resolution: "@aws-sdk/client-organizations@npm:3.454.0" + version: 3.458.0 + resolution: "@aws-sdk/client-organizations@npm:3.458.0" dependencies: "@aws-crypto/sha256-browser": 3.0.0 "@aws-crypto/sha256-js": 3.0.0 - "@aws-sdk/client-sts": 3.454.0 + "@aws-sdk/client-sts": 3.458.0 "@aws-sdk/core": 3.451.0 - "@aws-sdk/credential-provider-node": 3.451.0 + "@aws-sdk/credential-provider-node": 3.458.0 "@aws-sdk/middleware-host-header": 3.451.0 "@aws-sdk/middleware-logger": 3.451.0 "@aws-sdk/middleware-recursion-detection": 3.451.0 @@ -536,20 +536,20 @@ __metadata: "@smithy/util-retry": ^2.0.6 "@smithy/util-utf8": ^2.0.2 tslib: ^2.5.0 - checksum: 66c4cf0f6eb8eccd61852b6231704aac6561f2a20a6232dc50c5988c7699f3a6bc878e3fb30daeb63e53201c807efe37316746e4a0e40e7df5b633f66a7612e1 + checksum: 396453eb2a76c4a99d2250f43acc32f7db73bf19ff6f7580da6756f0beaaff01b9b94dc2dfb3aa60c244cedcf61901b7339d29a5a4b2e3615006d7a62b510be2 languageName: node linkType: hard "@aws-sdk/client-s3@npm:^3.350.0": - version: 3.456.0 - resolution: "@aws-sdk/client-s3@npm:3.456.0" + version: 3.458.0 + resolution: "@aws-sdk/client-s3@npm:3.458.0" dependencies: "@aws-crypto/sha1-browser": 3.0.0 "@aws-crypto/sha256-browser": 3.0.0 "@aws-crypto/sha256-js": 3.0.0 - "@aws-sdk/client-sts": 3.454.0 + "@aws-sdk/client-sts": 3.458.0 "@aws-sdk/core": 3.451.0 - "@aws-sdk/credential-provider-node": 3.451.0 + "@aws-sdk/credential-provider-node": 3.458.0 "@aws-sdk/middleware-bucket-endpoint": 3.451.0 "@aws-sdk/middleware-expect-continue": 3.451.0 "@aws-sdk/middleware-flexible-checksums": 3.451.0 @@ -601,19 +601,19 @@ __metadata: "@smithy/util-waiter": ^2.0.13 fast-xml-parser: 4.2.5 tslib: ^2.5.0 - checksum: e77542547c7f30c39380fa8558d9917f2d989583b66ed9ee9200108e96bf675b72136f4f8985c299867f0414b44203c4d51b10f8243079eaff519666c58dbbb4 + checksum: 7b4ec3928262688224bc2ca68a5319e888847d9657cf12fef15cd579e266f8d0c03d6965e482f2b528ad3e1e93b5495c9dd45b064c9e35151615deac74608cd7 languageName: node linkType: hard "@aws-sdk/client-sqs@npm:^3.350.0": - version: 3.454.0 - resolution: "@aws-sdk/client-sqs@npm:3.454.0" + version: 3.458.0 + resolution: "@aws-sdk/client-sqs@npm:3.458.0" dependencies: "@aws-crypto/sha256-browser": 3.0.0 "@aws-crypto/sha256-js": 3.0.0 - "@aws-sdk/client-sts": 3.454.0 + "@aws-sdk/client-sts": 3.458.0 "@aws-sdk/core": 3.451.0 - "@aws-sdk/credential-provider-node": 3.451.0 + "@aws-sdk/credential-provider-node": 3.458.0 "@aws-sdk/middleware-host-header": 3.451.0 "@aws-sdk/middleware-logger": 3.451.0 "@aws-sdk/middleware-recursion-detection": 3.451.0 @@ -650,13 +650,13 @@ __metadata: "@smithy/util-retry": ^2.0.6 "@smithy/util-utf8": ^2.0.2 tslib: ^2.5.0 - checksum: 4851ddbd509982a9185a2e7e20f52e326ce84c94a42f26368c2e18bd77d29a3e16c832b6308ab126adc5fd5f6b53c9d556cdf5e1aa2bb81bed5c8651d70e6377 + checksum: 7352d83ea0ac3d846911e20329f8817efb42a38391a7f627331be6b42e6fed41cbbaa800e3177c4ab850faae25a435d3da864b100a587ab515da115899f4b2e4 languageName: node linkType: hard -"@aws-sdk/client-sso@npm:3.451.0": - version: 3.451.0 - resolution: "@aws-sdk/client-sso@npm:3.451.0" +"@aws-sdk/client-sso@npm:3.458.0": + version: 3.458.0 + resolution: "@aws-sdk/client-sso@npm:3.458.0" dependencies: "@aws-crypto/sha256-browser": 3.0.0 "@aws-crypto/sha256-js": 3.0.0 @@ -694,18 +694,18 @@ __metadata: "@smithy/util-retry": ^2.0.6 "@smithy/util-utf8": ^2.0.2 tslib: ^2.5.0 - checksum: 5ab78bf7704acad673eb2f97b7c9873e4e045e8476f827fc5f6e6f46ca37674f04efc1e168cdc4b3b0c5be1e6ada8e1a76fb4963a7af48560423a60b855f6005 + checksum: fd10ceb68526320f7302c206901f432fd7e09a7c65301f05b3e4c6d36764a7241f2984e2fb7c95cbece0d2e9a65aaa672121b1847cf368cc4c7fa0e5c1805bba languageName: node linkType: hard -"@aws-sdk/client-sts@npm:3.454.0, @aws-sdk/client-sts@npm:^3.350.0": - version: 3.454.0 - resolution: "@aws-sdk/client-sts@npm:3.454.0" +"@aws-sdk/client-sts@npm:3.458.0, @aws-sdk/client-sts@npm:^3.350.0": + version: 3.458.0 + resolution: "@aws-sdk/client-sts@npm:3.458.0" dependencies: "@aws-crypto/sha256-browser": 3.0.0 "@aws-crypto/sha256-js": 3.0.0 "@aws-sdk/core": 3.451.0 - "@aws-sdk/credential-provider-node": 3.451.0 + "@aws-sdk/credential-provider-node": 3.458.0 "@aws-sdk/middleware-host-header": 3.451.0 "@aws-sdk/middleware-logger": 3.451.0 "@aws-sdk/middleware-recursion-detection": 3.451.0 @@ -742,7 +742,7 @@ __metadata: "@smithy/util-utf8": ^2.0.2 fast-xml-parser: 4.2.5 tslib: ^2.5.0 - checksum: 92e687abc8dcd5f6ddf911fe5800f04eeb11164214327072334275b04725ac77ee2170247b69df645ff756ed9f2b27916921d442fb393dc46084c114b5f76f54 + checksum: 167a07c100103ef12e74c83be1dd115f583843308e1f3430eec030b2932edecfb665df2158c9131f7eeb0df41e665b7419a443e8689b1aa732bc5a413a0b4fad languageName: node linkType: hard @@ -756,16 +756,16 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/credential-provider-cognito-identity@npm:3.454.0": - version: 3.454.0 - resolution: "@aws-sdk/credential-provider-cognito-identity@npm:3.454.0" +"@aws-sdk/credential-provider-cognito-identity@npm:3.458.0": + version: 3.458.0 + resolution: "@aws-sdk/credential-provider-cognito-identity@npm:3.458.0" dependencies: - "@aws-sdk/client-cognito-identity": 3.454.0 + "@aws-sdk/client-cognito-identity": 3.458.0 "@aws-sdk/types": 3.451.0 "@smithy/property-provider": ^2.0.0 "@smithy/types": ^2.5.0 tslib: ^2.5.0 - checksum: 4291033f9554ecd83f6a6dffc3309fa0da212dc9c3d197438abc77ed006a3622e9b81fe070305e5038f3ed15eb2a276306d8a040bea7a02d5591d66452e1c460 + checksum: a2e59ac5743913eb828ca520c7dd972994c9a9f5e63a1f5df49deba1264acffbe35dc6418dd03198dd1bc888855666c7646d9811694bc4aa00fd12984b2ec55e languageName: node linkType: hard @@ -798,13 +798,13 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/credential-provider-ini@npm:3.451.0": - version: 3.451.0 - resolution: "@aws-sdk/credential-provider-ini@npm:3.451.0" +"@aws-sdk/credential-provider-ini@npm:3.458.0": + version: 3.458.0 + resolution: "@aws-sdk/credential-provider-ini@npm:3.458.0" dependencies: "@aws-sdk/credential-provider-env": 3.451.0 "@aws-sdk/credential-provider-process": 3.451.0 - "@aws-sdk/credential-provider-sso": 3.451.0 + "@aws-sdk/credential-provider-sso": 3.458.0 "@aws-sdk/credential-provider-web-identity": 3.451.0 "@aws-sdk/types": 3.451.0 "@smithy/credential-provider-imds": ^2.0.0 @@ -812,18 +812,18 @@ __metadata: "@smithy/shared-ini-file-loader": ^2.0.6 "@smithy/types": ^2.5.0 tslib: ^2.5.0 - checksum: 6d549724209f24c2e21fa88f318c7faaa9e2e58c854fcabc257b71cd2e6f849d38eaa932e16b44bf56c420183fd4ae804ac44c7584808af868ae7316fde2c3b1 + checksum: 23d4d9e5007a3b6214a027cc7a64f50879bdecf3702d799157f586427c9862cbde166512e52aa86e6306ab12058f06178d268d4ef8cc40aedf822d6d4d90e901 languageName: node linkType: hard -"@aws-sdk/credential-provider-node@npm:3.451.0, @aws-sdk/credential-provider-node@npm:^3.350.0": - version: 3.451.0 - resolution: "@aws-sdk/credential-provider-node@npm:3.451.0" +"@aws-sdk/credential-provider-node@npm:3.458.0, @aws-sdk/credential-provider-node@npm:^3.350.0": + version: 3.458.0 + resolution: "@aws-sdk/credential-provider-node@npm:3.458.0" dependencies: "@aws-sdk/credential-provider-env": 3.451.0 - "@aws-sdk/credential-provider-ini": 3.451.0 + "@aws-sdk/credential-provider-ini": 3.458.0 "@aws-sdk/credential-provider-process": 3.451.0 - "@aws-sdk/credential-provider-sso": 3.451.0 + "@aws-sdk/credential-provider-sso": 3.458.0 "@aws-sdk/credential-provider-web-identity": 3.451.0 "@aws-sdk/types": 3.451.0 "@smithy/credential-provider-imds": ^2.0.0 @@ -831,7 +831,7 @@ __metadata: "@smithy/shared-ini-file-loader": ^2.0.6 "@smithy/types": ^2.5.0 tslib: ^2.5.0 - checksum: 19dd93776250fd4e55a70daaca311f1f0bb27e5b195713e3f9d8e8431411e637c917a46bbd41dcf2044a93e0fdea02ebb238863f8c49684bf3e63aff928b5a6b + checksum: 94dad3e9df77e565bb689a76e819e7250e0d4698e49452d761664444347da41816305f77d03464a1f1b447cdb5078269a4b350a896244a769958f792f1a5d040 languageName: node linkType: hard @@ -848,18 +848,18 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/credential-provider-sso@npm:3.451.0": - version: 3.451.0 - resolution: "@aws-sdk/credential-provider-sso@npm:3.451.0" +"@aws-sdk/credential-provider-sso@npm:3.458.0": + version: 3.458.0 + resolution: "@aws-sdk/credential-provider-sso@npm:3.458.0" dependencies: - "@aws-sdk/client-sso": 3.451.0 + "@aws-sdk/client-sso": 3.458.0 "@aws-sdk/token-providers": 3.451.0 "@aws-sdk/types": 3.451.0 "@smithy/property-provider": ^2.0.0 "@smithy/shared-ini-file-loader": ^2.0.6 "@smithy/types": ^2.5.0 tslib: ^2.5.0 - checksum: 34483b4a213cac1f4859978319b38ef7f69a0d090de49a98d987486da2691a4cf5f474601ce338497d030156b1616a455a8d0bb79a4abbdbe8873a91e451ead2 + checksum: fca1283a4203874f6416ccdf3ba541fee62cbdf95677e5bcfeca9bb9a86c57ee37f204e30729ceb0cc17c51d531b5072d753364fd103e5fe2fef6ac330b2ee44 languageName: node linkType: hard @@ -876,26 +876,26 @@ __metadata: linkType: hard "@aws-sdk/credential-providers@npm:^3.350.0": - version: 3.454.0 - resolution: "@aws-sdk/credential-providers@npm:3.454.0" + version: 3.458.0 + resolution: "@aws-sdk/credential-providers@npm:3.458.0" dependencies: - "@aws-sdk/client-cognito-identity": 3.454.0 - "@aws-sdk/client-sso": 3.451.0 - "@aws-sdk/client-sts": 3.454.0 - "@aws-sdk/credential-provider-cognito-identity": 3.454.0 + "@aws-sdk/client-cognito-identity": 3.458.0 + "@aws-sdk/client-sso": 3.458.0 + "@aws-sdk/client-sts": 3.458.0 + "@aws-sdk/credential-provider-cognito-identity": 3.458.0 "@aws-sdk/credential-provider-env": 3.451.0 "@aws-sdk/credential-provider-http": 3.451.0 - "@aws-sdk/credential-provider-ini": 3.451.0 - "@aws-sdk/credential-provider-node": 3.451.0 + "@aws-sdk/credential-provider-ini": 3.458.0 + "@aws-sdk/credential-provider-node": 3.458.0 "@aws-sdk/credential-provider-process": 3.451.0 - "@aws-sdk/credential-provider-sso": 3.451.0 + "@aws-sdk/credential-provider-sso": 3.458.0 "@aws-sdk/credential-provider-web-identity": 3.451.0 "@aws-sdk/types": 3.451.0 "@smithy/credential-provider-imds": ^2.0.0 "@smithy/property-provider": ^2.0.0 "@smithy/types": ^2.5.0 tslib: ^2.5.0 - checksum: fd6a59aded8a16a800c4354ca5445faac0b5507ca65ca7d1bdc2d5b12efb2c161eb87f399ac2c3e1579b5913f26858bb90d74e1a5026647b375efa7ae9233db9 + checksum: 5b57f869b96f90cdaf5f005f7cfd5a3e03e8a27f7763089b4d9942f586dc55996dfb90ddd66e5b1eb3a277f4d1333a50180adb68a437e054d92eed310b79c47a languageName: node linkType: hard @@ -921,8 +921,8 @@ __metadata: linkType: hard "@aws-sdk/lib-storage@npm:^3.350.0": - version: 3.456.0 - resolution: "@aws-sdk/lib-storage@npm:3.456.0" + version: 3.458.0 + resolution: "@aws-sdk/lib-storage@npm:3.458.0" dependencies: "@smithy/abort-controller": ^2.0.1 "@smithy/middleware-endpoint": ^2.2.0 @@ -933,7 +933,7 @@ __metadata: tslib: ^2.5.0 peerDependencies: "@aws-sdk/client-s3": ^3.0.0 - checksum: 001f9fa653e22edc3c95635b570df05d0c34ce456fd7bc15d6daa36102b988835764efc646e5232888be1a3f0f877dc8d68934b246089b8e7ba795606d10cab6 + checksum: c05dde775ba46cb03a35e362ffb69eb4aafd08d80dbb8a514a20ebf0604e8e35f19df2a732165fa62a843edb9cb3ba66625ca366326608205071a36d26580dc8 languageName: node linkType: hard From 2565cc8f767c838f0c7829c8035c4aafde9a3b1f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 27 Nov 2023 12:08:13 +0000 Subject: [PATCH 127/261] fix(deps): update dependency @rollup/plugin-commonjs to v25 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .changeset/renovate-a277605.md | 5 +++++ packages/cli/package.json | 2 +- yarn.lock | 25 ++++++++----------------- 3 files changed, 14 insertions(+), 18 deletions(-) create mode 100644 .changeset/renovate-a277605.md diff --git a/.changeset/renovate-a277605.md b/.changeset/renovate-a277605.md new file mode 100644 index 0000000000..2bb2274e49 --- /dev/null +++ b/.changeset/renovate-a277605.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Updated dependency `@rollup/plugin-commonjs` to `^25.0.0`. diff --git a/packages/cli/package.json b/packages/cli/package.json index 40880607e5..3460f6ba0e 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -46,7 +46,7 @@ "@octokit/oauth-app": "^4.2.0", "@octokit/request": "^6.0.0", "@pmmmwh/react-refresh-webpack-plugin": "^0.5.7", - "@rollup/plugin-commonjs": "^23.0.0", + "@rollup/plugin-commonjs": "^25.0.0", "@rollup/plugin-json": "^5.0.0", "@rollup/plugin-node-resolve": "^13.0.6", "@rollup/plugin-yaml": "^4.0.0", diff --git a/yarn.lock b/yarn.lock index 3df09f3795..24686f7c6d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3602,7 +3602,7 @@ __metadata: "@octokit/oauth-app": ^4.2.0 "@octokit/request": ^6.0.0 "@pmmmwh/react-refresh-webpack-plugin": ^0.5.7 - "@rollup/plugin-commonjs": ^23.0.0 + "@rollup/plugin-commonjs": ^25.0.0 "@rollup/plugin-json": ^5.0.0 "@rollup/plugin-node-resolve": ^13.0.6 "@rollup/plugin-yaml": ^4.0.0 @@ -12487,7 +12487,7 @@ __metadata: languageName: node linkType: hard -"@jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.4.13, @jridgewell/sourcemap-codec@npm:^1.4.14, @jridgewell/sourcemap-codec@npm:^1.4.15": +"@jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.4.14, @jridgewell/sourcemap-codec@npm:^1.4.15": version: 1.4.15 resolution: "@jridgewell/sourcemap-codec@npm:1.4.15" checksum: b881c7e503db3fc7f3c1f35a1dd2655a188cc51a3612d76efc8a6eb74728bef5606e6758ee77423e564092b4a518aba569bbb21c9bac5ab7a35b0c6ae7e344c8 @@ -15265,22 +15265,22 @@ __metadata: languageName: node linkType: hard -"@rollup/plugin-commonjs@npm:^23.0.0": - version: 23.0.7 - resolution: "@rollup/plugin-commonjs@npm:23.0.7" +"@rollup/plugin-commonjs@npm:^25.0.0": + version: 25.0.7 + resolution: "@rollup/plugin-commonjs@npm:25.0.7" dependencies: "@rollup/pluginutils": ^5.0.1 commondir: ^1.0.1 estree-walker: ^2.0.2 glob: ^8.0.3 is-reference: 1.2.1 - magic-string: ^0.27.0 + magic-string: ^0.30.3 peerDependencies: - rollup: ^2.68.0||^3.0.0 + rollup: ^2.68.0||^3.0.0||^4.0.0 peerDependenciesMeta: rollup: optional: true - checksum: 01d90947bd4aa664c568cec172399825921f29afc035a6d8aec153868ab151ce7901ad56a101c76655e31b21567ddc70313c4bca476685b872218f041757a8c9 + checksum: 052e11839a9edc556eda5dcc759ab816dcc57e9f0f905a1e6e14fff954eaa6b1e2d0d544f5bd18d863993c5eba43d8ac9c19d9bb53b1c3b1213f32cfc9d50b2e languageName: node linkType: hard @@ -33239,15 +33239,6 @@ __metadata: languageName: node linkType: hard -"magic-string@npm:^0.27.0": - version: 0.27.0 - resolution: "magic-string@npm:0.27.0" - dependencies: - "@jridgewell/sourcemap-codec": ^1.4.13 - checksum: 273faaa50baadb7a2df6e442eac34ad611304fc08fe16e24fe2e472fd944bfcb73ffb50d2dc972dc04e92784222002af46868cb9698b1be181c81830fd95a13e - languageName: node - linkType: hard - "magic-string@npm:^0.30.3": version: 0.30.5 resolution: "magic-string@npm:0.30.5" From 1da5f434f339956b8e8505a838ad45d96b34c79d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Mon, 27 Nov 2023 13:19:10 +0100 Subject: [PATCH 128/261] Ensure redaction of secrets that have accidental extra whitespace around them MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .changeset/hungry-buckets-compare.md | 5 +++++ packages/backend-app-api/src/logging/WinstonLogger.test.ts | 2 +- packages/backend-app-api/src/logging/WinstonLogger.ts | 6 +++++- 3 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 .changeset/hungry-buckets-compare.md diff --git a/.changeset/hungry-buckets-compare.md b/.changeset/hungry-buckets-compare.md new file mode 100644 index 0000000000..c70f38bfb7 --- /dev/null +++ b/.changeset/hungry-buckets-compare.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-app-api': patch +--- + +Ensure redaction of secrets that have accidental extra whitespace around them diff --git a/packages/backend-app-api/src/logging/WinstonLogger.test.ts b/packages/backend-app-api/src/logging/WinstonLogger.test.ts index e05e47ee1d..c7173b1cbe 100644 --- a/packages/backend-app-api/src/logging/WinstonLogger.test.ts +++ b/packages/backend-app-api/src/logging/WinstonLogger.test.ts @@ -30,7 +30,7 @@ describe('WinstonLogger', () => { stack: 'hello (world) from this file', }; expect(redacter.format.transform(msg(log))).toEqual(msg(log)); - redacter.add(['hello']); + redacter.add(['hello\n']); expect(redacter.format.transform(msg(log))).toEqual( msg({ ...log, diff --git a/packages/backend-app-api/src/logging/WinstonLogger.ts b/packages/backend-app-api/src/logging/WinstonLogger.ts index bfceb5b2f2..7dd0ed80b0 100644 --- a/packages/backend-app-api/src/logging/WinstonLogger.ts +++ b/packages/backend-app-api/src/logging/WinstonLogger.ts @@ -89,7 +89,11 @@ export class WinstonLogger implements RootLoggerService { })(), add(newRedactions) { let added = 0; - for (const redaction of newRedactions) { + for (const redactionToTrim of newRedactions) { + // Trimming the string ensures that we don't accdentally get extra + // newlines or other whitespace interfering with the redaction; this + // can happen for example when using string literals in yaml + const redaction = redactionToTrim.trim(); // Exclude secrets that are empty or just one character in length. These // typically mean that you are running local dev or tests, or using the // --lax flag which sets things to just 'x'. From c21c9cf07bcd05f924658b74425f51263f09e588 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 27 Nov 2023 13:43:06 +0100 Subject: [PATCH 129/261] frontend-test-utils: re-export APIs from test-utils Signed-off-by: Patrik Oldsberg --- .changeset/modern-mails-live.md | 5 +++ packages/frontend-test-utils/api-report.md | 45 +++++++++++++++++++ .../frontend-test-utils/src/apis/index.ts | 28 ++++++++++++ packages/frontend-test-utils/src/index.ts | 8 ++++ 4 files changed, 86 insertions(+) create mode 100644 .changeset/modern-mails-live.md create mode 100644 packages/frontend-test-utils/src/apis/index.ts diff --git a/.changeset/modern-mails-live.md b/.changeset/modern-mails-live.md new file mode 100644 index 0000000000..82155c44d5 --- /dev/null +++ b/.changeset/modern-mails-live.md @@ -0,0 +1,5 @@ +--- +'@backstage/frontend-test-utils': patch +--- + +Re-export mock API implementations as well as `TestApiProvider`, TestApiRegistry`, `withLogCollector`and`setupRequestMockHandlers`froom`@backstage/test-utils`. diff --git a/packages/frontend-test-utils/api-report.md b/packages/frontend-test-utils/api-report.md index 8d7837b90a..59f5696ddc 100644 --- a/packages/frontend-test-utils/api-report.md +++ b/packages/frontend-test-utils/api-report.md @@ -3,9 +3,24 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +import { ErrorWithContext } from '@backstage/test-utils'; import { Extension } from '@backstage/frontend-plugin-api'; import { JsonObject } from '@backstage/types'; +import { MockAnalyticsApi } from '@backstage/test-utils'; +import { MockConfigApi } from '@backstage/test-utils'; +import { MockErrorApi } from '@backstage/test-utils'; +import { MockErrorApiOptions } from '@backstage/test-utils'; +import { MockFetchApi } from '@backstage/test-utils'; +import { MockFetchApiOptions } from '@backstage/test-utils'; +import { MockPermissionApi } from '@backstage/test-utils'; +import { MockStorageApi } from '@backstage/test-utils'; +import { MockStorageBucket } from '@backstage/test-utils'; import { RenderResult } from '@testing-library/react'; +import { setupRequestMockHandlers } from '@backstage/test-utils'; +import { TestApiProvider } from '@backstage/test-utils'; +import { TestApiProviderProps } from '@backstage/test-utils'; +import { TestApiRegistry } from '@backstage/test-utils'; +import { withLogCollector } from '@backstage/test-utils'; // @public (undocumented) export function createExtensionTester( @@ -15,6 +30,8 @@ export function createExtensionTester( }, ): ExtensionTester; +export { ErrorWithContext }; + // @public (undocumented) export class ExtensionTester { // (undocumented) @@ -27,4 +44,32 @@ export class ExtensionTester { // (undocumented) render(options?: { config?: JsonObject }): RenderResult; } + +export { MockAnalyticsApi }; + +export { MockConfigApi }; + +export { MockErrorApi }; + +export { MockErrorApiOptions }; + +export { MockFetchApi }; + +export { MockFetchApiOptions }; + +export { MockPermissionApi }; + +export { MockStorageApi }; + +export { MockStorageBucket }; + +export { setupRequestMockHandlers }; + +export { TestApiProvider }; + +export { TestApiProviderProps }; + +export { TestApiRegistry }; + +export { withLogCollector }; ``` diff --git a/packages/frontend-test-utils/src/apis/index.ts b/packages/frontend-test-utils/src/apis/index.ts new file mode 100644 index 0000000000..81bd8a7abd --- /dev/null +++ b/packages/frontend-test-utils/src/apis/index.ts @@ -0,0 +1,28 @@ +/* + * 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 { + MockAnalyticsApi, + MockConfigApi, + type ErrorWithContext, + MockErrorApi, + type MockErrorApiOptions, + MockFetchApi, + type MockFetchApiOptions, + MockPermissionApi, + MockStorageApi, + type MockStorageBucket, +} from '@backstage/test-utils'; diff --git a/packages/frontend-test-utils/src/index.ts b/packages/frontend-test-utils/src/index.ts index 6a28cc2abe..0dab8e75b7 100644 --- a/packages/frontend-test-utils/src/index.ts +++ b/packages/frontend-test-utils/src/index.ts @@ -20,4 +20,12 @@ * Contains utilities that can be used when testing frontend features such as extensions. */ +export * from './apis'; export * from './app'; + +export { TestApiProvider, TestApiRegistry } from '@backstage/test-utils'; +export type { TestApiProviderProps } from '@backstage/test-utils'; + +export { withLogCollector } from '@backstage/test-utils'; + +export { setupRequestMockHandlers } from '@backstage/test-utils'; From e8f2acef80f7012e7c31a0804510609abb7bde67 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 27 Nov 2023 13:53:50 +0100 Subject: [PATCH 130/261] test-utils: move mockBreakpoint to core-componets/testUtils Signed-off-by: Patrik Oldsberg --- .changeset/chilly-bikes-kick.md | 5 +++ .changeset/little-suits-collect.md | 5 +++ packages/core-components/package.json | 19 ++++++-- .../src/layout/Sidebar/MobileSidebar.test.tsx | 3 +- .../src/layout/Sidebar/SidebarGroup.test.tsx | 3 +- packages/core-components/src/testUtils.ts | 43 +++++++++++++++++++ .../core-components/testUtils-api-report.md | 10 +++++ packages/test-utils/api-report.md | 2 +- .../src/testUtils/mockBreakpoint.ts | 1 + .../CatalogPage/DefaultCatalogPage.test.tsx | 2 +- 10 files changed, 86 insertions(+), 7 deletions(-) create mode 100644 .changeset/chilly-bikes-kick.md create mode 100644 .changeset/little-suits-collect.md create mode 100644 packages/core-components/src/testUtils.ts create mode 100644 packages/core-components/testUtils-api-report.md diff --git a/.changeset/chilly-bikes-kick.md b/.changeset/chilly-bikes-kick.md new file mode 100644 index 0000000000..f5eb5380d3 --- /dev/null +++ b/.changeset/chilly-bikes-kick.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-components': patch +--- + +Added a new `/testUtils` sub-path that initially exports a `mockBreakpoint` helper. diff --git a/.changeset/little-suits-collect.md b/.changeset/little-suits-collect.md new file mode 100644 index 0000000000..2a1eb4c833 --- /dev/null +++ b/.changeset/little-suits-collect.md @@ -0,0 +1,5 @@ +--- +'@backstage/test-utils': patch +--- + +Deprecated `mockBreakpoint`, as it is now available from `@backstage/core-components/testUtils` instead. diff --git a/packages/core-components/package.json b/packages/core-components/package.json index 7670a5792d..49d1e9867e 100644 --- a/packages/core-components/package.json +++ b/packages/core-components/package.json @@ -3,9 +3,7 @@ "description": "Core components used by Backstage plugins and apps", "version": "0.13.9-next.0", "publishConfig": { - "access": "public", - "main": "dist/index.esm.js", - "types": "dist/index.d.ts" + "access": "public" }, "backstage": { "role": "web-library" @@ -22,6 +20,21 @@ "license": "Apache-2.0", "main": "src/index.ts", "types": "src/index.ts", + "exports": { + ".": "./src/index.ts", + "./testUtils": "./src/testUtils.ts", + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "testUtils": [ + "src/testUtils.ts" + ], + "package.json": [ + "package.json" + ] + } + }, "sideEffects": false, "scripts": { "build": "backstage-cli package build", diff --git a/packages/core-components/src/layout/Sidebar/MobileSidebar.test.tsx b/packages/core-components/src/layout/Sidebar/MobileSidebar.test.tsx index 7012afabf1..c29276a6cf 100644 --- a/packages/core-components/src/layout/Sidebar/MobileSidebar.test.tsx +++ b/packages/core-components/src/layout/Sidebar/MobileSidebar.test.tsx @@ -14,7 +14,8 @@ * limitations under the License. */ -import { mockBreakpoint, renderInTestApp } from '@backstage/test-utils'; +import { renderInTestApp } from '@backstage/test-utils'; +import { mockBreakpoint } from '@backstage/core-components/testUtils'; import CreateComponentIcon from '@material-ui/icons/AddCircleOutline'; import HomeIcon from '@material-ui/icons/Home'; import LayersIcon from '@material-ui/icons/Layers'; diff --git a/packages/core-components/src/layout/Sidebar/SidebarGroup.test.tsx b/packages/core-components/src/layout/Sidebar/SidebarGroup.test.tsx index 687140277a..b59395efab 100644 --- a/packages/core-components/src/layout/Sidebar/SidebarGroup.test.tsx +++ b/packages/core-components/src/layout/Sidebar/SidebarGroup.test.tsx @@ -14,7 +14,8 @@ * limitations under the License. */ -import { mockBreakpoint, renderInTestApp } from '@backstage/test-utils'; +import { mockBreakpoint } from '@backstage/core-components/testUtils'; +import { renderInTestApp } from '@backstage/test-utils'; import HomeIcon from '@material-ui/icons/Home'; import LayersIcon from '@material-ui/icons/Layers'; import LibraryBooks from '@material-ui/icons/LibraryBooks'; diff --git a/packages/core-components/src/testUtils.ts b/packages/core-components/src/testUtils.ts new file mode 100644 index 0000000000..17bb0db63b --- /dev/null +++ b/packages/core-components/src/testUtils.ts @@ -0,0 +1,43 @@ +/* + * 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. + */ + +/** + * This is a mocking method suggested in the Jest docs, as it is not implemented in JSDOM yet. + * It can be used to mock values for the Material UI `useMediaQuery` hook if it is used in a tested component. + * + * For issues checkout the documentation: + * https://jestjs.io/docs/manual-mocks#mocking-methods-which-are-not-implemented-in-jsdom + * + * If there are any updates from Material UI React on testing `useMediaQuery` this mock should be replaced + * https://mui.com/material-ui/react-use-media-query/#testing + * + * @public + */ +export function mockBreakpoint(options: { matches: boolean }) { + Object.defineProperty(window, 'matchMedia', { + writable: true, + value: jest.fn().mockImplementation(query => ({ + matches: options.matches ?? false, + media: query, + onchange: null, + addListener: jest.fn(), // deprecated + removeListener: jest.fn(), // deprecated + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + dispatchEvent: jest.fn(), + })), + }); +} diff --git a/packages/core-components/testUtils-api-report.md b/packages/core-components/testUtils-api-report.md new file mode 100644 index 0000000000..93a6bb2a07 --- /dev/null +++ b/packages/core-components/testUtils-api-report.md @@ -0,0 +1,10 @@ +## API Report File for "@backstage/core-components" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +// @public +export function mockBreakpoint(options: { matches: boolean }): void; + +// (No @packageDocumentation comment for this package) +``` diff --git a/packages/test-utils/api-report.md b/packages/test-utils/api-report.md index 60bd352726..913413acd1 100644 --- a/packages/test-utils/api-report.md +++ b/packages/test-utils/api-report.md @@ -74,7 +74,7 @@ export class MockAnalyticsApi implements AnalyticsApi { getEvents(): AnalyticsEvent[]; } -// @public +// @public @deprecated export function mockBreakpoint(options: { matches: boolean }): void; // @public diff --git a/packages/test-utils/src/testUtils/mockBreakpoint.ts b/packages/test-utils/src/testUtils/mockBreakpoint.ts index 78d7c9497f..c674c98f06 100644 --- a/packages/test-utils/src/testUtils/mockBreakpoint.ts +++ b/packages/test-utils/src/testUtils/mockBreakpoint.ts @@ -25,6 +25,7 @@ * https://mui.com/material-ui/react-use-media-query/#testing * * @public + * @deprecated Import from `@backstage/core-components/testUtils` instead. */ export default function mockBreakpoint(options: { matches: boolean }) { Object.defineProperty(window, 'matchMedia', { diff --git a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.test.tsx b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.test.tsx index f3cc0cb042..e7ba2b960e 100644 --- a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.test.tsx +++ b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.test.tsx @@ -32,8 +32,8 @@ import { MockStarredEntitiesApi, starredEntitiesApiRef, } from '@backstage/plugin-catalog-react'; +import { mockBreakpoint } from '@backstage/core-components/testUtils'; import { - mockBreakpoint, MockStorageApi, TestApiProvider, renderInTestApp, From 627554e9938afc8cf243adbeb04279be8b3d0d4a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 27 Nov 2023 13:03:06 +0000 Subject: [PATCH 131/261] fix(deps): update dependency @rollup/plugin-node-resolve to v15 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .changeset/renovate-0c44581.md | 5 +++ packages/cli/package.json | 2 +- yarn.lock | 75 +++++++++++++--------------------- 3 files changed, 34 insertions(+), 48 deletions(-) create mode 100644 .changeset/renovate-0c44581.md diff --git a/.changeset/renovate-0c44581.md b/.changeset/renovate-0c44581.md new file mode 100644 index 0000000000..afddf45fed --- /dev/null +++ b/.changeset/renovate-0c44581.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Updated dependency `@rollup/plugin-node-resolve` to `^15.0.0`. diff --git a/packages/cli/package.json b/packages/cli/package.json index 40880607e5..f44e28d254 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -48,7 +48,7 @@ "@pmmmwh/react-refresh-webpack-plugin": "^0.5.7", "@rollup/plugin-commonjs": "^23.0.0", "@rollup/plugin-json": "^5.0.0", - "@rollup/plugin-node-resolve": "^13.0.6", + "@rollup/plugin-node-resolve": "^15.0.0", "@rollup/plugin-yaml": "^4.0.0", "@spotify/eslint-config-base": "^14.0.0", "@spotify/eslint-config-react": "^14.0.0", diff --git a/yarn.lock b/yarn.lock index a6bd247f97..fff420a0b1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3604,7 +3604,7 @@ __metadata: "@pmmmwh/react-refresh-webpack-plugin": ^0.5.7 "@rollup/plugin-commonjs": ^23.0.0 "@rollup/plugin-json": ^5.0.0 - "@rollup/plugin-node-resolve": ^13.0.6 + "@rollup/plugin-node-resolve": ^15.0.0 "@rollup/plugin-yaml": ^4.0.0 "@spotify/eslint-config-base": ^14.0.0 "@spotify/eslint-config-react": ^14.0.0 @@ -15314,19 +15314,22 @@ __metadata: languageName: node linkType: hard -"@rollup/plugin-node-resolve@npm:^13.0.6": - version: 13.3.0 - resolution: "@rollup/plugin-node-resolve@npm:13.3.0" +"@rollup/plugin-node-resolve@npm:^15.0.0": + version: 15.2.3 + resolution: "@rollup/plugin-node-resolve@npm:15.2.3" dependencies: - "@rollup/pluginutils": ^3.1.0 - "@types/resolve": 1.17.1 + "@rollup/pluginutils": ^5.0.1 + "@types/resolve": 1.20.2 deepmerge: ^4.2.2 - is-builtin-module: ^3.1.0 + is-builtin-module: ^3.2.1 is-module: ^1.0.0 - resolve: ^1.19.0 + resolve: ^1.22.1 peerDependencies: - rollup: ^2.42.0 - checksum: ec5418e6b3c23a9e30683056b3010e9d325316dcfae93fbc673ae64dad8e56a2ce761c15c48f5e2dcfe0c822fdc4a4905ee6346e3dcf90603ba2260afef5a5e6 + rollup: ^2.78.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + checksum: 730f32c2f8fdddff07cf0fca86a5dac7c475605fb96930197a868c066e62eb6388c557545e4f7d99b7a283411754c9fbf98944ab086b6074e04fc1292e234aa8 languageName: node linkType: hard @@ -15346,19 +15349,6 @@ __metadata: languageName: node linkType: hard -"@rollup/pluginutils@npm:^3.1.0": - version: 3.1.0 - resolution: "@rollup/pluginutils@npm:3.1.0" - dependencies: - "@types/estree": 0.0.39 - estree-walker: ^1.0.1 - picomatch: ^2.2.2 - peerDependencies: - rollup: ^1.20.0||^2.0.0 - checksum: 8be16e27863c219edbb25a4e6ec2fe0e1e451d9e917b6a43cf2ae5bc025a6b8faaa40f82a6e53b66d0de37b58ff472c6c3d57a83037ae635041f8df959d6d9aa - languageName: node - linkType: hard - "@rollup/pluginutils@npm:^4.1.1, @rollup/pluginutils@npm:^4.2.0, @rollup/pluginutils@npm:^4.2.1": version: 4.2.1 resolution: "@rollup/pluginutils@npm:4.2.1" @@ -19001,12 +18991,10 @@ __metadata: languageName: node linkType: hard -"@types/resolve@npm:1.17.1": - version: 1.17.1 - resolution: "@types/resolve@npm:1.17.1" - dependencies: - "@types/node": "*" - checksum: dc6a6df507656004e242dcb02c784479deca516d5f4b58a1707e708022b269ae147e1da0521f3e8ad0d63638869d87e0adc023f0bd5454aa6f72ac66c7525cf5 +"@types/resolve@npm:1.20.2": + version: 1.20.2 + resolution: "@types/resolve@npm:1.20.2" + checksum: 61c2cad2499ffc8eab36e3b773945d337d848d3ac6b7b0a87c805ba814bc838ef2f262fc0f109bfd8d2e0898ff8bd80ad1025f9ff64f1f71d3d4294c9f14e5f6 languageName: node linkType: hard @@ -21978,10 +21966,10 @@ __metadata: languageName: node linkType: hard -"builtin-modules@npm:^3.0.0": - version: 3.2.0 - resolution: "builtin-modules@npm:3.2.0" - checksum: 0265aa1ba78e1a16f4e18668d815cb43fb364e6a6b8aa9189c6f44c7b894a551a43b323c40206959d2d4b2568c1f2805607ad6c88adc306a776ce6904cca6715 +"builtin-modules@npm:^3.3.0": + version: 3.3.0 + resolution: "builtin-modules@npm:3.3.0" + checksum: db021755d7ed8be048f25668fe2117620861ef6703ea2c65ed2779c9e3636d5c3b82325bd912244293959ff3ae303afa3471f6a15bf5060c103e4cc3a839749d languageName: node linkType: hard @@ -26334,13 +26322,6 @@ __metadata: languageName: node linkType: hard -"estree-walker@npm:^1.0.1": - version: 1.0.1 - resolution: "estree-walker@npm:1.0.1" - checksum: 7e70da539691f6db03a08e7ce94f394ce2eef4180e136d251af299d41f92fb2d28ebcd9a6e393e3728d7970aeb5358705ddf7209d52fbcb2dd4693f95dcf925f - languageName: node - linkType: hard - "estree-walker@npm:^2.0.1, estree-walker@npm:^2.0.2": version: 2.0.2 resolution: "estree-walker@npm:2.0.2" @@ -29979,12 +29960,12 @@ __metadata: languageName: node linkType: hard -"is-builtin-module@npm:^3.1.0": - version: 3.1.0 - resolution: "is-builtin-module@npm:3.1.0" +"is-builtin-module@npm:^3.2.1": + version: 3.2.1 + resolution: "is-builtin-module@npm:3.2.1" dependencies: - builtin-modules: ^3.0.0 - checksum: f1e5dd2cd5f252d4d799b20a0c8c4f7e9c399c4d141749af76ca0121058d4062c3015d026f1b1409dd3d2a4ddfb9b15cf6eb9c370fed53fea8652ce35b5e95cb + builtin-modules: ^3.3.0 + checksum: e8f0ffc19a98240bda9c7ada84d846486365af88d14616e737d280d378695c8c448a621dcafc8332dbf0fcd0a17b0763b845400709963fa9151ddffece90ae88 languageName: node linkType: hard @@ -39664,7 +39645,7 @@ __metadata: languageName: node linkType: hard -"resolve@npm:^1.1.6, resolve@npm:^1.10.0, resolve@npm:^1.14.2, resolve@npm:^1.17.0, resolve@npm:^1.19.0, resolve@npm:^1.20.0, resolve@npm:^1.22.4, resolve@npm:~1.22.1": +"resolve@npm:^1.1.6, resolve@npm:^1.10.0, resolve@npm:^1.14.2, resolve@npm:^1.17.0, resolve@npm:^1.19.0, resolve@npm:^1.20.0, resolve@npm:^1.22.1, resolve@npm:^1.22.4, resolve@npm:~1.22.1": version: 1.22.8 resolution: "resolve@npm:1.22.8" dependencies: @@ -39700,7 +39681,7 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@^1.1.6#~builtin, resolve@patch:resolve@^1.10.0#~builtin, resolve@patch:resolve@^1.14.2#~builtin, resolve@patch:resolve@^1.17.0#~builtin, resolve@patch:resolve@^1.19.0#~builtin, resolve@patch:resolve@^1.20.0#~builtin, resolve@patch:resolve@^1.22.4#~builtin, resolve@patch:resolve@~1.22.1#~builtin": +"resolve@patch:resolve@^1.1.6#~builtin, resolve@patch:resolve@^1.10.0#~builtin, resolve@patch:resolve@^1.14.2#~builtin, resolve@patch:resolve@^1.17.0#~builtin, resolve@patch:resolve@^1.19.0#~builtin, resolve@patch:resolve@^1.20.0#~builtin, resolve@patch:resolve@^1.22.1#~builtin, resolve@patch:resolve@^1.22.4#~builtin, resolve@patch:resolve@~1.22.1#~builtin": version: 1.22.8 resolution: "resolve@patch:resolve@npm%3A1.22.8#~builtin::version=1.22.8&hash=07638b" dependencies: From 5c794cd5835c6c2be565134d0a744743dc95637a Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Mon, 27 Nov 2023 14:39:17 +0100 Subject: [PATCH 132/261] refactor: add app not to route objs Signed-off-by: Camila Belo --- .../src/extensions/CoreRouter.tsx | 11 ++++- .../src/routing/RouteTracker.test.tsx | 34 +++++++++----- .../src/routing/RouteTracker.tsx | 22 ++------- .../routing/extractRouteInfoFromAppNode.ts | 1 + .../frontend-app-api/src/routing/types.ts | 2 + .../src/wiring/InternalAppContext.ts | 2 + .../frontend-app-api/src/wiring/createApp.tsx | 6 +-- .../src/analytics/AnalyticsContext.test.tsx | 19 ++++---- .../src/analytics/AnalyticsContext.tsx | 3 +- .../src/analytics/Tracker.test.ts | 47 +++++-------------- .../src/analytics/Tracker.ts | 13 ++--- .../src/analytics/types.ts | 6 +-- .../src/analytics/useAnalytics.test.tsx | 3 +- 13 files changed, 73 insertions(+), 96 deletions(-) diff --git a/packages/frontend-app-api/src/extensions/CoreRouter.tsx b/packages/frontend-app-api/src/extensions/CoreRouter.tsx index f128a246e6..510af04b51 100644 --- a/packages/frontend-app-api/src/extensions/CoreRouter.tsx +++ b/packages/frontend-app-api/src/extensions/CoreRouter.tsx @@ -33,6 +33,7 @@ import { AppIdentityProxy } from '../../../core-app-api/src/apis/implementations import { BrowserRouter } from 'react-router-dom'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports import { signInPageComponentDataRef } from '../../../frontend-plugin-api/src/extensions/createSignInPageExtension'; +import { RouteTracker } from '../routing/RouteTracker'; export const CoreRouter = createExtension({ id: 'core.router', @@ -132,7 +133,7 @@ export function AppRouter(props: AppRouterProps) { if (!internalAppContext) { throw new Error('AppRouter must be rendered within the AppProvider'); } - const { appIdentityProxy } = internalAppContext; + const { routeObjects, appIdentityProxy } = internalAppContext; // If the app hasn't configured a sign-in page, we just continue as guest. if (!SignInPageComponent) { @@ -159,11 +160,17 @@ export function AppRouter(props: AppRouterProps) { { signOutTargetUrl: basePath || '/' }, ); - return {children}; + return ( + + + {children} + + ); } return ( + { plugins: new Set([plugin0]), caseSensitive: false, children: [MATCH_ALL_ROUTE], + appNode: { + spec: { extension: { id: 'home.page.index' }, source: { id: 'home' } }, + } as AppNode, }, { path: '/path/:p1/:p2', @@ -51,6 +55,12 @@ describe('RouteTracker', () => { plugins: new Set([plugin1]), caseSensitive: false, children: [MATCH_ALL_ROUTE], + appNode: { + spec: { + extension: { id: 'plugin1.page.index' }, + source: { id: 'plugin1' }, + }, + } as AppNode, }, { path: '/path2/:param', @@ -59,6 +69,12 @@ describe('RouteTracker', () => { plugins: new Set([plugin2]), caseSensitive: false, children: [MATCH_ALL_ROUTE], + appNode: { + spec: { + extension: { id: 'plugin2.page.index' }, + source: { id: 'plugin2' }, + }, + } as AppNode, }, ]; @@ -86,9 +102,8 @@ describe('RouteTracker', () => { p2: 'bar', }, context: { - extension: 'App', + extensionId: 'plugin1.page.index', pluginId: 'plugin1', - routeRef: undefined, }, subject: '/path/foo/bar', value: undefined, @@ -118,9 +133,8 @@ describe('RouteTracker', () => { param: 'hello', }, context: { - extension: 'App', + extensionId: 'plugin2.page.index', pluginId: 'plugin2', - routeRef: undefined, }, subject: '/path2/hello', value: undefined, @@ -143,9 +157,8 @@ describe('RouteTracker', () => { p2: 'bar', }, context: { - extension: 'App', + extensionId: 'plugin1.page.index', pluginId: 'plugin1', - routeRef: undefined, }, subject: '/path/foo/bar?q=1#header-1', value: undefined, @@ -165,16 +178,15 @@ describe('RouteTracker', () => { action: 'navigate', attributes: {}, context: { - extension: 'App', + extensionId: 'home.page.index', pluginId: 'home', - routeRef: undefined, }, subject: '/', value: undefined, }); }); - it('should return default context when it would have otherwise matched on the root path', async () => { + it.skip('should return default context when it would have otherwise matched on the root path', async () => { render( @@ -195,7 +207,6 @@ describe('RouteTracker', () => { context: { extension: 'App', pluginId: 'root', - routeRef: 'unknown', }, subject: '/not-routable-extension', value: undefined, @@ -217,9 +228,8 @@ describe('RouteTracker', () => { param: 'param-value', }, context: { - extension: 'App', + extensionId: 'plugin2.page.index', pluginId: 'plugin2', - routeRef: undefined, }, subject: '/path2/param-value/sub-route', value: undefined, diff --git a/packages/frontend-app-api/src/routing/RouteTracker.tsx b/packages/frontend-app-api/src/routing/RouteTracker.tsx index a25a12fae2..7bceb05cf9 100644 --- a/packages/frontend-app-api/src/routing/RouteTracker.tsx +++ b/packages/frontend-app-api/src/routing/RouteTracker.tsx @@ -16,7 +16,6 @@ import React, { useEffect } from 'react'; import { matchRoutes, useLocation } from 'react-router-dom'; -import { RouteRef, BackstagePlugin } from '@backstage/core-plugin-api'; import { useAnalytics, AnalyticsContext, @@ -55,18 +54,6 @@ const getExtensionContext = ( return undefined; } - // If there is a single route ref, use it. - let routeRef: RouteRef | undefined; - if (routeObject.routeRefs.size === 1) { - routeRef = routeObject.routeRefs.values().next().value; - } - - // If there is a single plugin, use it. - let plugin: BackstagePlugin | undefined; - if (routeObject.plugins.size === 1) { - plugin = routeObject.plugins.values().next().value; - } - const params = Object.entries( routeMatch?.params || {}, ).reduce((acc, [key, value]) => { @@ -76,12 +63,13 @@ const getExtensionContext = ( return acc; }, {}); + const plugin = routeObject.appNode?.spec.source; + const extension = routeObject.appNode?.spec.extension; + return { - extension: 'App', - pluginId: plugin?.getId() || 'root', - ...(routeRef ? { routeRef: (routeRef as { id?: string }).id } : {}), - _routeNodeType: routeObject.element as string, params, + pluginId: plugin?.id || 'root', + extensionId: extension?.id || 'App', }; } catch { return undefined; diff --git a/packages/frontend-app-api/src/routing/extractRouteInfoFromAppNode.ts b/packages/frontend-app-api/src/routing/extractRouteInfoFromAppNode.ts index 2bfd09a3e8..17afbeb4c9 100644 --- a/packages/frontend-app-api/src/routing/extractRouteInfoFromAppNode.ts +++ b/packages/frontend-app-api/src/routing/extractRouteInfoFromAppNode.ts @@ -84,6 +84,7 @@ export function extractRouteInfoFromAppNode(node: AppNode): { caseSensitive: false, children: [MATCH_ALL_ROUTE], plugins: new Set(), + appNode: current, }; parentChildren.push(currentObj); diff --git a/packages/frontend-app-api/src/routing/types.ts b/packages/frontend-app-api/src/routing/types.ts index 5f1ed9be84..05ea73dff8 100644 --- a/packages/frontend-app-api/src/routing/types.ts +++ b/packages/frontend-app-api/src/routing/types.ts @@ -15,6 +15,7 @@ */ import { + AppNode, ExternalRouteRef, RouteRef, SubRouteRef, @@ -35,4 +36,5 @@ export interface BackstageRouteObject { path: string; routeRefs: Set; plugins: Set; + appNode?: AppNode; } diff --git a/packages/frontend-app-api/src/wiring/InternalAppContext.ts b/packages/frontend-app-api/src/wiring/InternalAppContext.ts index 805c46a067..81264bd81b 100644 --- a/packages/frontend-app-api/src/wiring/InternalAppContext.ts +++ b/packages/frontend-app-api/src/wiring/InternalAppContext.ts @@ -17,10 +17,12 @@ import { createContext } from 'react'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports import { AppIdentityProxy } from '../../../core-app-api/src/apis/implementations/IdentityApi/AppIdentityProxy'; +import { BackstageRouteObject } from '../routing/types'; export const InternalAppContext = createContext< | undefined | { appIdentityProxy: AppIdentityProxy; + routeObjects: BackstageRouteObject[]; } >(undefined); diff --git a/packages/frontend-app-api/src/wiring/createApp.tsx b/packages/frontend-app-api/src/wiring/createApp.tsx index 6f5a1592c2..a1412f1c3c 100644 --- a/packages/frontend-app-api/src/wiring/createApp.tsx +++ b/packages/frontend-app-api/src/wiring/createApp.tsx @@ -97,7 +97,6 @@ import { CoreRouter } from '../extensions/CoreRouter'; import { toInternalBackstagePlugin } from '../../../frontend-plugin-api/src/wiring/createPlugin'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports import { toInternalExtensionOverrides } from '../../../frontend-plugin-api/src/wiring/createExtensionOverrides'; -import { RouteTracker } from '../routing/RouteTracker'; const builtinExtensions = [ Core, @@ -342,8 +341,9 @@ export function createSpecializedApp(options?: { - - + {rootEl} diff --git a/packages/frontend-plugin-api/src/analytics/AnalyticsContext.test.tsx b/packages/frontend-plugin-api/src/analytics/AnalyticsContext.test.tsx index c29ec5b3ca..8e78bdc8c4 100644 --- a/packages/frontend-plugin-api/src/analytics/AnalyticsContext.test.tsx +++ b/packages/frontend-plugin-api/src/analytics/AnalyticsContext.test.tsx @@ -23,9 +23,8 @@ const AnalyticsSpy = () => { const context = useAnalyticsContext(); return ( <> -
{context.routeRef}
{context.pluginId}
-
{context.extension}
+
{context.extensionId}
{context.custom}
); @@ -36,9 +35,8 @@ describe('AnalyticsContext', () => { it('returns default values', () => { const { result } = renderHook(() => useAnalyticsContext()); expect(result.current).toEqual({ - extension: 'App', + extensionId: 'App', pluginId: 'root', - routeRef: 'unknown', }); }); }); @@ -51,9 +49,8 @@ describe('AnalyticsContext', () => { , ); - expect(result.getByTestId('extension')).toHaveTextContent('App'); + expect(result.getByTestId('extension-id')).toHaveTextContent('App'); expect(result.getByTestId('plugin-id')).toHaveTextContent('root'); - expect(result.getByTestId('route-ref')).toHaveTextContent('unknown'); }); it('uses provided analytics context', () => { @@ -63,23 +60,23 @@ describe('AnalyticsContext', () => { , ); - expect(result.getByTestId('extension')).toHaveTextContent('App'); + expect(result.getByTestId('extension-id')).toHaveTextContent('App'); expect(result.getByTestId('plugin-id')).toHaveTextContent('custom'); - expect(result.getByTestId('route-ref')).toHaveTextContent('unknown'); }); it('uses nested analytics context', () => { const result = render( - + , ); - expect(result.getByTestId('extension')).toHaveTextContent('AnalyticsSpy'); + expect(result.getByTestId('extension-id')).toHaveTextContent( + 'AnalyticsSpy', + ); expect(result.getByTestId('plugin-id')).toHaveTextContent('custom'); - expect(result.getByTestId('route-ref')).toHaveTextContent('unknown'); }); }); }); diff --git a/packages/frontend-plugin-api/src/analytics/AnalyticsContext.tsx b/packages/frontend-plugin-api/src/analytics/AnalyticsContext.tsx index 105be8e2b5..10ef475803 100644 --- a/packages/frontend-plugin-api/src/analytics/AnalyticsContext.tsx +++ b/packages/frontend-plugin-api/src/analytics/AnalyticsContext.tsx @@ -37,9 +37,8 @@ export const useAnalyticsContext = (): AnalyticsContextValue => { // Provide a default value if no value exists. if (theContext === undefined) { return { - routeRef: 'unknown', pluginId: 'root', - extension: 'App', + extensionId: 'App', }; } diff --git a/packages/frontend-plugin-api/src/analytics/Tracker.test.ts b/packages/frontend-plugin-api/src/analytics/Tracker.test.ts index e0e3a87f6d..f1670cf9c4 100644 --- a/packages/frontend-plugin-api/src/analytics/Tracker.test.ts +++ b/packages/frontend-plugin-api/src/analytics/Tracker.test.ts @@ -19,9 +19,8 @@ import { Tracker, routableExtensionRenderedEvent } from './Tracker'; describe('Tracker', () => { const defaultContext = { - routeRef: 'unknown', pluginId: 'root', - extension: 'App', + extensionId: 'App', }; const globalEvents = getOrCreateGlobalSingleton( 'core-plugin-api:analytics-tracker-events', @@ -56,9 +55,8 @@ describe('Tracker', () => { it('captures simple event with set context', () => { trackerUnderTest.setContext({ - routeRef: 'catalog:entity', pluginId: 'catalog', - extension: 'App', + extensionId: 'App', }); trackerUnderTest.captureEvent('click', 'test 2', { value: 2, @@ -72,9 +70,8 @@ describe('Tracker', () => { value: 2, attributes: { to: '/page-2' }, context: { - routeRef: 'catalog:entity', pluginId: 'catalog', - extension: 'App', + extensionId: 'App', }, }), ); @@ -83,10 +80,8 @@ describe('Tracker', () => { describe('accurate navigate events', () => { it('never captures _routeNodeType context key on navigate event', () => { trackerUnderTest.setContext({ - routeRef: 'catalog:entity', pluginId: 'catalog', - extension: 'App', - _routeNodeType: 'mounted', + extensionId: 'App', }); trackerUnderTest.captureEvent('navigate', '/page-3'); @@ -99,7 +94,6 @@ describe('Tracker', () => { it('never immediately captures navigate event with _routeNodeType "gathered"', () => { trackerUnderTest.setContext({ ...defaultContext, - _routeNodeType: 'gathered', }); trackerUnderTest.captureEvent('navigate', '/page-4'); @@ -116,15 +110,13 @@ describe('Tracker', () => { // User navigates to a gathered mountpoint with multiple plugins trackerUnderTest.setContext({ ...defaultContext, - _routeNodeType: 'gathered', }); trackerUnderTest.captureEvent('navigate', '/page-5'); // A routable extension is rendered with specific plugin context trackerUnderTest.setContext({ - routeRef: 'some:ref', pluginId: 'some-plugin', - extension: 'App', + extensionId: 'App', }); trackerUnderTest.captureEvent(routableExtensionRenderedEvent, ''); @@ -138,9 +130,8 @@ describe('Tracker', () => { action: 'navigate', subject: '/page-5', context: { - routeRef: 'some:ref', pluginId: 'some-plugin', - extension: 'App', + extensionId: 'App', }, }), ); @@ -150,9 +141,8 @@ describe('Tracker', () => { action: 'click', subject: 'test 5', context: { - routeRef: 'some:ref', pluginId: 'some-plugin', - extension: 'App', + extensionId: 'App', }, }), ); @@ -162,22 +152,19 @@ describe('Tracker', () => { // User navigates to a gathered mountpoint with multiple plugins trackerUnderTest.setContext({ ...defaultContext, - _routeNodeType: 'gathered', }); trackerUnderTest.captureEvent('navigate', '/page-6'); // A routable extension is rendered with specific plugin context trackerUnderTest.setContext({ - routeRef: 'another:ref', pluginId: 'another-plugin', - extension: 'App', + extensionId: 'App', }); trackerUnderTest.captureEvent(routableExtensionRenderedEvent, ''); // User navigates to another gathered mountpoint with multiple plugins trackerUnderTest.setContext({ ...defaultContext, - _routeNodeType: 'gathered', }); trackerUnderTest.captureEvent('navigate', '/page-6-2'); @@ -188,9 +175,8 @@ describe('Tracker', () => { action: 'navigate', subject: '/page-6', context: { - routeRef: 'another:ref', pluginId: 'another-plugin', - extension: 'App', + extensionId: 'App', }, }), ); @@ -200,7 +186,6 @@ describe('Tracker', () => { // User navigates to a gathered mountpoint with multiple plugins trackerUnderTest.setContext({ ...defaultContext, - _routeNodeType: 'gathered', }); trackerUnderTest.captureEvent('navigate', '/page-7'); @@ -230,16 +215,14 @@ describe('Tracker', () => { // User navigates to a gathered mountpoint with multiple plugins trackerUnderTest.setContext({ ...defaultContext, - _routeNodeType: 'gathered', }); trackerUnderTest.captureEvent('navigate', '/page-8'); // A routable extension is rendered with specific plugin context and // captured via a separate tracker instance. const anotherTracker = new Tracker(analyticsApiSpy, { - routeRef: 'the:ref', pluginId: 'the-plugin', - extension: 'App', + extensionId: 'App', }); anotherTracker.captureEvent(routableExtensionRenderedEvent, ''); @@ -254,9 +237,8 @@ describe('Tracker', () => { action: 'navigate', subject: '/page-8', context: { - routeRef: 'the:ref', pluginId: 'the-plugin', - extension: 'App', + extensionId: 'App', }, }), ); @@ -273,15 +255,13 @@ describe('Tracker', () => { // User navigates to a gathered mountpoint with multiple plugins trackerUnderTest.setContext({ ...defaultContext, - _routeNodeType: 'gathered', }); trackerUnderTest.captureEvent('navigate', '/page-9'); // A routable extension is rendered with specific plugin context trackerUnderTest.setContext({ - routeRef: 'very:ref', pluginId: 'very-plugin', - extension: 'ShouldBeReplaced', + extensionId: 'ShouldBeReplaced', }); trackerUnderTest.captureEvent(routableExtensionRenderedEvent, ''); @@ -295,9 +275,8 @@ describe('Tracker', () => { action: 'navigate', subject: '/page-9', context: { - routeRef: 'very:ref', pluginId: 'very-plugin', - extension: 'App', + extensionId: 'App', }, }), ); diff --git a/packages/frontend-plugin-api/src/analytics/Tracker.ts b/packages/frontend-plugin-api/src/analytics/Tracker.ts index 130410e2a2..dd0d770354 100644 --- a/packages/frontend-plugin-api/src/analytics/Tracker.ts +++ b/packages/frontend-plugin-api/src/analytics/Tracker.ts @@ -68,9 +68,8 @@ export class Tracker implements AnalyticsTracker { constructor( private readonly analyticsApi: AnalyticsApi, private context: AnalyticsContextValue = { - routeRef: 'unknown', pluginId: 'root', - extension: 'App', + extensionId: 'App', }, ) { // Only register a single beforeunload event across all trackers. @@ -110,7 +109,7 @@ export class Tracker implements AnalyticsTracker { }: { value?: number; attributes?: AnalyticsEventAttributes } = {}, ) { // Never pass internal "_routeNodeType" context value. - const { _routeNodeType, ...context } = this.context; + const context = this.context; // Never fire the special "_routable-extension-rendered" internal event. if (action === routableExtensionRenderedEvent) { @@ -120,7 +119,7 @@ export class Tracker implements AnalyticsTracker { globalEvents.mostRecentRoutableExtensionRender = { context: { ...context, - extension: 'App', + extensionId: 'App', }, }; } @@ -148,11 +147,7 @@ export class Tracker implements AnalyticsTracker { // Never directly fire a navigation event on a gathered route with default // contextual details. - if ( - action === 'navigate' && - _routeNodeType === 'gathered' && - context.pluginId === 'root' - ) { + if (action === 'navigate' && context.pluginId === 'root') { // Instead, set it on the global store. globalEvents.mostRecentGatheredNavigation = { action, diff --git a/packages/frontend-plugin-api/src/analytics/types.ts b/packages/frontend-plugin-api/src/analytics/types.ts index ed5dcd588d..21347e2fc7 100644 --- a/packages/frontend-plugin-api/src/analytics/types.ts +++ b/packages/frontend-plugin-api/src/analytics/types.ts @@ -26,14 +26,12 @@ export type CommonAnalyticsContext = { pluginId: string; /** - * The ID of the routeRef that was active when the event was captured. + * The nearest known parent extension where the event was captured. */ - routeRef: string; - /** * The nearest known parent extension where the event was captured. */ - extension: string; + extensionId: string; }; /** diff --git a/packages/frontend-plugin-api/src/analytics/useAnalytics.test.tsx b/packages/frontend-plugin-api/src/analytics/useAnalytics.test.tsx index e83826991a..630ce0331a 100644 --- a/packages/frontend-plugin-api/src/analytics/useAnalytics.test.tsx +++ b/packages/frontend-plugin-api/src/analytics/useAnalytics.test.tsx @@ -58,9 +58,8 @@ describe('useAnalytics', () => { some: 'value', }, context: { - extension: 'App', + extensionId: 'App', pluginId: 'root', - routeRef: 'unknown', }, }); }); From f91be2c06f24c1f8d5fd41f4feb2549243f0ac18 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 27 Nov 2023 14:03:15 +0000 Subject: [PATCH 133/261] fix(deps): update dependency @stoplight/types to v14 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .changeset/renovate-1252136.md | 5 +++++ packages/repo-tools/package.json | 2 +- yarn.lock | 14 ++++++++++++-- 3 files changed, 18 insertions(+), 3 deletions(-) create mode 100644 .changeset/renovate-1252136.md diff --git a/.changeset/renovate-1252136.md b/.changeset/renovate-1252136.md new file mode 100644 index 0000000000..0be5143b30 --- /dev/null +++ b/.changeset/renovate-1252136.md @@ -0,0 +1,5 @@ +--- +'@backstage/repo-tools': patch +--- + +Updated dependency `@stoplight/types` to `^14.0.0`. diff --git a/packages/repo-tools/package.json b/packages/repo-tools/package.json index 3bd76a6e60..761344662a 100644 --- a/packages/repo-tools/package.json +++ b/packages/repo-tools/package.json @@ -45,7 +45,7 @@ "@stoplight/spectral-parsers": "^1.0.2", "@stoplight/spectral-rulesets": "^1.18.0", "@stoplight/spectral-runtime": "^1.1.2", - "@stoplight/types": "^13.14.0", + "@stoplight/types": "^14.0.0", "chalk": "^4.0.0", "codeowners-utils": "^1.0.2", "commander": "^9.1.0", diff --git a/yarn.lock b/yarn.lock index eb70b18813..4b87abba12 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10059,7 +10059,7 @@ __metadata: "@stoplight/spectral-parsers": ^1.0.2 "@stoplight/spectral-rulesets": ^1.18.0 "@stoplight/spectral-runtime": ^1.1.2 - "@stoplight/types": ^13.14.0 + "@stoplight/types": ^14.0.0 "@types/is-glob": ^4.0.2 "@types/mock-fs": ^4.13.0 "@types/node": ^18.17.8 @@ -16452,7 +16452,7 @@ __metadata: languageName: node linkType: hard -"@stoplight/types@npm:^12.3.0 || ^13.0.0, @stoplight/types@npm:^13.0.0, @stoplight/types@npm:^13.12.0, @stoplight/types@npm:^13.14.0, @stoplight/types@npm:^13.15.0, @stoplight/types@npm:^13.6.0": +"@stoplight/types@npm:^12.3.0 || ^13.0.0, @stoplight/types@npm:^13.0.0, @stoplight/types@npm:^13.12.0, @stoplight/types@npm:^13.15.0, @stoplight/types@npm:^13.6.0": version: 13.20.0 resolution: "@stoplight/types@npm:13.20.0" dependencies: @@ -16462,6 +16462,16 @@ __metadata: languageName: node linkType: hard +"@stoplight/types@npm:^14.0.0": + version: 14.0.0 + resolution: "@stoplight/types@npm:14.0.0" + dependencies: + "@types/json-schema": ^7.0.4 + utility-types: ^3.10.0 + checksum: 462fb6c718a2679927421ca1fffb5e31be2d150130e95a2771ffba04f68fc0e0f8ef3d4ae050e63fd4044bc4103e2ea82c98e1f5c7ff192a78914838eb250e5e + languageName: node + linkType: hard + "@stoplight/types@npm:~13.6.0": version: 13.6.0 resolution: "@stoplight/types@npm:13.6.0" From 0699cf25dfafc19737847bb75b74262760629a28 Mon Sep 17 00:00:00 2001 From: Tiago Barbosa Date: Mon, 27 Nov 2023 14:10:17 +0000 Subject: [PATCH 134/261] resolving package version conflict Signed-off-by: Tiago Barbosa Signed-off-by: Tiago Barbosa --- plugins/pagerduty/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/pagerduty/package.json b/plugins/pagerduty/package.json index 04326b2ec3..48bab25db5 100644 --- a/plugins/pagerduty/package.json +++ b/plugins/pagerduty/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-pagerduty", "description": "This package has been deprecated, consider using [@pagerduty/backstage-plugin](https://github.com/pagerduty/backstage-plugin) instead.", - "version": "0.6.7", + "version": "0.6.9-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", From 04a7cbdc035dc26cfe88730bbdb47bfecee6f082 Mon Sep 17 00:00:00 2001 From: Tiago Barbosa Date: Mon, 27 Nov 2023 14:12:55 +0000 Subject: [PATCH 135/261] resolving description conflict for plugin Signed-off-by: Tiago Barbosa --- plugins/pagerduty/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/pagerduty/package.json b/plugins/pagerduty/package.json index 48bab25db5..7dc2e5af13 100644 --- a/plugins/pagerduty/package.json +++ b/plugins/pagerduty/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-pagerduty", - "description": "This package has been deprecated, consider using [@pagerduty/backstage-plugin](https://github.com/pagerduty/backstage-plugin) instead.", + "description": "This plugin has been deprecated, consider using [@pagerduty/backstage-plugin](https://github.com/pagerduty/backstage-plugin) instead.", "version": "0.6.9-next.0", "main": "src/index.ts", "types": "src/index.ts", From 5ef37a9c39b6395606a63b810b21227cf1619917 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Mon, 27 Nov 2023 15:26:42 +0100 Subject: [PATCH 136/261] test: fix route tracker skipped test Co-authored-by: Patrik Oldsberg Signed-off-by: Camila Belo --- .../src/routing/RouteTracker.test.tsx | 32 +++++-- .../src/routing/RouteTracker.tsx | 2 +- .../extractRouteInfoFromAppNode.test.ts | 85 +++++++++++++++++-- 3 files changed, 103 insertions(+), 16 deletions(-) diff --git a/packages/frontend-app-api/src/routing/RouteTracker.test.tsx b/packages/frontend-app-api/src/routing/RouteTracker.test.tsx index 0696b533df..0e66d0e50d 100644 --- a/packages/frontend-app-api/src/routing/RouteTracker.test.tsx +++ b/packages/frontend-app-api/src/routing/RouteTracker.test.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ import { TestApiProvider } from '@backstage/test-utils'; -import React from 'react'; +import React, { useEffect } from 'react'; import { BackstageRouteObject } from './types'; import { fireEvent, render } from '@testing-library/react'; import { RouteTracker } from './RouteTracker'; @@ -25,6 +25,7 @@ import { AnalyticsApi, analyticsApiRef, AppNode, + useAnalytics, } from '@backstage/frontend-plugin-api'; import { MATCH_ALL_ROUTE } from './extractRouteInfoFromAppNode'; @@ -186,31 +187,46 @@ describe('RouteTracker', () => { }); }); - it.skip('should return default context when it would have otherwise matched on the root path', async () => { + it('should return default context when it would have otherwise matched on the root path', async () => { + const Dummy = () => { + const analytics = useAnalytics(); + useEffect(() => { + analytics.captureEvent('click', 'test', {}); + }, [analytics]); + return
dummy
; + }; + render( - Non-extension} - /> + } /> , ); - expect(mockedAnalytics.captureEvent).toHaveBeenCalledWith({ + expect(mockedAnalytics.captureEvent).toHaveBeenNthCalledWith(1, { action: 'navigate', attributes: {}, context: { - extension: 'App', + extensionId: 'App', pluginId: 'root', }, subject: '/not-routable-extension', value: undefined, }); + expect(mockedAnalytics.captureEvent).toHaveBeenNthCalledWith(2, { + action: 'click', + attributes: undefined, + context: { + extensionId: 'App', + pluginId: 'root', + }, + subject: 'test', + value: undefined, + }); }); it('should return parent route context on navigating to a sub-route', async () => { diff --git a/packages/frontend-app-api/src/routing/RouteTracker.tsx b/packages/frontend-app-api/src/routing/RouteTracker.tsx index 7bceb05cf9..8cddca5c68 100644 --- a/packages/frontend-app-api/src/routing/RouteTracker.tsx +++ b/packages/frontend-app-api/src/routing/RouteTracker.tsx @@ -20,7 +20,7 @@ import { useAnalytics, AnalyticsContext, AnalyticsEventAttributes, -} from '@backstage/core-plugin-api'; +} from '@backstage/frontend-plugin-api'; import { BackstageRouteObject } from './types'; /** diff --git a/packages/frontend-app-api/src/routing/extractRouteInfoFromAppNode.test.ts b/packages/frontend-app-api/src/routing/extractRouteInfoFromAppNode.test.ts index 112e1435ae..c94a06a442 100644 --- a/packages/frontend-app-api/src/routing/extractRouteInfoFromAppNode.test.ts +++ b/packages/frontend-app-api/src/routing/extractRouteInfoFromAppNode.test.ts @@ -19,6 +19,7 @@ import { BackstagePlugin } from '@backstage/core-plugin-api'; import { extractRouteInfoFromAppNode } from './extractRouteInfoFromAppNode'; import { AnyRouteRefParams, + AppNode, Extension, RouteRef, coreExtensionData, @@ -99,8 +100,10 @@ function routeObj( children: any[] = [], type: 'mounted' | 'gathered' = 'mounted', backstagePlugin?: BackstagePlugin, + appNode?: AppNode, ) { return { + appNode, path: path, caseSensitive: false, element: type, @@ -171,7 +174,14 @@ describe('discovery', () => { [ref5, ref1], ]); expect(info.routeObjects).toEqual([ - routeObj('nothing', []), + routeObj( + 'nothing', + [], + undefined, + undefined, + undefined, + expect.any(Object), + ), routeObj( 'foo', [ref1], @@ -179,16 +189,41 @@ describe('discovery', () => { routeObj( 'bar/:id', [ref2], - [routeObj('baz', [ref3], undefined, undefined, expect.any(Object))], + [ + routeObj( + 'baz', + [ref3], + undefined, + undefined, + expect.any(Object), + expect.any(Object), + ), + ], undefined, expect.any(Object), + expect.any(Object), + ), + routeObj( + 'blop', + [ref5], + undefined, + undefined, + expect.any(Object), + expect.any(Object), ), - routeObj('blop', [ref5], undefined, undefined, expect.any(Object)), ], undefined, expect.any(Object), + expect.any(Object), + ), + routeObj( + 'divsoup', + [ref4], + undefined, + undefined, + expect.any(Object), + expect.any(Object), ), - routeObj('divsoup', [ref4], undefined, undefined, expect.any(Object)), ]); }); @@ -349,13 +384,30 @@ describe('discovery', () => { [ref5, ref3], ]); expect(info.routeObjects).toEqual([ - routeObj('foo', [ref1, ref2], [], 'mounted', expect.any(Object)), + routeObj( + 'foo', + [ref1, ref2], + [], + 'mounted', + expect.any(Object), + expect.any(Object), + ), routeObj( 'bar', [ref3], - [routeObj('', [ref4, ref5], [], 'mounted', expect.any(Object))], + [ + routeObj( + '', + [ref4, ref5], + [], + 'mounted', + expect.any(Object), + expect.any(Object), + ), + ], 'mounted', expect.any(Object), + expect.any(Object), ), ]); }); @@ -429,18 +481,22 @@ describe('discovery', () => { undefined, undefined, expect.any(Object), + expect.any(Object), ), ], undefined, expect.any(Object), + expect.any(Object), ), ], 'mounted', expect.any(Object), + expect.any(Object), ), ], undefined, expect.any(Object), + expect.any(Object), ), ]); }); @@ -499,7 +555,14 @@ describe('discovery', () => { 'r', [], [ - routeObj('x', [ref1], [], 'mounted', expect.any(Object)), + routeObj( + 'x', + [ref1], + [], + 'mounted', + expect.any(Object), + expect.any(Object), + ), routeObj( 'y', [], @@ -514,6 +577,7 @@ describe('discovery', () => { undefined, 'mounted', expect.any(Object), + expect.any(Object), ), routeObj( 'b', @@ -521,15 +585,22 @@ describe('discovery', () => { undefined, 'mounted', expect.any(Object), + expect.any(Object), ), ], 'mounted', expect.any(Object), + expect.any(Object), ), ], 'mounted', + undefined, + expect.any(Object), ), ], + undefined, + undefined, + expect.any(Object), ), ]); }); From 2aee53bbeb8a5be9990cf220cd4937b7ee72b822 Mon Sep 17 00:00:00 2001 From: Federico Morreale Date: Mon, 27 Nov 2023 16:17:46 +0100 Subject: [PATCH 137/261] fix: add slider if stepper overflows Signed-off-by: Federico Morreale --- .changeset/perfect-crabs-help.md | 5 +++++ .../src/next/components/Stepper/Stepper.tsx | 7 ++++++- .../src/next/components/TaskSteps/TaskSteps.tsx | 1 + 3 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 .changeset/perfect-crabs-help.md diff --git a/.changeset/perfect-crabs-help.md b/.changeset/perfect-crabs-help.md new file mode 100644 index 0000000000..831649ffe7 --- /dev/null +++ b/.changeset/perfect-crabs-help.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-react': patch +--- + +Add horizontal slider if stepper overflows diff --git a/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx b/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx index 5aaf76316c..a0b06c0e69 100644 --- a/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx +++ b/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx @@ -190,7 +190,12 @@ export const Stepper = (stepperProps: StepperProps) => { return ( <> {isValidating && } - + {steps.map((step, index) => { const isAllowedLabelClick = activeStep > index; return ( diff --git a/plugins/scaffolder-react/src/next/components/TaskSteps/TaskSteps.tsx b/plugins/scaffolder-react/src/next/components/TaskSteps/TaskSteps.tsx index 96f0d9d865..d74d298778 100644 --- a/plugins/scaffolder-react/src/next/components/TaskSteps/TaskSteps.tsx +++ b/plugins/scaffolder-react/src/next/components/TaskSteps/TaskSteps.tsx @@ -58,6 +58,7 @@ export const TaskSteps = (props: TaskStepsProps) => { activeStep={props.activeStep} alternativeLabel variant="elevation" + style={{ overflowX: 'auto' }} > {props.steps.map(step => { const isCompleted = step.status === 'completed'; From 705fa5b5496891bc86f72f600fa7e922fa579d41 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Mon, 27 Nov 2023 16:01:41 +0100 Subject: [PATCH 138/261] docs: update frontend-plugin-api report Signed-off-by: Camila Belo --- packages/frontend-plugin-api/api-report.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/frontend-plugin-api/api-report.md b/packages/frontend-plugin-api/api-report.md index d4acc4b5b7..c1c920559e 100644 --- a/packages/frontend-plugin-api/api-report.md +++ b/packages/frontend-plugin-api/api-report.md @@ -281,8 +281,7 @@ export { bitbucketServerAuthApiRef }; // @public export type CommonAnalyticsContext = { pluginId: string; - routeRef: string; - extension: string; + extensionId: string; }; export { ConfigApi }; From 1def17fd023171740e036d0759bb6a422997a860 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Mon, 27 Nov 2023 16:11:43 +0100 Subject: [PATCH 139/261] refactor: use apis provider on the analytics context test Signed-off-by: Camila Belo --- .../src/analytics/useAnalytics.test.tsx | 33 ++++++++----------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/packages/frontend-plugin-api/src/analytics/useAnalytics.test.tsx b/packages/frontend-plugin-api/src/analytics/useAnalytics.test.tsx index 630ce0331a..beb16b1fbb 100644 --- a/packages/frontend-plugin-api/src/analytics/useAnalytics.test.tsx +++ b/packages/frontend-plugin-api/src/analytics/useAnalytics.test.tsx @@ -16,36 +16,31 @@ import { renderHook } from '@testing-library/react'; import { useAnalytics } from './useAnalytics'; -import { useApi } from '@backstage/core-plugin-api'; - -jest.mock('@backstage/core-plugin-api', () => ({ - ...jest.requireActual('@backstage/core-plugin-api'), - useApi: jest.fn(), -})); - -const mocked = (f: Function) => f as jest.Mock; +import { analyticsApiRef } from '@backstage/core-plugin-api'; +import { TestApiProvider } from '@backstage/test-utils'; +import React from 'react'; describe('useAnalytics', () => { it('returns tracker with no implementation defined', () => { - // Simulate useApi() throwing an error. - mocked(useApi).mockImplementation(() => { - throw new Error(); - }); - - // Result should still have a captureEvent method. - const { result } = renderHook(() => useAnalytics()); + // useApi throws an error because the Analytics API is not implemented + // But the result should still have a captureEvent method. + const { result } = renderHook(() => useAnalytics(), {}); expect(result.current.captureEvent).toBeDefined(); }); it('returns tracker from defined analytics api', () => { const captureEvent = jest.fn(); - // Simulate useApi returning a valid tracker. - mocked(useApi).mockReturnValue({ captureEvent }); - // Calling the captureEvent method of the underlying implementation should // pass along the given event as well as the default context. - const { result } = renderHook(() => useAnalytics()); + const { result } = renderHook(() => useAnalytics(), { + wrapper: ({ children }) => ( + // Simulate useApi returning a valid tracker. + + {children} + + ), + }); result.current.captureEvent('an action', 'a subject', { value: 42, attributes: { some: 'value' }, From d535229fe465adb267909469c92c4e45111f2739 Mon Sep 17 00:00:00 2001 From: Philipp Hugenroth Date: Mon, 27 Nov 2023 16:25:20 +0100 Subject: [PATCH 140/261] Improve code examples Signed-off-by: Philipp Hugenroth --- docs/tutorials/migrate-to-mui5.md | 49 ++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/docs/tutorials/migrate-to-mui5.md b/docs/tutorials/migrate-to-mui5.md index cda662be7d..96129ceb8a 100644 --- a/docs/tutorials/migrate-to-mui5.md +++ b/docs/tutorials/migrate-to-mui5.md @@ -9,31 +9,46 @@ Backstage supports developing new plugins or components using Material UI v5. At By default, the `UnifiedThemeProvider` is already used. If you add a custom theme in your `createApp` function, you would need to replace the Material UI `ThemeProvider` with the `UnifiedThemeProvider`: ```diff ts -const app = createApp({ - // ... - themes: [ - { - // ... - provider: ({ children }) => ( -- . -- {children}. -- - ), - } - ] -}); ++ import import { ++ UnifiedThemeProvider, ++ themes as builtinThemes, ++ } from '@backstage/theme'; + + const app = createApp({ + // ... + themes: [ + { + // ... + provider: ({ children }) => ( +- . +- {children}. +- + ), + } + ] + }); ``` Before making specific changes to your Backstage instance, it might be helpful to take a look at the [Migration Guide provided by Material UI](https://mui.com/material-ui/migration/migration-v4/) first. It breaks down the differences between v4 and v5, and will make it easier to understand the impact on your Backstage instance & plugins. It is worth noting that we are still using `@mui/styles` & `jss`. You may stumble upon documentation for migrating to `emotion` when using `makeStyles` or `withStyles`. It is not necessary to switch to `emotion`. +Important to keep in mind is that Material UI v5 is meant to be used with React Version 17 or higher. This means if you intend to use the Material UI v5 components in your plugins, you have to enforce React Version to be at least 17 for these plugins: + +```json +... + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0", + "react-router-dom": "6.0.0-beta.0 || ^6.3.0" + }, +... +``` + To comply with Material UI recommendations, we are enforcing a new linting rule that favors standard imports over named imports and also restricts 3rd-level imports as they are considered private ([Guide: Minimizing Bundle Size](https://mui.com/material-ui/guides/minimizing-bundle-size)). -Important to keep in mind is that Material UI v5 is meant to be used with React Version 17 or higher. This means if you intend to use the Material UI v5 components in your plugins, you have to enforce React Version to be at least 17 for these plugins as well. - -There are `core-components` as well as components exported from `*-react` plugins written in Material UI v4, which expect Material UI components as props. In these cases you will still be forced to import Material UI v4 components. +There are `core-components` as well as components exported from Backstage `*-react` plugins written in Material UI v4, which expect Material UI components as props. In these cases you will still be forced to use Material UI v4. For current known issues with the Material UI v5 migration, follow our [Milestone on GitHub](https://github.com/backstage/backstage/milestone/40). Please open a new issue if you run into different problems. From 7b7ba510fe11cef79646ee5fbee79e2aeda204a3 Mon Sep 17 00:00:00 2001 From: Tiago Barbosa Date: Mon, 27 Nov 2023 15:44:50 +0000 Subject: [PATCH 141/261] fix(api-report): :bug: fixed issue with character escaping in api-report generation fixed issue with character escaping in api-report generation Signed-off-by: Tiago Barbosa --- plugins/pagerduty/api-report.md | 8 ++++---- plugins/pagerduty/src/plugin.ts | 6 +++--- plugins/pagerduty/src/types.ts | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/plugins/pagerduty/api-report.md b/plugins/pagerduty/api-report.md index db73259dd5..a96cab1af1 100644 --- a/plugins/pagerduty/api-report.md +++ b/plugins/pagerduty/api-report.md @@ -16,7 +16,7 @@ import { JSX as JSX_2 } from 'react'; import { default as React_2 } from 'react'; import { ReactNode } from 'react'; -// @public (undocumented) +// @public @deprecated (undocumented) export const EntityPagerDutyCard: ( props: EntityPagerDutyCardProps, ) => JSX_2.Element; @@ -27,7 +27,7 @@ export type EntityPagerDutyCardProps = { disableChangeEvents?: boolean; }; -// @public (undocumented) +// @public @deprecated (undocumented) export const HomePagePagerDutyCard: ( props: CardExtensionProps, ) => JSX_2.Element; @@ -138,7 +138,7 @@ export type PagerDutyClientApiDependencies = { fetchApi: FetchApi; }; -// @public (undocumented) +// @public @deprecated (undocumented) export type PagerDutyEntity = { integrationKey?: string; serviceId?: string; @@ -176,7 +176,7 @@ export type PagerDutyOnCallsResponse = { oncalls: PagerDutyOnCall[]; }; -// @public (undocumented) +// @public @deprecated (undocumented) const pagerDutyPlugin: BackstagePlugin<{}, {}>; export { pagerDutyPlugin }; export { pagerDutyPlugin as plugin }; diff --git a/plugins/pagerduty/src/plugin.ts b/plugins/pagerduty/src/plugin.ts index 22f8ae60ee..4144eb5878 100644 --- a/plugins/pagerduty/src/plugin.ts +++ b/plugins/pagerduty/src/plugin.ts @@ -32,7 +32,7 @@ export const rootRouteRef = createRouteRef({ /** * @public - * @deprecated This plugin will be removed in a future release. Please use @pagerduty/backstage-plugin plugin instead (https://www.npmjs.com/package/@pagerduty/backstage-plugin). + * @deprecated This plugin will be removed in a future release. Please use \@pagerduty/backstage-plugin plugin instead (https://www.npmjs.com/package/\@pagerduty/backstage-plugin). */ export const pagerDutyPlugin = createPlugin({ id: 'pagerduty', @@ -52,7 +52,7 @@ export const pagerDutyPlugin = createPlugin({ /** * @public - * @deprecated This plugin and it's cards will be removed in a future release. Please use @pagerduty/backstage-plugin plugin instead (https://www.npmjs.com/package/@pagerduty/backstage-plugin). + * @deprecated This plugin and it's cards will be removed in a future release. Please use \@pagerduty/backstage-plugin plugin instead (https://www.npmjs.com/package/\@pagerduty/backstage-plugin). */ export const EntityPagerDutyCard = pagerDutyPlugin.provide( createComponentExtension({ @@ -68,7 +68,7 @@ export const EntityPagerDutyCard = pagerDutyPlugin.provide( /** * @public - * @deprecated This plugin and it's cards will be removed in a future release. Please use @pagerduty/backstage-plugin plugin instead (https://www.npmjs.com/package/@pagerduty/backstage-plugin). + * @deprecated This plugin and it's cards will be removed in a future release. Please use \@pagerduty/backstage-plugin plugin instead (https://www.npmjs.com/package/\@pagerduty/backstage-plugin). */ export const HomePagePagerDutyCard = pagerDutyPlugin.provide( createCardExtension({ diff --git a/plugins/pagerduty/src/types.ts b/plugins/pagerduty/src/types.ts index 3ecfb4e745..e026a6ffbe 100644 --- a/plugins/pagerduty/src/types.ts +++ b/plugins/pagerduty/src/types.ts @@ -16,7 +16,7 @@ /** * @public - * @deprecated This plugin and it's types will be removed in a future release. Please use @pagerduty/backstage-plugin plugin instead (https://www.npmjs.com/package/@pagerduty/backstage-plugin). + * @deprecated This plugin and it's types will be removed in a future release. Please use \@pagerduty/backstage-plugin plugin instead (https://www.npmjs.com/package/\@pagerduty/backstage-plugin). */ export type PagerDutyEntity = { integrationKey?: string; From 418e6bc1338150e874c2b9f31bcce526ac72a5a9 Mon Sep 17 00:00:00 2001 From: Federico Morreale Date: Mon, 27 Nov 2023 17:17:31 +0100 Subject: [PATCH 142/261] refactor: apply overflow on default theme Signed-off-by: Federico Morreale --- packages/theme/src/v5/defaultComponentThemes.ts | 7 +++++++ .../src/next/components/Stepper/Stepper.tsx | 7 +------ .../src/next/components/TaskSteps/TaskSteps.tsx | 1 - 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/packages/theme/src/v5/defaultComponentThemes.ts b/packages/theme/src/v5/defaultComponentThemes.ts index e484300818..80e57aa4df 100644 --- a/packages/theme/src/v5/defaultComponentThemes.ts +++ b/packages/theme/src/v5/defaultComponentThemes.ts @@ -239,4 +239,11 @@ export const defaultComponentThemes: ThemeOptions['components'] = { underline: 'hover', }, }, + MuiStepper: { + styleOverrides: { + root: { + overflowX: 'auto', + }, + }, + }, }; diff --git a/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx b/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx index a0b06c0e69..5aaf76316c 100644 --- a/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx +++ b/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx @@ -190,12 +190,7 @@ export const Stepper = (stepperProps: StepperProps) => { return ( <> {isValidating && } - + {steps.map((step, index) => { const isAllowedLabelClick = activeStep > index; return ( diff --git a/plugins/scaffolder-react/src/next/components/TaskSteps/TaskSteps.tsx b/plugins/scaffolder-react/src/next/components/TaskSteps/TaskSteps.tsx index d74d298778..96f0d9d865 100644 --- a/plugins/scaffolder-react/src/next/components/TaskSteps/TaskSteps.tsx +++ b/plugins/scaffolder-react/src/next/components/TaskSteps/TaskSteps.tsx @@ -58,7 +58,6 @@ export const TaskSteps = (props: TaskStepsProps) => { activeStep={props.activeStep} alternativeLabel variant="elevation" - style={{ overflowX: 'auto' }} > {props.steps.map(step => { const isCompleted = step.status === 'completed'; From a285f41e4c2d96f6ca752d3ef0902345e5a19f9a Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 27 Nov 2023 19:25:34 +0100 Subject: [PATCH 143/261] Update .changeset/modern-mails-live.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Fredrik Adelöw Signed-off-by: Patrik Oldsberg --- .changeset/modern-mails-live.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/modern-mails-live.md b/.changeset/modern-mails-live.md index 82155c44d5..f8e12e8815 100644 --- a/.changeset/modern-mails-live.md +++ b/.changeset/modern-mails-live.md @@ -2,4 +2,4 @@ '@backstage/frontend-test-utils': patch --- -Re-export mock API implementations as well as `TestApiProvider`, TestApiRegistry`, `withLogCollector`and`setupRequestMockHandlers`froom`@backstage/test-utils`. +Re-export mock API implementations as well as `TestApiProvider`, `TestApiRegistry`, `withLogCollector`, and `setupRequestMockHandlers` from `@backstage/test-utils`. From 08d7e4676ad0d76bc3856de94fbd1afa8f68c226 Mon Sep 17 00:00:00 2001 From: Lillian Bose <69570539+blbose@users.noreply.github.com> Date: Tue, 28 Nov 2023 00:25:41 +0530 Subject: [PATCH 144/261] feat: GH Workflow Runs as Card View (#20939) * feat: GH Workflow Runs as Card View Signed-off-by: blbose * feat: GH Workflow Runs as Card View Signed-off-by: blbose * feat: GH Workflow Runs as Card View Signed-off-by: blbose * fix dagda1 github link in OWNERS.md Signed-off-by: Paul Cowan Signed-off-by: blbose * Added description for publish:gerrit scaffolder actions Signed-off-by: Andy Muldoon Signed-off-by: blbose * Add existing OpenCost plugin to the Backstage Plugin Directory Signed-off-by: Matt Ray Signed-off-by: blbose * Squared Penny the Pig logo Signed-off-by: Matt Ray Signed-off-by: blbose * chore(deps): update dependency @types/supertest to v2.0.15 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Signed-off-by: blbose * chore(deps): update dependency @types/stoppable to v1.1.2 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Signed-off-by: blbose * chore(deps): update dependency @types/rollup-plugin-peer-deps-external to v2.2.3 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Signed-off-by: blbose * chore(deps): update dependency @types/regression to v2.0.4 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Signed-off-by: blbose * chore(deps): update dependency @types/recursive-readdir to v2.2.3 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Signed-off-by: blbose * chore(deps): update dependency @types/recharts to v1.8.26 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Signed-off-by: blbose * chore(deps): update dependency @types/luxon to v3.3.3 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Signed-off-by: blbose * chore(deps): update dependency @types/swagger-ui-react to v4.18.2 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Signed-off-by: blbose * chore(deps): update dependency @types/tar to v6.1.7 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Signed-off-by: blbose * chore(deps): update dependency @types/xml2js to v0.4.13 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Signed-off-by: blbose * feat: GH Workflow Runs as Card View Signed-off-by: blbose * feat: GH Workflow Runs as Card View Signed-off-by: blbose * feat: GH Workflow Runs as Card View Signed-off-by: blbose * feat: GH Workflow Runs as Card View Signed-off-by: blbose * feat: GH Workflow Runs as Card View Signed-off-by: blbose * feat: GH Workflow Runs as Card View Signed-off-by: blbose * file mode changes revert Signed-off-by: blbose * api-report warning fix Signed-off-by: blbose * fix: UX perspective changes Signed-off-by: blbose * fix:eslint warning removal Signed-off-by: blbose * fix:avoiding of id based on acierto review Signed-off-by: blbose * fix: latest review comments Signed-off-by: blbose * fix: review comment changes from Freben Signed-off-by: blbose * fix: review comment changes from Freben Signed-off-by: blbose * fix: rebase conflict Signed-off-by: blbose * fix: rebase conflicts Signed-off-by: blbose * fix: rebase conflict Signed-off-by: blbose * fix: rebase conflicts Signed-off-by: blbose * fix: rebase conflict Signed-off-by: blbose * fix: rebase conflicts Signed-off-by: blbose * fix: rebase conflict Signed-off-by: blbose * fix: rebase conflicts Signed-off-by: blbose * fix: rebase conflict Signed-off-by: blbose * fix: rebase conflicts Signed-off-by: blbose * fix: rebase conflict Signed-off-by: blbose * fix: rebase conflicts Signed-off-by: blbose * fix: rebase conflict Signed-off-by: blbose * fix: rebase conflicts Signed-off-by: blbose --------- Signed-off-by: blbose Signed-off-by: Paul Cowan Signed-off-by: Andy Muldoon Signed-off-by: Matt Ray Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Paul Cowan Co-authored-by: Andy Muldoon Co-authored-by: Matt Ray Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .changeset/khaki-hounds-think.md | 5 + plugins/github-actions/README.md | 16 + plugins/github-actions/api-report.md | 53 ++- plugins/github-actions/dev/index.tsx | 6 + plugins/github-actions/docs/card-view.png | Bin 0 -> 211144 bytes .../src/api/GithubActionsApi.ts | 17 + .../src/api/GithubActionsClient.ts | 37 ++ plugins/github-actions/src/api/types.ts | 16 + .../github-actions/src/components/Router.tsx | 16 +- .../WorkflowRunsCard/WorkflowRunsCard.tsx | 412 ++++++++++++++++++ .../src/components/WorkflowRunsCard/index.ts | 16 + .../src/components/useWorkflowRuns.ts | 50 ++- 12 files changed, 635 insertions(+), 9 deletions(-) create mode 100644 .changeset/khaki-hounds-think.md create mode 100644 plugins/github-actions/docs/card-view.png create mode 100644 plugins/github-actions/src/components/WorkflowRunsCard/WorkflowRunsCard.tsx create mode 100644 plugins/github-actions/src/components/WorkflowRunsCard/index.ts diff --git a/.changeset/khaki-hounds-think.md b/.changeset/khaki-hounds-think.md new file mode 100644 index 0000000000..9c7145fc89 --- /dev/null +++ b/.changeset/khaki-hounds-think.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-github-actions': patch +--- + +Github Workflow Runs UI is modified to show in optional Card view instead of table, with branch selection option diff --git a/plugins/github-actions/README.md b/plugins/github-actions/README.md index b94862db2b..d0b5ceb54d 100644 --- a/plugins/github-actions/README.md +++ b/plugins/github-actions/README.md @@ -92,3 +92,19 @@ integrations: - There is a limit of 100 apps for one OAuth client/token pair - The OAuth application must be at the GitHub organization level in order to display the workflows. If you do not see any workflows, confirm the OAuth application was created in the organization and not a specific user account. + +## Optional Workflow Runs Card View + +Github Workflow Runs optional UI to show in Card view instead of table, with branch selection option + +```tsx + +// You can add the tab to any number of pages, the service page is shown as an +// example given here +const serviceEntityPage = ( + + {/* other tabs... */} + + + +``` diff --git a/plugins/github-actions/api-report.md b/plugins/github-actions/api-report.md index 887556f431..7a7eb4e972 100644 --- a/plugins/github-actions/api-report.md +++ b/plugins/github-actions/api-report.md @@ -16,6 +16,17 @@ import { RestEndpointMethodTypes } from '@octokit/rest'; import { RouteRef } from '@backstage/core-plugin-api'; import { ScmAuthApi } from '@backstage/integration-react'; +// @public (undocumented) +export type Branch = { + name: string; +}; + +// @public (undocumented) +export type Branches = { + default_branch: string; + branches: Branch[]; +}; + // @public (undocumented) export enum BuildStatus { // (undocumented) @@ -29,7 +40,7 @@ export enum BuildStatus { } // @public (undocumented) -export const EntityGithubActionsContent: () => JSX_2.Element; +export const EntityGithubActionsContent: (props: RouterProps) => JSX_2.Element; // @public (undocumented) export const EntityLatestGithubActionRunCard: (props: { @@ -106,6 +117,21 @@ export type GithubActionsApi = { }) => Promise< RestEndpointMethodTypes['actions']['downloadJobLogsForWorkflowRun']['response']['data'] >; + listBranches: (options: { + hostname?: string; + owner: string; + repo: string; + page: number; + }) => Promise< + RestEndpointMethodTypes['repos']['listBranches']['response']['data'] + >; + getDefaultBranch: (options: { + hostname?: string; + owner: string; + repo: string; + }) => Promise< + RestEndpointMethodTypes['repos']['get']['response']['data']['default_branch'] + >; }; // @public (undocumented) @@ -124,6 +150,14 @@ export class GithubActionsClient implements GithubActionsApi { RestEndpointMethodTypes['actions']['downloadJobLogsForWorkflowRun']['response']['data'] >; // (undocumented) + getDefaultBranch(options: { + hostname?: string; + owner: string; + repo: string; + }): Promise< + RestEndpointMethodTypes['repos']['get']['response']['data']['default_branch'] + >; + // (undocumented) getWorkflow(options: { hostname?: string; owner: string; @@ -142,6 +176,15 @@ export class GithubActionsClient implements GithubActionsApi { RestEndpointMethodTypes['actions']['getWorkflowRun']['response']['data'] >; // (undocumented) + listBranches(options: { + hostname?: string; + owner: string; + repo: string; + page?: number; + }): Promise< + RestEndpointMethodTypes['repos']['listBranches']['response']['data'] + >; + // (undocumented) listJobsForWorkflowRun(options: { hostname?: string; owner: string; @@ -226,7 +269,13 @@ export const RecentWorkflowRunsCard: (props: { }) => React_2.JSX.Element; // @public (undocumented) -export const Router: () => React_2.JSX.Element; +export const Router: (props: RouterProps) => React_2.JSX.Element; + +// @public (undocumented) +export interface RouterProps { + // (undocumented) + view?: 'cards' | 'table'; +} // @public (undocumented) export type Step = { diff --git a/plugins/github-actions/dev/index.tsx b/plugins/github-actions/dev/index.tsx index 153478ddbc..8321d33930 100644 --- a/plugins/github-actions/dev/index.tsx +++ b/plugins/github-actions/dev/index.tsx @@ -63,6 +63,12 @@ const mockGithubActionsApi: GithubActionsApi = { async reRunWorkflow() { return {} as any; }, + async listBranches() { + return {} as any; + }, + async getDefaultBranch() { + return {} as any; + }, }; createDevApp() diff --git a/plugins/github-actions/docs/card-view.png b/plugins/github-actions/docs/card-view.png new file mode 100644 index 0000000000000000000000000000000000000000..ef59c294d47b5257fce90d24ba5d9907a31350bc GIT binary patch literal 211144 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 z%0D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�ucBLYP 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 literal 0 HcmV?d00001 diff --git a/plugins/github-actions/src/api/GithubActionsApi.ts b/plugins/github-actions/src/api/GithubActionsApi.ts index 14dbc3210e..6d3b25f93d 100644 --- a/plugins/github-actions/src/api/GithubActionsApi.ts +++ b/plugins/github-actions/src/api/GithubActionsApi.ts @@ -83,4 +83,21 @@ export type GithubActionsApi = { }) => Promise< RestEndpointMethodTypes['actions']['downloadJobLogsForWorkflowRun']['response']['data'] >; + + listBranches: (options: { + hostname?: string; + owner: string; + repo: string; + page: number; + }) => Promise< + RestEndpointMethodTypes['repos']['listBranches']['response']['data'] + >; + + getDefaultBranch: (options: { + hostname?: string; + owner: string; + repo: string; + }) => Promise< + RestEndpointMethodTypes['repos']['get']['response']['data']['default_branch'] + >; }; diff --git a/plugins/github-actions/src/api/GithubActionsClient.ts b/plugins/github-actions/src/api/GithubActionsClient.ts index e427c343e2..734326e61b 100644 --- a/plugins/github-actions/src/api/GithubActionsClient.ts +++ b/plugins/github-actions/src/api/GithubActionsClient.ts @@ -174,4 +174,41 @@ export class GithubActionsClient implements GithubActionsApi { return workflow.data; } + + async listBranches(options: { + hostname?: string; + owner: string; + repo: string; + page?: number; + }): Promise< + RestEndpointMethodTypes['repos']['listBranches']['response']['data'] + > { + const { hostname, owner, repo, page = 0 } = options; + const octokit = await this.getOctokit(hostname); + const response = await octokit.rest.repos.listBranches({ + owner, + repo, + per_page: 100, + page, + }); + + return response.data; + } + + async getDefaultBranch(options: { + hostname?: string; + owner: string; + repo: string; + }): Promise< + RestEndpointMethodTypes['repos']['get']['response']['data']['default_branch'] + > { + const { hostname, owner, repo } = options; + const octokit = await this.getOctokit(hostname); + const response = await octokit.rest.repos.get({ + owner, + repo, + }); + + return response.data.default_branch; + } } diff --git a/plugins/github-actions/src/api/types.ts b/plugins/github-actions/src/api/types.ts index 2e997d9bf7..394289149b 100644 --- a/plugins/github-actions/src/api/types.ts +++ b/plugins/github-actions/src/api/types.ts @@ -49,3 +49,19 @@ export enum BuildStatus { 'pending', 'running', } + +/** @public */ +export type Branch = { + name: string; +}; + +/** @public */ +export type Branches = { + default_branch: string; + branches: Branch[]; +}; + +/** @public */ +export interface RouterProps { + view?: 'cards' | 'table'; +} diff --git a/plugins/github-actions/src/components/Router.tsx b/plugins/github-actions/src/components/Router.tsx index e9a40f13f4..ff4e6bfa44 100644 --- a/plugins/github-actions/src/components/Router.tsx +++ b/plugins/github-actions/src/components/Router.tsx @@ -23,15 +23,18 @@ import { import { Routes, Route } from 'react-router-dom'; import { buildRouteRef } from '../routes'; import { WorkflowRunDetails } from './WorkflowRunDetails'; +import { WorkflowRunsCard } from './WorkflowRunsCard'; import { WorkflowRunsTable } from './WorkflowRunsTable'; import { GITHUB_ACTIONS_ANNOTATION } from './getProjectNameFromEntity'; +import { RouterProps } from '../api/types'; /** @public */ export const isGithubActionsAvailable = (entity: Entity) => Boolean(entity.metadata.annotations?.[GITHUB_ACTIONS_ANNOTATION]); /** @public */ -export const Router = () => { +export const Router = (props: RouterProps) => { + const { view = 'table' } = props; const { entity } = useEntity(); if (!isGithubActionsAvailable(entity)) { @@ -39,14 +42,21 @@ export const Router = () => { ); } + + const workflowRunsComponent = + view === 'cards' ? ( + + ) : ( + + ); + return ( - } /> + } /> - ) ); }; diff --git a/plugins/github-actions/src/components/WorkflowRunsCard/WorkflowRunsCard.tsx b/plugins/github-actions/src/components/WorkflowRunsCard/WorkflowRunsCard.tsx new file mode 100644 index 0000000000..dc97720736 --- /dev/null +++ b/plugins/github-actions/src/components/WorkflowRunsCard/WorkflowRunsCard.tsx @@ -0,0 +1,412 @@ +/* + * 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 React, { ChangeEvent, useEffect, useState } from 'react'; +import { + Typography, + Box, + IconButton, + Tooltip, + Button, + Chip, + ButtonGroup, + Grid, + makeStyles, + createStyles, + Theme, + TablePagination, + Select, + MenuItem, + TextField, + CircularProgress, +} from '@material-ui/core'; +import { + EmptyState, + Link, + MarkdownContent, + InfoCard, +} from '@backstage/core-components'; +import GitHubIcon from '@material-ui/icons/GitHub'; +import RetryIcon from '@material-ui/icons/Replay'; +import SyncIcon from '@material-ui/icons/Sync'; +import ExternalLinkIcon from '@material-ui/icons/Launch'; +import { useRouteRef } from '@backstage/core-plugin-api'; +import { useWorkflowRuns, WorkflowRun } from '../useWorkflowRuns'; +import { WorkflowRunStatus } from '../WorkflowRunStatus'; +import { buildRouteRef } from '../../routes'; +import { getProjectNameFromEntity } from '../getProjectNameFromEntity'; +import { getHostnameFromEntity } from '../getHostnameFromEntity'; + +import { Alert, Color } from '@material-ui/lab'; +import { Entity } from '@backstage/catalog-model'; + +const useStyles = makeStyles((theme: Theme) => + createStyles({ + card: { + border: `1px solid ${theme.palette.divider}`, + boxShadow: theme.shadows[2], + borderRadius: '4px', + overflow: 'visible', + position: 'relative', + margin: theme.spacing(4, 1, 1), + flex: '1', + minWidth: '0px', + }, + externalLinkIcon: { + fontSize: 'inherit', + verticalAlign: 'middle', + }, + bottomline: { + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + marginTop: '-5px', + }, + pagination: { + width: '100%', + }, + }), +); + +type WorkflowRunsCardViewProps = { + runs?: WorkflowRun[]; + searchTerm: string; + loading: boolean; + onChangePageSize: (pageSize: number) => void; + onChangePage: (page: number) => void; + page: number; + total: number; + pageSize: number; + projectName: string; +}; + +const statusColors: Record = { + skipped: 'warning', + canceled: 'info', + timed_out: 'error', + failure: 'error', + success: 'success', +}; + +const matchesSearchTerm = (run: WorkflowRun, searchTerm: string) => { + const lowerCaseSearchTerm = searchTerm.toLocaleLowerCase(); + return ( + run.workflowName?.toLocaleLowerCase().includes(lowerCaseSearchTerm) || + run.source.branchName?.toLocaleLowerCase().includes(lowerCaseSearchTerm) || + run.status?.toLocaleLowerCase().includes(lowerCaseSearchTerm) || + run.id?.toLocaleLowerCase().includes(lowerCaseSearchTerm) + ); +}; + +export const WorkflowRunsCardView = ({ + runs, + searchTerm, + loading, + onChangePageSize, + onChangePage, + page, + total, + pageSize, +}: WorkflowRunsCardViewProps) => { + const classes = useStyles(); + const routeLink = useRouteRef(buildRouteRef); + + const filteredRuns = runs?.filter(run => matchesSearchTerm(run, searchTerm)); + + return ( + + {filteredRuns && runs?.length !== 0 ? ( + filteredRuns.map(run => ( + + + + + + + + + + {run.workflowName} + + + + + + + + + + + + {run.source.branchName && ( + + )} + + + + + } + /> +
+ {run.githubUrl && ( + + Workflow runs on GitHub{' '} + + + )} + + + + + + + +
+
+
+
+ + )) + ) : ( + + {loading ? : 'No matching runs found.'} + + )} +
+ onChangePage(newPage)} + onRowsPerPageChange={event => + onChangePageSize(parseInt(event.target.value, 6)) + } + labelRowsPerPage="Workflows per page" + rowsPerPageOptions={[6, 12, 18, { label: 'All', value: -1 }]} + /> +
+ + ); +}; + +type WorkflowRunsCardProps = { + entity: Entity; +}; + +const WorkflowRunsCardSearch = ({ + searchTerm, + handleSearch, + retry, +}: { + searchTerm: string; + handleSearch: (event: ChangeEvent) => void; + retry: () => void; +}) => { + return ( + <> + + + + + + + + + + + ); +}; + +export const WorkflowRunsCard = ({ entity }: WorkflowRunsCardProps) => { + const projectName = getProjectNameFromEntity(entity); + const hostname = getHostnameFromEntity(entity); + const [owner, repo] = (projectName ?? '/').split('/'); + const [branch, setBranch] = useState('default'); + const [runs, setRuns] = useState([]); + const [searchTerm, setSearchTerm] = useState(''); + + const handleSearch = (event: ChangeEvent) => { + setSearchTerm(event.target.value); + }; + + const [ + { runs: runsData, branches, defaultBranch, ...cardProps }, + { retry, setPage, setPageSize }, + ] = useWorkflowRuns({ + hostname, + owner, + repo, + branch: branch === 'all' ? undefined : branch, + }); + + const githubHost = hostname || 'github.com'; + const hasNoRuns = !cardProps.loading && !runsData; + + const handleMenuChange = ( + event: ChangeEvent<{ name?: string; value: unknown }>, + ) => { + const selectedValue = event.target.value as string; + setBranch(selectedValue); + setPage(0); + retry(); + }; + + useEffect(() => { + setRuns(runsData); + }, [runsData, branch]); + + useEffect(() => { + setBranch(defaultBranch); + }, [defaultBranch]); + + return ( + + {hasNoRuns ? ( + + Create new Workflow + + } + /> + ) : ( + + + + {projectName} + + + + + + } + > + + + )} + + ); +}; + +export default WorkflowRunsCard; diff --git a/plugins/github-actions/src/components/WorkflowRunsCard/index.ts b/plugins/github-actions/src/components/WorkflowRunsCard/index.ts new file mode 100644 index 0000000000..77b4c85664 --- /dev/null +++ b/plugins/github-actions/src/components/WorkflowRunsCard/index.ts @@ -0,0 +1,16 @@ +/* + * 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. + */ +export { WorkflowRunsCard, WorkflowRunsCardView } from './WorkflowRunsCard'; diff --git a/plugins/github-actions/src/components/useWorkflowRuns.ts b/plugins/github-actions/src/components/useWorkflowRuns.ts index 9ffbdad452..aacfabbe2f 100644 --- a/plugins/github-actions/src/components/useWorkflowRuns.ts +++ b/plugins/github-actions/src/components/useWorkflowRuns.ts @@ -17,6 +17,7 @@ import { useState } from 'react'; import useAsyncRetry from 'react-use/lib/useAsyncRetry'; import { githubActionsApiRef } from '../api/GithubActionsApi'; import { useApi, errorApiRef } from '@backstage/core-plugin-api'; +import { Branch } from '../api'; export type WorkflowRun = { workflowName?: string; @@ -41,12 +42,12 @@ export function useWorkflowRuns({ owner, repo, branch, - initialPageSize = 5, + initialPageSize = 6, }: { hostname?: string; owner: string; repo: string; - branch?: string; + branch?: string | undefined; initialPageSize?: number; }) { const api = useApi(githubActionsApiRef); @@ -56,6 +57,8 @@ export function useWorkflowRuns({ const [total, setTotal] = useState(0); const [page, setPage] = useState(0); const [pageSize, setPageSize] = useState(initialPageSize); + const [branches, setBranches] = useState([]); + const [defaultBranch, setDefaultBranch] = useState(''); const { loading, @@ -63,6 +66,43 @@ export function useWorkflowRuns({ retry, error, } = useAsyncRetry(async () => { + const fetchedDefaultBranch = await api.getDefaultBranch({ + hostname, + owner, + repo, + }); + + setDefaultBranch(fetchedDefaultBranch); + let selectedBranch = branch; + if (branch === 'default') { + selectedBranch = fetchedDefaultBranch; + } + + const fetchBranches = async () => { + let next = true; + let iteratePage = 0; + const branchSet: Branch[] = []; + + while (next) { + const branchesData = await api.listBranches({ + hostname, + owner, + repo, + page: iteratePage, + }); + if (branchesData.length === 0) { + next = false; + } + iteratePage++; + branchSet.push(...branchesData); + } + + return branchSet; + }; + + const branchSet = await fetchBranches(); + setBranches(branchSet); + // GitHub API pagination count starts from 1 const workflowRunsData = await api.listWorkflowRuns({ hostname, @@ -70,7 +110,7 @@ export function useWorkflowRuns({ repo, pageSize, page: page + 1, - branch, + branch: selectedBranch, }); setTotal(workflowRunsData.total_count); // Transformation here @@ -88,7 +128,7 @@ export function useWorkflowRuns({ }); } catch (e) { errorApi.post( - new Error(`Failed to rerun the workflow: ${e.message}`), + new Error(`Failed to rerun the workflow: ${(e as Error).message}`), ); } }, @@ -115,6 +155,8 @@ export function useWorkflowRuns({ pageSize, loading, runs, + branches, + defaultBranch, projectName: `${owner}/${repo}`, total, error, From 4050f7776bf8a66d34614d7c423aead0aa4f8577 Mon Sep 17 00:00:00 2001 From: knottAutodesk <143034967+knottAutodesk@users.noreply.github.com> Date: Mon, 27 Nov 2023 12:16:35 -0800 Subject: [PATCH 145/261] Update api.md The link to `The Life of an Entity` was broken. Signed-off-by: knottAutodesk <143034967+knottAutodesk@users.noreply.github.com> --- docs/features/software-catalog/api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/features/software-catalog/api.md b/docs/features/software-catalog/api.md index 3ccd89b286..bbe943daff 100644 --- a/docs/features/software-catalog/api.md +++ b/docs/features/software-catalog/api.md @@ -32,7 +32,7 @@ with a `Bearer` token, which should then be the Backstage token returned by the These are the endpoints that deal with reading of entities directly. What it exposes are final entities - i.e. the output of all processing and the stitching process, not the raw originally ingested entity data. See [The Life of an -Entity](life-of-an-entity.md) for more details about this process and +Entity](https://backstage.io/docs/features/software-catalog/life-of-an-entity) for more details about this process and distinction. ### `GET /entities` From d5f0e991eab3516b14e766590f1caa49a075a585 Mon Sep 17 00:00:00 2001 From: Larry Knott Date: Mon, 27 Nov 2023 13:55:46 -0800 Subject: [PATCH 146/261] Better link fix Signed-off-by: Larry Knott --- docs/features/software-catalog/api.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/features/software-catalog/api.md b/docs/features/software-catalog/api.md index bbe943daff..97d43209d6 100644 --- a/docs/features/software-catalog/api.md +++ b/docs/features/software-catalog/api.md @@ -31,8 +31,8 @@ with a `Bearer` token, which should then be the Backstage token returned by the These are the endpoints that deal with reading of entities directly. What it exposes are final entities - i.e. the output of all processing and the stitching -process, not the raw originally ingested entity data. See [The Life of an -Entity](https://backstage.io/docs/features/software-catalog/life-of-an-entity) for more details about this process and +process, not the raw originally ingested entity data. See +[The Life of an Entity](./life-of-an-entity.md) for more details about this process and distinction. ### `GET /entities` From 1f34975c1d95fb116eb11b601b75625b09491706 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 27 Nov 2023 22:30:50 +0000 Subject: [PATCH 147/261] chore(deps): update helm release postgresql to v13.2.21 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- contrib/chart/backstage/Chart.lock | 6 +++--- contrib/chart/backstage/Chart.yaml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/contrib/chart/backstage/Chart.lock b/contrib/chart/backstage/Chart.lock index b6068caacf..c835a4dcd1 100644 --- a/contrib/chart/backstage/Chart.lock +++ b/contrib/chart/backstage/Chart.lock @@ -1,6 +1,6 @@ dependencies: - name: postgresql repository: https://charts.bitnami.com/bitnami - version: 13.2.12 -digest: sha256:3add6e2f2c055e415403ebbba7740113ee052b87ad72e59b35b301df2098d41e -generated: "2023-11-20T12:09:32.786270903Z" + version: 13.2.21 +digest: sha256:8f8b0fe6c2e8f640237f61dcfab5821865d67753af06a782db7d61372cbbb9b9 +generated: "2023-11-27T22:30:42.837126565Z" diff --git a/contrib/chart/backstage/Chart.yaml b/contrib/chart/backstage/Chart.yaml index 80ff44462c..efd84f1d38 100644 --- a/contrib/chart/backstage/Chart.yaml +++ b/contrib/chart/backstage/Chart.yaml @@ -18,7 +18,7 @@ sources: dependencies: - name: postgresql condition: postgresql.enabled - version: 13.2.12 + version: 13.2.21 repository: https://charts.bitnami.com/bitnami maintainers: From 966eb3c4bf2283952667fa1ac036c71f5fe75284 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 28 Nov 2023 03:38:57 +0000 Subject: [PATCH 148/261] chore(deps): update dependency @types/react to v18.2.39 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index eb70b18813..8d8aa46338 100644 --- a/yarn.lock +++ b/yarn.lock @@ -18944,13 +18944,13 @@ __metadata: linkType: hard "@types/react@npm:^18": - version: 18.2.38 - resolution: "@types/react@npm:18.2.38" + version: 18.2.39 + resolution: "@types/react@npm:18.2.39" dependencies: "@types/prop-types": "*" "@types/scheduler": "*" csstype: ^3.0.2 - checksum: 71f8c167173d32252be8b2d3c1c76b3570b94d2fbbd139da86d146be453626f5777e12c2781559119637520dbef9f91cffe968f67b5901618f29226d49fad326 + checksum: 9bcb1f1f060f1bf8f4730fb1c7772d0323a6e707f274efee3b976c40d92af4677df4d88e9135faaacf34e13e02f92ef24eb7d0cbcf7fb75c1883f5623ccb19f4 languageName: node linkType: hard From 0ffee55010c892c5928cab36fa80d5f382fa29cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Tue, 28 Nov 2023 10:00:54 +0100 Subject: [PATCH 149/261] Toned down the warning message when git is not found MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .changeset/famous-peas-reflect.md | 5 +++++ packages/cli/src/lib/bundler/config.ts | 18 ++++++++++++------ 2 files changed, 17 insertions(+), 6 deletions(-) create mode 100644 .changeset/famous-peas-reflect.md diff --git a/.changeset/famous-peas-reflect.md b/.changeset/famous-peas-reflect.md new file mode 100644 index 0000000000..c8aed3c16b --- /dev/null +++ b/.changeset/famous-peas-reflect.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Toned down the warning message when git is not found diff --git a/packages/cli/src/lib/bundler/config.ts b/packages/cli/src/lib/bundler/config.ts index 542cc83ce9..65c3853bc2 100644 --- a/packages/cli/src/lib/bundler/config.ts +++ b/packages/cli/src/lib/bundler/config.ts @@ -55,18 +55,24 @@ export function resolveBaseUrl(config: Config): URL { async function readBuildInfo() { const timestamp = Date.now(); - let commit = 'unknown'; + let commit: string | unknown; try { commit = await runPlain('git', 'rev-parse', 'HEAD'); } catch (error) { - console.warn(`WARNING: Failed to read git commit, ${error}`); + // ignore, see below } - let gitVersion = 'unknown'; + let gitVersion: string | unknown; try { gitVersion = await runPlain('git', 'describe', '--always'); } catch (error) { - console.warn(`WARNING: Failed to describe git version, ${error}`); + // ignore, see below + } + + if (commit === undefined || gitVersion === undefined) { + console.info( + 'NOTE: Did not compute git version or commit hash, could not execute the git command line utility', + ); } const { version: packageVersion } = await fs.readJson( @@ -75,10 +81,10 @@ async function readBuildInfo() { return { cliVersion: version, - gitVersion, + gitVersion: gitVersion ?? 'unknown', packageVersion, timestamp, - commit, + commit: commit ?? 'unknown', }; } From 2b725913c170504af94df68817dfaf97c0d89de7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 28 Nov 2023 09:15:56 +0000 Subject: [PATCH 150/261] fix(deps): update rjsf monorepo to v5.14.3 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .changeset/renovate-1ed81a0.md | 11 +++++ plugins/home-react/package.json | 2 +- plugins/home/package.json | 8 ++-- plugins/scaffolder-react/package.json | 8 ++-- plugins/scaffolder/package.json | 8 ++-- yarn.lock | 58 +++++++++++++-------------- 6 files changed, 53 insertions(+), 42 deletions(-) create mode 100644 .changeset/renovate-1ed81a0.md diff --git a/.changeset/renovate-1ed81a0.md b/.changeset/renovate-1ed81a0.md new file mode 100644 index 0000000000..ae2e061f24 --- /dev/null +++ b/.changeset/renovate-1ed81a0.md @@ -0,0 +1,11 @@ +--- +'@backstage/plugin-home-react': patch +'@backstage/plugin-home': patch +'@backstage/plugin-scaffolder-react': patch +'@backstage/plugin-scaffolder': patch +--- + +Updated dependency `@rjsf/utils` to `5.14.3`. +Updated dependency `@rjsf/core` to `5.14.3`. +Updated dependency `@rjsf/material-ui` to `5.14.3`. +Updated dependency `@rjsf/validator-ajv8` to `5.14.3`. diff --git a/plugins/home-react/package.json b/plugins/home-react/package.json index cb9a0cd388..08d16b78e4 100644 --- a/plugins/home-react/package.json +++ b/plugins/home-react/package.json @@ -38,7 +38,7 @@ "@backstage/core-plugin-api": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@rjsf/utils": "5.14.2", + "@rjsf/utils": "5.14.3", "@types/react": "^16.13.1 || ^17.0.0" }, "peerDependencies": { diff --git a/plugins/home/package.json b/plugins/home/package.json index 78eaf80fe3..1394b69a62 100644 --- a/plugins/home/package.json +++ b/plugins/home/package.json @@ -61,10 +61,10 @@ "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", - "@rjsf/core": "5.14.2", - "@rjsf/material-ui": "5.14.2", - "@rjsf/utils": "5.14.2", - "@rjsf/validator-ajv8": "5.14.2", + "@rjsf/core": "5.14.3", + "@rjsf/material-ui": "5.14.3", + "@rjsf/utils": "5.14.3", + "@rjsf/validator-ajv8": "5.14.3", "@types/react": "^16.13.1 || ^17.0.0", "lodash": "^4.17.21", "luxon": "^3.4.3", diff --git a/plugins/scaffolder-react/package.json b/plugins/scaffolder-react/package.json index 4a5f619882..ddad8ad8de 100644 --- a/plugins/scaffolder-react/package.json +++ b/plugins/scaffolder-react/package.json @@ -60,10 +60,10 @@ "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", "@react-hookz/web": "^23.0.0", - "@rjsf/core": "5.14.2", - "@rjsf/material-ui": "5.14.2", - "@rjsf/utils": "5.14.2", - "@rjsf/validator-ajv8": "5.14.2", + "@rjsf/core": "5.14.3", + "@rjsf/material-ui": "5.14.3", + "@rjsf/utils": "5.14.3", + "@rjsf/validator-ajv8": "5.14.3", "@types/json-schema": "^7.0.9", "@types/react": "^16.13.1 || ^17.0.0", "classnames": "^2.2.6", diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index d02220059d..8f393c8f29 100644 --- a/plugins/scaffolder/package.json +++ b/plugins/scaffolder/package.json @@ -68,10 +68,10 @@ "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", "@react-hookz/web": "^23.0.0", - "@rjsf/core": "5.14.2", - "@rjsf/material-ui": "5.14.2", - "@rjsf/utils": "5.14.2", - "@rjsf/validator-ajv8": "5.14.2", + "@rjsf/core": "5.14.3", + "@rjsf/material-ui": "5.14.3", + "@rjsf/utils": "5.14.3", + "@rjsf/validator-ajv8": "5.14.3", "@types/react": "^16.13.1 || ^17.0.0", "@uiw/react-codemirror": "^4.9.3", "classnames": "^2.2.6", diff --git a/yarn.lock b/yarn.lock index eb70b18813..224fb198f4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7317,7 +7317,7 @@ __metadata: "@backstage/test-utils": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@rjsf/utils": 5.14.2 + "@rjsf/utils": 5.14.3 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 "@testing-library/react": ^14.0.0 @@ -7354,10 +7354,10 @@ __metadata: "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 "@material-ui/lab": 4.0.0-alpha.61 - "@rjsf/core": 5.14.2 - "@rjsf/material-ui": 5.14.2 - "@rjsf/utils": 5.14.2 - "@rjsf/validator-ajv8": 5.14.2 + "@rjsf/core": 5.14.3 + "@rjsf/material-ui": 5.14.3 + "@rjsf/utils": 5.14.3 + "@rjsf/validator-ajv8": 5.14.3 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 "@testing-library/react": ^14.0.0 @@ -8814,10 +8814,10 @@ __metadata: "@material-ui/icons": ^4.9.1 "@material-ui/lab": 4.0.0-alpha.61 "@react-hookz/web": ^23.0.0 - "@rjsf/core": 5.14.2 - "@rjsf/material-ui": 5.14.2 - "@rjsf/utils": 5.14.2 - "@rjsf/validator-ajv8": 5.14.2 + "@rjsf/core": 5.14.3 + "@rjsf/material-ui": 5.14.3 + "@rjsf/utils": 5.14.3 + "@rjsf/validator-ajv8": 5.14.3 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 "@testing-library/react": ^14.0.0 @@ -8877,10 +8877,10 @@ __metadata: "@material-ui/icons": ^4.9.1 "@material-ui/lab": 4.0.0-alpha.61 "@react-hookz/web": ^23.0.0 - "@rjsf/core": 5.14.2 - "@rjsf/material-ui": 5.14.2 - "@rjsf/utils": 5.14.2 - "@rjsf/validator-ajv8": 5.14.2 + "@rjsf/core": 5.14.3 + "@rjsf/material-ui": 5.14.3 + "@rjsf/utils": 5.14.3 + "@rjsf/validator-ajv8": 5.14.3 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 "@testing-library/react": ^14.0.0 @@ -15085,9 +15085,9 @@ __metadata: languageName: node linkType: hard -"@rjsf/core@npm:5.14.2": - version: 5.14.2 - resolution: "@rjsf/core@npm:5.14.2" +"@rjsf/core@npm:5.14.3": + version: 5.14.3 + resolution: "@rjsf/core@npm:5.14.3" dependencies: lodash: ^4.17.21 lodash-es: ^4.17.21 @@ -15097,20 +15097,20 @@ __metadata: peerDependencies: "@rjsf/utils": ^5.12.x react: ^16.14.0 || >=17 - checksum: 8e3ce39e6c31ae4a72e7d4483f091b77327578ab74a65ebc39c348286d737e0fe829902e0d1218e354bf8a8e8a5055c90aac6c996f386ef7a48546f7d3ea6500 + checksum: 9929ae7b99f1c79dc108095c3338a30fe373cd0fc6c613f65d163f7729cda2509070bb7da581ce3ad068a41ea5050f4e8417508c12e53feb41c56119082d3aac languageName: node linkType: hard -"@rjsf/material-ui@npm:5.14.2": - version: 5.14.2 - resolution: "@rjsf/material-ui@npm:5.14.2" +"@rjsf/material-ui@npm:5.14.3": + version: 5.14.3 + resolution: "@rjsf/material-ui@npm:5.14.3" peerDependencies: "@material-ui/core": ^4.12.3 "@material-ui/icons": ^4.11.2 "@rjsf/core": ^5.12.x "@rjsf/utils": ^5.12.x react: ^16.14.0 || >=17 - checksum: 502cdea7ae9d7d24f9aaee86edc4cc1019e5f956c2446c4f2b5ec377aff31d2d6a6df5c75db54f6fa0d3eb22d855b67e1e8778dfa2b37d88f917098344bbdf08 + checksum: fa9b9a831fa333bb794ccde85f415c8daf18334d975a0f2aa1cd497017e7a03c398d5b4f4209eafd4aed4aa476578ef82e95cf544c5542ee030b080226f09388 languageName: node linkType: hard @@ -15129,9 +15129,9 @@ __metadata: languageName: node linkType: hard -"@rjsf/utils@npm:5.14.2": - version: 5.14.2 - resolution: "@rjsf/utils@npm:5.14.2" +"@rjsf/utils@npm:5.14.3": + version: 5.14.3 + resolution: "@rjsf/utils@npm:5.14.3" dependencies: json-schema-merge-allof: ^0.8.1 jsonpointer: ^5.0.1 @@ -15140,13 +15140,13 @@ __metadata: react-is: ^18.2.0 peerDependencies: react: ^16.14.0 || >=17 - checksum: e1caf316a3ab96b7b184988fd8e4db4904bdf0ab01146826f4dbd7ab5765c6f28f2e8c328366ace586f2bf8f903f482c32b4aefaf76ed72a16f31ca9814308ba + checksum: 759f85e1d205d360024e569ab04c57543cbec4af8293636ba0af0ec7797bdcb361cd0b33c176ede464f101b33eb4240b60e241537ba19edefc04b91b80e6051e languageName: node linkType: hard -"@rjsf/validator-ajv8@npm:5.14.2": - version: 5.14.2 - resolution: "@rjsf/validator-ajv8@npm:5.14.2" +"@rjsf/validator-ajv8@npm:5.14.3": + version: 5.14.3 + resolution: "@rjsf/validator-ajv8@npm:5.14.3" dependencies: ajv: ^8.12.0 ajv-formats: ^2.1.1 @@ -15154,7 +15154,7 @@ __metadata: lodash-es: ^4.17.21 peerDependencies: "@rjsf/utils": ^5.12.x - checksum: 5f8b7961e8ae15ab596e9904f38fc543858ad72566b4fbf15e57cea7dd1f9b9017cb8ba780bf0312635696ef681ef11765cb523c361a68d6e998ae486df23d6e + checksum: 8b7caa0d5a81ecffaee1a538625c93ff8fdf860d67b80e75901df62112d00479bed6987c25427b84957b4e483c80c80d91713922bdb21ae8dd440242f0e8f5e3 languageName: node linkType: hard From f4f4c33912ee187fa523742bdb7318c2daf1193f Mon Sep 17 00:00:00 2001 From: Federico Morreale Date: Tue, 28 Nov 2023 10:18:24 +0100 Subject: [PATCH 151/261] Revert "refactor: apply overflow on default theme" This reverts commit 418e6bc1338150e874c2b9f31bcce526ac72a5a9. Signed-off-by: Federico Morreale --- packages/theme/src/v5/defaultComponentThemes.ts | 7 ------- .../src/next/components/Stepper/Stepper.tsx | 7 ++++++- .../src/next/components/TaskSteps/TaskSteps.tsx | 1 + 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/packages/theme/src/v5/defaultComponentThemes.ts b/packages/theme/src/v5/defaultComponentThemes.ts index 80e57aa4df..e484300818 100644 --- a/packages/theme/src/v5/defaultComponentThemes.ts +++ b/packages/theme/src/v5/defaultComponentThemes.ts @@ -239,11 +239,4 @@ export const defaultComponentThemes: ThemeOptions['components'] = { underline: 'hover', }, }, - MuiStepper: { - styleOverrides: { - root: { - overflowX: 'auto', - }, - }, - }, }; diff --git a/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx b/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx index 5aaf76316c..a0b06c0e69 100644 --- a/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx +++ b/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx @@ -190,7 +190,12 @@ export const Stepper = (stepperProps: StepperProps) => { return ( <> {isValidating && } - + {steps.map((step, index) => { const isAllowedLabelClick = activeStep > index; return ( diff --git a/plugins/scaffolder-react/src/next/components/TaskSteps/TaskSteps.tsx b/plugins/scaffolder-react/src/next/components/TaskSteps/TaskSteps.tsx index 96f0d9d865..d74d298778 100644 --- a/plugins/scaffolder-react/src/next/components/TaskSteps/TaskSteps.tsx +++ b/plugins/scaffolder-react/src/next/components/TaskSteps/TaskSteps.tsx @@ -58,6 +58,7 @@ export const TaskSteps = (props: TaskStepsProps) => { activeStep={props.activeStep} alternativeLabel variant="elevation" + style={{ overflowX: 'auto' }} > {props.steps.map(step => { const isCompleted = step.status === 'completed'; From aea8f8d329530c8c54f9616bc34de07efc777872 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 28 Nov 2023 10:47:35 +0100 Subject: [PATCH 152/261] repo-tools: flip around API report naming Signed-off-by: Patrik Oldsberg --- .changeset/gorgeous-snails-admire.md | 5 +++++ .prettierignore | 2 +- .../{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../{testUtils-api-report.md => api-report-testUtils.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../{testUtils-api-report.md => api-report-testUtils.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 ...{playwright-api-report.md => api-report-playwright.md} | 0 .../repo-tools/src/commands/api-reports/api-extractor.ts | 8 ++++---- .../{alpha-api-report.md => api-report-alpha.md} | 0 plugins/adr/{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../catalog/{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../explore/{alpha-api-report.md => api-report-alpha.md} | 0 .../graphiql/{alpha-api-report.md => api-report-alpha.md} | 0 plugins/home/{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../search/{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../techdocs/{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 .../{alpha-api-report.md => api-report-alpha.md} | 0 69 files changed, 10 insertions(+), 5 deletions(-) create mode 100644 .changeset/gorgeous-snails-admire.md rename packages/backend-app-api/{alpha-api-report.md => api-report-alpha.md} (100%) rename packages/backend-common/{alpha-api-report.md => api-report-alpha.md} (100%) rename packages/backend-common/{testUtils-api-report.md => api-report-testUtils.md} (100%) rename packages/backend-plugin-api/{alpha-api-report.md => api-report-alpha.md} (100%) rename packages/catalog-model/{alpha-api-report.md => api-report-alpha.md} (100%) rename packages/core-components/{testUtils-api-report.md => api-report-testUtils.md} (100%) rename packages/core-plugin-api/{alpha-api-report.md => api-report-alpha.md} (100%) rename packages/e2e-test-utils/{playwright-api-report.md => api-report-playwright.md} (100%) rename packages/test-utils/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/adr/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/app-backend/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/bazaar-backend/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/catalog-backend-module-aws/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/catalog-backend-module-azure/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/catalog-backend-module-bitbucket-cloud/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/catalog-backend-module-bitbucket-server/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/catalog-backend-module-gcp/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/catalog-backend-module-gerrit/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/catalog-backend-module-github/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/catalog-backend-module-gitlab/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/catalog-backend-module-incremental-ingestion/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/catalog-backend-module-msgraph/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/catalog-backend-module-puppetdb/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/catalog-backend/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/catalog-common/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/catalog-import/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/catalog-node/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/catalog-react/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/catalog/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/events-backend-module-aws-sqs/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/events-backend-module-azure/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/events-backend-module-bitbucket-cloud/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/events-backend-module-gerrit/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/events-backend-module-github/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/events-backend-module-gitlab/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/events-backend/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/events-node/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/explore/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/graphiql/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/home/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/kafka-backend/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/kubernetes-backend/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/periskop-backend/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/permission-backend/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/permission-node/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/proxy-backend/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/scaffolder-backend/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/scaffolder-common/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/scaffolder-node/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/scaffolder-react/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/scaffolder/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/search-backend-module-catalog/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/search-backend-module-elasticsearch/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/search-backend-module-explore/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/search-backend-module-pg/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/search-backend-module-techdocs/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/search-backend-node/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/search-backend/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/search-react/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/search/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/stack-overflow/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/tech-radar/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/techdocs-backend/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/techdocs/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/user-settings-backend/{alpha-api-report.md => api-report-alpha.md} (100%) rename plugins/user-settings/{alpha-api-report.md => api-report-alpha.md} (100%) diff --git a/.changeset/gorgeous-snails-admire.md b/.changeset/gorgeous-snails-admire.md new file mode 100644 index 0000000000..45875ed366 --- /dev/null +++ b/.changeset/gorgeous-snails-admire.md @@ -0,0 +1,5 @@ +--- +'@backstage/repo-tools': minor +--- + +**BREAKING**: API Reports generated for sub-path exports now place the name as a suffix rather than prefix, for example `api-report-alpha.md` instead of `alpha-api-report.md`. When upgrading to this version you'll need to re-create any such API reports and delete the old ones. diff --git a/.prettierignore b/.prettierignore index ad2bd355ed..c54ee5d821 100644 --- a/.prettierignore +++ b/.prettierignore @@ -5,7 +5,7 @@ coverage *.hbs templates api-report.md -*-api-report.md +api-report-*.md cli-report.md plugins/scaffolder-backend/sample-templates .vscode diff --git a/packages/backend-app-api/alpha-api-report.md b/packages/backend-app-api/api-report-alpha.md similarity index 100% rename from packages/backend-app-api/alpha-api-report.md rename to packages/backend-app-api/api-report-alpha.md diff --git a/packages/backend-common/alpha-api-report.md b/packages/backend-common/api-report-alpha.md similarity index 100% rename from packages/backend-common/alpha-api-report.md rename to packages/backend-common/api-report-alpha.md diff --git a/packages/backend-common/testUtils-api-report.md b/packages/backend-common/api-report-testUtils.md similarity index 100% rename from packages/backend-common/testUtils-api-report.md rename to packages/backend-common/api-report-testUtils.md diff --git a/packages/backend-plugin-api/alpha-api-report.md b/packages/backend-plugin-api/api-report-alpha.md similarity index 100% rename from packages/backend-plugin-api/alpha-api-report.md rename to packages/backend-plugin-api/api-report-alpha.md diff --git a/packages/catalog-model/alpha-api-report.md b/packages/catalog-model/api-report-alpha.md similarity index 100% rename from packages/catalog-model/alpha-api-report.md rename to packages/catalog-model/api-report-alpha.md diff --git a/packages/core-components/testUtils-api-report.md b/packages/core-components/api-report-testUtils.md similarity index 100% rename from packages/core-components/testUtils-api-report.md rename to packages/core-components/api-report-testUtils.md diff --git a/packages/core-plugin-api/alpha-api-report.md b/packages/core-plugin-api/api-report-alpha.md similarity index 100% rename from packages/core-plugin-api/alpha-api-report.md rename to packages/core-plugin-api/api-report-alpha.md diff --git a/packages/e2e-test-utils/playwright-api-report.md b/packages/e2e-test-utils/api-report-playwright.md similarity index 100% rename from packages/e2e-test-utils/playwright-api-report.md rename to packages/e2e-test-utils/api-report-playwright.md diff --git a/packages/repo-tools/src/commands/api-reports/api-extractor.ts b/packages/repo-tools/src/commands/api-reports/api-extractor.ts index ce3e6f5b20..c978e49300 100644 --- a/packages/repo-tools/src/commands/api-reports/api-extractor.ts +++ b/packages/repo-tools/src/commands/api-reports/api-extractor.ts @@ -375,8 +375,8 @@ export async function runApiExtraction({ packageDir, ); - const prefix = name === 'index' ? '' : `${name}-`; - const reportFileName = `${prefix}api-report.md`; + const suffix = name === 'index' ? '' : `-${name}`; + const reportFileName = `api-report${suffix}.md`; const reportPath = resolvePath(projectFolder, reportFileName); const warningCountBefore = await countApiReportWarnings(reportPath); @@ -396,7 +396,7 @@ export async function runApiExtraction({ reportFolder: projectFolder, reportTempFolder: resolvePath( outputDir, - `${prefix}`, + `${suffix}`, ), }, @@ -406,7 +406,7 @@ export async function runApiExtraction({ enabled: name === 'index', apiJsonFilePath: resolvePath( outputDir, - `${prefix}.api.json`, + `${suffix}.api.json`, ), }, diff --git a/packages/test-utils/alpha-api-report.md b/packages/test-utils/api-report-alpha.md similarity index 100% rename from packages/test-utils/alpha-api-report.md rename to packages/test-utils/api-report-alpha.md diff --git a/plugins/adr/alpha-api-report.md b/plugins/adr/api-report-alpha.md similarity index 100% rename from plugins/adr/alpha-api-report.md rename to plugins/adr/api-report-alpha.md diff --git a/plugins/app-backend/alpha-api-report.md b/plugins/app-backend/api-report-alpha.md similarity index 100% rename from plugins/app-backend/alpha-api-report.md rename to plugins/app-backend/api-report-alpha.md diff --git a/plugins/bazaar-backend/alpha-api-report.md b/plugins/bazaar-backend/api-report-alpha.md similarity index 100% rename from plugins/bazaar-backend/alpha-api-report.md rename to plugins/bazaar-backend/api-report-alpha.md diff --git a/plugins/catalog-backend-module-aws/alpha-api-report.md b/plugins/catalog-backend-module-aws/api-report-alpha.md similarity index 100% rename from plugins/catalog-backend-module-aws/alpha-api-report.md rename to plugins/catalog-backend-module-aws/api-report-alpha.md diff --git a/plugins/catalog-backend-module-azure/alpha-api-report.md b/plugins/catalog-backend-module-azure/api-report-alpha.md similarity index 100% rename from plugins/catalog-backend-module-azure/alpha-api-report.md rename to plugins/catalog-backend-module-azure/api-report-alpha.md diff --git a/plugins/catalog-backend-module-bitbucket-cloud/alpha-api-report.md b/plugins/catalog-backend-module-bitbucket-cloud/api-report-alpha.md similarity index 100% rename from plugins/catalog-backend-module-bitbucket-cloud/alpha-api-report.md rename to plugins/catalog-backend-module-bitbucket-cloud/api-report-alpha.md diff --git a/plugins/catalog-backend-module-bitbucket-server/alpha-api-report.md b/plugins/catalog-backend-module-bitbucket-server/api-report-alpha.md similarity index 100% rename from plugins/catalog-backend-module-bitbucket-server/alpha-api-report.md rename to plugins/catalog-backend-module-bitbucket-server/api-report-alpha.md diff --git a/plugins/catalog-backend-module-gcp/alpha-api-report.md b/plugins/catalog-backend-module-gcp/api-report-alpha.md similarity index 100% rename from plugins/catalog-backend-module-gcp/alpha-api-report.md rename to plugins/catalog-backend-module-gcp/api-report-alpha.md diff --git a/plugins/catalog-backend-module-gerrit/alpha-api-report.md b/plugins/catalog-backend-module-gerrit/api-report-alpha.md similarity index 100% rename from plugins/catalog-backend-module-gerrit/alpha-api-report.md rename to plugins/catalog-backend-module-gerrit/api-report-alpha.md diff --git a/plugins/catalog-backend-module-github/alpha-api-report.md b/plugins/catalog-backend-module-github/api-report-alpha.md similarity index 100% rename from plugins/catalog-backend-module-github/alpha-api-report.md rename to plugins/catalog-backend-module-github/api-report-alpha.md diff --git a/plugins/catalog-backend-module-gitlab/alpha-api-report.md b/plugins/catalog-backend-module-gitlab/api-report-alpha.md similarity index 100% rename from plugins/catalog-backend-module-gitlab/alpha-api-report.md rename to plugins/catalog-backend-module-gitlab/api-report-alpha.md diff --git a/plugins/catalog-backend-module-incremental-ingestion/alpha-api-report.md b/plugins/catalog-backend-module-incremental-ingestion/api-report-alpha.md similarity index 100% rename from plugins/catalog-backend-module-incremental-ingestion/alpha-api-report.md rename to plugins/catalog-backend-module-incremental-ingestion/api-report-alpha.md diff --git a/plugins/catalog-backend-module-msgraph/alpha-api-report.md b/plugins/catalog-backend-module-msgraph/api-report-alpha.md similarity index 100% rename from plugins/catalog-backend-module-msgraph/alpha-api-report.md rename to plugins/catalog-backend-module-msgraph/api-report-alpha.md diff --git a/plugins/catalog-backend-module-puppetdb/alpha-api-report.md b/plugins/catalog-backend-module-puppetdb/api-report-alpha.md similarity index 100% rename from plugins/catalog-backend-module-puppetdb/alpha-api-report.md rename to plugins/catalog-backend-module-puppetdb/api-report-alpha.md diff --git a/plugins/catalog-backend/alpha-api-report.md b/plugins/catalog-backend/api-report-alpha.md similarity index 100% rename from plugins/catalog-backend/alpha-api-report.md rename to plugins/catalog-backend/api-report-alpha.md diff --git a/plugins/catalog-common/alpha-api-report.md b/plugins/catalog-common/api-report-alpha.md similarity index 100% rename from plugins/catalog-common/alpha-api-report.md rename to plugins/catalog-common/api-report-alpha.md diff --git a/plugins/catalog-import/alpha-api-report.md b/plugins/catalog-import/api-report-alpha.md similarity index 100% rename from plugins/catalog-import/alpha-api-report.md rename to plugins/catalog-import/api-report-alpha.md diff --git a/plugins/catalog-node/alpha-api-report.md b/plugins/catalog-node/api-report-alpha.md similarity index 100% rename from plugins/catalog-node/alpha-api-report.md rename to plugins/catalog-node/api-report-alpha.md diff --git a/plugins/catalog-react/alpha-api-report.md b/plugins/catalog-react/api-report-alpha.md similarity index 100% rename from plugins/catalog-react/alpha-api-report.md rename to plugins/catalog-react/api-report-alpha.md diff --git a/plugins/catalog/alpha-api-report.md b/plugins/catalog/api-report-alpha.md similarity index 100% rename from plugins/catalog/alpha-api-report.md rename to plugins/catalog/api-report-alpha.md diff --git a/plugins/events-backend-module-aws-sqs/alpha-api-report.md b/plugins/events-backend-module-aws-sqs/api-report-alpha.md similarity index 100% rename from plugins/events-backend-module-aws-sqs/alpha-api-report.md rename to plugins/events-backend-module-aws-sqs/api-report-alpha.md diff --git a/plugins/events-backend-module-azure/alpha-api-report.md b/plugins/events-backend-module-azure/api-report-alpha.md similarity index 100% rename from plugins/events-backend-module-azure/alpha-api-report.md rename to plugins/events-backend-module-azure/api-report-alpha.md diff --git a/plugins/events-backend-module-bitbucket-cloud/alpha-api-report.md b/plugins/events-backend-module-bitbucket-cloud/api-report-alpha.md similarity index 100% rename from plugins/events-backend-module-bitbucket-cloud/alpha-api-report.md rename to plugins/events-backend-module-bitbucket-cloud/api-report-alpha.md diff --git a/plugins/events-backend-module-gerrit/alpha-api-report.md b/plugins/events-backend-module-gerrit/api-report-alpha.md similarity index 100% rename from plugins/events-backend-module-gerrit/alpha-api-report.md rename to plugins/events-backend-module-gerrit/api-report-alpha.md diff --git a/plugins/events-backend-module-github/alpha-api-report.md b/plugins/events-backend-module-github/api-report-alpha.md similarity index 100% rename from plugins/events-backend-module-github/alpha-api-report.md rename to plugins/events-backend-module-github/api-report-alpha.md diff --git a/plugins/events-backend-module-gitlab/alpha-api-report.md b/plugins/events-backend-module-gitlab/api-report-alpha.md similarity index 100% rename from plugins/events-backend-module-gitlab/alpha-api-report.md rename to plugins/events-backend-module-gitlab/api-report-alpha.md diff --git a/plugins/events-backend/alpha-api-report.md b/plugins/events-backend/api-report-alpha.md similarity index 100% rename from plugins/events-backend/alpha-api-report.md rename to plugins/events-backend/api-report-alpha.md diff --git a/plugins/events-node/alpha-api-report.md b/plugins/events-node/api-report-alpha.md similarity index 100% rename from plugins/events-node/alpha-api-report.md rename to plugins/events-node/api-report-alpha.md diff --git a/plugins/explore/alpha-api-report.md b/plugins/explore/api-report-alpha.md similarity index 100% rename from plugins/explore/alpha-api-report.md rename to plugins/explore/api-report-alpha.md diff --git a/plugins/graphiql/alpha-api-report.md b/plugins/graphiql/api-report-alpha.md similarity index 100% rename from plugins/graphiql/alpha-api-report.md rename to plugins/graphiql/api-report-alpha.md diff --git a/plugins/home/alpha-api-report.md b/plugins/home/api-report-alpha.md similarity index 100% rename from plugins/home/alpha-api-report.md rename to plugins/home/api-report-alpha.md diff --git a/plugins/kafka-backend/alpha-api-report.md b/plugins/kafka-backend/api-report-alpha.md similarity index 100% rename from plugins/kafka-backend/alpha-api-report.md rename to plugins/kafka-backend/api-report-alpha.md diff --git a/plugins/kubernetes-backend/alpha-api-report.md b/plugins/kubernetes-backend/api-report-alpha.md similarity index 100% rename from plugins/kubernetes-backend/alpha-api-report.md rename to plugins/kubernetes-backend/api-report-alpha.md diff --git a/plugins/periskop-backend/alpha-api-report.md b/plugins/periskop-backend/api-report-alpha.md similarity index 100% rename from plugins/periskop-backend/alpha-api-report.md rename to plugins/periskop-backend/api-report-alpha.md diff --git a/plugins/permission-backend/alpha-api-report.md b/plugins/permission-backend/api-report-alpha.md similarity index 100% rename from plugins/permission-backend/alpha-api-report.md rename to plugins/permission-backend/api-report-alpha.md diff --git a/plugins/permission-node/alpha-api-report.md b/plugins/permission-node/api-report-alpha.md similarity index 100% rename from plugins/permission-node/alpha-api-report.md rename to plugins/permission-node/api-report-alpha.md diff --git a/plugins/proxy-backend/alpha-api-report.md b/plugins/proxy-backend/api-report-alpha.md similarity index 100% rename from plugins/proxy-backend/alpha-api-report.md rename to plugins/proxy-backend/api-report-alpha.md diff --git a/plugins/scaffolder-backend/alpha-api-report.md b/plugins/scaffolder-backend/api-report-alpha.md similarity index 100% rename from plugins/scaffolder-backend/alpha-api-report.md rename to plugins/scaffolder-backend/api-report-alpha.md diff --git a/plugins/scaffolder-common/alpha-api-report.md b/plugins/scaffolder-common/api-report-alpha.md similarity index 100% rename from plugins/scaffolder-common/alpha-api-report.md rename to plugins/scaffolder-common/api-report-alpha.md diff --git a/plugins/scaffolder-node/alpha-api-report.md b/plugins/scaffolder-node/api-report-alpha.md similarity index 100% rename from plugins/scaffolder-node/alpha-api-report.md rename to plugins/scaffolder-node/api-report-alpha.md diff --git a/plugins/scaffolder-react/alpha-api-report.md b/plugins/scaffolder-react/api-report-alpha.md similarity index 100% rename from plugins/scaffolder-react/alpha-api-report.md rename to plugins/scaffolder-react/api-report-alpha.md diff --git a/plugins/scaffolder/alpha-api-report.md b/plugins/scaffolder/api-report-alpha.md similarity index 100% rename from plugins/scaffolder/alpha-api-report.md rename to plugins/scaffolder/api-report-alpha.md diff --git a/plugins/search-backend-module-catalog/alpha-api-report.md b/plugins/search-backend-module-catalog/api-report-alpha.md similarity index 100% rename from plugins/search-backend-module-catalog/alpha-api-report.md rename to plugins/search-backend-module-catalog/api-report-alpha.md diff --git a/plugins/search-backend-module-elasticsearch/alpha-api-report.md b/plugins/search-backend-module-elasticsearch/api-report-alpha.md similarity index 100% rename from plugins/search-backend-module-elasticsearch/alpha-api-report.md rename to plugins/search-backend-module-elasticsearch/api-report-alpha.md diff --git a/plugins/search-backend-module-explore/alpha-api-report.md b/plugins/search-backend-module-explore/api-report-alpha.md similarity index 100% rename from plugins/search-backend-module-explore/alpha-api-report.md rename to plugins/search-backend-module-explore/api-report-alpha.md diff --git a/plugins/search-backend-module-pg/alpha-api-report.md b/plugins/search-backend-module-pg/api-report-alpha.md similarity index 100% rename from plugins/search-backend-module-pg/alpha-api-report.md rename to plugins/search-backend-module-pg/api-report-alpha.md diff --git a/plugins/search-backend-module-techdocs/alpha-api-report.md b/plugins/search-backend-module-techdocs/api-report-alpha.md similarity index 100% rename from plugins/search-backend-module-techdocs/alpha-api-report.md rename to plugins/search-backend-module-techdocs/api-report-alpha.md diff --git a/plugins/search-backend-node/alpha-api-report.md b/plugins/search-backend-node/api-report-alpha.md similarity index 100% rename from plugins/search-backend-node/alpha-api-report.md rename to plugins/search-backend-node/api-report-alpha.md diff --git a/plugins/search-backend/alpha-api-report.md b/plugins/search-backend/api-report-alpha.md similarity index 100% rename from plugins/search-backend/alpha-api-report.md rename to plugins/search-backend/api-report-alpha.md diff --git a/plugins/search-react/alpha-api-report.md b/plugins/search-react/api-report-alpha.md similarity index 100% rename from plugins/search-react/alpha-api-report.md rename to plugins/search-react/api-report-alpha.md diff --git a/plugins/search/alpha-api-report.md b/plugins/search/api-report-alpha.md similarity index 100% rename from plugins/search/alpha-api-report.md rename to plugins/search/api-report-alpha.md diff --git a/plugins/stack-overflow/alpha-api-report.md b/plugins/stack-overflow/api-report-alpha.md similarity index 100% rename from plugins/stack-overflow/alpha-api-report.md rename to plugins/stack-overflow/api-report-alpha.md diff --git a/plugins/tech-radar/alpha-api-report.md b/plugins/tech-radar/api-report-alpha.md similarity index 100% rename from plugins/tech-radar/alpha-api-report.md rename to plugins/tech-radar/api-report-alpha.md diff --git a/plugins/techdocs-backend/alpha-api-report.md b/plugins/techdocs-backend/api-report-alpha.md similarity index 100% rename from plugins/techdocs-backend/alpha-api-report.md rename to plugins/techdocs-backend/api-report-alpha.md diff --git a/plugins/techdocs/alpha-api-report.md b/plugins/techdocs/api-report-alpha.md similarity index 100% rename from plugins/techdocs/alpha-api-report.md rename to plugins/techdocs/api-report-alpha.md diff --git a/plugins/user-settings-backend/alpha-api-report.md b/plugins/user-settings-backend/api-report-alpha.md similarity index 100% rename from plugins/user-settings-backend/alpha-api-report.md rename to plugins/user-settings-backend/api-report-alpha.md diff --git a/plugins/user-settings/alpha-api-report.md b/plugins/user-settings/api-report-alpha.md similarity index 100% rename from plugins/user-settings/alpha-api-report.md rename to plugins/user-settings/api-report-alpha.md From cd2b9fbc0e4ac3150b55a319d24708a67fa929fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Tue, 28 Nov 2023 10:48:59 +0100 Subject: [PATCH 153/261] derp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- packages/cli/src/lib/bundler/config.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/cli/src/lib/bundler/config.ts b/packages/cli/src/lib/bundler/config.ts index 65c3853bc2..a9d5c2aa67 100644 --- a/packages/cli/src/lib/bundler/config.ts +++ b/packages/cli/src/lib/bundler/config.ts @@ -55,14 +55,14 @@ export function resolveBaseUrl(config: Config): URL { async function readBuildInfo() { const timestamp = Date.now(); - let commit: string | unknown; + let commit: string | undefined; try { commit = await runPlain('git', 'rev-parse', 'HEAD'); } catch (error) { // ignore, see below } - let gitVersion: string | unknown; + let gitVersion: string | undefined; try { gitVersion = await runPlain('git', 'describe', '--always'); } catch (error) { From 7c86ff2b6b113e6f7e1ae61009080061842feebc Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Fri, 27 Oct 2023 08:45:39 +0200 Subject: [PATCH 154/261] feat: create core component extension Signed-off-by: Camila Belo --- .../frontend-app-api/src/extensions/Core.tsx | 14 ++- .../src/extensions/CoreComponents.tsx | 98 +++++++++++++++++++ .../frontend-app-api/src/wiring/createApp.tsx | 10 +- .../src/wiring/coreExtensionData.ts | 21 +++- 4 files changed, 140 insertions(+), 3 deletions(-) create mode 100644 packages/frontend-app-api/src/extensions/CoreComponents.tsx diff --git a/packages/frontend-app-api/src/extensions/Core.tsx b/packages/frontend-app-api/src/extensions/Core.tsx index 60772d435c..84407d1f09 100644 --- a/packages/frontend-app-api/src/extensions/Core.tsx +++ b/packages/frontend-app-api/src/extensions/Core.tsx @@ -14,6 +14,8 @@ * limitations under the License. */ +import React from 'react'; + import { coreExtensionData, createExtension, @@ -30,6 +32,12 @@ export const Core = createExtension({ themes: createExtensionInput({ theme: coreExtensionData.theme, }), + components: createExtensionInput( + { + provider: coreExtensionData.reactComponent, + }, + { singleton: true }, + ), root: createExtensionInput( { element: coreExtensionData.reactElement, @@ -42,7 +50,11 @@ export const Core = createExtension({ }, factory({ inputs }) { return { - root: inputs.root.element, + root: ( + + {inputs.root.element} + + ), }; }, }); diff --git a/packages/frontend-app-api/src/extensions/CoreComponents.tsx b/packages/frontend-app-api/src/extensions/CoreComponents.tsx new file mode 100644 index 0000000000..3e1bc8e8bc --- /dev/null +++ b/packages/frontend-app-api/src/extensions/CoreComponents.tsx @@ -0,0 +1,98 @@ +/* + * 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 React, { PropsWithChildren, useMemo } from 'react'; +import { + createExtension, + coreExtensionData, + createExtensionInput, +} from '@backstage/frontend-plugin-api'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { AppContextProvider } from '../../../core-app-api/src/app/AppContext'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { useApp } from '../../../core-plugin-api/src/app/useApp'; + +export const CoreComponents = createExtension({ + id: 'core.components', + attachTo: { id: 'core', input: 'components' }, + inputs: { + progress: createExtensionInput( + { + component: coreExtensionData.components.progress, + }, + { + singleton: true, + }, + ), + bootErrorPage: createExtensionInput( + { + component: coreExtensionData.components.bootErrorPage, + }, + { + singleton: true, + }, + ), + notFoundErrorPage: createExtensionInput( + { + component: coreExtensionData.components.notFoundErrorPage, + }, + { + singleton: true, + }, + ), + errorBoundaryFallback: createExtensionInput( + { + component: coreExtensionData.components.errorBoundaryFallback, + }, + { + singleton: true, + }, + ), + }, + output: { + provider: coreExtensionData.reactComponent, + }, + factory({ bind, inputs }) { + bind({ + provider: function Provider(props: PropsWithChildren<{}>) { + const { children } = props; + const parentContext = useApp(); + + const appContext = useMemo( + () => ({ + ...parentContext, + // Only override components + getComponents: () => ({ + // Skipping Router and SignInPage + ...parentContext.getComponents(), + Progress: inputs.progress.component, + BootErrorPage: inputs.bootErrorPage.component, + NotFoundErrorPage: inputs.notFoundErrorPage.component, + ErrorBoundaryFallback: inputs.errorBoundaryFallback.component, + }), + }), + [parentContext], + ); + + return ( + + {children} + + ); + }, + }); + }, +}); diff --git a/packages/frontend-app-api/src/wiring/createApp.tsx b/packages/frontend-app-api/src/wiring/createApp.tsx index a1412f1c3c..8d51df84c0 100644 --- a/packages/frontend-app-api/src/wiring/createApp.tsx +++ b/packages/frontend-app-api/src/wiring/createApp.tsx @@ -89,6 +89,7 @@ import { RoutingProvider } from '../routing/RoutingProvider'; import { resolveRouteBindings } from '../routing/resolveRouteBindings'; import { collectRouteIds } from '../routing/collectRouteIds'; import { createAppTree } from '../tree'; +import { CoreComponents } from '../extensions/CoreComponents'; import { AppNode } from '@backstage/frontend-plugin-api'; import { toLegacyPlugin } from '../routing/toLegacyPlugin'; import { InternalAppContext } from './InternalAppContext'; @@ -104,6 +105,7 @@ const builtinExtensions = [ CoreRoutes, CoreNav, CoreLayout, + CoreComponents, LightTheme, DarkTheme, ]; @@ -376,7 +378,13 @@ function createLegacyAppContext(plugins: BackstagePlugin[]): AppContext { }, getComponents(): AppComponents { - return defaultComponents; + return { + ...defaultComponents, + Progress: () => null, + BootErrorPage: () => null, + NotFoundErrorPage: () => null, + ErrorBoundaryFallback: () => null, + }; }, }; } diff --git a/packages/frontend-plugin-api/src/wiring/coreExtensionData.ts b/packages/frontend-plugin-api/src/wiring/coreExtensionData.ts index 9ffdb835ba..64abfb74eb 100644 --- a/packages/frontend-plugin-api/src/wiring/coreExtensionData.ts +++ b/packages/frontend-plugin-api/src/wiring/coreExtensionData.ts @@ -20,8 +20,10 @@ import { AppTheme, IconComponent, } from '@backstage/core-plugin-api'; -import { createExtensionDataRef } from './createExtensionDataRef'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { AppComponents } from '../../../core-app-api/src/app/types'; import { RouteRef } from '../routing'; +import { createExtensionDataRef } from './createExtensionDataRef'; /** @public */ export type NavTarget = { @@ -38,6 +40,9 @@ export type LogoElements = { /** @public */ export const coreExtensionData = { + reactComponent: createExtensionDataRef< + (props: T) => JSX.Element + >('core.reactComponent'), reactElement: createExtensionDataRef('core.reactElement'), routePath: createExtensionDataRef('core.routing.path'), apiFactory: createExtensionDataRef('core.api.factory'), @@ -45,4 +50,18 @@ export const coreExtensionData = { navTarget: createExtensionDataRef('core.nav.target'), theme: createExtensionDataRef('core.theme'), logoElements: createExtensionDataRef('core.logos'), + components: { + progress: createExtensionDataRef( + 'core.components.progress', + ), + bootErrorPage: createExtensionDataRef( + 'core.components.bootErrorPage', + ), + notFoundErrorPage: createExtensionDataRef< + AppComponents['NotFoundErrorPage'] + >('core.components.notFoundErrorPage'), + errorBoundaryFallback: createExtensionDataRef< + AppComponents['ErrorBoundaryFallback'] + >('core.components.errorBoundary'), + }, }; From c26c40956605409fd72ed63cd26ee32e8971b973 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Fri, 27 Oct 2023 08:47:24 +0200 Subject: [PATCH 155/261] feat: create core component factories Signed-off-by: Camila Belo --- packages/app-next/src/App.tsx | 38 ++++++++ .../src/extensions/CoreComponents.tsx | 24 +++++ .../src/extensions/CoreRoutes.tsx | 14 ++- .../frontend-app-api/src/wiring/createApp.tsx | 12 ++- .../extensions/createComponentExtension.tsx | 95 +++++++++++++++++++ .../src/extensions/index.ts | 6 ++ 6 files changed, 185 insertions(+), 4 deletions(-) create mode 100644 packages/frontend-plugin-api/src/extensions/createComponentExtension.tsx diff --git a/packages/app-next/src/App.tsx b/packages/app-next/src/App.tsx index 67faf8d646..88dc4a7207 100644 --- a/packages/app-next/src/App.tsx +++ b/packages/app-next/src/App.tsx @@ -29,6 +29,7 @@ import { createExtension, createApiExtension, createExtensionOverrides, + createNotFoundErrorPageExtension, } from '@backstage/frontend-plugin-api'; import techdocsPlugin from '@backstage/plugin-techdocs/alpha'; import { homePage } from './HomePage'; @@ -48,6 +49,8 @@ import { } from '@backstage/integration-react'; import { createSignInPageExtension } from '@backstage/frontend-plugin-api'; import { SignInPage } from '@backstage/core-components'; +import { Box, Typography } from '@material-ui/core'; +import { Button } from '@backstage/core-components'; /* @@ -108,6 +111,40 @@ const scmIntegrationApi = createApiExtension({ }), }); +const customNotFoundErrorPage = createNotFoundErrorPageExtension({ + component: () => ( + + 404 + + Bowie was unable to locate this page. Please contact your support team + if this page used to exist. + + Backstage bowie + + + ), +}); + const collectedLegacyPlugins = collectLegacyRoutes( } /> @@ -129,6 +166,7 @@ const app = createApp({ scmAuthExtension, scmIntegrationApi, signInPage, + customNotFoundErrorPage, ], }), ], diff --git a/packages/frontend-app-api/src/extensions/CoreComponents.tsx b/packages/frontend-app-api/src/extensions/CoreComponents.tsx index 3e1bc8e8bc..a0651d6423 100644 --- a/packages/frontend-app-api/src/extensions/CoreComponents.tsx +++ b/packages/frontend-app-api/src/extensions/CoreComponents.tsx @@ -19,12 +19,36 @@ import { createExtension, coreExtensionData, createExtensionInput, + createProgressExtension, + createBootErrorPageExtension, + createNotFoundErrorPageExtension, + createErrorBoundaryFallbackExtension, } from '@backstage/frontend-plugin-api'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { components as defaultComponents } from '../../../app-defaults/src/defaults'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports import { AppContextProvider } from '../../../core-app-api/src/app/AppContext'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports import { useApp } from '../../../core-plugin-api/src/app/useApp'; +export const DefaultProgressComponent = createProgressExtension({ + component: defaultComponents.Progress, +}); + +export const DefaultBootErrorPageComponent = createBootErrorPageExtension({ + component: defaultComponents.BootErrorPage, +}); + +export const DefaultNotFoundErrorPageComponent = + createNotFoundErrorPageExtension({ + component: defaultComponents.NotFoundErrorPage, + }); + +export const DefaultErrorBoundaryComponent = + createErrorBoundaryFallbackExtension({ + component: defaultComponents.ErrorBoundaryFallback, + }); + export const CoreComponents = createExtension({ id: 'core.components', attachTo: { id: 'core', input: 'components' }, diff --git a/packages/frontend-app-api/src/extensions/CoreRoutes.tsx b/packages/frontend-app-api/src/extensions/CoreRoutes.tsx index 985fd07be9..e2798c091d 100644 --- a/packages/frontend-app-api/src/extensions/CoreRoutes.tsx +++ b/packages/frontend-app-api/src/extensions/CoreRoutes.tsx @@ -21,6 +21,8 @@ import { createExtensionInput, } from '@backstage/frontend-plugin-api'; import { useRoutes } from 'react-router-dom'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { useApp } from '../../../core-plugin-api/src/app/useApp'; export const CoreRoutes = createExtension({ id: 'core.routes', @@ -37,12 +39,18 @@ export const CoreRoutes = createExtension({ }, factory({ inputs }) { const Routes = () => { - const element = useRoutes( - inputs.routes.map(route => ({ + const app = useApp(); + const { NotFoundErrorPage } = app.getComponents(); + const element = useRoutes([ + ...inputs.routes.map(route => ({ path: `${route.path}/*`, element: route.element, })), - ); + { + path: '*', + element: , + }, + ]); return element; }; diff --git a/packages/frontend-app-api/src/wiring/createApp.tsx b/packages/frontend-app-api/src/wiring/createApp.tsx index 8d51df84c0..caa7064b2d 100644 --- a/packages/frontend-app-api/src/wiring/createApp.tsx +++ b/packages/frontend-app-api/src/wiring/createApp.tsx @@ -89,7 +89,13 @@ import { RoutingProvider } from '../routing/RoutingProvider'; import { resolveRouteBindings } from '../routing/resolveRouteBindings'; import { collectRouteIds } from '../routing/collectRouteIds'; import { createAppTree } from '../tree'; -import { CoreComponents } from '../extensions/CoreComponents'; +import { + CoreComponents, + DefaultProgressComponent, + DefaultErrorBoundaryComponent, + DefaultBootErrorPageComponent, + DefaultNotFoundErrorPageComponent, +} from '../extensions/CoreComponents'; import { AppNode } from '@backstage/frontend-plugin-api'; import { toLegacyPlugin } from '../routing/toLegacyPlugin'; import { InternalAppContext } from './InternalAppContext'; @@ -106,6 +112,10 @@ const builtinExtensions = [ CoreNav, CoreLayout, CoreComponents, + DefaultProgressComponent, + DefaultErrorBoundaryComponent, + DefaultBootErrorPageComponent, + DefaultNotFoundErrorPageComponent, LightTheme, DarkTheme, ]; diff --git a/packages/frontend-plugin-api/src/extensions/createComponentExtension.tsx b/packages/frontend-plugin-api/src/extensions/createComponentExtension.tsx new file mode 100644 index 0000000000..5c882dd638 --- /dev/null +++ b/packages/frontend-plugin-api/src/extensions/createComponentExtension.tsx @@ -0,0 +1,95 @@ +/* + * 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. + */ + +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { AppComponents } from '../../../core-app-api/src/app/types'; +import { coreExtensionData, createExtension } from '../wiring'; + +/** @public */ +export function createBootErrorPageExtension(options: { + component: AppComponents['BootErrorPage']; +}) { + return createExtension({ + id: `core.components.bootErrorPage`, + attachTo: { id: 'core.components', input: 'bootErrorPage' }, + inputs: {}, + output: { + component: coreExtensionData.components.bootErrorPage, + }, + factory({ bind }) { + bind({ + component: options.component, + }); + }, + }); +} + +/** @public */ +export function createNotFoundErrorPageExtension(options: { + component: AppComponents['NotFoundErrorPage']; +}) { + return createExtension({ + id: `core.components.notFoundErrorPage`, + attachTo: { id: 'core.components', input: 'notFoundErrorPage' }, + inputs: {}, + output: { + component: coreExtensionData.components.notFoundErrorPage, + }, + factory({ bind }) { + bind({ + component: options.component, + }); + }, + }); +} + +/** @public */ +export function createErrorBoundaryFallbackExtension(options: { + component: AppComponents['ErrorBoundaryFallback']; +}) { + return createExtension({ + id: `core.components.errorBoundaryFallback`, + attachTo: { id: 'core.components', input: 'errorBoundaryFallback' }, + inputs: {}, + output: { + component: coreExtensionData.components.errorBoundaryFallback, + }, + factory({ bind }) { + bind({ + component: options.component, + }); + }, + }); +} + +/** @public */ +export function createProgressExtension(options: { + component: AppComponents['Progress']; +}) { + return createExtension({ + id: `core.components.progress`, + attachTo: { id: 'core.components', input: 'progress' }, + inputs: {}, + output: { + component: coreExtensionData.components.progress, + }, + factory({ bind }) { + bind({ + component: options.component, + }); + }, + }); +} diff --git a/packages/frontend-plugin-api/src/extensions/index.ts b/packages/frontend-plugin-api/src/extensions/index.ts index d696774272..d036cb5dda 100644 --- a/packages/frontend-plugin-api/src/extensions/index.ts +++ b/packages/frontend-plugin-api/src/extensions/index.ts @@ -19,3 +19,9 @@ export { createPageExtension } from './createPageExtension'; export { createNavItemExtension } from './createNavItemExtension'; export { createSignInPageExtension } from './createSignInPageExtension'; export { createThemeExtension } from './createThemeExtension'; +export { + createProgressExtension, + createBootErrorPageExtension, + createNotFoundErrorPageExtension, + createErrorBoundaryFallbackExtension, +} from './createComponentExtension'; From 04c8b48fb995a5cabaaa75fc6e596288c5850111 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Fri, 27 Oct 2023 09:48:12 +0200 Subject: [PATCH 156/261] refactor: lazy load core components Signed-off-by: Camila Belo --- packages/app-next/src/App.tsx | 38 +-- .../examples/notFoundErrorPageExtension.tsx | 58 +++++ .../src/extensions/CoreComponents.tsx | 8 +- .../frontend-app-api/src/wiring/createApp.tsx | 1 + .../src/components/ExtensionError.tsx | 27 ++ .../src/components/index.ts | 2 + .../extensions/createComponentExtension.tsx | 245 +++++++++++++----- .../src/extensions/createPageExtension.tsx | 7 +- packages/frontend-plugin-api/src/index.ts | 7 + packages/frontend-plugin-api/src/types.ts | 28 ++ .../src/wiring/coreExtensionData.ts | 25 +- 11 files changed, 327 insertions(+), 119 deletions(-) create mode 100644 packages/app-next/src/examples/notFoundErrorPageExtension.tsx create mode 100644 packages/frontend-plugin-api/src/components/ExtensionError.tsx diff --git a/packages/app-next/src/App.tsx b/packages/app-next/src/App.tsx index 88dc4a7207..3fb91bd03e 100644 --- a/packages/app-next/src/App.tsx +++ b/packages/app-next/src/App.tsx @@ -17,6 +17,7 @@ import React from 'react'; import { createApp } from '@backstage/frontend-app-api'; import { pagesPlugin } from './examples/pagesPlugin'; +import customNotFoundErrorPage from './examples/notFoundErrorPageExtension'; import graphiqlPlugin from '@backstage/plugin-graphiql/alpha'; import techRadarPlugin from '@backstage/plugin-tech-radar/alpha'; import userSettingsPlugin from '@backstage/plugin-user-settings/alpha'; @@ -29,7 +30,6 @@ import { createExtension, createApiExtension, createExtensionOverrides, - createNotFoundErrorPageExtension, } from '@backstage/frontend-plugin-api'; import techdocsPlugin from '@backstage/plugin-techdocs/alpha'; import { homePage } from './HomePage'; @@ -49,8 +49,6 @@ import { } from '@backstage/integration-react'; import { createSignInPageExtension } from '@backstage/frontend-plugin-api'; import { SignInPage } from '@backstage/core-components'; -import { Box, Typography } from '@material-ui/core'; -import { Button } from '@backstage/core-components'; /* @@ -111,40 +109,6 @@ const scmIntegrationApi = createApiExtension({ }), }); -const customNotFoundErrorPage = createNotFoundErrorPageExtension({ - component: () => ( - - 404 - - Bowie was unable to locate this page. Please contact your support team - if this page used to exist. - - Backstage bowie - - - ), -}); - const collectedLegacyPlugins = collectLegacyRoutes( } /> diff --git a/packages/app-next/src/examples/notFoundErrorPageExtension.tsx b/packages/app-next/src/examples/notFoundErrorPageExtension.tsx new file mode 100644 index 0000000000..93807a1757 --- /dev/null +++ b/packages/app-next/src/examples/notFoundErrorPageExtension.tsx @@ -0,0 +1,58 @@ +/* + * 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 React from 'react'; +import { createNotFoundErrorPageExtension } from '@backstage/frontend-plugin-api'; +import { Box, Typography } from '@material-ui/core'; +import { Button } from '@backstage/core-components'; + +function CustomNotFoundErrorPage() { + return ( + + 404 + + Bowie was unable to locate this page. Please contact your support team + if this page used to exist. + + Backstage bowie + + + ); +} + +export default createNotFoundErrorPageExtension({ + component: async () => CustomNotFoundErrorPage, +}); diff --git a/packages/frontend-app-api/src/extensions/CoreComponents.tsx b/packages/frontend-app-api/src/extensions/CoreComponents.tsx index a0651d6423..543baef3ad 100644 --- a/packages/frontend-app-api/src/extensions/CoreComponents.tsx +++ b/packages/frontend-app-api/src/extensions/CoreComponents.tsx @@ -32,21 +32,21 @@ import { AppContextProvider } from '../../../core-app-api/src/app/AppContext'; import { useApp } from '../../../core-plugin-api/src/app/useApp'; export const DefaultProgressComponent = createProgressExtension({ - component: defaultComponents.Progress, + component: async () => defaultComponents.Progress, }); export const DefaultBootErrorPageComponent = createBootErrorPageExtension({ - component: defaultComponents.BootErrorPage, + component: async () => defaultComponents.BootErrorPage, }); export const DefaultNotFoundErrorPageComponent = createNotFoundErrorPageExtension({ - component: defaultComponents.NotFoundErrorPage, + component: async () => defaultComponents.NotFoundErrorPage, }); export const DefaultErrorBoundaryComponent = createErrorBoundaryFallbackExtension({ - component: defaultComponents.ErrorBoundaryFallback, + component: async () => defaultComponents.ErrorBoundaryFallback, }); export const CoreComponents = createExtension({ diff --git a/packages/frontend-app-api/src/wiring/createApp.tsx b/packages/frontend-app-api/src/wiring/createApp.tsx index caa7064b2d..deaeded6f1 100644 --- a/packages/frontend-app-api/src/wiring/createApp.tsx +++ b/packages/frontend-app-api/src/wiring/createApp.tsx @@ -390,6 +390,7 @@ function createLegacyAppContext(plugins: BackstagePlugin[]): AppContext { getComponents(): AppComponents { return { ...defaultComponents, + // The default nullable components are overridden by the CoreComponents built-in extension Progress: () => null, BootErrorPage: () => null, NotFoundErrorPage: () => null, diff --git a/packages/frontend-plugin-api/src/components/ExtensionError.tsx b/packages/frontend-plugin-api/src/components/ExtensionError.tsx new file mode 100644 index 0000000000..5aa2ae03bd --- /dev/null +++ b/packages/frontend-plugin-api/src/components/ExtensionError.tsx @@ -0,0 +1,27 @@ +/* + * 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 React from 'react'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { useApp } from '../../../core-plugin-api/src/app/useApp'; + +/** @public */ +export function ExtensionError(props: { error: Error }) { + const { error } = props; + const app = useApp(); + const { BootErrorPage } = app.getComponents(); + return ; +} diff --git a/packages/frontend-plugin-api/src/components/index.ts b/packages/frontend-plugin-api/src/components/index.ts index 7056a59271..fec315fed6 100644 --- a/packages/frontend-plugin-api/src/components/index.ts +++ b/packages/frontend-plugin-api/src/components/index.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +export { ExtensionError } from './ExtensionError'; + export { ExtensionBoundary, type ExtensionBoundaryProps, diff --git a/packages/frontend-plugin-api/src/extensions/createComponentExtension.tsx b/packages/frontend-plugin-api/src/extensions/createComponentExtension.tsx index 5c882dd638..cd86bbdf22 100644 --- a/packages/frontend-plugin-api/src/extensions/createComponentExtension.tsx +++ b/packages/frontend-plugin-api/src/extensions/createComponentExtension.tsx @@ -14,81 +14,194 @@ * limitations under the License. */ -// eslint-disable-next-line @backstage/no-relative-monorepo-imports -import { AppComponents } from '../../../core-app-api/src/app/types'; -import { coreExtensionData, createExtension } from '../wiring'; +import React, { lazy } from 'react'; +import { + AnyExtensionInputMap, + ExtensionInputValues, + coreExtensionData, + createExtension, +} from '../wiring'; +import { + Expand, + CoreProgressComponent, + CoreBootErrorPageComponent, + CoreNotFoundErrorPageComponent, + CoreErrorBoundaryFallbackComponent, +} from '../types'; +import { PortableSchema } from '../schema'; +import { ExtensionError, ExtensionBoundary } from '../components'; /** @public */ -export function createBootErrorPageExtension(options: { - component: AppComponents['BootErrorPage']; +export function createProgressExtension< + TConfig extends {}, + TInputs extends AnyExtensionInputMap, +>(options: { + disabled?: boolean; + inputs?: TInputs; + configSchema?: PortableSchema; + component: (options: { + config: TConfig; + inputs: Expand>; + }) => Promise; }) { + const id = 'core.components.progress'; return createExtension({ - id: `core.components.bootErrorPage`, - attachTo: { id: 'core.components', input: 'bootErrorPage' }, - inputs: {}, - output: { - component: coreExtensionData.components.bootErrorPage, - }, - factory({ bind }) { - bind({ - component: options.component, - }); - }, - }); -} - -/** @public */ -export function createNotFoundErrorPageExtension(options: { - component: AppComponents['NotFoundErrorPage']; -}) { - return createExtension({ - id: `core.components.notFoundErrorPage`, - attachTo: { id: 'core.components', input: 'notFoundErrorPage' }, - inputs: {}, - output: { - component: coreExtensionData.components.notFoundErrorPage, - }, - factory({ bind }) { - bind({ - component: options.component, - }); - }, - }); -} - -/** @public */ -export function createErrorBoundaryFallbackExtension(options: { - component: AppComponents['ErrorBoundaryFallback']; -}) { - return createExtension({ - id: `core.components.errorBoundaryFallback`, - attachTo: { id: 'core.components', input: 'errorBoundaryFallback' }, - inputs: {}, - output: { - component: coreExtensionData.components.errorBoundaryFallback, - }, - factory({ bind }) { - bind({ - component: options.component, - }); - }, - }); -} - -/** @public */ -export function createProgressExtension(options: { - component: AppComponents['Progress']; -}) { - return createExtension({ - id: `core.components.progress`, + id, attachTo: { id: 'core.components', input: 'progress' }, - inputs: {}, + inputs: options.inputs, + disabled: options.disabled, + configSchema: options.configSchema, output: { component: coreExtensionData.components.progress, }, - factory({ bind }) { + factory({ bind, config, inputs, source }) { + const ExtensionComponent = lazy(() => + options + .component({ config, inputs }) + .then(component => ({ default: component })) + .catch(error => ({ + default: () => , + })), + ); + bind({ - component: options.component, + component: props => ( + + + + ), + }); + }, + }); +} + +/** @public */ +export function createBootErrorPageExtension< + TConfig extends {}, + TInputs extends AnyExtensionInputMap, +>(options: { + disabled?: boolean; + inputs?: TInputs; + configSchema?: PortableSchema; + component: (options: { + config: TConfig; + inputs: Expand>; + }) => Promise; +}) { + const id = 'core.components.bootErrorPage'; + return createExtension({ + id, + attachTo: { id: 'core.components', input: 'bootErrorPage' }, + inputs: options.inputs, + disabled: options.disabled, + configSchema: options.configSchema, + output: { + component: coreExtensionData.components.bootErrorPage, + }, + factory({ bind, config, inputs, source }) { + const ExtensionComponent = lazy(() => + options + .component({ config, inputs }) + .then(component => ({ default: component })) + .catch(error => ({ + default: () => , + })), + ); + + bind({ + component: props => ( + + + + ), + }); + }, + }); +} + +/** @public */ +export function createNotFoundErrorPageExtension< + TConfig extends {}, + TInputs extends AnyExtensionInputMap, +>(options: { + disabled?: boolean; + inputs?: TInputs; + configSchema?: PortableSchema; + component: (options: { + config: TConfig; + inputs: Expand>; + }) => Promise; +}) { + const id = 'core.components.notFoundErrorPage'; + return createExtension({ + id, + attachTo: { id: 'core.components', input: 'notFoundErrorPage' }, + inputs: options.inputs, + disabled: options.disabled, + configSchema: options.configSchema, + output: { + component: coreExtensionData.components.notFoundErrorPage, + }, + factory({ bind, config, inputs, source }) { + const ExtensionComponent = lazy(() => + options + .component({ config, inputs }) + .then(component => ({ default: component })) + .catch(error => ({ + default: () => , + })), + ); + + bind({ + component: props => ( + + + + ), + }); + }, + }); +} + +/** @public */ +export function createErrorBoundaryFallbackExtension< + TConfig extends {}, + TInputs extends AnyExtensionInputMap, +>(options: { + disabled?: boolean; + inputs?: TInputs; + configSchema?: PortableSchema; + component: (options: { + config: TConfig; + inputs: Expand>; + }) => Promise; +}) { + const id = 'core.components.errorBoundaryFallback'; + return createExtension({ + id, + attachTo: { id: 'core.components', input: 'errorBoundaryFallback' }, + inputs: options.inputs, + disabled: options.disabled, + configSchema: options.configSchema, + output: { + component: coreExtensionData.components.errorBoundaryFallback, + }, + factory({ bind, config, inputs, source }) { + const ExtensionComponent = lazy(() => + options + .component({ config, inputs }) + .then(component => ({ default: component })) + .catch(error => ({ + default: () => , + })), + ); + + bind({ + component: props => ( + + + + ), }); }, }); diff --git a/packages/frontend-plugin-api/src/extensions/createPageExtension.tsx b/packages/frontend-plugin-api/src/extensions/createPageExtension.tsx index 99733ba367..d05f051a67 100644 --- a/packages/frontend-plugin-api/src/extensions/createPageExtension.tsx +++ b/packages/frontend-plugin-api/src/extensions/createPageExtension.tsx @@ -15,7 +15,7 @@ */ import React, { lazy } from 'react'; -import { ExtensionBoundary } from '../components'; +import { ExtensionError, ExtensionBoundary } from '../components'; import { createSchemaFromZod, PortableSchema } from '../schema'; import { coreExtensionData, @@ -79,7 +79,10 @@ export function createPageExtension< const ExtensionComponent = lazy(() => options .loader({ config, inputs }) - .then(element => ({ default: () => element })), + .then(element => ({ default: () => element })) + .catch(error => ({ + default: () => , + })), ); return { diff --git a/packages/frontend-plugin-api/src/index.ts b/packages/frontend-plugin-api/src/index.ts index 10f89b81b5..a38a7991fb 100644 --- a/packages/frontend-plugin-api/src/index.ts +++ b/packages/frontend-plugin-api/src/index.ts @@ -29,3 +29,10 @@ export * from './routing'; export * from './schema'; export * from './apis/system'; export * from './wiring'; + +export type { + CoreProgressComponent, + CoreBootErrorPageComponent, + CoreNotFoundErrorPageComponent, + CoreErrorBoundaryFallbackComponent, +} from './types'; diff --git a/packages/frontend-plugin-api/src/types.ts b/packages/frontend-plugin-api/src/types.ts index 8b6f02a942..f3f68c362c 100644 --- a/packages/frontend-plugin-api/src/types.ts +++ b/packages/frontend-plugin-api/src/types.ts @@ -14,9 +14,37 @@ * limitations under the License. */ +import { BackstagePlugin } from '@backstage/core-plugin-api'; +import { ComponentType, PropsWithChildren } from 'react'; + // TODO(Rugvip): This might be a quite useful utility type, maybe add to @backstage/types? /** * Utility type to expand type aliases into their equivalent type. * @ignore */ export type Expand = T extends infer O ? { [K in keyof O]: O[K] } : never; + +/** @public */ +export type CoreProgressComponent = ComponentType>; + +/** @public */ +export type CoreBootErrorPageComponent = ComponentType< + PropsWithChildren<{ + step: 'load-config' | 'load-chunk'; + error: Error; + }> +>; + +/** @public */ +export type CoreNotFoundErrorPageComponent = ComponentType< + PropsWithChildren<{}> +>; + +/** @public */ +export type CoreErrorBoundaryFallbackComponent = ComponentType< + PropsWithChildren<{ + plugin?: BackstagePlugin; + error: Error; + resetError: () => void; + }> +>; diff --git a/packages/frontend-plugin-api/src/wiring/coreExtensionData.ts b/packages/frontend-plugin-api/src/wiring/coreExtensionData.ts index 64abfb74eb..d2432b51ae 100644 --- a/packages/frontend-plugin-api/src/wiring/coreExtensionData.ts +++ b/packages/frontend-plugin-api/src/wiring/coreExtensionData.ts @@ -20,9 +20,13 @@ import { AppTheme, IconComponent, } from '@backstage/core-plugin-api'; -// eslint-disable-next-line @backstage/no-relative-monorepo-imports -import { AppComponents } from '../../../core-app-api/src/app/types'; import { RouteRef } from '../routing'; +import { + CoreProgressComponent, + CoreBootErrorPageComponent, + CoreNotFoundErrorPageComponent, + CoreErrorBoundaryFallbackComponent, +} from '../types'; import { createExtensionDataRef } from './createExtensionDataRef'; /** @public */ @@ -51,17 +55,18 @@ export const coreExtensionData = { theme: createExtensionDataRef('core.theme'), logoElements: createExtensionDataRef('core.logos'), components: { - progress: createExtensionDataRef( + progress: createExtensionDataRef( 'core.components.progress', ), - bootErrorPage: createExtensionDataRef( + bootErrorPage: createExtensionDataRef( 'core.components.bootErrorPage', ), - notFoundErrorPage: createExtensionDataRef< - AppComponents['NotFoundErrorPage'] - >('core.components.notFoundErrorPage'), - errorBoundaryFallback: createExtensionDataRef< - AppComponents['ErrorBoundaryFallback'] - >('core.components.errorBoundary'), + notFoundErrorPage: createExtensionDataRef( + 'core.components.notFoundErrorPage', + ), + errorBoundaryFallback: + createExtensionDataRef( + 'core.components.errorBoundary', + ), }, }; From a159a0498e70a2d150f36cf199f962510c98ac43 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Fri, 27 Oct 2023 18:50:06 +0200 Subject: [PATCH 157/261] tests: update built-in extensions Signed-off-by: Camila Belo --- .../src/extensions/CoreComponents.tsx | 48 ++++++++++++++----- .../extractRouteInfoFromAppNode.test.ts | 10 +++- 2 files changed, 44 insertions(+), 14 deletions(-) diff --git a/packages/frontend-app-api/src/extensions/CoreComponents.tsx b/packages/frontend-app-api/src/extensions/CoreComponents.tsx index 543baef3ad..d951983331 100644 --- a/packages/frontend-app-api/src/extensions/CoreComponents.tsx +++ b/packages/frontend-app-api/src/extensions/CoreComponents.tsx @@ -58,6 +58,7 @@ export const CoreComponents = createExtension({ component: coreExtensionData.components.progress, }, { + optional: true, singleton: true, }, ), @@ -66,6 +67,7 @@ export const CoreComponents = createExtension({ component: coreExtensionData.components.bootErrorPage, }, { + optional: true, singleton: true, }, ), @@ -74,6 +76,7 @@ export const CoreComponents = createExtension({ component: coreExtensionData.components.notFoundErrorPage, }, { + optional: true, singleton: true, }, ), @@ -82,6 +85,7 @@ export const CoreComponents = createExtension({ component: coreExtensionData.components.errorBoundaryFallback, }, { + optional: true, singleton: true, }, ), @@ -93,26 +97,44 @@ export const CoreComponents = createExtension({ bind({ provider: function Provider(props: PropsWithChildren<{}>) { const { children } = props; - const parentContext = useApp(); + const app = useApp(); - const appContext = useMemo( + const context = useMemo( () => ({ - ...parentContext, + ...app, // Only override components - getComponents: () => ({ - // Skipping Router and SignInPage - ...parentContext.getComponents(), - Progress: inputs.progress.component, - BootErrorPage: inputs.bootErrorPage.component, - NotFoundErrorPage: inputs.notFoundErrorPage.component, - ErrorBoundaryFallback: inputs.errorBoundaryFallback.component, - }), + getComponents: () => { + const { + progress, + bootErrorPage, + notFoundErrorPage, + errorBoundaryFallback, + } = inputs; + + const { + Progress, + BootErrorPage, + NotFoundErrorPage, + ErrorBoundaryFallback, + ...components + } = app.getComponents(); + + return { + ...components, + Progress: progress?.component ?? Progress, + BootErrorPage: bootErrorPage?.component ?? BootErrorPage, + NotFoundErrorPage: + notFoundErrorPage?.component ?? NotFoundErrorPage, + ErrorBoundaryFallback: + errorBoundaryFallback?.component ?? ErrorBoundaryFallback, + }; + }, }), - [parentContext], + [app], ); return ( - + {children} ); diff --git a/packages/frontend-app-api/src/routing/extractRouteInfoFromAppNode.test.ts b/packages/frontend-app-api/src/routing/extractRouteInfoFromAppNode.test.ts index c94a06a442..ffab978217 100644 --- a/packages/frontend-app-api/src/routing/extractRouteInfoFromAppNode.test.ts +++ b/packages/frontend-app-api/src/routing/extractRouteInfoFromAppNode.test.ts @@ -35,6 +35,7 @@ import { CoreRoutes } from '../extensions/CoreRoutes'; import { CoreNav } from '../extensions/CoreNav'; import { CoreLayout } from '../extensions/CoreLayout'; import { CoreRouter } from '../extensions/CoreRouter'; +import { CoreComponents } from '../extensions/CoreComponents'; const ref1 = createRouteRef(); const ref2 = createRouteRef(); @@ -81,7 +82,14 @@ function routeInfoFromExtensions(extensions: Extension[]) { }); const tree = createAppTree({ config: new MockConfigApi({}), - builtinExtensions: [Core, CoreRoutes, CoreNav, CoreLayout, CoreRouter], + builtinExtensions: [ + Core, + CoreRoutes, + CoreNav, + CoreLayout, + CoreRouter, + CoreComponents, + ], features: [plugin], }); From 52cbee40255c86a3e15e42dfcb1cf78c9d2368ec Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Mon, 30 Oct 2023 12:13:38 +0100 Subject: [PATCH 158/261] refactor: use component ref Signed-off-by: Camila Belo --- .../examples/notFoundErrorPageExtension.tsx | 8 +- .../frontend-app-api/src/extensions/Core.tsx | 17 +- .../src/extensions/CoreComponents.tsx | 144 -------------- .../src/extensions/components.tsx | 46 +++++ .../extractRouteInfoFromAppNode.test.ts | 16 +- .../frontend-app-api/src/wiring/createApp.tsx | 65 +++++-- .../src/components/ComponentRef.tsx | 63 +++++++ .../src/components/ExtensionBoundary.tsx | 12 +- .../src/components/index.ts | 8 + .../extensions/createComponentExtension.tsx | 175 +++--------------- .../src/extensions/index.ts | 7 +- .../src/wiring/coreExtensionData.ts | 31 +--- 12 files changed, 217 insertions(+), 375 deletions(-) delete mode 100644 packages/frontend-app-api/src/extensions/CoreComponents.tsx create mode 100644 packages/frontend-app-api/src/extensions/components.tsx create mode 100644 packages/frontend-plugin-api/src/components/ComponentRef.tsx diff --git a/packages/app-next/src/examples/notFoundErrorPageExtension.tsx b/packages/app-next/src/examples/notFoundErrorPageExtension.tsx index 93807a1757..0e1fbd40f8 100644 --- a/packages/app-next/src/examples/notFoundErrorPageExtension.tsx +++ b/packages/app-next/src/examples/notFoundErrorPageExtension.tsx @@ -15,7 +15,10 @@ */ import React from 'react'; -import { createNotFoundErrorPageExtension } from '@backstage/frontend-plugin-api'; +import { + createComponentExtension, + coreNotFoundErrorPageComponentRef, +} from '@backstage/frontend-plugin-api'; import { Box, Typography } from '@material-ui/core'; import { Button } from '@backstage/core-components'; @@ -53,6 +56,7 @@ function CustomNotFoundErrorPage() { ); } -export default createNotFoundErrorPageExtension({ +export default createComponentExtension({ + ref: coreNotFoundErrorPageComponentRef, component: async () => CustomNotFoundErrorPage, }); diff --git a/packages/frontend-app-api/src/extensions/Core.tsx b/packages/frontend-app-api/src/extensions/Core.tsx index 84407d1f09..441cb5bcf0 100644 --- a/packages/frontend-app-api/src/extensions/Core.tsx +++ b/packages/frontend-app-api/src/extensions/Core.tsx @@ -14,8 +14,6 @@ * limitations under the License. */ -import React from 'react'; - import { coreExtensionData, createExtension, @@ -32,12 +30,9 @@ export const Core = createExtension({ themes: createExtensionInput({ theme: coreExtensionData.theme, }), - components: createExtensionInput( - { - provider: coreExtensionData.reactComponent, - }, - { singleton: true }, - ), + components: createExtensionInput({ + component: coreExtensionData.component, + }), root: createExtensionInput( { element: coreExtensionData.reactElement, @@ -50,11 +45,7 @@ export const Core = createExtension({ }, factory({ inputs }) { return { - root: ( - - {inputs.root.element} - - ), + root: inputs.root.element, }; }, }); diff --git a/packages/frontend-app-api/src/extensions/CoreComponents.tsx b/packages/frontend-app-api/src/extensions/CoreComponents.tsx deleted file mode 100644 index d951983331..0000000000 --- a/packages/frontend-app-api/src/extensions/CoreComponents.tsx +++ /dev/null @@ -1,144 +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 React, { PropsWithChildren, useMemo } from 'react'; -import { - createExtension, - coreExtensionData, - createExtensionInput, - createProgressExtension, - createBootErrorPageExtension, - createNotFoundErrorPageExtension, - createErrorBoundaryFallbackExtension, -} from '@backstage/frontend-plugin-api'; -// eslint-disable-next-line @backstage/no-relative-monorepo-imports -import { components as defaultComponents } from '../../../app-defaults/src/defaults'; -// eslint-disable-next-line @backstage/no-relative-monorepo-imports -import { AppContextProvider } from '../../../core-app-api/src/app/AppContext'; -// eslint-disable-next-line @backstage/no-relative-monorepo-imports -import { useApp } from '../../../core-plugin-api/src/app/useApp'; - -export const DefaultProgressComponent = createProgressExtension({ - component: async () => defaultComponents.Progress, -}); - -export const DefaultBootErrorPageComponent = createBootErrorPageExtension({ - component: async () => defaultComponents.BootErrorPage, -}); - -export const DefaultNotFoundErrorPageComponent = - createNotFoundErrorPageExtension({ - component: async () => defaultComponents.NotFoundErrorPage, - }); - -export const DefaultErrorBoundaryComponent = - createErrorBoundaryFallbackExtension({ - component: async () => defaultComponents.ErrorBoundaryFallback, - }); - -export const CoreComponents = createExtension({ - id: 'core.components', - attachTo: { id: 'core', input: 'components' }, - inputs: { - progress: createExtensionInput( - { - component: coreExtensionData.components.progress, - }, - { - optional: true, - singleton: true, - }, - ), - bootErrorPage: createExtensionInput( - { - component: coreExtensionData.components.bootErrorPage, - }, - { - optional: true, - singleton: true, - }, - ), - notFoundErrorPage: createExtensionInput( - { - component: coreExtensionData.components.notFoundErrorPage, - }, - { - optional: true, - singleton: true, - }, - ), - errorBoundaryFallback: createExtensionInput( - { - component: coreExtensionData.components.errorBoundaryFallback, - }, - { - optional: true, - singleton: true, - }, - ), - }, - output: { - provider: coreExtensionData.reactComponent, - }, - factory({ bind, inputs }) { - bind({ - provider: function Provider(props: PropsWithChildren<{}>) { - const { children } = props; - const app = useApp(); - - const context = useMemo( - () => ({ - ...app, - // Only override components - getComponents: () => { - const { - progress, - bootErrorPage, - notFoundErrorPage, - errorBoundaryFallback, - } = inputs; - - const { - Progress, - BootErrorPage, - NotFoundErrorPage, - ErrorBoundaryFallback, - ...components - } = app.getComponents(); - - return { - ...components, - Progress: progress?.component ?? Progress, - BootErrorPage: bootErrorPage?.component ?? BootErrorPage, - NotFoundErrorPage: - notFoundErrorPage?.component ?? NotFoundErrorPage, - ErrorBoundaryFallback: - errorBoundaryFallback?.component ?? ErrorBoundaryFallback, - }; - }, - }), - [app], - ); - - return ( - - {children} - - ); - }, - }); - }, -}); diff --git a/packages/frontend-app-api/src/extensions/components.tsx b/packages/frontend-app-api/src/extensions/components.tsx new file mode 100644 index 0000000000..5bd4431a28 --- /dev/null +++ b/packages/frontend-app-api/src/extensions/components.tsx @@ -0,0 +1,46 @@ +/* + * 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 { + createComponentExtension, + coreProgressComponentRef, + coreBootErrorPageComponentRef, + coreNotFoundErrorPageComponentRef, + coreErrorBoundaryFallbackComponentRef, +} from '@backstage/frontend-plugin-api'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { components as defaultComponents } from '../../../app-defaults/src/defaults'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports + +export const DefaultProgressComponent = createComponentExtension({ + ref: coreProgressComponentRef, + component: async () => defaultComponents.Progress, +}); + +export const DefaultBootErrorPageComponent = createComponentExtension({ + ref: coreBootErrorPageComponentRef, + component: async () => defaultComponents.BootErrorPage, +}); + +export const DefaultNotFoundErrorPageComponent = createComponentExtension({ + ref: coreNotFoundErrorPageComponentRef, + component: async () => defaultComponents.NotFoundErrorPage, +}); + +export const DefaultErrorBoundaryComponent = createComponentExtension({ + ref: coreErrorBoundaryFallbackComponentRef, + component: async () => defaultComponents.ErrorBoundaryFallback, +}); diff --git a/packages/frontend-app-api/src/routing/extractRouteInfoFromAppNode.test.ts b/packages/frontend-app-api/src/routing/extractRouteInfoFromAppNode.test.ts index ffab978217..a06d236b77 100644 --- a/packages/frontend-app-api/src/routing/extractRouteInfoFromAppNode.test.ts +++ b/packages/frontend-app-api/src/routing/extractRouteInfoFromAppNode.test.ts @@ -30,12 +30,7 @@ import { } from '@backstage/frontend-plugin-api'; import { MockConfigApi } from '@backstage/test-utils'; import { createAppTree } from '../tree'; -import { Core } from '../extensions/Core'; -import { CoreRoutes } from '../extensions/CoreRoutes'; -import { CoreNav } from '../extensions/CoreNav'; -import { CoreLayout } from '../extensions/CoreLayout'; -import { CoreRouter } from '../extensions/CoreRouter'; -import { CoreComponents } from '../extensions/CoreComponents'; +import { builtinExtensions } from '../wiring/createApp'; const ref1 = createRouteRef(); const ref2 = createRouteRef(); @@ -81,15 +76,8 @@ function routeInfoFromExtensions(extensions: Extension[]) { extensions, }); const tree = createAppTree({ + builtinExtensions, config: new MockConfigApi({}), - builtinExtensions: [ - Core, - CoreRoutes, - CoreNav, - CoreLayout, - CoreRouter, - CoreComponents, - ], features: [plugin], }); diff --git a/packages/frontend-app-api/src/wiring/createApp.tsx b/packages/frontend-app-api/src/wiring/createApp.tsx index deaeded6f1..b22d258eae 100644 --- a/packages/frontend-app-api/src/wiring/createApp.tsx +++ b/packages/frontend-app-api/src/wiring/createApp.tsx @@ -20,7 +20,12 @@ import { AppTree, appTreeApiRef, BackstagePlugin, + ComponentRef, + coreBootErrorPageComponentRef, + coreErrorBoundaryFallbackComponentRef, coreExtensionData, + coreNotFoundErrorPageComponentRef, + coreProgressComponentRef, ExtensionDataRef, ExtensionOverrides, RouteRef, @@ -90,12 +95,11 @@ import { resolveRouteBindings } from '../routing/resolveRouteBindings'; import { collectRouteIds } from '../routing/collectRouteIds'; import { createAppTree } from '../tree'; import { - CoreComponents, DefaultProgressComponent, DefaultErrorBoundaryComponent, DefaultBootErrorPageComponent, DefaultNotFoundErrorPageComponent, -} from '../extensions/CoreComponents'; +} from '../extensions/components'; import { AppNode } from '@backstage/frontend-plugin-api'; import { toLegacyPlugin } from '../routing/toLegacyPlugin'; import { InternalAppContext } from './InternalAppContext'; @@ -105,13 +109,12 @@ import { toInternalBackstagePlugin } from '../../../frontend-plugin-api/src/wiri // eslint-disable-next-line @backstage/no-relative-monorepo-imports import { toInternalExtensionOverrides } from '../../../frontend-plugin-api/src/wiring/createExtensionOverrides'; -const builtinExtensions = [ +export const builtinExtensions = [ Core, CoreRouter, CoreRoutes, CoreNav, CoreLayout, - CoreComponents, DefaultProgressComponent, DefaultErrorBoundaryComponent, DefaultBootErrorPageComponent, @@ -316,6 +319,7 @@ export function createSpecializedApp(options?: { features.filter( (f): f is BackstagePlugin => f.$$type === '@backstage/BackstagePlugin', ), + tree.root, ); const appIdentityProxy = new AppIdentityProxy(); @@ -371,7 +375,49 @@ export function createSpecializedApp(options?: { }; } -function createLegacyAppContext(plugins: BackstagePlugin[]): AppContext { +function createLegacyAppContext( + plugins: BackstagePlugin[], + core: AppNode, +): AppContext { + const components = core.edges.attachments + .get('components') + ?.map(e => e.instance?.getData(coreExtensionData.component)); + + function getComponent>( + ref: TRef, + ): TRef['T'] | undefined { + return components?.find(component => component?.ref.id === ref.id)?.impl; + } + + const { + Progress: DefaultProgress, + BootErrorPage: DefaultBootErrorPage, + NotFoundErrorPage: DefaultNotFoundErrorPage, + ErrorBoundaryFallback: DefaultErrorBoundaryFallback, + ...rest + } = defaultComponents; + + const CustomProgress = getComponent(coreProgressComponentRef); + + const CustomBootErrorPage = getComponent(coreBootErrorPageComponentRef); + + const CustomNotFoundErrorPage = getComponent( + coreNotFoundErrorPageComponentRef, + ); + + const CustomErrorBoundaryFallback = getComponent( + coreErrorBoundaryFallbackComponentRef, + ); + + const overriddenComponents = { + ...rest, + Progress: CustomProgress ?? DefaultProgress, + BootErrorPage: CustomBootErrorPage ?? DefaultBootErrorPage, + NotFoundErrorPage: CustomNotFoundErrorPage ?? DefaultNotFoundErrorPage, + ErrorBoundaryFallback: + CustomErrorBoundaryFallback ?? DefaultErrorBoundaryFallback, + }; + return { getPlugins(): LegacyBackstagePlugin[] { return plugins.map(toLegacyPlugin); @@ -388,14 +434,7 @@ function createLegacyAppContext(plugins: BackstagePlugin[]): AppContext { }, getComponents(): AppComponents { - return { - ...defaultComponents, - // The default nullable components are overridden by the CoreComponents built-in extension - Progress: () => null, - BootErrorPage: () => null, - NotFoundErrorPage: () => null, - ErrorBoundaryFallback: () => null, - }; + return overriddenComponents; }, }; } diff --git a/packages/frontend-plugin-api/src/components/ComponentRef.tsx b/packages/frontend-plugin-api/src/components/ComponentRef.tsx new file mode 100644 index 0000000000..13588ba779 --- /dev/null +++ b/packages/frontend-plugin-api/src/components/ComponentRef.tsx @@ -0,0 +1,63 @@ +/* + * 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 { + CoreBootErrorPageComponent, + CoreErrorBoundaryFallbackComponent, + CoreNotFoundErrorPageComponent, + CoreProgressComponent, +} from '../types'; + +/** @public */ +export type ComponentRef = { + id: string; + T: T; +}; + +/** @public */ +export function createComponentRef(options: { + id: string; +}): ComponentRef { + const { id } = options; + return { + id, + get T(): T { + throw new Error(`tried to read ComponentRef.T of ${id}`); + }, + }; +} + +/** @public */ +export const coreProgressComponentRef = + createComponentRef({ id: 'core.components.progress' }); + +/** @public */ +export const coreBootErrorPageComponentRef = + createComponentRef({ + id: 'core.components.bootErrorPage', + }); + +/** @public */ +export const coreNotFoundErrorPageComponentRef = + createComponentRef({ + id: 'core.components.notFoundErrorPage', + }); + +/** @public */ +export const coreErrorBoundaryFallbackComponentRef = + createComponentRef({ + id: 'core.components.errorBoundaryFallback', + }); diff --git a/packages/frontend-plugin-api/src/components/ExtensionBoundary.tsx b/packages/frontend-plugin-api/src/components/ExtensionBoundary.tsx index 8fad8d8336..c9fa75c7fa 100644 --- a/packages/frontend-plugin-api/src/components/ExtensionBoundary.tsx +++ b/packages/frontend-plugin-api/src/components/ExtensionBoundary.tsx @@ -14,10 +14,14 @@ * limitations under the License. */ -import React, { PropsWithChildren, ReactNode, useEffect } from 'react'; +import React, { + PropsWithChildren, + ReactNode, + Suspense, + useEffect, +} from 'react'; import { AnalyticsContext, useAnalytics } from '@backstage/core-plugin-api'; import { ErrorBoundary } from './ErrorBoundary'; -import { ExtensionSuspense } from './ExtensionSuspense'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports import { routableExtensionRenderedEvent } from '../../../core-plugin-api/src/analytics/Tracker'; import { AppNode } from '../apis'; @@ -60,12 +64,12 @@ export function ExtensionBoundary(props: ExtensionBoundaryProps) { }; return ( - + {children} - + ); } diff --git a/packages/frontend-plugin-api/src/components/index.ts b/packages/frontend-plugin-api/src/components/index.ts index fec315fed6..4bee5c5f7b 100644 --- a/packages/frontend-plugin-api/src/components/index.ts +++ b/packages/frontend-plugin-api/src/components/index.ts @@ -14,6 +14,14 @@ * limitations under the License. */ +export { + coreProgressComponentRef, + coreBootErrorPageComponentRef, + coreErrorBoundaryFallbackComponentRef, + coreNotFoundErrorPageComponentRef, + type ComponentRef, +} from './ComponentRef'; + export { ExtensionError } from './ExtensionError'; export { diff --git a/packages/frontend-plugin-api/src/extensions/createComponentExtension.tsx b/packages/frontend-plugin-api/src/extensions/createComponentExtension.tsx index cd86bbdf22..678d05049d 100644 --- a/packages/frontend-plugin-api/src/extensions/createComponentExtension.tsx +++ b/packages/frontend-plugin-api/src/extensions/createComponentExtension.tsx @@ -21,40 +21,36 @@ import { coreExtensionData, createExtension, } from '../wiring'; -import { - Expand, - CoreProgressComponent, - CoreBootErrorPageComponent, - CoreNotFoundErrorPageComponent, - CoreErrorBoundaryFallbackComponent, -} from '../types'; +import { Expand } from '../types'; import { PortableSchema } from '../schema'; -import { ExtensionError, ExtensionBoundary } from '../components'; +import { ExtensionError, ExtensionBoundary, ComponentRef } from '../components'; /** @public */ -export function createProgressExtension< +export function createComponentExtension< + TRef extends ComponentRef, TConfig extends {}, TInputs extends AnyExtensionInputMap, >(options: { + ref: TRef; disabled?: boolean; inputs?: TInputs; configSchema?: PortableSchema; - component: (options: { + component: (values: { config: TConfig; inputs: Expand>; - }) => Promise; + }) => Promise; }) { - const id = 'core.components.progress'; + const id = options.ref.id; return createExtension({ id, - attachTo: { id: 'core.components', input: 'progress' }, + attachTo: { id: 'core', input: 'components' }, inputs: options.inputs, disabled: options.disabled, configSchema: options.configSchema, output: { - component: coreExtensionData.components.progress, + component: coreExtensionData.component, }, - factory({ bind, config, inputs, source }) { + factory({ config, inputs, source }) { const ExtensionComponent = lazy(() => options .component({ config, inputs }) @@ -64,145 +60,16 @@ export function createProgressExtension< })), ); - bind({ - component: props => ( - - - - ), - }); - }, - }); -} - -/** @public */ -export function createBootErrorPageExtension< - TConfig extends {}, - TInputs extends AnyExtensionInputMap, ->(options: { - disabled?: boolean; - inputs?: TInputs; - configSchema?: PortableSchema; - component: (options: { - config: TConfig; - inputs: Expand>; - }) => Promise; -}) { - const id = 'core.components.bootErrorPage'; - return createExtension({ - id, - attachTo: { id: 'core.components', input: 'bootErrorPage' }, - inputs: options.inputs, - disabled: options.disabled, - configSchema: options.configSchema, - output: { - component: coreExtensionData.components.bootErrorPage, - }, - factory({ bind, config, inputs, source }) { - const ExtensionComponent = lazy(() => - options - .component({ config, inputs }) - .then(component => ({ default: component })) - .catch(error => ({ - default: () => , - })), - ); - - bind({ - component: props => ( - - - - ), - }); - }, - }); -} - -/** @public */ -export function createNotFoundErrorPageExtension< - TConfig extends {}, - TInputs extends AnyExtensionInputMap, ->(options: { - disabled?: boolean; - inputs?: TInputs; - configSchema?: PortableSchema; - component: (options: { - config: TConfig; - inputs: Expand>; - }) => Promise; -}) { - const id = 'core.components.notFoundErrorPage'; - return createExtension({ - id, - attachTo: { id: 'core.components', input: 'notFoundErrorPage' }, - inputs: options.inputs, - disabled: options.disabled, - configSchema: options.configSchema, - output: { - component: coreExtensionData.components.notFoundErrorPage, - }, - factory({ bind, config, inputs, source }) { - const ExtensionComponent = lazy(() => - options - .component({ config, inputs }) - .then(component => ({ default: component })) - .catch(error => ({ - default: () => , - })), - ); - - bind({ - component: props => ( - - - - ), - }); - }, - }); -} - -/** @public */ -export function createErrorBoundaryFallbackExtension< - TConfig extends {}, - TInputs extends AnyExtensionInputMap, ->(options: { - disabled?: boolean; - inputs?: TInputs; - configSchema?: PortableSchema; - component: (options: { - config: TConfig; - inputs: Expand>; - }) => Promise; -}) { - const id = 'core.components.errorBoundaryFallback'; - return createExtension({ - id, - attachTo: { id: 'core.components', input: 'errorBoundaryFallback' }, - inputs: options.inputs, - disabled: options.disabled, - configSchema: options.configSchema, - output: { - component: coreExtensionData.components.errorBoundaryFallback, - }, - factory({ bind, config, inputs, source }) { - const ExtensionComponent = lazy(() => - options - .component({ config, inputs }) - .then(component => ({ default: component })) - .catch(error => ({ - default: () => , - })), - ); - - bind({ - component: props => ( - - - - ), - }); + return { + component: { + ref: options.ref, + impl: props => ( + + + + ), + }, + }; }, }); } diff --git a/packages/frontend-plugin-api/src/extensions/index.ts b/packages/frontend-plugin-api/src/extensions/index.ts index d036cb5dda..a3be81f2a3 100644 --- a/packages/frontend-plugin-api/src/extensions/index.ts +++ b/packages/frontend-plugin-api/src/extensions/index.ts @@ -19,9 +19,4 @@ export { createPageExtension } from './createPageExtension'; export { createNavItemExtension } from './createNavItemExtension'; export { createSignInPageExtension } from './createSignInPageExtension'; export { createThemeExtension } from './createThemeExtension'; -export { - createProgressExtension, - createBootErrorPageExtension, - createNotFoundErrorPageExtension, - createErrorBoundaryFallbackExtension, -} from './createComponentExtension'; +export { createComponentExtension } from './createComponentExtension'; diff --git a/packages/frontend-plugin-api/src/wiring/coreExtensionData.ts b/packages/frontend-plugin-api/src/wiring/coreExtensionData.ts index d2432b51ae..9bdb4b23eb 100644 --- a/packages/frontend-plugin-api/src/wiring/coreExtensionData.ts +++ b/packages/frontend-plugin-api/src/wiring/coreExtensionData.ts @@ -14,19 +14,14 @@ * limitations under the License. */ -import { JSX } from 'react'; +import { ComponentType, JSX } from 'react'; import { AnyApiFactory, AppTheme, IconComponent, } from '@backstage/core-plugin-api'; import { RouteRef } from '../routing'; -import { - CoreProgressComponent, - CoreBootErrorPageComponent, - CoreNotFoundErrorPageComponent, - CoreErrorBoundaryFallbackComponent, -} from '../types'; +import { ComponentRef } from '../components'; import { createExtensionDataRef } from './createExtensionDataRef'; /** @public */ @@ -44,9 +39,6 @@ export type LogoElements = { /** @public */ export const coreExtensionData = { - reactComponent: createExtensionDataRef< - (props: T) => JSX.Element - >('core.reactComponent'), reactElement: createExtensionDataRef('core.reactElement'), routePath: createExtensionDataRef('core.routing.path'), apiFactory: createExtensionDataRef('core.api.factory'), @@ -54,19 +46,8 @@ export const coreExtensionData = { navTarget: createExtensionDataRef('core.nav.target'), theme: createExtensionDataRef('core.theme'), logoElements: createExtensionDataRef('core.logos'), - components: { - progress: createExtensionDataRef( - 'core.components.progress', - ), - bootErrorPage: createExtensionDataRef( - 'core.components.bootErrorPage', - ), - notFoundErrorPage: createExtensionDataRef( - 'core.components.notFoundErrorPage', - ), - errorBoundaryFallback: - createExtensionDataRef( - 'core.components.errorBoundary', - ), - }, + component: createExtensionDataRef<{ + ref: ComponentRef>; + impl: ComponentType; + }>('component.ref'), }; From 227c7394ea2b8939464190fb643b058b715b43f5 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Mon, 30 Oct 2023 15:18:33 +0100 Subject: [PATCH 159/261] feat: create collect legacy components Signed-off-by: Camila Belo --- packages/app-next/src/App.tsx | 13 +++- .../examples/notFoundErrorPageExtension.tsx | 2 +- .../src/collectLegacyComponents.test.tsx | 61 +++++++++++++++++++ .../src/collectLegacyComponents.tsx | 53 ++++++++++++++++ packages/core-compat-api/src/index.ts | 1 + 5 files changed, 126 insertions(+), 4 deletions(-) create mode 100644 packages/core-compat-api/src/collectLegacyComponents.test.tsx create mode 100644 packages/core-compat-api/src/collectLegacyComponents.tsx diff --git a/packages/app-next/src/App.tsx b/packages/app-next/src/App.tsx index 3fb91bd03e..791d2b38fa 100644 --- a/packages/app-next/src/App.tsx +++ b/packages/app-next/src/App.tsx @@ -17,7 +17,7 @@ import React from 'react'; import { createApp } from '@backstage/frontend-app-api'; import { pagesPlugin } from './examples/pagesPlugin'; -import customNotFoundErrorPage from './examples/notFoundErrorPageExtension'; +import { CustomNotFoundErrorPage } from './examples/notFoundErrorPageExtension'; import graphiqlPlugin from '@backstage/plugin-graphiql/alpha'; import techRadarPlugin from '@backstage/plugin-tech-radar/alpha'; import userSettingsPlugin from '@backstage/plugin-user-settings/alpha'; @@ -33,7 +33,10 @@ import { } from '@backstage/frontend-plugin-api'; import techdocsPlugin from '@backstage/plugin-techdocs/alpha'; import { homePage } from './HomePage'; -import { collectLegacyRoutes } from '@backstage/core-compat-api'; +import { + collectLegacyComponents, + collectLegacyRoutes, +} from '@backstage/core-compat-api'; import { FlatRoutes } from '@backstage/core-app-api'; import { Route } from 'react-router'; import { CatalogImportPage } from '@backstage/plugin-catalog-import'; @@ -115,6 +118,10 @@ const collectedLegacyPlugins = collectLegacyRoutes( , ); +const legacyAppComponents = collectLegacyComponents({ + NotFoundErrorPage: CustomNotFoundErrorPage, +}); + const app = createApp({ features: [ graphiqlPlugin, @@ -130,7 +137,7 @@ const app = createApp({ scmAuthExtension, scmIntegrationApi, signInPage, - customNotFoundErrorPage, + ...legacyAppComponents, ], }), ], diff --git a/packages/app-next/src/examples/notFoundErrorPageExtension.tsx b/packages/app-next/src/examples/notFoundErrorPageExtension.tsx index 0e1fbd40f8..c076b059f4 100644 --- a/packages/app-next/src/examples/notFoundErrorPageExtension.tsx +++ b/packages/app-next/src/examples/notFoundErrorPageExtension.tsx @@ -22,7 +22,7 @@ import { import { Box, Typography } from '@material-ui/core'; import { Button } from '@backstage/core-components'; -function CustomNotFoundErrorPage() { +export function CustomNotFoundErrorPage() { return ( { + const components = { + Progress: () =>
Progress
, + BootErrorPage: () =>
BootErrorPage
, + NotFoundErrorPage: () =>
NotFoundErrorPage
, + ErrorBoundaryFallback: () =>
ErrorBoundaryFallback
, + }; + + it('should collect legacy routes', () => { + const collected = collectLegacyComponents(components); + + expect( + collected.map(p => ({ + id: p.id, + attachTo: p.attachTo, + disabled: p.disabled, + })), + ).toEqual([ + { + id: 'core.components.progress', + attachTo: { id: 'core', input: 'components' }, + disabled: false, + }, + { + id: 'core.components.bootErrorPage', + attachTo: { id: 'core', input: 'components' }, + disabled: false, + }, + { + id: 'core.components.notFoundErrorPage', + attachTo: { id: 'core', input: 'components' }, + disabled: false, + }, + { + id: 'core.components.errorBoundaryFallback', + attachTo: { id: 'core', input: 'components' }, + disabled: false, + }, + ]); + }); +}); diff --git a/packages/core-compat-api/src/collectLegacyComponents.tsx b/packages/core-compat-api/src/collectLegacyComponents.tsx new file mode 100644 index 0000000000..97c3ee22ad --- /dev/null +++ b/packages/core-compat-api/src/collectLegacyComponents.tsx @@ -0,0 +1,53 @@ +/* + * 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 { + Extension, + ComponentRef, + createComponentExtension, + coreProgressComponentRef, + coreBootErrorPageComponentRef, + coreNotFoundErrorPageComponentRef, + coreErrorBoundaryFallbackComponentRef, +} from '@backstage/frontend-plugin-api'; +import { AppComponents } from '@backstage/core-plugin-api'; + +type ComponentTypes = T[keyof T]; + +const refs: Record> = { + Progress: coreProgressComponentRef, + BootErrorPage: coreBootErrorPageComponentRef, + NotFoundErrorPage: coreNotFoundErrorPageComponentRef, + ErrorBoundaryFallback: coreErrorBoundaryFallbackComponentRef, +}; + +/** @public */ +export function collectLegacyComponents(components: Partial) { + return Object.entries(components).reduce[]>( + (extensions, [componentName, componentFunction]) => { + const ref = refs[componentName]; + return ref + ? extensions.concat( + createComponentExtension({ + ref, + component: async () => componentFunction, + }), + ) + : extensions; + }, + [], + ); +} diff --git a/packages/core-compat-api/src/index.ts b/packages/core-compat-api/src/index.ts index 421ced7054..d31513e559 100644 --- a/packages/core-compat-api/src/index.ts +++ b/packages/core-compat-api/src/index.ts @@ -14,5 +14,6 @@ * limitations under the License. */ export { collectLegacyRoutes } from './collectLegacyRoutes'; +export { collectLegacyComponents } from './collectLegacyComponents'; export { convertLegacyApp } from './convertLegacyApp'; export { convertLegacyRouteRef } from './convertLegacyRouteRef'; From 8f80db46b7a7dab2caea73a727a986e422151275 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Mon, 6 Nov 2023 09:27:53 +0100 Subject: [PATCH 160/261] refactor: use new components context Signed-off-by: Camila Belo --- .../frontend-app-api/src/extensions/Core.tsx | 16 ++++- .../src/extensions/CoreRoutes.tsx | 8 +-- .../src/components/ComponentsContext.tsx | 58 +++++++++++++++++++ .../src/components/index.ts | 6 ++ 4 files changed, 83 insertions(+), 5 deletions(-) create mode 100644 packages/frontend-plugin-api/src/components/ComponentsContext.tsx diff --git a/packages/frontend-app-api/src/extensions/Core.tsx b/packages/frontend-app-api/src/extensions/Core.tsx index 441cb5bcf0..4347eb1b45 100644 --- a/packages/frontend-app-api/src/extensions/Core.tsx +++ b/packages/frontend-app-api/src/extensions/Core.tsx @@ -18,7 +18,9 @@ import { coreExtensionData, createExtension, createExtensionInput, + ComponentsProvider, } from '@backstage/frontend-plugin-api'; +import React from 'react'; export const Core = createExtension({ id: 'core', @@ -44,8 +46,20 @@ export const Core = createExtension({ root: coreExtensionData.reactElement, }, factory({ inputs }) { + const components = inputs.components.reduce( + (rest, { component }) => ({ + ...rest, + [component.ref.id]: component.impl, + }), + {}, + ); + return { - root: inputs.root.element, + root: ( + + {inputs.root.element} + + ), }; }, }); diff --git a/packages/frontend-app-api/src/extensions/CoreRoutes.tsx b/packages/frontend-app-api/src/extensions/CoreRoutes.tsx index e2798c091d..b2918cfcc9 100644 --- a/packages/frontend-app-api/src/extensions/CoreRoutes.tsx +++ b/packages/frontend-app-api/src/extensions/CoreRoutes.tsx @@ -19,10 +19,10 @@ import { createExtension, coreExtensionData, createExtensionInput, + coreNotFoundErrorPageComponentRef, + useComponent, } from '@backstage/frontend-plugin-api'; import { useRoutes } from 'react-router-dom'; -// eslint-disable-next-line @backstage/no-relative-monorepo-imports -import { useApp } from '../../../core-plugin-api/src/app/useApp'; export const CoreRoutes = createExtension({ id: 'core.routes', @@ -39,8 +39,8 @@ export const CoreRoutes = createExtension({ }, factory({ inputs }) { const Routes = () => { - const app = useApp(); - const { NotFoundErrorPage } = app.getComponents(); + const NotFoundErrorPage = useComponent(coreNotFoundErrorPageComponentRef); + const element = useRoutes([ ...inputs.routes.map(route => ({ path: `${route.path}/*`, diff --git a/packages/frontend-plugin-api/src/components/ComponentsContext.tsx b/packages/frontend-plugin-api/src/components/ComponentsContext.tsx new file mode 100644 index 0000000000..7b1058f83c --- /dev/null +++ b/packages/frontend-plugin-api/src/components/ComponentsContext.tsx @@ -0,0 +1,58 @@ +/* + * 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 { ComponentRef } from '@backstage/frontend-plugin-api'; +import { + createVersionedContext, + createVersionedValueMap, + useVersionedContext, +} from '@backstage/version-bridge'; +import React from 'react'; +import { ComponentType, PropsWithChildren } from 'react'; + +/** @public */ +export type ComponentsContextValue = Record>; + +const ComponentsContext = createVersionedContext<{ 1: ComponentsContextValue }>( + 'components-context', +); + +/** @public */ +export function ComponentsProvider( + props: PropsWithChildren<{ value: ComponentsContextValue }>, +) { + const { value, children } = props; + return ( + + {children} + + ); +} + +/** @public */ +export function useComponent< + P extends {}, + T extends ComponentRef>, +>(ref: T): T['T'] { + const components = useVersionedContext<{ 1: ComponentsContextValue }>( + 'components-context', + ); + const component = components?.atVersion(1)?.[ref.id]; + if (!component) { + throw new Error(`No implementation available for ${ref.id}`); + } + return component; +} diff --git a/packages/frontend-plugin-api/src/components/index.ts b/packages/frontend-plugin-api/src/components/index.ts index 4bee5c5f7b..575e5efbe0 100644 --- a/packages/frontend-plugin-api/src/components/index.ts +++ b/packages/frontend-plugin-api/src/components/index.ts @@ -14,6 +14,12 @@ * limitations under the License. */ +export { + ComponentsProvider, + useComponent, + type ComponentsContextValue, +} from './ComponentsContext'; + export { coreProgressComponentRef, coreBootErrorPageComponentRef, From 9c6b0ab576cbe66bc119d93d7057efe248dc9068 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Sat, 11 Nov 2023 11:17:38 +0100 Subject: [PATCH 161/261] test: update root tree snapshot Signed-off-by: Camila Belo --- packages/frontend-app-api/src/wiring/createApp.test.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/frontend-app-api/src/wiring/createApp.test.tsx b/packages/frontend-app-api/src/wiring/createApp.test.tsx index 41d722a68e..232de74de4 100644 --- a/packages/frontend-app-api/src/wiring/createApp.test.tsx +++ b/packages/frontend-app-api/src/wiring/createApp.test.tsx @@ -199,6 +199,12 @@ describe('createApp', () => { ] ] + components [ + + + + + ] themes [ From cba5b3ba3bac128063014de768de44fc4b6dee28 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Fri, 27 Oct 2023 13:57:41 +0200 Subject: [PATCH 162/261] docs: update api reports Signed-off-by: Camila Belo --- packages/core-compat-api/api-report.md | 7 ++ packages/frontend-plugin-api/api-report.md | 88 +++++++++++++++++++ .../extensions/createComponentExtension.tsx | 4 +- 3 files changed, 97 insertions(+), 2 deletions(-) diff --git a/packages/core-compat-api/api-report.md b/packages/core-compat-api/api-report.md index 877aefa24f..866517b5c8 100644 --- a/packages/core-compat-api/api-report.md +++ b/packages/core-compat-api/api-report.md @@ -6,7 +6,9 @@ /// import { AnyRouteRefParams } from '@backstage/core-plugin-api'; +import { AppComponents } from '@backstage/core-plugin-api'; import { BackstagePlugin } from '@backstage/frontend-plugin-api'; +import { Extension } from '@backstage/frontend-plugin-api'; import { ExtensionOverrides } from '@backstage/frontend-plugin-api'; import { ExternalRouteRef } from '@backstage/core-plugin-api'; import { ExternalRouteRef as ExternalRouteRef_2 } from '@backstage/frontend-plugin-api'; @@ -16,6 +18,11 @@ import { RouteRef as RouteRef_2 } from '@backstage/frontend-plugin-api'; import { SubRouteRef } from '@backstage/core-plugin-api'; import { SubRouteRef as SubRouteRef_2 } from '@backstage/frontend-plugin-api'; +// @public (undocumented) +export function collectLegacyComponents( + components: Partial, +): Extension[]; + // @public (undocumented) export function collectLegacyRoutes( flatRoutesElement: JSX.Element, diff --git a/packages/frontend-plugin-api/api-report.md b/packages/frontend-plugin-api/api-report.md index c1c920559e..2255dafdd0 100644 --- a/packages/frontend-plugin-api/api-report.md +++ b/packages/frontend-plugin-api/api-report.md @@ -22,9 +22,11 @@ import { AuthProviderInfo } from '@backstage/core-plugin-api'; import { AuthRequestOptions } from '@backstage/core-plugin-api'; import { BackstageIdentityApi } from '@backstage/core-plugin-api'; import { BackstageIdentityResponse } from '@backstage/core-plugin-api'; +import { BackstagePlugin as BackstagePlugin_2 } from '@backstage/core-plugin-api'; import { BackstageUserIdentity } from '@backstage/core-plugin-api'; import { bitbucketAuthApiRef } from '@backstage/core-plugin-api'; import { bitbucketServerAuthApiRef } from '@backstage/core-plugin-api'; +import { ComponentRef as ComponentRef_2 } from '@backstage/frontend-plugin-api'; import { ComponentType } from 'react'; import { ConfigApi } from '@backstage/core-plugin-api'; import { configApiRef } from '@backstage/core-plugin-api'; @@ -64,6 +66,7 @@ import { OpenIdConnectApi } from '@backstage/core-plugin-api'; import { PendingOAuthRequest } from '@backstage/core-plugin-api'; import { ProfileInfo } from '@backstage/core-plugin-api'; import { ProfileInfoApi } from '@backstage/core-plugin-api'; +import { PropsWithChildren } from 'react'; import { default as React_2 } from 'react'; import { ReactNode } from 'react'; import { SessionApi } from '@backstage/core-plugin-api'; @@ -284,6 +287,22 @@ export type CommonAnalyticsContext = { extensionId: string; }; +// @public (undocumented) +export type ComponentRef = { + id: string; + T: T; +}; + +// @public (undocumented) +export type ComponentsContextValue = Record>; + +// @public (undocumented) +export function ComponentsProvider( + props: PropsWithChildren<{ + value: ComponentsContextValue; + }>, +): React_2.JSX.Element; + export { ConfigApi }; export { configApiRef }; @@ -304,6 +323,29 @@ export interface ConfigurableExtensionDataRef< >; } +// @public (undocumented) +export type CoreBootErrorPageComponent = ComponentType< + PropsWithChildren<{ + step: 'load-config' | 'load-chunk'; + error: Error; + }> +>; + +// @public (undocumented) +export const coreBootErrorPageComponentRef: ComponentRef; + +// @public (undocumented) +export type CoreErrorBoundaryFallbackComponent = ComponentType< + PropsWithChildren<{ + plugin?: BackstagePlugin_2; + error: Error; + resetError: () => void; + }> +>; + +// @public (undocumented) +export const coreErrorBoundaryFallbackComponentRef: ComponentRef; + // @public (undocumented) export const coreExtensionData: { reactElement: ConfigurableExtensionDataRef; @@ -313,8 +355,29 @@ export const coreExtensionData: { navTarget: ConfigurableExtensionDataRef; theme: ConfigurableExtensionDataRef; logoElements: ConfigurableExtensionDataRef; + component: ConfigurableExtensionDataRef< + { + ref: ComponentRef>; + impl: ComponentType; + }, + {} + >; }; +// @public (undocumented) +export type CoreNotFoundErrorPageComponent = ComponentType< + PropsWithChildren<{}> +>; + +// @public (undocumented) +export const coreNotFoundErrorPageComponentRef: ComponentRef; + +// @public (undocumented) +export type CoreProgressComponent = ComponentType>; + +// @public (undocumented) +export const coreProgressComponentRef: ComponentRef; + // @public (undocumented) export function createApiExtension< TConfig extends {}, @@ -341,6 +404,22 @@ export { createApiFactory }; export { createApiRef }; +// @public (undocumented) +export function createComponentExtension< + TRef extends ComponentRef, + TConfig extends {}, + TInputs extends AnyExtensionInputMap, +>(options: { + ref: TRef; + disabled?: boolean; + inputs?: TInputs; + configSchema?: PortableSchema; + component: (values: { + config: TConfig; + inputs: Expand>; + }) => Promise; +}): Extension; + // @public (undocumented) export function createExtension< TOutput extends AnyExtensionDataMap, @@ -621,6 +700,9 @@ export type ExtensionDataValues = { : never]?: TExtensionData[DataName]['T']; }; +// @public (undocumented) +export function ExtensionError(props: { error: Error }): React_2.JSX.Element; + // @public (undocumented) export interface ExtensionInput< TExtensionData extends AnyExtensionDataMap, @@ -828,6 +910,12 @@ export { useApi }; export { useApiHolder }; +// @public (undocumented) +export function useComponent< + P extends {}, + T extends ComponentRef_2>, +>(ref: T): T['T']; + // @public export function useRouteRef< TOptional extends boolean, diff --git a/packages/frontend-plugin-api/src/extensions/createComponentExtension.tsx b/packages/frontend-plugin-api/src/extensions/createComponentExtension.tsx index 678d05049d..376510312f 100644 --- a/packages/frontend-plugin-api/src/extensions/createComponentExtension.tsx +++ b/packages/frontend-plugin-api/src/extensions/createComponentExtension.tsx @@ -50,7 +50,7 @@ export function createComponentExtension< output: { component: coreExtensionData.component, }, - factory({ config, inputs, source }) { + factory({ config, inputs, node }) { const ExtensionComponent = lazy(() => options .component({ config, inputs }) @@ -64,7 +64,7 @@ export function createComponentExtension< component: { ref: options.ref, impl: props => ( - + ), From 1f12fb762c365d19f3824dee7351e7637f31047d Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Fri, 27 Oct 2023 10:07:33 +0200 Subject: [PATCH 163/261] docs: add changeset files Signed-off-by: Camila Belo --- .changeset/brown-books-carry.md | 5 +++++ .changeset/clever-wombats-sneeze.md | 5 +++++ 2 files changed, 10 insertions(+) create mode 100644 .changeset/brown-books-carry.md create mode 100644 .changeset/clever-wombats-sneeze.md diff --git a/.changeset/brown-books-carry.md b/.changeset/brown-books-carry.md new file mode 100644 index 0000000000..1299354445 --- /dev/null +++ b/.changeset/brown-books-carry.md @@ -0,0 +1,5 @@ +--- +'@backstage/frontend-app-api': patch +--- + +Create a core components extension that allows adopters to override core app components such as `Progress`, `BootErrorPage`, `NotFoundErrorPage` and `ErrorBoundaryFallback`. diff --git a/.changeset/clever-wombats-sneeze.md b/.changeset/clever-wombats-sneeze.md new file mode 100644 index 0000000000..ffd94aa9f0 --- /dev/null +++ b/.changeset/clever-wombats-sneeze.md @@ -0,0 +1,5 @@ +--- +'@backstage/frontend-plugin-api': patch +--- + +Create factories for overriding default core components extensions. From 221293e22d0089c4486f18dd48e5fa6828021884 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Fri, 17 Nov 2023 16:30:36 +0100 Subject: [PATCH 164/261] frontend-*-api: initial ComponentsApi 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: Camila Belo Signed-off-by: Patrik Oldsberg --- .../ComponentsApi/ComponentsApi.ts | 34 +++++++++++++++++ .../implementations/ComponentsApi/index.ts | 17 +++++++++ .../src/apis/definitions/ComponentsApi.ts | 37 +++++++++++++++++++ .../src/apis/definitions/index.ts | 1 + 4 files changed, 89 insertions(+) create mode 100644 packages/frontend-app-api/src/apis/implementations/ComponentsApi/ComponentsApi.ts create mode 100644 packages/frontend-app-api/src/apis/implementations/ComponentsApi/index.ts create mode 100644 packages/frontend-plugin-api/src/apis/definitions/ComponentsApi.ts diff --git a/packages/frontend-app-api/src/apis/implementations/ComponentsApi/ComponentsApi.ts b/packages/frontend-app-api/src/apis/implementations/ComponentsApi/ComponentsApi.ts new file mode 100644 index 0000000000..87a12d136e --- /dev/null +++ b/packages/frontend-app-api/src/apis/implementations/ComponentsApi/ComponentsApi.ts @@ -0,0 +1,34 @@ +/* + * 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 { ComponentRef, ComponentsApi } from '@backstage/frontend-plugin-api'; + +/** + * Implementation for the {@linkComponentApi} + * + * @internal + */ +export class DefaultComponentsApi implements ComponentsApi { + #components: Map, any>; + + constructor(components: Map, any>) { + this.#components = components; + } + + getComponent(ref: ComponentRef): T | undefined { + return this.#components.get(ref); + } +} diff --git a/packages/frontend-app-api/src/apis/implementations/ComponentsApi/index.ts b/packages/frontend-app-api/src/apis/implementations/ComponentsApi/index.ts new file mode 100644 index 0000000000..f04059c54f --- /dev/null +++ b/packages/frontend-app-api/src/apis/implementations/ComponentsApi/index.ts @@ -0,0 +1,17 @@ +/* + * 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 { DefaultComponentsApi } from './ComponentsApi'; diff --git a/packages/frontend-plugin-api/src/apis/definitions/ComponentsApi.ts b/packages/frontend-plugin-api/src/apis/definitions/ComponentsApi.ts new file mode 100644 index 0000000000..6f057e70f2 --- /dev/null +++ b/packages/frontend-plugin-api/src/apis/definitions/ComponentsApi.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 { ComponentRef } from '../../components'; +import { createApiRef } from '../system'; + +/** + * API for looking up components based on component refs. + * + * @public + */ +export interface ComponentsApi { + // TODO: Should component refs also provide the default implementation so that we're guaranteed to get a component? + getComponent(ref: ComponentRef): T | undefined; +} + +/** + * The `ApiRef` of {@link ComponentsApi}. + * + * @public + */ +export const componentsApiRef = createApiRef({ + id: 'core.components', +}); diff --git a/packages/frontend-plugin-api/src/apis/definitions/index.ts b/packages/frontend-plugin-api/src/apis/definitions/index.ts index 8791912e4a..f2496ee61a 100644 --- a/packages/frontend-plugin-api/src/apis/definitions/index.ts +++ b/packages/frontend-plugin-api/src/apis/definitions/index.ts @@ -34,6 +34,7 @@ export * from './auth'; export * from './AlertApi'; export * from './AppThemeApi'; +export * from './ComponentsApi'; export * from './ConfigApi'; export * from './DiscoveryApi'; export * from './ErrorApi'; From 413f05a6c9dfe99b17562a448a093619b1b5db35 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Fri, 17 Nov 2023 17:10:40 +0100 Subject: [PATCH 165/261] refactor: replace components context in app Signed-off-by: Camila Belo --- .../ComponentsApi/ComponentsApi.ts | 8 ++- .../frontend-app-api/src/extensions/Core.tsx | 16 +---- .../src/extensions/CoreRoutes.tsx | 8 ++- .../frontend-app-api/src/wiring/createApp.tsx | 71 ++++++------------- packages/frontend-plugin-api/api-report.md | 23 +++--- .../src/apis/definitions/ComponentsApi.ts | 2 +- .../src/components/ComponentsContext.tsx | 58 --------------- .../src/components/index.ts | 6 -- 8 files changed, 44 insertions(+), 148 deletions(-) delete mode 100644 packages/frontend-plugin-api/src/components/ComponentsContext.tsx diff --git a/packages/frontend-app-api/src/apis/implementations/ComponentsApi/ComponentsApi.ts b/packages/frontend-app-api/src/apis/implementations/ComponentsApi/ComponentsApi.ts index 87a12d136e..50d125e4ab 100644 --- a/packages/frontend-app-api/src/apis/implementations/ComponentsApi/ComponentsApi.ts +++ b/packages/frontend-app-api/src/apis/implementations/ComponentsApi/ComponentsApi.ts @@ -28,7 +28,11 @@ export class DefaultComponentsApi implements ComponentsApi { this.#components = components; } - getComponent(ref: ComponentRef): T | undefined { - return this.#components.get(ref); + getComponent(ref: ComponentRef): T { + const impl = this.#components.get(ref); + if (!impl) { + throw new Error(`No implementation found for component ref ${ref}`); + } + return impl; } } diff --git a/packages/frontend-app-api/src/extensions/Core.tsx b/packages/frontend-app-api/src/extensions/Core.tsx index 4347eb1b45..441cb5bcf0 100644 --- a/packages/frontend-app-api/src/extensions/Core.tsx +++ b/packages/frontend-app-api/src/extensions/Core.tsx @@ -18,9 +18,7 @@ import { coreExtensionData, createExtension, createExtensionInput, - ComponentsProvider, } from '@backstage/frontend-plugin-api'; -import React from 'react'; export const Core = createExtension({ id: 'core', @@ -46,20 +44,8 @@ export const Core = createExtension({ root: coreExtensionData.reactElement, }, factory({ inputs }) { - const components = inputs.components.reduce( - (rest, { component }) => ({ - ...rest, - [component.ref.id]: component.impl, - }), - {}, - ); - return { - root: ( - - {inputs.root.element} - - ), + root: inputs.root.element, }; }, }); diff --git a/packages/frontend-app-api/src/extensions/CoreRoutes.tsx b/packages/frontend-app-api/src/extensions/CoreRoutes.tsx index b2918cfcc9..37b0e5d62f 100644 --- a/packages/frontend-app-api/src/extensions/CoreRoutes.tsx +++ b/packages/frontend-app-api/src/extensions/CoreRoutes.tsx @@ -20,7 +20,8 @@ import { coreExtensionData, createExtensionInput, coreNotFoundErrorPageComponentRef, - useComponent, + useApi, + componentsApiRef, } from '@backstage/frontend-plugin-api'; import { useRoutes } from 'react-router-dom'; @@ -39,7 +40,10 @@ export const CoreRoutes = createExtension({ }, factory({ inputs }) { const Routes = () => { - const NotFoundErrorPage = useComponent(coreNotFoundErrorPageComponentRef); + const componentsApi = useApi(componentsApiRef); + const NotFoundErrorPage = componentsApi.getComponent( + coreNotFoundErrorPageComponentRef, + ); const element = useRoutes([ ...inputs.routes.map(route => ({ diff --git a/packages/frontend-app-api/src/wiring/createApp.tsx b/packages/frontend-app-api/src/wiring/createApp.tsx index b22d258eae..4e463fb526 100644 --- a/packages/frontend-app-api/src/wiring/createApp.tsx +++ b/packages/frontend-app-api/src/wiring/createApp.tsx @@ -21,11 +21,8 @@ import { appTreeApiRef, BackstagePlugin, ComponentRef, - coreBootErrorPageComponentRef, - coreErrorBoundaryFallbackComponentRef, + componentsApiRef, coreExtensionData, - coreNotFoundErrorPageComponentRef, - coreProgressComponentRef, ExtensionDataRef, ExtensionOverrides, RouteRef, @@ -108,6 +105,7 @@ import { CoreRouter } from '../extensions/CoreRouter'; import { toInternalBackstagePlugin } from '../../../frontend-plugin-api/src/wiring/createPlugin'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports import { toInternalExtensionOverrides } from '../../../frontend-plugin-api/src/wiring/createExtensionOverrides'; +import { DefaultComponentsApi } from '../apis/implementations/ComponentsApi'; export const builtinExtensions = [ Core, @@ -319,7 +317,6 @@ export function createSpecializedApp(options?: { features.filter( (f): f is BackstagePlugin => f.$$type === '@backstage/BackstagePlugin', ), - tree.root, ); const appIdentityProxy = new AppIdentityProxy(); @@ -375,49 +372,7 @@ export function createSpecializedApp(options?: { }; } -function createLegacyAppContext( - plugins: BackstagePlugin[], - core: AppNode, -): AppContext { - const components = core.edges.attachments - .get('components') - ?.map(e => e.instance?.getData(coreExtensionData.component)); - - function getComponent>( - ref: TRef, - ): TRef['T'] | undefined { - return components?.find(component => component?.ref.id === ref.id)?.impl; - } - - const { - Progress: DefaultProgress, - BootErrorPage: DefaultBootErrorPage, - NotFoundErrorPage: DefaultNotFoundErrorPage, - ErrorBoundaryFallback: DefaultErrorBoundaryFallback, - ...rest - } = defaultComponents; - - const CustomProgress = getComponent(coreProgressComponentRef); - - const CustomBootErrorPage = getComponent(coreBootErrorPageComponentRef); - - const CustomNotFoundErrorPage = getComponent( - coreNotFoundErrorPageComponentRef, - ); - - const CustomErrorBoundaryFallback = getComponent( - coreErrorBoundaryFallbackComponentRef, - ); - - const overriddenComponents = { - ...rest, - Progress: CustomProgress ?? DefaultProgress, - BootErrorPage: CustomBootErrorPage ?? DefaultBootErrorPage, - NotFoundErrorPage: CustomNotFoundErrorPage ?? DefaultNotFoundErrorPage, - ErrorBoundaryFallback: - CustomErrorBoundaryFallback ?? DefaultErrorBoundaryFallback, - }; - +function createLegacyAppContext(plugins: BackstagePlugin[]): AppContext { return { getPlugins(): LegacyBackstagePlugin[] { return plugins.map(toLegacyPlugin); @@ -434,7 +389,7 @@ function createLegacyAppContext( }, getComponents(): AppComponents { - return overriddenComponents; + return defaultComponents; }, }; } @@ -483,6 +438,24 @@ function createApiHolder( }), }); + const componentsExtensions = + tree.root.edges.attachments + .get('components') + ?.map(e => e.instance?.getData(coreExtensionData.component)) + .filter(x => !!x) ?? []; + + const componentsMap = componentsExtensions.reduce( + (components, component) => + component ? components.set(component.ref, component?.impl) : components, + new Map, any>(), + ); + + factoryRegistry.register('static', { + api: componentsApiRef, + deps: {}, + factory: () => new DefaultComponentsApi(componentsMap), + }); + factoryRegistry.register('static', { api: appThemeApiRef, deps: {}, diff --git a/packages/frontend-plugin-api/api-report.md b/packages/frontend-plugin-api/api-report.md index 2255dafdd0..3d89c415fa 100644 --- a/packages/frontend-plugin-api/api-report.md +++ b/packages/frontend-plugin-api/api-report.md @@ -13,6 +13,7 @@ import { AnyApiRef } from '@backstage/core-plugin-api'; import { ApiFactory } from '@backstage/core-plugin-api'; import { ApiHolder } from '@backstage/core-plugin-api'; import { ApiRef } from '@backstage/core-plugin-api'; +import { ApiRef as ApiRef_2 } from '@backstage/core-plugin-api/src/apis/system/types'; import { ApiRefConfig } from '@backstage/core-plugin-api'; import { AppTheme } from '@backstage/core-plugin-api'; import { AppThemeApi } from '@backstage/core-plugin-api'; @@ -26,7 +27,6 @@ import { BackstagePlugin as BackstagePlugin_2 } from '@backstage/core-plugin-api import { BackstageUserIdentity } from '@backstage/core-plugin-api'; import { bitbucketAuthApiRef } from '@backstage/core-plugin-api'; import { bitbucketServerAuthApiRef } from '@backstage/core-plugin-api'; -import { ComponentRef as ComponentRef_2 } from '@backstage/frontend-plugin-api'; import { ComponentType } from 'react'; import { ConfigApi } from '@backstage/core-plugin-api'; import { configApiRef } from '@backstage/core-plugin-api'; @@ -293,15 +293,14 @@ export type ComponentRef = { T: T; }; -// @public (undocumented) -export type ComponentsContextValue = Record>; +// @public +export interface ComponentsApi { + // (undocumented) + getComponent(ref: ComponentRef): T; +} -// @public (undocumented) -export function ComponentsProvider( - props: PropsWithChildren<{ - value: ComponentsContextValue; - }>, -): React_2.JSX.Element; +// @public +export const componentsApiRef: ApiRef_2; export { ConfigApi }; @@ -910,12 +909,6 @@ export { useApi }; export { useApiHolder }; -// @public (undocumented) -export function useComponent< - P extends {}, - T extends ComponentRef_2>, ->(ref: T): T['T']; - // @public export function useRouteRef< TOptional extends boolean, diff --git a/packages/frontend-plugin-api/src/apis/definitions/ComponentsApi.ts b/packages/frontend-plugin-api/src/apis/definitions/ComponentsApi.ts index 6f057e70f2..452e692389 100644 --- a/packages/frontend-plugin-api/src/apis/definitions/ComponentsApi.ts +++ b/packages/frontend-plugin-api/src/apis/definitions/ComponentsApi.ts @@ -24,7 +24,7 @@ import { createApiRef } from '../system'; */ export interface ComponentsApi { // TODO: Should component refs also provide the default implementation so that we're guaranteed to get a component? - getComponent(ref: ComponentRef): T | undefined; + getComponent(ref: ComponentRef): T; } /** diff --git a/packages/frontend-plugin-api/src/components/ComponentsContext.tsx b/packages/frontend-plugin-api/src/components/ComponentsContext.tsx deleted file mode 100644 index 7b1058f83c..0000000000 --- a/packages/frontend-plugin-api/src/components/ComponentsContext.tsx +++ /dev/null @@ -1,58 +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 { ComponentRef } from '@backstage/frontend-plugin-api'; -import { - createVersionedContext, - createVersionedValueMap, - useVersionedContext, -} from '@backstage/version-bridge'; -import React from 'react'; -import { ComponentType, PropsWithChildren } from 'react'; - -/** @public */ -export type ComponentsContextValue = Record>; - -const ComponentsContext = createVersionedContext<{ 1: ComponentsContextValue }>( - 'components-context', -); - -/** @public */ -export function ComponentsProvider( - props: PropsWithChildren<{ value: ComponentsContextValue }>, -) { - const { value, children } = props; - return ( - - {children} - - ); -} - -/** @public */ -export function useComponent< - P extends {}, - T extends ComponentRef>, ->(ref: T): T['T'] { - const components = useVersionedContext<{ 1: ComponentsContextValue }>( - 'components-context', - ); - const component = components?.atVersion(1)?.[ref.id]; - if (!component) { - throw new Error(`No implementation available for ${ref.id}`); - } - return component; -} diff --git a/packages/frontend-plugin-api/src/components/index.ts b/packages/frontend-plugin-api/src/components/index.ts index 575e5efbe0..4bee5c5f7b 100644 --- a/packages/frontend-plugin-api/src/components/index.ts +++ b/packages/frontend-plugin-api/src/components/index.ts @@ -14,12 +14,6 @@ * limitations under the License. */ -export { - ComponentsProvider, - useComponent, - type ComponentsContextValue, -} from './ComponentsContext'; - export { coreProgressComponentRef, coreBootErrorPageComponentRef, From a9da252cb4c2816ca4e8b3ed01deda296427d900 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Mon, 20 Nov 2023 09:37:24 +0100 Subject: [PATCH 166/261] refator: group core component ref in a object Signed-off-by: Camila Belo --- .../examples/notFoundErrorPageExtension.tsx | 4 ++-- .../src/collectLegacyComponents.tsx | 13 ++++------- .../src/extensions/CoreRoutes.tsx | 4 ++-- .../src/extensions/components.tsx | 13 ++++------- packages/frontend-plugin-api/api-report.md | 16 +++++-------- .../src/components/ComponentRef.tsx | 23 +++++++++++-------- .../src/components/index.ts | 8 +------ 7 files changed, 35 insertions(+), 46 deletions(-) diff --git a/packages/app-next/src/examples/notFoundErrorPageExtension.tsx b/packages/app-next/src/examples/notFoundErrorPageExtension.tsx index c076b059f4..b1e88b6457 100644 --- a/packages/app-next/src/examples/notFoundErrorPageExtension.tsx +++ b/packages/app-next/src/examples/notFoundErrorPageExtension.tsx @@ -17,7 +17,7 @@ import React from 'react'; import { createComponentExtension, - coreNotFoundErrorPageComponentRef, + coreComponentsRefs, } from '@backstage/frontend-plugin-api'; import { Box, Typography } from '@material-ui/core'; import { Button } from '@backstage/core-components'; @@ -57,6 +57,6 @@ export function CustomNotFoundErrorPage() { } export default createComponentExtension({ - ref: coreNotFoundErrorPageComponentRef, + ref: coreComponentsRefs.notFoundErrorPage, component: async () => CustomNotFoundErrorPage, }); diff --git a/packages/core-compat-api/src/collectLegacyComponents.tsx b/packages/core-compat-api/src/collectLegacyComponents.tsx index 97c3ee22ad..17a354f52d 100644 --- a/packages/core-compat-api/src/collectLegacyComponents.tsx +++ b/packages/core-compat-api/src/collectLegacyComponents.tsx @@ -18,20 +18,17 @@ import { Extension, ComponentRef, createComponentExtension, - coreProgressComponentRef, - coreBootErrorPageComponentRef, - coreNotFoundErrorPageComponentRef, - coreErrorBoundaryFallbackComponentRef, + coreComponentsRefs, } from '@backstage/frontend-plugin-api'; import { AppComponents } from '@backstage/core-plugin-api'; type ComponentTypes = T[keyof T]; const refs: Record> = { - Progress: coreProgressComponentRef, - BootErrorPage: coreBootErrorPageComponentRef, - NotFoundErrorPage: coreNotFoundErrorPageComponentRef, - ErrorBoundaryFallback: coreErrorBoundaryFallbackComponentRef, + Progress: coreComponentsRefs.progress, + BootErrorPage: coreComponentsRefs.bootErrorPage, + NotFoundErrorPage: coreComponentsRefs.notFoundErrorPage, + ErrorBoundaryFallback: coreComponentsRefs.errorBoundaryFallback, }; /** @public */ diff --git a/packages/frontend-app-api/src/extensions/CoreRoutes.tsx b/packages/frontend-app-api/src/extensions/CoreRoutes.tsx index 37b0e5d62f..9acd27b6bf 100644 --- a/packages/frontend-app-api/src/extensions/CoreRoutes.tsx +++ b/packages/frontend-app-api/src/extensions/CoreRoutes.tsx @@ -19,7 +19,7 @@ import { createExtension, coreExtensionData, createExtensionInput, - coreNotFoundErrorPageComponentRef, + coreComponentsRefs, useApi, componentsApiRef, } from '@backstage/frontend-plugin-api'; @@ -42,7 +42,7 @@ export const CoreRoutes = createExtension({ const Routes = () => { const componentsApi = useApi(componentsApiRef); const NotFoundErrorPage = componentsApi.getComponent( - coreNotFoundErrorPageComponentRef, + coreComponentsRefs.notFoundErrorPage, ); const element = useRoutes([ diff --git a/packages/frontend-app-api/src/extensions/components.tsx b/packages/frontend-app-api/src/extensions/components.tsx index 5bd4431a28..cf34859aa0 100644 --- a/packages/frontend-app-api/src/extensions/components.tsx +++ b/packages/frontend-app-api/src/extensions/components.tsx @@ -16,31 +16,28 @@ import { createComponentExtension, - coreProgressComponentRef, - coreBootErrorPageComponentRef, - coreNotFoundErrorPageComponentRef, - coreErrorBoundaryFallbackComponentRef, + coreComponentsRefs, } from '@backstage/frontend-plugin-api'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports import { components as defaultComponents } from '../../../app-defaults/src/defaults'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports export const DefaultProgressComponent = createComponentExtension({ - ref: coreProgressComponentRef, + ref: coreComponentsRefs.progress, component: async () => defaultComponents.Progress, }); export const DefaultBootErrorPageComponent = createComponentExtension({ - ref: coreBootErrorPageComponentRef, + ref: coreComponentsRefs.bootErrorPage, component: async () => defaultComponents.BootErrorPage, }); export const DefaultNotFoundErrorPageComponent = createComponentExtension({ - ref: coreNotFoundErrorPageComponentRef, + ref: coreComponentsRefs.notFoundErrorPage, component: async () => defaultComponents.NotFoundErrorPage, }); export const DefaultErrorBoundaryComponent = createComponentExtension({ - ref: coreErrorBoundaryFallbackComponentRef, + ref: coreComponentsRefs.errorBoundaryFallback, component: async () => defaultComponents.ErrorBoundaryFallback, }); diff --git a/packages/frontend-plugin-api/api-report.md b/packages/frontend-plugin-api/api-report.md index 3d89c415fa..fe92a9cb44 100644 --- a/packages/frontend-plugin-api/api-report.md +++ b/packages/frontend-plugin-api/api-report.md @@ -331,7 +331,12 @@ export type CoreBootErrorPageComponent = ComponentType< >; // @public (undocumented) -export const coreBootErrorPageComponentRef: ComponentRef; +export const coreComponentsRefs: { + progress: ComponentRef; + bootErrorPage: ComponentRef; + notFoundErrorPage: ComponentRef; + errorBoundaryFallback: ComponentRef; +}; // @public (undocumented) export type CoreErrorBoundaryFallbackComponent = ComponentType< @@ -342,9 +347,6 @@ export type CoreErrorBoundaryFallbackComponent = ComponentType< }> >; -// @public (undocumented) -export const coreErrorBoundaryFallbackComponentRef: ComponentRef; - // @public (undocumented) export const coreExtensionData: { reactElement: ConfigurableExtensionDataRef; @@ -368,15 +370,9 @@ export type CoreNotFoundErrorPageComponent = ComponentType< PropsWithChildren<{}> >; -// @public (undocumented) -export const coreNotFoundErrorPageComponentRef: ComponentRef; - // @public (undocumented) export type CoreProgressComponent = ComponentType>; -// @public (undocumented) -export const coreProgressComponentRef: ComponentRef; - // @public (undocumented) export function createApiExtension< TConfig extends {}, diff --git a/packages/frontend-plugin-api/src/components/ComponentRef.tsx b/packages/frontend-plugin-api/src/components/ComponentRef.tsx index 13588ba779..2db85b9a42 100644 --- a/packages/frontend-plugin-api/src/components/ComponentRef.tsx +++ b/packages/frontend-plugin-api/src/components/ComponentRef.tsx @@ -40,24 +40,29 @@ export function createComponentRef(options: { }; } -/** @public */ -export const coreProgressComponentRef = - createComponentRef({ id: 'core.components.progress' }); +const coreProgressComponentRef = createComponentRef({ + id: 'core.components.progress', +}); -/** @public */ -export const coreBootErrorPageComponentRef = +const coreBootErrorPageComponentRef = createComponentRef({ id: 'core.components.bootErrorPage', }); -/** @public */ -export const coreNotFoundErrorPageComponentRef = +const coreNotFoundErrorPageComponentRef = createComponentRef({ id: 'core.components.notFoundErrorPage', }); -/** @public */ -export const coreErrorBoundaryFallbackComponentRef = +const coreErrorBoundaryFallbackComponentRef = createComponentRef({ id: 'core.components.errorBoundaryFallback', }); + +/** @public */ +export const coreComponentsRefs = { + progress: coreProgressComponentRef, + bootErrorPage: coreBootErrorPageComponentRef, + notFoundErrorPage: coreNotFoundErrorPageComponentRef, + errorBoundaryFallback: coreErrorBoundaryFallbackComponentRef, +}; diff --git a/packages/frontend-plugin-api/src/components/index.ts b/packages/frontend-plugin-api/src/components/index.ts index 4bee5c5f7b..e0b3d09543 100644 --- a/packages/frontend-plugin-api/src/components/index.ts +++ b/packages/frontend-plugin-api/src/components/index.ts @@ -14,13 +14,7 @@ * limitations under the License. */ -export { - coreProgressComponentRef, - coreBootErrorPageComponentRef, - coreErrorBoundaryFallbackComponentRef, - coreNotFoundErrorPageComponentRef, - type ComponentRef, -} from './ComponentRef'; +export { coreComponentsRefs, type ComponentRef } from './ComponentRef'; export { ExtensionError } from './ExtensionError'; From 73e65a75ffb771d5ad2da6e8078768cb0020e57b Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Mon, 20 Nov 2023 09:43:07 +0100 Subject: [PATCH 167/261] refator: remove extension error pattern Signed-off-by: Camila Belo --- packages/frontend-plugin-api/api-report.md | 3 --- .../src/components/ExtensionError.tsx | 27 ------------------- .../src/components/index.ts | 2 -- .../extensions/createComponentExtension.tsx | 7 ++--- .../src/extensions/createPageExtension.tsx | 7 ++--- 5 files changed, 4 insertions(+), 42 deletions(-) delete mode 100644 packages/frontend-plugin-api/src/components/ExtensionError.tsx diff --git a/packages/frontend-plugin-api/api-report.md b/packages/frontend-plugin-api/api-report.md index fe92a9cb44..b5c63f9d22 100644 --- a/packages/frontend-plugin-api/api-report.md +++ b/packages/frontend-plugin-api/api-report.md @@ -695,9 +695,6 @@ export type ExtensionDataValues = { : never]?: TExtensionData[DataName]['T']; }; -// @public (undocumented) -export function ExtensionError(props: { error: Error }): React_2.JSX.Element; - // @public (undocumented) export interface ExtensionInput< TExtensionData extends AnyExtensionDataMap, diff --git a/packages/frontend-plugin-api/src/components/ExtensionError.tsx b/packages/frontend-plugin-api/src/components/ExtensionError.tsx deleted file mode 100644 index 5aa2ae03bd..0000000000 --- a/packages/frontend-plugin-api/src/components/ExtensionError.tsx +++ /dev/null @@ -1,27 +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 React from 'react'; -// eslint-disable-next-line @backstage/no-relative-monorepo-imports -import { useApp } from '../../../core-plugin-api/src/app/useApp'; - -/** @public */ -export function ExtensionError(props: { error: Error }) { - const { error } = props; - const app = useApp(); - const { BootErrorPage } = app.getComponents(); - return ; -} diff --git a/packages/frontend-plugin-api/src/components/index.ts b/packages/frontend-plugin-api/src/components/index.ts index e0b3d09543..a7d947599f 100644 --- a/packages/frontend-plugin-api/src/components/index.ts +++ b/packages/frontend-plugin-api/src/components/index.ts @@ -16,8 +16,6 @@ export { coreComponentsRefs, type ComponentRef } from './ComponentRef'; -export { ExtensionError } from './ExtensionError'; - export { ExtensionBoundary, type ExtensionBoundaryProps, diff --git a/packages/frontend-plugin-api/src/extensions/createComponentExtension.tsx b/packages/frontend-plugin-api/src/extensions/createComponentExtension.tsx index 376510312f..e337f3f822 100644 --- a/packages/frontend-plugin-api/src/extensions/createComponentExtension.tsx +++ b/packages/frontend-plugin-api/src/extensions/createComponentExtension.tsx @@ -23,7 +23,7 @@ import { } from '../wiring'; import { Expand } from '../types'; import { PortableSchema } from '../schema'; -import { ExtensionError, ExtensionBoundary, ComponentRef } from '../components'; +import { ExtensionBoundary, ComponentRef } from '../components'; /** @public */ export function createComponentExtension< @@ -54,10 +54,7 @@ export function createComponentExtension< const ExtensionComponent = lazy(() => options .component({ config, inputs }) - .then(component => ({ default: component })) - .catch(error => ({ - default: () => , - })), + .then(component => ({ default: component })), ); return { diff --git a/packages/frontend-plugin-api/src/extensions/createPageExtension.tsx b/packages/frontend-plugin-api/src/extensions/createPageExtension.tsx index d05f051a67..99733ba367 100644 --- a/packages/frontend-plugin-api/src/extensions/createPageExtension.tsx +++ b/packages/frontend-plugin-api/src/extensions/createPageExtension.tsx @@ -15,7 +15,7 @@ */ import React, { lazy } from 'react'; -import { ExtensionError, ExtensionBoundary } from '../components'; +import { ExtensionBoundary } from '../components'; import { createSchemaFromZod, PortableSchema } from '../schema'; import { coreExtensionData, @@ -79,10 +79,7 @@ export function createPageExtension< const ExtensionComponent = lazy(() => options .loader({ config, inputs }) - .then(element => ({ default: () => element })) - .catch(error => ({ - default: () => , - })), + .then(element => ({ default: () => element })), ); return { From 0e8f4a65aa6553ec0591ebe0459f280288f5e2c2 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Tue, 28 Nov 2023 10:01:37 +0100 Subject: [PATCH 168/261] refactor: make components optionally lazy Signed-off-by: Camila Belo --- .../examples/notFoundErrorPageExtension.tsx | 2 +- .../src/collectLegacyComponents.tsx | 6 ++-- .../src/extensions/components.tsx | 8 ++--- .../extensions/createComponentExtension.tsx | 32 +++++++++++++------ 4 files changed, 31 insertions(+), 17 deletions(-) diff --git a/packages/app-next/src/examples/notFoundErrorPageExtension.tsx b/packages/app-next/src/examples/notFoundErrorPageExtension.tsx index b1e88b6457..82acc25fb5 100644 --- a/packages/app-next/src/examples/notFoundErrorPageExtension.tsx +++ b/packages/app-next/src/examples/notFoundErrorPageExtension.tsx @@ -58,5 +58,5 @@ export function CustomNotFoundErrorPage() { export default createComponentExtension({ ref: coreComponentsRefs.notFoundErrorPage, - component: async () => CustomNotFoundErrorPage, + component: { sync: () => CustomNotFoundErrorPage }, }); diff --git a/packages/core-compat-api/src/collectLegacyComponents.tsx b/packages/core-compat-api/src/collectLegacyComponents.tsx index 17a354f52d..6092ca1be7 100644 --- a/packages/core-compat-api/src/collectLegacyComponents.tsx +++ b/packages/core-compat-api/src/collectLegacyComponents.tsx @@ -34,13 +34,13 @@ const refs: Record> = { /** @public */ export function collectLegacyComponents(components: Partial) { return Object.entries(components).reduce[]>( - (extensions, [componentName, componentFunction]) => { - const ref = refs[componentName]; + (extensions, [name, component]) => { + const ref = refs[name]; return ref ? extensions.concat( createComponentExtension({ ref, - component: async () => componentFunction, + component: { sync: () => component }, }), ) : extensions; diff --git a/packages/frontend-app-api/src/extensions/components.tsx b/packages/frontend-app-api/src/extensions/components.tsx index cf34859aa0..fa9187a831 100644 --- a/packages/frontend-app-api/src/extensions/components.tsx +++ b/packages/frontend-app-api/src/extensions/components.tsx @@ -24,20 +24,20 @@ import { components as defaultComponents } from '../../../app-defaults/src/defau export const DefaultProgressComponent = createComponentExtension({ ref: coreComponentsRefs.progress, - component: async () => defaultComponents.Progress, + component: { sync: () => defaultComponents.Progress }, }); export const DefaultBootErrorPageComponent = createComponentExtension({ ref: coreComponentsRefs.bootErrorPage, - component: async () => defaultComponents.BootErrorPage, + component: { sync: () => defaultComponents.BootErrorPage }, }); export const DefaultNotFoundErrorPageComponent = createComponentExtension({ ref: coreComponentsRefs.notFoundErrorPage, - component: async () => defaultComponents.NotFoundErrorPage, + component: { sync: () => defaultComponents.NotFoundErrorPage }, }); export const DefaultErrorBoundaryComponent = createComponentExtension({ ref: coreComponentsRefs.errorBoundaryFallback, - component: async () => defaultComponents.ErrorBoundaryFallback, + component: { sync: () => defaultComponents.ErrorBoundaryFallback }, }); diff --git a/packages/frontend-plugin-api/src/extensions/createComponentExtension.tsx b/packages/frontend-plugin-api/src/extensions/createComponentExtension.tsx index e337f3f822..a20faa0b3a 100644 --- a/packages/frontend-plugin-api/src/extensions/createComponentExtension.tsx +++ b/packages/frontend-plugin-api/src/extensions/createComponentExtension.tsx @@ -35,10 +35,19 @@ export function createComponentExtension< disabled?: boolean; inputs?: TInputs; configSchema?: PortableSchema; - component: (values: { - config: TConfig; - inputs: Expand>; - }) => Promise; + component: + | { + lazy: (values: { + config: TConfig; + inputs: Expand>; + }) => Promise; + } + | { + sync: (values: { + config: TConfig; + inputs: Expand>; + }) => TRef['T']; + }; }) { const id = options.ref.id; return createExtension({ @@ -51,11 +60,16 @@ export function createComponentExtension< component: coreExtensionData.component, }, factory({ config, inputs, node }) { - const ExtensionComponent = lazy(() => - options - .component({ config, inputs }) - .then(component => ({ default: component })), - ); + let ExtensionComponent: TRef['T']; + + if ('sync' in options.component) { + ExtensionComponent = options.component.sync({ config, inputs }); + } else { + const loader = options.component.lazy({ config, inputs }); + ExtensionComponent = lazy(() => + loader.then(component => ({ default: component })), + ); + } return { component: { From 16942238cb835f1e005a34c0c976625a6901344a Mon Sep 17 00:00:00 2001 From: blam Date: Tue, 28 Nov 2023 10:48:08 +0100 Subject: [PATCH 169/261] chore: fixing header options Signed-off-by: blam --- plugins/scaffolder/src/components/Router/Router.tsx | 1 + .../src/next/TemplateWizardPage/TemplateWizardPage.tsx | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/plugins/scaffolder/src/components/Router/Router.tsx b/plugins/scaffolder/src/components/Router/Router.tsx index bdda92c0ef..c3d971bd11 100644 --- a/plugins/scaffolder/src/components/Router/Router.tsx +++ b/plugins/scaffolder/src/components/Router/Router.tsx @@ -142,6 +142,7 @@ export const Router = (props: PropsWithChildren) => { element={ { @@ -87,6 +92,7 @@ export const TemplateWizardPage = (props: TemplateWizardPageProps) => { pageTitleOverride="Create a new component" title="Create a new component" subtitle="Create new software components using standard templates in your organization" + {...props.headerOptions} /> Date: Tue, 28 Nov 2023 10:49:27 +0100 Subject: [PATCH 170/261] chore: changeset Signed-off-by: blam --- .changeset/sour-pumas-reply.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/sour-pumas-reply.md diff --git a/.changeset/sour-pumas-reply.md b/.changeset/sour-pumas-reply.md new file mode 100644 index 0000000000..99b812acdd --- /dev/null +++ b/.changeset/sour-pumas-reply.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder': patch +--- + +Fixing `headerOptions` not being passed through the `TemplatePage` component From af3a06a080ff8213739a658d9f5a91c9e65c1e33 Mon Sep 17 00:00:00 2001 From: blam Date: Tue, 28 Nov 2023 11:16:22 +0100 Subject: [PATCH 171/261] chore: update api-reports Signed-off-by: blam --- plugins/scaffolder/api-report-alpha.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/plugins/scaffolder/api-report-alpha.md b/plugins/scaffolder/api-report-alpha.md index e659b8f30d..6a1e0648a4 100644 --- a/plugins/scaffolder/api-report-alpha.md +++ b/plugins/scaffolder/api-report-alpha.md @@ -85,6 +85,11 @@ export type TemplateWizardPageProps = { }; layouts?: LayoutOptions[]; formProps?: FormProps_3; + headerOptions?: { + pageTitleOverride?: string; + title?: string; + subtitle?: string; + }; }; // (No @packageDocumentation comment for this package) From 0025a3c5953181032cb62833ab922172fc3ecc9c Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Tue, 28 Nov 2023 10:50:42 +0100 Subject: [PATCH 172/261] docs: update api reports Signed-off-by: Camila Belo --- packages/frontend-plugin-api/api-report.md | 20 +++++++++++++------ .../src/apis/definitions/ComponentsApi.ts | 2 +- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/packages/frontend-plugin-api/api-report.md b/packages/frontend-plugin-api/api-report.md index b5c63f9d22..e1ed76d82c 100644 --- a/packages/frontend-plugin-api/api-report.md +++ b/packages/frontend-plugin-api/api-report.md @@ -13,7 +13,6 @@ import { AnyApiRef } from '@backstage/core-plugin-api'; import { ApiFactory } from '@backstage/core-plugin-api'; import { ApiHolder } from '@backstage/core-plugin-api'; import { ApiRef } from '@backstage/core-plugin-api'; -import { ApiRef as ApiRef_2 } from '@backstage/core-plugin-api/src/apis/system/types'; import { ApiRefConfig } from '@backstage/core-plugin-api'; import { AppTheme } from '@backstage/core-plugin-api'; import { AppThemeApi } from '@backstage/core-plugin-api'; @@ -300,7 +299,7 @@ export interface ComponentsApi { } // @public -export const componentsApiRef: ApiRef_2; +export const componentsApiRef: ApiRef; export { ConfigApi }; @@ -409,10 +408,19 @@ export function createComponentExtension< disabled?: boolean; inputs?: TInputs; configSchema?: PortableSchema; - component: (values: { - config: TConfig; - inputs: Expand>; - }) => Promise; + component: + | { + lazy: (values: { + config: TConfig; + inputs: Expand>; + }) => Promise; + } + | { + sync: (values: { + config: TConfig; + inputs: Expand>; + }) => TRef['T']; + }; }): Extension; // @public (undocumented) diff --git a/packages/frontend-plugin-api/src/apis/definitions/ComponentsApi.ts b/packages/frontend-plugin-api/src/apis/definitions/ComponentsApi.ts index 452e692389..b55ed96549 100644 --- a/packages/frontend-plugin-api/src/apis/definitions/ComponentsApi.ts +++ b/packages/frontend-plugin-api/src/apis/definitions/ComponentsApi.ts @@ -14,8 +14,8 @@ * limitations under the License. */ +import { createApiRef } from '@backstage/core-plugin-api'; import { ComponentRef } from '../../components'; -import { createApiRef } from '../system'; /** * API for looking up components based on component refs. From cc4228ec11f08ba9ca8581f7f5734d3a2f7daae3 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 28 Nov 2023 11:53:57 +0100 Subject: [PATCH 173/261] switch all backend module IDs to use kebab-case Signed-off-by: Patrik Oldsberg --- .changeset/wicked-pants-end.md | 35 +++++++++++++++++++ .../backend-system/architecture/06-modules.md | 2 +- .../architecture/07-naming-patterns.md | 18 +++++----- .../building-backends/08-migrating.md | 8 ++--- .../building-plugins-and-modules/01-index.md | 2 +- .../08-migrating.md | 2 +- docs/plugins/new-backend-system.md | 2 +- .../src/wiring/BackendInitializer.test.ts | 18 +++++----- .../src/next/wiring/TestBackend.test.ts | 6 ++-- .../src/next/wiring/TestBackend.ts | 2 +- .../src/module.ts | 2 +- .../src/module.ts | 2 +- .../src/module.ts | 2 +- .../catalogModuleAwsS3EntityProvider.ts | 2 +- .../catalogModuleAzureDevOpsEntityProvider.ts | 2 +- ...talogModuleBitbucketCloudEntityProvider.ts | 2 +- ...alogModuleBitbucketServerEntityProvider.ts | 2 +- .../catalogModuleGcpGkeEntityProvider.ts | 2 +- .../catalogModuleGerritEntityProvider.ts | 2 +- .../src/module.ts | 2 +- .../catalogModuleGithubEntityProvider.ts | 2 +- ...alogModuleGitlabDiscoveryEntityProvider.ts | 2 +- ...IncrementalIngestionEntityProvider.test.ts | 2 +- ...oduleIncrementalIngestionEntityProvider.ts | 4 +-- .../src/run.ts | 2 +- .../catalogModulePuppetDbEntityProvider.ts | 2 +- .../src/module.ts | 2 +- .../src/module.ts | 2 +- .../performance/stitchingPerformance.test.ts | 4 +-- ...entsModuleAwsSqsConsumingEventPublisher.ts | 2 +- .../eventsModuleAzureDevOpsEventRouter.ts | 2 +- .../eventsModuleBitbucketCloudEventRouter.ts | 2 +- .../service/eventsModuleGerritEventRouter.ts | 2 +- .../service/eventsModuleGithubEventRouter.ts | 2 +- .../src/service/eventsModuleGithubWebhook.ts | 2 +- .../service/eventsModuleGitlabEventRouter.ts | 2 +- .../src/service/eventsModuleGitlabWebhook.ts | 2 +- plugins/events-backend/README.md | 4 +-- .../src/routes/resourceRoutes.test.ts | 2 +- .../src/module.ts | 2 +- .../search-backend-module-catalog/README.md | 2 +- .../src/alpha.ts | 2 +- .../src/alpha.ts | 2 +- .../src/alpha.ts | 2 +- plugins/search-backend-module-pg/src/alpha.ts | 2 +- .../SearchStackOverflowCollatorModule.ts | 2 +- .../src/alpha.ts | 2 +- 47 files changed, 106 insertions(+), 69 deletions(-) create mode 100644 .changeset/wicked-pants-end.md diff --git a/.changeset/wicked-pants-end.md b/.changeset/wicked-pants-end.md new file mode 100644 index 0000000000..ecb42d0957 --- /dev/null +++ b/.changeset/wicked-pants-end.md @@ -0,0 +1,35 @@ +--- +'@backstage/plugin-catalog-backend-module-scaffolder-entity-model': patch +'@backstage/plugin-search-backend-module-stack-overflow-collator': patch +'@backstage/plugin-catalog-backend-module-incremental-ingestion': patch +'@backstage/plugin-permission-backend-module-allow-all-policy': patch +'@backstage/plugin-auth-backend-module-oauth2-proxy-provider': patch +'@backstage/plugin-catalog-backend-module-bitbucket-server': patch +'@backstage/plugin-catalog-backend-module-bitbucket-cloud': patch +'@backstage/plugin-events-backend-module-bitbucket-cloud': patch +'@backstage/plugin-auth-backend-module-gcp-iap-provider': patch +'@backstage/plugin-auth-backend-module-google-provider': patch +'@backstage/plugin-search-backend-module-elasticsearch': patch +'@backstage/plugin-catalog-backend-module-unprocessed': patch +'@backstage/plugin-catalog-backend-module-github-org': patch +'@backstage/plugin-catalog-backend-module-puppetdb': patch +'@backstage/plugin-search-backend-module-techdocs': patch +'@backstage/plugin-catalog-backend-module-gerrit': patch +'@backstage/plugin-catalog-backend-module-github': patch +'@backstage/plugin-catalog-backend-module-gitlab': patch +'@backstage/plugin-events-backend-module-aws-sqs': patch +'@backstage/plugin-search-backend-module-catalog': patch +'@backstage/plugin-search-backend-module-explore': patch +'@backstage/plugin-catalog-backend-module-azure': patch +'@backstage/plugin-events-backend-module-gerrit': patch +'@backstage/plugin-events-backend-module-github': patch +'@backstage/plugin-events-backend-module-gitlab': patch +'@backstage/plugin-events-backend-module-azure': patch +'@backstage/plugin-catalog-backend-module-aws': patch +'@backstage/plugin-catalog-backend-module-gcp': patch +'@backstage/plugin-search-backend-module-pg': patch +'@backstage/backend-test-utils': patch +'@backstage/plugin-events-backend': patch +--- + +Switched module ID to use kebab-case. diff --git a/docs/backend-system/architecture/06-modules.md b/docs/backend-system/architecture/06-modules.md index e916e4fdf6..b15c873c39 100644 --- a/docs/backend-system/architecture/06-modules.md +++ b/docs/backend-system/architecture/06-modules.md @@ -25,8 +25,8 @@ import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node' import { MyCustomProcessor } from './MyCustomProcessor'; export const catalogModuleExampleCustomProcessor = createBackendModule({ - moduleId: 'exampleCustomProcessor', pluginId: 'catalog', + moduleId: 'example-custom-processor', register(env) { env.registerInit({ deps: { diff --git a/docs/backend-system/architecture/07-naming-patterns.md b/docs/backend-system/architecture/07-naming-patterns.md index 3e57fa6863..9af1e09a27 100644 --- a/docs/backend-system/architecture/07-naming-patterns.md +++ b/docs/backend-system/architecture/07-naming-patterns.md @@ -10,18 +10,20 @@ description: Naming patterns in the backend system These are the naming patterns to adhere to within the backend system. They help us keep exports consistent across packages and make it easier to understand the usage and intent of exports. +As a rule, all names should be camel case, with the exceptions of plugin and module IDs, which should be kebab case. + ### Plugins -| Description | Pattern | Examples | -| ----------- | ------------ | ----------------------------------- | -| export | `Plugin` | `catalogPlugin`, `scaffolderPlugin` | -| ID | `''` | `'catalog'`, `'scaffolder'` | +| Description | Pattern | Examples | +| ----------- | ----------------- | ------------------------------------- | +| export | `Plugin` | `catalogPlugin`, `userSettingsPlugin` | +| ID | `''` | `'catalog'`, `'user-settings'` | Example: ```ts -export const catalogPlugin = createBackendPlugin({ - pluginId: 'catalog', +export const userSettingsPlugin = createBackendPlugin({ + pluginId: 'user-settings', ... }) ``` @@ -31,14 +33,14 @@ export const catalogPlugin = createBackendPlugin({ | Description | Pattern | Examples | | ----------- | ---------------------------- | ----------------------------------- | | export | `Module` | `catalogModuleGithubEntityProvider` | -| ID | `''` | `'githubEntityProvider'` | +| ID | `''` | `'github-entity-provider'` | Example: ```ts export const catalogModuleGithubEntityProvider = createBackendModule({ pluginId: 'catalog', - moduleId: 'githubEntityProvider', + moduleId: 'github-entity-provider', ... }) ``` diff --git a/docs/backend-system/building-backends/08-migrating.md b/docs/backend-system/building-backends/08-migrating.md index 98dde46d38..a105f806b0 100644 --- a/docs/backend-system/building-backends/08-migrating.md +++ b/docs/backend-system/building-backends/08-migrating.md @@ -297,7 +297,7 @@ import { microsoftGraphOrgEntityProviderTransformExtensionPoint } from '@backsta backend.add( createBackendModule({ pluginId: 'catalog', - moduleId: 'microsoftGraphExtensions', + moduleId: 'microsoft-graph-extensions', register(env) { env.registerInit({ deps: { @@ -337,7 +337,7 @@ import { createBackendModule } from '@backstage/backend-plugin-api'; /* highlight-add-start */ const catalogModuleCustomExtensions = createBackendModule({ pluginId: 'catalog', // name of the plugin that the module is targeting - moduleId: 'customExtensions', + moduleId: 'custom-extensions', register(env) { env.registerInit({ deps: { @@ -406,7 +406,7 @@ import { createBackendModule } from '@backstage/backend-plugin-api'; /* highlight-add-start */ const eventsModuleCustomExtensions = createBackendModule({ pluginId: 'events', // name of the plugin that the module is targeting - moduleId: 'customExtensions', + moduleId: 'custom-extensions', register(env) { env.registerInit({ deps: { @@ -471,7 +471,7 @@ import { createBackendModule } from '@backstage/backend-plugin-api'; /* highlight-add-start */ const scaffolderModuleCustomExtensions = createBackendModule({ pluginId: 'scaffolder', // name of the plugin that the module is targeting - moduleId: 'customExtensions', + moduleId: 'custom-extensions', register(env) { env.registerInit({ deps: { diff --git a/docs/backend-system/building-plugins-and-modules/01-index.md b/docs/backend-system/building-plugins-and-modules/01-index.md index 7d97694aec..0f12e81a8c 100644 --- a/docs/backend-system/building-plugins-and-modules/01-index.md +++ b/docs/backend-system/building-plugins-and-modules/01-index.md @@ -104,8 +104,8 @@ import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node' import { MyCustomProcessor } from './MyCustomProcessor'; export const catalogModuleExampleCustomProcessor = createBackendModule({ - moduleId: 'exampleCustomProcessor', pluginId: 'catalog', + moduleId: 'example-custom-processor', register(env) { env.registerInit({ deps: { diff --git a/docs/backend-system/building-plugins-and-modules/08-migrating.md b/docs/backend-system/building-plugins-and-modules/08-migrating.md index 269a09b55c..cc920c576e 100644 --- a/docs/backend-system/building-plugins-and-modules/08-migrating.md +++ b/docs/backend-system/building-plugins-and-modules/08-migrating.md @@ -196,7 +196,7 @@ import { GoogleContainerEngineSupplier } from './GoogleContainerEngineSupplier'; export default createBackendModule({ pluginId: 'kubernetes', - moduleId: 'gke.supplier', + moduleId: 'gke-supplier', register(env) { env.registerInit({ deps: { diff --git a/docs/plugins/new-backend-system.md b/docs/plugins/new-backend-system.md index be27e9427d..b2c73af33b 100644 --- a/docs/plugins/new-backend-system.md +++ b/docs/plugins/new-backend-system.md @@ -147,8 +147,8 @@ import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node' import { MyCustomProcessor } from './processor'; export const exampleCustomProcessorCatalogModule = createBackendModule({ - moduleId: 'exampleCustomProcessor', pluginId: 'catalog', + moduleId: 'example-custom-processor', register(env) { env.registerInit({ deps: { diff --git a/packages/backend-app-api/src/wiring/BackendInitializer.test.ts b/packages/backend-app-api/src/wiring/BackendInitializer.test.ts index 791b9b1c3a..b5b53083a9 100644 --- a/packages/backend-app-api/src/wiring/BackendInitializer.test.ts +++ b/packages/backend-app-api/src/wiring/BackendInitializer.test.ts @@ -102,7 +102,7 @@ describe('BackendInitializer', () => { init.add( createBackendModule({ pluginId: 'test', - moduleId: 'modA', + moduleId: 'mod-a', register(reg) { reg.registerInit({ deps: { extension: extensionPoint }, @@ -118,7 +118,7 @@ describe('BackendInitializer', () => { init.add( createBackendModule({ pluginId: 'test', - moduleId: 'modB', + moduleId: 'mod-b', register(reg) { const values = ['b']; reg.registerExtensionPoint(extensionPoint, { values }); @@ -135,7 +135,7 @@ describe('BackendInitializer', () => { init.add( createBackendModule({ pluginId: 'test', - moduleId: 'modC', + moduleId: 'mod-c', register(reg) { reg.registerInit({ deps: { extension: extensionPoint }, @@ -265,7 +265,7 @@ describe('BackendInitializer', () => { init.add( createBackendModule({ pluginId: 'test', - moduleId: 'modA', + moduleId: 'mod-a', register(reg) { reg.registerExtensionPoint(extA, 'a'); reg.registerInit({ @@ -278,7 +278,7 @@ describe('BackendInitializer', () => { init.add( createBackendModule({ pluginId: 'test', - moduleId: 'modB', + moduleId: 'mod-b', register(reg) { reg.registerExtensionPoint(extB, 'b'); reg.registerInit({ @@ -289,7 +289,7 @@ describe('BackendInitializer', () => { })(), ); await expect(init.start()).rejects.toThrow( - "Circular dependency detected for modules of plugin 'test', 'modA' -> 'modB' -> 'modA'", + "Circular dependency detected for modules of plugin 'test', 'mod-a' -> 'mod-b' -> 'mod-a'", ); }); @@ -298,7 +298,7 @@ describe('BackendInitializer', () => { const extA = createExtensionPoint({ id: 'a' }); init.add( createBackendPlugin({ - pluginId: 'testA', + pluginId: 'test-a', register(reg) { reg.registerExtensionPoint(extA, 'a'); reg.registerInit({ @@ -310,7 +310,7 @@ describe('BackendInitializer', () => { ); init.add( createBackendModule({ - pluginId: 'testB', + pluginId: 'test-b', moduleId: 'mod', register(reg) { reg.registerInit({ @@ -321,7 +321,7 @@ describe('BackendInitializer', () => { })(), ); await expect(init.start()).rejects.toThrow( - "Extension point registered for plugin 'testA' may not be used by module for plugin 'testB'", + "Extension point registered for plugin 'test-a' may not be used by module for plugin 'test-b'", ); }); }); 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 b127712927..d71c774dd9 100644 --- a/packages/backend-test-utils/src/next/wiring/TestBackend.test.ts +++ b/packages/backend-test-utils/src/next/wiring/TestBackend.test.ts @@ -33,8 +33,8 @@ beforeAll(async () => { await startTestBackend({ features: [ createBackendModule({ - moduleId: 'test.module', pluginId: 'test', + moduleId: 'test-module', register(env) { env.registerInit({ deps: { lifecycle: coreServices.lifecycle }, @@ -128,8 +128,8 @@ describe('TestBackend', () => { }); const testModule = createBackendModule({ - moduleId: 'test.module', pluginId: 'test', + moduleId: 'test-module', register(env) { env.registerInit({ deps: { @@ -153,8 +153,8 @@ describe('TestBackend', () => { const shutdownSpy = jest.fn(); const testModule = createBackendModule({ - moduleId: 'test.module', pluginId: 'test', + moduleId: 'test-module', register(env) { env.registerInit({ deps: { diff --git a/packages/backend-test-utils/src/next/wiring/TestBackend.ts b/packages/backend-test-utils/src/next/wiring/TestBackend.ts index 21ae6159c9..14e8920390 100644 --- a/packages/backend-test-utils/src/next/wiring/TestBackend.ts +++ b/packages/backend-test-utils/src/next/wiring/TestBackend.ts @@ -156,7 +156,7 @@ function createExtensionPointTestModules( modules.push( createBackendModule({ pluginId, - moduleId: 'testExtensionPointRegistration', + moduleId: 'test-extension-point-registration', register(reg) { for (const id of pluginExtensionPointIds) { const tuple = extensionPointMap.get(id)!; diff --git a/plugins/auth-backend-module-gcp-iap-provider/src/module.ts b/plugins/auth-backend-module-gcp-iap-provider/src/module.ts index 90771eecb9..23c503c317 100644 --- a/plugins/auth-backend-module-gcp-iap-provider/src/module.ts +++ b/plugins/auth-backend-module-gcp-iap-provider/src/module.ts @@ -26,7 +26,7 @@ import { gcpIapSignInResolvers } from './resolvers'; /** @public */ export const authModuleGcpIapProvider = createBackendModule({ pluginId: 'auth', - moduleId: 'gcpIapProvider', + moduleId: 'gcp-iap-provider', register(reg) { reg.registerInit({ deps: { diff --git a/plugins/auth-backend-module-google-provider/src/module.ts b/plugins/auth-backend-module-google-provider/src/module.ts index 0354f99880..d0f8020b92 100644 --- a/plugins/auth-backend-module-google-provider/src/module.ts +++ b/plugins/auth-backend-module-google-provider/src/module.ts @@ -26,7 +26,7 @@ import { googleSignInResolvers } from './resolvers'; /** @public */ export const authModuleGoogleProvider = createBackendModule({ pluginId: 'auth', - moduleId: 'googleProvider', + moduleId: 'google-provider', register(reg) { reg.registerInit({ deps: { diff --git a/plugins/auth-backend-module-oauth2-proxy-provider/src/module.ts b/plugins/auth-backend-module-oauth2-proxy-provider/src/module.ts index 0d9b9ae74f..9ca6be4688 100644 --- a/plugins/auth-backend-module-oauth2-proxy-provider/src/module.ts +++ b/plugins/auth-backend-module-oauth2-proxy-provider/src/module.ts @@ -26,7 +26,7 @@ import { oauth2ProxySignInResolvers } from './resolvers'; /** @public */ export const authModuleOauth2ProxyProvider = createBackendModule({ pluginId: 'auth', - moduleId: 'oauth2ProxyProvider', + moduleId: 'oauth2-proxy-provider', register(reg) { reg.registerInit({ deps: { diff --git a/plugins/catalog-backend-module-aws/src/module/catalogModuleAwsS3EntityProvider.ts b/plugins/catalog-backend-module-aws/src/module/catalogModuleAwsS3EntityProvider.ts index 521d61d3d8..e7816ae12f 100644 --- a/plugins/catalog-backend-module-aws/src/module/catalogModuleAwsS3EntityProvider.ts +++ b/plugins/catalog-backend-module-aws/src/module/catalogModuleAwsS3EntityProvider.ts @@ -29,7 +29,7 @@ import { AwsS3EntityProvider } from '../providers'; */ export const catalogModuleAwsS3EntityProvider = createBackendModule({ pluginId: 'catalog', - moduleId: 'awsS3EntityProvider', + moduleId: 'aws-s3-entity-provider', register(env) { env.registerInit({ deps: { diff --git a/plugins/catalog-backend-module-azure/src/module/catalogModuleAzureDevOpsEntityProvider.ts b/plugins/catalog-backend-module-azure/src/module/catalogModuleAzureDevOpsEntityProvider.ts index 804c0d4712..b9c55041b3 100644 --- a/plugins/catalog-backend-module-azure/src/module/catalogModuleAzureDevOpsEntityProvider.ts +++ b/plugins/catalog-backend-module-azure/src/module/catalogModuleAzureDevOpsEntityProvider.ts @@ -29,7 +29,7 @@ import { AzureDevOpsEntityProvider } from '../providers'; */ export const catalogModuleAzureDevOpsEntityProvider = createBackendModule({ pluginId: 'catalog', - moduleId: 'azureDevOpsEntityProvider', + moduleId: 'azure-dev-ops-entity-provider', register(env) { env.registerInit({ deps: { diff --git a/plugins/catalog-backend-module-bitbucket-cloud/src/module/catalogModuleBitbucketCloudEntityProvider.ts b/plugins/catalog-backend-module-bitbucket-cloud/src/module/catalogModuleBitbucketCloudEntityProvider.ts index e5e1ad1609..39265dc1a5 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/src/module/catalogModuleBitbucketCloudEntityProvider.ts +++ b/plugins/catalog-backend-module-bitbucket-cloud/src/module/catalogModuleBitbucketCloudEntityProvider.ts @@ -31,7 +31,7 @@ import { BitbucketCloudEntityProvider } from '../providers/BitbucketCloudEntityP */ export const catalogModuleBitbucketCloudEntityProvider = createBackendModule({ pluginId: 'catalog', - moduleId: 'bitbucketCloudEntityProvider', + moduleId: 'bitbucket-cloud-entity-provider', register(env) { env.registerInit({ deps: { diff --git a/plugins/catalog-backend-module-bitbucket-server/src/module/catalogModuleBitbucketServerEntityProvider.ts b/plugins/catalog-backend-module-bitbucket-server/src/module/catalogModuleBitbucketServerEntityProvider.ts index ef71df9b06..dd2a423cdc 100644 --- a/plugins/catalog-backend-module-bitbucket-server/src/module/catalogModuleBitbucketServerEntityProvider.ts +++ b/plugins/catalog-backend-module-bitbucket-server/src/module/catalogModuleBitbucketServerEntityProvider.ts @@ -27,7 +27,7 @@ import { BitbucketServerEntityProvider } from '../providers'; */ export const catalogModuleBitbucketServerEntityProvider = createBackendModule({ pluginId: 'catalog', - moduleId: 'bitbucketServerEntityProvider', + moduleId: 'bitbucket-server-entity-provider', register(env) { env.registerInit({ deps: { diff --git a/plugins/catalog-backend-module-gcp/src/module/catalogModuleGcpGkeEntityProvider.ts b/plugins/catalog-backend-module-gcp/src/module/catalogModuleGcpGkeEntityProvider.ts index 7f93bddbfe..acc216e1f6 100644 --- a/plugins/catalog-backend-module-gcp/src/module/catalogModuleGcpGkeEntityProvider.ts +++ b/plugins/catalog-backend-module-gcp/src/module/catalogModuleGcpGkeEntityProvider.ts @@ -29,7 +29,7 @@ import { GkeEntityProvider } from '../providers/GkeEntityProvider'; */ export const catalogModuleGcpGkeEntityProvider = createBackendModule({ pluginId: 'catalog', - moduleId: 'gcpGkeEntityProvider', + moduleId: 'gcp-gke-entity-provider', register(env) { env.registerInit({ deps: { diff --git a/plugins/catalog-backend-module-gerrit/src/module/catalogModuleGerritEntityProvider.ts b/plugins/catalog-backend-module-gerrit/src/module/catalogModuleGerritEntityProvider.ts index bb29ce6eef..af870d095f 100644 --- a/plugins/catalog-backend-module-gerrit/src/module/catalogModuleGerritEntityProvider.ts +++ b/plugins/catalog-backend-module-gerrit/src/module/catalogModuleGerritEntityProvider.ts @@ -27,7 +27,7 @@ import { GerritEntityProvider } from '../providers/GerritEntityProvider'; */ export const catalogModuleGerritEntityProvider = createBackendModule({ pluginId: 'catalog', - moduleId: 'gerritEntityProvider', + moduleId: 'gerrit-entity-provider', register(env) { env.registerInit({ deps: { diff --git a/plugins/catalog-backend-module-github-org/src/module.ts b/plugins/catalog-backend-module-github-org/src/module.ts index e510464bb7..d666f78bde 100644 --- a/plugins/catalog-backend-module-github-org/src/module.ts +++ b/plugins/catalog-backend-module-github-org/src/module.ts @@ -68,7 +68,7 @@ export const githubOrgEntityProviderTransformsExtensionPoint = */ export const catalogModuleGithubOrgEntityProvider = createBackendModule({ pluginId: 'catalog', - moduleId: 'githubOrgEntityProvider', + moduleId: 'github-org-entity-provider', register(env) { let userTransformer: UserTransformer | undefined; let teamTransformer: TeamTransformer | undefined; diff --git a/plugins/catalog-backend-module-github/src/module/catalogModuleGithubEntityProvider.ts b/plugins/catalog-backend-module-github/src/module/catalogModuleGithubEntityProvider.ts index 8e052bd0a0..bfa8cf2a4e 100644 --- a/plugins/catalog-backend-module-github/src/module/catalogModuleGithubEntityProvider.ts +++ b/plugins/catalog-backend-module-github/src/module/catalogModuleGithubEntityProvider.ts @@ -29,7 +29,7 @@ import { GithubEntityProvider } from '../providers/GithubEntityProvider'; */ export const catalogModuleGithubEntityProvider = createBackendModule({ pluginId: 'catalog', - moduleId: 'githubEntityProvider', + moduleId: 'github-entity-provider', register(env) { env.registerInit({ deps: { diff --git a/plugins/catalog-backend-module-gitlab/src/module/catalogModuleGitlabDiscoveryEntityProvider.ts b/plugins/catalog-backend-module-gitlab/src/module/catalogModuleGitlabDiscoveryEntityProvider.ts index d192e8f3a5..9979d0862e 100644 --- a/plugins/catalog-backend-module-gitlab/src/module/catalogModuleGitlabDiscoveryEntityProvider.ts +++ b/plugins/catalog-backend-module-gitlab/src/module/catalogModuleGitlabDiscoveryEntityProvider.ts @@ -29,7 +29,7 @@ import { GitlabDiscoveryEntityProvider } from '../providers'; */ export const catalogModuleGitlabDiscoveryEntityProvider = createBackendModule({ pluginId: 'catalog', - moduleId: 'gitlabDiscoveryEntityProvider', + moduleId: 'gitlab-discovery-entity-provider', register(env) { env.registerInit({ deps: { diff --git a/plugins/catalog-backend-module-incremental-ingestion/src/module/catalogModuleIncrementalIngestionEntityProvider.test.ts b/plugins/catalog-backend-module-incremental-ingestion/src/module/catalogModuleIncrementalIngestionEntityProvider.test.ts index 7d76ddf480..316a4be7eb 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/src/module/catalogModuleIncrementalIngestionEntityProvider.test.ts +++ b/plugins/catalog-backend-module-incremental-ingestion/src/module/catalogModuleIncrementalIngestionEntityProvider.test.ts @@ -48,7 +48,7 @@ describe('catalogModuleIncrementalIngestionEntityProvider', () => { catalogModuleIncrementalIngestionEntityProvider(), createBackendModule({ pluginId: 'catalog', - moduleId: 'incrementalTest', + moduleId: 'incremental-test', register(env) { env.registerInit({ deps: { extension: incrementalIngestionProvidersExtensionPoint }, diff --git a/plugins/catalog-backend-module-incremental-ingestion/src/module/catalogModuleIncrementalIngestionEntityProvider.ts b/plugins/catalog-backend-module-incremental-ingestion/src/module/catalogModuleIncrementalIngestionEntityProvider.ts index 4e94088ef6..adb5ab6a04 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/src/module/catalogModuleIncrementalIngestionEntityProvider.ts +++ b/plugins/catalog-backend-module-incremental-ingestion/src/module/catalogModuleIncrementalIngestionEntityProvider.ts @@ -49,7 +49,7 @@ export interface IncrementalIngestionProviderExtensionPoint { * ```ts * backend.add(createBackendModule({ * pluginId: 'catalog', - * moduleId: 'myIncrementalProvider', + * moduleId: 'my-incremental-provider', * register(env) { * env.registerInit({ * deps: { @@ -85,7 +85,7 @@ export const incrementalIngestionProvidersExtensionPoint = export const catalogModuleIncrementalIngestionEntityProvider = createBackendModule({ pluginId: 'catalog', - moduleId: 'incrementalIngestionEntityProvider', + moduleId: 'incremental-ingestion-entity-provider', register(env) { const addedProviders = new Array<{ provider: IncrementalEntityProvider; diff --git a/plugins/catalog-backend-module-incremental-ingestion/src/run.ts b/plugins/catalog-backend-module-incremental-ingestion/src/run.ts index c24deb6adb..5af31482a6 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/src/run.ts +++ b/plugins/catalog-backend-module-incremental-ingestion/src/run.ts @@ -67,7 +67,7 @@ async function main() { backend.add( createBackendModule({ pluginId: 'catalog', - moduleId: 'incrementalTestProvider', + moduleId: 'incremental-test-provider', register(reg) { reg.registerInit({ deps: { extension: incrementalIngestionProvidersExtensionPoint }, diff --git a/plugins/catalog-backend-module-puppetdb/src/module/catalogModulePuppetDbEntityProvider.ts b/plugins/catalog-backend-module-puppetdb/src/module/catalogModulePuppetDbEntityProvider.ts index 5546b5283b..aad28eb47a 100644 --- a/plugins/catalog-backend-module-puppetdb/src/module/catalogModulePuppetDbEntityProvider.ts +++ b/plugins/catalog-backend-module-puppetdb/src/module/catalogModulePuppetDbEntityProvider.ts @@ -29,7 +29,7 @@ import { PuppetDbEntityProvider } from '../providers/PuppetDbEntityProvider'; */ export const catalogModulePuppetDbEntityProvider = createBackendModule({ pluginId: 'catalog', - moduleId: 'puppetDbEntityProvider', + moduleId: 'puppetdb-entity-provider', register(env) { env.registerInit({ deps: { diff --git a/plugins/catalog-backend-module-scaffolder-entity-model/src/module.ts b/plugins/catalog-backend-module-scaffolder-entity-model/src/module.ts index 8ed763d32c..74048dea12 100644 --- a/plugins/catalog-backend-module-scaffolder-entity-model/src/module.ts +++ b/plugins/catalog-backend-module-scaffolder-entity-model/src/module.ts @@ -26,7 +26,7 @@ import { ScaffolderEntitiesProcessor } from '@backstage/plugin-catalog-backend-m */ export const catalogModuleScaffolderEntityModel = createBackendModule({ pluginId: 'catalog', - moduleId: 'scaffolderEntityModel', + moduleId: 'scaffolder-entity-model', register(env) { env.registerInit({ deps: { diff --git a/plugins/catalog-backend-module-unprocessed/src/module.ts b/plugins/catalog-backend-module-unprocessed/src/module.ts index 1db4fd70b0..8c724d432d 100644 --- a/plugins/catalog-backend-module-unprocessed/src/module.ts +++ b/plugins/catalog-backend-module-unprocessed/src/module.ts @@ -27,7 +27,7 @@ import { UnprocessedEntitiesModule } from './UnprocessedEntitiesModule'; */ export const catalogModuleUnprocessedEntities = createBackendModule({ pluginId: 'catalog', - moduleId: 'catalogModuleUnprocessedEntities', + moduleId: 'catalog-module-unprocessed-entities', register(env) { env.registerInit({ deps: { diff --git a/plugins/catalog-backend/src/tests/performance/stitchingPerformance.test.ts b/plugins/catalog-backend/src/tests/performance/stitchingPerformance.test.ts index ad659ce845..7902a5e230 100644 --- a/plugins/catalog-backend/src/tests/performance/stitchingPerformance.test.ts +++ b/plugins/catalog-backend/src/tests/performance/stitchingPerformance.test.ts @@ -188,8 +188,8 @@ describePerformanceTest('stitchingPerformance', () => { factory: () => ({ getClient: async () => knex }), }), createBackendModule({ - moduleId: 'syntheticLoadEntities', pluginId: 'catalog', + moduleId: 'synthetic-load-entities', register(reg) { reg.registerInit({ deps: { @@ -245,8 +245,8 @@ describePerformanceTest('stitchingPerformance', () => { factory: () => ({ getClient: async () => knex }), }), createBackendModule({ - moduleId: 'syntheticLoadEntities', pluginId: 'catalog', + moduleId: 'synthetic-load-entities', register(reg) { reg.registerInit({ deps: { diff --git a/plugins/events-backend-module-aws-sqs/src/service/eventsModuleAwsSqsConsumingEventPublisher.ts b/plugins/events-backend-module-aws-sqs/src/service/eventsModuleAwsSqsConsumingEventPublisher.ts index 9045047094..eabab94708 100644 --- a/plugins/events-backend-module-aws-sqs/src/service/eventsModuleAwsSqsConsumingEventPublisher.ts +++ b/plugins/events-backend-module-aws-sqs/src/service/eventsModuleAwsSqsConsumingEventPublisher.ts @@ -29,7 +29,7 @@ import { AwsSqsConsumingEventPublisher } from '../publisher/AwsSqsConsumingEvent */ export const eventsModuleAwsSqsConsumingEventPublisher = createBackendModule({ pluginId: 'events', - moduleId: 'awsSqsConsumingEventPublisher', + moduleId: 'aws-sqs-consuming-event-publisher', register(env) { env.registerInit({ deps: { diff --git a/plugins/events-backend-module-azure/src/service/eventsModuleAzureDevOpsEventRouter.ts b/plugins/events-backend-module-azure/src/service/eventsModuleAzureDevOpsEventRouter.ts index 36f3acada0..50bc384502 100644 --- a/plugins/events-backend-module-azure/src/service/eventsModuleAzureDevOpsEventRouter.ts +++ b/plugins/events-backend-module-azure/src/service/eventsModuleAzureDevOpsEventRouter.ts @@ -27,7 +27,7 @@ import { AzureDevOpsEventRouter } from '../router/AzureDevOpsEventRouter'; */ export const eventsModuleAzureDevOpsEventRouter = createBackendModule({ pluginId: 'events', - moduleId: 'azureDevOpsEventRouter', + moduleId: 'azure-dev-ops-event-router', register(env) { env.registerInit({ deps: { diff --git a/plugins/events-backend-module-bitbucket-cloud/src/service/eventsModuleBitbucketCloudEventRouter.ts b/plugins/events-backend-module-bitbucket-cloud/src/service/eventsModuleBitbucketCloudEventRouter.ts index 60a8cc31c8..841a463001 100644 --- a/plugins/events-backend-module-bitbucket-cloud/src/service/eventsModuleBitbucketCloudEventRouter.ts +++ b/plugins/events-backend-module-bitbucket-cloud/src/service/eventsModuleBitbucketCloudEventRouter.ts @@ -27,7 +27,7 @@ import { BitbucketCloudEventRouter } from '../router/BitbucketCloudEventRouter'; */ export const eventsModuleBitbucketCloudEventRouter = createBackendModule({ pluginId: 'events', - moduleId: 'bitbucketCloudEventRouter', + moduleId: 'bitbucket-cloud-event-router', register(env) { env.registerInit({ deps: { diff --git a/plugins/events-backend-module-gerrit/src/service/eventsModuleGerritEventRouter.ts b/plugins/events-backend-module-gerrit/src/service/eventsModuleGerritEventRouter.ts index 8d490ea0b2..780ff7f878 100644 --- a/plugins/events-backend-module-gerrit/src/service/eventsModuleGerritEventRouter.ts +++ b/plugins/events-backend-module-gerrit/src/service/eventsModuleGerritEventRouter.ts @@ -27,7 +27,7 @@ import { GerritEventRouter } from '../router/GerritEventRouter'; */ export const eventsModuleGerritEventRouter = createBackendModule({ pluginId: 'events', - moduleId: 'gerritEventRouter', + moduleId: 'gerrit-event-router', register(env) { env.registerInit({ deps: { diff --git a/plugins/events-backend-module-github/src/service/eventsModuleGithubEventRouter.ts b/plugins/events-backend-module-github/src/service/eventsModuleGithubEventRouter.ts index 17485098c2..093307dfaf 100644 --- a/plugins/events-backend-module-github/src/service/eventsModuleGithubEventRouter.ts +++ b/plugins/events-backend-module-github/src/service/eventsModuleGithubEventRouter.ts @@ -27,7 +27,7 @@ import { GithubEventRouter } from '../router/GithubEventRouter'; */ export const eventsModuleGithubEventRouter = createBackendModule({ pluginId: 'events', - moduleId: 'githubEventRouter', + moduleId: 'github-event-router', register(env) { env.registerInit({ deps: { diff --git a/plugins/events-backend-module-github/src/service/eventsModuleGithubWebhook.ts b/plugins/events-backend-module-github/src/service/eventsModuleGithubWebhook.ts index b4bd666036..647b21c364 100644 --- a/plugins/events-backend-module-github/src/service/eventsModuleGithubWebhook.ts +++ b/plugins/events-backend-module-github/src/service/eventsModuleGithubWebhook.ts @@ -30,7 +30,7 @@ import { createGithubSignatureValidator } from '../http/createGithubSignatureVal */ export const eventsModuleGithubWebhook = createBackendModule({ pluginId: 'events', - moduleId: 'githubWebhook', + moduleId: 'github-webhook', register(env) { env.registerInit({ deps: { diff --git a/plugins/events-backend-module-gitlab/src/service/eventsModuleGitlabEventRouter.ts b/plugins/events-backend-module-gitlab/src/service/eventsModuleGitlabEventRouter.ts index 3425601529..fc44e95057 100644 --- a/plugins/events-backend-module-gitlab/src/service/eventsModuleGitlabEventRouter.ts +++ b/plugins/events-backend-module-gitlab/src/service/eventsModuleGitlabEventRouter.ts @@ -27,7 +27,7 @@ import { GitlabEventRouter } from '../router/GitlabEventRouter'; */ export const eventsModuleGitlabEventRouter = createBackendModule({ pluginId: 'events', - moduleId: 'gitlabEventRouter', + moduleId: 'gitlab-event-router', register(env) { env.registerInit({ deps: { diff --git a/plugins/events-backend-module-gitlab/src/service/eventsModuleGitlabWebhook.ts b/plugins/events-backend-module-gitlab/src/service/eventsModuleGitlabWebhook.ts index bd596b4baf..77bca7236b 100644 --- a/plugins/events-backend-module-gitlab/src/service/eventsModuleGitlabWebhook.ts +++ b/plugins/events-backend-module-gitlab/src/service/eventsModuleGitlabWebhook.ts @@ -32,7 +32,7 @@ import { createGitlabTokenValidator } from '../http/createGitlabTokenValidator'; */ export const eventsModuleGitlabWebhook = createBackendModule({ pluginId: 'events', - moduleId: 'gitlabWebhook', + moduleId: 'gitlab-webhook', register(env) { env.registerInit({ deps: { diff --git a/plugins/events-backend/README.md b/plugins/events-backend/README.md index 969e1bbcb2..29c420cef2 100644 --- a/plugins/events-backend/README.md +++ b/plugins/events-backend/README.md @@ -201,7 +201,7 @@ import { eventsExtensionPoint } from '@backstage/plugin-events-node'; export const yourModuleEventsModule = createBackendModule({ pluginId: 'events', - moduleId: 'yourModule', + moduleId: 'your-module', register(env) { // [...] env.registerInit({ @@ -252,7 +252,7 @@ import { eventsExtensionPoint } from '@backstage/plugin-events-node'; export const eventsModuleYourFeature = createBackendModule({ pluginId: 'events', - moduleId: 'yourFeature', + moduleId: 'your-feature', register(env) { // [...] env.registerInit({ diff --git a/plugins/kubernetes-backend/src/routes/resourceRoutes.test.ts b/plugins/kubernetes-backend/src/routes/resourceRoutes.test.ts index b8254d781c..6d69606316 100644 --- a/plugins/kubernetes-backend/src/routes/resourceRoutes.test.ts +++ b/plugins/kubernetes-backend/src/routes/resourceRoutes.test.ts @@ -107,7 +107,7 @@ describe('resourcesRoutes', () => { import('@backstage/plugin-kubernetes-backend/alpha'), createBackendModule({ pluginId: 'kubernetes', - moduleId: 'testObjectsProvider', + moduleId: 'test-objects-provider', register(env) { env.registerInit({ deps: { extension: kubernetesObjectsProviderExtensionPoint }, diff --git a/plugins/permission-backend-module-policy-allow-all/src/module.ts b/plugins/permission-backend-module-policy-allow-all/src/module.ts index 47ab202a00..f7a38f293c 100644 --- a/plugins/permission-backend-module-policy-allow-all/src/module.ts +++ b/plugins/permission-backend-module-policy-allow-all/src/module.ts @@ -23,8 +23,8 @@ import { AllowAllPermissionPolicy } from './policy'; * @public */ export const permissionModuleAllowAllPolicy = createBackendModule({ - moduleId: 'allowAllPolicy', pluginId: 'permission', + moduleId: 'allow-all-policy', register(reg) { reg.registerInit({ deps: { policy: policyExtensionPoint }, diff --git a/plugins/search-backend-module-catalog/README.md b/plugins/search-backend-module-catalog/README.md index 9deeccb910..4f37234a7e 100644 --- a/plugins/search-backend-module-catalog/README.md +++ b/plugins/search-backend-module-catalog/README.md @@ -61,7 +61,7 @@ backend.add(searchModuleCatalogCollator()); backend.add( createBackendModule({ pluginId: 'search', - moduleId: 'myCatalogCollatorOptions', + moduleId: 'my-catalog-collator-options', register(reg) { reg.registerInit({ deps: { collator: catalogCollatorExtensionPoint }, diff --git a/plugins/search-backend-module-catalog/src/alpha.ts b/plugins/search-backend-module-catalog/src/alpha.ts index 5813bb235e..71dabeb011 100644 --- a/plugins/search-backend-module-catalog/src/alpha.ts +++ b/plugins/search-backend-module-catalog/src/alpha.ts @@ -61,8 +61,8 @@ export const catalogCollatorExtensionPoint = * @alpha */ export default createBackendModule({ - moduleId: 'catalogCollator', pluginId: 'search', + moduleId: 'catalog-collator', register(env) { let entityTransformer: CatalogCollatorEntityTransformer | undefined; diff --git a/plugins/search-backend-module-elasticsearch/src/alpha.ts b/plugins/search-backend-module-elasticsearch/src/alpha.ts index f289847865..f5952fbc86 100644 --- a/plugins/search-backend-module-elasticsearch/src/alpha.ts +++ b/plugins/search-backend-module-elasticsearch/src/alpha.ts @@ -45,8 +45,8 @@ export const elasticsearchTranslatorExtensionPoint = * @alpha */ export default createBackendModule({ - moduleId: 'elasticsearchEngine', pluginId: 'search', + moduleId: 'elasticsearch-engine', register(env) { let translator: ElasticSearchQueryTranslator | undefined; diff --git a/plugins/search-backend-module-explore/src/alpha.ts b/plugins/search-backend-module-explore/src/alpha.ts index e8e3361e1b..858be9220a 100644 --- a/plugins/search-backend-module-explore/src/alpha.ts +++ b/plugins/search-backend-module-explore/src/alpha.ts @@ -35,8 +35,8 @@ import { readTaskScheduleDefinitionFromConfig } from '@backstage/backend-tasks'; * @alpha */ export default createBackendModule({ - moduleId: 'exploreCollator', pluginId: 'search', + moduleId: 'explore-collator', register(env) { env.registerInit({ deps: { diff --git a/plugins/search-backend-module-pg/src/alpha.ts b/plugins/search-backend-module-pg/src/alpha.ts index 4052b56cb3..4628b300f2 100644 --- a/plugins/search-backend-module-pg/src/alpha.ts +++ b/plugins/search-backend-module-pg/src/alpha.ts @@ -25,8 +25,8 @@ import { PgSearchEngine } from './PgSearchEngine'; * Search backend module for the Postgres engine. */ export default createBackendModule({ - moduleId: 'postgresEngine', pluginId: 'search', + moduleId: 'postgres-engine', register(env) { env.registerInit({ deps: { diff --git a/plugins/search-backend-module-stack-overflow-collator/src/module/SearchStackOverflowCollatorModule.ts b/plugins/search-backend-module-stack-overflow-collator/src/module/SearchStackOverflowCollatorModule.ts index 3ef3d72c32..a8a0b266ba 100644 --- a/plugins/search-backend-module-stack-overflow-collator/src/module/SearchStackOverflowCollatorModule.ts +++ b/plugins/search-backend-module-stack-overflow-collator/src/module/SearchStackOverflowCollatorModule.ts @@ -28,8 +28,8 @@ import { StackOverflowQuestionsCollatorFactory } from '../collators'; * Search backend module for the Stack Overflow index. */ export const searchStackOverflowCollatorModule = createBackendModule({ - moduleId: 'stackOverflowCollator', pluginId: 'search', + moduleId: 'stack-overflow-collator', register(env) { env.registerInit({ deps: { diff --git a/plugins/search-backend-module-techdocs/src/alpha.ts b/plugins/search-backend-module-techdocs/src/alpha.ts index 950acd4039..e8be7cc864 100644 --- a/plugins/search-backend-module-techdocs/src/alpha.ts +++ b/plugins/search-backend-module-techdocs/src/alpha.ts @@ -51,8 +51,8 @@ export const techdocsCollatorEntityTransformerExtensionPoint = * Search backend module for the TechDocs index. */ export default createBackendModule({ - moduleId: 'techDocsCollator', pluginId: 'search', + moduleId: 'techdocs-collator', register(env) { let transformer: TechDocsCollatorEntityTransformer | undefined; From e223f2264d0d3e69f934ac1d8805ee33e690c7b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Wed, 22 Nov 2023 17:03:32 +0100 Subject: [PATCH 174/261] implement text based entity card/content filters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Vincenzo Scamporlino Signed-off-by: Fredrik Adelöw --- .changeset/stale-jokes-hunt.md | 5 + .changeset/thick-snails-travel.md | 5 + .changeset/thirty-fireants-cheer.md | 7 + packages/app-next/app-config.yaml | 3 +- plugins/catalog-common/api-report-alpha.md | 6 + plugins/catalog-common/package.json | 1 + plugins/catalog-common/src/alpha.ts | 1 + plugins/catalog-common/src/filter/index.ts | 17 ++ .../src/filter/matrchers/createHasMatcher.ts | 48 +++++ .../src/filter/matrchers/createIsMatcher.ts | 41 +++++ .../src/filter/matrchers/createKindMatcher.ts | 25 +++ .../src/filter/matrchers/createTypeMatcher.ts | 31 ++++ .../src/filter/matrchers/types.ts | 19 ++ .../src/filter/parseFilterExpression.test.ts | 169 ++++++++++++++++++ .../src/filter/parseFilterExpression.ts | 99 ++++++++++ plugins/catalog-react/api-report-alpha.md | 20 +-- plugins/catalog-react/src/alpha.tsx | 70 ++------ .../catalog/src/alpha/EntityOverviewPage.tsx | 42 +++-- plugins/catalog/src/alpha/entityCards.tsx | 4 +- plugins/catalog/src/alpha/entityContents.tsx | 2 +- plugins/catalog/src/alpha/plugin.tsx | 2 +- yarn.lock | 1 + 22 files changed, 529 insertions(+), 89 deletions(-) create mode 100644 .changeset/stale-jokes-hunt.md create mode 100644 .changeset/thick-snails-travel.md create mode 100644 .changeset/thirty-fireants-cheer.md create mode 100644 plugins/catalog-common/src/filter/index.ts create mode 100644 plugins/catalog-common/src/filter/matrchers/createHasMatcher.ts create mode 100644 plugins/catalog-common/src/filter/matrchers/createIsMatcher.ts create mode 100644 plugins/catalog-common/src/filter/matrchers/createKindMatcher.ts create mode 100644 plugins/catalog-common/src/filter/matrchers/createTypeMatcher.ts create mode 100644 plugins/catalog-common/src/filter/matrchers/types.ts create mode 100644 plugins/catalog-common/src/filter/parseFilterExpression.test.ts create mode 100644 plugins/catalog-common/src/filter/parseFilterExpression.ts diff --git a/.changeset/stale-jokes-hunt.md b/.changeset/stale-jokes-hunt.md new file mode 100644 index 0000000000..cbea2dd229 --- /dev/null +++ b/.changeset/stale-jokes-hunt.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-common': minor +--- + +Added a `parseFilterExpression` function to interpret visibility filters diff --git a/.changeset/thick-snails-travel.md b/.changeset/thick-snails-travel.md new file mode 100644 index 0000000000..af27df78e5 --- /dev/null +++ b/.changeset/thick-snails-travel.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog': minor +--- + +Properly support both function- and string-form visibility filter expressions diff --git a/.changeset/thirty-fireants-cheer.md b/.changeset/thirty-fireants-cheer.md new file mode 100644 index 0000000000..abda872570 --- /dev/null +++ b/.changeset/thirty-fireants-cheer.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-catalog-react': patch +--- + +Breaking alpha-API change to entity visibility filter functions to accept a bare entity as their first argument, instead of an object with an entity property. + +Functions that accept such filters now also support the string expression form of filters. diff --git a/packages/app-next/app-config.yaml b/packages/app-next/app-config.yaml index a46e119ac0..a90fe630b5 100644 --- a/packages/app-next/app-config.yaml +++ b/packages/app-next/app-config.yaml @@ -14,8 +14,7 @@ app: - entity.cards.labels - entity.cards.links: config: - filter: - - isKind: component + filter: kind:component # Entity page content - entity.content.techdocs diff --git a/plugins/catalog-common/api-report-alpha.md b/plugins/catalog-common/api-report-alpha.md index 12e0806a9c..573b35d3b3 100644 --- a/plugins/catalog-common/api-report-alpha.md +++ b/plugins/catalog-common/api-report-alpha.md @@ -4,6 +4,7 @@ ```ts import { BasicPermission } from '@backstage/plugin-permission-common'; +import { Entity } from '@backstage/catalog-model'; import { ResourcePermission } from '@backstage/plugin-permission-common'; // @alpha @@ -38,6 +39,11 @@ export const catalogPermissions: ( | ResourcePermission<'catalog-entity'> )[]; +// @alpha +export function parseFilterExpression( + expression: string, +): (entity: Entity) => boolean; + // @alpha export const RESOURCE_TYPE_CATALOG_ENTITY = 'catalog-entity'; diff --git a/plugins/catalog-common/package.json b/plugins/catalog-common/package.json index 45720ee32a..ac21b76c2a 100644 --- a/plugins/catalog-common/package.json +++ b/plugins/catalog-common/package.json @@ -46,6 +46,7 @@ }, "dependencies": { "@backstage/catalog-model": "workspace:^", + "@backstage/errors": "workspace:^", "@backstage/plugin-permission-common": "workspace:^", "@backstage/plugin-search-common": "workspace:^" }, diff --git a/plugins/catalog-common/src/alpha.ts b/plugins/catalog-common/src/alpha.ts index 2dfc028332..015769c8a7 100644 --- a/plugins/catalog-common/src/alpha.ts +++ b/plugins/catalog-common/src/alpha.ts @@ -26,3 +26,4 @@ export { catalogPermissions, } from './permissions'; export type { CatalogEntityPermission } from './permissions'; +export { parseFilterExpression } from './filter'; diff --git a/plugins/catalog-common/src/filter/index.ts b/plugins/catalog-common/src/filter/index.ts new file mode 100644 index 0000000000..c5ad803f4c --- /dev/null +++ b/plugins/catalog-common/src/filter/index.ts @@ -0,0 +1,17 @@ +/* + * 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 { parseFilterExpression } from './parseFilterExpression'; diff --git a/plugins/catalog-common/src/filter/matrchers/createHasMatcher.ts b/plugins/catalog-common/src/filter/matrchers/createHasMatcher.ts new file mode 100644 index 0000000000..7b9eebba1c --- /dev/null +++ b/plugins/catalog-common/src/filter/matrchers/createHasMatcher.ts @@ -0,0 +1,48 @@ +/* + * 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 { InputError } from '@backstage/errors'; +import { EntityMatcherFn } from './types'; + +/** + * Matches on the non-empty presence of different parts of the entity + */ +export function createHasMatcher(parameters: string[]): EntityMatcherFn { + const allowedMatchers: Record = { + labels: entity => { + return Object.keys(entity.metadata.labels ?? {}).length > 0; + }, + annotations: entity => { + return Object.keys(entity.metadata.annotations ?? {}).length > 0; + }, + links: entity => { + return (entity.metadata.links ?? []).length > 0; + }, + }; + + const matchers = parameters.map(parameter => { + const matcher = allowedMatchers[parameter.toLocaleLowerCase('en-US')]; + if (!matcher) { + const known = Object.keys(allowedMatchers).map(m => `'${m}'`); + throw new InputError( + `'${parameter}' is not a valid parameter for 'has' filter expressions, expected one of ${known}`, + ); + } + return matcher; + }); + + return entity => matchers.some(matcher => matcher(entity)); +} diff --git a/plugins/catalog-common/src/filter/matrchers/createIsMatcher.ts b/plugins/catalog-common/src/filter/matrchers/createIsMatcher.ts new file mode 100644 index 0000000000..3802d6dbce --- /dev/null +++ b/plugins/catalog-common/src/filter/matrchers/createIsMatcher.ts @@ -0,0 +1,41 @@ +/* + * 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 { InputError } from '@backstage/errors'; +import { EntityMatcherFn } from './types'; + +/** + * Matches on different semantic properties of the entity + */ +export function createIsMatcher(parameters: string[]): EntityMatcherFn { + const allowedMatchers: Record = { + orphan: entity => + Boolean(entity.metadata.annotations?.['backstage.io/orphan']), + }; + + const matchers = parameters.map(parameter => { + const matcher = allowedMatchers[parameter.toLocaleLowerCase('en-US')]; + if (!matcher) { + const known = Object.keys(allowedMatchers).map(m => `'${m}'`); + throw new InputError( + `'${parameter}' is not a valid parameter for 'is' filter expressions, expected one of ${known}`, + ); + } + return matcher; + }); + + return entity => matchers.some(matcher => matcher(entity)); +} diff --git a/plugins/catalog-common/src/filter/matrchers/createKindMatcher.ts b/plugins/catalog-common/src/filter/matrchers/createKindMatcher.ts new file mode 100644 index 0000000000..071746453e --- /dev/null +++ b/plugins/catalog-common/src/filter/matrchers/createKindMatcher.ts @@ -0,0 +1,25 @@ +/* + * 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 { EntityMatcherFn } from './types'; + +/** + * Matches on kind + */ +export function createKindMatcher(parameters: string[]): EntityMatcherFn { + const items = parameters.map(p => p.toLocaleLowerCase('en-US')); + return entity => items.includes(entity.kind.toLocaleLowerCase('en-US')); +} diff --git a/plugins/catalog-common/src/filter/matrchers/createTypeMatcher.ts b/plugins/catalog-common/src/filter/matrchers/createTypeMatcher.ts new file mode 100644 index 0000000000..d0e0f39c98 --- /dev/null +++ b/plugins/catalog-common/src/filter/matrchers/createTypeMatcher.ts @@ -0,0 +1,31 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { EntityMatcherFn } from './types'; + +/** + * Matches on spec.type + */ +export function createTypeMatcher(parameters: string[]): EntityMatcherFn { + const items = parameters.map(p => p.toLocaleLowerCase('en-US')); + return entity => { + const value = entity.spec?.type; + return ( + typeof value === 'string' && + items.includes(value.toLocaleLowerCase('en-US')) + ); + }; +} diff --git a/plugins/catalog-common/src/filter/matrchers/types.ts b/plugins/catalog-common/src/filter/matrchers/types.ts new file mode 100644 index 0000000000..0fff91b3d5 --- /dev/null +++ b/plugins/catalog-common/src/filter/matrchers/types.ts @@ -0,0 +1,19 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Entity } from '@backstage/catalog-model'; + +export type EntityMatcherFn = (entity: Entity) => boolean; diff --git a/plugins/catalog-common/src/filter/parseFilterExpression.test.ts b/plugins/catalog-common/src/filter/parseFilterExpression.test.ts new file mode 100644 index 0000000000..d8543c4e10 --- /dev/null +++ b/plugins/catalog-common/src/filter/parseFilterExpression.test.ts @@ -0,0 +1,169 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Entity } from '@backstage/catalog-model'; +import { + parseFilterExpression, + splitFilterExpression, +} from './parseFilterExpression'; + +describe('parseFilterExpression', () => { + it('supports "kind" expressions', () => { + const component = { kind: 'Component' } as unknown as Entity; + const user = { kind: 'User' } as unknown as Entity; + const resource = { kind: 'Resource' } as unknown as Entity; + + expect(parseFilterExpression('kind:component')(component)).toBe(true); + expect(parseFilterExpression('kind:componenT')(component)).toBe(true); + expect(parseFilterExpression('kind:user')(component)).toBe(false); + + // match ANY of the parameters + expect(parseFilterExpression('kind:user,component')(user)).toBe(true); + expect(parseFilterExpression('kind:user,component')(component)).toBe(true); + expect(parseFilterExpression('kind:user,component')(resource)).toBe(false); + }); + + it('supports "is" expressions', () => { + const empty = { + metadata: {}, + } as unknown as Entity; + const orphan = { + metadata: { + annotations: { ['backstage.io/orphan']: 'true' }, + }, + } as unknown as Entity; + + expect(parseFilterExpression('is:orphan')(empty)).toBe(false); + expect(parseFilterExpression('is:orphan')(orphan)).toBe(true); + + expect(() => + parseFilterExpression('is:orphan,bar'), + ).toThrowErrorMatchingInlineSnapshot( + `"'bar' is not a valid parameter for 'is' filter expressions, expected one of 'orphan'"`, + ); + }); + + it('supports "has" expressions', () => { + const empty1 = { + metadata: {}, + } as unknown as Entity; + const empty2 = { + metadata: { + labels: {}, + annotations: {}, + links: [], + }, + } as unknown as Entity; + const labels = { + metadata: { + labels: { a: 'b' }, + }, + } as unknown as Entity; + const annotations = { + metadata: { + annotations: { a: 'b' }, + }, + } as unknown as Entity; + const links = { + metadata: { links: [{}] }, + } as unknown as Entity; + + expect(parseFilterExpression('has:labels')(empty1)).toBe(false); + expect(parseFilterExpression('has:labels')(empty2)).toBe(false); + expect(parseFilterExpression('has:labels')(labels)).toBe(true); + + expect(parseFilterExpression('has:annotations')(empty1)).toBe(false); + expect(parseFilterExpression('has:annotations')(empty2)).toBe(false); + expect(parseFilterExpression('has:annotations')(annotations)).toBe(true); + + expect(parseFilterExpression('has:links')(empty1)).toBe(false); + expect(parseFilterExpression('has:links')(empty2)).toBe(false); + expect(parseFilterExpression('has:links')(links)).toBe(true); + + // match ANY of the parameters + expect(parseFilterExpression('has:labels,links')(empty1)).toBe(false); + expect(parseFilterExpression('has:labels,links')(empty2)).toBe(false); + expect(parseFilterExpression('has:labels,links')(labels)).toBe(true); + expect(parseFilterExpression('has:labels,links')(links)).toBe(true); + expect(parseFilterExpression('has:labels,links')(annotations)).toBe(false); + + expect(() => + parseFilterExpression('has:labels,bar'), + ).toThrowErrorMatchingInlineSnapshot( + `"'bar' is not a valid parameter for 'has' filter expressions, expected one of 'labels','annotations','links'"`, + ); + }); + + it('rejects unknown keys', () => { + expect(() => + parseFilterExpression('unknown:foo'), + ).toThrowErrorMatchingInlineSnapshot( + `"'unknown' is not a valid filter expression key, expected one of 'kind','type','is','has'"`, + ); + }); + + it('rejects malformed inputs', () => { + expect(() => parseFilterExpression(':')).toThrowErrorMatchingInlineSnapshot( + `"':' is not a valid filter expression, expected 'key:parameter' form"`, + ); + expect(() => + parseFilterExpression(':a'), + ).toThrowErrorMatchingInlineSnapshot( + `"':a' is not a valid filter expression, expected 'key:parameter' form"`, + ); + expect(() => + parseFilterExpression('a:'), + ).toThrowErrorMatchingInlineSnapshot( + `"'a:' is not a valid filter expression, expected 'key:parameter' form"`, + ); + }); +}); + +describe('splitFilterExpression', () => { + it('properly splits into expression atoms', () => { + expect(splitFilterExpression('')).toEqual([]); + expect(splitFilterExpression(' ')).toEqual([]); + expect(splitFilterExpression('kind:component')).toEqual([ + { key: 'kind', parameters: ['component'] }, + ]); + expect(splitFilterExpression('kind:component,user')).toEqual([ + { key: 'kind', parameters: ['component', 'user'] }, + ]); + expect(splitFilterExpression('kind:component,user type:foo')).toEqual([ + { key: 'kind', parameters: ['component', 'user'] }, + { key: 'type', parameters: ['foo'] }, + ]); + expect(splitFilterExpression('with:multiple:colons')).toEqual([ + { key: 'with', parameters: ['multiple:colons'] }, + ]); + }); + + it('rejects malformed inputs', () => { + expect(() => splitFilterExpression(':')).toThrowErrorMatchingInlineSnapshot( + `"':' is not a valid filter expression, expected 'key:parameter' form"`, + ); + expect(() => + splitFilterExpression(':a'), + ).toThrowErrorMatchingInlineSnapshot( + `"':a' is not a valid filter expression, expected 'key:parameter' form"`, + ); + expect(() => + splitFilterExpression('a:'), + ).toThrowErrorMatchingInlineSnapshot( + `"'a:' is not a valid filter expression, expected 'key:parameter' form"`, + ); + }); +}); diff --git a/plugins/catalog-common/src/filter/parseFilterExpression.ts b/plugins/catalog-common/src/filter/parseFilterExpression.ts new file mode 100644 index 0000000000..d2b46f582e --- /dev/null +++ b/plugins/catalog-common/src/filter/parseFilterExpression.ts @@ -0,0 +1,99 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Entity } from '@backstage/catalog-model'; +import { InputError } from '@backstage/errors'; +import { EntityMatcherFn } from './matrchers/types'; +import { createKindMatcher } from './matrchers/createKindMatcher'; +import { createTypeMatcher } from './matrchers/createTypeMatcher'; +import { createIsMatcher } from './matrchers/createIsMatcher'; +import { createHasMatcher } from './matrchers/createHasMatcher'; + +const rootMatcherFactories: Record< + string, + (parameters: string[]) => EntityMatcherFn +> = { + kind: createKindMatcher, + type: createTypeMatcher, + is: createIsMatcher, + has: createHasMatcher, +}; + +/** + * Parses a filter expression that decides whether to render an entity component + * or not. Returns a function that matches entities based on that expression. + * + * @alpha + * @remarks + * + * Filter strings are on the form `kind:user,group is:orphan`. There's + * effectively an AND between the space separated parts, and an OR between comma + * separated parameters. So the example filter string semantically means + * "entities that are of either User or Group kind, and also are orphans". + */ +export function parseFilterExpression( + expression: string, +): (entity: Entity) => boolean { + const parts = splitFilterExpression(expression); + + const matchers = parts.map(part => { + const factory = rootMatcherFactories[part.key]; + if (!factory) { + const known = Object.keys(rootMatcherFactories).map(m => `'${m}'`); + throw new InputError( + `'${part.key}' is not a valid filter expression key, expected one of ${known}`, + ); + } + return factory(part.parameters); + }); + + return (entity: Entity) => { + return matchers.every(matcher => { + try { + return matcher(entity); + } catch { + return false; + } + }); + }; +} + +export function splitFilterExpression( + expression: string, +): Array<{ key: string; parameters: string[] }> { + const words = expression + .split(' ') + .map(w => w.trim()) + .filter(Boolean); + + const result = new Array<{ key: string; parameters: string[] }>(); + + for (const word of words) { + const match = word.match(/^([^:]+):(.+)$/); + if (!match) { + throw new InputError( + `'${word}' is not a valid filter expression, expected 'key:parameter' form`, + ); + } + + const key = match[1]; + const parameters = match[2].split(','); + + result.push({ key, parameters }); + } + + return result; +} diff --git a/plugins/catalog-react/api-report-alpha.md b/plugins/catalog-react/api-report-alpha.md index ed851f810a..e284f80b8e 100644 --- a/plugins/catalog-react/api-report-alpha.md +++ b/plugins/catalog-react/api-report-alpha.md @@ -24,17 +24,12 @@ export function createEntityCardExtension< }; disabled?: boolean; inputs?: TInputs; - filter?: (ctx: { entity: Entity }) => boolean; + filter?: typeof entityFilterExtensionDataRef.T; loader: (options: { inputs: Expand>; }) => Promise; }): Extension<{ - filter?: - | { - isKind?: string | undefined; - isType?: string | undefined; - }[] - | undefined; + filter?: string | undefined; }>; // @alpha (undocumented) @@ -51,19 +46,14 @@ export function createEntityContentExtension< routeRef?: RouteRef; defaultPath: string; defaultTitle: string; - filter?: (ctx: { entity: Entity }) => boolean; + filter?: typeof entityFilterExtensionDataRef.T; loader: (options: { inputs: Expand>; }) => Promise; }): Extension<{ title: string; path: string; - filter?: - | { - isKind?: string | undefined; - isType?: string | undefined; - }[] - | undefined; + filter?: string | undefined; }>; // @alpha (undocumented) @@ -74,7 +64,7 @@ export const entityContentTitleExtensionDataRef: ConfigurableExtensionDataRef< // @alpha (undocumented) export const entityFilterExtensionDataRef: ConfigurableExtensionDataRef< - (ctx: { entity: Entity }) => boolean, + string | ((entity: Entity) => boolean), {} >; diff --git a/plugins/catalog-react/src/alpha.tsx b/plugins/catalog-react/src/alpha.tsx index a339816742..604c769fe5 100644 --- a/plugins/catalog-react/src/alpha.tsx +++ b/plugins/catalog-react/src/alpha.tsx @@ -14,7 +14,6 @@ * limitations under the License. */ -import React, { lazy } from 'react'; import { AnyExtensionInputMap, ExtensionBoundary, @@ -25,12 +24,13 @@ import { createExtensionDataRef, createSchemaFromZod, } from '@backstage/frontend-plugin-api'; +import React, { lazy } from 'react'; +import { Entity } from '@backstage/catalog-model'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports import { Expand } from '../../../packages/frontend-plugin-api/src/types'; -import { Entity } from '@backstage/catalog-model'; -export { isOwnerOf } from './utils'; export { useEntityPermission } from './hooks/useEntityPermission'; +export { isOwnerOf } from './utils'; /** @alpha */ export const entityContentTitleExtensionDataRef = @@ -38,41 +38,9 @@ export const entityContentTitleExtensionDataRef = /** @alpha */ export const entityFilterExtensionDataRef = createExtensionDataRef< - (ctx: { entity: Entity }) => boolean + string | ((entity: Entity) => boolean) >('plugin.catalog.entity.filter'); -function applyFilter(a?: string, b?: string): boolean { - if (!a) { - return true; - } - return a.toLocaleLowerCase('en-US') === b?.toLocaleLowerCase('en-US'); -} - -// TODO: Only two hardcoded isKind and isType filters are available for now -// This is just an initial config filter implementation and needs to be revisited -function buildFilter( - config: { filter?: { isKind?: string; isType?: string }[] }, - filterFunc?: (ctx: { entity: Entity }) => boolean, -) { - return (ctx: { entity: Entity }) => { - const configuredFilterMatch = config.filter?.some(filter => { - const kindMatch = applyFilter(filter.isKind, ctx.entity.kind); - const typeMatch = applyFilter( - filter.isType, - ctx.entity.spec?.type?.toString(), - ); - return kindMatch && typeMatch; - }); - if (configuredFilterMatch) { - return true; - } - if (filterFunc) { - return filterFunc(ctx); - } - return true; - }; -} - // TODO: Figure out how to merge with provided config schema /** @alpha */ export function createEntityCardExtension< @@ -82,7 +50,7 @@ export function createEntityCardExtension< attachTo?: { id: string; input: string }; disabled?: boolean; inputs?: TInputs; - filter?: (ctx: { entity: Entity }) => boolean; + filter?: typeof entityFilterExtensionDataRef.T; loader: (options: { inputs: Expand>; }) => Promise; @@ -98,19 +66,12 @@ export function createEntityCardExtension< disabled: options.disabled ?? true, output: { element: coreExtensionData.reactElement, - filter: entityFilterExtensionDataRef, + filter: entityFilterExtensionDataRef.optional(), }, inputs: options.inputs, configSchema: createSchemaFromZod(z => z.object({ - filter: z - .array( - z.object({ - isKind: z.string().optional(), - isType: z.string().optional(), - }), - ) - .optional(), + filter: z.string().optional(), }), ), factory({ config, inputs, node }) { @@ -126,7 +87,7 @@ export function createEntityCardExtension< ), - filter: buildFilter(config, options.filter), + filter: config.filter ?? options.filter, }; }, }); @@ -143,7 +104,7 @@ export function createEntityContentExtension< routeRef?: RouteRef; defaultPath: string; defaultTitle: string; - filter?: (ctx: { entity: Entity }) => boolean; + filter?: typeof entityFilterExtensionDataRef.T; loader: (options: { inputs: Expand>; }) => Promise; @@ -162,21 +123,14 @@ export function createEntityContentExtension< path: coreExtensionData.routePath, routeRef: coreExtensionData.routeRef.optional(), title: entityContentTitleExtensionDataRef, - filter: entityFilterExtensionDataRef, + filter: entityFilterExtensionDataRef.optional(), }, inputs: options.inputs, configSchema: createSchemaFromZod(z => z.object({ path: z.string().default(options.defaultPath), title: z.string().default(options.defaultTitle), - filter: z - .array( - z.object({ - isKind: z.string().optional(), - isType: z.string().optional(), - }), - ) - .optional(), + filter: z.string().optional(), }), ), factory({ config, inputs, node }) { @@ -195,7 +149,7 @@ export function createEntityContentExtension< ), - filter: buildFilter(config, options.filter), + filter: config.filter ?? options.filter, }; }, }); diff --git a/plugins/catalog/src/alpha/EntityOverviewPage.tsx b/plugins/catalog/src/alpha/EntityOverviewPage.tsx index baa93845ae..02ec044975 100644 --- a/plugins/catalog/src/alpha/EntityOverviewPage.tsx +++ b/plugins/catalog/src/alpha/EntityOverviewPage.tsx @@ -14,29 +14,51 @@ * limitations under the License. */ -import React from 'react'; -import { useEntity } from '@backstage/plugin-catalog-react'; import { Entity } from '@backstage/catalog-model'; +import { parseFilterExpression } from '@backstage/plugin-catalog-common/alpha'; +import { useEntity } from '@backstage/plugin-catalog-react'; import Grid from '@material-ui/core/Grid'; +import React, { useMemo } from 'react'; interface EntityOverviewPageProps { cards: Array<{ element: React.JSX.Element; - filter: (ctx: { entity: Entity }) => boolean; + filter?: string | ((entity: Entity) => boolean); }>; } +function CardWrapper(props: { + entity: Entity; + element: React.JSX.Element; + filter?: string | ((entity: Entity) => boolean); +}) { + const { entity, element, filter } = props; + + const filterFn = useMemo<(subject: Entity) => boolean>(() => { + if (!filter) { + return () => true; + } else if (typeof filter === 'function') { + return subject => filter(subject); + } + return parseFilterExpression(filter); + }, [filter]); + + return filterFn(entity) ? <>{element} : null; +} + export function EntityOverviewPage(props: EntityOverviewPageProps) { const { entity } = useEntity(); return ( - {props.cards - .filter(card => card.filter({ entity })) - .map(card => ( - - {card.element} - - ))} + {props.cards.map((card, index) => ( + + + + ))} ); } diff --git a/plugins/catalog/src/alpha/entityCards.tsx b/plugins/catalog/src/alpha/entityCards.tsx index c7b75679a7..572e2caa3c 100644 --- a/plugins/catalog/src/alpha/entityCards.tsx +++ b/plugins/catalog/src/alpha/entityCards.tsx @@ -27,7 +27,7 @@ export const EntityAboutCard = createEntityCardExtension({ export const EntityLinksCard = createEntityCardExtension({ id: 'links', - filter: ({ entity }) => Boolean(entity.metadata.links), + filter: 'has:links', loader: async () => import('../components/EntityLinksCard').then(m => { return ; @@ -36,7 +36,7 @@ export const EntityLinksCard = createEntityCardExtension({ export const EntityLabelsCard = createEntityCardExtension({ id: 'labels', - filter: ({ entity }) => Boolean(entity.metadata.labels), + filter: 'has:labels', loader: async () => import('../components/EntityLabelsCard').then(m => ( diff --git a/plugins/catalog/src/alpha/entityContents.tsx b/plugins/catalog/src/alpha/entityContents.tsx index 9bef4a5e0d..0bbee9bb7d 100644 --- a/plugins/catalog/src/alpha/entityContents.tsx +++ b/plugins/catalog/src/alpha/entityContents.tsx @@ -32,7 +32,7 @@ export const OverviewEntityContent = createEntityContentExtension({ inputs: { cards: createExtensionInput({ element: coreExtensionData.reactElement, - filter: entityFilterExtensionDataRef, + filter: entityFilterExtensionDataRef.optional(), }), }, loader: async ({ inputs }) => diff --git a/plugins/catalog/src/alpha/plugin.tsx b/plugins/catalog/src/alpha/plugin.tsx index 7140259df0..99aacd27da 100644 --- a/plugins/catalog/src/alpha/plugin.tsx +++ b/plugins/catalog/src/alpha/plugin.tsx @@ -22,8 +22,8 @@ import { entityRouteRef } from '@backstage/plugin-catalog-react'; import { createComponentRouteRef, createFromTemplateRouteRef, - unregisterRedirectRouteRef, rootRouteRef, + unregisterRedirectRouteRef, viewTechDocRouteRef, } from '../routes'; diff --git a/yarn.lock b/yarn.lock index 2399f06ac5..90be768746 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5831,6 +5831,7 @@ __metadata: dependencies: "@backstage/catalog-model": "workspace:^" "@backstage/cli": "workspace:^" + "@backstage/errors": "workspace:^" "@backstage/plugin-permission-common": "workspace:^" "@backstage/plugin-search-common": "workspace:^" languageName: unknown From 976519c3dc5fafed0788807e783ca88551710d74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Thu, 23 Nov 2023 11:31:03 +0100 Subject: [PATCH 175/261] add tests and error propagation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- plugins/catalog-common/api-report-alpha.md | 15 +++ .../filter/matrchers/createHasMatcher.test.ts | 109 ++++++++++++++++ .../src/filter/matrchers/createHasMatcher.ts | 19 ++- .../filter/matrchers/createIsMatcher.test.ts | 75 +++++++++++ .../src/filter/matrchers/createIsMatcher.ts | 19 ++- .../matrchers/createKindMatcher.test.ts | 46 +++++++ .../src/filter/matrchers/createKindMatcher.ts | 5 +- .../matrchers/createTypeMatcher.test.ts | 54 ++++++++ .../src/filter/matrchers/createTypeMatcher.ts | 5 +- .../src/filter/parseFilterExpression.test.ts | 122 ++++++++---------- .../src/filter/parseFilterExpression.ts | 52 +++++++- .../catalog/src/alpha/EntityOverviewPage.tsx | 28 ++-- 12 files changed, 449 insertions(+), 100 deletions(-) create mode 100644 plugins/catalog-common/src/filter/matrchers/createHasMatcher.test.ts create mode 100644 plugins/catalog-common/src/filter/matrchers/createIsMatcher.test.ts create mode 100644 plugins/catalog-common/src/filter/matrchers/createKindMatcher.test.ts create mode 100644 plugins/catalog-common/src/filter/matrchers/createTypeMatcher.test.ts diff --git a/plugins/catalog-common/api-report-alpha.md b/plugins/catalog-common/api-report-alpha.md index 573b35d3b3..bd36b499fe 100644 --- a/plugins/catalog-common/api-report-alpha.md +++ b/plugins/catalog-common/api-report-alpha.md @@ -42,6 +42,21 @@ export const catalogPermissions: ( // @alpha export function parseFilterExpression( expression: string, + options?: { + onParseError?: ( + error: Error, + context: { + expression: string; + }, + ) => void; + onEvaluateError?: ( + error: Error, + context: { + expression: string; + entity: Entity; + }, + ) => void; + }, ): (entity: Entity) => boolean; // @alpha diff --git a/plugins/catalog-common/src/filter/matrchers/createHasMatcher.test.ts b/plugins/catalog-common/src/filter/matrchers/createHasMatcher.test.ts new file mode 100644 index 0000000000..dbce5025b6 --- /dev/null +++ b/plugins/catalog-common/src/filter/matrchers/createHasMatcher.test.ts @@ -0,0 +1,109 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Entity } from '@backstage/catalog-model'; +import { createHasMatcher } from './createHasMatcher'; + +describe('createHasMatcher', () => { + const empty1 = { + metadata: {}, + } as unknown as Entity; + const empty2 = { + metadata: { + labels: {}, + annotations: {}, + links: [], + }, + } as unknown as Entity; + const labels = { + metadata: { + labels: { a: 'b' }, + }, + } as unknown as Entity; + const annotations = { + metadata: { + annotations: { a: 'b' }, + }, + } as unknown as Entity; + const links = { + metadata: { links: [{}] }, + } as unknown as Entity; + + const err = jest.fn(); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('supports valid parameters', () => { + expect(createHasMatcher(['labels'], err)(empty1)).toBe(false); + expect(createHasMatcher(['labels'], err)(empty2)).toBe(false); + expect(createHasMatcher(['labels'], err)(labels)).toBe(true); + + expect(createHasMatcher(['annotations'], err)(empty1)).toBe(false); + expect(createHasMatcher(['annotations'], err)(empty2)).toBe(false); + expect(createHasMatcher(['annotations'], err)(annotations)).toBe(true); + + expect(createHasMatcher(['links'], err)(empty1)).toBe(false); + expect(createHasMatcher(['links'], err)(empty2)).toBe(false); + expect(createHasMatcher(['links'], err)(links)).toBe(true); + + expect(err).not.toHaveBeenCalled(); + }); + + it('matches if ANY parameter matches', () => { + expect(createHasMatcher(['labels', 'links'], err)(empty1)).toBe(false); + expect(createHasMatcher(['labels', 'links'], err)(empty2)).toBe(false); + expect(createHasMatcher(['labels', 'links'], err)(labels)).toBe(true); + expect(createHasMatcher(['labels', 'links'], err)(links)).toBe(true); + expect(createHasMatcher(['labels', 'links'], err)(annotations)).toBe(false); + + expect(err).not.toHaveBeenCalled(); + }); + + it('emits errors properly, and skips over bad parameters', () => { + // throw if callback throws + expect(() => + createHasMatcher(['labels', 'bar'], e => { + throw e; + }), + ).toThrowErrorMatchingInlineSnapshot( + `"'bar' is not a valid parameter for 'has' filter expressions, expected one of 'labels','annotations','links'"`, + ); + expect(err).not.toHaveBeenCalled(); + + // continue if callback does not throw, and skip over the bad parameter + let matcher = createHasMatcher(['labels', 'foo', 'bar'], err); + expect(err).toHaveBeenCalledTimes(2); + expect(err).toHaveBeenCalledWith( + expect.objectContaining({ + message: `'foo' is not a valid parameter for 'has' filter expressions, expected one of 'labels','annotations','links'`, + }), + ); + expect(err).toHaveBeenCalledWith( + expect.objectContaining({ + message: `'bar' is not a valid parameter for 'has' filter expressions, expected one of 'labels','annotations','links'`, + }), + ); + expect(matcher(empty1)).toBe(false); + expect(matcher(labels)).toBe(true); + + // when no parameters at all match, just return true + matcher = createHasMatcher(['foo', 'bar'], err); + expect(matcher(empty1)).toBe(true); + expect(matcher(labels)).toBe(true); + }); +}); diff --git a/plugins/catalog-common/src/filter/matrchers/createHasMatcher.ts b/plugins/catalog-common/src/filter/matrchers/createHasMatcher.ts index 7b9eebba1c..f57316a65e 100644 --- a/plugins/catalog-common/src/filter/matrchers/createHasMatcher.ts +++ b/plugins/catalog-common/src/filter/matrchers/createHasMatcher.ts @@ -20,7 +20,10 @@ import { EntityMatcherFn } from './types'; /** * Matches on the non-empty presence of different parts of the entity */ -export function createHasMatcher(parameters: string[]): EntityMatcherFn { +export function createHasMatcher( + parameters: string[], + onParseError: (error: Error) => void, +): EntityMatcherFn { const allowedMatchers: Record = { labels: entity => { return Object.keys(entity.metadata.labels ?? {}).length > 0; @@ -33,16 +36,20 @@ export function createHasMatcher(parameters: string[]): EntityMatcherFn { }, }; - const matchers = parameters.map(parameter => { + const matchers = parameters.flatMap(parameter => { const matcher = allowedMatchers[parameter.toLocaleLowerCase('en-US')]; if (!matcher) { const known = Object.keys(allowedMatchers).map(m => `'${m}'`); - throw new InputError( - `'${parameter}' is not a valid parameter for 'has' filter expressions, expected one of ${known}`, + onParseError( + new InputError( + `'${parameter}' is not a valid parameter for 'has' filter expressions, expected one of ${known}`, + ), ); + return []; } - return matcher; + return [matcher]; }); - return entity => matchers.some(matcher => matcher(entity)); + return entity => + matchers.length ? matchers.some(matcher => matcher(entity)) : true; } diff --git a/plugins/catalog-common/src/filter/matrchers/createIsMatcher.test.ts b/plugins/catalog-common/src/filter/matrchers/createIsMatcher.test.ts new file mode 100644 index 0000000000..4cb3094d62 --- /dev/null +++ b/plugins/catalog-common/src/filter/matrchers/createIsMatcher.test.ts @@ -0,0 +1,75 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Entity } from '@backstage/catalog-model'; +import { createIsMatcher } from './createIsMatcher'; + +describe('createIsMatcher', () => { + const empty = { + metadata: {}, + } as unknown as Entity; + const orphan = { + metadata: { + annotations: { ['backstage.io/orphan']: 'true' }, + }, + } as unknown as Entity; + + const err = jest.fn(); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('supports valid parameters', () => { + expect(createIsMatcher(['orphan'], err)(empty)).toBe(false); + expect(createIsMatcher(['orphan'], err)(orphan)).toBe(true); + + expect(err).not.toHaveBeenCalled(); + }); + + it('emits errors properly, and skips over bad parameters', () => { + // throw if callback throws + expect(() => + createIsMatcher(['orphan', 'foo'], e => { + throw e; + }), + ).toThrowErrorMatchingInlineSnapshot( + `"'foo' is not a valid parameter for 'is' filter expressions, expected one of 'orphan'"`, + ); + expect(err).not.toHaveBeenCalled(); + + // continue if callback does not throw, and skip over the bad parameter + let matcher = createIsMatcher(['orphan', 'foo', 'bar'], err); + expect(err).toHaveBeenCalledTimes(2); + expect(err).toHaveBeenCalledWith( + expect.objectContaining({ + message: `'foo' is not a valid parameter for 'is' filter expressions, expected one of 'orphan'`, + }), + ); + expect(err).toHaveBeenCalledWith( + expect.objectContaining({ + message: `'bar' is not a valid parameter for 'is' filter expressions, expected one of 'orphan'`, + }), + ); + expect(matcher(empty)).toBe(false); + expect(matcher(orphan)).toBe(true); + + // when no parameters at all match, just return true + matcher = createIsMatcher(['foo', 'bar'], err); + expect(matcher(empty)).toBe(true); + expect(matcher(orphan)).toBe(true); + }); +}); diff --git a/plugins/catalog-common/src/filter/matrchers/createIsMatcher.ts b/plugins/catalog-common/src/filter/matrchers/createIsMatcher.ts index 3802d6dbce..30bfe4eb15 100644 --- a/plugins/catalog-common/src/filter/matrchers/createIsMatcher.ts +++ b/plugins/catalog-common/src/filter/matrchers/createIsMatcher.ts @@ -20,22 +20,29 @@ import { EntityMatcherFn } from './types'; /** * Matches on different semantic properties of the entity */ -export function createIsMatcher(parameters: string[]): EntityMatcherFn { +export function createIsMatcher( + parameters: string[], + onParseError: (error: Error) => void, +): EntityMatcherFn { const allowedMatchers: Record = { orphan: entity => Boolean(entity.metadata.annotations?.['backstage.io/orphan']), }; - const matchers = parameters.map(parameter => { + const matchers = parameters.flatMap(parameter => { const matcher = allowedMatchers[parameter.toLocaleLowerCase('en-US')]; if (!matcher) { const known = Object.keys(allowedMatchers).map(m => `'${m}'`); - throw new InputError( - `'${parameter}' is not a valid parameter for 'is' filter expressions, expected one of ${known}`, + onParseError( + new InputError( + `'${parameter}' is not a valid parameter for 'is' filter expressions, expected one of ${known}`, + ), ); + return []; } - return matcher; + return [matcher]; }); - return entity => matchers.some(matcher => matcher(entity)); + return entity => + matchers.length ? matchers.some(matcher => matcher(entity)) : true; } diff --git a/plugins/catalog-common/src/filter/matrchers/createKindMatcher.test.ts b/plugins/catalog-common/src/filter/matrchers/createKindMatcher.test.ts new file mode 100644 index 0000000000..f109acccd4 --- /dev/null +++ b/plugins/catalog-common/src/filter/matrchers/createKindMatcher.test.ts @@ -0,0 +1,46 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Entity } from '@backstage/catalog-model'; +import { createKindMatcher } from './createKindMatcher'; + +describe('createKindMatcher', () => { + const component = { kind: 'Component' } as unknown as Entity; + const user = { kind: 'User' } as unknown as Entity; + const resource = { kind: 'Resource' } as unknown as Entity; + + const err = jest.fn(); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('supports valid parameters', () => { + expect(createKindMatcher(['component'], err)(component)).toBe(true); + expect(createKindMatcher(['componenT'], err)(component)).toBe(true); + expect(createKindMatcher(['user'], err)(component)).toBe(false); + + expect(err).not.toHaveBeenCalled(); + }); + + it('matches if ANY parameter matches', () => { + expect(createKindMatcher(['user', 'component'], err)(user)).toBe(true); + expect(createKindMatcher(['user', 'component'], err)(component)).toBe(true); + expect(createKindMatcher(['user', 'component'], err)(resource)).toBe(false); + + expect(err).not.toHaveBeenCalled(); + }); +}); diff --git a/plugins/catalog-common/src/filter/matrchers/createKindMatcher.ts b/plugins/catalog-common/src/filter/matrchers/createKindMatcher.ts index 071746453e..4f7c475ebe 100644 --- a/plugins/catalog-common/src/filter/matrchers/createKindMatcher.ts +++ b/plugins/catalog-common/src/filter/matrchers/createKindMatcher.ts @@ -19,7 +19,10 @@ import { EntityMatcherFn } from './types'; /** * Matches on kind */ -export function createKindMatcher(parameters: string[]): EntityMatcherFn { +export function createKindMatcher( + parameters: string[], + _onParseError: (error: Error) => void, +): EntityMatcherFn { const items = parameters.map(p => p.toLocaleLowerCase('en-US')); return entity => items.includes(entity.kind.toLocaleLowerCase('en-US')); } diff --git a/plugins/catalog-common/src/filter/matrchers/createTypeMatcher.test.ts b/plugins/catalog-common/src/filter/matrchers/createTypeMatcher.test.ts new file mode 100644 index 0000000000..31c9af7e11 --- /dev/null +++ b/plugins/catalog-common/src/filter/matrchers/createTypeMatcher.test.ts @@ -0,0 +1,54 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Entity } from '@backstage/catalog-model'; +import { createTypeMatcher } from './createTypeMatcher'; + +describe('createTypeMatcher', () => { + const empty1 = {} as unknown as Entity; + const empty2 = { spec: {} } as unknown as Entity; + const service = { spec: { type: 'service' } } as unknown as Entity; + const website = { spec: { type: 'website' } } as unknown as Entity; + const pipeline = { spec: { type: 'pipeline' } } as unknown as Entity; + + const err = jest.fn(); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('supports valid parameters', () => { + expect(createTypeMatcher(['service'], err)(empty1)).toBe(false); + expect(createTypeMatcher(['service'], err)(empty2)).toBe(false); + + expect(createTypeMatcher(['service'], err)(service)).toBe(true); + expect(createTypeMatcher(['sErViCe'], err)(service)).toBe(true); + expect(createTypeMatcher(['service'], err)(service)).toBe(true); + expect(createTypeMatcher(['website'], err)(service)).toBe(false); + + expect(err).not.toHaveBeenCalled(); + }); + + it('matches if ANY parameter matches', () => { + expect(createTypeMatcher(['service', 'website'], err)(service)).toBe(true); + expect(createTypeMatcher(['service', 'website'], err)(website)).toBe(true); + expect(createTypeMatcher(['service', 'website'], err)(pipeline)).toBe( + false, + ); + + expect(err).not.toHaveBeenCalled(); + }); +}); diff --git a/plugins/catalog-common/src/filter/matrchers/createTypeMatcher.ts b/plugins/catalog-common/src/filter/matrchers/createTypeMatcher.ts index d0e0f39c98..31f7a5a461 100644 --- a/plugins/catalog-common/src/filter/matrchers/createTypeMatcher.ts +++ b/plugins/catalog-common/src/filter/matrchers/createTypeMatcher.ts @@ -19,7 +19,10 @@ import { EntityMatcherFn } from './types'; /** * Matches on spec.type */ -export function createTypeMatcher(parameters: string[]): EntityMatcherFn { +export function createTypeMatcher( + parameters: string[], + _onParseError: (error: Error) => void, +): EntityMatcherFn { const items = parameters.map(p => p.toLocaleLowerCase('en-US')); return entity => { const value = entity.spec?.type; diff --git a/plugins/catalog-common/src/filter/parseFilterExpression.test.ts b/plugins/catalog-common/src/filter/parseFilterExpression.test.ts index d8543c4e10..a53b84646e 100644 --- a/plugins/catalog-common/src/filter/parseFilterExpression.test.ts +++ b/plugins/catalog-common/src/filter/parseFilterExpression.test.ts @@ -21,19 +21,34 @@ import { } from './parseFilterExpression'; describe('parseFilterExpression', () => { + function run(expression: string) { + return parseFilterExpression(expression, { + onParseError(e: Error) { + throw e; + }, + }); + } + it('supports "kind" expressions', () => { const component = { kind: 'Component' } as unknown as Entity; const user = { kind: 'User' } as unknown as Entity; const resource = { kind: 'Resource' } as unknown as Entity; - expect(parseFilterExpression('kind:component')(component)).toBe(true); - expect(parseFilterExpression('kind:componenT')(component)).toBe(true); - expect(parseFilterExpression('kind:user')(component)).toBe(false); + expect(run('kind:user,component')(user)).toBe(true); + expect(run('kind:user,component')(component)).toBe(true); + expect(run('kind:user,component')(resource)).toBe(false); + }); - // match ANY of the parameters - expect(parseFilterExpression('kind:user,component')(user)).toBe(true); - expect(parseFilterExpression('kind:user,component')(component)).toBe(true); - expect(parseFilterExpression('kind:user,component')(resource)).toBe(false); + it('supports "type" expressions', () => { + const empty = {} as unknown as Entity; + const service = { spec: { type: 'service' } } as unknown as Entity; + const website = { spec: { type: 'website' } } as unknown as Entity; + const pipeline = { spec: { type: 'pipeline' } } as unknown as Entity; + + expect(run('type:service,website')(empty)).toBe(false); + expect(run('type:service,website')(service)).toBe(true); + expect(run('type:service,website')(website)).toBe(true); + expect(run('type:service,website')(pipeline)).toBe(false); }); it('supports "is" expressions', () => { @@ -46,123 +61,90 @@ describe('parseFilterExpression', () => { }, } as unknown as Entity; - expect(parseFilterExpression('is:orphan')(empty)).toBe(false); - expect(parseFilterExpression('is:orphan')(orphan)).toBe(true); + expect(run('is:orphan')(empty)).toBe(false); + expect(run('is:orphan')(orphan)).toBe(true); - expect(() => - parseFilterExpression('is:orphan,bar'), - ).toThrowErrorMatchingInlineSnapshot( + expect(() => run('is:orphan,bar')).toThrowErrorMatchingInlineSnapshot( `"'bar' is not a valid parameter for 'is' filter expressions, expected one of 'orphan'"`, ); }); it('supports "has" expressions', () => { - const empty1 = { + const empty = { metadata: {}, } as unknown as Entity; - const empty2 = { - metadata: { - labels: {}, - annotations: {}, - links: [], - }, - } as unknown as Entity; const labels = { - metadata: { - labels: { a: 'b' }, - }, + metadata: { labels: { a: 'b' } }, } as unknown as Entity; const annotations = { - metadata: { - annotations: { a: 'b' }, - }, + metadata: { annotations: { a: 'b' } }, } as unknown as Entity; const links = { metadata: { links: [{}] }, } as unknown as Entity; - expect(parseFilterExpression('has:labels')(empty1)).toBe(false); - expect(parseFilterExpression('has:labels')(empty2)).toBe(false); - expect(parseFilterExpression('has:labels')(labels)).toBe(true); + expect(run('has:labels,links')(empty)).toBe(false); + expect(run('has:labels,links')(labels)).toBe(true); + expect(run('has:labels,links')(links)).toBe(true); + expect(run('has:labels,links')(annotations)).toBe(false); - expect(parseFilterExpression('has:annotations')(empty1)).toBe(false); - expect(parseFilterExpression('has:annotations')(empty2)).toBe(false); - expect(parseFilterExpression('has:annotations')(annotations)).toBe(true); - - expect(parseFilterExpression('has:links')(empty1)).toBe(false); - expect(parseFilterExpression('has:links')(empty2)).toBe(false); - expect(parseFilterExpression('has:links')(links)).toBe(true); - - // match ANY of the parameters - expect(parseFilterExpression('has:labels,links')(empty1)).toBe(false); - expect(parseFilterExpression('has:labels,links')(empty2)).toBe(false); - expect(parseFilterExpression('has:labels,links')(labels)).toBe(true); - expect(parseFilterExpression('has:labels,links')(links)).toBe(true); - expect(parseFilterExpression('has:labels,links')(annotations)).toBe(false); - - expect(() => - parseFilterExpression('has:labels,bar'), - ).toThrowErrorMatchingInlineSnapshot( + expect(() => run('has:labels,bar')).toThrowErrorMatchingInlineSnapshot( `"'bar' is not a valid parameter for 'has' filter expressions, expected one of 'labels','annotations','links'"`, ); }); it('rejects unknown keys', () => { - expect(() => - parseFilterExpression('unknown:foo'), - ).toThrowErrorMatchingInlineSnapshot( + expect(() => run('unknown:foo')).toThrowErrorMatchingInlineSnapshot( `"'unknown' is not a valid filter expression key, expected one of 'kind','type','is','has'"`, ); }); it('rejects malformed inputs', () => { - expect(() => parseFilterExpression(':')).toThrowErrorMatchingInlineSnapshot( + expect(() => run(':')).toThrowErrorMatchingInlineSnapshot( `"':' is not a valid filter expression, expected 'key:parameter' form"`, ); - expect(() => - parseFilterExpression(':a'), - ).toThrowErrorMatchingInlineSnapshot( + expect(() => run(':a')).toThrowErrorMatchingInlineSnapshot( `"':a' is not a valid filter expression, expected 'key:parameter' form"`, ); - expect(() => - parseFilterExpression('a:'), - ).toThrowErrorMatchingInlineSnapshot( + expect(() => run('a:')).toThrowErrorMatchingInlineSnapshot( `"'a:' is not a valid filter expression, expected 'key:parameter' form"`, ); }); }); describe('splitFilterExpression', () => { + function run(expression: string) { + return splitFilterExpression(expression, e => { + throw e; + }); + } + it('properly splits into expression atoms', () => { - expect(splitFilterExpression('')).toEqual([]); - expect(splitFilterExpression(' ')).toEqual([]); - expect(splitFilterExpression('kind:component')).toEqual([ + expect(run('')).toEqual([]); + expect(run(' ')).toEqual([]); + expect(run('kind:component')).toEqual([ { key: 'kind', parameters: ['component'] }, ]); - expect(splitFilterExpression('kind:component,user')).toEqual([ + expect(run('kind:component,user')).toEqual([ { key: 'kind', parameters: ['component', 'user'] }, ]); - expect(splitFilterExpression('kind:component,user type:foo')).toEqual([ + expect(run('kind:component,user type:foo')).toEqual([ { key: 'kind', parameters: ['component', 'user'] }, { key: 'type', parameters: ['foo'] }, ]); - expect(splitFilterExpression('with:multiple:colons')).toEqual([ + expect(run('with:multiple:colons')).toEqual([ { key: 'with', parameters: ['multiple:colons'] }, ]); }); it('rejects malformed inputs', () => { - expect(() => splitFilterExpression(':')).toThrowErrorMatchingInlineSnapshot( + expect(() => run(':')).toThrowErrorMatchingInlineSnapshot( `"':' is not a valid filter expression, expected 'key:parameter' form"`, ); - expect(() => - splitFilterExpression(':a'), - ).toThrowErrorMatchingInlineSnapshot( + expect(() => run(':a')).toThrowErrorMatchingInlineSnapshot( `"':a' is not a valid filter expression, expected 'key:parameter' form"`, ); - expect(() => - splitFilterExpression('a:'), - ).toThrowErrorMatchingInlineSnapshot( + expect(() => run('a:')).toThrowErrorMatchingInlineSnapshot( `"'a:' is not a valid filter expression, expected 'key:parameter' form"`, ); }); diff --git a/plugins/catalog-common/src/filter/parseFilterExpression.ts b/plugins/catalog-common/src/filter/parseFilterExpression.ts index d2b46f582e..ffd25d75d3 100644 --- a/plugins/catalog-common/src/filter/parseFilterExpression.ts +++ b/plugins/catalog-common/src/filter/parseFilterExpression.ts @@ -24,7 +24,10 @@ import { createHasMatcher } from './matrchers/createHasMatcher'; const rootMatcherFactories: Record< string, - (parameters: string[]) => EntityMatcherFn + ( + parameters: string[], + onParseError: (error: Error) => void, + ) => EntityMatcherFn > = { kind: createKindMatcher, type: createTypeMatcher, @@ -43,11 +46,39 @@ const rootMatcherFactories: Record< * effectively an AND between the space separated parts, and an OR between comma * separated parameters. So the example filter string semantically means * "entities that are of either User or Group kind, and also are orphans". + * + * The `onParseError` callback is called whenever an error was encountered + * during initial parsing of the expression. If the callback throws, + * `parseFilterExpression` throws that same error. If the callback does not + * throw, the part of the input expression that had an error is ignored entirely + * and parsing continues. + * + * The `onEvaluateError` callback is called whenever an error was encountered + * during evaluation of the returned function. If the callback throws, the + * evaluation call throws the same error. If the callback does not throw, the + * whole evaluation returns false. */ export function parseFilterExpression( expression: string, + options?: { + onParseError?: ( + error: Error, + context: { + expression: string; + }, + ) => void; + onEvaluateError?: ( + error: Error, + context: { + expression: string; + entity: Entity; + }, + ) => void; + }, ): (entity: Entity) => boolean { - const parts = splitFilterExpression(expression); + const parts = splitFilterExpression(expression, e => + options?.onParseError?.(e, { expression }), + ); const matchers = parts.map(part => { const factory = rootMatcherFactories[part.key]; @@ -57,14 +88,17 @@ export function parseFilterExpression( `'${part.key}' is not a valid filter expression key, expected one of ${known}`, ); } - return factory(part.parameters); + return factory(part.parameters, e => + options?.onParseError?.(e, { expression }), + ); }); return (entity: Entity) => { return matchers.every(matcher => { try { return matcher(entity); - } catch { + } catch (e) { + options?.onEvaluateError?.(e, { expression, entity }); return false; } }); @@ -73,6 +107,7 @@ export function parseFilterExpression( export function splitFilterExpression( expression: string, + onParseError: (error: Error) => void, ): Array<{ key: string; parameters: string[] }> { const words = expression .split(' ') @@ -84,13 +119,16 @@ export function splitFilterExpression( for (const word of words) { const match = word.match(/^([^:]+):(.+)$/); if (!match) { - throw new InputError( - `'${word}' is not a valid filter expression, expected 'key:parameter' form`, + onParseError( + new InputError( + `'${word}' is not a valid filter expression, expected 'key:parameter' form`, + ), ); + continue; } const key = match[1]; - const parameters = match[2].split(','); + const parameters = match[2].split(',').filter(Boolean); // silently ignore double commas result.push({ key, parameters }); } diff --git a/plugins/catalog/src/alpha/EntityOverviewPage.tsx b/plugins/catalog/src/alpha/EntityOverviewPage.tsx index 02ec044975..5ef6b9a2e5 100644 --- a/plugins/catalog/src/alpha/EntityOverviewPage.tsx +++ b/plugins/catalog/src/alpha/EntityOverviewPage.tsx @@ -40,10 +40,21 @@ function CardWrapper(props: { } else if (typeof filter === 'function') { return subject => filter(subject); } - return parseFilterExpression(filter); + return parseFilterExpression(filter, { + onParseError(_error) { + // ignore silently + }, + onEvaluateError(_error) { + // ignore silently + }, + }); }, [filter]); - return filterFn(entity) ? <>{element} : null; + return filterFn(entity) ? ( + + {element} + + ) : null; } export function EntityOverviewPage(props: EntityOverviewPageProps) { @@ -51,13 +62,12 @@ export function EntityOverviewPage(props: EntityOverviewPageProps) { return ( {props.cards.map((card, index) => ( - - - + ))} ); From 3bb23d78f79f5ee94d50d2251a64381dc624daa0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Thu, 23 Nov 2023 14:59:23 +0100 Subject: [PATCH 176/261] Update .changeset/stale-jokes-hunt.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Patrik Oldsberg Signed-off-by: Fredrik Adelöw --- .changeset/stale-jokes-hunt.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/stale-jokes-hunt.md b/.changeset/stale-jokes-hunt.md index cbea2dd229..1e78a3a446 100644 --- a/.changeset/stale-jokes-hunt.md +++ b/.changeset/stale-jokes-hunt.md @@ -2,4 +2,4 @@ '@backstage/plugin-catalog-common': minor --- -Added a `parseFilterExpression` function to interpret visibility filters +Added a `parseFilterExpression` function to interpret visibility filters, exported from the `/alpha` sub-path. From c2dac8cc1ed41964fd991e5eefb7bec8928c59d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Thu, 23 Nov 2023 14:59:39 +0100 Subject: [PATCH 177/261] Update .changeset/thick-snails-travel.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Patrik Oldsberg Signed-off-by: Fredrik Adelöw --- .changeset/thick-snails-travel.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/thick-snails-travel.md b/.changeset/thick-snails-travel.md index af27df78e5..bfd14d55e1 100644 --- a/.changeset/thick-snails-travel.md +++ b/.changeset/thick-snails-travel.md @@ -2,4 +2,4 @@ '@backstage/plugin-catalog': minor --- -Properly support both function- and string-form visibility filter expressions +Properly support both function- and string-form visibility filter expressions in the new extensions exported via `/alpha`. From 423e33d81ffcd9bf514f2e09bf28387209cc107c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Thu, 23 Nov 2023 15:56:20 +0100 Subject: [PATCH 178/261] move over to catalog and make internal, return errors in array MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .changeset/stale-jokes-hunt.md | 5 -- packages/app-next/app-config.yaml | 2 +- plugins/catalog-common/api-report-alpha.md | 21 ------ plugins/catalog-common/package.json | 1 - plugins/catalog-common/src/alpha.ts | 1 - plugins/catalog-common/src/filter/index.ts | 17 ----- .../catalog/src/alpha/EntityOverviewPage.tsx | 26 ++++--- .../filter/matrchers/createHasMatcher.test.ts | 0 .../filter/matrchers/createHasMatcher.ts | 0 .../filter/matrchers/createIsMatcher.test.ts | 0 .../filter/matrchers/createIsMatcher.ts | 0 .../matrchers/createKindMatcher.test.ts | 0 .../filter/matrchers/createKindMatcher.ts | 0 .../matrchers/createTypeMatcher.test.ts | 0 .../filter/matrchers/createTypeMatcher.ts | 0 .../src/alpha}/filter/matrchers/types.ts | 0 .../filter/parseFilterExpression.test.ts | 10 +-- .../alpha}/filter/parseFilterExpression.ts | 67 ++++++++----------- yarn.lock | 1 - 19 files changed, 51 insertions(+), 100 deletions(-) delete mode 100644 .changeset/stale-jokes-hunt.md delete mode 100644 plugins/catalog-common/src/filter/index.ts rename plugins/{catalog-common/src => catalog/src/alpha}/filter/matrchers/createHasMatcher.test.ts (100%) rename plugins/{catalog-common/src => catalog/src/alpha}/filter/matrchers/createHasMatcher.ts (100%) rename plugins/{catalog-common/src => catalog/src/alpha}/filter/matrchers/createIsMatcher.test.ts (100%) rename plugins/{catalog-common/src => catalog/src/alpha}/filter/matrchers/createIsMatcher.ts (100%) rename plugins/{catalog-common/src => catalog/src/alpha}/filter/matrchers/createKindMatcher.test.ts (100%) rename plugins/{catalog-common/src => catalog/src/alpha}/filter/matrchers/createKindMatcher.ts (100%) rename plugins/{catalog-common/src => catalog/src/alpha}/filter/matrchers/createTypeMatcher.test.ts (100%) rename plugins/{catalog-common/src => catalog/src/alpha}/filter/matrchers/createTypeMatcher.ts (100%) rename plugins/{catalog-common/src => catalog/src/alpha}/filter/matrchers/types.ts (100%) rename plugins/{catalog-common/src => catalog/src/alpha}/filter/parseFilterExpression.test.ts (96%) rename plugins/{catalog-common/src => catalog/src/alpha}/filter/parseFilterExpression.ts (66%) diff --git a/.changeset/stale-jokes-hunt.md b/.changeset/stale-jokes-hunt.md deleted file mode 100644 index 1e78a3a446..0000000000 --- a/.changeset/stale-jokes-hunt.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-common': minor ---- - -Added a `parseFilterExpression` function to interpret visibility filters, exported from the `/alpha` sub-path. diff --git a/packages/app-next/app-config.yaml b/packages/app-next/app-config.yaml index a90fe630b5..34cd78d480 100644 --- a/packages/app-next/app-config.yaml +++ b/packages/app-next/app-config.yaml @@ -14,7 +14,7 @@ app: - entity.cards.labels - entity.cards.links: config: - filter: kind:component + filter: kind:component has:links # Entity page content - entity.content.techdocs diff --git a/plugins/catalog-common/api-report-alpha.md b/plugins/catalog-common/api-report-alpha.md index bd36b499fe..12e0806a9c 100644 --- a/plugins/catalog-common/api-report-alpha.md +++ b/plugins/catalog-common/api-report-alpha.md @@ -4,7 +4,6 @@ ```ts import { BasicPermission } from '@backstage/plugin-permission-common'; -import { Entity } from '@backstage/catalog-model'; import { ResourcePermission } from '@backstage/plugin-permission-common'; // @alpha @@ -39,26 +38,6 @@ export const catalogPermissions: ( | ResourcePermission<'catalog-entity'> )[]; -// @alpha -export function parseFilterExpression( - expression: string, - options?: { - onParseError?: ( - error: Error, - context: { - expression: string; - }, - ) => void; - onEvaluateError?: ( - error: Error, - context: { - expression: string; - entity: Entity; - }, - ) => void; - }, -): (entity: Entity) => boolean; - // @alpha export const RESOURCE_TYPE_CATALOG_ENTITY = 'catalog-entity'; diff --git a/plugins/catalog-common/package.json b/plugins/catalog-common/package.json index ac21b76c2a..45720ee32a 100644 --- a/plugins/catalog-common/package.json +++ b/plugins/catalog-common/package.json @@ -46,7 +46,6 @@ }, "dependencies": { "@backstage/catalog-model": "workspace:^", - "@backstage/errors": "workspace:^", "@backstage/plugin-permission-common": "workspace:^", "@backstage/plugin-search-common": "workspace:^" }, diff --git a/plugins/catalog-common/src/alpha.ts b/plugins/catalog-common/src/alpha.ts index 015769c8a7..2dfc028332 100644 --- a/plugins/catalog-common/src/alpha.ts +++ b/plugins/catalog-common/src/alpha.ts @@ -26,4 +26,3 @@ export { catalogPermissions, } from './permissions'; export type { CatalogEntityPermission } from './permissions'; -export { parseFilterExpression } from './filter'; diff --git a/plugins/catalog-common/src/filter/index.ts b/plugins/catalog-common/src/filter/index.ts deleted file mode 100644 index c5ad803f4c..0000000000 --- a/plugins/catalog-common/src/filter/index.ts +++ /dev/null @@ -1,17 +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. - */ - -export { parseFilterExpression } from './parseFilterExpression'; diff --git a/plugins/catalog/src/alpha/EntityOverviewPage.tsx b/plugins/catalog/src/alpha/EntityOverviewPage.tsx index 5ef6b9a2e5..a71e789522 100644 --- a/plugins/catalog/src/alpha/EntityOverviewPage.tsx +++ b/plugins/catalog/src/alpha/EntityOverviewPage.tsx @@ -15,10 +15,10 @@ */ import { Entity } from '@backstage/catalog-model'; -import { parseFilterExpression } from '@backstage/plugin-catalog-common/alpha'; import { useEntity } from '@backstage/plugin-catalog-react'; import Grid from '@material-ui/core/Grid'; import React, { useMemo } from 'react'; +import { parseFilterExpression } from './filter/parseFilterExpression'; interface EntityOverviewPageProps { cards: Array<{ @@ -27,6 +27,9 @@ interface EntityOverviewPageProps { }>; } +// Keeps track of what filter expression strings that we've emitted warnings for so far +const seenExpressionStrings = new Set(); + function CardWrapper(props: { entity: Entity; element: React.JSX.Element; @@ -40,14 +43,19 @@ function CardWrapper(props: { } else if (typeof filter === 'function') { return subject => filter(subject); } - return parseFilterExpression(filter, { - onParseError(_error) { - // ignore silently - }, - onEvaluateError(_error) { - // ignore silently - }, - }); + const result = parseFilterExpression(filter); + if ( + result.expressionParseErrors.length && + !seenExpressionStrings.has(filter) + ) { + // eslint-disable-next-line no-console + console.warn( + `Error(s) in entity filter expression '${filter}'`, + result.expressionParseErrors, + ); + seenExpressionStrings.add(filter); + } + return result.filterFn; }, [filter]); return filterFn(entity) ? ( diff --git a/plugins/catalog-common/src/filter/matrchers/createHasMatcher.test.ts b/plugins/catalog/src/alpha/filter/matrchers/createHasMatcher.test.ts similarity index 100% rename from plugins/catalog-common/src/filter/matrchers/createHasMatcher.test.ts rename to plugins/catalog/src/alpha/filter/matrchers/createHasMatcher.test.ts diff --git a/plugins/catalog-common/src/filter/matrchers/createHasMatcher.ts b/plugins/catalog/src/alpha/filter/matrchers/createHasMatcher.ts similarity index 100% rename from plugins/catalog-common/src/filter/matrchers/createHasMatcher.ts rename to plugins/catalog/src/alpha/filter/matrchers/createHasMatcher.ts diff --git a/plugins/catalog-common/src/filter/matrchers/createIsMatcher.test.ts b/plugins/catalog/src/alpha/filter/matrchers/createIsMatcher.test.ts similarity index 100% rename from plugins/catalog-common/src/filter/matrchers/createIsMatcher.test.ts rename to plugins/catalog/src/alpha/filter/matrchers/createIsMatcher.test.ts diff --git a/plugins/catalog-common/src/filter/matrchers/createIsMatcher.ts b/plugins/catalog/src/alpha/filter/matrchers/createIsMatcher.ts similarity index 100% rename from plugins/catalog-common/src/filter/matrchers/createIsMatcher.ts rename to plugins/catalog/src/alpha/filter/matrchers/createIsMatcher.ts diff --git a/plugins/catalog-common/src/filter/matrchers/createKindMatcher.test.ts b/plugins/catalog/src/alpha/filter/matrchers/createKindMatcher.test.ts similarity index 100% rename from plugins/catalog-common/src/filter/matrchers/createKindMatcher.test.ts rename to plugins/catalog/src/alpha/filter/matrchers/createKindMatcher.test.ts diff --git a/plugins/catalog-common/src/filter/matrchers/createKindMatcher.ts b/plugins/catalog/src/alpha/filter/matrchers/createKindMatcher.ts similarity index 100% rename from plugins/catalog-common/src/filter/matrchers/createKindMatcher.ts rename to plugins/catalog/src/alpha/filter/matrchers/createKindMatcher.ts diff --git a/plugins/catalog-common/src/filter/matrchers/createTypeMatcher.test.ts b/plugins/catalog/src/alpha/filter/matrchers/createTypeMatcher.test.ts similarity index 100% rename from plugins/catalog-common/src/filter/matrchers/createTypeMatcher.test.ts rename to plugins/catalog/src/alpha/filter/matrchers/createTypeMatcher.test.ts diff --git a/plugins/catalog-common/src/filter/matrchers/createTypeMatcher.ts b/plugins/catalog/src/alpha/filter/matrchers/createTypeMatcher.ts similarity index 100% rename from plugins/catalog-common/src/filter/matrchers/createTypeMatcher.ts rename to plugins/catalog/src/alpha/filter/matrchers/createTypeMatcher.ts diff --git a/plugins/catalog-common/src/filter/matrchers/types.ts b/plugins/catalog/src/alpha/filter/matrchers/types.ts similarity index 100% rename from plugins/catalog-common/src/filter/matrchers/types.ts rename to plugins/catalog/src/alpha/filter/matrchers/types.ts diff --git a/plugins/catalog-common/src/filter/parseFilterExpression.test.ts b/plugins/catalog/src/alpha/filter/parseFilterExpression.test.ts similarity index 96% rename from plugins/catalog-common/src/filter/parseFilterExpression.test.ts rename to plugins/catalog/src/alpha/filter/parseFilterExpression.test.ts index a53b84646e..d1335524b4 100644 --- a/plugins/catalog-common/src/filter/parseFilterExpression.test.ts +++ b/plugins/catalog/src/alpha/filter/parseFilterExpression.test.ts @@ -22,11 +22,11 @@ import { describe('parseFilterExpression', () => { function run(expression: string) { - return parseFilterExpression(expression, { - onParseError(e: Error) { - throw e; - }, - }); + const result = parseFilterExpression(expression); + if (result.expressionParseErrors.length) { + throw result.expressionParseErrors[0]; + } + return result.filterFn; } it('supports "kind" expressions', () => { diff --git a/plugins/catalog-common/src/filter/parseFilterExpression.ts b/plugins/catalog/src/alpha/filter/parseFilterExpression.ts similarity index 66% rename from plugins/catalog-common/src/filter/parseFilterExpression.ts rename to plugins/catalog/src/alpha/filter/parseFilterExpression.ts index ffd25d75d3..a4c17cb8da 100644 --- a/plugins/catalog-common/src/filter/parseFilterExpression.ts +++ b/plugins/catalog/src/alpha/filter/parseFilterExpression.ts @@ -39,7 +39,6 @@ const rootMatcherFactories: Record< * Parses a filter expression that decides whether to render an entity component * or not. Returns a function that matches entities based on that expression. * - * @alpha * @remarks * * Filter strings are on the form `kind:user,group is:orphan`. There's @@ -47,61 +46,51 @@ const rootMatcherFactories: Record< * separated parameters. So the example filter string semantically means * "entities that are of either User or Group kind, and also are orphans". * - * The `onParseError` callback is called whenever an error was encountered - * during initial parsing of the expression. If the callback throws, - * `parseFilterExpression` throws that same error. If the callback does not - * throw, the part of the input expression that had an error is ignored entirely - * and parsing continues. - * - * The `onEvaluateError` callback is called whenever an error was encountered - * during evaluation of the returned function. If the callback throws, the - * evaluation call throws the same error. If the callback does not throw, the - * whole evaluation returns false. + * The `expressionParseErrors` array contains any errors that were encountered + * during initial parsing of the expression. Note that the parts of the input + * expression that had errors are ignored entirely and parsing continues as if + * they didn't exist. */ -export function parseFilterExpression( - expression: string, - options?: { - onParseError?: ( - error: Error, - context: { - expression: string; - }, - ) => void; - onEvaluateError?: ( - error: Error, - context: { - expression: string; - entity: Entity; - }, - ) => void; - }, -): (entity: Entity) => boolean { +export function parseFilterExpression(expression: string): { + filterFn: (entity: Entity) => boolean; + expressionParseErrors: Error[]; +} { + const expressionParseErrors: Error[] = []; + const parts = splitFilterExpression(expression, e => - options?.onParseError?.(e, { expression }), + expressionParseErrors.push(e), ); - const matchers = parts.map(part => { + const matchers = parts.flatMap(part => { const factory = rootMatcherFactories[part.key]; if (!factory) { const known = Object.keys(rootMatcherFactories).map(m => `'${m}'`); - throw new InputError( - `'${part.key}' is not a valid filter expression key, expected one of ${known}`, + expressionParseErrors.push( + new InputError( + `'${part.key}' is not a valid filter expression key, expected one of ${known}`, + ), ); + return []; } - return factory(part.parameters, e => - options?.onParseError?.(e, { expression }), + + const matcher = factory(part.parameters, e => + expressionParseErrors.push(e), ); + return [matcher]; }); - return (entity: Entity) => { - return matchers.every(matcher => { + const filterFn = (entity: Entity) => + matchers.every(matcher => { try { return matcher(entity); - } catch (e) { - options?.onEvaluateError?.(e, { expression, entity }); + } catch { return false; } }); + + return { + filterFn, + expressionParseErrors, }; } diff --git a/yarn.lock b/yarn.lock index 90be768746..2399f06ac5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5831,7 +5831,6 @@ __metadata: dependencies: "@backstage/catalog-model": "workspace:^" "@backstage/cli": "workspace:^" - "@backstage/errors": "workspace:^" "@backstage/plugin-permission-common": "workspace:^" "@backstage/plugin-search-common": "workspace:^" languageName: unknown From 969d028b93eb72dc70a707df8f945da0f18c9ac4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Thu, 23 Nov 2023 16:36:16 +0100 Subject: [PATCH 179/261] split apart into two filter refs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- plugins/catalog-react/api-report-alpha.md | 18 +++- plugins/catalog-react/src/alpha.tsx | 55 ++++++++++-- .../catalog/src/alpha/EntityOverviewPage.tsx | 88 ++++++++++++------- plugins/catalog/src/alpha/entityContents.tsx | 6 +- 4 files changed, 121 insertions(+), 46 deletions(-) diff --git a/plugins/catalog-react/api-report-alpha.md b/plugins/catalog-react/api-report-alpha.md index e284f80b8e..913055f8b0 100644 --- a/plugins/catalog-react/api-report-alpha.md +++ b/plugins/catalog-react/api-report-alpha.md @@ -24,7 +24,9 @@ export function createEntityCardExtension< }; disabled?: boolean; inputs?: TInputs; - filter?: typeof entityFilterExtensionDataRef.T; + filter?: + | typeof entityFilterFunctionExtensionDataRef.T + | typeof entityFilterExpressionExtensionDataRef.T; loader: (options: { inputs: Expand>; }) => Promise; @@ -46,7 +48,9 @@ export function createEntityContentExtension< routeRef?: RouteRef; defaultPath: string; defaultTitle: string; - filter?: typeof entityFilterExtensionDataRef.T; + filter?: + | typeof entityFilterFunctionExtensionDataRef.T + | typeof entityFilterExpressionExtensionDataRef.T; loader: (options: { inputs: Expand>; }) => Promise; @@ -63,8 +67,14 @@ export const entityContentTitleExtensionDataRef: ConfigurableExtensionDataRef< >; // @alpha (undocumented) -export const entityFilterExtensionDataRef: ConfigurableExtensionDataRef< - string | ((entity: Entity) => boolean), +export const entityFilterExpressionExtensionDataRef: ConfigurableExtensionDataRef< + string, + {} +>; + +// @alpha (undocumented) +export const entityFilterFunctionExtensionDataRef: ConfigurableExtensionDataRef< + (entity: Entity) => boolean, {} >; diff --git a/plugins/catalog-react/src/alpha.tsx b/plugins/catalog-react/src/alpha.tsx index 604c769fe5..43b7156b34 100644 --- a/plugins/catalog-react/src/alpha.tsx +++ b/plugins/catalog-react/src/alpha.tsx @@ -37,9 +37,13 @@ export const entityContentTitleExtensionDataRef = createExtensionDataRef('plugin.catalog.entity.content.title'); /** @alpha */ -export const entityFilterExtensionDataRef = createExtensionDataRef< - string | ((entity: Entity) => boolean) ->('plugin.catalog.entity.filter'); +export const entityFilterFunctionExtensionDataRef = createExtensionDataRef< + (entity: Entity) => boolean +>('plugin.catalog.entity.filter.fn'); + +/** @alpha */ +export const entityFilterExpressionExtensionDataRef = + createExtensionDataRef('plugin.catalog.entity.filter.expression'); // TODO: Figure out how to merge with provided config schema /** @alpha */ @@ -50,7 +54,9 @@ export function createEntityCardExtension< attachTo?: { id: string; input: string }; disabled?: boolean; inputs?: TInputs; - filter?: typeof entityFilterExtensionDataRef.T; + filter?: + | typeof entityFilterFunctionExtensionDataRef.T + | typeof entityFilterExpressionExtensionDataRef.T; loader: (options: { inputs: Expand>; }) => Promise; @@ -66,7 +72,8 @@ export function createEntityCardExtension< disabled: options.disabled ?? true, output: { element: coreExtensionData.reactElement, - filter: entityFilterExtensionDataRef.optional(), + filterFunction: entityFilterFunctionExtensionDataRef.optional(), + filterExpression: entityFilterExpressionExtensionDataRef.optional(), }, inputs: options.inputs, configSchema: createSchemaFromZod(z => @@ -87,7 +94,7 @@ export function createEntityCardExtension< ), - filter: config.filter ?? options.filter, + ...mergeFilters({ config, options }), }; }, }); @@ -104,7 +111,9 @@ export function createEntityContentExtension< routeRef?: RouteRef; defaultPath: string; defaultTitle: string; - filter?: typeof entityFilterExtensionDataRef.T; + filter?: + | typeof entityFilterFunctionExtensionDataRef.T + | typeof entityFilterExpressionExtensionDataRef.T; loader: (options: { inputs: Expand>; }) => Promise; @@ -123,7 +132,8 @@ export function createEntityContentExtension< path: coreExtensionData.routePath, routeRef: coreExtensionData.routeRef.optional(), title: entityContentTitleExtensionDataRef, - filter: entityFilterExtensionDataRef.optional(), + filterFunction: entityFilterFunctionExtensionDataRef.optional(), + filterExpression: entityFilterExpressionExtensionDataRef.optional(), }, inputs: options.inputs, configSchema: createSchemaFromZod(z => @@ -149,8 +159,35 @@ export function createEntityContentExtension< ), - filter: config.filter ?? options.filter, + ...mergeFilters({ config, options }), }; }, }); } + +/** + * Decides what filter outputs to produce, given some options and config + */ +function mergeFilters(inputs: { + options: { + filter?: + | typeof entityFilterFunctionExtensionDataRef.T + | typeof entityFilterExpressionExtensionDataRef.T; + }; + config: { + filter?: string; + }; +}): { + filterFunction?: typeof entityFilterFunctionExtensionDataRef.T; + filterExpression?: typeof entityFilterExpressionExtensionDataRef.T; +} { + const { options, config } = inputs; + if (config.filter) { + return { filterExpression: config.filter }; + } else if (typeof options.filter === 'string') { + return { filterExpression: options.filter }; + } else if (typeof options.filter === 'function') { + return { filterFunction: options.filter }; + } + return {}; +} diff --git a/plugins/catalog/src/alpha/EntityOverviewPage.tsx b/plugins/catalog/src/alpha/EntityOverviewPage.tsx index a71e789522..932e13d962 100644 --- a/plugins/catalog/src/alpha/EntityOverviewPage.tsx +++ b/plugins/catalog/src/alpha/EntityOverviewPage.tsx @@ -23,40 +23,71 @@ import { parseFilterExpression } from './filter/parseFilterExpression'; interface EntityOverviewPageProps { cards: Array<{ element: React.JSX.Element; - filter?: string | ((entity: Entity) => boolean); + filterFunction?: (entity: Entity) => boolean; + filterExpression?: string; }>; } -// Keeps track of what filter expression strings that we've emitted warnings for so far -const seenExpressionStrings = new Set(); +// Keeps track of what filter expression strings that we've seen duplicates of +// with functions, or which emitted parsing errors for so far +const seenParseErrorExpressionStrings = new Set(); +const seenDuplicateExpressionStrings = new Set(); +// Given an optional filter function and an optional filter expression, make +// sure that at most one of them was given, and return a filter function that +// does the right thing. +function buildFilterFn( + filterFunction?: (entity: Entity) => boolean, + filterExpression?: string, +): (entity: Entity) => boolean { + if ( + filterFunction && + filterExpression && + !seenDuplicateExpressionStrings.has(filterExpression) + ) { + // eslint-disable-next-line no-console + console.warn( + `Duplicate entity filter methods found, both '${filterExpression}' as well as a callback function, which is not permitted - using the callback`, + ); + seenDuplicateExpressionStrings.add(filterExpression); + } + + const filter = filterFunction || filterExpression; + if (!filter) { + return () => true; + } else if (typeof filter === 'function') { + return subject => filter(subject); + } + + const result = parseFilterExpression(filter); + if ( + result.expressionParseErrors.length && + !seenParseErrorExpressionStrings.has(filter) + ) { + // eslint-disable-next-line no-console + console.warn( + `Error(s) in entity filter expression '${filter}'`, + result.expressionParseErrors, + ); + seenParseErrorExpressionStrings.add(filter); + } + + return result.filterFn; +} + +// Handles the memoized parsing of filter expressions for each card function CardWrapper(props: { entity: Entity; element: React.JSX.Element; - filter?: string | ((entity: Entity) => boolean); + filterFunction?: (entity: Entity) => boolean; + filterExpression?: string; }) { - const { entity, element, filter } = props; + const { entity, element, filterFunction, filterExpression } = props; - const filterFn = useMemo<(subject: Entity) => boolean>(() => { - if (!filter) { - return () => true; - } else if (typeof filter === 'function') { - return subject => filter(subject); - } - const result = parseFilterExpression(filter); - if ( - result.expressionParseErrors.length && - !seenExpressionStrings.has(filter) - ) { - // eslint-disable-next-line no-console - console.warn( - `Error(s) in entity filter expression '${filter}'`, - result.expressionParseErrors, - ); - seenExpressionStrings.add(filter); - } - return result.filterFn; - }, [filter]); + const filterFn = useMemo( + () => buildFilterFn(filterFunction, filterExpression), + [filterFunction, filterExpression], + ); return filterFn(entity) ? ( @@ -70,12 +101,7 @@ export function EntityOverviewPage(props: EntityOverviewPageProps) { return ( {props.cards.map((card, index) => ( - + ))} ); diff --git a/plugins/catalog/src/alpha/entityContents.tsx b/plugins/catalog/src/alpha/entityContents.tsx index 0bbee9bb7d..e280326b02 100644 --- a/plugins/catalog/src/alpha/entityContents.tsx +++ b/plugins/catalog/src/alpha/entityContents.tsx @@ -21,7 +21,8 @@ import { } from '@backstage/frontend-plugin-api'; import { createEntityContentExtension, - entityFilterExtensionDataRef, + entityFilterFunctionExtensionDataRef, + entityFilterExpressionExtensionDataRef, } from '@backstage/plugin-catalog-react/alpha'; export const OverviewEntityContent = createEntityContentExtension({ @@ -32,7 +33,8 @@ export const OverviewEntityContent = createEntityContentExtension({ inputs: { cards: createExtensionInput({ element: coreExtensionData.reactElement, - filter: entityFilterExtensionDataRef.optional(), + filterFunction: entityFilterFunctionExtensionDataRef.optional(), + filterExpression: entityFilterExpressionExtensionDataRef.optional(), }), }, loader: async ({ inputs }) => From a52d98820162176bb3f2d53347d6b501766274c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Thu, 23 Nov 2023 16:39:41 +0100 Subject: [PATCH 180/261] moved out the matchers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .../filter/matrchers/createHasMatcher.ts | 24 +++++++++---------- .../alpha/filter/matrchers/createIsMatcher.ts | 10 ++++---- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/plugins/catalog/src/alpha/filter/matrchers/createHasMatcher.ts b/plugins/catalog/src/alpha/filter/matrchers/createHasMatcher.ts index f57316a65e..35a3f7baf7 100644 --- a/plugins/catalog/src/alpha/filter/matrchers/createHasMatcher.ts +++ b/plugins/catalog/src/alpha/filter/matrchers/createHasMatcher.ts @@ -17,6 +17,18 @@ import { InputError } from '@backstage/errors'; import { EntityMatcherFn } from './types'; +const allowedMatchers: Record = { + labels: entity => { + return Object.keys(entity.metadata.labels ?? {}).length > 0; + }, + annotations: entity => { + return Object.keys(entity.metadata.annotations ?? {}).length > 0; + }, + links: entity => { + return (entity.metadata.links ?? []).length > 0; + }, +}; + /** * Matches on the non-empty presence of different parts of the entity */ @@ -24,18 +36,6 @@ export function createHasMatcher( parameters: string[], onParseError: (error: Error) => void, ): EntityMatcherFn { - const allowedMatchers: Record = { - labels: entity => { - return Object.keys(entity.metadata.labels ?? {}).length > 0; - }, - annotations: entity => { - return Object.keys(entity.metadata.annotations ?? {}).length > 0; - }, - links: entity => { - return (entity.metadata.links ?? []).length > 0; - }, - }; - const matchers = parameters.flatMap(parameter => { const matcher = allowedMatchers[parameter.toLocaleLowerCase('en-US')]; if (!matcher) { diff --git a/plugins/catalog/src/alpha/filter/matrchers/createIsMatcher.ts b/plugins/catalog/src/alpha/filter/matrchers/createIsMatcher.ts index 30bfe4eb15..49a54349d1 100644 --- a/plugins/catalog/src/alpha/filter/matrchers/createIsMatcher.ts +++ b/plugins/catalog/src/alpha/filter/matrchers/createIsMatcher.ts @@ -17,6 +17,11 @@ import { InputError } from '@backstage/errors'; import { EntityMatcherFn } from './types'; +const allowedMatchers: Record = { + orphan: entity => + Boolean(entity.metadata.annotations?.['backstage.io/orphan']), +}; + /** * Matches on different semantic properties of the entity */ @@ -24,11 +29,6 @@ export function createIsMatcher( parameters: string[], onParseError: (error: Error) => void, ): EntityMatcherFn { - const allowedMatchers: Record = { - orphan: entity => - Boolean(entity.metadata.annotations?.['backstage.io/orphan']), - }; - const matchers = parameters.flatMap(parameter => { const matcher = allowedMatchers[parameter.toLocaleLowerCase('en-US')]; if (!matcher) { From 645c64332ab9f27d2c351762fb6d58849a7c40e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Fri, 24 Nov 2023 09:41:59 +0100 Subject: [PATCH 181/261] removed has:annotations since that makes little sense - they are always there MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .../filter/matrchers/createHasMatcher.test.ts | 17 +++-------------- .../alpha/filter/matrchers/createHasMatcher.ts | 3 --- .../alpha/filter/parseFilterExpression.test.ts | 2 +- 3 files changed, 4 insertions(+), 18 deletions(-) diff --git a/plugins/catalog/src/alpha/filter/matrchers/createHasMatcher.test.ts b/plugins/catalog/src/alpha/filter/matrchers/createHasMatcher.test.ts index dbce5025b6..53524d228e 100644 --- a/plugins/catalog/src/alpha/filter/matrchers/createHasMatcher.test.ts +++ b/plugins/catalog/src/alpha/filter/matrchers/createHasMatcher.test.ts @@ -24,7 +24,6 @@ describe('createHasMatcher', () => { const empty2 = { metadata: { labels: {}, - annotations: {}, links: [], }, } as unknown as Entity; @@ -33,11 +32,6 @@ describe('createHasMatcher', () => { labels: { a: 'b' }, }, } as unknown as Entity; - const annotations = { - metadata: { - annotations: { a: 'b' }, - }, - } as unknown as Entity; const links = { metadata: { links: [{}] }, } as unknown as Entity; @@ -53,10 +47,6 @@ describe('createHasMatcher', () => { expect(createHasMatcher(['labels'], err)(empty2)).toBe(false); expect(createHasMatcher(['labels'], err)(labels)).toBe(true); - expect(createHasMatcher(['annotations'], err)(empty1)).toBe(false); - expect(createHasMatcher(['annotations'], err)(empty2)).toBe(false); - expect(createHasMatcher(['annotations'], err)(annotations)).toBe(true); - expect(createHasMatcher(['links'], err)(empty1)).toBe(false); expect(createHasMatcher(['links'], err)(empty2)).toBe(false); expect(createHasMatcher(['links'], err)(links)).toBe(true); @@ -69,7 +59,6 @@ describe('createHasMatcher', () => { expect(createHasMatcher(['labels', 'links'], err)(empty2)).toBe(false); expect(createHasMatcher(['labels', 'links'], err)(labels)).toBe(true); expect(createHasMatcher(['labels', 'links'], err)(links)).toBe(true); - expect(createHasMatcher(['labels', 'links'], err)(annotations)).toBe(false); expect(err).not.toHaveBeenCalled(); }); @@ -81,7 +70,7 @@ describe('createHasMatcher', () => { throw e; }), ).toThrowErrorMatchingInlineSnapshot( - `"'bar' is not a valid parameter for 'has' filter expressions, expected one of 'labels','annotations','links'"`, + `"'bar' is not a valid parameter for 'has' filter expressions, expected one of 'labels','links'"`, ); expect(err).not.toHaveBeenCalled(); @@ -90,12 +79,12 @@ describe('createHasMatcher', () => { expect(err).toHaveBeenCalledTimes(2); expect(err).toHaveBeenCalledWith( expect.objectContaining({ - message: `'foo' is not a valid parameter for 'has' filter expressions, expected one of 'labels','annotations','links'`, + message: `'foo' is not a valid parameter for 'has' filter expressions, expected one of 'labels','links'`, }), ); expect(err).toHaveBeenCalledWith( expect.objectContaining({ - message: `'bar' is not a valid parameter for 'has' filter expressions, expected one of 'labels','annotations','links'`, + message: `'bar' is not a valid parameter for 'has' filter expressions, expected one of 'labels','links'`, }), ); expect(matcher(empty1)).toBe(false); diff --git a/plugins/catalog/src/alpha/filter/matrchers/createHasMatcher.ts b/plugins/catalog/src/alpha/filter/matrchers/createHasMatcher.ts index 35a3f7baf7..9fd393a561 100644 --- a/plugins/catalog/src/alpha/filter/matrchers/createHasMatcher.ts +++ b/plugins/catalog/src/alpha/filter/matrchers/createHasMatcher.ts @@ -21,9 +21,6 @@ const allowedMatchers: Record = { labels: entity => { return Object.keys(entity.metadata.labels ?? {}).length > 0; }, - annotations: entity => { - return Object.keys(entity.metadata.annotations ?? {}).length > 0; - }, links: entity => { return (entity.metadata.links ?? []).length > 0; }, diff --git a/plugins/catalog/src/alpha/filter/parseFilterExpression.test.ts b/plugins/catalog/src/alpha/filter/parseFilterExpression.test.ts index d1335524b4..616091739e 100644 --- a/plugins/catalog/src/alpha/filter/parseFilterExpression.test.ts +++ b/plugins/catalog/src/alpha/filter/parseFilterExpression.test.ts @@ -89,7 +89,7 @@ describe('parseFilterExpression', () => { expect(run('has:labels,links')(annotations)).toBe(false); expect(() => run('has:labels,bar')).toThrowErrorMatchingInlineSnapshot( - `"'bar' is not a valid parameter for 'has' filter expressions, expected one of 'labels','annotations','links'"`, + `"'bar' is not a valid parameter for 'has' filter expressions, expected one of 'labels','links'"`, ); }); From 9285518f24bef10ea300409cf1af26493810d791 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 28 Nov 2023 11:34:41 +0000 Subject: [PATCH 182/261] chore(deps): update dependency @changesets/cli to v2.27.1 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 233 +++++++++++++++++++++++++----------------------------- 1 file changed, 106 insertions(+), 127 deletions(-) diff --git a/yarn.lock b/yarn.lock index 2399f06ac5..6c248db102 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10262,15 +10262,15 @@ __metadata: languageName: node linkType: hard -"@changesets/apply-release-plan@npm:^6.1.4": - version: 6.1.4 - resolution: "@changesets/apply-release-plan@npm:6.1.4" +"@changesets/apply-release-plan@npm:^7.0.0": + version: 7.0.0 + resolution: "@changesets/apply-release-plan@npm:7.0.0" dependencies: "@babel/runtime": ^7.20.1 - "@changesets/config": ^2.3.1 - "@changesets/get-version-range-type": ^0.3.2 - "@changesets/git": ^2.0.0 - "@changesets/types": ^5.2.1 + "@changesets/config": ^3.0.0 + "@changesets/get-version-range-type": ^0.4.0 + "@changesets/git": ^3.0.0 + "@changesets/types": ^6.0.0 "@manypkg/get-packages": ^1.1.3 detect-indent: ^6.0.0 fs-extra: ^7.0.1 @@ -10279,61 +10279,60 @@ __metadata: prettier: ^2.7.1 resolve-from: ^5.0.0 semver: ^7.5.3 - checksum: d386aee70c5483c97d964c6fa1191878005b7050d34b2e1e4a1ad66d9ad44f8f20d1c884e01e770b954bd2d4364f935510e53ae896212669f67e5c37b2a610c7 + checksum: ad83f89a3d46cd5249fa960cb0324114532bd5f25e74466d181afd6661273824859d038a12ba587a5e044f9169810e4a6febbb61e23c3819b3b28c00176a8bdf languageName: node linkType: hard -"@changesets/assemble-release-plan@npm:^5.2.4": - version: 5.2.4 - resolution: "@changesets/assemble-release-plan@npm:5.2.4" +"@changesets/assemble-release-plan@npm:^6.0.0": + version: 6.0.0 + resolution: "@changesets/assemble-release-plan@npm:6.0.0" dependencies: "@babel/runtime": ^7.20.1 - "@changesets/errors": ^0.1.4 - "@changesets/get-dependents-graph": ^1.3.6 - "@changesets/types": ^5.2.1 + "@changesets/errors": ^0.2.0 + "@changesets/get-dependents-graph": ^2.0.0 + "@changesets/types": ^6.0.0 "@manypkg/get-packages": ^1.1.3 semver: ^7.5.3 - checksum: 32f443a0afec3d5a4afc68c8de32e8ff88531ea24976b50583b1d6870d71cec2729f27952af82854eb54e2ad0a619872d211d654c596ee0eb42c83ab54ad15ae + checksum: 0e6d25f25e0e3cc0e92aa8c43f5f496bae9464e2523be4ff81e31b6c9971b63bb1264821a2483c48d451d89d60af1acebe727e7f8c392ed48188a3ff26d0950e languageName: node linkType: hard -"@changesets/changelog-git@npm:^0.1.14": - version: 0.1.14 - resolution: "@changesets/changelog-git@npm:0.1.14" +"@changesets/changelog-git@npm:^0.2.0": + version: 0.2.0 + resolution: "@changesets/changelog-git@npm:0.2.0" dependencies: - "@changesets/types": ^5.2.1 - checksum: 60b45bb899e66cec669ab3884d5d18550cd30bf5a8b06f335eb72aa6c9e018dd3e0187e4df61c91a22076153e346b735b792f0e9c6186e6245b1b7aec2fc42d4 + "@changesets/types": ^6.0.0 + checksum: 132660f7fdabbdda00ac803cc822d6427a1a38a17a5f414e87ad32f6dc4cbef5280a147ecdc087a28dc06c8bd0762f8d6e7132d01b8a4142b59fbe1bc2177034 languageName: node linkType: hard "@changesets/cli@npm:^2.14.0": - version: 2.26.2 - resolution: "@changesets/cli@npm:2.26.2" + version: 2.27.1 + resolution: "@changesets/cli@npm:2.27.1" dependencies: "@babel/runtime": ^7.20.1 - "@changesets/apply-release-plan": ^6.1.4 - "@changesets/assemble-release-plan": ^5.2.4 - "@changesets/changelog-git": ^0.1.14 - "@changesets/config": ^2.3.1 - "@changesets/errors": ^0.1.4 - "@changesets/get-dependents-graph": ^1.3.6 - "@changesets/get-release-plan": ^3.0.17 - "@changesets/git": ^2.0.0 - "@changesets/logger": ^0.0.5 - "@changesets/pre": ^1.0.14 - "@changesets/read": ^0.5.9 - "@changesets/types": ^5.2.1 - "@changesets/write": ^0.2.3 + "@changesets/apply-release-plan": ^7.0.0 + "@changesets/assemble-release-plan": ^6.0.0 + "@changesets/changelog-git": ^0.2.0 + "@changesets/config": ^3.0.0 + "@changesets/errors": ^0.2.0 + "@changesets/get-dependents-graph": ^2.0.0 + "@changesets/get-release-plan": ^4.0.0 + "@changesets/git": ^3.0.0 + "@changesets/logger": ^0.1.0 + "@changesets/pre": ^2.0.0 + "@changesets/read": ^0.6.0 + "@changesets/types": ^6.0.0 + "@changesets/write": ^0.3.0 "@manypkg/get-packages": ^1.1.3 - "@types/is-ci": ^3.0.0 "@types/semver": ^7.5.0 ansi-colors: ^4.1.3 chalk: ^2.1.0 + ci-info: ^3.7.0 enquirer: ^2.3.0 external-editor: ^3.1.0 fs-extra: ^7.0.1 human-id: ^1.0.2 - is-ci: ^3.0.1 meow: ^6.0.0 outdent: ^0.5.0 p-limit: ^2.2.0 @@ -10345,129 +10344,129 @@ __metadata: tty-table: ^4.1.5 bin: changeset: bin.js - checksum: fc7b5bf319b19abed7a8d33a9fbd9ce49108af61c9c51920f609a49cb0c557f0b998711250d0cac149d0bed8a522f3109c4d8b0dda65b96ff2f823d16ca2f972 + checksum: 0d030dec7e0ef28626082a257d57f46cdf65edb65a95f5a3511a9d298ca052388d8ab7f9a714943864eddc59148c4afb0b802a9c75b5bea45aade4c0dc7a5fa6 languageName: node linkType: hard -"@changesets/config@npm:^2.3.1": - version: 2.3.1 - resolution: "@changesets/config@npm:2.3.1" +"@changesets/config@npm:^3.0.0": + version: 3.0.0 + resolution: "@changesets/config@npm:3.0.0" dependencies: - "@changesets/errors": ^0.1.4 - "@changesets/get-dependents-graph": ^1.3.6 - "@changesets/logger": ^0.0.5 - "@changesets/types": ^5.2.1 + "@changesets/errors": ^0.2.0 + "@changesets/get-dependents-graph": ^2.0.0 + "@changesets/logger": ^0.1.0 + "@changesets/types": ^6.0.0 "@manypkg/get-packages": ^1.1.3 fs-extra: ^7.0.1 micromatch: ^4.0.2 - checksum: 8af58e3add4751ac8ce2c01f026ac8843b8d1c07c9a3df6518496eaef67f56458a84cad310763c588f7eccbf6831afbf280df7e05e78b294027b6b847be3d0cc + checksum: 31a8c37e38768cf3676d24b7d371009dd1d691f221ecf086b79f0d96dc8e95aa408cda3659eb867a14615ea38a1c2be448bf0655c7570539af57c930ca784051 languageName: node linkType: hard -"@changesets/errors@npm:^0.1.4": - version: 0.1.4 - resolution: "@changesets/errors@npm:0.1.4" +"@changesets/errors@npm:^0.2.0": + version: 0.2.0 + resolution: "@changesets/errors@npm:0.2.0" dependencies: extendable-error: ^0.1.5 - checksum: 10734f1379715bf5a70b566dd42b50a75964d76f382bb67332776614454deda6d04a43dd7e727cd7cba56d7f2f7c95a07c7c0a19dd5d64fb1980b28322840733 + checksum: 4b79373f92287af4f723e8dbbccaf0299aa8735fc043243d0ad587f04a7614615ea50180be575d4438b9f00aa82d1cf85e902b77a55bdd3e0a8dd97e77b18c60 languageName: node linkType: hard -"@changesets/get-dependents-graph@npm:^1.3.6": - version: 1.3.6 - resolution: "@changesets/get-dependents-graph@npm:1.3.6" +"@changesets/get-dependents-graph@npm:^2.0.0": + version: 2.0.0 + resolution: "@changesets/get-dependents-graph@npm:2.0.0" dependencies: - "@changesets/types": ^5.2.1 + "@changesets/types": ^6.0.0 "@manypkg/get-packages": ^1.1.3 chalk: ^2.1.0 fs-extra: ^7.0.1 semver: ^7.5.3 - checksum: d2cbbc5041063b939899502d1b264a0d9edb655acefd7f6197883229156bb7cfd1ace642ae4a1f7f7b432f2c51429f5dc9851ff5a9ed47f1c0159916e66627a9 + checksum: 6690d3ed36e8a636bc2a985d209bd72ee1100601ccf00850ca1fbe8500af839a3f4e5bd2167858cf11383aa76360f853e481533157060ad882fb56319db3090a languageName: node linkType: hard -"@changesets/get-release-plan@npm:^3.0.17": - version: 3.0.17 - resolution: "@changesets/get-release-plan@npm:3.0.17" +"@changesets/get-release-plan@npm:^4.0.0": + version: 4.0.0 + resolution: "@changesets/get-release-plan@npm:4.0.0" dependencies: "@babel/runtime": ^7.20.1 - "@changesets/assemble-release-plan": ^5.2.4 - "@changesets/config": ^2.3.1 - "@changesets/pre": ^1.0.14 - "@changesets/read": ^0.5.9 - "@changesets/types": ^5.2.1 + "@changesets/assemble-release-plan": ^6.0.0 + "@changesets/config": ^3.0.0 + "@changesets/pre": ^2.0.0 + "@changesets/read": ^0.6.0 + "@changesets/types": ^6.0.0 "@manypkg/get-packages": ^1.1.3 - checksum: 8a0e3794d0f1e6220d173dbec96352ad69b585d013c3183888ca598dfdfcaa8a5ac3f7f36d5c511575cdc3559c2ad6f8cecfaa16ba9c24380899a81daa7af924 + checksum: 57672c1e94f95de8ac65aac969275e0cb225f02aa86b2cef69329fff6e36ba5fde04eadeb6af36f4d8ac41a8fd329028b4df4c23c15c10fd13e026c77463d576 languageName: node linkType: hard -"@changesets/get-version-range-type@npm:^0.3.2": - version: 0.3.2 - resolution: "@changesets/get-version-range-type@npm:0.3.2" - checksum: b7ee7127c472a3886906ca6db336ac11233a5e75abc882084bfb4794e79a8936e3faceec3c04bf61c26453cd7f74278d9bf22aea4cdca8c1cd992591925b3c9b +"@changesets/get-version-range-type@npm:^0.4.0": + version: 0.4.0 + resolution: "@changesets/get-version-range-type@npm:0.4.0" + checksum: 2e8c511e658e193f48de7f09522649c4cf072932f0cbe0f252a7f2703d7775b0b90b632254526338795d0658e340be9dff3879cfc8eba4534b8cd6071efff8c9 languageName: node linkType: hard -"@changesets/git@npm:^2.0.0": - version: 2.0.0 - resolution: "@changesets/git@npm:2.0.0" +"@changesets/git@npm:^3.0.0": + version: 3.0.0 + resolution: "@changesets/git@npm:3.0.0" dependencies: "@babel/runtime": ^7.20.1 - "@changesets/errors": ^0.1.4 - "@changesets/types": ^5.2.1 + "@changesets/errors": ^0.2.0 + "@changesets/types": ^6.0.0 "@manypkg/get-packages": ^1.1.3 is-subdir: ^1.1.1 micromatch: ^4.0.2 spawndamnit: ^2.0.0 - checksum: 3820b7b689bbe8dfb93222c766bee214e68a45f07b2b5c8056891f9ffe6f1e369c0f84388246a9eea5317b496ae80ffd1508319190f79c359f060ebf8ccb7b13 + checksum: a8fa66d77302b50d5e604aca898ee813247537d23a05004637ecee4aa1579d6a2859283c099bdcf3e2b232258c93ff81dd57aa867858788e457df40118c64c2b languageName: node linkType: hard -"@changesets/logger@npm:^0.0.5": - version: 0.0.5 - resolution: "@changesets/logger@npm:0.0.5" +"@changesets/logger@npm:^0.1.0": + version: 0.1.0 + resolution: "@changesets/logger@npm:0.1.0" dependencies: chalk: ^2.1.0 - checksum: bfec3cd9122b00c0ec25e96730f771ffd662ef3906d571bad1e4e9993f9d54d357d3eaf074b3dfaa4e23af759ce68efa2a97d8b845b0d8c951df5d21c6dfdff5 + checksum: d8ef1b7caf3d2c15a9e7743b7a9462e0c2e61c76d9a5bbed5eff805afa8226117505309c6e9095001136b4f6d9ae0aba61377e53af8aa0809f1febd1b5f787f1 languageName: node linkType: hard -"@changesets/parse@npm:^0.3.16": - version: 0.3.16 - resolution: "@changesets/parse@npm:0.3.16" +"@changesets/parse@npm:^0.4.0": + version: 0.4.0 + resolution: "@changesets/parse@npm:0.4.0" dependencies: - "@changesets/types": ^5.2.1 + "@changesets/types": ^6.0.0 js-yaml: ^3.13.1 - checksum: 475f808ac8d33ec90af3914d55af1da8eeb9336d6cab7dd9e5be74af844f0ec04f4a67d5237a1d3284a468e0c9198e2be01d0e5870a1b28e63bc240f5f1ffea9 + checksum: 3dd970b244479746233ebd357cfff3816cf9f344ebf2cf0c7c55ce8579adfd3f506978e86ad61222dc3acf1548a2105ffdd8b3e940b3f82b225741315cee2bf0 languageName: node linkType: hard -"@changesets/pre@npm:^1.0.14": - version: 1.0.14 - resolution: "@changesets/pre@npm:1.0.14" +"@changesets/pre@npm:^2.0.0": + version: 2.0.0 + resolution: "@changesets/pre@npm:2.0.0" dependencies: "@babel/runtime": ^7.20.1 - "@changesets/errors": ^0.1.4 - "@changesets/types": ^5.2.1 + "@changesets/errors": ^0.2.0 + "@changesets/types": ^6.0.0 "@manypkg/get-packages": ^1.1.3 fs-extra: ^7.0.1 - checksum: 6b849bd6f916476a5b5664bc4286020bee506985c82f723a757fa4e681b0b7129db81751f16072ac55a980ffd83a4b234d6b8d0f8b6bc889aa0c0fd5377431e8 + checksum: 6a01086405f4e4ce63abb8f222de39b69a5762c9c8c8f19c0d3c72f7798248d7a152937028f1be24be1f8a4a5e47e4cb23c54bc36f979539b24a728c893caf4e languageName: node linkType: hard -"@changesets/read@npm:^0.5.9": - version: 0.5.9 - resolution: "@changesets/read@npm:0.5.9" +"@changesets/read@npm:^0.6.0": + version: 0.6.0 + resolution: "@changesets/read@npm:0.6.0" dependencies: "@babel/runtime": ^7.20.1 - "@changesets/git": ^2.0.0 - "@changesets/logger": ^0.0.5 - "@changesets/parse": ^0.3.16 - "@changesets/types": ^5.2.1 + "@changesets/git": ^3.0.0 + "@changesets/logger": ^0.1.0 + "@changesets/parse": ^0.4.0 + "@changesets/types": ^6.0.0 chalk: ^2.1.0 fs-extra: ^7.0.1 p-filter: ^2.1.0 - checksum: 0875a80829186de2da55bc0347601cc31b269d54fb6967a5093abacbbd9f949e352907b8340b61348a304228fdade670ded151327f16eea3424b5b4b2bb9888c + checksum: 3da6428124b4983f6ccbdae324c73044cd6a84269bfdbaff545331042e3d6845c647613b5d8f4ffdd48bad5b791623eca2be1b507652ea47b77e136cd2e26c70 languageName: node linkType: hard @@ -10478,23 +10477,23 @@ __metadata: languageName: node linkType: hard -"@changesets/types@npm:^5.2.1": - version: 5.2.1 - resolution: "@changesets/types@npm:5.2.1" - checksum: 527dc1aa41b040fe35bcd55f7d07bec710320b179b000c429723e25b87aac18be487daf5047d4fecf2781aad78f73abff111e76e411b652f7a2e812a464c69f2 +"@changesets/types@npm:^6.0.0": + version: 6.0.0 + resolution: "@changesets/types@npm:6.0.0" + checksum: d528b5d712f62c26ea422c7d34ccf6eac57a353c0733d96716db3c796ecd9bba5d496d48b37d5d46b784dc45b69c06ce3345fa3515df981bb68456cad68e6465 languageName: node linkType: hard -"@changesets/write@npm:^0.2.3": - version: 0.2.3 - resolution: "@changesets/write@npm:0.2.3" +"@changesets/write@npm:^0.3.0": + version: 0.3.0 + resolution: "@changesets/write@npm:0.3.0" dependencies: "@babel/runtime": ^7.20.1 - "@changesets/types": ^5.2.1 + "@changesets/types": ^6.0.0 fs-extra: ^7.0.1 human-id: ^1.0.2 prettier: ^2.7.1 - checksum: 40ad8069f9adc565b78a5f25992e31b41a12e551d94c29e1b4def49ce98871a1e358feda6536be8b363a6dba18b1226a22ecfc60fdd7bc1e74bfcf46b07f91be + checksum: 37588eb3ef2af15b3ea09d46864c994780619d20b791ea5b654801a035a3a12540c7f953e6e4f36731678615edc6d1c32f8fe174d599d3e6ce2d68263865788b languageName: node linkType: hard @@ -18279,15 +18278,6 @@ __metadata: languageName: node linkType: hard -"@types/is-ci@npm:^3.0.0": - version: 3.0.0 - resolution: "@types/is-ci@npm:3.0.0" - dependencies: - ci-info: ^3.1.0 - checksum: 7c1f1f16c1fa2134de7400d82766c83fa76057261ba890628af77a09382ebb92d945bb077b98cfcf3d40ab1469c9ffbd2278112867edbe57aa655f53547eb139 - languageName: node - linkType: hard - "@types/is-glob@npm:^4.0.2": version: 4.0.4 resolution: "@types/is-glob@npm:4.0.4" @@ -22489,7 +22479,7 @@ __metadata: languageName: node linkType: hard -"ci-info@npm:^3.1.0, ci-info@npm:^3.2.0, ci-info@npm:^3.7.0": +"ci-info@npm:^3.2.0, ci-info@npm:^3.7.0": version: 3.8.0 resolution: "ci-info@npm:3.8.0" checksum: d0a4d3160497cae54294974a7246202244fff031b0a6ea20dd57b10ec510aa17399c41a1b0982142c105f3255aff2173e5c0dd7302ee1b2f28ba3debda375098 @@ -30051,17 +30041,6 @@ __metadata: languageName: node linkType: hard -"is-ci@npm:^3.0.1": - version: 3.0.1 - resolution: "is-ci@npm:3.0.1" - dependencies: - ci-info: ^3.2.0 - bin: - is-ci: bin.js - checksum: 192c66dc7826d58f803ecae624860dccf1899fc1f3ac5505284c0a5cf5f889046ffeb958fa651e5725d5705c5bcb14f055b79150ea5fcad7456a9569de60260e - languageName: node - linkType: hard - "is-core-module@npm:^2.1.0, is-core-module@npm:^2.13.0, is-core-module@npm:^2.13.1, is-core-module@npm:^2.9.0": version: 2.13.1 resolution: "is-core-module@npm:2.13.1" From 356906bab82c1f13970c8077b429ef7d86cece58 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 28 Nov 2023 13:37:18 +0000 Subject: [PATCH 183/261] Version Packages (next) --- .changeset/pre.json | 73 +- docs/releases/v1.21.0-next.2-changelog.md | 3088 +++++++++++++++++ package.json | 2 +- packages/app-defaults/CHANGELOG.md | 11 + packages/app-defaults/package.json | 2 +- packages/app-next-example-plugin/CHANGELOG.md | 8 + packages/app-next-example-plugin/package.json | 2 +- packages/app-next/CHANGELOG.md | 76 + packages/app-next/package.json | 2 +- packages/app/CHANGELOG.md | 76 + packages/app/package.json | 2 +- packages/backend-app-api/CHANGELOG.md | 19 + packages/backend-app-api/package.json | 2 +- packages/backend-common/CHANGELOG.md | 17 + packages/backend-common/package.json | 2 +- packages/backend-defaults/CHANGELOG.md | 9 + packages/backend-defaults/package.json | 2 +- packages/backend-next/CHANGELOG.md | 41 + packages/backend-next/package.json | 2 +- packages/backend-openapi-utils/CHANGELOG.md | 9 + packages/backend-openapi-utils/package.json | 2 +- packages/backend-plugin-api/CHANGELOG.md | 11 + packages/backend-plugin-api/package.json | 2 +- packages/backend-plugin-manager/CHANGELOG.md | 23 + packages/backend-plugin-manager/package.json | 2 +- packages/backend-tasks/CHANGELOG.md | 10 + packages/backend-tasks/package.json | 2 +- packages/backend-test-utils/CHANGELOG.md | 13 + packages/backend-test-utils/package.json | 2 +- packages/backend/CHANGELOG.md | 58 + packages/backend/package.json | 2 +- packages/catalog-client/CHANGELOG.md | 12 + packages/catalog-client/package.json | 2 +- packages/cli/CHANGELOG.md | 25 + packages/cli/package.json | 2 +- packages/core-app-api/CHANGELOG.md | 11 + packages/core-app-api/package.json | 2 +- packages/core-compat-api/CHANGELOG.md | 9 + packages/core-compat-api/package.json | 2 +- packages/core-components/CHANGELOG.md | 15 + packages/core-components/package.json | 2 +- packages/core-plugin-api/CHANGELOG.md | 10 + packages/core-plugin-api/package.json | 2 +- packages/create-app/CHANGELOG.md | 8 + packages/create-app/package.json | 2 +- packages/dev-utils/CHANGELOG.md | 14 + packages/dev-utils/package.json | 2 +- packages/e2e-test/CHANGELOG.md | 9 + packages/e2e-test/package.json | 2 +- packages/eslint-plugin/CHANGELOG.md | 6 + packages/eslint-plugin/package.json | 2 +- packages/frontend-app-api/CHANGELOG.md | 23 + packages/frontend-app-api/package.json | 2 +- packages/frontend-plugin-api/CHANGELOG.md | 20 + packages/frontend-plugin-api/package.json | 2 +- packages/frontend-test-utils/CHANGELOG.md | 12 + packages/frontend-test-utils/package.json | 2 +- packages/integration-react/CHANGELOG.md | 9 + packages/integration-react/package.json | 2 +- packages/integration/CHANGELOG.md | 8 + packages/integration/package.json | 2 +- packages/repo-tools/CHANGELOG.md | 15 + packages/repo-tools/package.json | 2 +- .../techdocs-cli-embedded-app/CHANGELOG.md | 19 + .../techdocs-cli-embedded-app/package.json | 2 +- packages/techdocs-cli/CHANGELOG.md | 15 + packages/techdocs-cli/package.json | 2 +- packages/test-utils/CHANGELOG.md | 14 + packages/test-utils/package.json | 2 +- plugins/adr-backend/CHANGELOG.md | 15 + plugins/adr-backend/package.json | 2 +- plugins/adr-common/CHANGELOG.md | 9 + plugins/adr-common/package.json | 2 +- plugins/adr/CHANGELOG.md | 17 + plugins/adr/package.json | 2 +- plugins/airbrake-backend/CHANGELOG.md | 9 + plugins/airbrake-backend/package.json | 2 +- plugins/airbrake/CHANGELOG.md | 13 + plugins/airbrake/package.json | 2 +- plugins/allure/CHANGELOG.md | 11 + plugins/allure/package.json | 2 +- plugins/analytics-module-ga/CHANGELOG.md | 10 + plugins/analytics-module-ga/package.json | 2 +- plugins/analytics-module-ga4/CHANGELOG.md | 10 + plugins/analytics-module-ga4/package.json | 2 +- .../CHANGELOG.md | 9 + .../package.json | 2 +- plugins/apache-airflow/CHANGELOG.md | 8 + plugins/apache-airflow/package.json | 2 +- plugins/api-docs/CHANGELOG.md | 13 + plugins/api-docs/package.json | 2 +- plugins/apollo-explorer/CHANGELOG.md | 9 + plugins/apollo-explorer/package.json | 2 +- plugins/app-backend/CHANGELOG.md | 12 + plugins/app-backend/package.json | 2 +- plugins/app-node/CHANGELOG.md | 7 + plugins/app-node/package.json | 2 +- .../CHANGELOG.md | 9 + .../package.json | 2 +- .../CHANGELOG.md | 10 + .../package.json | 2 +- .../CHANGELOG.md | 9 + .../package.json | 2 +- .../CHANGELOG.md | 9 + .../package.json | 2 +- .../CHANGELOG.md | 8 + .../package.json | 2 +- .../CHANGELOG.md | 9 + .../package.json | 2 +- .../CHANGELOG.md | 9 + .../package.json | 2 +- .../CHANGELOG.md | 15 + .../package.json | 2 +- .../CHANGELOG.md | 9 + .../package.json | 2 +- .../CHANGELOG.md | 10 + .../package.json | 2 +- .../CHANGELOG.md | 15 + .../package.json | 2 +- plugins/auth-backend/CHANGELOG.md | 25 + plugins/auth-backend/package.json | 2 +- plugins/auth-node/CHANGELOG.md | 13 + plugins/auth-node/package.json | 2 +- plugins/azure-devops-backend/CHANGELOG.md | 21 + plugins/azure-devops-backend/package.json | 2 +- plugins/azure-devops-common/CHANGELOG.md | 6 + plugins/azure-devops-common/package.json | 2 +- plugins/azure-devops/CHANGELOG.md | 14 + plugins/azure-devops/package.json | 2 +- plugins/azure-sites-backend/CHANGELOG.md | 10 + plugins/azure-sites-backend/package.json | 2 +- plugins/azure-sites/CHANGELOG.md | 12 + plugins/azure-sites/package.json | 2 +- plugins/badges-backend/CHANGELOG.md | 13 + plugins/badges-backend/package.json | 2 +- plugins/badges/CHANGELOG.md | 12 + plugins/badges/package.json | 2 +- plugins/bazaar-backend/CHANGELOG.md | 11 + plugins/bazaar-backend/package.json | 2 +- plugins/bazaar/CHANGELOG.md | 14 + plugins/bazaar/package.json | 2 +- plugins/bitbucket-cloud-common/CHANGELOG.md | 7 + plugins/bitbucket-cloud-common/package.json | 2 +- plugins/bitrise/CHANGELOG.md | 11 + plugins/bitrise/package.json | 2 +- .../catalog-backend-module-aws/CHANGELOG.md | 18 + .../catalog-backend-module-aws/package.json | 2 +- .../catalog-backend-module-azure/CHANGELOG.md | 16 + .../catalog-backend-module-azure/package.json | 2 +- .../CHANGELOG.md | 15 + .../package.json | 2 +- .../CHANGELOG.md | 17 + .../package.json | 2 +- .../CHANGELOG.md | 14 + .../package.json | 2 +- .../CHANGELOG.md | 14 + .../package.json | 2 +- .../catalog-backend-module-gcp/CHANGELOG.md | 13 + .../catalog-backend-module-gcp/package.json | 2 +- .../CHANGELOG.md | 14 + .../package.json | 2 +- .../CHANGELOG.md | 12 + .../package.json | 2 +- .../CHANGELOG.md | 17 + .../package.json | 2 +- .../CHANGELOG.md | 13 + .../package.json | 2 +- .../CHANGELOG.md | 17 + .../package.json | 2 +- .../catalog-backend-module-ldap/CHANGELOG.md | 13 + .../catalog-backend-module-ldap/package.json | 2 +- .../CHANGELOG.md | 14 + .../package.json | 2 +- .../CHANGELOG.md | 14 + .../package.json | 2 +- .../CHANGELOG.md | 14 + .../package.json | 2 +- .../CHANGELOG.md | 12 + .../package.json | 2 +- .../CHANGELOG.md | 9 + .../package.json | 2 +- plugins/catalog-backend/CHANGELOG.md | 25 + plugins/catalog-backend/package.json | 2 +- plugins/catalog-graph/CHANGELOG.md | 13 + plugins/catalog-graph/package.json | 2 +- plugins/catalog-import/CHANGELOG.md | 18 + plugins/catalog-import/package.json | 2 +- plugins/catalog-node/CHANGELOG.md | 12 + plugins/catalog-node/package.json | 2 +- plugins/catalog-react/CHANGELOG.md | 26 + plugins/catalog-react/package.json | 2 +- .../catalog-unprocessed-entities/CHANGELOG.md | 11 + .../catalog-unprocessed-entities/package.json | 2 +- plugins/catalog/CHANGELOG.md | 30 + plugins/catalog/package.json | 2 +- .../CHANGELOG.md | 9 + .../package.json | 2 +- plugins/cicd-statistics/CHANGELOG.md | 9 + plugins/cicd-statistics/package.json | 2 +- plugins/circleci/CHANGELOG.md | 12 + plugins/circleci/package.json | 2 +- plugins/cloudbuild/CHANGELOG.md | 11 + plugins/cloudbuild/package.json | 2 +- plugins/code-climate/CHANGELOG.md | 11 + plugins/code-climate/package.json | 2 +- plugins/code-coverage-backend/CHANGELOG.md | 14 + plugins/code-coverage-backend/package.json | 2 +- plugins/code-coverage/CHANGELOG.md | 13 + plugins/code-coverage/package.json | 2 +- plugins/codescene/CHANGELOG.md | 11 + plugins/codescene/package.json | 2 +- plugins/config-schema/CHANGELOG.md | 12 + plugins/config-schema/package.json | 2 +- plugins/cost-insights/CHANGELOG.md | 13 + plugins/cost-insights/package.json | 2 +- plugins/devtools-backend/CHANGELOG.md | 17 + plugins/devtools-backend/package.json | 2 +- plugins/devtools/CHANGELOG.md | 13 + plugins/devtools/package.json | 2 +- plugins/dynatrace/CHANGELOG.md | 11 + plugins/dynatrace/package.json | 2 +- plugins/entity-feedback-backend/CHANGELOG.md | 13 + plugins/entity-feedback-backend/package.json | 2 +- plugins/entity-feedback/CHANGELOG.md | 13 + plugins/entity-feedback/package.json | 2 +- plugins/entity-validation/CHANGELOG.md | 15 + plugins/entity-validation/package.json | 2 +- .../CHANGELOG.md | 12 + .../package.json | 2 +- .../events-backend-module-azure/CHANGELOG.md | 8 + .../events-backend-module-azure/package.json | 2 +- .../CHANGELOG.md | 8 + .../package.json | 2 +- .../events-backend-module-gerrit/CHANGELOG.md | 8 + .../events-backend-module-gerrit/package.json | 2 +- .../events-backend-module-github/CHANGELOG.md | 9 + .../events-backend-module-github/package.json | 2 +- .../events-backend-module-gitlab/CHANGELOG.md | 9 + .../events-backend-module-gitlab/package.json | 2 +- .../events-backend-test-utils/CHANGELOG.md | 7 + .../events-backend-test-utils/package.json | 2 +- plugins/events-backend/CHANGELOG.md | 10 + plugins/events-backend/package.json | 2 +- plugins/events-node/CHANGELOG.md | 7 + plugins/events-node/package.json | 2 +- .../example-todo-list-backend/CHANGELOG.md | 11 + .../example-todo-list-backend/package.json | 2 +- plugins/example-todo-list/CHANGELOG.md | 9 + plugins/example-todo-list/package.json | 2 +- plugins/explore-backend/CHANGELOG.md | 12 + plugins/explore-backend/package.json | 2 +- plugins/explore-react/CHANGELOG.md | 8 + plugins/explore-react/package.json | 2 +- plugins/explore/CHANGELOG.md | 17 + plugins/explore/package.json | 2 +- plugins/firehydrant/CHANGELOG.md | 11 + plugins/firehydrant/package.json | 2 +- plugins/fossa/CHANGELOG.md | 12 + plugins/fossa/package.json | 2 +- plugins/gcalendar/CHANGELOG.md | 10 + plugins/gcalendar/package.json | 2 +- plugins/gcp-projects/CHANGELOG.md | 10 + plugins/gcp-projects/package.json | 2 +- plugins/git-release-manager/CHANGELOG.md | 10 + plugins/git-release-manager/package.json | 2 +- plugins/github-actions/CHANGELOG.md | 14 + plugins/github-actions/package.json | 2 +- plugins/github-deployments/CHANGELOG.md | 14 + plugins/github-deployments/package.json | 2 +- plugins/github-issues/CHANGELOG.md | 13 + plugins/github-issues/package.json | 2 +- .../github-pull-requests-board/CHANGELOG.md | 12 + .../github-pull-requests-board/package.json | 2 +- plugins/gitops-profiles/CHANGELOG.md | 10 + plugins/gitops-profiles/package.json | 2 +- plugins/gocd/CHANGELOG.md | 12 + plugins/gocd/package.json | 2 +- plugins/graphiql/CHANGELOG.md | 11 + plugins/graphiql/package.json | 2 +- plugins/graphql-voyager/CHANGELOG.md | 9 + plugins/graphql-voyager/package.json | 2 +- plugins/home-react/CHANGELOG.md | 12 + plugins/home-react/package.json | 2 +- plugins/home/CHANGELOG.md | 25 + plugins/home/package.json | 2 +- plugins/ilert/CHANGELOG.md | 12 + plugins/ilert/package.json | 2 +- plugins/jenkins-backend/CHANGELOG.md | 17 + plugins/jenkins-backend/package.json | 2 +- plugins/jenkins/CHANGELOG.md | 13 + plugins/jenkins/package.json | 2 +- plugins/kafka-backend/CHANGELOG.md | 11 + plugins/kafka-backend/package.json | 2 +- plugins/kafka/CHANGELOG.md | 12 + plugins/kafka/package.json | 2 +- plugins/kubernetes-backend/CHANGELOG.md | 22 + plugins/kubernetes-backend/package.json | 2 +- plugins/kubernetes-cluster/CHANGELOG.md | 15 + plugins/kubernetes-cluster/package.json | 2 +- plugins/kubernetes-common/CHANGELOG.md | 11 + plugins/kubernetes-common/package.json | 2 +- plugins/kubernetes-node/CHANGELOG.md | 9 + plugins/kubernetes-node/package.json | 2 +- plugins/kubernetes-react/CHANGELOG.md | 12 + plugins/kubernetes-react/package.json | 2 +- plugins/kubernetes/CHANGELOG.md | 16 + plugins/kubernetes/package.json | 2 +- plugins/lighthouse-backend/CHANGELOG.md | 15 + plugins/lighthouse-backend/package.json | 2 +- plugins/lighthouse/CHANGELOG.md | 13 + plugins/lighthouse/package.json | 2 +- plugins/linguist-backend/CHANGELOG.md | 17 + plugins/linguist-backend/package.json | 2 +- plugins/linguist/CHANGELOG.md | 13 + plugins/linguist/package.json | 2 +- plugins/microsoft-calendar/CHANGELOG.md | 10 + plugins/microsoft-calendar/package.json | 2 +- plugins/newrelic-dashboard/CHANGELOG.md | 11 + plugins/newrelic-dashboard/package.json | 2 +- plugins/newrelic/CHANGELOG.md | 9 + plugins/newrelic/package.json | 2 +- plugins/nomad-backend/CHANGELOG.md | 10 + plugins/nomad-backend/package.json | 2 +- plugins/nomad/CHANGELOG.md | 12 + plugins/nomad/package.json | 2 +- plugins/octopus-deploy/CHANGELOG.md | 11 + plugins/octopus-deploy/package.json | 2 +- plugins/opencost/CHANGELOG.md | 9 + plugins/opencost/package.json | 2 +- plugins/org-react/CHANGELOG.md | 12 + plugins/org-react/package.json | 2 +- plugins/org/CHANGELOG.md | 11 + plugins/org/package.json | 2 +- plugins/pagerduty/CHANGELOG.md | 17 + plugins/pagerduty/package.json | 2 +- plugins/periskop-backend/CHANGELOG.md | 9 + plugins/periskop-backend/package.json | 2 +- plugins/periskop/CHANGELOG.md | 12 + plugins/periskop/package.json | 2 +- .../CHANGELOG.md | 11 + .../package.json | 2 +- plugins/permission-backend/CHANGELOG.md | 13 + plugins/permission-backend/package.json | 2 +- plugins/permission-node/CHANGELOG.md | 12 + plugins/permission-node/package.json | 2 +- plugins/permission-react/CHANGELOG.md | 9 + plugins/permission-react/package.json | 2 +- plugins/playlist-backend/CHANGELOG.md | 16 + plugins/playlist-backend/package.json | 2 +- plugins/playlist/CHANGELOG.md | 17 + plugins/playlist/package.json | 2 +- plugins/proxy-backend/CHANGELOG.md | 9 + plugins/proxy-backend/package.json | 2 +- plugins/puppetdb/CHANGELOG.md | 12 + plugins/puppetdb/package.json | 2 +- plugins/rollbar-backend/CHANGELOG.md | 8 + plugins/rollbar-backend/package.json | 2 +- plugins/rollbar/CHANGELOG.md | 11 + plugins/rollbar/package.json | 2 +- .../CHANGELOG.md | 12 + .../package.json | 2 +- .../CHANGELOG.md | 12 + .../package.json | 2 +- .../CHANGELOG.md | 10 + .../package.json | 2 +- .../CHANGELOG.md | 12 + .../package.json | 2 +- .../CHANGELOG.md | 10 + .../package.json | 2 +- .../CHANGELOG.md | 9 + .../package.json | 2 +- plugins/scaffolder-backend/CHANGELOG.md | 24 + plugins/scaffolder-backend/package.json | 2 +- plugins/scaffolder-node/CHANGELOG.md | 13 + plugins/scaffolder-node/package.json | 2 +- plugins/scaffolder-react/CHANGELOG.md | 23 + plugins/scaffolder-react/package.json | 2 +- plugins/scaffolder/CHANGELOG.md | 27 + plugins/scaffolder/package.json | 2 +- .../CHANGELOG.md | 18 + .../package.json | 2 +- .../CHANGELOG.md | 12 + .../package.json | 2 +- .../CHANGELOG.md | 13 + .../package.json | 2 +- plugins/search-backend-module-pg/CHANGELOG.md | 11 + plugins/search-backend-module-pg/package.json | 2 +- .../CHANGELOG.md | 12 + .../package.json | 2 +- .../CHANGELOG.md | 18 + .../package.json | 2 +- plugins/search-backend-node/CHANGELOG.md | 13 + plugins/search-backend-node/package.json | 2 +- plugins/search-backend/CHANGELOG.md | 17 + plugins/search-backend/package.json | 2 +- plugins/search-react/CHANGELOG.md | 14 + plugins/search-react/package.json | 2 +- plugins/search/CHANGELOG.md | 19 + plugins/search/package.json | 2 +- plugins/sentry/CHANGELOG.md | 11 + plugins/sentry/package.json | 2 +- plugins/shortcuts/CHANGELOG.md | 10 + plugins/shortcuts/package.json | 2 +- plugins/sonarqube-backend/CHANGELOG.md | 10 + plugins/sonarqube-backend/package.json | 2 +- plugins/sonarqube-react/CHANGELOG.md | 8 + plugins/sonarqube-react/package.json | 2 +- plugins/sonarqube/CHANGELOG.md | 12 + plugins/sonarqube/package.json | 2 +- plugins/splunk-on-call/CHANGELOG.md | 11 + plugins/splunk-on-call/package.json | 2 +- plugins/stack-overflow-backend/CHANGELOG.md | 10 + plugins/stack-overflow-backend/package.json | 2 +- plugins/stack-overflow/CHANGELOG.md | 14 + plugins/stack-overflow/package.json | 2 +- plugins/stackstorm/CHANGELOG.md | 10 + plugins/stackstorm/package.json | 2 +- .../CHANGELOG.md | 11 + .../package.json | 2 +- plugins/tech-insights-backend/CHANGELOG.md | 15 + plugins/tech-insights-backend/package.json | 2 +- plugins/tech-insights-node/CHANGELOG.md | 11 + plugins/tech-insights-node/package.json | 2 +- plugins/tech-insights/CHANGELOG.md | 14 + plugins/tech-insights/package.json | 2 +- plugins/tech-radar/CHANGELOG.md | 11 + plugins/tech-radar/package.json | 2 +- .../techdocs-addons-test-utils/CHANGELOG.md | 18 + .../techdocs-addons-test-utils/package.json | 2 +- plugins/techdocs-backend/CHANGELOG.md | 18 + plugins/techdocs-backend/package.json | 2 +- .../CHANGELOG.md | 13 + .../package.json | 2 +- plugins/techdocs-node/CHANGELOG.md | 17 + plugins/techdocs-node/package.json | 2 +- plugins/techdocs-react/CHANGELOG.md | 11 + plugins/techdocs-react/package.json | 2 +- plugins/techdocs/CHANGELOG.md | 20 + plugins/techdocs/package.json | 2 +- plugins/todo-backend/CHANGELOG.md | 15 + plugins/todo-backend/package.json | 2 +- plugins/todo/CHANGELOG.md | 12 + plugins/todo/package.json | 2 +- plugins/user-settings-backend/CHANGELOG.md | 13 + plugins/user-settings-backend/package.json | 2 +- plugins/user-settings/CHANGELOG.md | 16 + plugins/user-settings/package.json | 2 +- plugins/vault-backend/CHANGELOG.md | 12 + plugins/vault-backend/package.json | 2 +- plugins/vault-node/CHANGELOG.md | 7 + plugins/vault-node/package.json | 2 +- plugins/vault/CHANGELOG.md | 12 + plugins/vault/package.json | 2 +- plugins/xcmetrics/CHANGELOG.md | 10 + plugins/xcmetrics/package.json | 2 +- yarn.lock | 13 +- 456 files changed, 6484 insertions(+), 230 deletions(-) create mode 100644 docs/releases/v1.21.0-next.2-changelog.md create mode 100644 plugins/auth-backend-module-oauth2-proxy-provider/CHANGELOG.md create mode 100644 plugins/auth-backend-module-vmware-cloud-provider/CHANGELOG.md diff --git a/.changeset/pre.json b/.changeset/pre.json index 5a151bfc2f..69d9cbf255 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -255,61 +255,130 @@ "@backstage/plugin-xcmetrics": "0.2.45", "@backstage/frontend-test-utils": "0.0.0", "@backstage/plugin-auth-backend-module-atlassian-provider": "0.0.0", - "@backstage/plugin-auth-backend-module-okta-provider": "0.0.0" + "@backstage/plugin-auth-backend-module-okta-provider": "0.0.0", + "@backstage/plugin-auth-backend-module-oauth2-proxy-provider": "0.0.0", + "@backstage/plugin-auth-backend-module-vmware-cloud-provider": "0.0.0" }, "changesets": [ "angry-eagles-end", "angry-gorillas-unite", "angry-walls-despacito", "angry-walls-juggle", + "big-swans-guess", + "blue-meals-chew", + "brave-parents-stare", "brave-socks-raise", "breezy-pans-glow", "bright-eyes-film", + "brown-books-carry", "chatty-actors-live", + "chilled-buses-love", "chilled-terms-breathe", + "chilly-bikes-kick", + "clever-wombats-sneeze", "cold-pans-crash", + "cool-knives-argue", "create-app-1700579510", "create-app-1700607979", "curly-walls-relate", "dry-readers-raise", "eleven-ants-pretend", "empty-dingos-grow", + "empty-fireants-study", + "famous-flies-kick", + "famous-peas-reflect", + "fifty-cameras-share", + "fifty-seas-grab", + "five-feet-call", + "forty-clocks-hug", + "four-needles-watch", + "funny-bobcats-try", "gentle-lies-greet", + "giant-files-fry", + "gold-humans-tease", "gold-shirts-yell", + "gorgeous-snails-admire", "great-rings-type", + "green-seals-play", + "healthy-feet-kick", + "healthy-poets-search", + "hip-berries-begin", + "honest-houses-hide", "hot-wolves-flash", + "hungry-buckets-compare", + "khaki-clocks-happen", + "khaki-hounds-think", "kind-badgers-rush", + "kind-cycles-happen", "large-weeks-accept", + "little-suits-collect", "long-wolves-return", "lovely-terms-search", "lucky-kids-cough", "metal-eggs-smile", "mighty-beans-wink", + "modern-mails-live", "nasty-tips-exercise", + "nervous-dancers-wait", + "nervous-penguins-sort", "perfect-apes-sing", + "perfect-crabs-help", "pink-dryers-repair", "plenty-numbers-enjoy", "polite-knives-build", "poor-pandas-dream", + "pretty-onions-knock", + "pretty-ravens-serve", "proud-flies-travel", + "proud-seahorses-explain", "quick-horses-reply", + "real-bees-thank", "renovate-07b1766", "renovate-169bdc2", + "renovate-1ed81a0", "renovate-240982c", "renovate-4891ee7", + "renovate-4b1eded", + "renovate-522261c", + "renovate-6075f87", "renovate-6c0fb81", + "renovate-6e5c790", + "renovate-796bd6f", + "renovate-8d8b90d", "renovate-9d2d52e", + "renovate-a6399d6", "renovate-b193efa", + "renovate-c4e012c", "renovate-c7270d5", + "renovate-dee7ad1", "renovate-ead3ba6", "renovate-f5b18be", + "rich-singers-join", + "rude-beans-drop", + "rude-ears-greet", + "silent-rats-reflect", "silly-numbers-wash", + "silver-rocks-deliver", "sixty-adults-kiss", "sixty-houses-agree", + "slow-trees-warn", + "smooth-frogs-decide", + "sour-pumas-reply", "spotty-olives-share", + "stale-bats-end", + "stale-walls-cross", + "strange-suits-glow", + "tame-pants-end", + "tender-peas-smoke", + "thick-snails-travel", + "thirty-fireants-cheer", "tiny-cobras-look", + "tricky-donkeys-do", "tricky-islands-wonder", "twenty-beans-laugh", - "violet-zebras-thank" + "unlucky-clouds-build", + "violet-zebras-thank", + "warm-plums-beg", + "wicked-elephants-think" ] } diff --git a/docs/releases/v1.21.0-next.2-changelog.md b/docs/releases/v1.21.0-next.2-changelog.md new file mode 100644 index 0000000000..ba5c3c007d --- /dev/null +++ b/docs/releases/v1.21.0-next.2-changelog.md @@ -0,0 +1,3088 @@ +# Release v1.21.0-next.2 + +## @backstage/catalog-client@1.5.0-next.0 + +### Minor Changes + +- 38340678c3: The internals of `CatalogClient` are now auto-generated using the `backstage-repo-tools schema openapi generate-client` command. + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/cli@0.25.0-next.1 + +### Minor Changes + +- 38340678c3: Updates the ESLint config to ignore issues created by generated files in `**/src/generated/**`. + +### Patch Changes + +- 0ffee55010: Toned down the warning message when git is not found +- c6f3743172: Added a warning when starting a standalone backend plugin that hasn't been updated to the new backend system. +- 3e358b0dff: Added deprecation warning for React Router v6 beta, please make sure you have migrated your apps to use React Router v6 stable as support for the beta version will be removed. See the [migration tutorial](https://backstage.io/docs/tutorials/react-router-stable-migration) for more information. +- 8056425e09: Updated dependency `@typescript-eslint/eslint-plugin` to `6.12.0`. +- 33e96e59e7: Switched the `@typescript-eslint/eslint-plugin` dependency back to using a `^` version range. +- Updated dependencies + - @backstage/eslint-plugin@0.1.4-next.0 + - @backstage/integration@1.8.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/cli-node@0.2.0 + - @backstage/config@1.1.1 + - @backstage/config-loader@1.5.3 + - @backstage/errors@1.2.3 + - @backstage/release-manifests@0.0.11 + - @backstage/types@1.1.1 + +## @backstage/frontend-app-api@0.4.0-next.1 + +### Minor Changes + +- e539735435: Updated core extension structure to make space for the sign-in page by adding `core.router`. + +### Patch Changes + +- 5eb6b8a7bc: Added the nav logo extension for customization of sidebar logo +- 1f12fb762c: Create a core components extension that allows adopters to override core app components such as `Progress`, `BootErrorPage`, `NotFoundErrorPage` and `ErrorBoundaryFallback`. +- 59709286b3: Collect and register feature flags from plugins and extension overrides. +- f27ee7d937: Migrate analytics route tracker component. +- a5a04739e1: Updates to provide `node` to extension factories instead of `id` and `source`. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## @backstage/frontend-plugin-api@0.4.0-next.1 + +### Minor Changes + +- a5a04739e1: The extension `factory` function now longer receives `id` or `source`, but instead now provides the extension's `AppNode` as `node`. The `ExtensionBoundary` component has also been updated to receive a `node` prop rather than `id` and `source`. + +### Patch Changes + +- 5eb6b8a7bc: Added the nav logo extension for customization of sidebar logo +- 1f12fb762c: Create factories for overriding default core components extensions. +- 59709286b3: Add feature flags to plugins and extension overrides. +- e539735435: Added `createSignInPageExtension`. +- f27ee7d937: Migrate analytics api and context files. +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## @backstage/repo-tools@0.5.0-next.0 + +### Minor Changes + +- aea8f8d329: **BREAKING**: API Reports generated for sub-path exports now place the name as a suffix rather than prefix, for example `api-report-alpha.md` instead of `alpha-api-report.md`. When upgrading to this version you'll need to re-create any such API reports and delete the old ones. +- 38340678c3: Adds a new command `schema openapi generate-client` that creates a Typescript client with Backstage flavor, including the discovery API and fetch API. This command doesn't currently generate a complete client and needs to be wrapped or exported manually by a separate Backstage plugin. See `@backstage/catalog-client/src/generated` for example output. + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/cli-node@0.2.0 + - @backstage/errors@1.2.3 + +## @techdocs/cli@1.8.0-next.1 + +### Minor Changes + +- b2dccad7b3: Support passing additional `mkdocs-server` CLI parameters (`--dirtyreload`, `--strict` and `--clean`) when run in containerized mode. + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs-node@1.11.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + +## @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.0-next.0 + +### Minor Changes + +- 271aa12c7c: Release of `oauth2-proxy-provider` plugin + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.1 + +## @backstage/plugin-auth-backend-module-vmware-cloud-provider@0.1.0-next.0 + +### Minor Changes + +- ed02c69a3c: Add VMware Cloud auth backend module provider + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-auth-node@0.4.2-next.1 + +## @backstage/plugin-azure-devops-backend@0.5.0-next.1 + +### Minor Changes + +- 844969cd97: **BREAKING** New `fromConfig` static method must be used now when creating an instance of the `AzureDevOpsApi` + + Added support for using the `AzureDevOpsCredentialsProvider` + +### Patch Changes + +- 043b724c56: Introduced new `AzureDevOpsAnnotatorProcessor` that adds the needed annotations automatically. Also, moved constants to common package so they can be shared more easily +- Updated dependencies + - @backstage/plugin-azure-devops-common@0.3.2-next.0 + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.5.1-next.1 + +## @backstage/plugin-catalog@1.16.0-next.2 + +### Minor Changes + +- e223f2264d: Properly support both function- and string-form visibility filter expressions in the new extensions exported via `/alpha`. + +### Patch Changes + +- 53600976bb: Ensure that passed-in icons are taken advantage of in the presentation API +- a5a04739e1: Internal refactor of alpha exports due to a change in how extension factories are defined. +- 78a10bb085: Adding in spec.type chip to search results for clarity +- fb8f3bdbc2: Updated alpha translation message keys to use nested format and camel case. +- 531e1a2a79: Updated alpha plugin to include the `unregisterRedirect` external route. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/plugin-search-react@1.7.4-next.1 + - @backstage/core-compat-api@0.0.1-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-scaffolder-common@1.4.3 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-home@0.6.0-next.1 + +### Minor Changes + +- 5a317f59c0: Added view of entities grouped by kind to make it easier to distinguish entities with different kind but same name + +### Patch Changes + +- 2b725913c1: Updated dependency `@rjsf/utils` to `5.14.3`. + Updated dependency `@rjsf/core` to `5.14.3`. + Updated dependency `@rjsf/material-ui` to `5.14.3`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.3`. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/plugin-home-react@0.1.6-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-pagerduty@0.7.0-next.1 + +### Minor Changes + +- 5fca16fdf6: This package has been deprecated, consider using [@pagerduty/backstage-plugin](https://github.com/pagerduty/backstage-plugin) instead. + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-home-react@0.1.6-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/app-defaults@1.4.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/plugin-permission-react@0.4.18-next.1 + - @backstage/theme@0.5.0-next.0 + +## @backstage/backend-app-api@0.5.9-next.1 + +### Patch Changes + +- 1da5f434f3: Ensure redaction of secrets that have accidental extra whitespace around them +- 9f8f266ff4: Add redacting for secrets in stack traces of logs +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/cli-common@0.1.13 + - @backstage/cli-node@0.2.0 + - @backstage/config@1.1.1 + - @backstage/config-loader@1.5.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-permission-node@0.7.19-next.1 + +## @backstage/backend-common@0.20.0-next.1 + +### Patch Changes + +- 2666675457: Updated dependency `@google-cloud/storage` to `^7.0.0`. +- Updated dependencies + - @backstage/backend-app-api@0.5.9-next.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-dev-utils@0.1.2 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/config-loader@1.5.3 + - @backstage/errors@1.2.3 + - @backstage/integration-aws-node@0.1.8 + - @backstage/types@1.1.1 + +## @backstage/backend-defaults@0.2.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-app-api@0.5.9-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + +## @backstage/backend-openapi-utils@0.1.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/backend-plugin-api@0.6.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-permission-common@0.7.10 + +## @backstage/backend-tasks@0.5.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/backend-test-utils@0.2.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-app-api@0.5.9-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + +## @backstage/core-app-api@1.11.2-next.1 + +### Patch Changes + +- 3e358b0dff: Added deprecation warning for React Router v6 beta, please make sure you have migrated your apps to use React Router v6 stable as support for the beta version will be removed. See the [migration tutorial](https://backstage.io/docs/tutorials/react-router-stable-migration) for more information. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## @backstage/core-compat-api@0.0.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/core-app-api@1.11.2-next.1 + +## @backstage/core-components@0.13.9-next.1 + +### Patch Changes + +- e8f2acef80: Added a new `/testUtils` sub-path that initially exports a `mockBreakpoint` helper. +- 07dfdf3702: Updated dependency `linkifyjs` to `4.1.3`. +- a518c5a25b: Updated dependency `@react-hookz/web` to `^23.0.0`. +- f291757e70: Update `linkify-react` to version `4.1.3` +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/version-bridge@1.0.7 + +## @backstage/core-plugin-api@1.8.1-next.1 + +### Patch Changes + +- 0c93dc37b2: The `createTranslationRef` function from the `/alpha` subpath can now also accept a nested object structure of default translation messages, which will be flatted using `.` separators. +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## @backstage/create-app@0.5.8-next.2 + +### Patch Changes + +- 375b6f7d68: CircelCI plugin moved permanently +- Updated dependencies + - @backstage/cli-common@0.1.13 + +## @backstage/dev-utils@1.0.25-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/app-defaults@1.4.6-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/eslint-plugin@0.1.4-next.0 + +### Patch Changes + +- 107dc46ab1: The `no-undeclared-imports` rule will now prefer using version queries that already exist en the repo for the same dependency type when installing new packages. + +## @backstage/frontend-test-utils@0.1.0-next.1 + +### Patch Changes + +- e539735435: Updates for `core.router` addition. +- c21c9cf07b: Re-export mock API implementations as well as `TestApiProvider`, `TestApiRegistry`, `withLogCollector`, and `setupRequestMockHandlers` from `@backstage/test-utils`. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/frontend-app-api@0.4.0-next.1 + - @backstage/test-utils@1.4.6-next.1 + - @backstage/types@1.1.1 + +## @backstage/integration@1.8.0-next.1 + +### Patch Changes + +- 99fb54183b: Updated dependency `@azure/identity` to `^4.0.0`. +- Updated dependencies + - @backstage/config@1.1.1 + +## @backstage/integration-react@1.1.22-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/config@1.1.1 + +## @backstage/test-utils@1.4.6-next.1 + +### Patch Changes + +- e8f2acef80: Deprecated `mockBreakpoint`, as it is now available from `@backstage/core-components/testUtils` instead. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/plugin-permission-react@0.4.18-next.1 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.10 + +## @backstage/plugin-adr@0.6.11-next.1 + +### Patch Changes + +- fb8f3bdbc2: Updated alpha translation message keys to use nested format and camel case. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-search-react@1.7.4-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-adr-common@0.2.18-next.1 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-adr-backend@0.4.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-adr-common@0.2.18-next.1 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-adr-common@0.2.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-airbrake@0.3.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/test-utils@1.4.6-next.1 + - @backstage/dev-utils@1.0.25-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-airbrake-backend@0.3.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + +## @backstage/plugin-allure@0.1.44-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-analytics-module-ga@0.1.36-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-analytics-module-ga4@0.1.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-analytics-module-newrelic-browser@0.0.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/config@1.1.1 + +## @backstage/plugin-apache-airflow@0.2.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + +## @backstage/plugin-api-docs@0.10.2-next.2 + +### Patch Changes + +- e16e7ce6a5: Updated dependency `@asyncapi/react-component` to `1.2.2`. +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-catalog@1.16.0-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-apollo-explorer@0.1.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-app-backend@0.3.56-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/config-loader@1.5.3 + - @backstage/types@1.1.1 + - @backstage/plugin-app-node@0.1.8-next.1 + +## @backstage/plugin-app-node@0.1.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.1 + +## @backstage/plugin-auth-backend@0.20.1-next.1 + +### Patch Changes + +- 7ac25759a5: `oauth2-proxy` auth implementation has been moved to `@backstage/plugin-auth-backend-module-oauth2-proxy-provider` +- bcbbf8e042: Updated dependency `@google-cloud/firestore` to `^7.0.0`. +- Updated dependencies + - @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.0-next.0 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/plugin-auth-backend-module-atlassian-provider@0.1.0-next.1 + - @backstage/plugin-auth-backend-module-github-provider@0.1.5-next.1 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.1.5-next.1 + - @backstage/plugin-auth-backend-module-google-provider@0.1.5-next.1 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.1.5-next.1 + - @backstage/plugin-auth-backend-module-okta-provider@0.0.1-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.2-next.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-catalog-node@1.5.1-next.1 + +## @backstage/plugin-auth-backend-module-atlassian-provider@0.1.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + +## @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + +## @backstage/plugin-auth-backend-module-github-provider@0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + +## @backstage/plugin-auth-backend-module-gitlab-provider@0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + +## @backstage/plugin-auth-backend-module-google-provider@0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + +## @backstage/plugin-auth-backend-module-microsoft-provider@0.1.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + +## @backstage/plugin-auth-backend-module-oauth2-provider@0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + +## @backstage/plugin-auth-backend-module-okta-provider@0.0.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + +## @backstage/plugin-auth-backend-module-pinniped-provider@0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + +## @backstage/plugin-auth-node@0.4.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-azure-devops@0.3.10-next.1 + +### Patch Changes + +- 043b724c56: Introduced new `AzureDevOpsAnnotatorProcessor` that adds the needed annotations automatically. Also, moved constants to common package so they can be shared more easily +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-azure-devops-common@0.3.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-azure-devops-common@0.3.2-next.0 + +### Patch Changes + +- 043b724c56: Introduced new `AzureDevOpsAnnotatorProcessor` that adds the needed annotations automatically. Also, moved constants to common package so they can be shared more easily + +## @backstage/plugin-azure-sites@0.1.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-azure-sites-common@0.1.1 + +## @backstage/plugin-azure-sites-backend@0.1.18-next.1 + +### Patch Changes + +- 99fb54183b: Updated dependency `@azure/identity` to `^4.0.0`. +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-azure-sites-common@0.1.1 + +## @backstage/plugin-badges@0.2.52-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-badges-backend@0.3.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.1 + +## @backstage/plugin-bazaar@0.2.20-next.2 + +### Patch Changes + +- 5d796829bb: Internalize 'AboutField' to break catalog dependency +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-bazaar-backend@0.3.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.1 + +## @backstage/plugin-bitbucket-cloud-common@0.2.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + +## @backstage/plugin-bitrise@0.1.55-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-catalog-backend@1.15.1-next.1 + +### Patch Changes + +- 38340678c3: Update the OpenAPI spec to support the use of `openapi-generator`. +- 7123c58b3d: Updated dependency `@types/glob` to `^8.0.0`. +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-openapi-utils@0.1.1-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.5.1-next.1 + - @backstage/plugin-events-node@0.2.17-next.1 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.1 + - @backstage/plugin-search-backend-module-catalog@0.1.12-next.1 + +## @backstage/plugin-catalog-backend-module-aws@0.3.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration-aws-node@0.1.8 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.5.1-next.1 + +## @backstage/plugin-catalog-backend-module-azure@0.1.27-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.5.1-next.1 + +## @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.1-next.1 + +### Patch Changes + +- eb44e92898: Support authenticated backends +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-openapi-utils@0.1.1-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-node@1.5.1-next.1 + +## @backstage/plugin-catalog-backend-module-bitbucket@0.2.23-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-bitbucket-cloud-common@0.2.15-next.1 + - @backstage/plugin-catalog-node@1.5.1-next.1 + +## @backstage/plugin-catalog-backend-module-bitbucket-cloud@0.1.23-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-bitbucket-cloud-common@0.2.15-next.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.5.1-next.1 + - @backstage/plugin-events-node@0.2.17-next.1 + +## @backstage/plugin-catalog-backend-module-bitbucket-server@0.1.21-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-node@1.5.1-next.1 + +## @backstage/plugin-catalog-backend-module-gcp@0.1.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-node@1.5.1-next.1 + +## @backstage/plugin-catalog-backend-module-gerrit@0.1.24-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-node@1.5.1-next.1 + +## @backstage/plugin-catalog-backend-module-github@0.4.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.15.1-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.5.1-next.1 + - @backstage/plugin-events-node@0.2.17-next.1 + +## @backstage/plugin-catalog-backend-module-github-org@0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-backend-module-github@0.4.6-next.1 + - @backstage/plugin-catalog-node@1.5.1-next.1 + +## @backstage/plugin-catalog-backend-module-gitlab@0.3.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-node@1.5.1-next.1 + +## @backstage/plugin-catalog-backend-module-incremental-ingestion@0.4.12-next.1 + +### Patch Changes + +- 43b2eb8f70: Ensure that cursors always come back as JSON on sqlite too +- Updated dependencies + - @backstage/plugin-catalog-backend@1.15.1-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-node@1.5.1-next.1 + - @backstage/plugin-events-node@0.2.17-next.1 + - @backstage/plugin-permission-common@0.7.10 + +## @backstage/plugin-catalog-backend-module-ldap@0.5.23-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.5.1-next.1 + +## @backstage/plugin-catalog-backend-module-msgraph@0.5.15-next.1 + +### Patch Changes + +- 99fb54183b: Updated dependency `@azure/identity` to `^4.0.0`. +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.5.1-next.1 + +## @backstage/plugin-catalog-backend-module-openapi@0.1.25-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.15.1-next.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.5.1-next.1 + +## @backstage/plugin-catalog-backend-module-puppetdb@0.1.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-node@1.5.1-next.1 + +## @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.5.1-next.1 + - @backstage/plugin-scaffolder-common@1.4.3 + +## @backstage/plugin-catalog-backend-module-unprocessed@0.3.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-auth-node@0.4.2-next.1 + +## @backstage/plugin-catalog-graph@0.3.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog-import@0.10.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/integration@1.8.0-next.1 + - @backstage/core-compat-api@0.0.1-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.18 + +## @backstage/plugin-catalog-node@1.5.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + +## @backstage/plugin-catalog-react@1.9.2-next.1 + +### Patch Changes + +- 53600976bb: Ensure that passed-in icons are taken advantage of in the presentation API + +- 08d9e67199: Add default icon for kind resource. + +- a5a04739e1: Internal refactor of alpha exports due to a change in how extension factories are defined. + +- e223f2264d: Breaking alpha-API change to entity visibility filter functions to accept a bare entity as their first argument, instead of an object with an entity property. + + Functions that accept such filters now also support the string expression form of filters. + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/plugin-permission-react@0.4.18-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-permission-common@0.7.10 + +## @backstage/plugin-catalog-unprocessed-entities@0.1.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-cicd-statistics@0.1.30-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-cicd-statistics-module-gitlab@0.1.24-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-cicd-statistics@0.1.30-next.1 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-circleci@0.3.28-next.1 + +### Patch Changes + +- 375b6f7d68: CircelCI plugin moved permanently +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-cloudbuild@0.3.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-code-climate@0.1.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-code-coverage@0.2.21-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-code-coverage-backend@0.2.22-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.1 + +## @backstage/plugin-codescene@0.1.20-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-config-schema@0.1.48-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-cost-insights@0.12.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-cost-insights-common@0.1.2 + +## @backstage/plugin-devtools@0.1.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-permission-react@0.4.18-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-devtools-common@0.1.6 + +## @backstage/plugin-devtools-backend@0.2.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/config-loader@1.5.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-devtools-common@0.1.6 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.1 + +## @backstage/plugin-dynatrace@8.0.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-entity-feedback@0.2.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-entity-feedback-common@0.1.3 + +## @backstage/plugin-entity-feedback-backend@0.2.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-entity-feedback-common@0.1.3 + +## @backstage/plugin-entity-validation@0.1.13-next.1 + +### Patch Changes + +- a518c5a25b: Updated dependency `@react-hookz/web` to `^23.0.0`. +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-catalog-common@1.0.18 + +## @backstage/plugin-events-backend@0.2.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.17-next.1 + +## @backstage/plugin-events-backend-module-aws-sqs@0.2.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-events-node@0.2.17-next.1 + +## @backstage/plugin-events-backend-module-azure@0.1.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/plugin-events-node@0.2.17-next.1 + +## @backstage/plugin-events-backend-module-bitbucket-cloud@0.1.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/plugin-events-node@0.2.17-next.1 + +## @backstage/plugin-events-backend-module-gerrit@0.1.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/plugin-events-node@0.2.17-next.1 + +## @backstage/plugin-events-backend-module-github@0.1.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.17-next.1 + +## @backstage/plugin-events-backend-module-gitlab@0.1.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.17-next.1 + +## @backstage/plugin-events-backend-test-utils@0.1.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.2.17-next.1 + +## @backstage/plugin-events-node@0.2.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.1 + +## @backstage/plugin-explore@0.4.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-search-react@1.7.4-next.1 + - @backstage/plugin-explore-react@0.0.34-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-explore-backend@0.0.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-backend-module-explore@0.1.12-next.1 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-explore-react@0.0.34-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-explore-common@0.0.2 + +## @backstage/plugin-firehydrant@0.2.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-fossa@0.2.60-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-gcalendar@0.3.21-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-gcp-projects@0.3.44-next.1 + +### Patch Changes + +- a518c5a25b: Updated dependency `@react-hookz/web` to `^23.0.0`. +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-git-release-manager@0.3.40-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-github-actions@0.6.9-next.1 + +### Patch Changes + +- 08d7e4676a: Github Workflow Runs UI is modified to show in optional Card view instead of table, with branch selection option +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-github-deployments@0.1.59-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-github-issues@0.2.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-github-pull-requests-board@0.1.22-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-gitops-profiles@0.3.43-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-gocd@0.1.34-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-graphiql@0.3.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/core-compat-api@0.0.1-next.1 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-graphql-voyager@0.1.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-home-react@0.1.6-next.1 + +### Patch Changes + +- 2b725913c1: Updated dependency `@rjsf/utils` to `5.14.3`. + Updated dependency `@rjsf/core` to `5.14.3`. + Updated dependency `@rjsf/material-ui` to `5.14.3`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.3`. +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + +## @backstage/plugin-ilert@0.2.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-jenkins@0.9.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-jenkins-common@0.1.21 + +## @backstage/plugin-jenkins-backend@0.3.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-catalog-node@1.5.1-next.1 + - @backstage/plugin-jenkins-common@0.1.21 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.1 + +## @backstage/plugin-kafka@0.3.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-kafka-backend@0.3.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-kubernetes@0.11.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + - @backstage/plugin-kubernetes-react@0.1.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-kubernetes-backend@0.14.0-next.1 + +### Patch Changes + +- ae94d3ce6f: Updated dependency `@aws-crypto/sha256-js` to `^5.0.0`. +- 99fb54183b: Updated dependency `@azure/identity` to `^4.0.0`. +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration-aws-node@0.1.8 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-catalog-node@1.5.1-next.1 + - @backstage/plugin-kubernetes-node@0.1.2-next.1 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.1 + +## @backstage/plugin-kubernetes-cluster@0.0.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + - @backstage/plugin-kubernetes-react@0.1.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-kubernetes-common@0.7.2-next.1 + +### Patch Changes + +- 5d796829bb: Remove unused dependency +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.10 + +## @backstage/plugin-kubernetes-node@0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-kubernetes-react@0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-lighthouse@0.4.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-lighthouse-common@0.1.4 + +## @backstage/plugin-lighthouse-backend@0.3.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-node@1.5.1-next.1 + - @backstage/plugin-lighthouse-common@0.1.4 + +## @backstage/plugin-linguist@0.1.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-linguist-common@0.1.2 + +## @backstage/plugin-linguist-backend@0.5.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-catalog-node@1.5.1-next.1 + - @backstage/plugin-linguist-common@0.1.2 + +## @backstage/plugin-microsoft-calendar@0.1.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-newrelic@0.3.43-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-newrelic-dashboard@0.3.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-nomad@0.1.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-nomad-backend@0.1.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-octopus-deploy@0.2.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-opencost@0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-org@0.6.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-org-react@0.1.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-periskop@0.1.26-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-periskop-backend@0.2.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + +## @backstage/plugin-permission-backend@0.5.31-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.1 + +## @backstage/plugin-permission-backend-module-allow-all-policy@0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.1 + +## @backstage/plugin-permission-node@0.7.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-permission-common@0.7.10 + +## @backstage/plugin-permission-react@0.4.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-permission-common@0.7.10 + +## @backstage/plugin-playlist@0.2.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-search-react@1.7.4-next.1 + - @backstage/plugin-permission-react@0.4.18-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-playlist-common@0.1.12 + +## @backstage/plugin-playlist-backend@0.3.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.1 + - @backstage/plugin-playlist-common@0.1.12 + +## @backstage/plugin-proxy-backend@0.4.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + +## @backstage/plugin-puppetdb@0.1.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-rollbar@0.4.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-rollbar-backend@0.1.53-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/config@1.1.1 + +## @backstage/plugin-scaffolder@1.16.2-next.1 + +### Patch Changes + +- 2b725913c1: Updated dependency `@rjsf/utils` to `5.14.3`. + Updated dependency `@rjsf/core` to `5.14.3`. + Updated dependency `@rjsf/material-ui` to `5.14.3`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.3`. +- a518c5a25b: Updated dependency `@react-hookz/web` to `^23.0.0`. +- b5fa6918dc: Fixing `headerOptions` not being passed through the `TemplatePage` component +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/plugin-scaffolder-react@1.6.2-next.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/plugin-permission-react@0.4.18-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-scaffolder-common@1.4.3 + +## @backstage/plugin-scaffolder-backend@1.19.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.15.1-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.5-next.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.5.1-next.1 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.1 + - @backstage/plugin-scaffolder-common@1.4.3 + - @backstage/plugin-scaffolder-node@0.2.9-next.1 + +## @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.2.9-next.1 + +## @backstage/plugin-scaffolder-backend-module-cookiecutter@0.2.32-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.2.9-next.1 + +## @backstage/plugin-scaffolder-backend-module-gitlab@0.2.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-scaffolder-node@0.2.9-next.1 + +## @backstage/plugin-scaffolder-backend-module-rails@0.4.25-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.2.9-next.1 + +## @backstage/plugin-scaffolder-backend-module-sentry@0.1.16-next.1 + +### Patch Changes + +- 7f8a801e6d: Added examples for `sentry:project:create` scaffolder action and unit tests. +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-scaffolder-node@0.2.9-next.1 + +## @backstage/plugin-scaffolder-backend-module-yeoman@0.2.29-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.2.9-next.1 + +## @backstage/plugin-scaffolder-node@0.2.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-common@1.4.3 + +## @backstage/plugin-scaffolder-react@1.6.2-next.1 + +### Patch Changes + +- fa66d1b5b3: Fixed bug in `ReviewState` where `enum` value was displayed in step review instead of the corresponding label when using `enumNames` +- 2aee53bbeb: Add horizontal slider if stepper overflows +- 2b725913c1: Updated dependency `@rjsf/utils` to `5.14.3`. + Updated dependency `@rjsf/core` to `5.14.3`. + Updated dependency `@rjsf/material-ui` to `5.14.3`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.3`. +- a518c5a25b: Updated dependency `@react-hookz/web` to `^23.0.0`. +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-scaffolder-common@1.4.3 + +## @backstage/plugin-search@1.4.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-search-react@1.7.4-next.1 + - @backstage/core-compat-api@0.0.1-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-search-backend@1.4.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-openapi-utils@0.1.1-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.1 + - @backstage/plugin-search-backend-node@1.2.12-next.1 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-search-backend-module-catalog@0.1.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.5.1-next.1 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-search-backend-node@1.2.12-next.1 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-search-backend-module-elasticsearch@1.3.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/integration-aws-node@0.1.8 + - @backstage/plugin-search-backend-node@1.2.12-next.1 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-search-backend-module-explore@0.1.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-backend-node@1.2.12-next.1 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-search-backend-module-pg@0.5.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-search-backend-node@1.2.12-next.1 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-search-backend-module-stack-overflow-collator@0.1.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-search-backend-node@1.2.12-next.1 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-search-backend-module-techdocs@0.1.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/plugin-techdocs-node@1.11.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.5.1-next.1 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-search-backend-node@1.2.12-next.1 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-search-backend-node@1.2.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-search-react@1.7.4-next.1 + +### Patch Changes + +- a5a04739e1: Internal refactor of alpha exports due to a change in how extension factories are defined. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-sentry@0.5.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-shortcuts@0.3.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-sonarqube@0.7.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-sonarqube-react@0.1.11-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-sonarqube-backend@0.2.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-sonarqube-react@0.1.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-splunk-on-call@0.4.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-stack-overflow@0.1.23-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-search-react@1.7.4-next.1 + - @backstage/plugin-home-react@0.1.6-next.1 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-stack-overflow-backend@0.2.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-search-backend-module-stack-overflow-collator@0.1.1-next.1 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-stackstorm@0.1.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-tech-insights@0.3.20-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + +## @backstage/plugin-tech-insights-backend@0.5.22-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + - @backstage/plugin-tech-insights-node@0.4.14-next.1 + +## @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.40-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-tech-insights-common@0.2.12 + - @backstage/plugin-tech-insights-node@0.4.14-next.1 + +## @backstage/plugin-tech-insights-node@0.4.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + +## @backstage/plugin-tech-radar@0.6.11-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/core-compat-api@0.0.1-next.1 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-techdocs@1.9.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-search-react@1.7.4-next.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/core-compat-api@0.0.1-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/plugin-techdocs-react@1.1.14-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-techdocs-addons-test-utils@1.0.25-next.2 + +### Patch Changes + +- 5d796829bb: Remove unnecessary catalog dependency +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-catalog@1.16.0-next.2 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/test-utils@1.4.6-next.1 + - @backstage/plugin-search-react@1.7.4-next.1 + - @backstage/plugin-techdocs@1.9.2-next.2 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/plugin-techdocs-react@1.1.14-next.1 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-techdocs-backend@1.9.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/integration@1.8.0-next.1 + - @backstage/plugin-techdocs-node@1.11.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-search-backend-module-techdocs@0.1.12-next.1 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-techdocs-module-addons-contrib@1.1.3-next.1 + +### Patch Changes + +- a518c5a25b: Updated dependency `@react-hookz/web` to `^23.0.0`. +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/plugin-techdocs-react@1.1.14-next.1 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-techdocs-node@1.11.0-next.1 + +### Patch Changes + +- 99fb54183b: Updated dependency `@azure/identity` to `^4.0.0`. +- 2666675457: Updated dependency `@google-cloud/storage` to `^7.0.0`. +- 4f773c15f6: Bumped the default TechDocs docker image version to the latest which was released several month ago +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration-aws-node@0.1.8 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-techdocs-react@1.1.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/version-bridge@1.0.7 + +## @backstage/plugin-todo@0.2.32-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-todo-backend@0.3.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-openapi-utils@0.1.1-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-node@1.5.1-next.1 + +## @backstage/plugin-user-settings@0.7.14-next.2 + +### Patch Changes + +- fb8f3bdbc2: Updated alpha translation message keys to use nested format and camel case. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/core-compat-api@0.0.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-user-settings-backend@0.2.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + +## @backstage/plugin-vault@0.1.23-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-vault-backend@0.4.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-vault-node@0.1.1-next.1 + +## @backstage/plugin-vault-node@0.1.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.1 + +## @backstage/plugin-xcmetrics@0.2.46-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## example-app@0.2.90-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-app-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/cli@0.25.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-catalog@1.16.0-next.2 + - @backstage/plugin-scaffolder-react@1.6.2-next.1 + - @backstage/plugin-home@0.6.0-next.1 + - @backstage/plugin-github-actions@0.6.9-next.1 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/plugin-search-react@1.7.4-next.1 + - @backstage/plugin-azure-devops@0.3.10-next.1 + - @backstage/plugin-scaffolder@1.16.2-next.1 + - @backstage/plugin-api-docs@0.10.2-next.2 + - @backstage/plugin-gcp-projects@0.3.44-next.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.3-next.1 + - @backstage/plugin-user-settings@0.7.14-next.2 + - @backstage/plugin-adr@0.6.11-next.1 + - @backstage/plugin-pagerduty@0.7.0-next.1 + - @backstage/plugin-catalog-import@0.10.4-next.2 + - @backstage/plugin-explore@0.4.14-next.1 + - @backstage/plugin-graphiql@0.3.1-next.2 + - @backstage/plugin-search@1.4.4-next.2 + - @backstage/plugin-stack-overflow@0.1.23-next.1 + - @backstage/plugin-tech-radar@0.6.11-next.2 + - @backstage/plugin-techdocs@1.9.2-next.2 + - @backstage/app-defaults@1.4.6-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/plugin-airbrake@0.3.28-next.1 + - @backstage/plugin-apache-airflow@0.2.18-next.1 + - @backstage/plugin-azure-sites@0.1.17-next.1 + - @backstage/plugin-badges@0.2.52-next.1 + - @backstage/plugin-catalog-graph@0.3.2-next.1 + - @backstage/plugin-catalog-unprocessed-entities@0.1.6-next.1 + - @backstage/plugin-cloudbuild@0.3.28-next.1 + - @backstage/plugin-code-coverage@0.2.21-next.1 + - @backstage/plugin-cost-insights@0.12.17-next.1 + - @backstage/plugin-devtools@0.1.7-next.1 + - @backstage/plugin-dynatrace@8.0.2-next.1 + - @backstage/plugin-entity-feedback@0.2.11-next.1 + - @backstage/plugin-gcalendar@0.3.21-next.1 + - @backstage/plugin-gocd@0.1.34-next.1 + - @backstage/plugin-jenkins@0.9.3-next.1 + - @backstage/plugin-kafka@0.3.28-next.1 + - @backstage/plugin-kubernetes@0.11.3-next.1 + - @backstage/plugin-kubernetes-cluster@0.0.4-next.1 + - @backstage/plugin-lighthouse@0.4.13-next.1 + - @backstage/plugin-linguist@0.1.13-next.1 + - @backstage/plugin-microsoft-calendar@0.1.10-next.1 + - @backstage/plugin-newrelic@0.3.43-next.1 + - @backstage/plugin-newrelic-dashboard@0.3.3-next.1 + - @backstage/plugin-nomad@0.1.9-next.1 + - @backstage/plugin-octopus-deploy@0.2.10-next.1 + - @backstage/plugin-org@0.6.18-next.1 + - @backstage/plugin-playlist@0.2.2-next.1 + - @backstage/plugin-puppetdb@0.1.11-next.1 + - @backstage/plugin-rollbar@0.4.28-next.1 + - @backstage/plugin-sentry@0.5.13-next.1 + - @backstage/plugin-shortcuts@0.3.17-next.1 + - @backstage/plugin-stackstorm@0.1.9-next.1 + - @backstage/plugin-tech-insights@0.3.20-next.1 + - @backstage/plugin-techdocs-react@1.1.14-next.1 + - @backstage/plugin-todo@0.2.32-next.1 + - @backstage/plugin-permission-react@0.4.18-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-search-common@1.2.8 + +## example-app-next@0.0.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/frontend-app-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/cli@0.25.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-catalog@1.16.0-next.2 + - @backstage/plugin-scaffolder-react@1.6.2-next.1 + - @backstage/plugin-home@0.6.0-next.1 + - @backstage/plugin-github-actions@0.6.9-next.1 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/plugin-search-react@1.7.4-next.1 + - @backstage/plugin-azure-devops@0.3.10-next.1 + - @backstage/plugin-scaffolder@1.16.2-next.1 + - @backstage/plugin-api-docs@0.10.2-next.2 + - @backstage/plugin-gcp-projects@0.3.44-next.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.3-next.1 + - @backstage/plugin-user-settings@0.7.14-next.2 + - @backstage/plugin-adr@0.6.11-next.1 + - @backstage/plugin-pagerduty@0.7.0-next.1 + - app-next-example-plugin@0.0.4-next.1 + - @backstage/core-compat-api@0.0.1-next.1 + - @backstage/plugin-catalog-import@0.10.4-next.2 + - @backstage/plugin-explore@0.4.14-next.1 + - @backstage/plugin-graphiql@0.3.1-next.2 + - @backstage/plugin-search@1.4.4-next.2 + - @backstage/plugin-tech-radar@0.6.11-next.2 + - @backstage/plugin-techdocs@1.9.2-next.2 + - @backstage/app-defaults@1.4.6-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/plugin-airbrake@0.3.28-next.1 + - @backstage/plugin-apache-airflow@0.2.18-next.1 + - @backstage/plugin-azure-sites@0.1.17-next.1 + - @backstage/plugin-badges@0.2.52-next.1 + - @backstage/plugin-catalog-graph@0.3.2-next.1 + - @backstage/plugin-catalog-unprocessed-entities@0.1.6-next.1 + - @backstage/plugin-cloudbuild@0.3.28-next.1 + - @backstage/plugin-code-coverage@0.2.21-next.1 + - @backstage/plugin-cost-insights@0.12.17-next.1 + - @backstage/plugin-devtools@0.1.7-next.1 + - @backstage/plugin-dynatrace@8.0.2-next.1 + - @backstage/plugin-entity-feedback@0.2.11-next.1 + - @backstage/plugin-gcalendar@0.3.21-next.1 + - @backstage/plugin-gocd@0.1.34-next.1 + - @backstage/plugin-jenkins@0.9.3-next.1 + - @backstage/plugin-kafka@0.3.28-next.1 + - @backstage/plugin-kubernetes@0.11.3-next.1 + - @backstage/plugin-lighthouse@0.4.13-next.1 + - @backstage/plugin-linguist@0.1.13-next.1 + - @backstage/plugin-microsoft-calendar@0.1.10-next.1 + - @backstage/plugin-newrelic@0.3.43-next.1 + - @backstage/plugin-newrelic-dashboard@0.3.3-next.1 + - @backstage/plugin-octopus-deploy@0.2.10-next.1 + - @backstage/plugin-org@0.6.18-next.1 + - @backstage/plugin-playlist@0.2.2-next.1 + - @backstage/plugin-puppetdb@0.1.11-next.1 + - @backstage/plugin-rollbar@0.4.28-next.1 + - @backstage/plugin-sentry@0.5.13-next.1 + - @backstage/plugin-shortcuts@0.3.17-next.1 + - @backstage/plugin-stackstorm@0.1.9-next.1 + - @backstage/plugin-tech-insights@0.3.20-next.1 + - @backstage/plugin-techdocs-react@1.1.14-next.1 + - @backstage/plugin-todo@0.2.32-next.1 + - @backstage/plugin-permission-react@0.4.18-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-search-common@1.2.8 + +## app-next-example-plugin@0.0.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + +## example-backend@0.2.90-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-backend@0.20.1-next.1 + - @backstage/plugin-catalog-backend@1.15.1-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/plugin-azure-devops-backend@0.5.0-next.1 + - @backstage/plugin-kubernetes-backend@0.14.0-next.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/plugin-azure-sites-backend@0.1.18-next.1 + - @backstage/backend-common@0.20.0-next.1 + - example-app@0.2.90-next.2 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-adr-backend@0.4.5-next.1 + - @backstage/plugin-app-backend@0.3.56-next.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-badges-backend@0.3.5-next.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.5-next.1 + - @backstage/plugin-catalog-backend-module-unprocessed@0.3.5-next.1 + - @backstage/plugin-catalog-node@1.5.1-next.1 + - @backstage/plugin-code-coverage-backend@0.2.22-next.1 + - @backstage/plugin-devtools-backend@0.2.5-next.1 + - @backstage/plugin-entity-feedback-backend@0.2.5-next.1 + - @backstage/plugin-events-backend@0.2.17-next.1 + - @backstage/plugin-events-node@0.2.17-next.1 + - @backstage/plugin-explore-backend@0.0.18-next.1 + - @backstage/plugin-jenkins-backend@0.3.2-next.1 + - @backstage/plugin-kafka-backend@0.3.6-next.1 + - @backstage/plugin-lighthouse-backend@0.3.5-next.1 + - @backstage/plugin-linguist-backend@0.5.5-next.1 + - @backstage/plugin-nomad-backend@0.1.10-next.1 + - @backstage/plugin-permission-backend@0.5.31-next.1 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.1 + - @backstage/plugin-playlist-backend@0.3.12-next.1 + - @backstage/plugin-proxy-backend@0.4.6-next.1 + - @backstage/plugin-rollbar-backend@0.1.53-next.1 + - @backstage/plugin-scaffolder-backend@1.19.2-next.1 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.9-next.1 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.25-next.1 + - @backstage/plugin-search-backend@1.4.8-next.1 + - @backstage/plugin-search-backend-module-catalog@0.1.12-next.1 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.11-next.1 + - @backstage/plugin-search-backend-module-explore@0.1.12-next.1 + - @backstage/plugin-search-backend-module-pg@0.5.17-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.12-next.1 + - @backstage/plugin-search-backend-node@1.2.12-next.1 + - @backstage/plugin-search-common@1.2.8 + - @backstage/plugin-tech-insights-backend@0.5.22-next.1 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.40-next.1 + - @backstage/plugin-tech-insights-node@0.4.14-next.1 + - @backstage/plugin-techdocs-backend@1.9.1-next.1 + - @backstage/plugin-todo-backend@0.3.6-next.1 + +## example-backend-next@0.0.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.1-next.1 + - @backstage/plugin-catalog-backend@1.15.1-next.1 + - @backstage/plugin-azure-devops-backend@0.5.0-next.1 + - @backstage/plugin-kubernetes-backend@0.14.0-next.1 + - @backstage/backend-defaults@0.2.8-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/plugin-adr-backend@0.4.5-next.1 + - @backstage/plugin-app-backend@0.3.56-next.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-badges-backend@0.3.5-next.1 + - @backstage/plugin-catalog-backend-module-openapi@0.1.25-next.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.5-next.1 + - @backstage/plugin-catalog-backend-module-unprocessed@0.3.5-next.1 + - @backstage/plugin-devtools-backend@0.2.5-next.1 + - @backstage/plugin-entity-feedback-backend@0.2.5-next.1 + - @backstage/plugin-jenkins-backend@0.3.2-next.1 + - @backstage/plugin-lighthouse-backend@0.3.5-next.1 + - @backstage/plugin-linguist-backend@0.5.5-next.1 + - @backstage/plugin-nomad-backend@0.1.10-next.1 + - @backstage/plugin-permission-backend@0.5.31-next.1 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.5-next.1 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.1 + - @backstage/plugin-playlist-backend@0.3.12-next.1 + - @backstage/plugin-proxy-backend@0.4.6-next.1 + - @backstage/plugin-scaffolder-backend@1.19.2-next.1 + - @backstage/plugin-search-backend@1.4.8-next.1 + - @backstage/plugin-search-backend-module-catalog@0.1.12-next.1 + - @backstage/plugin-search-backend-module-explore@0.1.12-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.12-next.1 + - @backstage/plugin-search-backend-node@1.2.12-next.1 + - @backstage/plugin-sonarqube-backend@0.2.10-next.1 + - @backstage/plugin-techdocs-backend@1.9.1-next.1 + - @backstage/plugin-todo-backend@0.3.6-next.1 + +## @backstage/backend-plugin-manager@0.0.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.15.1-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/cli-common@0.1.13 + - @backstage/cli-node@0.2.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-events-backend@0.2.17-next.1 + - @backstage/plugin-events-node@0.2.17-next.1 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.1 + - @backstage/plugin-scaffolder-node@0.2.9-next.1 + - @backstage/plugin-search-backend-node@1.2.12-next.1 + - @backstage/plugin-search-common@1.2.8 + +## e2e-test@0.2.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.8-next.2 + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + +## techdocs-cli-embedded-app@0.2.89-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/cli@0.25.0-next.1 + - @backstage/plugin-catalog@1.16.0-next.2 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/test-utils@1.4.6-next.1 + - @backstage/plugin-techdocs@1.9.2-next.2 + - @backstage/app-defaults@1.4.6-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/plugin-techdocs-react@1.1.14-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + +## @internal/plugin-todo-list@1.0.20-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.0 + +## @internal/plugin-todo-list-backend@1.0.20-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.1 diff --git a/package.json b/package.json index 1b23829f76..15c4a95953 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "@material-ui/pickers@^3.3.10": "patch:@material-ui/pickers@npm%3A3.3.11#./.yarn/patches/@material-ui-pickers-npm-3.3.11-1c8f68ea20.patch", "@material-ui/pickers@^3.2.10": "patch:@material-ui/pickers@npm%3A3.3.11#./.yarn/patches/@material-ui-pickers-npm-3.3.11-1c8f68ea20.patch" }, - "version": "1.21.0-next.1", + "version": "1.21.0-next.2", "dependencies": { "@backstage/errors": "workspace:^", "@manypkg/get-packages": "^1.1.3", diff --git a/packages/app-defaults/CHANGELOG.md b/packages/app-defaults/CHANGELOG.md index 62873d9809..3326a33169 100644 --- a/packages/app-defaults/CHANGELOG.md +++ b/packages/app-defaults/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/app-defaults +## 1.4.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/plugin-permission-react@0.4.18-next.1 + - @backstage/theme@0.5.0-next.0 + ## 1.4.6-next.0 ### Patch Changes diff --git a/packages/app-defaults/package.json b/packages/app-defaults/package.json index 550672d7fb..4857a14492 100644 --- a/packages/app-defaults/package.json +++ b/packages/app-defaults/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/app-defaults", "description": "Provides the default wiring of a Backstage App", - "version": "1.4.6-next.0", + "version": "1.4.6-next.1", "publishConfig": { "access": "public", "main": "dist/index.esm.js", diff --git a/packages/app-next-example-plugin/CHANGELOG.md b/packages/app-next-example-plugin/CHANGELOG.md index 2eff29241d..d47b2cf2eb 100644 --- a/packages/app-next-example-plugin/CHANGELOG.md +++ b/packages/app-next-example-plugin/CHANGELOG.md @@ -1,5 +1,13 @@ # app-next-example-plugin +## 0.0.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + ## 0.0.4-next.0 ### Patch Changes diff --git a/packages/app-next-example-plugin/package.json b/packages/app-next-example-plugin/package.json index b3de8f9a83..4e7e84dbe2 100644 --- a/packages/app-next-example-plugin/package.json +++ b/packages/app-next-example-plugin/package.json @@ -1,7 +1,7 @@ { "name": "app-next-example-plugin", "description": "Backstage internal example plugin", - "version": "0.0.4-next.0", + "version": "0.0.4-next.1", "publishConfig": { "access": "public", "main": "dist/index.esm.js", diff --git a/packages/app-next/CHANGELOG.md b/packages/app-next/CHANGELOG.md index 879025f1a0..ccf60e4e76 100644 --- a/packages/app-next/CHANGELOG.md +++ b/packages/app-next/CHANGELOG.md @@ -1,5 +1,81 @@ # example-app-next +## 0.0.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/frontend-app-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/cli@0.25.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-catalog@1.16.0-next.2 + - @backstage/plugin-scaffolder-react@1.6.2-next.1 + - @backstage/plugin-home@0.6.0-next.1 + - @backstage/plugin-github-actions@0.6.9-next.1 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/plugin-search-react@1.7.4-next.1 + - @backstage/plugin-azure-devops@0.3.10-next.1 + - @backstage/plugin-scaffolder@1.16.2-next.1 + - @backstage/plugin-api-docs@0.10.2-next.2 + - @backstage/plugin-gcp-projects@0.3.44-next.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.3-next.1 + - @backstage/plugin-user-settings@0.7.14-next.2 + - @backstage/plugin-adr@0.6.11-next.1 + - @backstage/plugin-pagerduty@0.7.0-next.1 + - app-next-example-plugin@0.0.4-next.1 + - @backstage/core-compat-api@0.0.1-next.1 + - @backstage/plugin-catalog-import@0.10.4-next.2 + - @backstage/plugin-explore@0.4.14-next.1 + - @backstage/plugin-graphiql@0.3.1-next.2 + - @backstage/plugin-search@1.4.4-next.2 + - @backstage/plugin-tech-radar@0.6.11-next.2 + - @backstage/plugin-techdocs@1.9.2-next.2 + - @backstage/app-defaults@1.4.6-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/plugin-airbrake@0.3.28-next.1 + - @backstage/plugin-apache-airflow@0.2.18-next.1 + - @backstage/plugin-azure-sites@0.1.17-next.1 + - @backstage/plugin-badges@0.2.52-next.1 + - @backstage/plugin-catalog-graph@0.3.2-next.1 + - @backstage/plugin-catalog-unprocessed-entities@0.1.6-next.1 + - @backstage/plugin-cloudbuild@0.3.28-next.1 + - @backstage/plugin-code-coverage@0.2.21-next.1 + - @backstage/plugin-cost-insights@0.12.17-next.1 + - @backstage/plugin-devtools@0.1.7-next.1 + - @backstage/plugin-dynatrace@8.0.2-next.1 + - @backstage/plugin-entity-feedback@0.2.11-next.1 + - @backstage/plugin-gcalendar@0.3.21-next.1 + - @backstage/plugin-gocd@0.1.34-next.1 + - @backstage/plugin-jenkins@0.9.3-next.1 + - @backstage/plugin-kafka@0.3.28-next.1 + - @backstage/plugin-kubernetes@0.11.3-next.1 + - @backstage/plugin-lighthouse@0.4.13-next.1 + - @backstage/plugin-linguist@0.1.13-next.1 + - @backstage/plugin-microsoft-calendar@0.1.10-next.1 + - @backstage/plugin-newrelic@0.3.43-next.1 + - @backstage/plugin-newrelic-dashboard@0.3.3-next.1 + - @backstage/plugin-octopus-deploy@0.2.10-next.1 + - @backstage/plugin-org@0.6.18-next.1 + - @backstage/plugin-playlist@0.2.2-next.1 + - @backstage/plugin-puppetdb@0.1.11-next.1 + - @backstage/plugin-rollbar@0.4.28-next.1 + - @backstage/plugin-sentry@0.5.13-next.1 + - @backstage/plugin-shortcuts@0.3.17-next.1 + - @backstage/plugin-stackstorm@0.1.9-next.1 + - @backstage/plugin-tech-insights@0.3.20-next.1 + - @backstage/plugin-techdocs-react@1.1.14-next.1 + - @backstage/plugin-todo@0.2.32-next.1 + - @backstage/plugin-permission-react@0.4.18-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-search-common@1.2.8 + ## 0.0.4-next.1 ### Patch Changes diff --git a/packages/app-next/package.json b/packages/app-next/package.json index f32b5108ec..8e441b0e4a 100644 --- a/packages/app-next/package.json +++ b/packages/app-next/package.json @@ -1,6 +1,6 @@ { "name": "example-app-next", - "version": "0.0.4-next.1", + "version": "0.0.4-next.2", "private": true, "backstage": { "role": "frontend" diff --git a/packages/app/CHANGELOG.md b/packages/app/CHANGELOG.md index 089aa84942..546a7918d7 100644 --- a/packages/app/CHANGELOG.md +++ b/packages/app/CHANGELOG.md @@ -1,5 +1,81 @@ # example-app +## 0.2.90-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-app-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/cli@0.25.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-catalog@1.16.0-next.2 + - @backstage/plugin-scaffolder-react@1.6.2-next.1 + - @backstage/plugin-home@0.6.0-next.1 + - @backstage/plugin-github-actions@0.6.9-next.1 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/plugin-search-react@1.7.4-next.1 + - @backstage/plugin-azure-devops@0.3.10-next.1 + - @backstage/plugin-scaffolder@1.16.2-next.1 + - @backstage/plugin-api-docs@0.10.2-next.2 + - @backstage/plugin-gcp-projects@0.3.44-next.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.3-next.1 + - @backstage/plugin-user-settings@0.7.14-next.2 + - @backstage/plugin-adr@0.6.11-next.1 + - @backstage/plugin-pagerduty@0.7.0-next.1 + - @backstage/plugin-catalog-import@0.10.4-next.2 + - @backstage/plugin-explore@0.4.14-next.1 + - @backstage/plugin-graphiql@0.3.1-next.2 + - @backstage/plugin-search@1.4.4-next.2 + - @backstage/plugin-stack-overflow@0.1.23-next.1 + - @backstage/plugin-tech-radar@0.6.11-next.2 + - @backstage/plugin-techdocs@1.9.2-next.2 + - @backstage/app-defaults@1.4.6-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/plugin-airbrake@0.3.28-next.1 + - @backstage/plugin-apache-airflow@0.2.18-next.1 + - @backstage/plugin-azure-sites@0.1.17-next.1 + - @backstage/plugin-badges@0.2.52-next.1 + - @backstage/plugin-catalog-graph@0.3.2-next.1 + - @backstage/plugin-catalog-unprocessed-entities@0.1.6-next.1 + - @backstage/plugin-cloudbuild@0.3.28-next.1 + - @backstage/plugin-code-coverage@0.2.21-next.1 + - @backstage/plugin-cost-insights@0.12.17-next.1 + - @backstage/plugin-devtools@0.1.7-next.1 + - @backstage/plugin-dynatrace@8.0.2-next.1 + - @backstage/plugin-entity-feedback@0.2.11-next.1 + - @backstage/plugin-gcalendar@0.3.21-next.1 + - @backstage/plugin-gocd@0.1.34-next.1 + - @backstage/plugin-jenkins@0.9.3-next.1 + - @backstage/plugin-kafka@0.3.28-next.1 + - @backstage/plugin-kubernetes@0.11.3-next.1 + - @backstage/plugin-kubernetes-cluster@0.0.4-next.1 + - @backstage/plugin-lighthouse@0.4.13-next.1 + - @backstage/plugin-linguist@0.1.13-next.1 + - @backstage/plugin-microsoft-calendar@0.1.10-next.1 + - @backstage/plugin-newrelic@0.3.43-next.1 + - @backstage/plugin-newrelic-dashboard@0.3.3-next.1 + - @backstage/plugin-nomad@0.1.9-next.1 + - @backstage/plugin-octopus-deploy@0.2.10-next.1 + - @backstage/plugin-org@0.6.18-next.1 + - @backstage/plugin-playlist@0.2.2-next.1 + - @backstage/plugin-puppetdb@0.1.11-next.1 + - @backstage/plugin-rollbar@0.4.28-next.1 + - @backstage/plugin-sentry@0.5.13-next.1 + - @backstage/plugin-shortcuts@0.3.17-next.1 + - @backstage/plugin-stackstorm@0.1.9-next.1 + - @backstage/plugin-tech-insights@0.3.20-next.1 + - @backstage/plugin-techdocs-react@1.1.14-next.1 + - @backstage/plugin-todo@0.2.32-next.1 + - @backstage/plugin-permission-react@0.4.18-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-search-common@1.2.8 + ## 0.2.90-next.1 ### Patch Changes diff --git a/packages/app/package.json b/packages/app/package.json index 2a8dccc6f1..63a2bdc4b5 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,6 +1,6 @@ { "name": "example-app", - "version": "0.2.90-next.1", + "version": "0.2.90-next.2", "private": true, "backstage": { "role": "frontend" diff --git a/packages/backend-app-api/CHANGELOG.md b/packages/backend-app-api/CHANGELOG.md index 1f19f67eea..e3a25d9514 100644 --- a/packages/backend-app-api/CHANGELOG.md +++ b/packages/backend-app-api/CHANGELOG.md @@ -1,5 +1,24 @@ # @backstage/backend-app-api +## 0.5.9-next.1 + +### Patch Changes + +- 1da5f434f3: Ensure redaction of secrets that have accidental extra whitespace around them +- 9f8f266ff4: Add redacting for secrets in stack traces of logs +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/cli-common@0.1.13 + - @backstage/cli-node@0.2.0 + - @backstage/config@1.1.1 + - @backstage/config-loader@1.5.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-permission-node@0.7.19-next.1 + ## 0.5.9-next.0 ### Patch Changes diff --git a/packages/backend-app-api/package.json b/packages/backend-app-api/package.json index 51e052d8a3..bf1269d0c9 100644 --- a/packages/backend-app-api/package.json +++ b/packages/backend-app-api/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-app-api", "description": "Core API used by Backstage backend apps", - "version": "0.5.9-next.0", + "version": "0.5.9-next.1", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/packages/backend-common/CHANGELOG.md b/packages/backend-common/CHANGELOG.md index 16a4bcafb4..dbe198bdb8 100644 --- a/packages/backend-common/CHANGELOG.md +++ b/packages/backend-common/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/backend-common +## 0.20.0-next.1 + +### Patch Changes + +- 2666675457: Updated dependency `@google-cloud/storage` to `^7.0.0`. +- Updated dependencies + - @backstage/backend-app-api@0.5.9-next.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-dev-utils@0.1.2 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/config-loader@1.5.3 + - @backstage/errors@1.2.3 + - @backstage/integration-aws-node@0.1.8 + - @backstage/types@1.1.1 + ## 0.20.0-next.0 ### Minor Changes diff --git a/packages/backend-common/package.json b/packages/backend-common/package.json index 14436fc1f2..8b30d1ed0f 100644 --- a/packages/backend-common/package.json +++ b/packages/backend-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-common", "description": "Common functionality library for Backstage backends", - "version": "0.20.0-next.0", + "version": "0.20.0-next.1", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/packages/backend-defaults/CHANGELOG.md b/packages/backend-defaults/CHANGELOG.md index 7354e39b9d..5f2063890a 100644 --- a/packages/backend-defaults/CHANGELOG.md +++ b/packages/backend-defaults/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/backend-defaults +## 0.2.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-app-api@0.5.9-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + ## 0.2.8-next.0 ### Patch Changes diff --git a/packages/backend-defaults/package.json b/packages/backend-defaults/package.json index bb2e2b0743..d9ff1ea302 100644 --- a/packages/backend-defaults/package.json +++ b/packages/backend-defaults/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-defaults", "description": "Backend defaults used by Backstage backend apps", - "version": "0.2.8-next.0", + "version": "0.2.8-next.1", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/packages/backend-next/CHANGELOG.md b/packages/backend-next/CHANGELOG.md index 5d035799c5..c1bfc21fba 100644 --- a/packages/backend-next/CHANGELOG.md +++ b/packages/backend-next/CHANGELOG.md @@ -1,5 +1,46 @@ # example-backend-next +## 0.0.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.1-next.1 + - @backstage/plugin-catalog-backend@1.15.1-next.1 + - @backstage/plugin-azure-devops-backend@0.5.0-next.1 + - @backstage/plugin-kubernetes-backend@0.14.0-next.1 + - @backstage/backend-defaults@0.2.8-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/plugin-adr-backend@0.4.5-next.1 + - @backstage/plugin-app-backend@0.3.56-next.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-badges-backend@0.3.5-next.1 + - @backstage/plugin-catalog-backend-module-openapi@0.1.25-next.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.5-next.1 + - @backstage/plugin-catalog-backend-module-unprocessed@0.3.5-next.1 + - @backstage/plugin-devtools-backend@0.2.5-next.1 + - @backstage/plugin-entity-feedback-backend@0.2.5-next.1 + - @backstage/plugin-jenkins-backend@0.3.2-next.1 + - @backstage/plugin-lighthouse-backend@0.3.5-next.1 + - @backstage/plugin-linguist-backend@0.5.5-next.1 + - @backstage/plugin-nomad-backend@0.1.10-next.1 + - @backstage/plugin-permission-backend@0.5.31-next.1 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.5-next.1 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.1 + - @backstage/plugin-playlist-backend@0.3.12-next.1 + - @backstage/plugin-proxy-backend@0.4.6-next.1 + - @backstage/plugin-scaffolder-backend@1.19.2-next.1 + - @backstage/plugin-search-backend@1.4.8-next.1 + - @backstage/plugin-search-backend-module-catalog@0.1.12-next.1 + - @backstage/plugin-search-backend-module-explore@0.1.12-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.12-next.1 + - @backstage/plugin-search-backend-node@1.2.12-next.1 + - @backstage/plugin-sonarqube-backend@0.2.10-next.1 + - @backstage/plugin-techdocs-backend@1.9.1-next.1 + - @backstage/plugin-todo-backend@0.3.6-next.1 + ## 0.0.18-next.0 ### Patch Changes diff --git a/packages/backend-next/package.json b/packages/backend-next/package.json index 2d53421dfc..fd7845252d 100644 --- a/packages/backend-next/package.json +++ b/packages/backend-next/package.json @@ -1,6 +1,6 @@ { "name": "example-backend-next", - "version": "0.0.18-next.0", + "version": "0.0.18-next.1", "main": "dist/index.cjs.js", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/packages/backend-openapi-utils/CHANGELOG.md b/packages/backend-openapi-utils/CHANGELOG.md index 39c12d507f..6df79cdcd8 100644 --- a/packages/backend-openapi-utils/CHANGELOG.md +++ b/packages/backend-openapi-utils/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/backend-openapi-utils +## 0.1.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + ## 0.1.1-next.0 ### Patch Changes diff --git a/packages/backend-openapi-utils/package.json b/packages/backend-openapi-utils/package.json index e3d57c8f27..d97638c05f 100644 --- a/packages/backend-openapi-utils/package.json +++ b/packages/backend-openapi-utils/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-openapi-utils", "description": "OpenAPI typescript support.", - "version": "0.1.1-next.0", + "version": "0.1.1-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/packages/backend-plugin-api/CHANGELOG.md b/packages/backend-plugin-api/CHANGELOG.md index 98d025ca68..9c3f730912 100644 --- a/packages/backend-plugin-api/CHANGELOG.md +++ b/packages/backend-plugin-api/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/backend-plugin-api +## 0.6.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-permission-common@0.7.10 + ## 0.6.8-next.0 ### Patch Changes diff --git a/packages/backend-plugin-api/package.json b/packages/backend-plugin-api/package.json index 81a4694934..bf7cee4e1b 100644 --- a/packages/backend-plugin-api/package.json +++ b/packages/backend-plugin-api/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-plugin-api", "description": "Core API used by Backstage backend plugins", - "version": "0.6.8-next.0", + "version": "0.6.8-next.1", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/packages/backend-plugin-manager/CHANGELOG.md b/packages/backend-plugin-manager/CHANGELOG.md index f826362f2d..e4481c8bac 100644 --- a/packages/backend-plugin-manager/CHANGELOG.md +++ b/packages/backend-plugin-manager/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/backend-plugin-manager +## 0.0.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.15.1-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/cli-common@0.1.13 + - @backstage/cli-node@0.2.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-events-backend@0.2.17-next.1 + - @backstage/plugin-events-node@0.2.17-next.1 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.1 + - @backstage/plugin-scaffolder-node@0.2.9-next.1 + - @backstage/plugin-search-backend-node@1.2.12-next.1 + - @backstage/plugin-search-common@1.2.8 + ## 0.0.4-next.0 ### Patch Changes diff --git a/packages/backend-plugin-manager/package.json b/packages/backend-plugin-manager/package.json index 643a94f3cb..7b3a57cc7b 100644 --- a/packages/backend-plugin-manager/package.json +++ b/packages/backend-plugin-manager/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-plugin-manager", "description": "Backstage plugin management backend", - "version": "0.0.4-next.0", + "version": "0.0.4-next.1", "private": true, "main": "src/index.ts", "types": "src/index.ts", diff --git a/packages/backend-tasks/CHANGELOG.md b/packages/backend-tasks/CHANGELOG.md index 8635aa3e03..c25edab02d 100644 --- a/packages/backend-tasks/CHANGELOG.md +++ b/packages/backend-tasks/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/backend-tasks +## 0.5.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + ## 0.5.13-next.0 ### Patch Changes diff --git a/packages/backend-tasks/package.json b/packages/backend-tasks/package.json index cd71be4190..f577380a7c 100644 --- a/packages/backend-tasks/package.json +++ b/packages/backend-tasks/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-tasks", "description": "Common distributed task management library for Backstage backends", - "version": "0.5.13-next.0", + "version": "0.5.13-next.1", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/packages/backend-test-utils/CHANGELOG.md b/packages/backend-test-utils/CHANGELOG.md index 4931fd8b2f..cd9428b8a0 100644 --- a/packages/backend-test-utils/CHANGELOG.md +++ b/packages/backend-test-utils/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/backend-test-utils +## 0.2.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-app-api@0.5.9-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + ## 0.2.9-next.0 ### Patch Changes diff --git a/packages/backend-test-utils/package.json b/packages/backend-test-utils/package.json index f449be08ed..390bb99954 100644 --- a/packages/backend-test-utils/package.json +++ b/packages/backend-test-utils/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-test-utils", "description": "Test helpers library for Backstage backends", - "version": "0.2.9-next.0", + "version": "0.2.9-next.1", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/packages/backend/CHANGELOG.md b/packages/backend/CHANGELOG.md index 11ddf672a8..f3a446b211 100644 --- a/packages/backend/CHANGELOG.md +++ b/packages/backend/CHANGELOG.md @@ -1,5 +1,63 @@ # example-backend +## 0.2.90-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-backend@0.20.1-next.1 + - @backstage/plugin-catalog-backend@1.15.1-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/plugin-azure-devops-backend@0.5.0-next.1 + - @backstage/plugin-kubernetes-backend@0.14.0-next.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/plugin-azure-sites-backend@0.1.18-next.1 + - @backstage/backend-common@0.20.0-next.1 + - example-app@0.2.90-next.2 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-adr-backend@0.4.5-next.1 + - @backstage/plugin-app-backend@0.3.56-next.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-badges-backend@0.3.5-next.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.5-next.1 + - @backstage/plugin-catalog-backend-module-unprocessed@0.3.5-next.1 + - @backstage/plugin-catalog-node@1.5.1-next.1 + - @backstage/plugin-code-coverage-backend@0.2.22-next.1 + - @backstage/plugin-devtools-backend@0.2.5-next.1 + - @backstage/plugin-entity-feedback-backend@0.2.5-next.1 + - @backstage/plugin-events-backend@0.2.17-next.1 + - @backstage/plugin-events-node@0.2.17-next.1 + - @backstage/plugin-explore-backend@0.0.18-next.1 + - @backstage/plugin-jenkins-backend@0.3.2-next.1 + - @backstage/plugin-kafka-backend@0.3.6-next.1 + - @backstage/plugin-lighthouse-backend@0.3.5-next.1 + - @backstage/plugin-linguist-backend@0.5.5-next.1 + - @backstage/plugin-nomad-backend@0.1.10-next.1 + - @backstage/plugin-permission-backend@0.5.31-next.1 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.1 + - @backstage/plugin-playlist-backend@0.3.12-next.1 + - @backstage/plugin-proxy-backend@0.4.6-next.1 + - @backstage/plugin-rollbar-backend@0.1.53-next.1 + - @backstage/plugin-scaffolder-backend@1.19.2-next.1 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.9-next.1 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.25-next.1 + - @backstage/plugin-search-backend@1.4.8-next.1 + - @backstage/plugin-search-backend-module-catalog@0.1.12-next.1 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.11-next.1 + - @backstage/plugin-search-backend-module-explore@0.1.12-next.1 + - @backstage/plugin-search-backend-module-pg@0.5.17-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.12-next.1 + - @backstage/plugin-search-backend-node@1.2.12-next.1 + - @backstage/plugin-search-common@1.2.8 + - @backstage/plugin-tech-insights-backend@0.5.22-next.1 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.40-next.1 + - @backstage/plugin-tech-insights-node@0.4.14-next.1 + - @backstage/plugin-techdocs-backend@1.9.1-next.1 + - @backstage/plugin-todo-backend@0.3.6-next.1 + ## 0.2.90-next.0 ### Patch Changes diff --git a/packages/backend/package.json b/packages/backend/package.json index fc964dfdbc..f57897f163 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -1,6 +1,6 @@ { "name": "example-backend", - "version": "0.2.90-next.0", + "version": "0.2.90-next.1", "main": "dist/index.cjs.js", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/packages/catalog-client/CHANGELOG.md b/packages/catalog-client/CHANGELOG.md index 7a2618f0e0..b7517e5734 100644 --- a/packages/catalog-client/CHANGELOG.md +++ b/packages/catalog-client/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/catalog-client +## 1.5.0-next.0 + +### Minor Changes + +- 38340678c3: The internals of `CatalogClient` are now auto-generated using the `backstage-repo-tools schema openapi generate-client` command. + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + ## 1.4.6 ### Patch Changes diff --git a/packages/catalog-client/package.json b/packages/catalog-client/package.json index 4f545262c3..2be5fbea43 100644 --- a/packages/catalog-client/package.json +++ b/packages/catalog-client/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/catalog-client", "description": "An isomorphic client for the catalog backend", - "version": "1.4.6", + "version": "1.5.0-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index ec80b61dc4..acee7fd45c 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -1,5 +1,30 @@ # @backstage/cli +## 0.25.0-next.1 + +### Minor Changes + +- 38340678c3: Updates the ESLint config to ignore issues created by generated files in `**/src/generated/**`. + +### Patch Changes + +- 0ffee55010: Toned down the warning message when git is not found +- c6f3743172: Added a warning when starting a standalone backend plugin that hasn't been updated to the new backend system. +- 3e358b0dff: Added deprecation warning for React Router v6 beta, please make sure you have migrated your apps to use React Router v6 stable as support for the beta version will be removed. See the [migration tutorial](https://backstage.io/docs/tutorials/react-router-stable-migration) for more information. +- 8056425e09: Updated dependency `@typescript-eslint/eslint-plugin` to `6.12.0`. +- 33e96e59e7: Switched the `@typescript-eslint/eslint-plugin` dependency back to using a `^` version range. +- Updated dependencies + - @backstage/eslint-plugin@0.1.4-next.0 + - @backstage/integration@1.8.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/cli-node@0.2.0 + - @backstage/config@1.1.1 + - @backstage/config-loader@1.5.3 + - @backstage/errors@1.2.3 + - @backstage/release-manifests@0.0.11 + - @backstage/types@1.1.1 + ## 0.24.1-next.0 ### Patch Changes diff --git a/packages/cli/package.json b/packages/cli/package.json index 1d1d3a8f59..38ff54a63f 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/cli", "description": "CLI for developing Backstage plugins and apps", - "version": "0.24.1-next.0", + "version": "0.25.0-next.1", "publishConfig": { "access": "public" }, diff --git a/packages/core-app-api/CHANGELOG.md b/packages/core-app-api/CHANGELOG.md index f77c607e3f..2a0e26c1e7 100644 --- a/packages/core-app-api/CHANGELOG.md +++ b/packages/core-app-api/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/core-app-api +## 1.11.2-next.1 + +### Patch Changes + +- 3e358b0dff: Added deprecation warning for React Router v6 beta, please make sure you have migrated your apps to use React Router v6 stable as support for the beta version will be removed. See the [migration tutorial](https://backstage.io/docs/tutorials/react-router-stable-migration) for more information. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + ## 1.11.2-next.0 ### Patch Changes diff --git a/packages/core-app-api/package.json b/packages/core-app-api/package.json index 0efa8b3bb8..b18f31eb4f 100644 --- a/packages/core-app-api/package.json +++ b/packages/core-app-api/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/core-app-api", "description": "Core app API used by Backstage apps", - "version": "1.11.2-next.0", + "version": "1.11.2-next.1", "publishConfig": { "access": "public" }, diff --git a/packages/core-compat-api/CHANGELOG.md b/packages/core-compat-api/CHANGELOG.md index 017e3ec785..1be69b6986 100644 --- a/packages/core-compat-api/CHANGELOG.md +++ b/packages/core-compat-api/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/core-compat-api +## 0.0.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/core-app-api@1.11.2-next.1 + ## 0.0.1-next.0 ### Patch Changes diff --git a/packages/core-compat-api/package.json b/packages/core-compat-api/package.json index f887193616..531b09722e 100644 --- a/packages/core-compat-api/package.json +++ b/packages/core-compat-api/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/core-compat-api", - "version": "0.0.1-next.0", + "version": "0.0.1-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/packages/core-components/CHANGELOG.md b/packages/core-components/CHANGELOG.md index f726aa1b19..6a319b1add 100644 --- a/packages/core-components/CHANGELOG.md +++ b/packages/core-components/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/core-components +## 0.13.9-next.1 + +### Patch Changes + +- e8f2acef80: Added a new `/testUtils` sub-path that initially exports a `mockBreakpoint` helper. +- 07dfdf3702: Updated dependency `linkifyjs` to `4.1.3`. +- a518c5a25b: Updated dependency `@react-hookz/web` to `^23.0.0`. +- f291757e70: Update `linkify-react` to version `4.1.3` +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/version-bridge@1.0.7 + ## 0.13.9-next.0 ### Patch Changes diff --git a/packages/core-components/package.json b/packages/core-components/package.json index 49d1e9867e..19bcb306cc 100644 --- a/packages/core-components/package.json +++ b/packages/core-components/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/core-components", "description": "Core components used by Backstage plugins and apps", - "version": "0.13.9-next.0", + "version": "0.13.9-next.1", "publishConfig": { "access": "public" }, diff --git a/packages/core-plugin-api/CHANGELOG.md b/packages/core-plugin-api/CHANGELOG.md index d80e3e9f89..eab6b0519b 100644 --- a/packages/core-plugin-api/CHANGELOG.md +++ b/packages/core-plugin-api/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/core-plugin-api +## 1.8.1-next.1 + +### Patch Changes + +- 0c93dc37b2: The `createTranslationRef` function from the `/alpha` subpath can now also accept a nested object structure of default translation messages, which will be flatted using `.` separators. +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + ## 1.8.1-next.0 ### Patch Changes diff --git a/packages/core-plugin-api/package.json b/packages/core-plugin-api/package.json index 98286779f8..3b0bc1f34b 100644 --- a/packages/core-plugin-api/package.json +++ b/packages/core-plugin-api/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/core-plugin-api", "description": "Core API used by Backstage plugins", - "version": "1.8.1-next.0", + "version": "1.8.1-next.1", "publishConfig": { "access": "public" }, diff --git a/packages/create-app/CHANGELOG.md b/packages/create-app/CHANGELOG.md index 74c2c3b7ce..9d7ccf5dce 100644 --- a/packages/create-app/CHANGELOG.md +++ b/packages/create-app/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/create-app +## 0.5.8-next.2 + +### Patch Changes + +- 375b6f7d68: CircelCI plugin moved permanently +- Updated dependencies + - @backstage/cli-common@0.1.13 + ## 0.5.8-next.1 ### Patch Changes diff --git a/packages/create-app/package.json b/packages/create-app/package.json index 52f075adc5..06fb467244 100644 --- a/packages/create-app/package.json +++ b/packages/create-app/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/create-app", "description": "A CLI that helps you create your own Backstage app", - "version": "0.5.8-next.1", + "version": "0.5.8-next.2", "publishConfig": { "access": "public" }, diff --git a/packages/dev-utils/CHANGELOG.md b/packages/dev-utils/CHANGELOG.md index 485dc687ab..49c5a7785d 100644 --- a/packages/dev-utils/CHANGELOG.md +++ b/packages/dev-utils/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/dev-utils +## 1.0.25-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/app-defaults@1.4.6-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + ## 1.0.25-next.0 ### Patch Changes diff --git a/packages/dev-utils/package.json b/packages/dev-utils/package.json index ddcb29bdc3..d7ca26d64f 100644 --- a/packages/dev-utils/package.json +++ b/packages/dev-utils/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/dev-utils", "description": "Utilities for developing Backstage plugins.", - "version": "1.0.25-next.0", + "version": "1.0.25-next.1", "publishConfig": { "access": "public", "main": "dist/index.esm.js", diff --git a/packages/e2e-test/CHANGELOG.md b/packages/e2e-test/CHANGELOG.md index 053825aae0..6b39139bac 100644 --- a/packages/e2e-test/CHANGELOG.md +++ b/packages/e2e-test/CHANGELOG.md @@ -1,5 +1,14 @@ # e2e-test +## 0.2.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.8-next.2 + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + ## 0.2.10-next.1 ### Patch Changes diff --git a/packages/e2e-test/package.json b/packages/e2e-test/package.json index 35eec664f9..9c78471d5c 100644 --- a/packages/e2e-test/package.json +++ b/packages/e2e-test/package.json @@ -1,7 +1,7 @@ { "name": "e2e-test", "description": "E2E test for verifying Backstage packages", - "version": "0.2.10-next.1", + "version": "0.2.10-next.2", "private": true, "backstage": { "role": "cli" diff --git a/packages/eslint-plugin/CHANGELOG.md b/packages/eslint-plugin/CHANGELOG.md index 56ed54388a..6335f22f3c 100644 --- a/packages/eslint-plugin/CHANGELOG.md +++ b/packages/eslint-plugin/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/eslint-plugin +## 0.1.4-next.0 + +### Patch Changes + +- 107dc46ab1: The `no-undeclared-imports` rule will now prefer using version queries that already exist en the repo for the same dependency type when installing new packages. + ## 0.1.3 ### Patch Changes diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json index 34a8205868..656ec78580 100644 --- a/packages/eslint-plugin/package.json +++ b/packages/eslint-plugin/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/eslint-plugin", "description": "Backstage ESLint plugin", - "version": "0.1.3", + "version": "0.1.4-next.0", "publishConfig": { "access": "public" }, diff --git a/packages/frontend-app-api/CHANGELOG.md b/packages/frontend-app-api/CHANGELOG.md index a933f6a649..216360658c 100644 --- a/packages/frontend-app-api/CHANGELOG.md +++ b/packages/frontend-app-api/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/frontend-app-api +## 0.4.0-next.1 + +### Minor Changes + +- e539735435: Updated core extension structure to make space for the sign-in page by adding `core.router`. + +### Patch Changes + +- 5eb6b8a7bc: Added the nav logo extension for customization of sidebar logo +- 1f12fb762c: Create a core components extension that allows adopters to override core app components such as `Progress`, `BootErrorPage`, `NotFoundErrorPage` and `ErrorBoundaryFallback`. +- 59709286b3: Collect and register feature flags from plugins and extension overrides. +- f27ee7d937: Migrate analytics route tracker component. +- a5a04739e1: Updates to provide `node` to extension factories instead of `id` and `source`. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + ## 0.3.1-next.0 ### Patch Changes diff --git a/packages/frontend-app-api/package.json b/packages/frontend-app-api/package.json index 7a32004273..5a179ef9f0 100644 --- a/packages/frontend-app-api/package.json +++ b/packages/frontend-app-api/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/frontend-app-api", - "version": "0.3.1-next.0", + "version": "0.4.0-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/packages/frontend-plugin-api/CHANGELOG.md b/packages/frontend-plugin-api/CHANGELOG.md index 94f90d6717..74c9e784ee 100644 --- a/packages/frontend-plugin-api/CHANGELOG.md +++ b/packages/frontend-plugin-api/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/frontend-plugin-api +## 0.4.0-next.1 + +### Minor Changes + +- a5a04739e1: The extension `factory` function now longer receives `id` or `source`, but instead now provides the extension's `AppNode` as `node`. The `ExtensionBoundary` component has also been updated to receive a `node` prop rather than `id` and `source`. + +### Patch Changes + +- 5eb6b8a7bc: Added the nav logo extension for customization of sidebar logo +- 1f12fb762c: Create factories for overriding default core components extensions. +- 59709286b3: Add feature flags to plugins and extension overrides. +- e539735435: Added `createSignInPageExtension`. +- f27ee7d937: Migrate analytics api and context files. +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + ## 0.3.1-next.0 ### Patch Changes diff --git a/packages/frontend-plugin-api/package.json b/packages/frontend-plugin-api/package.json index 45888aff39..4137aaabc6 100644 --- a/packages/frontend-plugin-api/package.json +++ b/packages/frontend-plugin-api/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/frontend-plugin-api", - "version": "0.3.1-next.0", + "version": "0.4.0-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/packages/frontend-test-utils/CHANGELOG.md b/packages/frontend-test-utils/CHANGELOG.md index d112822d13..b25a5a7c38 100644 --- a/packages/frontend-test-utils/CHANGELOG.md +++ b/packages/frontend-test-utils/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/frontend-test-utils +## 0.1.0-next.1 + +### Patch Changes + +- e539735435: Updates for `core.router` addition. +- c21c9cf07b: Re-export mock API implementations as well as `TestApiProvider`, `TestApiRegistry`, `withLogCollector`, and `setupRequestMockHandlers` from `@backstage/test-utils`. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/frontend-app-api@0.4.0-next.1 + - @backstage/test-utils@1.4.6-next.1 + - @backstage/types@1.1.1 + ## 0.1.0-next.0 ### Minor Changes diff --git a/packages/frontend-test-utils/package.json b/packages/frontend-test-utils/package.json index 2434eec37c..93e27869fb 100644 --- a/packages/frontend-test-utils/package.json +++ b/packages/frontend-test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/frontend-test-utils", - "version": "0.1.0-next.0", + "version": "0.1.0-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/packages/integration-react/CHANGELOG.md b/packages/integration-react/CHANGELOG.md index 21a4a75e75..34a24e7602 100644 --- a/packages/integration-react/CHANGELOG.md +++ b/packages/integration-react/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/integration-react +## 1.1.22-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/config@1.1.1 + ## 1.1.22-next.0 ### Patch Changes diff --git a/packages/integration-react/package.json b/packages/integration-react/package.json index f3e83da77e..4c7defc2d4 100644 --- a/packages/integration-react/package.json +++ b/packages/integration-react/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/integration-react", "description": "Frontend package for managing integrations towards external systems", - "version": "1.1.22-next.0", + "version": "1.1.22-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/packages/integration/CHANGELOG.md b/packages/integration/CHANGELOG.md index a3392a512d..74dee088d5 100644 --- a/packages/integration/CHANGELOG.md +++ b/packages/integration/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/integration +## 1.8.0-next.1 + +### Patch Changes + +- 99fb54183b: Updated dependency `@azure/identity` to `^4.0.0`. +- Updated dependencies + - @backstage/config@1.1.1 + ## 1.8.0-next.0 ### Minor Changes diff --git a/packages/integration/package.json b/packages/integration/package.json index df927acd55..8e403c2ce4 100644 --- a/packages/integration/package.json +++ b/packages/integration/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/integration", "description": "Helpers for managing integrations towards external systems", - "version": "1.8.0-next.0", + "version": "1.8.0-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/packages/repo-tools/CHANGELOG.md b/packages/repo-tools/CHANGELOG.md index b439c08fc6..0a0802d87e 100644 --- a/packages/repo-tools/CHANGELOG.md +++ b/packages/repo-tools/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/repo-tools +## 0.5.0-next.0 + +### Minor Changes + +- aea8f8d329: **BREAKING**: API Reports generated for sub-path exports now place the name as a suffix rather than prefix, for example `api-report-alpha.md` instead of `alpha-api-report.md`. When upgrading to this version you'll need to re-create any such API reports and delete the old ones. +- 38340678c3: Adds a new command `schema openapi generate-client` that creates a Typescript client with Backstage flavor, including the discovery API and fetch API. This command doesn't currently generate a complete client and needs to be wrapped or exported manually by a separate Backstage plugin. See `@backstage/catalog-client/src/generated` for example output. + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/cli-node@0.2.0 + - @backstage/errors@1.2.3 + ## 0.4.0 ### Minor Changes diff --git a/packages/repo-tools/package.json b/packages/repo-tools/package.json index 9dad92966b..9d4ae3542b 100644 --- a/packages/repo-tools/package.json +++ b/packages/repo-tools/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/repo-tools", "description": "CLI for Backstage repo tooling ", - "version": "0.4.0", + "version": "0.5.0-next.0", "publishConfig": { "access": "public" }, diff --git a/packages/techdocs-cli-embedded-app/CHANGELOG.md b/packages/techdocs-cli-embedded-app/CHANGELOG.md index b75cb32d7a..135f13d075 100644 --- a/packages/techdocs-cli-embedded-app/CHANGELOG.md +++ b/packages/techdocs-cli-embedded-app/CHANGELOG.md @@ -1,5 +1,24 @@ # techdocs-cli-embedded-app +## 0.2.89-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/cli@0.25.0-next.1 + - @backstage/plugin-catalog@1.16.0-next.2 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/test-utils@1.4.6-next.1 + - @backstage/plugin-techdocs@1.9.2-next.2 + - @backstage/app-defaults@1.4.6-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/plugin-techdocs-react@1.1.14-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + ## 0.2.89-next.1 ### Patch Changes diff --git a/packages/techdocs-cli-embedded-app/package.json b/packages/techdocs-cli-embedded-app/package.json index 21b1ff39f4..f3e5485658 100644 --- a/packages/techdocs-cli-embedded-app/package.json +++ b/packages/techdocs-cli-embedded-app/package.json @@ -1,6 +1,6 @@ { "name": "techdocs-cli-embedded-app", - "version": "0.2.89-next.1", + "version": "0.2.89-next.2", "private": true, "backstage": { "role": "frontend" diff --git a/packages/techdocs-cli/CHANGELOG.md b/packages/techdocs-cli/CHANGELOG.md index bdcd94b951..8769bd0c93 100644 --- a/packages/techdocs-cli/CHANGELOG.md +++ b/packages/techdocs-cli/CHANGELOG.md @@ -1,5 +1,20 @@ # @techdocs/cli +## 1.8.0-next.1 + +### Minor Changes + +- b2dccad7b3: Support passing additional `mkdocs-server` CLI parameters (`--dirtyreload`, `--strict` and `--clean`) when run in containerized mode. + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs-node@1.11.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + ## 1.8.0-next.0 ### Minor Changes diff --git a/packages/techdocs-cli/package.json b/packages/techdocs-cli/package.json index fa1c69d09b..94f9c159ee 100644 --- a/packages/techdocs-cli/package.json +++ b/packages/techdocs-cli/package.json @@ -1,7 +1,7 @@ { "name": "@techdocs/cli", "description": "Utility CLI for managing TechDocs sites in Backstage.", - "version": "1.8.0-next.0", + "version": "1.8.0-next.1", "publishConfig": { "access": "public" }, diff --git a/packages/test-utils/CHANGELOG.md b/packages/test-utils/CHANGELOG.md index 5bde6c3354..9a18091f6e 100644 --- a/packages/test-utils/CHANGELOG.md +++ b/packages/test-utils/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/test-utils +## 1.4.6-next.1 + +### Patch Changes + +- e8f2acef80: Deprecated `mockBreakpoint`, as it is now available from `@backstage/core-components/testUtils` instead. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/plugin-permission-react@0.4.18-next.1 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.10 + ## 1.4.6-next.0 ### Patch Changes diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index 15b3a387ae..ec48141e99 100644 --- a/packages/test-utils/package.json +++ b/packages/test-utils/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/test-utils", "description": "Utilities to test Backstage plugins and apps.", - "version": "1.4.6-next.0", + "version": "1.4.6-next.1", "publishConfig": { "access": "public" }, diff --git a/plugins/adr-backend/CHANGELOG.md b/plugins/adr-backend/CHANGELOG.md index 5ea30aee78..8be4a06ac9 100644 --- a/plugins/adr-backend/CHANGELOG.md +++ b/plugins/adr-backend/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-adr-backend +## 0.4.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-adr-common@0.2.18-next.1 + - @backstage/plugin-search-common@1.2.8 + ## 0.4.5-next.0 ### Patch Changes diff --git a/plugins/adr-backend/package.json b/plugins/adr-backend/package.json index 8981a4905d..c758ad68ed 100644 --- a/plugins/adr-backend/package.json +++ b/plugins/adr-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-adr-backend", - "version": "0.4.5-next.0", + "version": "0.4.5-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/adr-common/CHANGELOG.md b/plugins/adr-common/CHANGELOG.md index 2127f06437..3f02901db7 100644 --- a/plugins/adr-common/CHANGELOG.md +++ b/plugins/adr-common/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-adr-common +## 0.2.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-search-common@1.2.8 + ## 0.2.18-next.0 ### Patch Changes diff --git a/plugins/adr-common/package.json b/plugins/adr-common/package.json index 43bc951328..e04af0ade0 100644 --- a/plugins/adr-common/package.json +++ b/plugins/adr-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-adr-common", "description": "Common functionalities for the adr plugin", - "version": "0.2.18-next.0", + "version": "0.2.18-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/adr/CHANGELOG.md b/plugins/adr/CHANGELOG.md index 0e69d1e735..92390fdbb8 100644 --- a/plugins/adr/CHANGELOG.md +++ b/plugins/adr/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-adr +## 0.6.11-next.1 + +### Patch Changes + +- fb8f3bdbc2: Updated alpha translation message keys to use nested format and camel case. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-search-react@1.7.4-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-adr-common@0.2.18-next.1 + - @backstage/plugin-search-common@1.2.8 + ## 0.6.11-next.0 ### Patch Changes diff --git a/plugins/adr/package.json b/plugins/adr/package.json index 47468844ce..54d4bc7b8c 100644 --- a/plugins/adr/package.json +++ b/plugins/adr/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-adr", - "version": "0.6.11-next.0", + "version": "0.6.11-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/airbrake-backend/CHANGELOG.md b/plugins/airbrake-backend/CHANGELOG.md index 4ce8e4b3b5..da4b51d934 100644 --- a/plugins/airbrake-backend/CHANGELOG.md +++ b/plugins/airbrake-backend/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-airbrake-backend +## 0.3.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + ## 0.3.5-next.0 ### Patch Changes diff --git a/plugins/airbrake-backend/package.json b/plugins/airbrake-backend/package.json index a3ac0b4c27..75a2ed104e 100644 --- a/plugins/airbrake-backend/package.json +++ b/plugins/airbrake-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-airbrake-backend", - "version": "0.3.5-next.0", + "version": "0.3.5-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/airbrake/CHANGELOG.md b/plugins/airbrake/CHANGELOG.md index 19bc827a72..19a506f8e6 100644 --- a/plugins/airbrake/CHANGELOG.md +++ b/plugins/airbrake/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-airbrake +## 0.3.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/test-utils@1.4.6-next.1 + - @backstage/dev-utils@1.0.25-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + ## 0.3.28-next.0 ### Patch Changes diff --git a/plugins/airbrake/package.json b/plugins/airbrake/package.json index 932aa55e91..07a41bb804 100644 --- a/plugins/airbrake/package.json +++ b/plugins/airbrake/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-airbrake", - "version": "0.3.28-next.0", + "version": "0.3.28-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/allure/CHANGELOG.md b/plugins/allure/CHANGELOG.md index c72b6eedb6..ca8cdcc87b 100644 --- a/plugins/allure/CHANGELOG.md +++ b/plugins/allure/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-allure +## 0.1.44-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + ## 0.1.44-next.0 ### Patch Changes diff --git a/plugins/allure/package.json b/plugins/allure/package.json index ee1952c819..5778ad0834 100644 --- a/plugins/allure/package.json +++ b/plugins/allure/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-allure", "description": "A Backstage plugin that integrates with Allure", - "version": "0.1.44-next.0", + "version": "0.1.44-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/analytics-module-ga/CHANGELOG.md b/plugins/analytics-module-ga/CHANGELOG.md index acf6f0eb98..ba46e16809 100644 --- a/plugins/analytics-module-ga/CHANGELOG.md +++ b/plugins/analytics-module-ga/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-analytics-module-ga +## 0.1.36-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + ## 0.1.36-next.0 ### Patch Changes diff --git a/plugins/analytics-module-ga/package.json b/plugins/analytics-module-ga/package.json index 9cace65a5d..d2744caf9d 100644 --- a/plugins/analytics-module-ga/package.json +++ b/plugins/analytics-module-ga/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-analytics-module-ga", - "version": "0.1.36-next.0", + "version": "0.1.36-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/analytics-module-ga4/CHANGELOG.md b/plugins/analytics-module-ga4/CHANGELOG.md index a929abaf61..2e2b17ec8d 100644 --- a/plugins/analytics-module-ga4/CHANGELOG.md +++ b/plugins/analytics-module-ga4/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-analytics-module-ga4 +## 0.1.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + ## 0.1.7-next.0 ### Patch Changes diff --git a/plugins/analytics-module-ga4/package.json b/plugins/analytics-module-ga4/package.json index 90155e34a8..246a1bf2d6 100644 --- a/plugins/analytics-module-ga4/package.json +++ b/plugins/analytics-module-ga4/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-analytics-module-ga4", - "version": "0.1.7-next.0", + "version": "0.1.7-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/analytics-module-newrelic-browser/CHANGELOG.md b/plugins/analytics-module-newrelic-browser/CHANGELOG.md index 86a86de836..f243c28481 100644 --- a/plugins/analytics-module-newrelic-browser/CHANGELOG.md +++ b/plugins/analytics-module-newrelic-browser/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-analytics-module-newrelic-browser +## 0.0.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/config@1.1.1 + ## 0.0.5-next.0 ### Patch Changes diff --git a/plugins/analytics-module-newrelic-browser/package.json b/plugins/analytics-module-newrelic-browser/package.json index c9d876c315..0cb59225cd 100644 --- a/plugins/analytics-module-newrelic-browser/package.json +++ b/plugins/analytics-module-newrelic-browser/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-analytics-module-newrelic-browser", - "version": "0.0.5-next.0", + "version": "0.0.5-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/apache-airflow/CHANGELOG.md b/plugins/apache-airflow/CHANGELOG.md index 959d447f55..e38a08e81f 100644 --- a/plugins/apache-airflow/CHANGELOG.md +++ b/plugins/apache-airflow/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-apache-airflow +## 0.2.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + ## 0.2.18-next.0 ### Patch Changes diff --git a/plugins/apache-airflow/package.json b/plugins/apache-airflow/package.json index f1d122f4f5..97a63fd4c1 100644 --- a/plugins/apache-airflow/package.json +++ b/plugins/apache-airflow/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-apache-airflow", - "version": "0.2.18-next.0", + "version": "0.2.18-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/api-docs/CHANGELOG.md b/plugins/api-docs/CHANGELOG.md index d88c90e769..594448351b 100644 --- a/plugins/api-docs/CHANGELOG.md +++ b/plugins/api-docs/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-api-docs +## 0.10.2-next.2 + +### Patch Changes + +- e16e7ce6a5: Updated dependency `@asyncapi/react-component` to `1.2.2`. +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-catalog@1.16.0-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + ## 0.10.2-next.1 ### Patch Changes diff --git a/plugins/api-docs/package.json b/plugins/api-docs/package.json index 5196d13a51..30b8650e19 100644 --- a/plugins/api-docs/package.json +++ b/plugins/api-docs/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-api-docs", "description": "A Backstage plugin that helps represent API entities in the frontend", - "version": "0.10.2-next.1", + "version": "0.10.2-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/apollo-explorer/CHANGELOG.md b/plugins/apollo-explorer/CHANGELOG.md index 26cda3787a..ba51605e0d 100644 --- a/plugins/apollo-explorer/CHANGELOG.md +++ b/plugins/apollo-explorer/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-apollo-explorer +## 0.1.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.0 + ## 0.1.18-next.0 ### Patch Changes diff --git a/plugins/apollo-explorer/package.json b/plugins/apollo-explorer/package.json index 0cbc7cd292..0fbf80783d 100644 --- a/plugins/apollo-explorer/package.json +++ b/plugins/apollo-explorer/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-apollo-explorer", - "version": "0.1.18-next.0", + "version": "0.1.18-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/app-backend/CHANGELOG.md b/plugins/app-backend/CHANGELOG.md index d3c21b03fd..5ac1fe4aec 100644 --- a/plugins/app-backend/CHANGELOG.md +++ b/plugins/app-backend/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-app-backend +## 0.3.56-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/config-loader@1.5.3 + - @backstage/types@1.1.1 + - @backstage/plugin-app-node@0.1.8-next.1 + ## 0.3.56-next.0 ### Patch Changes diff --git a/plugins/app-backend/package.json b/plugins/app-backend/package.json index 87f6b6827c..235a7fd70b 100644 --- a/plugins/app-backend/package.json +++ b/plugins/app-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-app-backend", "description": "A Backstage backend plugin that serves the Backstage frontend app", - "version": "0.3.56-next.0", + "version": "0.3.56-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/app-node/CHANGELOG.md b/plugins/app-node/CHANGELOG.md index f901f5b879..b7069bc1c0 100644 --- a/plugins/app-node/CHANGELOG.md +++ b/plugins/app-node/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-app-node +## 0.1.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.1 + ## 0.1.8-next.0 ### Patch Changes diff --git a/plugins/app-node/package.json b/plugins/app-node/package.json index 042703f5ab..b6e805c857 100644 --- a/plugins/app-node/package.json +++ b/plugins/app-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-app-node", "description": "Node.js library for the app plugin", - "version": "0.1.8-next.0", + "version": "0.1.8-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/auth-backend-module-atlassian-provider/CHANGELOG.md b/plugins/auth-backend-module-atlassian-provider/CHANGELOG.md index 7e02d921ea..5eca1e2a07 100644 --- a/plugins/auth-backend-module-atlassian-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-atlassian-provider/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-auth-backend-module-atlassian-provider +## 0.1.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + ## 0.1.0-next.0 ### Minor Changes diff --git a/plugins/auth-backend-module-atlassian-provider/package.json b/plugins/auth-backend-module-atlassian-provider/package.json index a75aae73ea..9cfc21ba6a 100644 --- a/plugins/auth-backend-module-atlassian-provider/package.json +++ b/plugins/auth-backend-module-atlassian-provider/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-auth-backend-module-atlassian-provider", "description": "The atlassian-provider backend module for the auth plugin.", - "version": "0.1.0-next.0", + "version": "0.1.0-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/auth-backend-module-gcp-iap-provider/CHANGELOG.md b/plugins/auth-backend-module-gcp-iap-provider/CHANGELOG.md index 60aa68020a..cfd164ebfe 100644 --- a/plugins/auth-backend-module-gcp-iap-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-gcp-iap-provider/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-auth-backend-module-gcp-iap-provider +## 0.2.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + ## 0.2.2-next.0 ### Patch Changes diff --git a/plugins/auth-backend-module-gcp-iap-provider/package.json b/plugins/auth-backend-module-gcp-iap-provider/package.json index 2dbb69c8cd..f7d4ea7bc7 100644 --- a/plugins/auth-backend-module-gcp-iap-provider/package.json +++ b/plugins/auth-backend-module-gcp-iap-provider/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-auth-backend-module-gcp-iap-provider", "description": "A GCP IAP auth provider module for the Backstage auth backend", - "version": "0.2.2-next.0", + "version": "0.2.2-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/auth-backend-module-github-provider/CHANGELOG.md b/plugins/auth-backend-module-github-provider/CHANGELOG.md index 3bf47f8a7a..5b3acd377d 100644 --- a/plugins/auth-backend-module-github-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-github-provider/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-auth-backend-module-github-provider +## 0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + ## 0.1.5-next.0 ### Patch Changes diff --git a/plugins/auth-backend-module-github-provider/package.json b/plugins/auth-backend-module-github-provider/package.json index 218ec94cac..9ed4f7d3b9 100644 --- a/plugins/auth-backend-module-github-provider/package.json +++ b/plugins/auth-backend-module-github-provider/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-auth-backend-module-github-provider", "description": "The github-provider backend module for the auth plugin.", - "version": "0.1.5-next.0", + "version": "0.1.5-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/auth-backend-module-gitlab-provider/CHANGELOG.md b/plugins/auth-backend-module-gitlab-provider/CHANGELOG.md index c610e93ec8..03fb405e56 100644 --- a/plugins/auth-backend-module-gitlab-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-gitlab-provider/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-auth-backend-module-gitlab-provider +## 0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + ## 0.1.5-next.0 ### Patch Changes diff --git a/plugins/auth-backend-module-gitlab-provider/package.json b/plugins/auth-backend-module-gitlab-provider/package.json index 9d931e628c..fee472b198 100644 --- a/plugins/auth-backend-module-gitlab-provider/package.json +++ b/plugins/auth-backend-module-gitlab-provider/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-auth-backend-module-gitlab-provider", "description": "The gitlab-provider backend module for the auth plugin.", - "version": "0.1.5-next.0", + "version": "0.1.5-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/auth-backend-module-google-provider/CHANGELOG.md b/plugins/auth-backend-module-google-provider/CHANGELOG.md index a8edf35c7e..30fcf563b7 100644 --- a/plugins/auth-backend-module-google-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-google-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-auth-backend-module-google-provider +## 0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + ## 0.1.5-next.0 ### Patch Changes diff --git a/plugins/auth-backend-module-google-provider/package.json b/plugins/auth-backend-module-google-provider/package.json index 1cbb87c5b2..6ba15b3938 100644 --- a/plugins/auth-backend-module-google-provider/package.json +++ b/plugins/auth-backend-module-google-provider/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-auth-backend-module-google-provider", "description": "A Google auth provider module for the Backstage auth backend", - "version": "0.1.5-next.0", + "version": "0.1.5-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/auth-backend-module-microsoft-provider/CHANGELOG.md b/plugins/auth-backend-module-microsoft-provider/CHANGELOG.md index 76bf7d60d7..df5aea992d 100644 --- a/plugins/auth-backend-module-microsoft-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-microsoft-provider/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-auth-backend-module-microsoft-provider +## 0.1.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + ## 0.1.3-next.0 ### Patch Changes diff --git a/plugins/auth-backend-module-microsoft-provider/package.json b/plugins/auth-backend-module-microsoft-provider/package.json index e67da9228c..ea016cfcf7 100644 --- a/plugins/auth-backend-module-microsoft-provider/package.json +++ b/plugins/auth-backend-module-microsoft-provider/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-auth-backend-module-microsoft-provider", "description": "The microsoft-provider backend module for the auth plugin.", - "version": "0.1.3-next.0", + "version": "0.1.3-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md b/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md index bae3565d3b..5f7a5dc4b8 100644 --- a/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-auth-backend-module-oauth2-provider +## 0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + ## 0.1.5-next.0 ### Patch Changes diff --git a/plugins/auth-backend-module-oauth2-provider/package.json b/plugins/auth-backend-module-oauth2-provider/package.json index cc672f77b9..e31e64c3f5 100644 --- a/plugins/auth-backend-module-oauth2-provider/package.json +++ b/plugins/auth-backend-module-oauth2-provider/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-auth-backend-module-oauth2-provider", "description": "The oauth2-provider backend module for the auth plugin.", - "version": "0.1.5-next.0", + "version": "0.1.5-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/auth-backend-module-oauth2-proxy-provider/CHANGELOG.md b/plugins/auth-backend-module-oauth2-proxy-provider/CHANGELOG.md new file mode 100644 index 0000000000..ed2ec641b9 --- /dev/null +++ b/plugins/auth-backend-module-oauth2-proxy-provider/CHANGELOG.md @@ -0,0 +1,15 @@ +# @backstage/plugin-auth-backend-module-oauth2-proxy-provider + +## 0.1.0-next.0 + +### Minor Changes + +- 271aa12c7c: Release of `oauth2-proxy-provider` plugin + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.1 diff --git a/plugins/auth-backend-module-oauth2-proxy-provider/package.json b/plugins/auth-backend-module-oauth2-proxy-provider/package.json index be5617eb69..090a64ae66 100644 --- a/plugins/auth-backend-module-oauth2-proxy-provider/package.json +++ b/plugins/auth-backend-module-oauth2-proxy-provider/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-auth-backend-module-oauth2-proxy-provider", "description": "The oauth2-proxy-provider backend module for the auth plugin.", - "version": "0.0.0", + "version": "0.1.0-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/auth-backend-module-okta-provider/CHANGELOG.md b/plugins/auth-backend-module-okta-provider/CHANGELOG.md index 98782fccb5..6b0f8e6304 100644 --- a/plugins/auth-backend-module-okta-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-okta-provider/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-auth-backend-module-okta-provider +## 0.0.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + ## 0.0.1-next.0 ### Patch Changes diff --git a/plugins/auth-backend-module-okta-provider/package.json b/plugins/auth-backend-module-okta-provider/package.json index a9e8606335..fcbf37ccd7 100644 --- a/plugins/auth-backend-module-okta-provider/package.json +++ b/plugins/auth-backend-module-okta-provider/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-auth-backend-module-okta-provider", "description": "The okta-provider backend module for the auth plugin.", - "version": "0.0.1-next.0", + "version": "0.0.1-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/auth-backend-module-pinniped-provider/CHANGELOG.md b/plugins/auth-backend-module-pinniped-provider/CHANGELOG.md index 57d4e5611a..c2334029f2 100644 --- a/plugins/auth-backend-module-pinniped-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-pinniped-provider/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-auth-backend-module-pinniped-provider +## 0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + ## 0.1.2-next.0 ### Patch Changes diff --git a/plugins/auth-backend-module-pinniped-provider/package.json b/plugins/auth-backend-module-pinniped-provider/package.json index 2b572696fd..c55c89eda2 100644 --- a/plugins/auth-backend-module-pinniped-provider/package.json +++ b/plugins/auth-backend-module-pinniped-provider/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-auth-backend-module-pinniped-provider", "description": "The pinniped-provider backend module for the auth plugin.", - "version": "0.1.2-next.0", + "version": "0.1.2-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/auth-backend-module-vmware-cloud-provider/CHANGELOG.md b/plugins/auth-backend-module-vmware-cloud-provider/CHANGELOG.md new file mode 100644 index 0000000000..332872c5cf --- /dev/null +++ b/plugins/auth-backend-module-vmware-cloud-provider/CHANGELOG.md @@ -0,0 +1,15 @@ +# @backstage/plugin-auth-backend-module-vmware-cloud-provider + +## 0.1.0-next.0 + +### Minor Changes + +- ed02c69a3c: Add VMware Cloud auth backend module provider + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-auth-node@0.4.2-next.1 diff --git a/plugins/auth-backend-module-vmware-cloud-provider/package.json b/plugins/auth-backend-module-vmware-cloud-provider/package.json index f48e69154b..db9de2741d 100644 --- a/plugins/auth-backend-module-vmware-cloud-provider/package.json +++ b/plugins/auth-backend-module-vmware-cloud-provider/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-auth-backend-module-vmware-cloud-provider", "description": "The vmware-cloud-provider backend module for the auth plugin.", - "version": "0.0.0", + "version": "0.1.0-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/auth-backend/CHANGELOG.md b/plugins/auth-backend/CHANGELOG.md index 2ab0a71b77..5e818e299a 100644 --- a/plugins/auth-backend/CHANGELOG.md +++ b/plugins/auth-backend/CHANGELOG.md @@ -1,5 +1,30 @@ # @backstage/plugin-auth-backend +## 0.20.1-next.1 + +### Patch Changes + +- 7ac25759a5: `oauth2-proxy` auth implementation has been moved to `@backstage/plugin-auth-backend-module-oauth2-proxy-provider` +- bcbbf8e042: Updated dependency `@google-cloud/firestore` to `^7.0.0`. +- Updated dependencies + - @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.0-next.0 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/plugin-auth-backend-module-atlassian-provider@0.1.0-next.1 + - @backstage/plugin-auth-backend-module-github-provider@0.1.5-next.1 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.1.5-next.1 + - @backstage/plugin-auth-backend-module-google-provider@0.1.5-next.1 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.1.5-next.1 + - @backstage/plugin-auth-backend-module-okta-provider@0.0.1-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.2-next.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-catalog-node@1.5.1-next.1 + ## 0.20.1-next.0 ### Patch Changes diff --git a/plugins/auth-backend/package.json b/plugins/auth-backend/package.json index b551d114bb..5060390d9a 100644 --- a/plugins/auth-backend/package.json +++ b/plugins/auth-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-auth-backend", "description": "A Backstage backend plugin that handles authentication", - "version": "0.20.1-next.0", + "version": "0.20.1-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/auth-node/CHANGELOG.md b/plugins/auth-node/CHANGELOG.md index d585f8d1d4..8262a10dab 100644 --- a/plugins/auth-node/CHANGELOG.md +++ b/plugins/auth-node/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-auth-node +## 0.4.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + ## 0.4.2-next.0 ### Patch Changes diff --git a/plugins/auth-node/package.json b/plugins/auth-node/package.json index 5a18593ab6..025d3c0eb6 100644 --- a/plugins/auth-node/package.json +++ b/plugins/auth-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-node", - "version": "0.4.2-next.0", + "version": "0.4.2-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/azure-devops-backend/CHANGELOG.md b/plugins/azure-devops-backend/CHANGELOG.md index 30b573b43f..0b4f978662 100644 --- a/plugins/azure-devops-backend/CHANGELOG.md +++ b/plugins/azure-devops-backend/CHANGELOG.md @@ -1,5 +1,26 @@ # @backstage/plugin-azure-devops-backend +## 0.5.0-next.1 + +### Minor Changes + +- 844969cd97: **BREAKING** New `fromConfig` static method must be used now when creating an instance of the `AzureDevOpsApi` + + Added support for using the `AzureDevOpsCredentialsProvider` + +### Patch Changes + +- 043b724c56: Introduced new `AzureDevOpsAnnotatorProcessor` that adds the needed annotations automatically. Also, moved constants to common package so they can be shared more easily +- Updated dependencies + - @backstage/plugin-azure-devops-common@0.3.2-next.0 + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.5.1-next.1 + ## 0.4.5-next.0 ### Patch Changes diff --git a/plugins/azure-devops-backend/package.json b/plugins/azure-devops-backend/package.json index 5b8bcda31c..6b223a26b2 100644 --- a/plugins/azure-devops-backend/package.json +++ b/plugins/azure-devops-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-azure-devops-backend", - "version": "0.4.5-next.0", + "version": "0.5.0-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/azure-devops-common/CHANGELOG.md b/plugins/azure-devops-common/CHANGELOG.md index e5637a9ff4..5ad70d8832 100644 --- a/plugins/azure-devops-common/CHANGELOG.md +++ b/plugins/azure-devops-common/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/plugin-azure-devops-common +## 0.3.2-next.0 + +### Patch Changes + +- 043b724c56: Introduced new `AzureDevOpsAnnotatorProcessor` that adds the needed annotations automatically. Also, moved constants to common package so they can be shared more easily + ## 0.3.1 ### Patch Changes diff --git a/plugins/azure-devops-common/package.json b/plugins/azure-devops-common/package.json index 7648e39539..f2bbe449ff 100644 --- a/plugins/azure-devops-common/package.json +++ b/plugins/azure-devops-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-azure-devops-common", - "version": "0.3.1", + "version": "0.3.2-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/azure-devops/CHANGELOG.md b/plugins/azure-devops/CHANGELOG.md index 919b4b7a25..3cd6209099 100644 --- a/plugins/azure-devops/CHANGELOG.md +++ b/plugins/azure-devops/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-azure-devops +## 0.3.10-next.1 + +### Patch Changes + +- 043b724c56: Introduced new `AzureDevOpsAnnotatorProcessor` that adds the needed annotations automatically. Also, moved constants to common package so they can be shared more easily +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-azure-devops-common@0.3.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + ## 0.3.10-next.0 ### Patch Changes diff --git a/plugins/azure-devops/package.json b/plugins/azure-devops/package.json index 9040d51e8d..39b14b8be2 100644 --- a/plugins/azure-devops/package.json +++ b/plugins/azure-devops/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-azure-devops", - "version": "0.3.10-next.0", + "version": "0.3.10-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/azure-sites-backend/CHANGELOG.md b/plugins/azure-sites-backend/CHANGELOG.md index 75cf7ac7a5..19953f496a 100644 --- a/plugins/azure-sites-backend/CHANGELOG.md +++ b/plugins/azure-sites-backend/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-azure-sites-backend +## 0.1.18-next.1 + +### Patch Changes + +- 99fb54183b: Updated dependency `@azure/identity` to `^4.0.0`. +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-azure-sites-common@0.1.1 + ## 0.1.18-next.0 ### Patch Changes diff --git a/plugins/azure-sites-backend/package.json b/plugins/azure-sites-backend/package.json index bf1cc6a144..1a62fead17 100644 --- a/plugins/azure-sites-backend/package.json +++ b/plugins/azure-sites-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-azure-sites-backend", - "version": "0.1.18-next.0", + "version": "0.1.18-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/azure-sites/CHANGELOG.md b/plugins/azure-sites/CHANGELOG.md index 3c36d729f3..95d7c4491e 100644 --- a/plugins/azure-sites/CHANGELOG.md +++ b/plugins/azure-sites/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-azure-sites +## 0.1.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-azure-sites-common@0.1.1 + ## 0.1.17-next.0 ### Patch Changes diff --git a/plugins/azure-sites/package.json b/plugins/azure-sites/package.json index 631d368bc8..e8a21a2a55 100644 --- a/plugins/azure-sites/package.json +++ b/plugins/azure-sites/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-azure-sites", - "version": "0.1.17-next.0", + "version": "0.1.17-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/badges-backend/CHANGELOG.md b/plugins/badges-backend/CHANGELOG.md index aab01f0504..f424b1b04e 100644 --- a/plugins/badges-backend/CHANGELOG.md +++ b/plugins/badges-backend/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-badges-backend +## 0.3.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.1 + ## 0.3.5-next.0 ### Patch Changes diff --git a/plugins/badges-backend/package.json b/plugins/badges-backend/package.json index 657ad01b09..6aaae4d8ea 100644 --- a/plugins/badges-backend/package.json +++ b/plugins/badges-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-badges-backend", "description": "A Backstage backend plugin that generates README badges for your entities", - "version": "0.3.5-next.0", + "version": "0.3.5-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/badges/CHANGELOG.md b/plugins/badges/CHANGELOG.md index 0d1a0856c9..f7330a5a9b 100644 --- a/plugins/badges/CHANGELOG.md +++ b/plugins/badges/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-badges +## 0.2.52-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + ## 0.2.52-next.0 ### Patch Changes diff --git a/plugins/badges/package.json b/plugins/badges/package.json index ff09805301..627af40a6b 100644 --- a/plugins/badges/package.json +++ b/plugins/badges/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-badges", "description": "A Backstage plugin that generates README badges for your entities", - "version": "0.2.52-next.0", + "version": "0.2.52-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/bazaar-backend/CHANGELOG.md b/plugins/bazaar-backend/CHANGELOG.md index ca50ba2d48..0fc8f9323d 100644 --- a/plugins/bazaar-backend/CHANGELOG.md +++ b/plugins/bazaar-backend/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-bazaar-backend +## 0.3.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.1 + ## 0.3.6-next.0 ### Patch Changes diff --git a/plugins/bazaar-backend/package.json b/plugins/bazaar-backend/package.json index f1deae24d8..5823ebe418 100644 --- a/plugins/bazaar-backend/package.json +++ b/plugins/bazaar-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-bazaar-backend", - "version": "0.3.6-next.0", + "version": "0.3.6-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/bazaar/CHANGELOG.md b/plugins/bazaar/CHANGELOG.md index 8dff109d9f..d89b8fa06b 100644 --- a/plugins/bazaar/CHANGELOG.md +++ b/plugins/bazaar/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-bazaar +## 0.2.20-next.2 + +### Patch Changes + +- 5d796829bb: Internalize 'AboutField' to break catalog dependency +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + ## 0.2.20-next.1 ### Patch Changes diff --git a/plugins/bazaar/package.json b/plugins/bazaar/package.json index a4b59ec57e..fcf5245a4a 100644 --- a/plugins/bazaar/package.json +++ b/plugins/bazaar/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-bazaar", - "version": "0.2.20-next.1", + "version": "0.2.20-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/bitbucket-cloud-common/CHANGELOG.md b/plugins/bitbucket-cloud-common/CHANGELOG.md index 58bfdcea30..12d38ed830 100644 --- a/plugins/bitbucket-cloud-common/CHANGELOG.md +++ b/plugins/bitbucket-cloud-common/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-bitbucket-cloud-common +## 0.2.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + ## 0.2.15-next.0 ### Patch Changes diff --git a/plugins/bitbucket-cloud-common/package.json b/plugins/bitbucket-cloud-common/package.json index 0aa9d3550e..5525510d5e 100644 --- a/plugins/bitbucket-cloud-common/package.json +++ b/plugins/bitbucket-cloud-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-bitbucket-cloud-common", "description": "Common functionalities for bitbucket-cloud plugins", - "version": "0.2.15-next.0", + "version": "0.2.15-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/bitrise/CHANGELOG.md b/plugins/bitrise/CHANGELOG.md index 3b180f797e..46f9c95da7 100644 --- a/plugins/bitrise/CHANGELOG.md +++ b/plugins/bitrise/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-bitrise +## 0.1.55-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + ## 0.1.55-next.0 ### Patch Changes diff --git a/plugins/bitrise/package.json b/plugins/bitrise/package.json index 5f4df1022f..47d35cbe58 100644 --- a/plugins/bitrise/package.json +++ b/plugins/bitrise/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-bitrise", "description": "A Backstage plugin that integrates towards Bitrise", - "version": "0.1.55-next.0", + "version": "0.1.55-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-aws/CHANGELOG.md b/plugins/catalog-backend-module-aws/CHANGELOG.md index 4447c07186..94d8f6913c 100644 --- a/plugins/catalog-backend-module-aws/CHANGELOG.md +++ b/plugins/catalog-backend-module-aws/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-catalog-backend-module-aws +## 0.3.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration-aws-node@0.1.8 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.5.1-next.1 + ## 0.3.2-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-aws/package.json b/plugins/catalog-backend-module-aws/package.json index a4ae3b395f..7dc89cd13e 100644 --- a/plugins/catalog-backend-module-aws/package.json +++ b/plugins/catalog-backend-module-aws/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-aws", "description": "A Backstage catalog backend module that helps integrate towards AWS", - "version": "0.3.2-next.0", + "version": "0.3.2-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-azure/CHANGELOG.md b/plugins/catalog-backend-module-azure/CHANGELOG.md index 04d6dcd33b..e34657c198 100644 --- a/plugins/catalog-backend-module-azure/CHANGELOG.md +++ b/plugins/catalog-backend-module-azure/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-catalog-backend-module-azure +## 0.1.27-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.5.1-next.1 + ## 0.1.27-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-azure/package.json b/plugins/catalog-backend-module-azure/package.json index 1ff6c4cc78..8425b22331 100644 --- a/plugins/catalog-backend-module-azure/package.json +++ b/plugins/catalog-backend-module-azure/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-azure", "description": "A Backstage catalog backend module that helps integrate towards Azure", - "version": "0.1.27-next.0", + "version": "0.1.27-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-backstage-openapi/CHANGELOG.md b/plugins/catalog-backend-module-backstage-openapi/CHANGELOG.md index cf6015342e..db59c77fc4 100644 --- a/plugins/catalog-backend-module-backstage-openapi/CHANGELOG.md +++ b/plugins/catalog-backend-module-backstage-openapi/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-catalog-backend-module-backstage-openapi +## 0.1.1-next.1 + +### Patch Changes + +- eb44e92898: Support authenticated backends +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-openapi-utils@0.1.1-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-node@1.5.1-next.1 + ## 0.1.1-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-backstage-openapi/package.json b/plugins/catalog-backend-module-backstage-openapi/package.json index 57611b6920..dc3fc37508 100644 --- a/plugins/catalog-backend-module-backstage-openapi/package.json +++ b/plugins/catalog-backend-module-backstage-openapi/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-backstage-openapi", - "version": "0.1.1-next.0", + "version": "0.1.1-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md b/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md index d0824e1fe6..4f54bad476 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md +++ b/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-catalog-backend-module-bitbucket-cloud +## 0.1.23-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-bitbucket-cloud-common@0.2.15-next.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.5.1-next.1 + - @backstage/plugin-events-node@0.2.17-next.1 + ## 0.1.23-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-bitbucket-cloud/package.json b/plugins/catalog-backend-module-bitbucket-cloud/package.json index fd991c00a6..6848617058 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/package.json +++ b/plugins/catalog-backend-module-bitbucket-cloud/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-bitbucket-cloud", "description": "A Backstage catalog backend module that helps integrate towards Bitbucket Cloud", - "version": "0.1.23-next.0", + "version": "0.1.23-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md b/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md index f96a8ee235..71e47ddb6c 100644 --- a/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md +++ b/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-catalog-backend-module-bitbucket-server +## 0.1.21-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-node@1.5.1-next.1 + ## 0.1.21-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-bitbucket-server/package.json b/plugins/catalog-backend-module-bitbucket-server/package.json index acba1bc02a..bf2130422b 100644 --- a/plugins/catalog-backend-module-bitbucket-server/package.json +++ b/plugins/catalog-backend-module-bitbucket-server/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-bitbucket-server", - "version": "0.1.21-next.0", + "version": "0.1.21-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-bitbucket/CHANGELOG.md b/plugins/catalog-backend-module-bitbucket/CHANGELOG.md index a611562cfe..3ceec86c77 100644 --- a/plugins/catalog-backend-module-bitbucket/CHANGELOG.md +++ b/plugins/catalog-backend-module-bitbucket/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-catalog-backend-module-bitbucket +## 0.2.23-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-bitbucket-cloud-common@0.2.15-next.1 + - @backstage/plugin-catalog-node@1.5.1-next.1 + ## 0.2.23-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-bitbucket/package.json b/plugins/catalog-backend-module-bitbucket/package.json index cc0d27df6b..75eb671f30 100644 --- a/plugins/catalog-backend-module-bitbucket/package.json +++ b/plugins/catalog-backend-module-bitbucket/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-bitbucket", "description": "A Backstage catalog backend module that helps integrate towards Bitbucket", - "version": "0.2.23-next.0", + "version": "0.2.23-next.1", "deprecated": true, "main": "src/index.ts", "types": "src/index.ts", diff --git a/plugins/catalog-backend-module-gcp/CHANGELOG.md b/plugins/catalog-backend-module-gcp/CHANGELOG.md index a438d1dc65..3af2589342 100644 --- a/plugins/catalog-backend-module-gcp/CHANGELOG.md +++ b/plugins/catalog-backend-module-gcp/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-catalog-backend-module-gcp +## 0.1.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-node@1.5.1-next.1 + ## 0.1.8-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-gcp/package.json b/plugins/catalog-backend-module-gcp/package.json index d33ffa9d47..e68aeaec66 100644 --- a/plugins/catalog-backend-module-gcp/package.json +++ b/plugins/catalog-backend-module-gcp/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-gcp", "description": "A Backstage catalog backend module that helps integrate towards GCP", - "version": "0.1.8-next.0", + "version": "0.1.8-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-gerrit/CHANGELOG.md b/plugins/catalog-backend-module-gerrit/CHANGELOG.md index b0f9d60904..6251a978b4 100644 --- a/plugins/catalog-backend-module-gerrit/CHANGELOG.md +++ b/plugins/catalog-backend-module-gerrit/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-catalog-backend-module-gerrit +## 0.1.24-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-node@1.5.1-next.1 + ## 0.1.24-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-gerrit/package.json b/plugins/catalog-backend-module-gerrit/package.json index 04e3457389..2bccaa62c2 100644 --- a/plugins/catalog-backend-module-gerrit/package.json +++ b/plugins/catalog-backend-module-gerrit/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-gerrit", - "version": "0.1.24-next.0", + "version": "0.1.24-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-github-org/CHANGELOG.md b/plugins/catalog-backend-module-github-org/CHANGELOG.md index cd9731e46c..dd857af17c 100644 --- a/plugins/catalog-backend-module-github-org/CHANGELOG.md +++ b/plugins/catalog-backend-module-github-org/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-catalog-backend-module-github-org +## 0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-backend-module-github@0.4.6-next.1 + - @backstage/plugin-catalog-node@1.5.1-next.1 + ## 0.1.2-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-github-org/package.json b/plugins/catalog-backend-module-github-org/package.json index a1abbd3207..b2d2904bc8 100644 --- a/plugins/catalog-backend-module-github-org/package.json +++ b/plugins/catalog-backend-module-github-org/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-github-org", "description": "The github-org backend module for the catalog plugin.", - "version": "0.1.2-next.0", + "version": "0.1.2-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-github/CHANGELOG.md b/plugins/catalog-backend-module-github/CHANGELOG.md index 535430f03b..780e095568 100644 --- a/plugins/catalog-backend-module-github/CHANGELOG.md +++ b/plugins/catalog-backend-module-github/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-catalog-backend-module-github +## 0.4.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.15.1-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.5.1-next.1 + - @backstage/plugin-events-node@0.2.17-next.1 + ## 0.4.6-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-github/package.json b/plugins/catalog-backend-module-github/package.json index e94b98e427..08f86b7feb 100644 --- a/plugins/catalog-backend-module-github/package.json +++ b/plugins/catalog-backend-module-github/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-github", "description": "A Backstage catalog backend module that helps integrate towards GitHub", - "version": "0.4.6-next.0", + "version": "0.4.6-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-gitlab/CHANGELOG.md b/plugins/catalog-backend-module-gitlab/CHANGELOG.md index 5d98bdd8c2..816002bd55 100644 --- a/plugins/catalog-backend-module-gitlab/CHANGELOG.md +++ b/plugins/catalog-backend-module-gitlab/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-catalog-backend-module-gitlab +## 0.3.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-node@1.5.1-next.1 + ## 0.3.5-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-gitlab/package.json b/plugins/catalog-backend-module-gitlab/package.json index d42961b665..0a9728756c 100644 --- a/plugins/catalog-backend-module-gitlab/package.json +++ b/plugins/catalog-backend-module-gitlab/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-gitlab", "description": "A Backstage catalog backend module that helps integrate towards GitLab", - "version": "0.3.5-next.0", + "version": "0.3.5-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md b/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md index f2b342aae6..d62732c7c2 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md +++ b/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-catalog-backend-module-incremental-ingestion +## 0.4.12-next.1 + +### Patch Changes + +- 43b2eb8f70: Ensure that cursors always come back as JSON on sqlite too +- Updated dependencies + - @backstage/plugin-catalog-backend@1.15.1-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-node@1.5.1-next.1 + - @backstage/plugin-events-node@0.2.17-next.1 + - @backstage/plugin-permission-common@0.7.10 + ## 0.4.12-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-incremental-ingestion/package.json b/plugins/catalog-backend-module-incremental-ingestion/package.json index 53677fdec2..003ee93d6a 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/package.json +++ b/plugins/catalog-backend-module-incremental-ingestion/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-incremental-ingestion", "description": "An entity provider for streaming large asset sources into the catalog", - "version": "0.4.12-next.0", + "version": "0.4.12-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-ldap/CHANGELOG.md b/plugins/catalog-backend-module-ldap/CHANGELOG.md index 987005f0a3..29a73c7239 100644 --- a/plugins/catalog-backend-module-ldap/CHANGELOG.md +++ b/plugins/catalog-backend-module-ldap/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-catalog-backend-module-ldap +## 0.5.23-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.5.1-next.1 + ## 0.5.23-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-ldap/package.json b/plugins/catalog-backend-module-ldap/package.json index fc1325c991..1fcf31f572 100644 --- a/plugins/catalog-backend-module-ldap/package.json +++ b/plugins/catalog-backend-module-ldap/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-ldap", "description": "A Backstage catalog backend module that helps integrate towards LDAP", - "version": "0.5.23-next.0", + "version": "0.5.23-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-msgraph/CHANGELOG.md b/plugins/catalog-backend-module-msgraph/CHANGELOG.md index e4d73b6745..ecdff69a6b 100644 --- a/plugins/catalog-backend-module-msgraph/CHANGELOG.md +++ b/plugins/catalog-backend-module-msgraph/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-catalog-backend-module-msgraph +## 0.5.15-next.1 + +### Patch Changes + +- 99fb54183b: Updated dependency `@azure/identity` to `^4.0.0`. +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.5.1-next.1 + ## 0.5.15-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-msgraph/package.json b/plugins/catalog-backend-module-msgraph/package.json index 52ff917585..e5767dbf10 100644 --- a/plugins/catalog-backend-module-msgraph/package.json +++ b/plugins/catalog-backend-module-msgraph/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-msgraph", "description": "A Backstage catalog backend module that helps integrate towards Microsoft Graph", - "version": "0.5.15-next.0", + "version": "0.5.15-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-openapi/CHANGELOG.md b/plugins/catalog-backend-module-openapi/CHANGELOG.md index 8b7743c39f..297b1d9393 100644 --- a/plugins/catalog-backend-module-openapi/CHANGELOG.md +++ b/plugins/catalog-backend-module-openapi/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-catalog-backend-module-openapi +## 0.1.25-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.15.1-next.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.5.1-next.1 + ## 0.1.25-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-openapi/package.json b/plugins/catalog-backend-module-openapi/package.json index 85e8cedb06..d1c3d7b605 100644 --- a/plugins/catalog-backend-module-openapi/package.json +++ b/plugins/catalog-backend-module-openapi/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-openapi", "description": "A Backstage catalog backend module that helps with OpenAPI specifications", - "version": "0.1.25-next.0", + "version": "0.1.25-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-puppetdb/CHANGELOG.md b/plugins/catalog-backend-module-puppetdb/CHANGELOG.md index 1a2febb565..0679c1f6e5 100644 --- a/plugins/catalog-backend-module-puppetdb/CHANGELOG.md +++ b/plugins/catalog-backend-module-puppetdb/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-catalog-backend-module-puppetdb +## 0.1.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-node@1.5.1-next.1 + ## 0.1.13-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-puppetdb/package.json b/plugins/catalog-backend-module-puppetdb/package.json index 751c37c16c..e908a1806a 100644 --- a/plugins/catalog-backend-module-puppetdb/package.json +++ b/plugins/catalog-backend-module-puppetdb/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-puppetdb", "description": "A Backstage catalog backend module that helps integrate towards PuppetDB", - "version": "0.1.13-next.0", + "version": "0.1.13-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md b/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md index f122b093e0..56edf10313 100644 --- a/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md +++ b/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-catalog-backend-module-scaffolder-entity-model +## 0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.5.1-next.1 + - @backstage/plugin-scaffolder-common@1.4.3 + ## 0.1.5-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-scaffolder-entity-model/package.json b/plugins/catalog-backend-module-scaffolder-entity-model/package.json index 638aa6d104..ed1bf21a26 100644 --- a/plugins/catalog-backend-module-scaffolder-entity-model/package.json +++ b/plugins/catalog-backend-module-scaffolder-entity-model/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-scaffolder-entity-model", "description": "Adds support for the scaffolder specific entity model (e.g. the Template kind) to the catalog backend plugin.", - "version": "0.1.5-next.0", + "version": "0.1.5-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-unprocessed/CHANGELOG.md b/plugins/catalog-backend-module-unprocessed/CHANGELOG.md index 45dbc74091..3bf8cf6245 100644 --- a/plugins/catalog-backend-module-unprocessed/CHANGELOG.md +++ b/plugins/catalog-backend-module-unprocessed/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-catalog-backend-module-unprocessed +## 0.3.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-auth-node@0.4.2-next.1 + ## 0.3.5-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-unprocessed/package.json b/plugins/catalog-backend-module-unprocessed/package.json index 9e0f29285e..3e4efb5715 100644 --- a/plugins/catalog-backend-module-unprocessed/package.json +++ b/plugins/catalog-backend-module-unprocessed/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-unprocessed", "description": "Backstage Catalog module to view unprocessed entities", - "version": "0.3.5-next.0", + "version": "0.3.5-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend/CHANGELOG.md b/plugins/catalog-backend/CHANGELOG.md index cb721208a3..c689547470 100644 --- a/plugins/catalog-backend/CHANGELOG.md +++ b/plugins/catalog-backend/CHANGELOG.md @@ -1,5 +1,30 @@ # @backstage/plugin-catalog-backend +## 1.15.1-next.1 + +### Patch Changes + +- 38340678c3: Update the OpenAPI spec to support the use of `openapi-generator`. +- 7123c58b3d: Updated dependency `@types/glob` to `^8.0.0`. +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-openapi-utils@0.1.1-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.5.1-next.1 + - @backstage/plugin-events-node@0.2.17-next.1 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.1 + - @backstage/plugin-search-backend-module-catalog@0.1.12-next.1 + ## 1.15.1-next.0 ### Patch Changes diff --git a/plugins/catalog-backend/package.json b/plugins/catalog-backend/package.json index 682d293086..cd83510bdc 100644 --- a/plugins/catalog-backend/package.json +++ b/plugins/catalog-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend", "description": "The Backstage backend plugin that provides the Backstage catalog", - "version": "1.15.1-next.0", + "version": "1.15.1-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-graph/CHANGELOG.md b/plugins/catalog-graph/CHANGELOG.md index 7c5667aa3b..a91217563d 100644 --- a/plugins/catalog-graph/CHANGELOG.md +++ b/plugins/catalog-graph/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-catalog-graph +## 0.3.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + ## 0.3.2-next.0 ### Patch Changes diff --git a/plugins/catalog-graph/package.json b/plugins/catalog-graph/package.json index a8be8619a4..2552f38f8a 100644 --- a/plugins/catalog-graph/package.json +++ b/plugins/catalog-graph/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-graph", - "version": "0.3.2-next.0", + "version": "0.3.2-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-import/CHANGELOG.md b/plugins/catalog-import/CHANGELOG.md index b5e55fa324..347d787911 100644 --- a/plugins/catalog-import/CHANGELOG.md +++ b/plugins/catalog-import/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-catalog-import +## 0.10.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/integration@1.8.0-next.1 + - @backstage/core-compat-api@0.0.1-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.18 + ## 0.10.4-next.1 ### Patch Changes diff --git a/plugins/catalog-import/package.json b/plugins/catalog-import/package.json index 23e0ea6755..be0793b026 100644 --- a/plugins/catalog-import/package.json +++ b/plugins/catalog-import/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-import", "description": "A Backstage plugin the helps you import entities into your catalog", - "version": "0.10.4-next.1", + "version": "0.10.4-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-node/CHANGELOG.md b/plugins/catalog-node/CHANGELOG.md index 20e5462e95..175d4c33c0 100644 --- a/plugins/catalog-node/CHANGELOG.md +++ b/plugins/catalog-node/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-catalog-node +## 1.5.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + ## 1.5.1-next.0 ### Patch Changes diff --git a/plugins/catalog-node/package.json b/plugins/catalog-node/package.json index f07ffd2c91..f76fde6ecf 100644 --- a/plugins/catalog-node/package.json +++ b/plugins/catalog-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-node", "description": "The plugin-catalog-node module for @backstage/plugin-catalog-backend", - "version": "1.5.1-next.0", + "version": "1.5.1-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-react/CHANGELOG.md b/plugins/catalog-react/CHANGELOG.md index 7bbbc00716..c4618fc659 100644 --- a/plugins/catalog-react/CHANGELOG.md +++ b/plugins/catalog-react/CHANGELOG.md @@ -1,5 +1,31 @@ # @backstage/plugin-catalog-react +## 1.9.2-next.1 + +### Patch Changes + +- 53600976bb: Ensure that passed-in icons are taken advantage of in the presentation API +- 08d9e67199: Add default icon for kind resource. +- a5a04739e1: Internal refactor of alpha exports due to a change in how extension factories are defined. +- e223f2264d: Breaking alpha-API change to entity visibility filter functions to accept a bare entity as their first argument, instead of an object with an entity property. + + Functions that accept such filters now also support the string expression form of filters. + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/plugin-permission-react@0.4.18-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-permission-common@0.7.10 + ## 1.9.2-next.0 ### Patch Changes diff --git a/plugins/catalog-react/package.json b/plugins/catalog-react/package.json index 1017cbf70b..4869b44cb8 100644 --- a/plugins/catalog-react/package.json +++ b/plugins/catalog-react/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-react", "description": "A frontend library that helps other Backstage plugins interact with the catalog", - "version": "1.9.2-next.0", + "version": "1.9.2-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-unprocessed-entities/CHANGELOG.md b/plugins/catalog-unprocessed-entities/CHANGELOG.md index 44fcaa4626..171f26282a 100644 --- a/plugins/catalog-unprocessed-entities/CHANGELOG.md +++ b/plugins/catalog-unprocessed-entities/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-catalog-unprocessed-entities +## 0.1.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + ## 0.1.6-next.0 ### Patch Changes diff --git a/plugins/catalog-unprocessed-entities/package.json b/plugins/catalog-unprocessed-entities/package.json index d1e466d27c..a443949861 100644 --- a/plugins/catalog-unprocessed-entities/package.json +++ b/plugins/catalog-unprocessed-entities/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-unprocessed-entities", - "version": "0.1.6-next.0", + "version": "0.1.6-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog/CHANGELOG.md b/plugins/catalog/CHANGELOG.md index 95bbf0bfb6..02a765dcf4 100644 --- a/plugins/catalog/CHANGELOG.md +++ b/plugins/catalog/CHANGELOG.md @@ -1,5 +1,35 @@ # @backstage/plugin-catalog +## 1.16.0-next.2 + +### Minor Changes + +- e223f2264d: Properly support both function- and string-form visibility filter expressions in the new extensions exported via `/alpha`. + +### Patch Changes + +- 53600976bb: Ensure that passed-in icons are taken advantage of in the presentation API +- a5a04739e1: Internal refactor of alpha exports due to a change in how extension factories are defined. +- 78a10bb085: Adding in spec.type chip to search results for clarity +- fb8f3bdbc2: Updated alpha translation message keys to use nested format and camel case. +- 531e1a2a79: Updated alpha plugin to include the `unregisterRedirect` external route. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/plugin-search-react@1.7.4-next.1 + - @backstage/core-compat-api@0.0.1-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-scaffolder-common@1.4.3 + - @backstage/plugin-search-common@1.2.8 + ## 1.16.0-next.1 ### Patch Changes diff --git a/plugins/catalog/package.json b/plugins/catalog/package.json index 1ac4fe3b73..88ee613922 100644 --- a/plugins/catalog/package.json +++ b/plugins/catalog/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog", "description": "The Backstage plugin for browsing the Backstage catalog", - "version": "1.16.0-next.1", + "version": "1.16.0-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/cicd-statistics-module-gitlab/CHANGELOG.md b/plugins/cicd-statistics-module-gitlab/CHANGELOG.md index 06bce48963..0a86a58cc5 100644 --- a/plugins/cicd-statistics-module-gitlab/CHANGELOG.md +++ b/plugins/cicd-statistics-module-gitlab/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-cicd-statistics-module-gitlab +## 0.1.24-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-cicd-statistics@0.1.30-next.1 + - @backstage/catalog-model@1.4.3 + ## 0.1.24-next.0 ### Patch Changes diff --git a/plugins/cicd-statistics-module-gitlab/package.json b/plugins/cicd-statistics-module-gitlab/package.json index 15c0602394..534060d805 100644 --- a/plugins/cicd-statistics-module-gitlab/package.json +++ b/plugins/cicd-statistics-module-gitlab/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-cicd-statistics-module-gitlab", "description": "CI/CD Statistics plugin module; Gitlab CICD", - "version": "0.1.24-next.0", + "version": "0.1.24-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/cicd-statistics/CHANGELOG.md b/plugins/cicd-statistics/CHANGELOG.md index 0cdd53dc87..187f00e25f 100644 --- a/plugins/cicd-statistics/CHANGELOG.md +++ b/plugins/cicd-statistics/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-cicd-statistics +## 0.1.30-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + ## 0.1.30-next.0 ### Patch Changes diff --git a/plugins/cicd-statistics/package.json b/plugins/cicd-statistics/package.json index 35a44e3fd0..f2bf5b9a64 100644 --- a/plugins/cicd-statistics/package.json +++ b/plugins/cicd-statistics/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-cicd-statistics", "description": "A frontend plugin visualizing CI/CD pipeline statistics (build time)", - "version": "0.1.30-next.0", + "version": "0.1.30-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/circleci/CHANGELOG.md b/plugins/circleci/CHANGELOG.md index 79a0b71b57..4740e2afb6 100644 --- a/plugins/circleci/CHANGELOG.md +++ b/plugins/circleci/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-circleci +## 0.3.28-next.1 + +### Patch Changes + +- 375b6f7d68: CircelCI plugin moved permanently +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + ## 0.3.28-next.0 ### Patch Changes diff --git a/plugins/circleci/package.json b/plugins/circleci/package.json index 7075a383a8..b3dadfb55b 100644 --- a/plugins/circleci/package.json +++ b/plugins/circleci/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-circleci", "description": "A Backstage plugin that integrates towards Circle CI", - "version": "0.3.28-next.0", + "version": "0.3.28-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/cloudbuild/CHANGELOG.md b/plugins/cloudbuild/CHANGELOG.md index 32ea259d87..b4403f7678 100644 --- a/plugins/cloudbuild/CHANGELOG.md +++ b/plugins/cloudbuild/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-cloudbuild +## 0.3.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + ## 0.3.28-next.0 ### Patch Changes diff --git a/plugins/cloudbuild/package.json b/plugins/cloudbuild/package.json index 1caaf87edd..f480404563 100644 --- a/plugins/cloudbuild/package.json +++ b/plugins/cloudbuild/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-cloudbuild", "description": "A Backstage plugin that integrates towards Google Cloud Build", - "version": "0.3.28-next.0", + "version": "0.3.28-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/code-climate/CHANGELOG.md b/plugins/code-climate/CHANGELOG.md index dd10502cf0..b10c55fe3a 100644 --- a/plugins/code-climate/CHANGELOG.md +++ b/plugins/code-climate/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-code-climate +## 0.1.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + ## 0.1.28-next.0 ### Patch Changes diff --git a/plugins/code-climate/package.json b/plugins/code-climate/package.json index 5210337fda..f0800fce83 100644 --- a/plugins/code-climate/package.json +++ b/plugins/code-climate/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-code-climate", - "version": "0.1.28-next.0", + "version": "0.1.28-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/code-coverage-backend/CHANGELOG.md b/plugins/code-coverage-backend/CHANGELOG.md index 08fe1692d8..37aedd5dce 100644 --- a/plugins/code-coverage-backend/CHANGELOG.md +++ b/plugins/code-coverage-backend/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-code-coverage-backend +## 0.2.22-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.1 + ## 0.2.22-next.0 ### Patch Changes diff --git a/plugins/code-coverage-backend/package.json b/plugins/code-coverage-backend/package.json index 4bd83b92f6..61f21d7438 100644 --- a/plugins/code-coverage-backend/package.json +++ b/plugins/code-coverage-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-code-coverage-backend", "description": "A Backstage backend plugin that helps you keep track of your code coverage", - "version": "0.2.22-next.0", + "version": "0.2.22-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/code-coverage/CHANGELOG.md b/plugins/code-coverage/CHANGELOG.md index a29cf758a8..d64996306c 100644 --- a/plugins/code-coverage/CHANGELOG.md +++ b/plugins/code-coverage/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-code-coverage +## 0.2.21-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + ## 0.2.21-next.0 ### Patch Changes diff --git a/plugins/code-coverage/package.json b/plugins/code-coverage/package.json index c4fda6c18b..e03d65a7b2 100644 --- a/plugins/code-coverage/package.json +++ b/plugins/code-coverage/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-code-coverage", "description": "A Backstage plugin that helps you keep track of your code coverage", - "version": "0.2.21-next.0", + "version": "0.2.21-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/codescene/CHANGELOG.md b/plugins/codescene/CHANGELOG.md index 36af453283..2d7f295123 100644 --- a/plugins/codescene/CHANGELOG.md +++ b/plugins/codescene/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-codescene +## 0.1.20-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + ## 0.1.20-next.0 ### Patch Changes diff --git a/plugins/codescene/package.json b/plugins/codescene/package.json index 9296b76c55..d21f66ac2b 100644 --- a/plugins/codescene/package.json +++ b/plugins/codescene/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-codescene", - "version": "0.1.20-next.0", + "version": "0.1.20-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/config-schema/CHANGELOG.md b/plugins/config-schema/CHANGELOG.md index b05b2e5e85..b57892c764 100644 --- a/plugins/config-schema/CHANGELOG.md +++ b/plugins/config-schema/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-config-schema +## 0.1.48-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + ## 0.1.48-next.0 ### Patch Changes diff --git a/plugins/config-schema/package.json b/plugins/config-schema/package.json index da59ec9de9..12740e5f49 100644 --- a/plugins/config-schema/package.json +++ b/plugins/config-schema/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-config-schema", "description": "A Backstage plugin that lets you browse the configuration schema of your app", - "version": "0.1.48-next.0", + "version": "0.1.48-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/cost-insights/CHANGELOG.md b/plugins/cost-insights/CHANGELOG.md index 471675b140..c941b62f66 100644 --- a/plugins/cost-insights/CHANGELOG.md +++ b/plugins/cost-insights/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-cost-insights +## 0.12.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-cost-insights-common@0.1.2 + ## 0.12.17-next.0 ### Patch Changes diff --git a/plugins/cost-insights/package.json b/plugins/cost-insights/package.json index 88166e729d..c9258bc464 100644 --- a/plugins/cost-insights/package.json +++ b/plugins/cost-insights/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-cost-insights", "description": "A Backstage plugin that helps you keep track of your cloud spend", - "version": "0.12.17-next.0", + "version": "0.12.17-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/devtools-backend/CHANGELOG.md b/plugins/devtools-backend/CHANGELOG.md index a1e9a0d4fd..655743c818 100644 --- a/plugins/devtools-backend/CHANGELOG.md +++ b/plugins/devtools-backend/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-devtools-backend +## 0.2.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/config-loader@1.5.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-devtools-common@0.1.6 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.1 + ## 0.2.5-next.0 ### Patch Changes diff --git a/plugins/devtools-backend/package.json b/plugins/devtools-backend/package.json index f4976a695f..b445c25ae6 100644 --- a/plugins/devtools-backend/package.json +++ b/plugins/devtools-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-devtools-backend", - "version": "0.2.5-next.0", + "version": "0.2.5-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/devtools/CHANGELOG.md b/plugins/devtools/CHANGELOG.md index f00218080d..a71d43fbd8 100644 --- a/plugins/devtools/CHANGELOG.md +++ b/plugins/devtools/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-devtools +## 0.1.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-permission-react@0.4.18-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-devtools-common@0.1.6 + ## 0.1.7-next.0 ### Patch Changes diff --git a/plugins/devtools/package.json b/plugins/devtools/package.json index 9f0318df40..67cbae9802 100644 --- a/plugins/devtools/package.json +++ b/plugins/devtools/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-devtools", - "version": "0.1.7-next.0", + "version": "0.1.7-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/dynatrace/CHANGELOG.md b/plugins/dynatrace/CHANGELOG.md index 180444eabd..102f88c562 100644 --- a/plugins/dynatrace/CHANGELOG.md +++ b/plugins/dynatrace/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-dynatrace +## 8.0.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + ## 8.0.2-next.0 ### Patch Changes diff --git a/plugins/dynatrace/package.json b/plugins/dynatrace/package.json index cd09c89a1c..552ebfaed3 100644 --- a/plugins/dynatrace/package.json +++ b/plugins/dynatrace/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-dynatrace", - "version": "8.0.2-next.0", + "version": "8.0.2-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/entity-feedback-backend/CHANGELOG.md b/plugins/entity-feedback-backend/CHANGELOG.md index 441859172c..101e8b0654 100644 --- a/plugins/entity-feedback-backend/CHANGELOG.md +++ b/plugins/entity-feedback-backend/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-entity-feedback-backend +## 0.2.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-entity-feedback-common@0.1.3 + ## 0.2.5-next.0 ### Patch Changes diff --git a/plugins/entity-feedback-backend/package.json b/plugins/entity-feedback-backend/package.json index e13f20fa64..c232a67307 100644 --- a/plugins/entity-feedback-backend/package.json +++ b/plugins/entity-feedback-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-entity-feedback-backend", - "version": "0.2.5-next.0", + "version": "0.2.5-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/entity-feedback/CHANGELOG.md b/plugins/entity-feedback/CHANGELOG.md index e890abd312..622d5c98f8 100644 --- a/plugins/entity-feedback/CHANGELOG.md +++ b/plugins/entity-feedback/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-entity-feedback +## 0.2.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-entity-feedback-common@0.1.3 + ## 0.2.11-next.0 ### Patch Changes diff --git a/plugins/entity-feedback/package.json b/plugins/entity-feedback/package.json index 4569a53c34..ab6c40e51e 100644 --- a/plugins/entity-feedback/package.json +++ b/plugins/entity-feedback/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-entity-feedback", - "version": "0.2.11-next.0", + "version": "0.2.11-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/entity-validation/CHANGELOG.md b/plugins/entity-validation/CHANGELOG.md index 3c5dd92fa1..843be5d6d1 100644 --- a/plugins/entity-validation/CHANGELOG.md +++ b/plugins/entity-validation/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-entity-validation +## 0.1.13-next.1 + +### Patch Changes + +- a518c5a25b: Updated dependency `@react-hookz/web` to `^23.0.0`. +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-catalog-common@1.0.18 + ## 0.1.13-next.0 ### Patch Changes diff --git a/plugins/entity-validation/package.json b/plugins/entity-validation/package.json index ce040e0c0c..dc0bd93565 100644 --- a/plugins/entity-validation/package.json +++ b/plugins/entity-validation/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-entity-validation", - "version": "0.1.13-next.0", + "version": "0.1.13-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/events-backend-module-aws-sqs/CHANGELOG.md b/plugins/events-backend-module-aws-sqs/CHANGELOG.md index c4f5ad2d51..113a641795 100644 --- a/plugins/events-backend-module-aws-sqs/CHANGELOG.md +++ b/plugins/events-backend-module-aws-sqs/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-events-backend-module-aws-sqs +## 0.2.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-events-node@0.2.17-next.1 + ## 0.2.11-next.0 ### Patch Changes diff --git a/plugins/events-backend-module-aws-sqs/package.json b/plugins/events-backend-module-aws-sqs/package.json index 74a36221e3..627aedd0be 100644 --- a/plugins/events-backend-module-aws-sqs/package.json +++ b/plugins/events-backend-module-aws-sqs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-aws-sqs", - "version": "0.2.11-next.0", + "version": "0.2.11-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/events-backend-module-azure/CHANGELOG.md b/plugins/events-backend-module-azure/CHANGELOG.md index 6ff642a8e3..e5ae8e0536 100644 --- a/plugins/events-backend-module-azure/CHANGELOG.md +++ b/plugins/events-backend-module-azure/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-events-backend-module-azure +## 0.1.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/plugin-events-node@0.2.17-next.1 + ## 0.1.18-next.0 ### Patch Changes diff --git a/plugins/events-backend-module-azure/package.json b/plugins/events-backend-module-azure/package.json index c4df3cc562..7908478ba7 100644 --- a/plugins/events-backend-module-azure/package.json +++ b/plugins/events-backend-module-azure/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-azure", - "version": "0.1.18-next.0", + "version": "0.1.18-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/events-backend-module-bitbucket-cloud/CHANGELOG.md b/plugins/events-backend-module-bitbucket-cloud/CHANGELOG.md index 0a74f17134..d33369f7b5 100644 --- a/plugins/events-backend-module-bitbucket-cloud/CHANGELOG.md +++ b/plugins/events-backend-module-bitbucket-cloud/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-events-backend-module-bitbucket-cloud +## 0.1.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/plugin-events-node@0.2.17-next.1 + ## 0.1.18-next.0 ### Patch Changes diff --git a/plugins/events-backend-module-bitbucket-cloud/package.json b/plugins/events-backend-module-bitbucket-cloud/package.json index 68783b5478..ed1c10f433 100644 --- a/plugins/events-backend-module-bitbucket-cloud/package.json +++ b/plugins/events-backend-module-bitbucket-cloud/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-bitbucket-cloud", - "version": "0.1.18-next.0", + "version": "0.1.18-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/events-backend-module-gerrit/CHANGELOG.md b/plugins/events-backend-module-gerrit/CHANGELOG.md index 300f445915..156a8f24d8 100644 --- a/plugins/events-backend-module-gerrit/CHANGELOG.md +++ b/plugins/events-backend-module-gerrit/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-events-backend-module-gerrit +## 0.1.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/plugin-events-node@0.2.17-next.1 + ## 0.1.18-next.0 ### Patch Changes diff --git a/plugins/events-backend-module-gerrit/package.json b/plugins/events-backend-module-gerrit/package.json index 882aa89f5e..24a70d19bf 100644 --- a/plugins/events-backend-module-gerrit/package.json +++ b/plugins/events-backend-module-gerrit/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-gerrit", - "version": "0.1.18-next.0", + "version": "0.1.18-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/events-backend-module-github/CHANGELOG.md b/plugins/events-backend-module-github/CHANGELOG.md index 0d68ab29f1..725de56c46 100644 --- a/plugins/events-backend-module-github/CHANGELOG.md +++ b/plugins/events-backend-module-github/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-events-backend-module-github +## 0.1.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.17-next.1 + ## 0.1.18-next.0 ### Patch Changes diff --git a/plugins/events-backend-module-github/package.json b/plugins/events-backend-module-github/package.json index acc0a7fcf9..fe57a4ffbd 100644 --- a/plugins/events-backend-module-github/package.json +++ b/plugins/events-backend-module-github/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-github", - "version": "0.1.18-next.0", + "version": "0.1.18-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/events-backend-module-gitlab/CHANGELOG.md b/plugins/events-backend-module-gitlab/CHANGELOG.md index ce34e6fe75..c13f8865d5 100644 --- a/plugins/events-backend-module-gitlab/CHANGELOG.md +++ b/plugins/events-backend-module-gitlab/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-events-backend-module-gitlab +## 0.1.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.17-next.1 + ## 0.1.18-next.0 ### Patch Changes diff --git a/plugins/events-backend-module-gitlab/package.json b/plugins/events-backend-module-gitlab/package.json index 794e6cba27..b8000bbe2e 100644 --- a/plugins/events-backend-module-gitlab/package.json +++ b/plugins/events-backend-module-gitlab/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-gitlab", - "version": "0.1.18-next.0", + "version": "0.1.18-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/events-backend-test-utils/CHANGELOG.md b/plugins/events-backend-test-utils/CHANGELOG.md index 505bdcd256..96b8d616ea 100644 --- a/plugins/events-backend-test-utils/CHANGELOG.md +++ b/plugins/events-backend-test-utils/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-events-backend-test-utils +## 0.1.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.2.17-next.1 + ## 0.1.18-next.0 ### Patch Changes diff --git a/plugins/events-backend-test-utils/package.json b/plugins/events-backend-test-utils/package.json index e82047e483..ddb5ab31d1 100644 --- a/plugins/events-backend-test-utils/package.json +++ b/plugins/events-backend-test-utils/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-events-backend-test-utils", "description": "The plugin-events-backend-test-utils for @backstage/plugin-events-node", - "version": "0.1.18-next.0", + "version": "0.1.18-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/events-backend/CHANGELOG.md b/plugins/events-backend/CHANGELOG.md index 2c0c2cbf70..80cfe97cc2 100644 --- a/plugins/events-backend/CHANGELOG.md +++ b/plugins/events-backend/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-events-backend +## 0.2.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.17-next.1 + ## 0.2.17-next.0 ### Patch Changes diff --git a/plugins/events-backend/package.json b/plugins/events-backend/package.json index 1288abf0a3..f6c3398952 100644 --- a/plugins/events-backend/package.json +++ b/plugins/events-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend", - "version": "0.2.17-next.0", + "version": "0.2.17-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/events-node/CHANGELOG.md b/plugins/events-node/CHANGELOG.md index 787e3daa7b..4c2b466971 100644 --- a/plugins/events-node/CHANGELOG.md +++ b/plugins/events-node/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-events-node +## 0.2.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.1 + ## 0.2.17-next.0 ### Patch Changes diff --git a/plugins/events-node/package.json b/plugins/events-node/package.json index 531138ff69..b56c54125f 100644 --- a/plugins/events-node/package.json +++ b/plugins/events-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-events-node", "description": "The plugin-events-node module for @backstage/plugin-events-backend", - "version": "0.2.17-next.0", + "version": "0.2.17-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/example-todo-list-backend/CHANGELOG.md b/plugins/example-todo-list-backend/CHANGELOG.md index 1cc13d252a..36106c9b4b 100644 --- a/plugins/example-todo-list-backend/CHANGELOG.md +++ b/plugins/example-todo-list-backend/CHANGELOG.md @@ -1,5 +1,16 @@ # @internal/plugin-todo-list-backend +## 1.0.20-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.1 + ## 1.0.20-next.0 ### Patch Changes diff --git a/plugins/example-todo-list-backend/package.json b/plugins/example-todo-list-backend/package.json index a04643c4c2..ad2997423a 100644 --- a/plugins/example-todo-list-backend/package.json +++ b/plugins/example-todo-list-backend/package.json @@ -1,6 +1,6 @@ { "name": "@internal/plugin-todo-list-backend", - "version": "1.0.20-next.0", + "version": "1.0.20-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/example-todo-list/CHANGELOG.md b/plugins/example-todo-list/CHANGELOG.md index b3a8a8f93d..0e7e213137 100644 --- a/plugins/example-todo-list/CHANGELOG.md +++ b/plugins/example-todo-list/CHANGELOG.md @@ -1,5 +1,14 @@ # @internal/plugin-todo-list +## 1.0.20-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.0 + ## 1.0.20-next.0 ### Patch Changes diff --git a/plugins/example-todo-list/package.json b/plugins/example-todo-list/package.json index d08efb9d22..9538280e94 100644 --- a/plugins/example-todo-list/package.json +++ b/plugins/example-todo-list/package.json @@ -1,6 +1,6 @@ { "name": "@internal/plugin-todo-list", - "version": "1.0.20-next.0", + "version": "1.0.20-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/explore-backend/CHANGELOG.md b/plugins/explore-backend/CHANGELOG.md index 9e7c38e8f8..c880ce5374 100644 --- a/plugins/explore-backend/CHANGELOG.md +++ b/plugins/explore-backend/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-explore-backend +## 0.0.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-backend-module-explore@0.1.12-next.1 + - @backstage/plugin-search-common@1.2.8 + ## 0.0.18-next.0 ### Patch Changes diff --git a/plugins/explore-backend/package.json b/plugins/explore-backend/package.json index ac94ef4c05..8f53a106d6 100644 --- a/plugins/explore-backend/package.json +++ b/plugins/explore-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-explore-backend", - "version": "0.0.18-next.0", + "version": "0.0.18-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/explore-react/CHANGELOG.md b/plugins/explore-react/CHANGELOG.md index 59a6c265d0..08217fd6de 100644 --- a/plugins/explore-react/CHANGELOG.md +++ b/plugins/explore-react/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-explore-react +## 0.0.34-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-explore-common@0.0.2 + ## 0.0.34-next.0 ### Patch Changes diff --git a/plugins/explore-react/package.json b/plugins/explore-react/package.json index 65e554db77..aee56ab3fd 100644 --- a/plugins/explore-react/package.json +++ b/plugins/explore-react/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-explore-react", "description": "A frontend library for Backstage plugins that want to interact with the explore plugin", - "version": "0.0.34-next.0", + "version": "0.0.34-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/explore/CHANGELOG.md b/plugins/explore/CHANGELOG.md index 091216334f..8a42d288fe 100644 --- a/plugins/explore/CHANGELOG.md +++ b/plugins/explore/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-explore +## 0.4.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-search-react@1.7.4-next.1 + - @backstage/plugin-explore-react@0.0.34-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-common@1.2.8 + ## 0.4.14-next.0 ### Patch Changes diff --git a/plugins/explore/package.json b/plugins/explore/package.json index b1169ae515..382b3b6691 100644 --- a/plugins/explore/package.json +++ b/plugins/explore/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-explore", "description": "A Backstage plugin for building an exploration page of your software ecosystem", - "version": "0.4.14-next.0", + "version": "0.4.14-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/firehydrant/CHANGELOG.md b/plugins/firehydrant/CHANGELOG.md index 53b350f331..fff099f63c 100644 --- a/plugins/firehydrant/CHANGELOG.md +++ b/plugins/firehydrant/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-firehydrant +## 0.2.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + ## 0.2.12-next.0 ### Patch Changes diff --git a/plugins/firehydrant/package.json b/plugins/firehydrant/package.json index 19f4ed58d6..953bebce22 100644 --- a/plugins/firehydrant/package.json +++ b/plugins/firehydrant/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-firehydrant", "description": "A Backstage plugin that integrates towards FireHydrant", - "version": "0.2.12-next.0", + "version": "0.2.12-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/fossa/CHANGELOG.md b/plugins/fossa/CHANGELOG.md index fea4e21868..26e1272aa8 100644 --- a/plugins/fossa/CHANGELOG.md +++ b/plugins/fossa/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-fossa +## 0.2.60-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + ## 0.2.60-next.0 ### Patch Changes diff --git a/plugins/fossa/package.json b/plugins/fossa/package.json index be34560e1b..cca6446a46 100644 --- a/plugins/fossa/package.json +++ b/plugins/fossa/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-fossa", "description": "A Backstage plugin that integrates towards FOSSA", - "version": "0.2.60-next.0", + "version": "0.2.60-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/gcalendar/CHANGELOG.md b/plugins/gcalendar/CHANGELOG.md index e8663cb365..627f65b156 100644 --- a/plugins/gcalendar/CHANGELOG.md +++ b/plugins/gcalendar/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-gcalendar +## 0.3.21-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + ## 0.3.21-next.0 ### Patch Changes diff --git a/plugins/gcalendar/package.json b/plugins/gcalendar/package.json index c75c431f18..8bd2d578e2 100644 --- a/plugins/gcalendar/package.json +++ b/plugins/gcalendar/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-gcalendar", - "version": "0.3.21-next.0", + "version": "0.3.21-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/gcp-projects/CHANGELOG.md b/plugins/gcp-projects/CHANGELOG.md index c1a3f6ca6d..65d1fe430e 100644 --- a/plugins/gcp-projects/CHANGELOG.md +++ b/plugins/gcp-projects/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-gcp-projects +## 0.3.44-next.1 + +### Patch Changes + +- a518c5a25b: Updated dependency `@react-hookz/web` to `^23.0.0`. +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.0 + ## 0.3.44-next.0 ### Patch Changes diff --git a/plugins/gcp-projects/package.json b/plugins/gcp-projects/package.json index 73fdba578d..004309ebb6 100644 --- a/plugins/gcp-projects/package.json +++ b/plugins/gcp-projects/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-gcp-projects", "description": "A Backstage plugin that helps you manage projects in GCP", - "version": "0.3.44-next.0", + "version": "0.3.44-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/git-release-manager/CHANGELOG.md b/plugins/git-release-manager/CHANGELOG.md index 3c4beb18b0..e4737858c3 100644 --- a/plugins/git-release-manager/CHANGELOG.md +++ b/plugins/git-release-manager/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-git-release-manager +## 0.3.40-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/theme@0.5.0-next.0 + ## 0.3.40-next.0 ### Patch Changes diff --git a/plugins/git-release-manager/package.json b/plugins/git-release-manager/package.json index c0454d5b3b..b0380670e4 100644 --- a/plugins/git-release-manager/package.json +++ b/plugins/git-release-manager/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-git-release-manager", "description": "A Backstage plugin that helps you manage releases in git", - "version": "0.3.40-next.0", + "version": "0.3.40-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/github-actions/CHANGELOG.md b/plugins/github-actions/CHANGELOG.md index 4466f730c3..78f9b7a699 100644 --- a/plugins/github-actions/CHANGELOG.md +++ b/plugins/github-actions/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-github-actions +## 0.6.9-next.1 + +### Patch Changes + +- 08d7e4676a: Github Workflow Runs UI is modified to show in optional Card view instead of table, with branch selection option +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + ## 0.6.9-next.0 ### Patch Changes diff --git a/plugins/github-actions/package.json b/plugins/github-actions/package.json index fe419c47b7..3d47fa4ed8 100644 --- a/plugins/github-actions/package.json +++ b/plugins/github-actions/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-github-actions", "description": "A Backstage plugin that integrates towards GitHub Actions", - "version": "0.6.9-next.0", + "version": "0.6.9-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/github-deployments/CHANGELOG.md b/plugins/github-deployments/CHANGELOG.md index 7945e4810d..cab881189f 100644 --- a/plugins/github-deployments/CHANGELOG.md +++ b/plugins/github-deployments/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-github-deployments +## 0.1.59-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + ## 0.1.59-next.0 ### Patch Changes diff --git a/plugins/github-deployments/package.json b/plugins/github-deployments/package.json index a3a7383151..8db532b20e 100644 --- a/plugins/github-deployments/package.json +++ b/plugins/github-deployments/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-github-deployments", "description": "A Backstage plugin that integrates towards GitHub Deployments", - "version": "0.1.59-next.0", + "version": "0.1.59-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/github-issues/CHANGELOG.md b/plugins/github-issues/CHANGELOG.md index 2f6ab11e34..473c325dd4 100644 --- a/plugins/github-issues/CHANGELOG.md +++ b/plugins/github-issues/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-github-issues +## 0.2.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + ## 0.2.17-next.0 ### Patch Changes diff --git a/plugins/github-issues/package.json b/plugins/github-issues/package.json index bf6b8a39fd..d8b19cf5df 100644 --- a/plugins/github-issues/package.json +++ b/plugins/github-issues/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-github-issues", - "version": "0.2.17-next.0", + "version": "0.2.17-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/github-pull-requests-board/CHANGELOG.md b/plugins/github-pull-requests-board/CHANGELOG.md index 6dfb8de0c8..2e697a4771 100644 --- a/plugins/github-pull-requests-board/CHANGELOG.md +++ b/plugins/github-pull-requests-board/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-github-pull-requests-board +## 0.1.22-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + ## 0.1.22-next.0 ### Patch Changes diff --git a/plugins/github-pull-requests-board/package.json b/plugins/github-pull-requests-board/package.json index fe792bd7ab..b160ae27e8 100644 --- a/plugins/github-pull-requests-board/package.json +++ b/plugins/github-pull-requests-board/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-github-pull-requests-board", "description": "A Backstage plugin that allows you to see all open Pull Requests for all the repositories owned by your team", - "version": "0.1.22-next.0", + "version": "0.1.22-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/gitops-profiles/CHANGELOG.md b/plugins/gitops-profiles/CHANGELOG.md index 5cbca6f5d7..24aa989eff 100644 --- a/plugins/gitops-profiles/CHANGELOG.md +++ b/plugins/gitops-profiles/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-gitops-profiles +## 0.3.43-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + ## 0.3.43-next.0 ### Patch Changes diff --git a/plugins/gitops-profiles/package.json b/plugins/gitops-profiles/package.json index e5befa4e8e..d599d328be 100644 --- a/plugins/gitops-profiles/package.json +++ b/plugins/gitops-profiles/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-gitops-profiles", "description": "A Backstage plugin that helps you manage GitOps profiles", - "version": "0.3.43-next.0", + "version": "0.3.43-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/gocd/CHANGELOG.md b/plugins/gocd/CHANGELOG.md index e0d44dfe91..54be67883c 100644 --- a/plugins/gocd/CHANGELOG.md +++ b/plugins/gocd/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-gocd +## 0.1.34-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + ## 0.1.34-next.0 ### Patch Changes diff --git a/plugins/gocd/package.json b/plugins/gocd/package.json index 5e54063738..54358233fd 100644 --- a/plugins/gocd/package.json +++ b/plugins/gocd/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-gocd", "description": "A Backstage plugin that integrates towards GoCD", - "version": "0.1.34-next.0", + "version": "0.1.34-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/graphiql/CHANGELOG.md b/plugins/graphiql/CHANGELOG.md index 3066f9fa22..4d339dea27 100644 --- a/plugins/graphiql/CHANGELOG.md +++ b/plugins/graphiql/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-graphiql +## 0.3.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/core-compat-api@0.0.1-next.1 + - @backstage/theme@0.5.0-next.0 + ## 0.3.1-next.1 ### Patch Changes diff --git a/plugins/graphiql/package.json b/plugins/graphiql/package.json index eab8f6c141..7ed0f98285 100644 --- a/plugins/graphiql/package.json +++ b/plugins/graphiql/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-graphiql", "description": "Backstage plugin for browsing GraphQL APIs", - "version": "0.3.1-next.1", + "version": "0.3.1-next.2", "publishConfig": { "access": "public" }, diff --git a/plugins/graphql-voyager/CHANGELOG.md b/plugins/graphql-voyager/CHANGELOG.md index d3ea493357..033e22a800 100644 --- a/plugins/graphql-voyager/CHANGELOG.md +++ b/plugins/graphql-voyager/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-graphql-voyager +## 0.1.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.0 + ## 0.1.10-next.0 ### Patch Changes diff --git a/plugins/graphql-voyager/package.json b/plugins/graphql-voyager/package.json index 904f388234..88ba1bd92b 100644 --- a/plugins/graphql-voyager/package.json +++ b/plugins/graphql-voyager/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-graphql-voyager", "description": "Backstage plugin for GraphQL Voyager", - "version": "0.1.10-next.0", + "version": "0.1.10-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/home-react/CHANGELOG.md b/plugins/home-react/CHANGELOG.md index bfe53d9bff..989c43dafe 100644 --- a/plugins/home-react/CHANGELOG.md +++ b/plugins/home-react/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-home-react +## 0.1.6-next.1 + +### Patch Changes + +- 2b725913c1: Updated dependency `@rjsf/utils` to `5.14.3`. + Updated dependency `@rjsf/core` to `5.14.3`. + Updated dependency `@rjsf/material-ui` to `5.14.3`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.3`. +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + ## 0.1.6-next.0 ### Patch Changes diff --git a/plugins/home-react/package.json b/plugins/home-react/package.json index 08d16b78e4..60dc92c3e7 100644 --- a/plugins/home-react/package.json +++ b/plugins/home-react/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-home-react", "description": "A Backstage plugin that contains react components helps you build a home page", - "version": "0.1.6-next.0", + "version": "0.1.6-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/home/CHANGELOG.md b/plugins/home/CHANGELOG.md index 28528b9793..dc8f69358f 100644 --- a/plugins/home/CHANGELOG.md +++ b/plugins/home/CHANGELOG.md @@ -1,5 +1,30 @@ # @backstage/plugin-home +## 0.6.0-next.1 + +### Minor Changes + +- 5a317f59c0: Added view of entities grouped by kind to make it easier to distinguish entities with different kind but same name + +### Patch Changes + +- 2b725913c1: Updated dependency `@rjsf/utils` to `5.14.3`. + Updated dependency `@rjsf/core` to `5.14.3`. + Updated dependency `@rjsf/material-ui` to `5.14.3`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.3`. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/plugin-home-react@0.1.6-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + ## 0.5.12-next.0 ### Patch Changes diff --git a/plugins/home/package.json b/plugins/home/package.json index 1394b69a62..57a5189fc9 100644 --- a/plugins/home/package.json +++ b/plugins/home/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-home", "description": "A Backstage plugin that helps you build a home page", - "version": "0.5.12-next.0", + "version": "0.6.0-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/ilert/CHANGELOG.md b/plugins/ilert/CHANGELOG.md index a410255f8d..30203b9bb7 100644 --- a/plugins/ilert/CHANGELOG.md +++ b/plugins/ilert/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-ilert +## 0.2.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + ## 0.2.17-next.0 ### Patch Changes diff --git a/plugins/ilert/package.json b/plugins/ilert/package.json index 7123186991..567f60f281 100644 --- a/plugins/ilert/package.json +++ b/plugins/ilert/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-ilert", "description": "A Backstage plugin that integrates towards iLert", - "version": "0.2.17-next.0", + "version": "0.2.17-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/jenkins-backend/CHANGELOG.md b/plugins/jenkins-backend/CHANGELOG.md index af36fa4d88..63337d737c 100644 --- a/plugins/jenkins-backend/CHANGELOG.md +++ b/plugins/jenkins-backend/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-jenkins-backend +## 0.3.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-catalog-node@1.5.1-next.1 + - @backstage/plugin-jenkins-common@0.1.21 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.1 + ## 0.3.2-next.0 ### Patch Changes diff --git a/plugins/jenkins-backend/package.json b/plugins/jenkins-backend/package.json index 41739ad4eb..2e8b9ab3dc 100644 --- a/plugins/jenkins-backend/package.json +++ b/plugins/jenkins-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-jenkins-backend", "description": "A Backstage backend plugin that integrates towards Jenkins", - "version": "0.3.2-next.0", + "version": "0.3.2-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/jenkins/CHANGELOG.md b/plugins/jenkins/CHANGELOG.md index f98c22df3e..d8c722d101 100644 --- a/plugins/jenkins/CHANGELOG.md +++ b/plugins/jenkins/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-jenkins +## 0.9.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-jenkins-common@0.1.21 + ## 0.9.3-next.0 ### Patch Changes diff --git a/plugins/jenkins/package.json b/plugins/jenkins/package.json index cc45d43590..c372414a03 100644 --- a/plugins/jenkins/package.json +++ b/plugins/jenkins/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-jenkins", "description": "A Backstage plugin that integrates towards Jenkins", - "version": "0.9.3-next.0", + "version": "0.9.3-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/kafka-backend/CHANGELOG.md b/plugins/kafka-backend/CHANGELOG.md index 076b38956b..f56a155e2c 100644 --- a/plugins/kafka-backend/CHANGELOG.md +++ b/plugins/kafka-backend/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-kafka-backend +## 0.3.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + ## 0.3.6-next.0 ### Patch Changes diff --git a/plugins/kafka-backend/package.json b/plugins/kafka-backend/package.json index 93c817cd65..b61139f4ce 100644 --- a/plugins/kafka-backend/package.json +++ b/plugins/kafka-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kafka-backend", "description": "A Backstage backend plugin that integrates towards Kafka", - "version": "0.3.6-next.0", + "version": "0.3.6-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/kafka/CHANGELOG.md b/plugins/kafka/CHANGELOG.md index 9dd1951c1d..c81f09daef 100644 --- a/plugins/kafka/CHANGELOG.md +++ b/plugins/kafka/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-kafka +## 0.3.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + ## 0.3.28-next.0 ### Patch Changes diff --git a/plugins/kafka/package.json b/plugins/kafka/package.json index 7e7a1bbbd7..b4f827f11a 100644 --- a/plugins/kafka/package.json +++ b/plugins/kafka/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kafka", "description": "A Backstage plugin that integrates towards Kafka", - "version": "0.3.28-next.0", + "version": "0.3.28-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/kubernetes-backend/CHANGELOG.md b/plugins/kubernetes-backend/CHANGELOG.md index 8a2f9b49bf..6938eed660 100644 --- a/plugins/kubernetes-backend/CHANGELOG.md +++ b/plugins/kubernetes-backend/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-kubernetes-backend +## 0.14.0-next.1 + +### Patch Changes + +- ae94d3ce6f: Updated dependency `@aws-crypto/sha256-js` to `^5.0.0`. +- 99fb54183b: Updated dependency `@azure/identity` to `^4.0.0`. +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration-aws-node@0.1.8 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-catalog-node@1.5.1-next.1 + - @backstage/plugin-kubernetes-node@0.1.2-next.1 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.1 + ## 0.14.0-next.0 ### Minor Changes diff --git a/plugins/kubernetes-backend/package.json b/plugins/kubernetes-backend/package.json index b4fdc103a9..d485a1163a 100644 --- a/plugins/kubernetes-backend/package.json +++ b/plugins/kubernetes-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kubernetes-backend", "description": "A Backstage backend plugin that integrates towards Kubernetes", - "version": "0.14.0-next.0", + "version": "0.14.0-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/kubernetes-cluster/CHANGELOG.md b/plugins/kubernetes-cluster/CHANGELOG.md index 969996da08..4ae5fcf0ae 100644 --- a/plugins/kubernetes-cluster/CHANGELOG.md +++ b/plugins/kubernetes-cluster/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-kubernetes-cluster +## 0.0.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + - @backstage/plugin-kubernetes-react@0.1.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + ## 0.0.4-next.0 ### Patch Changes diff --git a/plugins/kubernetes-cluster/package.json b/plugins/kubernetes-cluster/package.json index 6429f99d3f..f113325644 100644 --- a/plugins/kubernetes-cluster/package.json +++ b/plugins/kubernetes-cluster/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kubernetes-cluster", "description": "A Backstage plugin that shows details of Kubernetes clusters", - "version": "0.0.4-next.0", + "version": "0.0.4-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/kubernetes-common/CHANGELOG.md b/plugins/kubernetes-common/CHANGELOG.md index 7eeb148d94..b46fdd9a64 100644 --- a/plugins/kubernetes-common/CHANGELOG.md +++ b/plugins/kubernetes-common/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-kubernetes-common +## 0.7.2-next.1 + +### Patch Changes + +- 5d796829bb: Remove unused dependency +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.10 + ## 0.7.2-next.0 ### Patch Changes diff --git a/plugins/kubernetes-common/package.json b/plugins/kubernetes-common/package.json index c66ea6606e..318024535f 100644 --- a/plugins/kubernetes-common/package.json +++ b/plugins/kubernetes-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kubernetes-common", "description": "Common functionalities for kubernetes, to be shared between kubernetes and kubernetes-backend plugin", - "version": "0.7.2-next.0", + "version": "0.7.2-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/kubernetes-node/CHANGELOG.md b/plugins/kubernetes-node/CHANGELOG.md index 28619caaf9..d87d7a3cc8 100644 --- a/plugins/kubernetes-node/CHANGELOG.md +++ b/plugins/kubernetes-node/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-kubernetes-node +## 0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + ## 0.1.2-next.0 ### Patch Changes diff --git a/plugins/kubernetes-node/package.json b/plugins/kubernetes-node/package.json index 2f8b3237fc..852ce00d83 100644 --- a/plugins/kubernetes-node/package.json +++ b/plugins/kubernetes-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kubernetes-node", "description": "Node.js library for the kubernetes plugin", - "version": "0.1.2-next.0", + "version": "0.1.2-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/kubernetes-react/CHANGELOG.md b/plugins/kubernetes-react/CHANGELOG.md index fbc09b0b90..03ef769a99 100644 --- a/plugins/kubernetes-react/CHANGELOG.md +++ b/plugins/kubernetes-react/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-kubernetes-react +## 0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + ## 0.1.2-next.0 ### Patch Changes diff --git a/plugins/kubernetes-react/package.json b/plugins/kubernetes-react/package.json index 0b707da172..bacf82acd6 100644 --- a/plugins/kubernetes-react/package.json +++ b/plugins/kubernetes-react/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kubernetes-react", "description": "Web library for the kubernetes-react plugin", - "version": "0.1.2-next.0", + "version": "0.1.2-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/kubernetes/CHANGELOG.md b/plugins/kubernetes/CHANGELOG.md index f4a0c0dfd9..0131eca6ce 100644 --- a/plugins/kubernetes/CHANGELOG.md +++ b/plugins/kubernetes/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-kubernetes +## 0.11.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + - @backstage/plugin-kubernetes-react@0.1.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + ## 0.11.3-next.0 ### Patch Changes diff --git a/plugins/kubernetes/package.json b/plugins/kubernetes/package.json index 8970a9d19e..897e1abe04 100644 --- a/plugins/kubernetes/package.json +++ b/plugins/kubernetes/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kubernetes", "description": "A Backstage plugin that integrates towards Kubernetes", - "version": "0.11.3-next.0", + "version": "0.11.3-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/lighthouse-backend/CHANGELOG.md b/plugins/lighthouse-backend/CHANGELOG.md index 4d13ee7bb9..f5a92f575b 100644 --- a/plugins/lighthouse-backend/CHANGELOG.md +++ b/plugins/lighthouse-backend/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-lighthouse-backend +## 0.3.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-node@1.5.1-next.1 + - @backstage/plugin-lighthouse-common@0.1.4 + ## 0.3.5-next.0 ### Patch Changes diff --git a/plugins/lighthouse-backend/package.json b/plugins/lighthouse-backend/package.json index 84cff5b8eb..5a22e80a76 100644 --- a/plugins/lighthouse-backend/package.json +++ b/plugins/lighthouse-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-lighthouse-backend", "description": "Backend functionalities for lighthouse", - "version": "0.3.5-next.0", + "version": "0.3.5-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/lighthouse/CHANGELOG.md b/plugins/lighthouse/CHANGELOG.md index 0a43306d8b..4ebf99dbd3 100644 --- a/plugins/lighthouse/CHANGELOG.md +++ b/plugins/lighthouse/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-lighthouse +## 0.4.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-lighthouse-common@0.1.4 + ## 0.4.13-next.0 ### Patch Changes diff --git a/plugins/lighthouse/package.json b/plugins/lighthouse/package.json index d9e1562293..348ae348ff 100644 --- a/plugins/lighthouse/package.json +++ b/plugins/lighthouse/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-lighthouse", "description": "A Backstage plugin that integrates towards Lighthouse", - "version": "0.4.13-next.0", + "version": "0.4.13-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/linguist-backend/CHANGELOG.md b/plugins/linguist-backend/CHANGELOG.md index b6d4eeecba..ff680b0db5 100644 --- a/plugins/linguist-backend/CHANGELOG.md +++ b/plugins/linguist-backend/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-linguist-backend +## 0.5.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-catalog-node@1.5.1-next.1 + - @backstage/plugin-linguist-common@0.1.2 + ## 0.5.5-next.0 ### Patch Changes diff --git a/plugins/linguist-backend/package.json b/plugins/linguist-backend/package.json index 078e771acb..13f27b1f94 100644 --- a/plugins/linguist-backend/package.json +++ b/plugins/linguist-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-linguist-backend", - "version": "0.5.5-next.0", + "version": "0.5.5-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/linguist/CHANGELOG.md b/plugins/linguist/CHANGELOG.md index 9eff98f884..a8177709b6 100644 --- a/plugins/linguist/CHANGELOG.md +++ b/plugins/linguist/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-linguist +## 0.1.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-linguist-common@0.1.2 + ## 0.1.13-next.0 ### Patch Changes diff --git a/plugins/linguist/package.json b/plugins/linguist/package.json index f5c1fc6d16..630357d283 100644 --- a/plugins/linguist/package.json +++ b/plugins/linguist/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-linguist", - "version": "0.1.13-next.0", + "version": "0.1.13-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/microsoft-calendar/CHANGELOG.md b/plugins/microsoft-calendar/CHANGELOG.md index 5197b46b04..9fa9dcd330 100644 --- a/plugins/microsoft-calendar/CHANGELOG.md +++ b/plugins/microsoft-calendar/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-microsoft-calendar +## 0.1.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + ## 0.1.10-next.0 ### Patch Changes diff --git a/plugins/microsoft-calendar/package.json b/plugins/microsoft-calendar/package.json index 2f8e24ba7c..c49892a12f 100644 --- a/plugins/microsoft-calendar/package.json +++ b/plugins/microsoft-calendar/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-microsoft-calendar", - "version": "0.1.10-next.0", + "version": "0.1.10-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/newrelic-dashboard/CHANGELOG.md b/plugins/newrelic-dashboard/CHANGELOG.md index d4fc089300..e0b1a555d8 100644 --- a/plugins/newrelic-dashboard/CHANGELOG.md +++ b/plugins/newrelic-dashboard/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-newrelic-dashboard +## 0.3.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + ## 0.3.3-next.0 ### Patch Changes diff --git a/plugins/newrelic-dashboard/package.json b/plugins/newrelic-dashboard/package.json index 35360c23be..bbf7e0db14 100644 --- a/plugins/newrelic-dashboard/package.json +++ b/plugins/newrelic-dashboard/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-newrelic-dashboard", - "version": "0.3.3-next.0", + "version": "0.3.3-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/newrelic/CHANGELOG.md b/plugins/newrelic/CHANGELOG.md index cb8ad604bc..2eacc6f9de 100644 --- a/plugins/newrelic/CHANGELOG.md +++ b/plugins/newrelic/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-newrelic +## 0.3.43-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.0 + ## 0.3.43-next.0 ### Patch Changes diff --git a/plugins/newrelic/package.json b/plugins/newrelic/package.json index 3f4ae91bbe..328acc6dc6 100644 --- a/plugins/newrelic/package.json +++ b/plugins/newrelic/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-newrelic", "description": "A Backstage plugin that integrates towards New Relic", - "version": "0.3.43-next.0", + "version": "0.3.43-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/nomad-backend/CHANGELOG.md b/plugins/nomad-backend/CHANGELOG.md index edcee04e86..c9ce70c9bd 100644 --- a/plugins/nomad-backend/CHANGELOG.md +++ b/plugins/nomad-backend/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-nomad-backend +## 0.1.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + ## 0.1.10-next.0 ### Patch Changes diff --git a/plugins/nomad-backend/package.json b/plugins/nomad-backend/package.json index 074e35f1db..9b3236a36c 100644 --- a/plugins/nomad-backend/package.json +++ b/plugins/nomad-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-nomad-backend", - "version": "0.1.10-next.0", + "version": "0.1.10-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/nomad/CHANGELOG.md b/plugins/nomad/CHANGELOG.md index 6efac21380..db3028d3be 100644 --- a/plugins/nomad/CHANGELOG.md +++ b/plugins/nomad/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-nomad +## 0.1.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + ## 0.1.9-next.0 ### Patch Changes diff --git a/plugins/nomad/package.json b/plugins/nomad/package.json index fc8cab5de7..8f6c1bdaa0 100644 --- a/plugins/nomad/package.json +++ b/plugins/nomad/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-nomad", - "version": "0.1.9-next.0", + "version": "0.1.9-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/octopus-deploy/CHANGELOG.md b/plugins/octopus-deploy/CHANGELOG.md index 4855e1964e..5be0493e2e 100644 --- a/plugins/octopus-deploy/CHANGELOG.md +++ b/plugins/octopus-deploy/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-octopus-deploy +## 0.2.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + ## 0.2.10-next.0 ### Patch Changes diff --git a/plugins/octopus-deploy/package.json b/plugins/octopus-deploy/package.json index 2e28dd8453..29c3bf0e77 100644 --- a/plugins/octopus-deploy/package.json +++ b/plugins/octopus-deploy/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-octopus-deploy", - "version": "0.2.10-next.0", + "version": "0.2.10-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/opencost/CHANGELOG.md b/plugins/opencost/CHANGELOG.md index bc4fcbd562..0bd056f1db 100644 --- a/plugins/opencost/CHANGELOG.md +++ b/plugins/opencost/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-opencost +## 0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.0 + ## 0.2.3-next.0 ### Patch Changes diff --git a/plugins/opencost/package.json b/plugins/opencost/package.json index fba53eb9da..7c868ebeb1 100644 --- a/plugins/opencost/package.json +++ b/plugins/opencost/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-opencost", - "version": "0.2.3-next.0", + "version": "0.2.3-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/org-react/CHANGELOG.md b/plugins/org-react/CHANGELOG.md index 80ca996f05..285d048652 100644 --- a/plugins/org-react/CHANGELOG.md +++ b/plugins/org-react/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-org-react +## 0.1.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + ## 0.1.17-next.0 ### Patch Changes diff --git a/plugins/org-react/package.json b/plugins/org-react/package.json index 2893e283ee..af1daff510 100644 --- a/plugins/org-react/package.json +++ b/plugins/org-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-org-react", - "version": "0.1.17-next.0", + "version": "0.1.17-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/org/CHANGELOG.md b/plugins/org/CHANGELOG.md index 9157075dd9..e5099316fa 100644 --- a/plugins/org/CHANGELOG.md +++ b/plugins/org/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-org +## 0.6.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + ## 0.6.18-next.0 ### Patch Changes diff --git a/plugins/org/package.json b/plugins/org/package.json index 15c64bd7b8..2f087eedd5 100644 --- a/plugins/org/package.json +++ b/plugins/org/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-org", "description": "A Backstage plugin that helps you create entity pages for your organization", - "version": "0.6.18-next.0", + "version": "0.6.18-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/pagerduty/CHANGELOG.md b/plugins/pagerduty/CHANGELOG.md index 40c6ff4e02..e62d0366f1 100644 --- a/plugins/pagerduty/CHANGELOG.md +++ b/plugins/pagerduty/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-pagerduty +## 0.7.0-next.1 + +### Minor Changes + +- 5fca16fdf6: This package has been deprecated, consider using [@pagerduty/backstage-plugin](https://github.com/pagerduty/backstage-plugin) instead. + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-home-react@0.1.6-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + ## 0.6.9-next.0 ### Patch Changes diff --git a/plugins/pagerduty/package.json b/plugins/pagerduty/package.json index 7dc2e5af13..0e6a0667dc 100644 --- a/plugins/pagerduty/package.json +++ b/plugins/pagerduty/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-pagerduty", "description": "This plugin has been deprecated, consider using [@pagerduty/backstage-plugin](https://github.com/pagerduty/backstage-plugin) instead.", - "version": "0.6.9-next.0", + "version": "0.7.0-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/periskop-backend/CHANGELOG.md b/plugins/periskop-backend/CHANGELOG.md index 5884a31457..1b98851c12 100644 --- a/plugins/periskop-backend/CHANGELOG.md +++ b/plugins/periskop-backend/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-periskop-backend +## 0.2.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + ## 0.2.6-next.0 ### Patch Changes diff --git a/plugins/periskop-backend/package.json b/plugins/periskop-backend/package.json index e1de6e6751..481533c1ed 100644 --- a/plugins/periskop-backend/package.json +++ b/plugins/periskop-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-periskop-backend", - "version": "0.2.6-next.0", + "version": "0.2.6-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/periskop/CHANGELOG.md b/plugins/periskop/CHANGELOG.md index 139ab1c5f7..17573f96b5 100644 --- a/plugins/periskop/CHANGELOG.md +++ b/plugins/periskop/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-periskop +## 0.1.26-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + ## 0.1.26-next.0 ### Patch Changes diff --git a/plugins/periskop/package.json b/plugins/periskop/package.json index 9099c884a7..380f7d5fd7 100644 --- a/plugins/periskop/package.json +++ b/plugins/periskop/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-periskop", - "version": "0.1.26-next.0", + "version": "0.1.26-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md b/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md index 59488140e0..8b46dfe282 100644 --- a/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md +++ b/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-permission-backend-module-allow-all-policy +## 0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.1 + ## 0.1.5-next.0 ### Patch Changes diff --git a/plugins/permission-backend-module-policy-allow-all/package.json b/plugins/permission-backend-module-policy-allow-all/package.json index 259186d50b..b65ff60cfb 100644 --- a/plugins/permission-backend-module-policy-allow-all/package.json +++ b/plugins/permission-backend-module-policy-allow-all/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-permission-backend-module-allow-all-policy", "description": "Allow all policy backend module for the permission plugin.", - "version": "0.1.5-next.0", + "version": "0.1.5-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/permission-backend/CHANGELOG.md b/plugins/permission-backend/CHANGELOG.md index d40c6eff77..85c74ef3cb 100644 --- a/plugins/permission-backend/CHANGELOG.md +++ b/plugins/permission-backend/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-permission-backend +## 0.5.31-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.1 + ## 0.5.31-next.0 ### Patch Changes diff --git a/plugins/permission-backend/package.json b/plugins/permission-backend/package.json index c3e8c7a54c..3578b55a81 100644 --- a/plugins/permission-backend/package.json +++ b/plugins/permission-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-permission-backend", - "version": "0.5.31-next.0", + "version": "0.5.31-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/permission-node/CHANGELOG.md b/plugins/permission-node/CHANGELOG.md index a9c27025a9..757264e0fd 100644 --- a/plugins/permission-node/CHANGELOG.md +++ b/plugins/permission-node/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-permission-node +## 0.7.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-permission-common@0.7.10 + ## 0.7.19-next.0 ### Patch Changes diff --git a/plugins/permission-node/package.json b/plugins/permission-node/package.json index 4191d16a67..9e5197f312 100644 --- a/plugins/permission-node/package.json +++ b/plugins/permission-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-permission-node", "description": "Common permission and authorization utilities for backend plugins", - "version": "0.7.19-next.0", + "version": "0.7.19-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/permission-react/CHANGELOG.md b/plugins/permission-react/CHANGELOG.md index c5edb4e8f4..3fedc6e80a 100644 --- a/plugins/permission-react/CHANGELOG.md +++ b/plugins/permission-react/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-permission-react +## 0.4.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-permission-common@0.7.10 + ## 0.4.18-next.0 ### Patch Changes diff --git a/plugins/permission-react/package.json b/plugins/permission-react/package.json index 26f2cde701..433ec8bcb4 100644 --- a/plugins/permission-react/package.json +++ b/plugins/permission-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-permission-react", - "version": "0.4.18-next.0", + "version": "0.4.18-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/playlist-backend/CHANGELOG.md b/plugins/playlist-backend/CHANGELOG.md index 29b12ea597..3961855299 100644 --- a/plugins/playlist-backend/CHANGELOG.md +++ b/plugins/playlist-backend/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-playlist-backend +## 0.3.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.1 + - @backstage/plugin-playlist-common@0.1.12 + ## 0.3.12-next.0 ### Patch Changes diff --git a/plugins/playlist-backend/package.json b/plugins/playlist-backend/package.json index 28fc5e12da..cc24e9965e 100644 --- a/plugins/playlist-backend/package.json +++ b/plugins/playlist-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-playlist-backend", - "version": "0.3.12-next.0", + "version": "0.3.12-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/playlist/CHANGELOG.md b/plugins/playlist/CHANGELOG.md index 12d289d0bf..477608ee9d 100644 --- a/plugins/playlist/CHANGELOG.md +++ b/plugins/playlist/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-playlist +## 0.2.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-search-react@1.7.4-next.1 + - @backstage/plugin-permission-react@0.4.18-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-playlist-common@0.1.12 + ## 0.2.2-next.0 ### Patch Changes diff --git a/plugins/playlist/package.json b/plugins/playlist/package.json index c23be32837..495ab0db5f 100644 --- a/plugins/playlist/package.json +++ b/plugins/playlist/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-playlist", - "version": "0.2.2-next.0", + "version": "0.2.2-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/proxy-backend/CHANGELOG.md b/plugins/proxy-backend/CHANGELOG.md index 49518973c8..c5415d315c 100644 --- a/plugins/proxy-backend/CHANGELOG.md +++ b/plugins/proxy-backend/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-proxy-backend +## 0.4.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + ## 0.4.6-next.0 ### Patch Changes diff --git a/plugins/proxy-backend/package.json b/plugins/proxy-backend/package.json index a3bc61540f..48da413397 100644 --- a/plugins/proxy-backend/package.json +++ b/plugins/proxy-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-proxy-backend", "description": "A Backstage backend plugin that helps you set up proxy endpoints in the backend", - "version": "0.4.6-next.0", + "version": "0.4.6-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/puppetdb/CHANGELOG.md b/plugins/puppetdb/CHANGELOG.md index 0147ed7ac7..c3f622c3bd 100644 --- a/plugins/puppetdb/CHANGELOG.md +++ b/plugins/puppetdb/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-puppetdb +## 0.1.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + ## 0.1.11-next.0 ### Patch Changes diff --git a/plugins/puppetdb/package.json b/plugins/puppetdb/package.json index fbddd1a2e4..639c63c1f7 100644 --- a/plugins/puppetdb/package.json +++ b/plugins/puppetdb/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-puppetdb", "description": "Backstage plugin to visualize resource information and Puppet facts from PuppetDB.", - "version": "0.1.11-next.0", + "version": "0.1.11-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/rollbar-backend/CHANGELOG.md b/plugins/rollbar-backend/CHANGELOG.md index 26b858f2ae..548bd5cc2d 100644 --- a/plugins/rollbar-backend/CHANGELOG.md +++ b/plugins/rollbar-backend/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-rollbar-backend +## 0.1.53-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/config@1.1.1 + ## 0.1.53-next.0 ### Patch Changes diff --git a/plugins/rollbar-backend/package.json b/plugins/rollbar-backend/package.json index 6512f32d88..8f352c4ccf 100644 --- a/plugins/rollbar-backend/package.json +++ b/plugins/rollbar-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-rollbar-backend", "description": "A Backstage backend plugin that integrates towards Rollbar", - "version": "0.1.53-next.0", + "version": "0.1.53-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/rollbar/CHANGELOG.md b/plugins/rollbar/CHANGELOG.md index 8d8f35757a..96e3781700 100644 --- a/plugins/rollbar/CHANGELOG.md +++ b/plugins/rollbar/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-rollbar +## 0.4.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + ## 0.4.28-next.0 ### Patch Changes diff --git a/plugins/rollbar/package.json b/plugins/rollbar/package.json index 5c51bdab2a..3e9b05f360 100644 --- a/plugins/rollbar/package.json +++ b/plugins/rollbar/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-rollbar", "description": "A Backstage plugin that integrates towards Rollbar", - "version": "0.4.28-next.0", + "version": "0.4.28-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md b/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md index 96500ac2a5..838edd9202 100644 --- a/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-scaffolder-backend-module-confluence-to-markdown +## 0.2.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.2.9-next.1 + ## 0.2.9-next.0 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-confluence-to-markdown/package.json b/plugins/scaffolder-backend-module-confluence-to-markdown/package.json index 0f441ab713..7ffbb59464 100644 --- a/plugins/scaffolder-backend-module-confluence-to-markdown/package.json +++ b/plugins/scaffolder-backend-module-confluence-to-markdown/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-backend-module-confluence-to-markdown", "description": "The confluence-to-markdown module for @backstage/plugin-scaffolder-backend", - "version": "0.2.9-next.0", + "version": "0.2.9-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md b/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md index d7cf6eef65..29bace1808 100644 --- a/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-scaffolder-backend-module-cookiecutter +## 0.2.32-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.2.9-next.1 + ## 0.2.32-next.0 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-cookiecutter/package.json b/plugins/scaffolder-backend-module-cookiecutter/package.json index a9d7675198..25b8864b9b 100644 --- a/plugins/scaffolder-backend-module-cookiecutter/package.json +++ b/plugins/scaffolder-backend-module-cookiecutter/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-backend-module-cookiecutter", "description": "A module for the scaffolder backend that lets you template projects using cookiecutter", - "version": "0.2.32-next.0", + "version": "0.2.32-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md b/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md index 7b9fd3b55d..a9adb44355 100644 --- a/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-scaffolder-backend-module-gitlab +## 0.2.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-scaffolder-node@0.2.9-next.1 + ## 0.2.11-next.0 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-gitlab/package.json b/plugins/scaffolder-backend-module-gitlab/package.json index eccb663b54..94641be81c 100644 --- a/plugins/scaffolder-backend-module-gitlab/package.json +++ b/plugins/scaffolder-backend-module-gitlab/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-gitlab", - "version": "0.2.11-next.0", + "version": "0.2.11-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/scaffolder-backend-module-rails/CHANGELOG.md b/plugins/scaffolder-backend-module-rails/CHANGELOG.md index ebf034b594..20538718eb 100644 --- a/plugins/scaffolder-backend-module-rails/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-rails/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-scaffolder-backend-module-rails +## 0.4.25-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.2.9-next.1 + ## 0.4.25-next.0 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-rails/package.json b/plugins/scaffolder-backend-module-rails/package.json index abd4742845..37f26da084 100644 --- a/plugins/scaffolder-backend-module-rails/package.json +++ b/plugins/scaffolder-backend-module-rails/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-backend-module-rails", "description": "A module for the scaffolder backend that lets you template projects using Rails", - "version": "0.4.25-next.0", + "version": "0.4.25-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/scaffolder-backend-module-sentry/CHANGELOG.md b/plugins/scaffolder-backend-module-sentry/CHANGELOG.md index 2ba0251f7e..70b9b57a6b 100644 --- a/plugins/scaffolder-backend-module-sentry/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-sentry/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-scaffolder-backend-module-sentry +## 0.1.16-next.1 + +### Patch Changes + +- 7f8a801e6d: Added examples for `sentry:project:create` scaffolder action and unit tests. +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-scaffolder-node@0.2.9-next.1 + ## 0.1.16-next.0 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-sentry/package.json b/plugins/scaffolder-backend-module-sentry/package.json index 9429fd0252..c81996bfd6 100644 --- a/plugins/scaffolder-backend-module-sentry/package.json +++ b/plugins/scaffolder-backend-module-sentry/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-sentry", - "version": "0.1.16-next.0", + "version": "0.1.16-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md b/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md index 0e2c6901c0..53389300e2 100644 --- a/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-scaffolder-backend-module-yeoman +## 0.2.29-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.2.9-next.1 + ## 0.2.29-next.0 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-yeoman/package.json b/plugins/scaffolder-backend-module-yeoman/package.json index 400e2e616b..6870b60eb9 100644 --- a/plugins/scaffolder-backend-module-yeoman/package.json +++ b/plugins/scaffolder-backend-module-yeoman/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-yeoman", - "version": "0.2.29-next.0", + "version": "0.2.29-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/scaffolder-backend/CHANGELOG.md b/plugins/scaffolder-backend/CHANGELOG.md index 531f437ca3..30b1516a2d 100644 --- a/plugins/scaffolder-backend/CHANGELOG.md +++ b/plugins/scaffolder-backend/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-scaffolder-backend +## 1.19.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.15.1-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.5-next.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.5.1-next.1 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.1 + - @backstage/plugin-scaffolder-common@1.4.3 + - @backstage/plugin-scaffolder-node@0.2.9-next.1 + ## 1.19.2-next.0 ### Patch Changes diff --git a/plugins/scaffolder-backend/package.json b/plugins/scaffolder-backend/package.json index b1d5b86671..f1ea2a3517 100644 --- a/plugins/scaffolder-backend/package.json +++ b/plugins/scaffolder-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-backend", "description": "The Backstage backend plugin that helps you create new things", - "version": "1.19.2-next.0", + "version": "1.19.2-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/scaffolder-node/CHANGELOG.md b/plugins/scaffolder-node/CHANGELOG.md index 0d2c194e06..7dcb041c2f 100644 --- a/plugins/scaffolder-node/CHANGELOG.md +++ b/plugins/scaffolder-node/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-scaffolder-node +## 0.2.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-common@1.4.3 + ## 0.2.9-next.0 ### Patch Changes diff --git a/plugins/scaffolder-node/package.json b/plugins/scaffolder-node/package.json index f9506dcc96..5f5702a035 100644 --- a/plugins/scaffolder-node/package.json +++ b/plugins/scaffolder-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-node", "description": "The plugin-scaffolder-node module for @backstage/plugin-scaffolder-backend", - "version": "0.2.9-next.0", + "version": "0.2.9-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/scaffolder-react/CHANGELOG.md b/plugins/scaffolder-react/CHANGELOG.md index a66eb35b63..b1b2699564 100644 --- a/plugins/scaffolder-react/CHANGELOG.md +++ b/plugins/scaffolder-react/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/plugin-scaffolder-react +## 1.6.2-next.1 + +### Patch Changes + +- fa66d1b5b3: Fixed bug in `ReviewState` where `enum` value was displayed in step review instead of the corresponding label when using `enumNames` +- 2aee53bbeb: Add horizontal slider if stepper overflows +- 2b725913c1: Updated dependency `@rjsf/utils` to `5.14.3`. + Updated dependency `@rjsf/core` to `5.14.3`. + Updated dependency `@rjsf/material-ui` to `5.14.3`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.3`. +- a518c5a25b: Updated dependency `@react-hookz/web` to `^23.0.0`. +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-scaffolder-common@1.4.3 + ## 1.6.2-next.0 ### Patch Changes diff --git a/plugins/scaffolder-react/package.json b/plugins/scaffolder-react/package.json index ddad8ad8de..9849696d19 100644 --- a/plugins/scaffolder-react/package.json +++ b/plugins/scaffolder-react/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-react", "description": "A frontend library that helps other Backstage plugins interact with the Scaffolder", - "version": "1.6.2-next.0", + "version": "1.6.2-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/scaffolder/CHANGELOG.md b/plugins/scaffolder/CHANGELOG.md index 547e59f7f3..b1a60d6353 100644 --- a/plugins/scaffolder/CHANGELOG.md +++ b/plugins/scaffolder/CHANGELOG.md @@ -1,5 +1,32 @@ # @backstage/plugin-scaffolder +## 1.16.2-next.1 + +### Patch Changes + +- 2b725913c1: Updated dependency `@rjsf/utils` to `5.14.3`. + Updated dependency `@rjsf/core` to `5.14.3`. + Updated dependency `@rjsf/material-ui` to `5.14.3`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.3`. +- a518c5a25b: Updated dependency `@react-hookz/web` to `^23.0.0`. +- b5fa6918dc: Fixing `headerOptions` not being passed through the `TemplatePage` component +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/plugin-scaffolder-react@1.6.2-next.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/plugin-permission-react@0.4.18-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-scaffolder-common@1.4.3 + ## 1.16.2-next.0 ### Patch Changes diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index 8f393c8f29..13257e2731 100644 --- a/plugins/scaffolder/package.json +++ b/plugins/scaffolder/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder", "description": "The Backstage plugin that helps you create new things", - "version": "1.16.2-next.0", + "version": "1.16.2-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/search-backend-module-catalog/CHANGELOG.md b/plugins/search-backend-module-catalog/CHANGELOG.md index 76662cfb76..9ea8790218 100644 --- a/plugins/search-backend-module-catalog/CHANGELOG.md +++ b/plugins/search-backend-module-catalog/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-search-backend-module-catalog +## 0.1.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.5.1-next.1 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-search-backend-node@1.2.12-next.1 + - @backstage/plugin-search-common@1.2.8 + ## 0.1.12-next.0 ### Patch Changes diff --git a/plugins/search-backend-module-catalog/package.json b/plugins/search-backend-module-catalog/package.json index ebab4143cd..d8e78d2fb7 100644 --- a/plugins/search-backend-module-catalog/package.json +++ b/plugins/search-backend-module-catalog/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-search-backend-module-catalog", "description": "A module for the search backend that exports catalog modules", - "version": "0.1.12-next.0", + "version": "0.1.12-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/search-backend-module-elasticsearch/CHANGELOG.md b/plugins/search-backend-module-elasticsearch/CHANGELOG.md index 1fa95afa0d..93795174d9 100644 --- a/plugins/search-backend-module-elasticsearch/CHANGELOG.md +++ b/plugins/search-backend-module-elasticsearch/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-search-backend-module-elasticsearch +## 1.3.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/integration-aws-node@0.1.8 + - @backstage/plugin-search-backend-node@1.2.12-next.1 + - @backstage/plugin-search-common@1.2.8 + ## 1.3.11-next.0 ### Patch Changes diff --git a/plugins/search-backend-module-elasticsearch/package.json b/plugins/search-backend-module-elasticsearch/package.json index 04701c8849..61b26fb5f7 100644 --- a/plugins/search-backend-module-elasticsearch/package.json +++ b/plugins/search-backend-module-elasticsearch/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-search-backend-module-elasticsearch", "description": "A module for the search backend that implements search using ElasticSearch", - "version": "1.3.11-next.0", + "version": "1.3.11-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/search-backend-module-explore/CHANGELOG.md b/plugins/search-backend-module-explore/CHANGELOG.md index 7d0aba4645..01df12e913 100644 --- a/plugins/search-backend-module-explore/CHANGELOG.md +++ b/plugins/search-backend-module-explore/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-search-backend-module-explore +## 0.1.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-backend-node@1.2.12-next.1 + - @backstage/plugin-search-common@1.2.8 + ## 0.1.12-next.0 ### Patch Changes diff --git a/plugins/search-backend-module-explore/package.json b/plugins/search-backend-module-explore/package.json index 9dcdf01368..e700549839 100644 --- a/plugins/search-backend-module-explore/package.json +++ b/plugins/search-backend-module-explore/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-search-backend-module-explore", "description": "A module for the search backend that exports explore modules", - "version": "0.1.12-next.0", + "version": "0.1.12-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/search-backend-module-pg/CHANGELOG.md b/plugins/search-backend-module-pg/CHANGELOG.md index 99f0a42a8f..01d5cc175a 100644 --- a/plugins/search-backend-module-pg/CHANGELOG.md +++ b/plugins/search-backend-module-pg/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-search-backend-module-pg +## 0.5.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-search-backend-node@1.2.12-next.1 + - @backstage/plugin-search-common@1.2.8 + ## 0.5.17-next.0 ### Patch Changes diff --git a/plugins/search-backend-module-pg/package.json b/plugins/search-backend-module-pg/package.json index 8cdb82b04a..9a0bd19184 100644 --- a/plugins/search-backend-module-pg/package.json +++ b/plugins/search-backend-module-pg/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-search-backend-module-pg", "description": "A module for the search backend that implements search using PostgreSQL", - "version": "0.5.17-next.0", + "version": "0.5.17-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/search-backend-module-stack-overflow-collator/CHANGELOG.md b/plugins/search-backend-module-stack-overflow-collator/CHANGELOG.md index 5688dd774c..f8655cd2d6 100644 --- a/plugins/search-backend-module-stack-overflow-collator/CHANGELOG.md +++ b/plugins/search-backend-module-stack-overflow-collator/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-search-backend-module-stack-overflow-collator +## 0.1.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-search-backend-node@1.2.12-next.1 + - @backstage/plugin-search-common@1.2.8 + ## 0.1.1-next.0 ### Patch Changes diff --git a/plugins/search-backend-module-stack-overflow-collator/package.json b/plugins/search-backend-module-stack-overflow-collator/package.json index 6ecefe5951..7863538612 100644 --- a/plugins/search-backend-module-stack-overflow-collator/package.json +++ b/plugins/search-backend-module-stack-overflow-collator/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-search-backend-module-stack-overflow-collator", "description": "A module for the search backend that exports stack overflow modules", - "version": "0.1.1-next.0", + "version": "0.1.1-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/search-backend-module-techdocs/CHANGELOG.md b/plugins/search-backend-module-techdocs/CHANGELOG.md index 45753237fe..6f8c0593fc 100644 --- a/plugins/search-backend-module-techdocs/CHANGELOG.md +++ b/plugins/search-backend-module-techdocs/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-search-backend-module-techdocs +## 0.1.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/plugin-techdocs-node@1.11.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.5.1-next.1 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-search-backend-node@1.2.12-next.1 + - @backstage/plugin-search-common@1.2.8 + ## 0.1.12-next.0 ### Patch Changes diff --git a/plugins/search-backend-module-techdocs/package.json b/plugins/search-backend-module-techdocs/package.json index b40ca5a9a0..79a027023a 100644 --- a/plugins/search-backend-module-techdocs/package.json +++ b/plugins/search-backend-module-techdocs/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-search-backend-module-techdocs", "description": "A module for the search backend that exports techdocs modules", - "version": "0.1.12-next.0", + "version": "0.1.12-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/search-backend-node/CHANGELOG.md b/plugins/search-backend-node/CHANGELOG.md index c71883fce8..04a6c06796 100644 --- a/plugins/search-backend-node/CHANGELOG.md +++ b/plugins/search-backend-node/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-search-backend-node +## 1.2.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-search-common@1.2.8 + ## 1.2.12-next.0 ### Patch Changes diff --git a/plugins/search-backend-node/package.json b/plugins/search-backend-node/package.json index 7533f1f510..ff561f9754 100644 --- a/plugins/search-backend-node/package.json +++ b/plugins/search-backend-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-search-backend-node", "description": "A library for Backstage backend plugins that want to interact with the search backend plugin", - "version": "1.2.12-next.0", + "version": "1.2.12-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/search-backend/CHANGELOG.md b/plugins/search-backend/CHANGELOG.md index 544834466b..389ab42a68 100644 --- a/plugins/search-backend/CHANGELOG.md +++ b/plugins/search-backend/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-search-backend +## 1.4.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-openapi-utils@0.1.1-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.1 + - @backstage/plugin-search-backend-node@1.2.12-next.1 + - @backstage/plugin-search-common@1.2.8 + ## 1.4.8-next.0 ### Patch Changes diff --git a/plugins/search-backend/package.json b/plugins/search-backend/package.json index fb06cdcc7d..372aaaae03 100644 --- a/plugins/search-backend/package.json +++ b/plugins/search-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-search-backend", "description": "The Backstage backend plugin that provides your backstage app with search", - "version": "1.4.8-next.0", + "version": "1.4.8-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/search-react/CHANGELOG.md b/plugins/search-react/CHANGELOG.md index d64617c51c..37b0e72ca4 100644 --- a/plugins/search-react/CHANGELOG.md +++ b/plugins/search-react/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-search-react +## 1.7.4-next.1 + +### Patch Changes + +- a5a04739e1: Internal refactor of alpha exports due to a change in how extension factories are defined. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-search-common@1.2.8 + ## 1.7.4-next.0 ### Patch Changes diff --git a/plugins/search-react/package.json b/plugins/search-react/package.json index e4dff0421c..e007af3b51 100644 --- a/plugins/search-react/package.json +++ b/plugins/search-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-react", - "version": "1.7.4-next.0", + "version": "1.7.4-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/search/CHANGELOG.md b/plugins/search/CHANGELOG.md index cb9e3c9117..03f28975c2 100644 --- a/plugins/search/CHANGELOG.md +++ b/plugins/search/CHANGELOG.md @@ -1,5 +1,24 @@ # @backstage/plugin-search +## 1.4.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-search-react@1.7.4-next.1 + - @backstage/core-compat-api@0.0.1-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-search-common@1.2.8 + ## 1.4.4-next.1 ### Patch Changes diff --git a/plugins/search/package.json b/plugins/search/package.json index 9256b886ab..da5bbcbd33 100644 --- a/plugins/search/package.json +++ b/plugins/search/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-search", "description": "The Backstage plugin that provides your backstage app with search", - "version": "1.4.4-next.1", + "version": "1.4.4-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/sentry/CHANGELOG.md b/plugins/sentry/CHANGELOG.md index 1fa91a01ea..18cd09a846 100644 --- a/plugins/sentry/CHANGELOG.md +++ b/plugins/sentry/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-sentry +## 0.5.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + ## 0.5.13-next.0 ### Patch Changes diff --git a/plugins/sentry/package.json b/plugins/sentry/package.json index 1094ff07c5..aa705c40ca 100644 --- a/plugins/sentry/package.json +++ b/plugins/sentry/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-sentry", "description": "A Backstage plugin that integrates towards Sentry", - "version": "0.5.13-next.0", + "version": "0.5.13-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/shortcuts/CHANGELOG.md b/plugins/shortcuts/CHANGELOG.md index 3247352329..9360aa23a3 100644 --- a/plugins/shortcuts/CHANGELOG.md +++ b/plugins/shortcuts/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-shortcuts +## 0.3.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + ## 0.3.17-next.0 ### Patch Changes diff --git a/plugins/shortcuts/package.json b/plugins/shortcuts/package.json index 14afb8df00..85002ba918 100644 --- a/plugins/shortcuts/package.json +++ b/plugins/shortcuts/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-shortcuts", "description": "A Backstage plugin that provides a shortcuts feature to the sidebar", - "version": "0.3.17-next.0", + "version": "0.3.17-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/sonarqube-backend/CHANGELOG.md b/plugins/sonarqube-backend/CHANGELOG.md index d3daaf6505..45fd7abc59 100644 --- a/plugins/sonarqube-backend/CHANGELOG.md +++ b/plugins/sonarqube-backend/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-sonarqube-backend +## 0.2.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + ## 0.2.10-next.0 ### Patch Changes diff --git a/plugins/sonarqube-backend/package.json b/plugins/sonarqube-backend/package.json index 27b38e77a2..9959075967 100644 --- a/plugins/sonarqube-backend/package.json +++ b/plugins/sonarqube-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-sonarqube-backend", - "version": "0.2.10-next.0", + "version": "0.2.10-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/sonarqube-react/CHANGELOG.md b/plugins/sonarqube-react/CHANGELOG.md index a4ff66eaf1..ff15e247ae 100644 --- a/plugins/sonarqube-react/CHANGELOG.md +++ b/plugins/sonarqube-react/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-sonarqube-react +## 0.1.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/catalog-model@1.4.3 + ## 0.1.11-next.0 ### Patch Changes diff --git a/plugins/sonarqube-react/package.json b/plugins/sonarqube-react/package.json index a3578bec1f..c5c90158a1 100644 --- a/plugins/sonarqube-react/package.json +++ b/plugins/sonarqube-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-sonarqube-react", - "version": "0.1.11-next.0", + "version": "0.1.11-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/sonarqube/CHANGELOG.md b/plugins/sonarqube/CHANGELOG.md index 1dc9f44886..d9750032ea 100644 --- a/plugins/sonarqube/CHANGELOG.md +++ b/plugins/sonarqube/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-sonarqube +## 0.7.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-sonarqube-react@0.1.11-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + ## 0.7.10-next.0 ### Patch Changes diff --git a/plugins/sonarqube/package.json b/plugins/sonarqube/package.json index 742a7249a7..ec8ec3f633 100644 --- a/plugins/sonarqube/package.json +++ b/plugins/sonarqube/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-sonarqube", "description": "", - "version": "0.7.10-next.0", + "version": "0.7.10-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/splunk-on-call/CHANGELOG.md b/plugins/splunk-on-call/CHANGELOG.md index 5ebc73d577..6b567af287 100644 --- a/plugins/splunk-on-call/CHANGELOG.md +++ b/plugins/splunk-on-call/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-splunk-on-call +## 0.4.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + ## 0.4.17-next.0 ### Patch Changes diff --git a/plugins/splunk-on-call/package.json b/plugins/splunk-on-call/package.json index 8fc0fd6397..d612cbbbbd 100644 --- a/plugins/splunk-on-call/package.json +++ b/plugins/splunk-on-call/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-splunk-on-call", "description": "A Backstage plugin that integrates towards Splunk On-Call", - "version": "0.4.17-next.0", + "version": "0.4.17-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/stack-overflow-backend/CHANGELOG.md b/plugins/stack-overflow-backend/CHANGELOG.md index d736c2435a..aec0d6a964 100644 --- a/plugins/stack-overflow-backend/CHANGELOG.md +++ b/plugins/stack-overflow-backend/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-stack-overflow-backend +## 0.2.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-search-backend-module-stack-overflow-collator@0.1.1-next.1 + - @backstage/plugin-search-common@1.2.8 + ## 0.2.12-next.0 ### Patch Changes diff --git a/plugins/stack-overflow-backend/package.json b/plugins/stack-overflow-backend/package.json index e4c1d82265..584f9313d2 100644 --- a/plugins/stack-overflow-backend/package.json +++ b/plugins/stack-overflow-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-stack-overflow-backend", "description": "Deprecated, consider using @backstage/plugin-search-backend-module-stack-overflow-collator instead", - "version": "0.2.12-next.0", + "version": "0.2.12-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/stack-overflow/CHANGELOG.md b/plugins/stack-overflow/CHANGELOG.md index 7f579095b9..503462c664 100644 --- a/plugins/stack-overflow/CHANGELOG.md +++ b/plugins/stack-overflow/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-stack-overflow +## 0.1.23-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-search-react@1.7.4-next.1 + - @backstage/plugin-home-react@0.1.6-next.1 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-search-common@1.2.8 + ## 0.1.23-next.0 ### Patch Changes diff --git a/plugins/stack-overflow/package.json b/plugins/stack-overflow/package.json index 9c55565b0a..2ec939d18c 100644 --- a/plugins/stack-overflow/package.json +++ b/plugins/stack-overflow/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-stack-overflow", - "version": "0.1.23-next.0", + "version": "0.1.23-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/stackstorm/CHANGELOG.md b/plugins/stackstorm/CHANGELOG.md index f1e3f1b9ed..5a1f4c0d1c 100644 --- a/plugins/stackstorm/CHANGELOG.md +++ b/plugins/stackstorm/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-stackstorm +## 0.1.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + ## 0.1.9-next.0 ### Patch Changes diff --git a/plugins/stackstorm/package.json b/plugins/stackstorm/package.json index bf2bf2ec8c..3a16c66874 100644 --- a/plugins/stackstorm/package.json +++ b/plugins/stackstorm/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-stackstorm", "description": "A Backstage plugin that integrates towards StackStorm", - "version": "0.1.9-next.0", + "version": "0.1.9-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/tech-insights-backend-module-jsonfc/CHANGELOG.md b/plugins/tech-insights-backend-module-jsonfc/CHANGELOG.md index 2c5dc6d596..dd119052ae 100644 --- a/plugins/tech-insights-backend-module-jsonfc/CHANGELOG.md +++ b/plugins/tech-insights-backend-module-jsonfc/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-tech-insights-backend-module-jsonfc +## 0.1.40-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-tech-insights-common@0.2.12 + - @backstage/plugin-tech-insights-node@0.4.14-next.1 + ## 0.1.40-next.0 ### Patch Changes diff --git a/plugins/tech-insights-backend-module-jsonfc/package.json b/plugins/tech-insights-backend-module-jsonfc/package.json index b9250e979f..3fc9d67aed 100644 --- a/plugins/tech-insights-backend-module-jsonfc/package.json +++ b/plugins/tech-insights-backend-module-jsonfc/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-tech-insights-backend-module-jsonfc", - "version": "0.1.40-next.0", + "version": "0.1.40-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/tech-insights-backend/CHANGELOG.md b/plugins/tech-insights-backend/CHANGELOG.md index fdd358402f..c80a4ea1d7 100644 --- a/plugins/tech-insights-backend/CHANGELOG.md +++ b/plugins/tech-insights-backend/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-tech-insights-backend +## 0.5.22-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + - @backstage/plugin-tech-insights-node@0.4.14-next.1 + ## 0.5.22-next.0 ### Patch Changes diff --git a/plugins/tech-insights-backend/package.json b/plugins/tech-insights-backend/package.json index 46399ebc06..0fbbcf6463 100644 --- a/plugins/tech-insights-backend/package.json +++ b/plugins/tech-insights-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-tech-insights-backend", - "version": "0.5.22-next.0", + "version": "0.5.22-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/tech-insights-node/CHANGELOG.md b/plugins/tech-insights-node/CHANGELOG.md index 5bc20edd52..634b690d9b 100644 --- a/plugins/tech-insights-node/CHANGELOG.md +++ b/plugins/tech-insights-node/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-tech-insights-node +## 0.4.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + ## 0.4.14-next.0 ### Patch Changes diff --git a/plugins/tech-insights-node/package.json b/plugins/tech-insights-node/package.json index e44a0faa42..8b29e6cceb 100644 --- a/plugins/tech-insights-node/package.json +++ b/plugins/tech-insights-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-tech-insights-node", - "version": "0.4.14-next.0", + "version": "0.4.14-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/tech-insights/CHANGELOG.md b/plugins/tech-insights/CHANGELOG.md index 24a0a87835..a73f3dd78e 100644 --- a/plugins/tech-insights/CHANGELOG.md +++ b/plugins/tech-insights/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-tech-insights +## 0.3.20-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + ## 0.3.20-next.0 ### Patch Changes diff --git a/plugins/tech-insights/package.json b/plugins/tech-insights/package.json index 8e25134cea..47b0044adb 100644 --- a/plugins/tech-insights/package.json +++ b/plugins/tech-insights/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-tech-insights", - "version": "0.3.20-next.0", + "version": "0.3.20-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/tech-radar/CHANGELOG.md b/plugins/tech-radar/CHANGELOG.md index 0157900471..b732328bb6 100644 --- a/plugins/tech-radar/CHANGELOG.md +++ b/plugins/tech-radar/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-tech-radar +## 0.6.11-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/core-compat-api@0.0.1-next.1 + - @backstage/theme@0.5.0-next.0 + ## 0.6.11-next.1 ### Patch Changes diff --git a/plugins/tech-radar/package.json b/plugins/tech-radar/package.json index 258e25d753..bcfcc7c583 100644 --- a/plugins/tech-radar/package.json +++ b/plugins/tech-radar/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-tech-radar", "description": "A Backstage plugin that lets you display a Tech Radar for your organization", - "version": "0.6.11-next.1", + "version": "0.6.11-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/techdocs-addons-test-utils/CHANGELOG.md b/plugins/techdocs-addons-test-utils/CHANGELOG.md index 2ac11de91a..0a5115644e 100644 --- a/plugins/techdocs-addons-test-utils/CHANGELOG.md +++ b/plugins/techdocs-addons-test-utils/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-techdocs-addons-test-utils +## 1.0.25-next.2 + +### Patch Changes + +- 5d796829bb: Remove unnecessary catalog dependency +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-catalog@1.16.0-next.2 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/test-utils@1.4.6-next.1 + - @backstage/plugin-search-react@1.7.4-next.1 + - @backstage/plugin-techdocs@1.9.2-next.2 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/plugin-techdocs-react@1.1.14-next.1 + - @backstage/theme@0.5.0-next.0 + ## 1.0.25-next.1 ### Patch Changes diff --git a/plugins/techdocs-addons-test-utils/package.json b/plugins/techdocs-addons-test-utils/package.json index 9cb79ffb2d..6f334f9ae6 100644 --- a/plugins/techdocs-addons-test-utils/package.json +++ b/plugins/techdocs-addons-test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs-addons-test-utils", - "version": "1.0.25-next.1", + "version": "1.0.25-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/techdocs-backend/CHANGELOG.md b/plugins/techdocs-backend/CHANGELOG.md index 38cafea9aa..a307b1cdbb 100644 --- a/plugins/techdocs-backend/CHANGELOG.md +++ b/plugins/techdocs-backend/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-techdocs-backend +## 1.9.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/integration@1.8.0-next.1 + - @backstage/plugin-techdocs-node@1.11.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-search-backend-module-techdocs@0.1.12-next.1 + - @backstage/plugin-search-common@1.2.8 + ## 1.9.1-next.0 ### Patch Changes diff --git a/plugins/techdocs-backend/package.json b/plugins/techdocs-backend/package.json index d1885d9b94..4f288788a9 100644 --- a/plugins/techdocs-backend/package.json +++ b/plugins/techdocs-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-techdocs-backend", "description": "The Backstage backend plugin that renders technical documentation for your components", - "version": "1.9.1-next.0", + "version": "1.9.1-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/techdocs-module-addons-contrib/CHANGELOG.md b/plugins/techdocs-module-addons-contrib/CHANGELOG.md index 1b074bf428..cb30015229 100644 --- a/plugins/techdocs-module-addons-contrib/CHANGELOG.md +++ b/plugins/techdocs-module-addons-contrib/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-techdocs-module-addons-contrib +## 1.1.3-next.1 + +### Patch Changes + +- a518c5a25b: Updated dependency `@react-hookz/web` to `^23.0.0`. +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/plugin-techdocs-react@1.1.14-next.1 + - @backstage/theme@0.5.0-next.0 + ## 1.1.3-next.0 ### Patch Changes diff --git a/plugins/techdocs-module-addons-contrib/package.json b/plugins/techdocs-module-addons-contrib/package.json index a8d73b0913..231a8c2fa7 100644 --- a/plugins/techdocs-module-addons-contrib/package.json +++ b/plugins/techdocs-module-addons-contrib/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-techdocs-module-addons-contrib", "description": "Plugin module for contributed TechDocs Addons", - "version": "1.1.3-next.0", + "version": "1.1.3-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/techdocs-node/CHANGELOG.md b/plugins/techdocs-node/CHANGELOG.md index 84ffa704a5..b2649d492f 100644 --- a/plugins/techdocs-node/CHANGELOG.md +++ b/plugins/techdocs-node/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-techdocs-node +## 1.11.0-next.1 + +### Patch Changes + +- 99fb54183b: Updated dependency `@azure/identity` to `^4.0.0`. +- 2666675457: Updated dependency `@google-cloud/storage` to `^7.0.0`. +- 4f773c15f6: Bumped the default TechDocs docker image version to the latest which was released several month ago +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration-aws-node@0.1.8 + - @backstage/plugin-search-common@1.2.8 + ## 1.11.0-next.0 ### Minor Changes diff --git a/plugins/techdocs-node/package.json b/plugins/techdocs-node/package.json index ed9ad108c8..51a18a28bc 100644 --- a/plugins/techdocs-node/package.json +++ b/plugins/techdocs-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-techdocs-node", "description": "Common node.js functionalities for TechDocs, to be shared between techdocs-backend plugin and techdocs-cli", - "version": "1.11.0-next.0", + "version": "1.11.0-next.1", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/plugins/techdocs-react/CHANGELOG.md b/plugins/techdocs-react/CHANGELOG.md index c22425c38d..5c7c768ee2 100644 --- a/plugins/techdocs-react/CHANGELOG.md +++ b/plugins/techdocs-react/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-techdocs-react +## 1.1.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/version-bridge@1.0.7 + ## 1.1.14-next.0 ### Patch Changes diff --git a/plugins/techdocs-react/package.json b/plugins/techdocs-react/package.json index af3f4f3898..75d5a67aa3 100644 --- a/plugins/techdocs-react/package.json +++ b/plugins/techdocs-react/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-techdocs-react", "description": "Shared frontend utilities for TechDocs and Addons", - "version": "1.1.14-next.0", + "version": "1.1.14-next.1", "publishConfig": { "access": "public", "main": "dist/index.esm.js", diff --git a/plugins/techdocs/CHANGELOG.md b/plugins/techdocs/CHANGELOG.md index 781546b460..26794126a7 100644 --- a/plugins/techdocs/CHANGELOG.md +++ b/plugins/techdocs/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-techdocs +## 1.9.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-search-react@1.7.4-next.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/core-compat-api@0.0.1-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/plugin-techdocs-react@1.1.14-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-search-common@1.2.8 + ## 1.9.2-next.1 ### Patch Changes diff --git a/plugins/techdocs/package.json b/plugins/techdocs/package.json index 7ddd663700..2217c19956 100644 --- a/plugins/techdocs/package.json +++ b/plugins/techdocs/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-techdocs", "description": "The Backstage plugin that renders technical documentation for your components", - "version": "1.9.2-next.1", + "version": "1.9.2-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/todo-backend/CHANGELOG.md b/plugins/todo-backend/CHANGELOG.md index 21206ffb11..c2a25854d6 100644 --- a/plugins/todo-backend/CHANGELOG.md +++ b/plugins/todo-backend/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-todo-backend +## 0.3.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-openapi-utils@0.1.1-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-node@1.5.1-next.1 + ## 0.3.6-next.0 ### Patch Changes diff --git a/plugins/todo-backend/package.json b/plugins/todo-backend/package.json index de6cacce0e..2d33b028ca 100644 --- a/plugins/todo-backend/package.json +++ b/plugins/todo-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-todo-backend", "description": "A Backstage backend plugin that lets you browse TODO comments in your source code", - "version": "0.3.6-next.0", + "version": "0.3.6-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/todo/CHANGELOG.md b/plugins/todo/CHANGELOG.md index e11b9cf345..260e669324 100644 --- a/plugins/todo/CHANGELOG.md +++ b/plugins/todo/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-todo +## 0.2.32-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + ## 0.2.32-next.0 ### Patch Changes diff --git a/plugins/todo/package.json b/plugins/todo/package.json index a8da3e18f0..8df6781fb1 100644 --- a/plugins/todo/package.json +++ b/plugins/todo/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-todo", "description": "A Backstage plugin that lets you browse TODO comments in your source code", - "version": "0.2.32-next.0", + "version": "0.2.32-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/user-settings-backend/CHANGELOG.md b/plugins/user-settings-backend/CHANGELOG.md index e749a227fb..8158c2681d 100644 --- a/plugins/user-settings-backend/CHANGELOG.md +++ b/plugins/user-settings-backend/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-user-settings-backend +## 0.2.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + ## 0.2.7-next.0 ### Patch Changes diff --git a/plugins/user-settings-backend/package.json b/plugins/user-settings-backend/package.json index 63957f0457..3bbbf6a2be 100644 --- a/plugins/user-settings-backend/package.json +++ b/plugins/user-settings-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-user-settings-backend", "description": "The Backstage backend plugin to manage user settings", - "version": "0.2.7-next.0", + "version": "0.2.7-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/user-settings/CHANGELOG.md b/plugins/user-settings/CHANGELOG.md index 09db865099..1cbc748245 100644 --- a/plugins/user-settings/CHANGELOG.md +++ b/plugins/user-settings/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-user-settings +## 0.7.14-next.2 + +### Patch Changes + +- fb8f3bdbc2: Updated alpha translation message keys to use nested format and camel case. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/core-compat-api@0.0.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + ## 0.7.14-next.1 ### Patch Changes diff --git a/plugins/user-settings/package.json b/plugins/user-settings/package.json index 95cda4711e..c25cff5ede 100644 --- a/plugins/user-settings/package.json +++ b/plugins/user-settings/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-user-settings", "description": "A Backstage plugin that provides a settings page", - "version": "0.7.14-next.1", + "version": "0.7.14-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/vault-backend/CHANGELOG.md b/plugins/vault-backend/CHANGELOG.md index 6437abf187..ccbf0d4030 100644 --- a/plugins/vault-backend/CHANGELOG.md +++ b/plugins/vault-backend/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-vault-backend +## 0.4.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-vault-node@0.1.1-next.1 + ## 0.4.1-next.0 ### Patch Changes diff --git a/plugins/vault-backend/package.json b/plugins/vault-backend/package.json index f3e1b35e34..82420b5493 100644 --- a/plugins/vault-backend/package.json +++ b/plugins/vault-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-vault-backend", "description": "A Backstage backend plugin that integrates towards Vault", - "version": "0.4.1-next.0", + "version": "0.4.1-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/vault-node/CHANGELOG.md b/plugins/vault-node/CHANGELOG.md index cad01e299c..794c570555 100644 --- a/plugins/vault-node/CHANGELOG.md +++ b/plugins/vault-node/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-vault-node +## 0.1.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.1 + ## 0.1.1-next.0 ### Patch Changes diff --git a/plugins/vault-node/package.json b/plugins/vault-node/package.json index 5895ebe1c6..b8ccb98ce3 100644 --- a/plugins/vault-node/package.json +++ b/plugins/vault-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-vault-node", "description": "Node.js library for the vault plugin", - "version": "0.1.1-next.0", + "version": "0.1.1-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/vault/CHANGELOG.md b/plugins/vault/CHANGELOG.md index 8af5828881..b1a30d0111 100644 --- a/plugins/vault/CHANGELOG.md +++ b/plugins/vault/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-vault +## 0.1.23-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + ## 0.1.23-next.0 ### Patch Changes diff --git a/plugins/vault/package.json b/plugins/vault/package.json index f6d6523564..9374be54ec 100644 --- a/plugins/vault/package.json +++ b/plugins/vault/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-vault", "description": "A Backstage plugin that integrates towards Vault", - "version": "0.1.23-next.0", + "version": "0.1.23-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/xcmetrics/CHANGELOG.md b/plugins/xcmetrics/CHANGELOG.md index 7db4abda2d..a1aacf43a0 100644 --- a/plugins/xcmetrics/CHANGELOG.md +++ b/plugins/xcmetrics/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-xcmetrics +## 0.2.46-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + ## 0.2.46-next.0 ### Patch Changes diff --git a/plugins/xcmetrics/package.json b/plugins/xcmetrics/package.json index c4e3b72cdb..516c609b7a 100644 --- a/plugins/xcmetrics/package.json +++ b/plugins/xcmetrics/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-xcmetrics", "description": "A Backstage plugin that shows XCode build metrics for your components", - "version": "0.2.46-next.0", + "version": "0.2.46-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/yarn.lock b/yarn.lock index 97224acaac..45e22286fa 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3520,7 +3520,18 @@ __metadata: languageName: unknown linkType: soft -"@backstage/catalog-client@^1.4.6, @backstage/catalog-client@workspace:^, @backstage/catalog-client@workspace:packages/catalog-client": +"@backstage/catalog-client@npm:^1.4.6": + version: 1.4.6 + resolution: "@backstage/catalog-client@npm:1.4.6" + dependencies: + "@backstage/catalog-model": ^1.4.3 + "@backstage/errors": ^1.2.3 + cross-fetch: ^4.0.0 + checksum: c62b479ea8865c23046f742d75db5fb36827627e78cfdff64e713eb72abd11fef071b8150c07e695e5e6d879d257a8a9dc85ec132b7c64229c6a0bd2ef821200 + languageName: node + linkType: hard + +"@backstage/catalog-client@workspace:^, @backstage/catalog-client@workspace:packages/catalog-client": version: 0.0.0-use.local resolution: "@backstage/catalog-client@workspace:packages/catalog-client" dependencies: From 01dfe4770af27f1eb4ab4e234ebdcada9aa19906 Mon Sep 17 00:00:00 2001 From: MT Lewis Date: Tue, 28 Nov 2023 15:09:36 +0000 Subject: [PATCH 184/261] docs: add note about transitive group membership to identity resolver docs Signed-off-by: MT Lewis --- docs/auth/identity-resolver.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/auth/identity-resolver.md b/docs/auth/identity-resolver.md index a65f3d7899..0a626ef175 100644 --- a/docs/auth/identity-resolver.md +++ b/docs/auth/identity-resolver.md @@ -236,6 +236,12 @@ export default async function createPlugin( // an entity you will need to replace this step as well. // // You might also replace it if you for example want to filter out certain groups. + // + // Note that `getDefaultOwnershipEntityRefs` only includes groups to which the + // user has a direct MEMBER_OF relationship. It's perfectly fine to include + // groups that the user is transitively part of in the claims array, but the + // catalog doesn't currently provide a direct way of accessing this list of + // groups. const ownershipRefs = getDefaultOwnershipEntityRefs(entity); // The last step is to issue the token, where we might provide more options in the future. From 7e1907047f307d7615e9bd9235ca07dd9d90bcf4 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 21 Nov 2023 16:49:25 +0100 Subject: [PATCH 185/261] frontend-plugin-api: add ExtensionDefinition IR Co-authored-by: Philipp Hugenroth Co-authored-by: Camila Belo Co-authored-by: Vincenzo Scamporlino Signed-off-by: Patrik Oldsberg --- .../src/wiring/createExtension.ts | 29 +++++++++++++++++-- .../src/wiring/createPlugin.ts | 21 ++++++++++++-- 2 files changed, 44 insertions(+), 6 deletions(-) diff --git a/packages/frontend-plugin-api/src/wiring/createExtension.ts b/packages/frontend-plugin-api/src/wiring/createExtension.ts index 9443caeb66..3c876a5c00 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtension.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtension.ts @@ -73,7 +73,9 @@ export interface CreateExtensionOptions< TInputs extends AnyExtensionInputMap, TConfig, > { - id: string; + namespace?: string; + name?: string; + kind?: string; attachTo: { id: string; input: string }; disabled?: boolean; inputs?: TInputs; @@ -86,6 +88,27 @@ export interface CreateExtensionOptions< }): Expand>; } +/** @public */ +export interface ExtensionDefinition { + $$type: '@backstage/ExtensionDefinition'; + namespace?: string; + name?: string; + kind?: string; + attachTo: { id: string; input: string }; + disabled: boolean; + inputs: AnyExtensionInputMap; + output: AnyExtensionDataMap; + configSchema?: PortableSchema; + factory(options: { + node: AppNode; + config: TConfig; + inputs: Record< + string, + undefined | Record | Array> + >; + }): ExtensionDataValues; +} + /** @public */ export interface Extension { $$type: '@backstage/Extension'; @@ -112,11 +135,11 @@ export function createExtension< TConfig = never, >( options: CreateExtensionOptions, -): Extension { +): ExtensionDefinition { return { ...options, disabled: options.disabled ?? false, - $$type: '@backstage/Extension', + $$type: '@backstage/ExtensionDefinition', inputs: options.inputs ?? {}, factory({ inputs, ...rest }) { // TODO: Simplify this, but TS wouldn't infer the input type for some reason diff --git a/packages/frontend-plugin-api/src/wiring/createPlugin.ts b/packages/frontend-plugin-api/src/wiring/createPlugin.ts index 5e2a55ab88..3ded409fa7 100644 --- a/packages/frontend-plugin-api/src/wiring/createPlugin.ts +++ b/packages/frontend-plugin-api/src/wiring/createPlugin.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { Extension } from './createExtension'; +import { Extension, ExtensionDefinition } from './createExtension'; import { ExternalRouteRef, RouteRef } from '../routing'; import { FeatureFlagConfig } from './types'; @@ -32,7 +32,7 @@ export interface PluginOptions< id: string; routes?: Routes; externalRoutes?: ExternalRoutes; - extensions?: Extension[]; + extensions?: ExtensionDefinition[]; featureFlags?: FeatureFlagConfig[]; } @@ -70,8 +70,23 @@ export function createPlugin< id: options.id, routes: options.routes ?? ({} as Routes), externalRoutes: options.externalRoutes ?? ({} as ExternalRoutes), - extensions: options.extensions ?? [], featureFlags: options.featureFlags ?? [], + extensions: (options.extensions ?? []).map(definition => { + const { name, namespace: _, kind, ...rest } = definition; + + let id; + if (kind && name) { + id = `${kind}:${options.id}/${name}`; + } else if (kind) { + id = `${kind}:${options.id}`; + } else if (name) { + id = `${options.id}/${name}`; + } else { + id = options.id; + } + + return { id, ...rest, $$type: '@backstage/Extension' }; + }), } as InternalBackstagePlugin; } From 9351d17834e81829b5bdbd26a06c00701d547c82 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 21 Nov 2023 16:50:01 +0100 Subject: [PATCH 186/261] frontend-plugin-api: update createNavItemExtensions to use new naming strucutre Co-authored-by: Camila Belo Co-authored-by: Philipp Hugenroth Co-authored-by: Vincenzo Scamporlino Signed-off-by: Patrik Oldsberg --- .../src/extensions/createNavItemExtension.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/frontend-plugin-api/src/extensions/createNavItemExtension.tsx b/packages/frontend-plugin-api/src/extensions/createNavItemExtension.tsx index 84fbe5ffee..0ad8d80e96 100644 --- a/packages/frontend-plugin-api/src/extensions/createNavItemExtension.tsx +++ b/packages/frontend-plugin-api/src/extensions/createNavItemExtension.tsx @@ -24,14 +24,17 @@ import { RouteRef } from '../routing'; * @public */ export function createNavItemExtension(options: { - id: string; + namespace?: string; + name?: string; routeRef: RouteRef; title: string; icon: IconComponent; }) { - const { id, routeRef, title, icon } = options; + const { routeRef, title, icon, namespace, name } = options; return createExtension({ - id, + namespace, + name, + kind: 'nav-item', attachTo: { id: 'core.nav', input: 'items' }, configSchema: createSchemaFromZod(z => z.object({ From 1227f693f0c09a516410565051accddd0061521e Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 21 Nov 2023 16:58:01 +0100 Subject: [PATCH 187/261] frontend-plugin-api: add resolveExtensionDefinition helper + use for extension overrides Signed-off-by: Patrik Oldsberg --- .../src/wiring/createExtensionOverrides.ts | 7 +-- .../src/wiring/createPlugin.ts | 20 ++------- .../src/wiring/resolveExtensionDefinition.ts | 45 +++++++++++++++++++ 3 files changed, 53 insertions(+), 19 deletions(-) create mode 100644 packages/frontend-plugin-api/src/wiring/resolveExtensionDefinition.ts diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionOverrides.ts b/packages/frontend-plugin-api/src/wiring/createExtensionOverrides.ts index 3902654db7..6c368a0e8b 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtensionOverrides.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtensionOverrides.ts @@ -14,12 +14,13 @@ * limitations under the License. */ -import { Extension } from './createExtension'; +import { Extension, ExtensionDefinition } from './createExtension'; +import { resolveExtensionDefinition } from './resolveExtensionDefinition'; import { FeatureFlagConfig } from './types'; /** @public */ export interface ExtensionOverridesOptions { - extensions: Extension[]; + extensions: ExtensionDefinition[]; featureFlags?: FeatureFlagConfig[]; } @@ -42,7 +43,7 @@ export function createExtensionOverrides( return { $$type: '@backstage/ExtensionOverrides', version: 'v1', - extensions: options.extensions, + extensions: options.extensions.map(def => resolveExtensionDefinition(def)), featureFlags: options.featureFlags ?? [], } as InternalExtensionOverrides; } diff --git a/packages/frontend-plugin-api/src/wiring/createPlugin.ts b/packages/frontend-plugin-api/src/wiring/createPlugin.ts index 3ded409fa7..d7ee418990 100644 --- a/packages/frontend-plugin-api/src/wiring/createPlugin.ts +++ b/packages/frontend-plugin-api/src/wiring/createPlugin.ts @@ -17,6 +17,7 @@ import { Extension, ExtensionDefinition } from './createExtension'; import { ExternalRouteRef, RouteRef } from '../routing'; import { FeatureFlagConfig } from './types'; +import { resolveExtensionDefinition } from './resolveExtensionDefinition'; /** @public */ export type AnyRoutes = { [name in string]: RouteRef }; @@ -71,22 +72,9 @@ export function createPlugin< routes: options.routes ?? ({} as Routes), externalRoutes: options.externalRoutes ?? ({} as ExternalRoutes), featureFlags: options.featureFlags ?? [], - extensions: (options.extensions ?? []).map(definition => { - const { name, namespace: _, kind, ...rest } = definition; - - let id; - if (kind && name) { - id = `${kind}:${options.id}/${name}`; - } else if (kind) { - id = `${kind}:${options.id}`; - } else if (name) { - id = `${options.id}/${name}`; - } else { - id = options.id; - } - - return { id, ...rest, $$type: '@backstage/Extension' }; - }), + extensions: (options.extensions ?? []).map(def => + resolveExtensionDefinition(def, { namespace: options.id }), + ), } as InternalBackstagePlugin; } diff --git a/packages/frontend-plugin-api/src/wiring/resolveExtensionDefinition.ts b/packages/frontend-plugin-api/src/wiring/resolveExtensionDefinition.ts new file mode 100644 index 0000000000..7a7e319590 --- /dev/null +++ b/packages/frontend-plugin-api/src/wiring/resolveExtensionDefinition.ts @@ -0,0 +1,45 @@ +/* + * 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 { Extension, ExtensionDefinition } from './createExtension'; + +/** @internal */ +export function resolveExtensionDefinition( + definition: ExtensionDefinition, + context?: { namespace?: string }, +): Extension { + const { name, kind, namespace: _, ...rest } = definition; + const namespace = context?.namespace ?? definition.namespace; + + if (!namespace) { + throw new Error( + `Extension must declare an explicit namespace as it could not be resolved from context, name=${name} kind=${kind}`, + ); + } + + let id; + if (kind && name) { + id = `${kind}:${namespace}/${name}`; // nav-item:catalog/index + } else if (kind) { + id = `${kind}:${namespace}`; // nav-item:search + } else if (name) { + id = `${namespace}/${name}`; // core/nav + } else { + id = namespace; // core + } + + return { id, ...rest, $$type: '@backstage/Extension' }; +} From e8802b3f83c7f1b8b0115d5e6ecbece1582ffdd0 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 21 Nov 2023 17:02:28 +0100 Subject: [PATCH 188/261] frontend-plugin-api: basic tests for resolveExtensionDefinition Signed-off-by: Patrik Oldsberg --- .../wiring/resolveExtensionDefinition.test.ts | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 packages/frontend-plugin-api/src/wiring/resolveExtensionDefinition.test.ts diff --git a/packages/frontend-plugin-api/src/wiring/resolveExtensionDefinition.test.ts b/packages/frontend-plugin-api/src/wiring/resolveExtensionDefinition.test.ts new file mode 100644 index 0000000000..202c513aa2 --- /dev/null +++ b/packages/frontend-plugin-api/src/wiring/resolveExtensionDefinition.test.ts @@ -0,0 +1,48 @@ +/* + * 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 { ExtensionDefinition } from './createExtension'; +import { resolveExtensionDefinition } from './resolveExtensionDefinition'; + +describe('resolveExtensionDefinition', () => { + it.each([ + [{ namespace: 'ns' }, 'ns'], + [{ namespace: 'ns', name: 'n' }, 'ns/n'], + [{ kind: 'k', namespace: 'ns' }, 'k:ns'], + [{ kind: 'k', namespace: 'ns', name: 'n' }, 'k:ns/n'], + ])(`should resolve extension IDs %s`, (definition, expected) => { + const resolved = resolveExtensionDefinition( + definition as ExtensionDefinition, + ); + expect(resolved.id).toBe(expected); + }); + + it('should fail to resolve extension ID without namespace', () => { + expect(() => + resolveExtensionDefinition({ + kind: 'k', + name: 'n', + } as ExtensionDefinition), + ).toThrow( + 'Extension must declare an explicit namespace as it could not be resolved from context, name=n kind=k', + ); + expect(() => + resolveExtensionDefinition({} as ExtensionDefinition), + ).toThrow( + 'Extension must declare an explicit namespace as it could not be resolved from context, name=undefined kind=undefined', + ); + }); +}); From 6cde9098197855f4cc5f5fc71129f5bb1108f177 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 22 Nov 2023 12:00:39 +0100 Subject: [PATCH 189/261] frontend-plugin-api: naming refactor for createApiExtension Signed-off-by: Patrik Oldsberg --- .../src/extensions/createApiExtension.test.ts | 40 +++++++++++++++---- .../src/extensions/createApiExtension.ts | 38 ++++++++---------- 2 files changed, 48 insertions(+), 30 deletions(-) diff --git a/packages/frontend-plugin-api/src/extensions/createApiExtension.test.ts b/packages/frontend-plugin-api/src/extensions/createApiExtension.test.ts index e90c0b6b85..b2f84f05aa 100644 --- a/packages/frontend-plugin-api/src/extensions/createApiExtension.test.ts +++ b/packages/frontend-plugin-api/src/extensions/createApiExtension.test.ts @@ -26,13 +26,38 @@ describe('createApiExtension', () => { factory: () => ({ foo: 'bar' }), }); - const extension = createApiExtension({ - factory, + expect( + createApiExtension({ + factory, + }), + ).toEqual({ + $$type: '@backstage/ExtensionDefinition', + kind: 'api', + attachTo: { id: 'core', input: 'apis' }, + disabled: false, + configSchema: undefined, + inputs: {}, + output: { + api: expect.objectContaining({ + $$type: '@backstage/ExtensionDataRef', + id: 'core.api.factory', + config: {}, + }), + }, + factory: expect.any(Function), }); - expect(extension).toEqual({ - $$type: '@backstage/Extension', - id: 'apis.test', + expect( + createApiExtension({ + factory, + namespace: 'ns', + name: 'n', + }), + ).toEqual({ + $$type: '@backstage/ExtensionDefinition', + kind: 'api', + namespace: 'ns', + name: 'n', attachTo: { id: 'core', input: 'apis' }, disabled: false, configSchema: undefined, @@ -53,7 +78,6 @@ describe('createApiExtension', () => { const factory = jest.fn(() => ({ foo: 'bar' })); const extension = createApiExtension({ - api, inputs: {}, factory({ config: _config, inputs: _inputs }) { return createApiFactory({ @@ -65,8 +89,8 @@ describe('createApiExtension', () => { }); // boo expect(extension).toEqual({ - $$type: '@backstage/Extension', - id: 'apis.test', + $$type: '@backstage/ExtensionDefinition', + kind: 'api', attachTo: { id: 'core', input: 'apis' }, disabled: false, configSchema: undefined, diff --git a/packages/frontend-plugin-api/src/extensions/createApiExtension.ts b/packages/frontend-plugin-api/src/extensions/createApiExtension.ts index 7b6dded022..fb9acf0076 100644 --- a/packages/frontend-plugin-api/src/extensions/createApiExtension.ts +++ b/packages/frontend-plugin-api/src/extensions/createApiExtension.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { AnyApiFactory, AnyApiRef } from '@backstage/core-plugin-api'; +import { AnyApiFactory } from '@backstage/core-plugin-api'; import { PortableSchema } from '../schema'; import { ExtensionInputValues, @@ -28,30 +28,24 @@ import { Expand } from '../types'; export function createApiExtension< TConfig extends {}, TInputs extends AnyExtensionInputMap, ->( - options: ( - | { - api: AnyApiRef; - factory: (options: { - config: TConfig; - inputs: Expand>; - }) => AnyApiFactory; - } - | { - factory: AnyApiFactory; - } - ) & { - configSchema?: PortableSchema; - inputs?: TInputs; - }, -) { +>(options: { + factory: + | AnyApiFactory + | ((options: { + config: TConfig; + inputs: Expand>; + }) => AnyApiFactory); + namespace?: string; + name?: string; + configSchema?: PortableSchema; + inputs?: TInputs; +}) { const { factory, configSchema, inputs: extensionInputs } = options; - const apiRef = - 'api' in options ? options.api : (factory as { api: AnyApiRef }).api; - return createExtension({ - id: `apis.${apiRef.id}`, + kind: 'api', + namespace: options.namespace, + name: options.name, attachTo: { id: 'core', input: 'apis' }, inputs: extensionInputs, configSchema, From 5196a136c16750113eea1edcf129bbe010318130 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 22 Nov 2023 12:01:38 +0100 Subject: [PATCH 190/261] frontend-plugin-api: option ordering and export for createExtension types Signed-off-by: Patrik Oldsberg --- packages/frontend-plugin-api/src/wiring/createExtension.ts | 4 ++-- packages/frontend-plugin-api/src/wiring/index.ts | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/frontend-plugin-api/src/wiring/createExtension.ts b/packages/frontend-plugin-api/src/wiring/createExtension.ts index 3c876a5c00..25b30142a4 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtension.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtension.ts @@ -73,9 +73,9 @@ export interface CreateExtensionOptions< TInputs extends AnyExtensionInputMap, TConfig, > { + kind?: string; namespace?: string; name?: string; - kind?: string; attachTo: { id: string; input: string }; disabled?: boolean; inputs?: TInputs; @@ -91,9 +91,9 @@ export interface CreateExtensionOptions< /** @public */ export interface ExtensionDefinition { $$type: '@backstage/ExtensionDefinition'; + kind?: string; namespace?: string; name?: string; - kind?: string; attachTo: { id: string; input: string }; disabled: boolean; inputs: AnyExtensionInputMap; diff --git a/packages/frontend-plugin-api/src/wiring/index.ts b/packages/frontend-plugin-api/src/wiring/index.ts index 191307ce1a..24f83be6e5 100644 --- a/packages/frontend-plugin-api/src/wiring/index.ts +++ b/packages/frontend-plugin-api/src/wiring/index.ts @@ -22,6 +22,7 @@ export { export { createExtension, type Extension, + type ExtensionDefinition, type CreateExtensionOptions, type ExtensionDataValues, type ExtensionInputValues, From b21f33deda86563620a2be0ea263d76a8560bfdd Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 22 Nov 2023 13:14:52 +0100 Subject: [PATCH 191/261] frontend-app-api: update instantiateAppNodeTree tests for ExtensionDefinition Signed-off-by: Patrik Oldsberg --- .../src/tree/instantiateAppNodeTree.test.ts | 423 ++++++++++-------- 1 file changed, 231 insertions(+), 192 deletions(-) diff --git a/packages/frontend-app-api/src/tree/instantiateAppNodeTree.test.ts b/packages/frontend-app-api/src/tree/instantiateAppNodeTree.test.ts index 802c71f729..7167038184 100644 --- a/packages/frontend-app-api/src/tree/instantiateAppNodeTree.test.ts +++ b/packages/frontend-app-api/src/tree/instantiateAppNodeTree.test.ts @@ -28,28 +28,33 @@ import { } from './instantiateAppNodeTree'; import { AppNodeInstance, AppNodeSpec } from '@backstage/frontend-plugin-api'; import { resolveAppTree } from './resolveAppTree'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { resolveExtensionDefinition } from '../../../frontend-plugin-api/src/wiring/resolveExtensionDefinition'; const testDataRef = createExtensionDataRef('test'); const otherDataRef = createExtensionDataRef('other'); const inputMirrorDataRef = createExtensionDataRef('mirror'); -const simpleExtension = createExtension({ - id: 'core.test', - attachTo: { id: 'ignored', input: 'ignored' }, - output: { - test: testDataRef, - other: otherDataRef.optional(), - }, - configSchema: createSchemaFromZod(z => - z.object({ - output: z.string().default('test'), - other: z.number().optional(), - }), - ), - factory({ config }) { - return { test: config.output, other: config.other }; - }, -}); +const simpleExtension = resolveExtensionDefinition( + createExtension({ + namespace: 'core', + name: 'test', + attachTo: { id: 'ignored', input: 'ignored' }, + output: { + test: testDataRef, + other: otherDataRef.optional(), + }, + configSchema: createSchemaFromZod(z => + z.object({ + output: z.string().default('test'), + other: z.number().optional(), + }), + ), + factory({ config }) { + return { test: config.output, other: config.other }; + }, + }), +); function makeSpec( extension: Extension, @@ -117,19 +122,21 @@ describe('instantiateAppNodeTree', () => { it('should instantiate a node with attachments', () => { const tree = resolveAppTree('root-node', [ makeSpec( - createExtension({ - id: 'root-node', - attachTo: { id: 'ignored', input: 'ignored' }, - inputs: { - test: createExtensionInput({ test: testDataRef }), - }, - output: { - inputMirror: inputMirrorDataRef, - }, - factory({ inputs }) { - return { inputMirror: inputs }; - }, - }), + resolveExtensionDefinition( + createExtension({ + namespace: 'root-node', + attachTo: { id: 'ignored', input: 'ignored' }, + inputs: { + test: createExtensionInput({ test: testDataRef }), + }, + output: { + inputMirror: inputMirrorDataRef, + }, + factory({ inputs }) { + return { inputMirror: inputs }; + }, + }), + ), ), makeSpec(simpleExtension, { id: 'child-node', @@ -159,19 +166,21 @@ describe('instantiateAppNodeTree', () => { const tree = resolveAppTree('root-node', [ { ...makeSpec( - createExtension({ - id: 'root-node', - attachTo: { id: 'ignored', input: 'ignored' }, - inputs: { - test: createExtensionInput({ test: testDataRef }), - }, - output: { - inputMirror: inputMirrorDataRef, - }, - factory({ inputs }) { - return { inputMirror: inputs }; - }, - }), + resolveExtensionDefinition( + createExtension({ + namespace: 'root-node', + attachTo: { id: 'ignored', input: 'ignored' }, + inputs: { + test: createExtensionInput({ test: testDataRef }), + }, + output: { + inputMirror: inputMirrorDataRef, + }, + factory({ inputs }) { + return { inputMirror: inputs }; + }, + }), + ), ), }, { @@ -242,43 +251,46 @@ describe('createAppNodeInstance', () => { const instance = createAppNodeInstance({ attachments, node: makeNode( - createExtension({ - id: 'core.test', - attachTo: { id: 'ignored', input: 'ignored' }, - inputs: { - optionalSingletonPresent: createExtensionInput( - { + resolveExtensionDefinition( + createExtension({ + namespace: 'core', + name: 'test', + attachTo: { id: 'ignored', input: 'ignored' }, + inputs: { + optionalSingletonPresent: createExtensionInput( + { + test: testDataRef, + other: otherDataRef.optional(), + }, + { singleton: true, optional: true }, + ), + optionalSingletonMissing: createExtensionInput( + { + test: testDataRef, + other: otherDataRef.optional(), + }, + { singleton: true, optional: true }, + ), + singleton: createExtensionInput( + { + test: testDataRef, + other: otherDataRef.optional(), + }, + { singleton: true }, + ), + many: createExtensionInput({ test: testDataRef, other: otherDataRef.optional(), - }, - { singleton: true, optional: true }, - ), - optionalSingletonMissing: createExtensionInput( - { - test: testDataRef, - other: otherDataRef.optional(), - }, - { singleton: true, optional: true }, - ), - singleton: createExtensionInput( - { - test: testDataRef, - other: otherDataRef.optional(), - }, - { singleton: true }, - ), - many: createExtensionInput({ - test: testDataRef, - other: otherDataRef.optional(), - }), - }, - output: { - inputMirror: inputMirrorDataRef, - }, - factory({ inputs }) { - return { inputMirror: inputs }; - }, - }), + }), + }, + output: { + inputMirror: inputMirrorDataRef, + }, + factory({ inputs }) { + return { inputMirror: inputs }; + }, + }), + ), ), }); @@ -297,7 +309,7 @@ describe('createAppNodeInstance', () => { attachments: new Map(), }), ).toThrow( - "Invalid configuration for extension 'core.test'; caused by Error: Expected number, received string at 'other'", + "Invalid configuration for extension 'core/test'; caused by Error: Expected number, received string at 'other'", ); }); @@ -305,21 +317,24 @@ describe('createAppNodeInstance', () => { expect(() => createAppNodeInstance({ node: makeNode( - createExtension({ - id: 'core.test', - attachTo: { id: 'ignored', input: 'ignored' }, - output: {}, - factory() { - const error = new Error('NOPE'); - error.name = 'NopeError'; - throw error; - }, - }), + resolveExtensionDefinition( + createExtension({ + namespace: 'core', + name: 'test', + attachTo: { id: 'ignored', input: 'ignored' }, + output: {}, + factory() { + const error = new Error('NOPE'); + error.name = 'NopeError'; + throw error; + }, + }), + ), ), attachments: new Map(), }), ).toThrow( - "Failed to instantiate extension 'core.test'; caused by NopeError: NOPE", + "Failed to instantiate extension 'core/test'; caused by NopeError: NOPE", ); }); @@ -327,22 +342,25 @@ describe('createAppNodeInstance', () => { expect(() => createAppNodeInstance({ node: makeNode( - createExtension({ - id: 'core.test', - attachTo: { id: 'ignored', input: 'ignored' }, - output: { - test1: testDataRef, - test2: testDataRef, - }, - factory({}) { - return { test1: 'test', test2: 'test2' }; - }, - }), + resolveExtensionDefinition( + createExtension({ + namespace: 'core', + name: 'test', + attachTo: { id: 'ignored', input: 'ignored' }, + output: { + test1: testDataRef, + test2: testDataRef, + }, + factory({}) { + return { test1: 'test', test2: 'test2' }; + }, + }), + ), ), attachments: new Map(), }), ).toThrow( - "Failed to instantiate extension 'core.test', duplicate extension data 'test' received via output 'test2'", + "Failed to instantiate extension 'core/test', duplicate extension data 'test' received via output 'test2'", ); }); @@ -350,21 +368,24 @@ describe('createAppNodeInstance', () => { expect(() => createAppNodeInstance({ node: makeNode( - createExtension({ - id: 'core.test', - attachTo: { id: 'ignored', input: 'ignored' }, - output: { - test: testDataRef, - }, - factory({}) { - return { nonexistent: 'test' } as any; - }, - }), + resolveExtensionDefinition( + createExtension({ + namespace: 'core', + name: 'test', + attachTo: { id: 'ignored', input: 'ignored' }, + output: { + test: testDataRef, + }, + factory({}) { + return { nonexistent: 'test' } as any; + }, + }), + ), ), attachments: new Map(), }), ).toThrow( - "Failed to instantiate extension 'core.test', unknown output provided via 'nonexistent'", + "Failed to instantiate extension 'core/test', unknown output provided via 'nonexistent'", ); }); @@ -372,25 +393,28 @@ describe('createAppNodeInstance', () => { expect(() => createAppNodeInstance({ node: makeNode( - createExtension({ - id: 'core.test', - attachTo: { id: 'ignored', input: 'ignored' }, - inputs: { - singleton: createExtensionInput( - { - test: testDataRef, - }, - { singleton: true }, - ), - }, - output: {}, - factory: () => ({}), - }), + resolveExtensionDefinition( + createExtension({ + namespace: 'core', + name: 'test', + attachTo: { id: 'ignored', input: 'ignored' }, + inputs: { + singleton: createExtensionInput( + { + test: testDataRef, + }, + { singleton: true }, + ), + }, + output: {}, + factory: () => ({}), + }), + ), ), attachments: new Map(), }), ).toThrow( - "Failed to instantiate extension 'core.test', input 'singleton' is required but was not received", + "Failed to instantiate extension 'core/test', input 'singleton' is required but was not received", ); }); @@ -416,21 +440,24 @@ describe('createAppNodeInstance', () => { ], ]), node: makeNode( - createExtension({ - id: 'core.test', - attachTo: { id: 'ignored', input: 'ignored' }, - inputs: { - declared: createExtensionInput({ - test: testDataRef, - }), - }, - output: {}, - factory: () => ({}), - }), + resolveExtensionDefinition( + createExtension({ + namespace: 'core', + name: 'test', + attachTo: { id: 'ignored', input: 'ignored' }, + inputs: { + declared: createExtensionInput({ + test: testDataRef, + }), + }, + output: {}, + factory: () => ({}), + }), + ), ), }), ).toThrow( - "Failed to instantiate extension 'core.test', received undeclared input 'undeclared' from extension 'core.test'", + "Failed to instantiate extension 'core/test', received undeclared input 'undeclared' from extension 'core/test'", ); }); @@ -451,16 +478,19 @@ describe('createAppNodeInstance', () => { ], ]), node: makeNode( - createExtension({ - id: 'core.test', - attachTo: { id: 'ignored', input: 'ignored' }, - output: {}, - factory: () => ({}), - }), + resolveExtensionDefinition( + createExtension({ + namespace: 'core', + name: 'test', + attachTo: { id: 'ignored', input: 'ignored' }, + output: {}, + factory: () => ({}), + }), + ), ), }), ).toThrow( - "Failed to instantiate extension 'core.test', received undeclared inputs 'undeclared1' from extension 'core.test' and 'undeclared2' from extensions 'core.test', 'core.test'", + "Failed to instantiate extension 'core/test', received undeclared inputs 'undeclared1' from extension 'core/test' and 'undeclared2' from extensions 'core/test', 'core/test'", ); }); @@ -477,24 +507,27 @@ describe('createAppNodeInstance', () => { ], ]), node: makeNode( - createExtension({ - id: 'core.test', - attachTo: { id: 'ignored', input: 'ignored' }, - inputs: { - singleton: createExtensionInput( - { - test: testDataRef, - }, - { singleton: true }, - ), - }, - output: {}, - factory: () => ({}), - }), + resolveExtensionDefinition( + createExtension({ + namespace: 'core', + name: 'test', + attachTo: { id: 'ignored', input: 'ignored' }, + inputs: { + singleton: createExtensionInput( + { + test: testDataRef, + }, + { singleton: true }, + ), + }, + output: {}, + factory: () => ({}), + }), + ), ), }), ).toThrow( - "Failed to instantiate extension 'core.test', expected exactly one 'singleton' input but received multiple: 'core.test', 'core.test'", + "Failed to instantiate extension 'core/test', expected exactly one 'singleton' input but received multiple: 'core/test', 'core/test'", ); }); @@ -511,24 +544,27 @@ describe('createAppNodeInstance', () => { ], ]), node: makeNode( - createExtension({ - id: 'core.test', - attachTo: { id: 'ignored', input: 'ignored' }, - inputs: { - singleton: createExtensionInput( - { - test: testDataRef, - }, - { singleton: true, optional: true }, - ), - }, - output: {}, - factory: () => ({}), - }), + resolveExtensionDefinition( + createExtension({ + namespace: 'core', + name: 'test', + attachTo: { id: 'ignored', input: 'ignored' }, + inputs: { + singleton: createExtensionInput( + { + test: testDataRef, + }, + { singleton: true, optional: true }, + ), + }, + output: {}, + factory: () => ({}), + }), + ), ), }), ).toThrow( - "Failed to instantiate extension 'core.test', expected at most one 'singleton' input but received multiple: 'core.test', 'core.test'", + "Failed to instantiate extension 'core/test', expected at most one 'singleton' input but received multiple: 'core/test', 'core/test'", ); }); @@ -539,24 +575,27 @@ describe('createAppNodeInstance', () => { ['singleton', [makeInstanceWithId(simpleExtension, undefined)]], ]), node: makeNode( - createExtension({ - id: 'core.test', - attachTo: { id: 'ignored', input: 'ignored' }, - inputs: { - singleton: createExtensionInput( - { - other: otherDataRef, - }, - { singleton: true }, - ), - }, - output: {}, - factory: () => ({}), - }), + resolveExtensionDefinition( + createExtension({ + namespace: 'core', + name: 'test', + attachTo: { id: 'ignored', input: 'ignored' }, + inputs: { + singleton: createExtensionInput( + { + other: otherDataRef, + }, + { singleton: true }, + ), + }, + output: {}, + factory: () => ({}), + }), + ), ), }), ).toThrow( - "Failed to instantiate extension 'core.test', input 'singleton' did not receive required extension data 'other' from extension 'core.test'", + "Failed to instantiate extension 'core/test', input 'singleton' did not receive required extension data 'other' from extension 'core/test'", ); }); }); From 36c94b8462586e8239f5e6527465c905cd82593b Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 22 Nov 2023 13:41:57 +0100 Subject: [PATCH 192/261] plugins: refactor DI extension IDs Co-authored-by: Camila Belo Signed-off-by: Patrik Oldsberg --- .changeset/rich-bees-breathe.md | 17 ++++++++++++++ plugins/adr/src/alpha.tsx | 1 - plugins/catalog-import/src/alpha.tsx | 1 - plugins/catalog-react/src/alpha.tsx | 22 ++++++++++--------- .../alpha/createCatalogFilterExtension.tsx | 11 +++++----- plugins/catalog/src/alpha/entityCards.tsx | 18 +++++++-------- plugins/catalog/src/alpha/entityContents.tsx | 2 +- plugins/catalog/src/alpha/filters.tsx | 16 +++++++------- plugins/catalog/src/alpha/navItems.tsx | 1 - plugins/catalog/src/alpha/pages.tsx | 3 +-- .../catalog/src/alpha/searchResultItems.tsx | 1 - plugins/explore/src/alpha.tsx | 1 - plugins/graphiql/src/alpha.tsx | 19 ++++++++-------- plugins/home/src/alpha.tsx | 1 - plugins/search-react/src/alpha.test.tsx | 3 --- plugins/search-react/src/alpha.tsx | 16 +++++++++----- plugins/search/src/alpha.tsx | 2 -- plugins/stack-overflow/src/alpha.tsx | 1 - plugins/tech-radar/src/alpha.tsx | 2 -- plugins/techdocs/src/alpha.tsx | 10 ++------- plugins/user-settings/src/alpha.tsx | 1 - 21 files changed, 76 insertions(+), 73 deletions(-) create mode 100644 .changeset/rich-bees-breathe.md diff --git a/.changeset/rich-bees-breathe.md b/.changeset/rich-bees-breathe.md new file mode 100644 index 0000000000..7a40e3df2f --- /dev/null +++ b/.changeset/rich-bees-breathe.md @@ -0,0 +1,17 @@ +--- +'@backstage/plugin-catalog-import': patch +'@backstage/plugin-stack-overflow': patch +'@backstage/plugin-catalog-react': patch +'@backstage/plugin-user-settings': patch +'@backstage/plugin-search-react': patch +'@backstage/plugin-tech-radar': patch +'@backstage/plugin-graphiql': patch +'@backstage/plugin-techdocs': patch +'@backstage/plugin-catalog': patch +'@backstage/plugin-explore': patch +'@backstage/plugin-search': patch +'@backstage/plugin-home': patch +'@backstage/plugin-adr': patch +--- + +Refactor of the alpha exports due to API change in how extension IDs are constructed. diff --git a/plugins/adr/src/alpha.tsx b/plugins/adr/src/alpha.tsx index 1f6fa0711d..ea4d32e0da 100644 --- a/plugins/adr/src/alpha.tsx +++ b/plugins/adr/src/alpha.tsx @@ -31,7 +31,6 @@ function isAdrDocument(result: any): result is AdrDocument { /** @alpha */ export const AdrSearchResultListItemExtension = createSearchResultListItemExtension({ - id: 'adr', configSchema: createSchemaFromZod(z => z.object({ // TODO: Define how the icon can be configurable diff --git a/plugins/catalog-import/src/alpha.tsx b/plugins/catalog-import/src/alpha.tsx index 18ddda2ceb..7ecbac5346 100644 --- a/plugins/catalog-import/src/alpha.tsx +++ b/plugins/catalog-import/src/alpha.tsx @@ -38,7 +38,6 @@ import { catalogApiRef } from '@backstage/plugin-catalog-react'; // TODO: It's currently possible to override the import page with a custom one. We need to decide // whether this type of override is typically done with an input or by overriding the entire extension. const CatalogImportPageExtension = createPageExtension({ - id: 'plugin.catalog-import.page', defaultPath: '/catalog-import', routeRef: convertLegacyRouteRef(rootRouteRef), loader: () => import('./components/ImportPage').then(m => ), diff --git a/plugins/catalog-react/src/alpha.tsx b/plugins/catalog-react/src/alpha.tsx index 43b7156b34..ccb0efbe6d 100644 --- a/plugins/catalog-react/src/alpha.tsx +++ b/plugins/catalog-react/src/alpha.tsx @@ -50,7 +50,8 @@ export const entityFilterExpressionExtensionDataRef = export function createEntityCardExtension< TInputs extends AnyExtensionInputMap, >(options: { - id: string; + namespace?: string; + name?: string; attachTo?: { id: string; input: string }; disabled?: boolean; inputs?: TInputs; @@ -61,12 +62,12 @@ export function createEntityCardExtension< inputs: Expand>; }) => Promise; }) { - const id = `entity.cards.${options.id}`; - return createExtension({ - id, + kind: 'entity-card', + namespace: options.namespace, + name: options.name, attachTo: options.attachTo ?? { - id: 'entity.content.overview', + id: 'entity-content:catalog/overview', input: 'cards', }, disabled: options.disabled ?? true, @@ -104,7 +105,8 @@ export function createEntityCardExtension< export function createEntityContentExtension< TInputs extends AnyExtensionInputMap, >(options: { - id: string; + namespace?: string; + name?: string; attachTo?: { id: string; input: string }; disabled?: boolean; inputs?: TInputs; @@ -118,12 +120,12 @@ export function createEntityContentExtension< inputs: Expand>; }) => Promise; }) { - const id = `entity.content.${options.id}`; - return createExtension({ - id, + kind: 'entity-content', + namespace: options.namespace, + name: options.name, attachTo: options.attachTo ?? { - id: 'plugin.catalog.page.entity', + id: 'page:catalog/entity', input: 'contents', }, disabled: options.disabled ?? true, diff --git a/plugins/catalog/src/alpha/createCatalogFilterExtension.tsx b/plugins/catalog/src/alpha/createCatalogFilterExtension.tsx index 7dae30c1fa..48ee647b81 100644 --- a/plugins/catalog/src/alpha/createCatalogFilterExtension.tsx +++ b/plugins/catalog/src/alpha/createCatalogFilterExtension.tsx @@ -28,16 +28,17 @@ export function createCatalogFilterExtension< TInputs extends AnyExtensionInputMap, TConfig = never, >(options: { - id: string; + namespace?: string; + name?: string; inputs?: TInputs; configSchema?: PortableSchema; loader: (options: { config: TConfig }) => Promise; }) { - const id = `catalog.filter.${options.id}`; - return createExtension({ - id, - attachTo: { id: 'plugin.catalog.page.index', input: 'filters' }, + kind: 'catalog-filter', + namespace: options.namespace, + name: options.name, + attachTo: { id: 'page:catalog', input: 'filters' }, inputs: options.inputs ?? {}, configSchema: options.configSchema, output: { diff --git a/plugins/catalog/src/alpha/entityCards.tsx b/plugins/catalog/src/alpha/entityCards.tsx index 572e2caa3c..6b458f282e 100644 --- a/plugins/catalog/src/alpha/entityCards.tsx +++ b/plugins/catalog/src/alpha/entityCards.tsx @@ -18,7 +18,7 @@ import React from 'react'; import { createEntityCardExtension } from '@backstage/plugin-catalog-react/alpha'; export const EntityAboutCard = createEntityCardExtension({ - id: 'about', + name: 'about', loader: async () => import('../components/AboutCard').then(m => ( @@ -26,7 +26,7 @@ export const EntityAboutCard = createEntityCardExtension({ }); export const EntityLinksCard = createEntityCardExtension({ - id: 'links', + name: 'links', filter: 'has:links', loader: async () => import('../components/EntityLinksCard').then(m => { @@ -35,7 +35,7 @@ export const EntityLinksCard = createEntityCardExtension({ }); export const EntityLabelsCard = createEntityCardExtension({ - id: 'labels', + name: 'labels', filter: 'has:labels', loader: async () => import('../components/EntityLabelsCard').then(m => ( @@ -44,7 +44,7 @@ export const EntityLabelsCard = createEntityCardExtension({ }); export const EntityDependsOnComponentsCard = createEntityCardExtension({ - id: 'dependsOn.components', + name: 'dependsOnComponents', loader: async () => import('../components/DependsOnComponentsCard').then(m => ( @@ -52,7 +52,7 @@ export const EntityDependsOnComponentsCard = createEntityCardExtension({ }); export const EntityDependsOnResourcesCard = createEntityCardExtension({ - id: 'dependsOn.resources', + name: 'dependsOnResources', loader: async () => import('../components/DependsOnResourcesCard').then(m => ( @@ -60,7 +60,7 @@ export const EntityDependsOnResourcesCard = createEntityCardExtension({ }); export const EntityHasComponentsCard = createEntityCardExtension({ - id: 'has.components', + name: 'hasComponents', loader: async () => import('../components/HasComponentsCard').then(m => ( @@ -68,7 +68,7 @@ export const EntityHasComponentsCard = createEntityCardExtension({ }); export const EntityHasResourcesCard = createEntityCardExtension({ - id: 'has.resources', + name: 'hasResources', loader: async () => import('../components/HasResourcesCard').then(m => ( @@ -76,7 +76,7 @@ export const EntityHasResourcesCard = createEntityCardExtension({ }); export const EntityHasSubcomponentsCard = createEntityCardExtension({ - id: 'has.subcomponents', + name: 'hasSubcomponents', loader: async () => import('../components/HasSubcomponentsCard').then(m => ( @@ -84,7 +84,7 @@ export const EntityHasSubcomponentsCard = createEntityCardExtension({ }); export const EntityHasSystemsCard = createEntityCardExtension({ - id: 'has.systems', + name: 'hasSystems', loader: async () => import('../components/HasSystemsCard').then(m => ( diff --git a/plugins/catalog/src/alpha/entityContents.tsx b/plugins/catalog/src/alpha/entityContents.tsx index e280326b02..72adf4ec60 100644 --- a/plugins/catalog/src/alpha/entityContents.tsx +++ b/plugins/catalog/src/alpha/entityContents.tsx @@ -26,7 +26,7 @@ import { } from '@backstage/plugin-catalog-react/alpha'; export const OverviewEntityContent = createEntityContentExtension({ - id: 'overview', + name: 'overview', defaultPath: '/', defaultTitle: 'Overview', disabled: false, diff --git a/plugins/catalog/src/alpha/filters.tsx b/plugins/catalog/src/alpha/filters.tsx index 7b73c2d14b..be06e70611 100644 --- a/plugins/catalog/src/alpha/filters.tsx +++ b/plugins/catalog/src/alpha/filters.tsx @@ -19,7 +19,7 @@ import { createCatalogFilterExtension } from './createCatalogFilterExtension'; import { createSchemaFromZod } from '@backstage/frontend-plugin-api'; const CatalogEntityTagFilter = createCatalogFilterExtension({ - id: 'entity.tag', + name: 'tag', loader: async () => { const { EntityTagPicker } = await import('@backstage/plugin-catalog-react'); return ; @@ -27,7 +27,7 @@ const CatalogEntityTagFilter = createCatalogFilterExtension({ }); const CatalogEntityKindFilter = createCatalogFilterExtension({ - id: 'entity.kind', + name: 'kind', configSchema: createSchemaFromZod(z => z.object({ initialFilter: z.string().default('component'), @@ -42,7 +42,7 @@ const CatalogEntityKindFilter = createCatalogFilterExtension({ }); const CatalogEntityTypeFilter = createCatalogFilterExtension({ - id: 'entity.type', + name: 'type', loader: async () => { const { EntityTypePicker } = await import( '@backstage/plugin-catalog-react' @@ -52,7 +52,7 @@ const CatalogEntityTypeFilter = createCatalogFilterExtension({ }); const CatalogEntityOwnerFilter = createCatalogFilterExtension({ - id: 'entity.mode', + name: 'mode', configSchema: createSchemaFromZod(z => z.object({ mode: z.enum(['owners-only', 'all']).optional(), @@ -67,7 +67,7 @@ const CatalogEntityOwnerFilter = createCatalogFilterExtension({ }); const CatalogEntityNamespaceFilter = createCatalogFilterExtension({ - id: 'entity.namespace', + name: 'namespace', loader: async () => { const { EntityNamespacePicker } = await import( '@backstage/plugin-catalog-react' @@ -77,7 +77,7 @@ const CatalogEntityNamespaceFilter = createCatalogFilterExtension({ }); const CatalogEntityLifecycleFilter = createCatalogFilterExtension({ - id: 'entity.lifecycle', + name: 'lifecycle', loader: async () => { const { EntityLifecyclePicker } = await import( '@backstage/plugin-catalog-react' @@ -87,7 +87,7 @@ const CatalogEntityLifecycleFilter = createCatalogFilterExtension({ }); const CatalogEntityProcessingStatusFilter = createCatalogFilterExtension({ - id: 'entity.processing.status', + name: 'processing.status', loader: async () => { const { EntityProcessingStatusPicker } = await import( '@backstage/plugin-catalog-react' @@ -97,7 +97,7 @@ const CatalogEntityProcessingStatusFilter = createCatalogFilterExtension({ }); const CatalogUserListFilter = createCatalogFilterExtension({ - id: 'user.list', + name: 'list', configSchema: createSchemaFromZod(z => z.object({ initialFilter: z.enum(['owned', 'starred', 'all']).default('owned'), diff --git a/plugins/catalog/src/alpha/navItems.tsx b/plugins/catalog/src/alpha/navItems.tsx index 77ea394a97..8dde27b95a 100644 --- a/plugins/catalog/src/alpha/navItems.tsx +++ b/plugins/catalog/src/alpha/navItems.tsx @@ -20,7 +20,6 @@ import { createNavItemExtension } from '@backstage/frontend-plugin-api'; import { rootRouteRef } from '../routes'; export const CatalogIndexNavItem = createNavItemExtension({ - id: 'catalog.nav.index', routeRef: convertLegacyRouteRef(rootRouteRef), title: 'Catalog', icon: HomeIcon, diff --git a/plugins/catalog/src/alpha/pages.tsx b/plugins/catalog/src/alpha/pages.tsx index 6324f53083..7dd32f7748 100644 --- a/plugins/catalog/src/alpha/pages.tsx +++ b/plugins/catalog/src/alpha/pages.tsx @@ -30,7 +30,6 @@ import { rootRouteRef } from '../routes'; import { useEntityFromUrl } from '../components/CatalogEntityPage/useEntityFromUrl'; export const CatalogIndexPage = createPageExtension({ - id: 'plugin.catalog.page.index', defaultPath: '/catalog', routeRef: convertLegacyRouteRef(rootRouteRef), inputs: { @@ -46,7 +45,7 @@ export const CatalogIndexPage = createPageExtension({ }); export const CatalogEntityPage = createPageExtension({ - id: 'plugin.catalog.page.entity', + name: 'entity', defaultPath: '/catalog/:namespace/:kind/:name', routeRef: convertLegacyRouteRef(entityRouteRef), inputs: { diff --git a/plugins/catalog/src/alpha/searchResultItems.tsx b/plugins/catalog/src/alpha/searchResultItems.tsx index f677869136..c84aabf300 100644 --- a/plugins/catalog/src/alpha/searchResultItems.tsx +++ b/plugins/catalog/src/alpha/searchResultItems.tsx @@ -18,7 +18,6 @@ import { createSearchResultListItemExtension } from '@backstage/plugin-search-re export const CatalogSearchResultListItemExtension = createSearchResultListItemExtension({ - id: 'catalog', predicate: result => result.type === 'software-catalog', component: () => import('../components/CatalogSearchResultListItem').then( diff --git a/plugins/explore/src/alpha.tsx b/plugins/explore/src/alpha.tsx index 1825af5ddb..f06379c84b 100644 --- a/plugins/explore/src/alpha.tsx +++ b/plugins/explore/src/alpha.tsx @@ -20,7 +20,6 @@ import { createSearchResultListItemExtension } from '@backstage/plugin-search-re /** @alpha */ export const ExploreSearchResultListItemExtension = createSearchResultListItemExtension({ - id: 'explore', predicate: result => result.type === 'tools', component: () => import('./components/ToolSearchResultListItem').then( diff --git a/plugins/graphiql/src/alpha.tsx b/plugins/graphiql/src/alpha.tsx index 760bc77d8e..29d6877a0a 100644 --- a/plugins/graphiql/src/alpha.tsx +++ b/plugins/graphiql/src/alpha.tsx @@ -38,7 +38,6 @@ import { convertLegacyRouteRef } from '@backstage/core-compat-api'; /** @alpha */ export const GraphiqlPage = createPageExtension({ - id: 'plugin.graphiql.page', defaultPath: '/graphiql', routeRef: convertLegacyRouteRef(graphiQLRouteRef), loader: () => import('./components').then(m => ), @@ -46,7 +45,6 @@ export const GraphiqlPage = createPageExtension({ /** @alpha */ export const graphiqlPageSidebarItem = createNavItemExtension({ - id: 'plugin.graphiql.nav.index', title: 'GraphiQL', icon: GraphiQLIcon as IconComponent, routeRef: convertLegacyRouteRef(graphiQLRouteRef), @@ -59,7 +57,7 @@ const endpointDataRef = createExtensionDataRef( /** @alpha */ export const graphiqlBrowseApi = createApiExtension({ - api: graphQlBrowseApiRef, // apis.plugin.graphiql.browse + name: 'browse', inputs: { endpoints: createExtensionInput({ endpoint: endpointDataRef, @@ -74,15 +72,18 @@ export const graphiqlBrowseApi = createApiExtension({ }); /** @alpha */ -export function createEndpointExtension(options: { - id: string; +export function createGraphiQLEndpointExtension(options: { + namespace?: string; + name?: string; configSchema?: PortableSchema; disabled?: boolean; factory: (options: { config: TConfig }) => { endpoint: GraphQLEndpoint }; }) { return createExtension({ - id: `apis.plugin.graphiql.browse.${options.id}`, - attachTo: { id: 'apis.plugin.graphiql.browse', input: 'endpoints' }, + kind: 'graphiql-endpoint', + namespace: options.namespace, + name: options.name, + attachTo: { id: 'api:graphiql/browse', input: 'endpoints' }, configSchema: options.configSchema, disabled: options.disabled ?? false, output: { @@ -97,8 +98,8 @@ export function createEndpointExtension(options: { } /** @alpha */ -const gitlabGraphiQLBrowseExtension = createEndpointExtension({ - id: 'gitlab', +const gitlabGraphiQLBrowseExtension = createGraphiQLEndpointExtension({ + name: 'gitlab', disabled: true, configSchema: createSchemaFromZod(z => z diff --git a/plugins/home/src/alpha.tsx b/plugins/home/src/alpha.tsx index c8308f7c0a..9ccb4c8ed6 100644 --- a/plugins/home/src/alpha.tsx +++ b/plugins/home/src/alpha.tsx @@ -33,7 +33,6 @@ const rootRouteRef = createRouteRef(); export const titleExtensionDataRef = createExtensionDataRef('title'); const HomepageCompositionRootExtension = createPageExtension({ - id: 'home', defaultPath: '/home', routeRef: rootRouteRef, inputs: { diff --git a/plugins/search-react/src/alpha.test.tsx b/plugins/search-react/src/alpha.test.tsx index e1a8166390..11e0b3fdb0 100644 --- a/plugins/search-react/src/alpha.test.tsx +++ b/plugins/search-react/src/alpha.test.tsx @@ -44,7 +44,6 @@ describe('createSearchResultListItemExtension', () => { const TechDocsSearchResultItemExtension = createSearchResultListItemExtension({ - id: 'techdocs', attachTo: { id: 'plugin.search.page', input: 'items' }, configSchema: createSchemaFromZod(z => z @@ -67,14 +66,12 @@ describe('createSearchResultListItemExtension', () => { const ExploreSearchResultItemExtension = createSearchResultListItemExtension({ - id: 'explore', attachTo: { id: 'plugin.search.page', input: 'items' }, predicate: result => result.type === 'explore', component: async () => ExploreSearchResultItemComponent, }); const SearchPageExtension = createPageExtension({ - id: 'plugin.search.page', defaultPath: '/', inputs: { items: createExtensionInput({ diff --git a/plugins/search-react/src/alpha.tsx b/plugins/search-react/src/alpha.tsx index bb738a2b08..c733e2ee9f 100644 --- a/plugins/search-react/src/alpha.tsx +++ b/plugins/search-react/src/alpha.tsx @@ -58,9 +58,13 @@ export type SearchResultItemExtensionOptions< TConfig extends { noTrack?: boolean }, > = { /** - * The extension id. + * The extension namespace. */ - id: string; + namespace?: string; + /** + * The extension name. + */ + name?: string; /** * The extension attachment point (e.g., search modal or page). */ @@ -86,8 +90,6 @@ export type SearchResultItemExtensionOptions< export function createSearchResultListItemExtension< TConfig extends { noTrack?: boolean }, >(options: SearchResultItemExtensionOptions) { - const id = `plugin.search.result.item.${options.id}`; - const configSchema = 'configSchema' in options ? options.configSchema @@ -98,9 +100,11 @@ export function createSearchResultListItemExtension< ) as PortableSchema); return createExtension({ - id, + kind: 'search-result-list-item', + namespace: options.namespace, + name: options.name, attachTo: options.attachTo ?? { - id: 'plugin.search.page', + id: 'page:search', input: 'items', }, configSchema, diff --git a/plugins/search/src/alpha.tsx b/plugins/search/src/alpha.tsx index ef11828c71..3f1d307237 100644 --- a/plugins/search/src/alpha.tsx +++ b/plugins/search/src/alpha.tsx @@ -98,7 +98,6 @@ const useSearchPageStyles = makeStyles((theme: Theme) => ({ /** @alpha */ export const SearchPage = createPageExtension({ - id: 'plugin.search.page', routeRef: convertLegacyRouteRef(rootRouteRef), configSchema: createSchemaFromZod(z => z.object({ @@ -235,7 +234,6 @@ export const SearchPage = createPageExtension({ /** @alpha */ export const SearchNavItem = createNavItemExtension({ - id: 'plugin.search.nav.index', routeRef: convertLegacyRouteRef(rootRouteRef), title: 'Search', icon: SearchIcon, diff --git a/plugins/stack-overflow/src/alpha.tsx b/plugins/stack-overflow/src/alpha.tsx index 3708271ef1..f34c91f78b 100644 --- a/plugins/stack-overflow/src/alpha.tsx +++ b/plugins/stack-overflow/src/alpha.tsx @@ -33,7 +33,6 @@ const StackOverflowApi = createApiExtension({ /** @alpha */ const StackOverflowSearchResultListItem = createSearchResultListItemExtension({ - id: 'stack-overflow', predicate: result => result.type === 'stack-overflow', component: () => import('./search/StackOverflowSearchResultListItem').then( diff --git a/plugins/tech-radar/src/alpha.tsx b/plugins/tech-radar/src/alpha.tsx index f9a34e2158..5d650bd245 100644 --- a/plugins/tech-radar/src/alpha.tsx +++ b/plugins/tech-radar/src/alpha.tsx @@ -29,7 +29,6 @@ import { rootRouteRef } from './plugin'; /** @alpha */ export const TechRadarPage = createPageExtension({ - id: 'plugin.techradar.page', defaultPath: '/tech-radar', routeRef: convertLegacyRouteRef(rootRouteRef), configSchema: createSchemaFromZod(z => @@ -49,7 +48,6 @@ export const TechRadarPage = createPageExtension({ }); const sampleTechRadarApi = createApiExtension({ - api: techRadarApiRef, factory() { return createApiFactory(techRadarApiRef, new SampleTechRadarApi()); }, diff --git a/plugins/techdocs/src/alpha.tsx b/plugins/techdocs/src/alpha.tsx index 533b4cb524..cad983df3c 100644 --- a/plugins/techdocs/src/alpha.tsx +++ b/plugins/techdocs/src/alpha.tsx @@ -46,8 +46,7 @@ import { createEntityContentExtension } from '@backstage/plugin-catalog-react/al /** @alpha */ const techDocsStorage = createApiExtension({ - api: techdocsStorageApiRef, - + name: 'storage', factory() { return createApiFactory({ api: techdocsStorageApiRef, @@ -70,7 +69,6 @@ const techDocsStorage = createApiExtension({ /** @alpha */ const techDocsClient = createApiExtension({ - api: techdocsApiRef, factory() { return createApiFactory({ api: techdocsApiRef, @@ -92,7 +90,6 @@ const techDocsClient = createApiExtension({ /** @alpha */ export const TechDocsSearchResultListItemExtension = createSearchResultListItemExtension({ - id: 'techdocs', configSchema: createSchemaFromZod(z => z.object({ // TODO: Define how the icon can be configurable @@ -118,7 +115,6 @@ export const TechDocsSearchResultListItemExtension = * @alpha */ const TechDocsIndexPage = createPageExtension({ - id: 'plugin.techdocs.indexPage', defaultPath: '/docs', routeRef: convertLegacyRouteRef(rootRouteRef), loader: () => @@ -133,7 +129,7 @@ const TechDocsIndexPage = createPageExtension({ * @alpha */ const TechDocsReaderPage = createPageExtension({ - id: 'plugin.techdocs.readerPage', + name: 'reader', defaultPath: '/docs/:namespace/:kind/:name', routeRef: convertLegacyRouteRef(rootDocsRouteRef), loader: () => @@ -148,7 +144,6 @@ const TechDocsReaderPage = createPageExtension({ * @alpha */ const TechDocsEntityContent = createEntityContentExtension({ - id: 'techdocs', defaultPath: 'docs', defaultTitle: 'TechDocs', loader: () => import('./Router').then(m => ), @@ -156,7 +151,6 @@ const TechDocsEntityContent = createEntityContentExtension({ /** @alpha */ const TechDocsNavItem = createNavItemExtension({ - id: 'plugin.techdocs.nav.index', icon: LibraryBooks, title: 'Docs', routeRef: convertLegacyRouteRef(rootRouteRef), diff --git a/plugins/user-settings/src/alpha.tsx b/plugins/user-settings/src/alpha.tsx index 419ee2808d..dfcd1d7e2e 100644 --- a/plugins/user-settings/src/alpha.tsx +++ b/plugins/user-settings/src/alpha.tsx @@ -27,7 +27,6 @@ import React from 'react'; export * from './translation'; const UserSettingsPage = createPageExtension({ - id: 'plugin.user-settings.page', defaultPath: '/settings', routeRef: convertLegacyRouteRef(settingsRouteRef), inputs: { From e3b55e280de5ee37aea87d9f59d501e1ac32d072 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 22 Nov 2023 13:50:03 +0100 Subject: [PATCH 193/261] frontend-app-api: allow extension IDs to contain slashes Co-authored-by: Camila Belo Signed-off-by: Patrik Oldsberg --- .../src/tree/readAppExtensionsConfig.test.ts | 7 ++----- .../frontend-app-api/src/tree/readAppExtensionsConfig.ts | 9 --------- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/packages/frontend-app-api/src/tree/readAppExtensionsConfig.test.ts b/packages/frontend-app-api/src/tree/readAppExtensionsConfig.test.ts index 91f6992f29..d291df7384 100644 --- a/packages/frontend-app-api/src/tree/readAppExtensionsConfig.test.ts +++ b/packages/frontend-app-api/src/tree/readAppExtensionsConfig.test.ts @@ -105,7 +105,7 @@ describe('readAppExtensionsConfig', () => { app: { extensions: [ { - 'core.router/routes': { + '': { extension: 'example-package#MyPage', config: { foo: 'bar' }, }, @@ -115,7 +115,7 @@ describe('readAppExtensionsConfig', () => { }), ), ).toThrowErrorMatchingInlineSnapshot( - `"Invalid extension configuration at app.extensions[0], extension ID must not contain slashes; got 'core.router/routes', did you mean 'core.router'?"`, + `"Invalid extension configuration at app.extensions[0], extension ID must not be empty or contain whitespace"`, ); }); }); @@ -166,9 +166,6 @@ describe('expandShorthandExtensionParameters', () => { expect(() => run(' a')).toThrowErrorMatchingInlineSnapshot( `"Invalid extension configuration at app.extensions[1], extension ID must not be empty or contain whitespace"`, ); - expect(() => run('core.router/routes')).toThrowErrorMatchingInlineSnapshot( - `"Invalid extension configuration at app.extensions[1], extension ID must not contain slashes; got 'core.router/routes', did you mean 'core.router'?"`, - ); }); it('supports null value', () => { diff --git a/packages/frontend-app-api/src/tree/readAppExtensionsConfig.ts b/packages/frontend-app-api/src/tree/readAppExtensionsConfig.ts index 2b5b51ce92..cca7064add 100644 --- a/packages/frontend-app-api/src/tree/readAppExtensionsConfig.ts +++ b/packages/frontend-app-api/src/tree/readAppExtensionsConfig.ts @@ -70,15 +70,6 @@ export function expandShorthandExtensionParameters( errorMsg('extension ID must not be empty or contain whitespace'), ); } - - if (id.includes('/')) { - let message = `extension ID must not contain slashes; got '${id}'`; - const good = id.split('/')[0]; - if (good) { - message += `, did you mean '${good}'?`; - } - throw new Error(errorMsg(message)); - } } // Example YAML: From 818eea4925551dc6815133e60ccc7653e2584164 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 22 Nov 2023 14:20:56 +0100 Subject: [PATCH 194/261] frontend-test-utils: updates to work with new extension IDs Co-authored-by: Camila Belo Signed-off-by: Patrik Oldsberg --- .changeset/forty-insects-drop.md | 5 +++ .../src/app/createExtensionTester.test.tsx | 8 ++-- .../src/app/createExtensionTester.ts | 38 ++++++++++++------- plugins/search-react/src/alpha.test.tsx | 5 ++- plugins/tech-radar/package.json | 1 + plugins/tech-radar/src/alpha.test.tsx | 34 +++++++++++++++++ plugins/tech-radar/src/alpha.tsx | 2 +- yarn.lock | 1 + 8 files changed, 73 insertions(+), 21 deletions(-) create mode 100644 .changeset/forty-insects-drop.md create mode 100644 plugins/tech-radar/src/alpha.test.tsx diff --git a/.changeset/forty-insects-drop.md b/.changeset/forty-insects-drop.md new file mode 100644 index 0000000000..e2a94662ed --- /dev/null +++ b/.changeset/forty-insects-drop.md @@ -0,0 +1,5 @@ +--- +'@backstage/frontend-test-utils': patch +--- + +Updates for compatibility with the new extension IDs. diff --git a/packages/frontend-test-utils/src/app/createExtensionTester.test.tsx b/packages/frontend-test-utils/src/app/createExtensionTester.test.tsx index 398acf4c74..e738bee7d1 100644 --- a/packages/frontend-test-utils/src/app/createExtensionTester.test.tsx +++ b/packages/frontend-test-utils/src/app/createExtensionTester.test.tsx @@ -26,7 +26,7 @@ describe('createExtensionTester', () => { it('should render a simple extension', async () => { createExtensionTester( createExtension({ - id: 'test', + namespace: 'test', attachTo: { id: 'ignored', input: 'ignored' }, output: { element: coreExtensionData.reactElement }, factory: () => ({ element:
test
}), @@ -39,7 +39,7 @@ describe('createExtensionTester', () => { it('should render an extension even if disabled by default', async () => { createExtensionTester( createExtension({ - id: 'test', + namespace: 'test', attachTo: { id: 'ignored', input: 'ignored' }, disabled: true, output: { element: coreExtensionData.reactElement }, @@ -54,7 +54,7 @@ describe('createExtensionTester', () => { expect(() => createExtensionTester( createExtension({ - id: 'test', + namespace: 'test', attachTo: { id: 'ignored', input: 'ignored' }, disabled: true, output: { path: coreExtensionData.routePath }, @@ -62,7 +62,7 @@ describe('createExtensionTester', () => { }), ).render(), ).toThrow( - "Failed to instantiate extension 'core.router', input 'children' did not receive required extension data 'core.reactElement' from extension 'test'", + "Failed to instantiate extension 'core/router', input 'children' did not receive required extension data 'core.reactElement' from extension 'test'", ); }); }); diff --git a/packages/frontend-test-utils/src/app/createExtensionTester.ts b/packages/frontend-test-utils/src/app/createExtensionTester.ts index c95ece342d..b6d6542818 100644 --- a/packages/frontend-test-utils/src/app/createExtensionTester.ts +++ b/packages/frontend-test-utils/src/app/createExtensionTester.ts @@ -15,7 +15,12 @@ */ import { createSpecializedApp } from '@backstage/frontend-app-api'; -import { Extension, createPlugin } from '@backstage/frontend-plugin-api'; +import { + ExtensionDefinition, + createExtensionOverrides, +} from '@backstage/frontend-plugin-api'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { resolveExtensionDefinition } from '../../../frontend-plugin-api/src/wiring/resolveExtensionDefinition'; import { MockConfigApi } from '@backstage/test-utils'; import { JsonArray, JsonObject, JsonValue } from '@backstage/types'; import { RenderResult, render } from '@testing-library/react'; @@ -24,7 +29,7 @@ import { RenderResult, render } from '@testing-library/react'; export class ExtensionTester { /** @internal */ static forSubject( - subject: Extension, + subject: ExtensionDefinition, options?: { config?: TConfig }, ): ExtensionTester { const tester = new ExtensionTester(); @@ -33,16 +38,22 @@ export class ExtensionTester { } readonly #extensions = new Array<{ - extension: Extension; + id: string; + extension: ExtensionDefinition; config?: JsonValue; }>(); add( - extension: Extension, + extension: ExtensionDefinition, options?: { config?: TConfig }, ): ExtensionTester { + const withNamespace = { + ...extension, + namespace: extension.namespace ?? 'test', + }; this.#extensions.push({ - extension, + id: resolveExtensionDefinition(withNamespace).id, + extension: withNamespace, config: options?.config as JsonValue, }); @@ -61,25 +72,25 @@ export class ExtensionTester { const extensionsConfig: JsonArray = [ ...rest.map(entry => ({ - [entry.extension.id]: { + [entry.id]: { config: entry.config, }, })), { - [subject.extension.id]: { - attachTo: { id: 'core.router', input: 'children' }, + [subject.id]: { + attachTo: { id: 'core/router', input: 'children' }, config: subject.config, disabled: false, }, }, { - 'core.layout': false, + 'core/layout': false, }, { - 'core.nav': false, + 'core/nav': false, }, { - 'core.routes': false, + 'core/routes': false, }, ]; @@ -93,8 +104,7 @@ export class ExtensionTester { const app = createSpecializedApp({ features: [ - createPlugin({ - id: 'test', + createExtensionOverrides({ extensions: this.#extensions.map(entry => entry.extension), }), ], @@ -107,7 +117,7 @@ export class ExtensionTester { /** @public */ export function createExtensionTester( - subject: Extension, + subject: ExtensionDefinition, options?: { config?: TConfig }, ): ExtensionTester { return ExtensionTester.forSubject(subject, options); diff --git a/plugins/search-react/src/alpha.test.tsx b/plugins/search-react/src/alpha.test.tsx index 11e0b3fdb0..6950dec664 100644 --- a/plugins/search-react/src/alpha.test.tsx +++ b/plugins/search-react/src/alpha.test.tsx @@ -44,7 +44,7 @@ describe('createSearchResultListItemExtension', () => { const TechDocsSearchResultItemExtension = createSearchResultListItemExtension({ - attachTo: { id: 'plugin.search.page', input: 'items' }, + namespace: 'techdocs', configSchema: createSchemaFromZod(z => z .object({ @@ -66,12 +66,13 @@ describe('createSearchResultListItemExtension', () => { const ExploreSearchResultItemExtension = createSearchResultListItemExtension({ - attachTo: { id: 'plugin.search.page', input: 'items' }, + namespace: 'explore', predicate: result => result.type === 'explore', component: async () => ExploreSearchResultItemComponent, }); const SearchPageExtension = createPageExtension({ + namespace: 'search', defaultPath: '/', inputs: { items: createExtensionInput({ diff --git a/plugins/tech-radar/package.json b/plugins/tech-radar/package.json index bcfcc7c583..2fba4121c7 100644 --- a/plugins/tech-radar/package.json +++ b/plugins/tech-radar/package.json @@ -68,6 +68,7 @@ "@backstage/cli": "workspace:^", "@backstage/core-app-api": "workspace:^", "@backstage/dev-utils": "workspace:^", + "@backstage/frontend-test-utils": "workspace:^", "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", diff --git a/plugins/tech-radar/src/alpha.test.tsx b/plugins/tech-radar/src/alpha.test.tsx new file mode 100644 index 0000000000..37d39c412b --- /dev/null +++ b/plugins/tech-radar/src/alpha.test.tsx @@ -0,0 +1,34 @@ +/* + * 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 { createExtensionTester } from '@backstage/frontend-test-utils'; +import { screen } from '@testing-library/react'; +import { TechRadarPage, sampleTechRadarApi } from './alpha'; + +describe('TechRadarPage', () => { + beforeAll(() => { + Object.defineProperty(window.SVGElement.prototype, 'getBBox', { + value: () => ({ width: 100, height: 100 }), + configurable: true, + }); + }); + + it('renders without exploding', async () => { + createExtensionTester(TechRadarPage).add(sampleTechRadarApi).render(); + + await expect(screen.findByText('Tech Radar')).resolves.toBeInTheDocument(); + }); +}); diff --git a/plugins/tech-radar/src/alpha.tsx b/plugins/tech-radar/src/alpha.tsx index 5d650bd245..295d084a9a 100644 --- a/plugins/tech-radar/src/alpha.tsx +++ b/plugins/tech-radar/src/alpha.tsx @@ -47,7 +47,7 @@ export const TechRadarPage = createPageExtension({ import('./components').then(m => ), }); -const sampleTechRadarApi = createApiExtension({ +export const sampleTechRadarApi = createApiExtension({ factory() { return createApiFactory(techRadarApiRef, new SampleTechRadarApi()); }, diff --git a/yarn.lock b/yarn.lock index 45e22286fa..aac0b29773 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9587,6 +9587,7 @@ __metadata: "@backstage/core-plugin-api": "workspace:^" "@backstage/dev-utils": "workspace:^" "@backstage/frontend-plugin-api": "workspace:^" + "@backstage/frontend-test-utils": "workspace:^" "@backstage/test-utils": "workspace:^" "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 From 046e4436c101bcf77c635c02f5ffc340e48f615b Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 22 Nov 2023 16:19:35 +0100 Subject: [PATCH 195/261] core-compat-api: updates for extension ID refactor Co-authored-by: Camila Belo Signed-off-by: Patrik Oldsberg --- .changeset/stupid-wasps-fold.md | 5 ++++ .../src/collectLegacyRoutes.test.tsx | 22 +++++++-------- .../src/collectLegacyRoutes.tsx | 18 ++++++------ .../src/convertLegacyApp.test.tsx | 28 +++++++++---------- .../core-compat-api/src/convertLegacyApp.ts | 8 ++++-- 5 files changed, 44 insertions(+), 37 deletions(-) create mode 100644 .changeset/stupid-wasps-fold.md diff --git a/.changeset/stupid-wasps-fold.md b/.changeset/stupid-wasps-fold.md new file mode 100644 index 0000000000..260dd9f5f1 --- /dev/null +++ b/.changeset/stupid-wasps-fold.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-compat-api': patch +--- + +Updates for compatibility with the new extension IDs. diff --git a/packages/core-compat-api/src/collectLegacyRoutes.test.tsx b/packages/core-compat-api/src/collectLegacyRoutes.test.tsx index d09911b39d..1238fbbcb4 100644 --- a/packages/core-compat-api/src/collectLegacyRoutes.test.tsx +++ b/packages/core-compat-api/src/collectLegacyRoutes.test.tsx @@ -51,13 +51,13 @@ describe('collectLegacyRoutes', () => { id: 'score-card', extensions: [ { - id: 'plugin.score-card.page', - attachTo: { id: 'core.routes', input: 'routes' }, + id: 'page:score-card', + attachTo: { id: 'core/routes', input: 'routes' }, disabled: false, defaultConfig: { path: 'score-board' }, }, { - id: 'apis.plugin.scoringdata.service', + id: 'api:score-card', attachTo: { id: 'core', input: 'apis' }, disabled: false, }, @@ -67,13 +67,13 @@ describe('collectLegacyRoutes', () => { id: 'stackstorm', extensions: [ { - id: 'plugin.stackstorm.page', - attachTo: { id: 'core.routes', input: 'routes' }, + id: 'page:stackstorm', + attachTo: { id: 'core/routes', input: 'routes' }, disabled: false, defaultConfig: { path: 'stackstorm' }, }, { - id: 'apis.plugin.stackstorm.service', + id: 'api:stackstorm', attachTo: { id: 'core', input: 'apis' }, disabled: false, }, @@ -83,19 +83,19 @@ describe('collectLegacyRoutes', () => { id: 'puppetDb', extensions: [ { - id: 'plugin.puppetDb.page', - attachTo: { id: 'core.routes', input: 'routes' }, + id: 'page:puppetDb', + attachTo: { id: 'core/routes', input: 'routes' }, disabled: false, defaultConfig: { path: 'puppetdb' }, }, { - id: 'plugin.puppetDb.page2', - attachTo: { id: 'core.routes', input: 'routes' }, + id: 'page:puppetDb/2', + attachTo: { id: 'core/routes', input: 'routes' }, disabled: false, defaultConfig: { path: 'puppetdb' }, }, { - id: 'apis.plugin.puppetdb.service', + id: 'api:puppetDb', attachTo: { id: 'core', input: 'apis' }, disabled: false, }, diff --git a/packages/core-compat-api/src/collectLegacyRoutes.tsx b/packages/core-compat-api/src/collectLegacyRoutes.tsx index 037107bfda..764149948d 100644 --- a/packages/core-compat-api/src/collectLegacyRoutes.tsx +++ b/packages/core-compat-api/src/collectLegacyRoutes.tsx @@ -16,11 +16,11 @@ import React, { ReactNode } from 'react'; import { - Extension, createApiExtension, createPageExtension, createPlugin, BackstagePlugin, + ExtensionDefinition, } from '@backstage/frontend-plugin-api'; import { Route, Routes } from 'react-router-dom'; import { @@ -64,7 +64,7 @@ export function collectLegacyRoutes( ): BackstagePlugin[] { const createdPluginIds = new Map< LegacyBackstagePlugin, - Extension[] + ExtensionDefinition[] >(); React.Children.forEach( @@ -95,19 +95,18 @@ export function collectLegacyRoutes( 'core.mountPoint', ); - const pluginId = plugin.getId(); - const detectedExtensions = - createdPluginIds.get(plugin) ?? new Array>(); + createdPluginIds.get(plugin) ?? + new Array>(); createdPluginIds.set(plugin, detectedExtensions); const path: string = route.props.path; detectedExtensions.push( createPageExtension({ - id: `plugin.${pluginId}.page${ - detectedExtensions.length ? detectedExtensions.length + 1 : '' - }`, + name: detectedExtensions.length + ? String(detectedExtensions.length + 1) + : undefined, defaultPath: path[0] === '/' ? path.slice(1) : path, routeRef: routeRef ? convertLegacyRouteRef(routeRef) : undefined, @@ -131,9 +130,10 @@ export function collectLegacyRoutes( id: plugin.getId(), extensions: [ ...extensions, - ...Array.from(plugin.getApis()).map(factory => + ...Array.from(plugin.getApis()).map((factory, index) => createApiExtension({ factory, + name: index > 0 ? String(index + 1) : undefined, }), ), ], diff --git a/packages/core-compat-api/src/convertLegacyApp.test.tsx b/packages/core-compat-api/src/convertLegacyApp.test.tsx index 0f1f6145c9..eeb53ad998 100644 --- a/packages/core-compat-api/src/convertLegacyApp.test.tsx +++ b/packages/core-compat-api/src/convertLegacyApp.test.tsx @@ -59,13 +59,13 @@ describe('convertLegacyApp', () => { id: 'score-card', extensions: [ { - id: 'plugin.score-card.page', - attachTo: { id: 'core.routes', input: 'routes' }, + id: 'page:score-card', + attachTo: { id: 'core/routes', input: 'routes' }, disabled: false, defaultConfig: { path: 'score-board' }, }, { - id: 'apis.plugin.scoringdata.service', + id: 'api:score-card', attachTo: { id: 'core', input: 'apis' }, disabled: false, }, @@ -75,13 +75,13 @@ describe('convertLegacyApp', () => { id: 'stackstorm', extensions: [ { - id: 'plugin.stackstorm.page', - attachTo: { id: 'core.routes', input: 'routes' }, + id: 'page:stackstorm', + attachTo: { id: 'core/routes', input: 'routes' }, disabled: false, defaultConfig: { path: 'stackstorm' }, }, { - id: 'apis.plugin.stackstorm.service', + id: 'api:stackstorm', attachTo: { id: 'core', input: 'apis' }, disabled: false, }, @@ -91,19 +91,19 @@ describe('convertLegacyApp', () => { id: 'puppetDb', extensions: [ { - id: 'plugin.puppetDb.page', - attachTo: { id: 'core.routes', input: 'routes' }, + id: 'page:puppetDb', + attachTo: { id: 'core/routes', input: 'routes' }, disabled: false, defaultConfig: { path: 'puppetdb' }, }, { - id: 'plugin.puppetDb.page2', - attachTo: { id: 'core.routes', input: 'routes' }, + id: 'page:puppetDb/2', + attachTo: { id: 'core/routes', input: 'routes' }, disabled: false, defaultConfig: { path: 'puppetdb' }, }, { - id: 'apis.plugin.puppetdb.service', + id: 'api:puppetDb', attachTo: { id: 'core', input: 'apis' }, disabled: false, }, @@ -113,13 +113,13 @@ describe('convertLegacyApp', () => { id: undefined, extensions: [ { - id: 'core.layout', + id: 'core/layout', attachTo: { id: 'core', input: 'root' }, disabled: false, }, { - id: 'core.nav', - attachTo: { id: 'core.layout', input: 'nav' }, + id: 'core/nav', + attachTo: { id: 'core/layout', input: 'nav' }, disabled: true, }, ], diff --git a/packages/core-compat-api/src/convertLegacyApp.ts b/packages/core-compat-api/src/convertLegacyApp.ts index 93521b3955..3b12f0e1fd 100644 --- a/packages/core-compat-api/src/convertLegacyApp.ts +++ b/packages/core-compat-api/src/convertLegacyApp.ts @@ -100,7 +100,8 @@ export function convertLegacyApp( const [routesEl] = routesEls; const CoreLayoutOverride = createExtension({ - id: 'core.layout', + namespace: 'core', + name: 'layout', attachTo: { id: 'core', input: 'root' }, inputs: { content: createExtensionInput( @@ -121,8 +122,9 @@ export function convertLegacyApp( }, }); const CoreNavOverride = createExtension({ - id: 'core.nav', - attachTo: { id: 'core.layout', input: 'nav' }, + namespace: 'core', + name: 'nav', + attachTo: { id: 'core/layout', input: 'nav' }, output: {}, factory: () => ({}), disabled: true, From 933dc2d7f6d3d645aedd9f0f9323b00436e52f7d Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 22 Nov 2023 16:19:54 +0100 Subject: [PATCH 196/261] app-next: updates for extension ID refactor Co-authored-by: Camila Belo Signed-off-by: Patrik Oldsberg --- packages/app-next-example-plugin/src/plugin.tsx | 1 - packages/app-next/app-config.yaml | 12 ++++++------ packages/app-next/src/App.tsx | 4 +++- packages/app-next/src/examples/pagesPlugin.tsx | 6 +++--- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/packages/app-next-example-plugin/src/plugin.tsx b/packages/app-next-example-plugin/src/plugin.tsx index a3c95e900c..99c377b7e5 100644 --- a/packages/app-next-example-plugin/src/plugin.tsx +++ b/packages/app-next-example-plugin/src/plugin.tsx @@ -21,7 +21,6 @@ import { } from '@backstage/frontend-plugin-api'; export const ExamplePage = createPageExtension({ - id: 'example.page', defaultPath: '/example', loader: () => import('./Component').then(m => ), }); diff --git a/packages/app-next/app-config.yaml b/packages/app-next/app-config.yaml index 34cd78d480..3eaab2fa1a 100644 --- a/packages/app-next/app-config.yaml +++ b/packages/app-next/app-config.yaml @@ -7,17 +7,17 @@ app: plugin.catalog.externalRoutes.viewTechDoc: plugin.techdocs.routes.docRoot extensions: - - apis.plugin.graphiql.browse.gitlab: true + # - apis.plugin.graphiql.browse.gitlab: true + - graphiql-endpoint:graphiql/gitlab: true - # Entity page cards - - entity.cards.about - - entity.cards.labels - - entity.cards.links: + - entity-card:catalog/about + - entity-card:catalog/labels + - entity-card:catalog/links: config: filter: kind:component has:links # Entity page content - - entity.content.techdocs + - entity-content:techdocs # scmAuthExtension: >- # createScmAuthExtension({ diff --git a/packages/app-next/src/App.tsx b/packages/app-next/src/App.tsx index 791d2b38fa..22b04c3a3f 100644 --- a/packages/app-next/src/App.tsx +++ b/packages/app-next/src/App.tsx @@ -83,7 +83,7 @@ TODO: /* app.tsx */ const homePageExtension = createExtension({ - id: 'myhomepage', + name: 'myhomepage', attachTo: { id: 'home', input: 'props' }, output: { children: coreExtensionData.reactElement, @@ -101,10 +101,12 @@ const signInPage = createSignInPageExtension({ }); const scmAuthExtension = createApiExtension({ + name: 'scm-auth', factory: ScmAuth.createDefaultApiFactory(), }); const scmIntegrationApi = createApiExtension({ + name: 'scm-integration', factory: createApiFactory({ api: scmIntegrationsApiRef, deps: { configApi: configApiRef }, diff --git a/packages/app-next/src/examples/pagesPlugin.tsx b/packages/app-next/src/examples/pagesPlugin.tsx index 1e9409a5e4..c5069f99c3 100644 --- a/packages/app-next/src/examples/pagesPlugin.tsx +++ b/packages/app-next/src/examples/pagesPlugin.tsx @@ -36,7 +36,7 @@ export const pageXRouteRef = createRouteRef(); // }); const IndexPage = createPageExtension({ - id: 'index', + name: 'index', defaultPath: '/', routeRef: indexRouteRef, loader: async () => { @@ -68,7 +68,7 @@ const IndexPage = createPageExtension({ }); const Page1 = createPageExtension({ - id: 'page1', + name: 'page1', defaultPath: '/page1', routeRef: page1RouteRef, loader: async () => { @@ -102,7 +102,7 @@ const Page1 = createPageExtension({ }); const ExternalPage = createPageExtension({ - id: 'pageX', + name: 'pageX', defaultPath: '/pageX', routeRef: pageXRouteRef, loader: async () => { From 082eccf5ad0be2e0557e79b067657eae17653b78 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 22 Nov 2023 16:24:04 +0100 Subject: [PATCH 197/261] frontend-plugin-api: allow extensions to only define a name Co-authored-by: Camila Belo Signed-off-by: Patrik Oldsberg --- .../wiring/resolveExtensionDefinition.test.ts | 6 ++--- .../src/wiring/resolveExtensionDefinition.ts | 23 ++++++++----------- .../src/app/createExtensionTester.ts | 2 +- 3 files changed, 13 insertions(+), 18 deletions(-) diff --git a/packages/frontend-plugin-api/src/wiring/resolveExtensionDefinition.test.ts b/packages/frontend-plugin-api/src/wiring/resolveExtensionDefinition.test.ts index 202c513aa2..8f3755ac5d 100644 --- a/packages/frontend-plugin-api/src/wiring/resolveExtensionDefinition.test.ts +++ b/packages/frontend-plugin-api/src/wiring/resolveExtensionDefinition.test.ts @@ -20,6 +20,7 @@ import { resolveExtensionDefinition } from './resolveExtensionDefinition'; describe('resolveExtensionDefinition', () => { it.each([ [{ namespace: 'ns' }, 'ns'], + [{ namespace: 'n' }, 'n'], [{ namespace: 'ns', name: 'n' }, 'ns/n'], [{ kind: 'k', namespace: 'ns' }, 'k:ns'], [{ kind: 'k', namespace: 'ns', name: 'n' }, 'k:ns/n'], @@ -34,15 +35,14 @@ describe('resolveExtensionDefinition', () => { expect(() => resolveExtensionDefinition({ kind: 'k', - name: 'n', } as ExtensionDefinition), ).toThrow( - 'Extension must declare an explicit namespace as it could not be resolved from context, name=n kind=k', + 'Extension must declare an explicit namespace or name as it could not be resolved from context, kind=k namespace=undefined name=undefined', ); expect(() => resolveExtensionDefinition({} as ExtensionDefinition), ).toThrow( - 'Extension must declare an explicit namespace as it could not be resolved from context, name=undefined kind=undefined', + 'Extension must declare an explicit namespace or name as it could not be resolved from context, kind=undefined namespace=undefined name=undefined', ); }); }); diff --git a/packages/frontend-plugin-api/src/wiring/resolveExtensionDefinition.ts b/packages/frontend-plugin-api/src/wiring/resolveExtensionDefinition.ts index 7a7e319590..3d7acb33bd 100644 --- a/packages/frontend-plugin-api/src/wiring/resolveExtensionDefinition.ts +++ b/packages/frontend-plugin-api/src/wiring/resolveExtensionDefinition.ts @@ -24,22 +24,17 @@ export function resolveExtensionDefinition( const { name, kind, namespace: _, ...rest } = definition; const namespace = context?.namespace ?? definition.namespace; - if (!namespace) { + const namePart = + name && namespace ? `${namespace}/${name}` : namespace || name; + if (!namePart) { throw new Error( - `Extension must declare an explicit namespace as it could not be resolved from context, name=${name} kind=${kind}`, + `Extension must declare an explicit namespace or name as it could not be resolved from context, kind=${kind} namespace=${namespace} name=${name}`, ); } - let id; - if (kind && name) { - id = `${kind}:${namespace}/${name}`; // nav-item:catalog/index - } else if (kind) { - id = `${kind}:${namespace}`; // nav-item:search - } else if (name) { - id = `${namespace}/${name}`; // core/nav - } else { - id = namespace; // core - } - - return { id, ...rest, $$type: '@backstage/Extension' }; + return { + ...rest, + id: kind ? `${kind}:${namePart}` : namePart, + $$type: '@backstage/Extension', + }; } diff --git a/packages/frontend-test-utils/src/app/createExtensionTester.ts b/packages/frontend-test-utils/src/app/createExtensionTester.ts index b6d6542818..257a47439c 100644 --- a/packages/frontend-test-utils/src/app/createExtensionTester.ts +++ b/packages/frontend-test-utils/src/app/createExtensionTester.ts @@ -49,7 +49,7 @@ export class ExtensionTester { ): ExtensionTester { const withNamespace = { ...extension, - namespace: extension.namespace ?? 'test', + name: !extension.namespace && !extension.name ? 'test' : extension.name, }; this.#extensions.push({ id: resolveExtensionDefinition(withNamespace).id, From bd3ebbc368f484c1fffa11d04b624f882cd5541e Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 22 Nov 2023 16:24:45 +0100 Subject: [PATCH 198/261] frontend-plugin-api: add extension duplication validation for createPlugin Co-authored-by: Camila Belo Signed-off-by: Patrik Oldsberg --- .../src/wiring/createPlugin.test.ts | 151 +++++++++++++----- .../src/wiring/createPlugin.ts | 23 ++- 2 files changed, 127 insertions(+), 47 deletions(-) diff --git a/packages/frontend-plugin-api/src/wiring/createPlugin.test.ts b/packages/frontend-plugin-api/src/wiring/createPlugin.test.ts index f69b54aa42..0653c42d7c 100644 --- a/packages/frontend-plugin-api/src/wiring/createPlugin.test.ts +++ b/packages/frontend-plugin-api/src/wiring/createPlugin.test.ts @@ -28,48 +28,34 @@ import { createExtensionInput } from './createExtensionInput'; const nameExtensionDataRef = createExtensionDataRef('name'); -const TechRadarPage = createExtension({ - id: 'plugin.techradar.page', - attachTo: { id: 'test.output', input: 'names' }, +const Extension1 = createExtension({ + name: '1', + attachTo: { id: 'test/output', input: 'names' }, output: { name: nameExtensionDataRef, }, factory() { - return { name: 'TechRadar' }; + return { name: 'extension-1' }; }, }); -const CatalogPage = createExtension({ - id: 'plugin.catalog.page', - attachTo: { id: 'test.output', input: 'names' }, +const Extension2 = createExtension({ + name: '2', + attachTo: { id: 'test/output', input: 'names' }, output: { name: nameExtensionDataRef, }, configSchema: createSchemaFromZod(z => - z.object({ name: z.string().default('Catalog') }), + z.object({ name: z.string().default('extension-2') }), ), factory({ config }) { return { name: config.name }; }, }); -const TechDocsAddon = createExtension({ - id: 'plugin.techdocs.addon.example', - attachTo: { id: 'plugin.techdocs.page', input: 'addons' }, - output: { - name: nameExtensionDataRef, - }, - configSchema: createSchemaFromZod(z => - z.object({ name: z.string().default('TechDocsAddon') }), - ), - factory({ config }) { - return { name: config.name }; - }, -}); - -const TechDocsPage = createExtension({ - id: 'plugin.techdocs.page', - attachTo: { id: 'test.output', input: 'names' }, +const Extension3 = createExtension({ + name: '3', + attachTo: { id: 'test/output', input: 'names' }, inputs: { addons: createExtensionInput({ name: nameExtensionDataRef, @@ -79,12 +65,40 @@ const TechDocsPage = createExtension({ name: nameExtensionDataRef, }, factory({ inputs }) { - return { name: `TechDocs-${inputs.addons.map(n => n.name).join('-')}` }; + return { name: `extension-3:${inputs.addons.map(n => n.name).join('-')}` }; + }, +}); + +const Child = createExtension({ + name: 'child', + attachTo: { id: 'test/3', input: 'addons' }, + output: { + name: nameExtensionDataRef, + }, + configSchema: createSchemaFromZod(z => + z.object({ name: z.string().default('child') }), + ), + factory({ config }) { + return { name: config.name }; + }, +}); + +const Child2 = createExtension({ + name: 'child2', + attachTo: { id: 'test/3', input: 'addons' }, + output: { + name: nameExtensionDataRef, + }, + configSchema: createSchemaFromZod(z => + z.object({ name: z.string().default('child2') }), + ), + factory({ config }) { + return { name: config.name }; }, }); const outputExtension = createExtension({ - id: 'test.output', + name: 'output', attachTo: { id: 'core', input: 'root' }, inputs: { names: createExtensionInput({ @@ -118,40 +132,34 @@ function createTestAppRoot({ describe('createPlugin', () => { it('should create an empty plugin', () => { - const plugin = createPlugin({ id: 'empty' }); + const plugin = createPlugin({ id: 'test' }); expect(plugin).toBeDefined(); }); it('should create a plugin with extension instances', async () => { const plugin = createPlugin({ - id: 'empty', - extensions: [TechRadarPage, CatalogPage, outputExtension], + id: 'test', + extensions: [Extension1, Extension2, outputExtension], }); expect(plugin).toBeDefined(); await renderWithEffects( createTestAppRoot({ features: [plugin], - config: { app: { extensions: [{ 'core.router': false }] } }, + config: { app: { extensions: [{ 'core/router': false }] } }, }), ); await expect( - screen.findByText('Names: TechRadar, Catalog'), + screen.findByText('Names: extension-1, extension-2'), ).resolves.toBeInTheDocument(); }); it('should create a plugin with nested extension instances', async () => { const plugin = createPlugin({ - id: 'empty', - extensions: [ - TechRadarPage, - CatalogPage, - TechDocsPage, - TechDocsAddon, - outputExtension, - ], + id: 'test', + extensions: [Extension1, Extension2, Extension3, Child, outputExtension], }); expect(plugin).toBeDefined(); @@ -161,10 +169,10 @@ describe('createPlugin', () => { config: { app: { extensions: [ - { 'core.router': false }, + { 'core/router': false }, { - 'plugin.catalog.page': { - config: { name: 'CatalogRenamed' }, + 'test/2': { + config: { name: 'extension-2-renamed' }, }, }, ], @@ -175,8 +183,63 @@ describe('createPlugin', () => { await expect( screen.findByText( - 'Names: TechRadar, CatalogRenamed, TechDocs-TechDocsAddon', + 'Names: extension-1, extension-2-renamed, extension-3:child', ), ).resolves.toBeInTheDocument(); }); + + it('should create a plugin with nested extension instances and multiple children', async () => { + const plugin = createPlugin({ + id: 'test', + extensions: [ + Extension1, + Extension2, + Extension3, + Child, + Child2, + outputExtension, + ], + }); + expect(plugin).toBeDefined(); + + await renderWithEffects( + createTestAppRoot({ + features: [plugin], + config: { + app: { + extensions: [{ 'core/router': false }], + }, + }, + }), + ); + + await expect( + screen.findByText( + 'Names: extension-1, extension-2, extension-3:child-child2', + ), + ).resolves.toBeInTheDocument(); + }); + + it('should throw on duplicate extensions', async () => { + expect(() => + createPlugin({ + id: 'test', + extensions: [Extension1, Extension1], + }), + ).toThrow("Plugin 'test' provided duplicate extensions: test/1"); + + expect(() => + createPlugin({ + id: 'test', + extensions: [ + Extension1, + Extension2, + Extension2, + Extension3, + Extension3, + Extension3, + ], + }), + ).toThrow("Plugin 'test' provided duplicate extensions: test/2, test/3"); + }); }); diff --git a/packages/frontend-plugin-api/src/wiring/createPlugin.ts b/packages/frontend-plugin-api/src/wiring/createPlugin.ts index d7ee418990..ecc4d08f9a 100644 --- a/packages/frontend-plugin-api/src/wiring/createPlugin.ts +++ b/packages/frontend-plugin-api/src/wiring/createPlugin.ts @@ -65,6 +65,25 @@ export function createPlugin< >( options: PluginOptions, ): BackstagePlugin { + const extensions = (options.extensions ?? []).map(def => + resolveExtensionDefinition(def, { namespace: options.id }), + ); + + const extensionIds = extensions.map(e => e.id); + if (extensionIds.length !== new Set(extensionIds).size) { + const duplicates = Array.from( + new Set( + extensionIds.filter((id, index) => extensionIds.indexOf(id) !== index), + ), + ); + // TODO(Rugvip): This could provide some more information about the kind + name of the extensions + throw new Error( + `Plugin '${options.id}' provided duplicate extensions: ${duplicates.join( + ', ', + )}`, + ); + } + return { $$type: '@backstage/BackstagePlugin', version: 'v1', @@ -72,9 +91,7 @@ export function createPlugin< routes: options.routes ?? ({} as Routes), externalRoutes: options.externalRoutes ?? ({} as ExternalRoutes), featureFlags: options.featureFlags ?? [], - extensions: (options.extensions ?? []).map(def => - resolveExtensionDefinition(def, { namespace: options.id }), - ), + extensions, } as InternalBackstagePlugin; } From 14cef885eca8d347bdef740429e892799217aec7 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 22 Nov 2023 16:25:24 +0100 Subject: [PATCH 199/261] frontend-plugin-api: avoid spreading all extension options Co-authored-by: Camila Belo Signed-off-by: Patrik Oldsberg --- .../src/wiring/createExtension.test.ts | 12 ++++++------ .../src/wiring/createExtension.ts | 9 +++++++-- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/packages/frontend-plugin-api/src/wiring/createExtension.test.ts b/packages/frontend-plugin-api/src/wiring/createExtension.test.ts index 071272d58f..07d52f5bb4 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtension.test.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtension.test.ts @@ -25,7 +25,7 @@ function unused(..._any: any[]) {} describe('createExtension', () => { it('should create an extension with a simple output', () => { const baseConfig = { - id: 'test', + namespace: 'test', attachTo: { id: 'root', input: 'default' }, output: { foo: stringData, @@ -39,7 +39,7 @@ describe('createExtension', () => { }; }, }); - expect(extension.id).toBe('test'); + expect(extension.namespace).toBe('test'); // When declared as an error function without a block the TypeScript errors // are a more specific and will point at the property that is problematic. @@ -163,7 +163,7 @@ describe('createExtension', () => { it('should create an extension with a some optional output', () => { const baseConfig = { - id: 'test', + namespace: 'test', attachTo: { id: 'root', input: 'default' }, output: { foo: stringData, @@ -176,7 +176,7 @@ describe('createExtension', () => { foo: 'bar', }), }); - expect(extension.id).toBe('test'); + expect(extension.namespace).toBe('test'); createExtension({ ...baseConfig, @@ -233,7 +233,7 @@ describe('createExtension', () => { it('should create an extension with input', () => { const extension = createExtension({ - id: 'test', + namespace: 'test', attachTo: { id: 'root', input: 'default' }, inputs: { mixed: createExtensionInput({ @@ -286,6 +286,6 @@ describe('createExtension', () => { }; }, }); - expect(extension.id).toBe('test'); + expect(extension.namespace).toBe('test'); }); }); diff --git a/packages/frontend-plugin-api/src/wiring/createExtension.ts b/packages/frontend-plugin-api/src/wiring/createExtension.ts index 25b30142a4..e4c79a925b 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtension.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtension.ts @@ -137,10 +137,15 @@ export function createExtension< options: CreateExtensionOptions, ): ExtensionDefinition { return { - ...options, - disabled: options.disabled ?? false, $$type: '@backstage/ExtensionDefinition', + kind: options.kind, + namespace: options.namespace, + name: options.name, + attachTo: options.attachTo, + disabled: options.disabled ?? false, inputs: options.inputs ?? {}, + output: options.output, + configSchema: options.configSchema, factory({ inputs, ...rest }) { // TODO: Simplify this, but TS wouldn't infer the input type for some reason return options.factory({ From fee0bd23b8933678072268311daf0113102ead6e Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 22 Nov 2023 16:29:45 +0100 Subject: [PATCH 200/261] frontend-plugin-api: update built-in extension creators for new extension ID systme Co-authored-by: Camila Belo Signed-off-by: Patrik Oldsberg --- .../src/extensions/createNavItemExtension.tsx | 2 +- .../extensions/createPageExtension.test.tsx | 26 ++++++++++--------- .../src/extensions/createPageExtension.tsx | 15 ++++++----- .../src/extensions/createThemeExtension.ts | 4 ++- 4 files changed, 26 insertions(+), 21 deletions(-) diff --git a/packages/frontend-plugin-api/src/extensions/createNavItemExtension.tsx b/packages/frontend-plugin-api/src/extensions/createNavItemExtension.tsx index 0ad8d80e96..207778fbd7 100644 --- a/packages/frontend-plugin-api/src/extensions/createNavItemExtension.tsx +++ b/packages/frontend-plugin-api/src/extensions/createNavItemExtension.tsx @@ -35,7 +35,7 @@ export function createNavItemExtension(options: { namespace, name, kind: 'nav-item', - attachTo: { id: 'core.nav', input: 'items' }, + attachTo: { id: 'core/nav', input: 'items' }, configSchema: createSchemaFromZod(z => z.object({ title: z.string().default(title), diff --git a/packages/frontend-plugin-api/src/extensions/createPageExtension.test.tsx b/packages/frontend-plugin-api/src/extensions/createPageExtension.test.tsx index f75821944a..525f10ee61 100644 --- a/packages/frontend-plugin-api/src/extensions/createPageExtension.test.tsx +++ b/packages/frontend-plugin-api/src/extensions/createPageExtension.test.tsx @@ -36,14 +36,15 @@ describe('createPageExtension', () => { expect( createPageExtension({ - id: 'test', + name: 'test', configSchema, loader: async () =>
, }), ).toEqual({ - $$type: '@backstage/Extension', - id: 'test', - attachTo: { id: 'core.routes', input: 'routes' }, + $$type: '@backstage/ExtensionDefinition', + name: 'test', + kind: 'page', + attachTo: { id: 'core/routes', input: 'routes' }, configSchema: expect.anything(), disabled: false, inputs: {}, @@ -57,7 +58,7 @@ describe('createPageExtension', () => { expect( createPageExtension({ - id: 'test', + name: 'test', attachTo: { id: 'other', input: 'place' }, disabled: true, configSchema, @@ -69,8 +70,9 @@ describe('createPageExtension', () => { loader: async () =>
, }), ).toEqual({ - $$type: '@backstage/Extension', - id: 'test', + $$type: '@backstage/ExtensionDefinition', + name: 'test', + kind: 'page', attachTo: { id: 'other', input: 'place' }, configSchema: expect.anything(), disabled: true, @@ -89,14 +91,15 @@ describe('createPageExtension', () => { expect( createPageExtension({ - id: 'test', + name: 'test', defaultPath: '/here', loader: async () =>
, }), ).toEqual({ - $$type: '@backstage/Extension', - id: 'test', - attachTo: { id: 'core.routes', input: 'routes' }, + $$type: '@backstage/ExtensionDefinition', + name: 'test', + kind: 'page', + attachTo: { id: 'core/routes', input: 'routes' }, configSchema: expect.anything(), disabled: false, inputs: {}, @@ -118,7 +121,6 @@ describe('createPageExtension', () => { createExtensionTester( createPageExtension({ - id: 'plugin.page', defaultPath: '/', loader: async () =>
Component
, }), diff --git a/packages/frontend-plugin-api/src/extensions/createPageExtension.tsx b/packages/frontend-plugin-api/src/extensions/createPageExtension.tsx index 99733ba367..6796fe884d 100644 --- a/packages/frontend-plugin-api/src/extensions/createPageExtension.tsx +++ b/packages/frontend-plugin-api/src/extensions/createPageExtension.tsx @@ -20,12 +20,12 @@ import { createSchemaFromZod, PortableSchema } from '../schema'; import { coreExtensionData, createExtension, - Extension, ExtensionInputValues, AnyExtensionInputMap, } from '../wiring'; import { RouteRef } from '../routing'; import { Expand } from '../types'; +import { ExtensionDefinition } from '../wiring/createExtension'; /** * Helper for creating extensions for a routable React page component. @@ -44,7 +44,8 @@ export function createPageExtension< configSchema: PortableSchema; } ) & { - id: string; + namespace?: string; + name?: string; attachTo?: { id: string; input: string }; disabled?: boolean; inputs?: TInputs; @@ -54,9 +55,7 @@ export function createPageExtension< inputs: Expand>; }) => Promise; }, -): Extension { - const { id } = options; - +): ExtensionDefinition { const configSchema = 'configSchema' in options ? options.configSchema @@ -65,8 +64,10 @@ export function createPageExtension< ) as PortableSchema); return createExtension({ - id, - attachTo: options.attachTo ?? { id: 'core.routes', input: 'routes' }, + kind: 'page', + namespace: options.namespace, + name: options.name, + attachTo: options.attachTo ?? { id: 'core/routes', input: 'routes' }, configSchema, inputs: options.inputs, disabled: options.disabled, diff --git a/packages/frontend-plugin-api/src/extensions/createThemeExtension.ts b/packages/frontend-plugin-api/src/extensions/createThemeExtension.ts index d41121d51c..5554a08874 100644 --- a/packages/frontend-plugin-api/src/extensions/createThemeExtension.ts +++ b/packages/frontend-plugin-api/src/extensions/createThemeExtension.ts @@ -20,7 +20,9 @@ import { AppTheme } from '@backstage/core-plugin-api'; /** @public */ export function createThemeExtension(theme: AppTheme) { return createExtension({ - id: `themes.${theme.id}`, + kind: 'theme', + namespace: 'app', + name: theme.id, attachTo: { id: 'core', input: 'themes' }, output: { theme: coreExtensionData.theme, From 710260b849cbcdb344ee5bfc3bb4beec099b0782 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 22 Nov 2023 16:30:27 +0100 Subject: [PATCH 201/261] frontend-app-api: update core extensions to new ID format Co-authored-by: Camila Belo Signed-off-by: Patrik Oldsberg --- packages/frontend-app-api/src/extensions/Core.tsx | 2 +- packages/frontend-app-api/src/extensions/CoreLayout.tsx | 5 +++-- packages/frontend-app-api/src/extensions/CoreNav.tsx | 5 +++-- packages/frontend-app-api/src/extensions/CoreRouter.tsx | 3 ++- packages/frontend-app-api/src/extensions/CoreRoutes.tsx | 5 +++-- packages/frontend-app-api/src/wiring/createApp.tsx | 4 +++- 6 files changed, 15 insertions(+), 9 deletions(-) diff --git a/packages/frontend-app-api/src/extensions/Core.tsx b/packages/frontend-app-api/src/extensions/Core.tsx index 441cb5bcf0..472ed4905a 100644 --- a/packages/frontend-app-api/src/extensions/Core.tsx +++ b/packages/frontend-app-api/src/extensions/Core.tsx @@ -21,7 +21,7 @@ import { } from '@backstage/frontend-plugin-api'; export const Core = createExtension({ - id: 'core', + namespace: 'core', attachTo: { id: 'root', input: 'default' }, // ignored inputs: { apis: createExtensionInput({ diff --git a/packages/frontend-app-api/src/extensions/CoreLayout.tsx b/packages/frontend-app-api/src/extensions/CoreLayout.tsx index 0099b67751..94681120db 100644 --- a/packages/frontend-app-api/src/extensions/CoreLayout.tsx +++ b/packages/frontend-app-api/src/extensions/CoreLayout.tsx @@ -23,8 +23,9 @@ import { import { SidebarPage } from '@backstage/core-components'; export const CoreLayout = createExtension({ - id: 'core.layout', - attachTo: { id: 'core.router', input: 'children' }, + namespace: 'core', + name: 'layout', + attachTo: { id: 'core/router', input: 'children' }, inputs: { nav: createExtensionInput( { diff --git a/packages/frontend-app-api/src/extensions/CoreNav.tsx b/packages/frontend-app-api/src/extensions/CoreNav.tsx index 8d0d4ea5de..21d113d3d6 100644 --- a/packages/frontend-app-api/src/extensions/CoreNav.tsx +++ b/packages/frontend-app-api/src/extensions/CoreNav.tsx @@ -75,8 +75,9 @@ const SidebarNavItem = (props: NavTarget) => { }; export const CoreNav = createExtension({ - id: 'core.nav', - attachTo: { id: 'core.layout', input: 'nav' }, + namespace: 'core', + name: 'nav', + attachTo: { id: 'core/layout', input: 'nav' }, inputs: { items: createExtensionInput({ target: coreExtensionData.navTarget, diff --git a/packages/frontend-app-api/src/extensions/CoreRouter.tsx b/packages/frontend-app-api/src/extensions/CoreRouter.tsx index 510af04b51..088fd25ae7 100644 --- a/packages/frontend-app-api/src/extensions/CoreRouter.tsx +++ b/packages/frontend-app-api/src/extensions/CoreRouter.tsx @@ -36,7 +36,8 @@ import { signInPageComponentDataRef } from '../../../frontend-plugin-api/src/ext import { RouteTracker } from '../routing/RouteTracker'; export const CoreRouter = createExtension({ - id: 'core.router', + namespace: 'core', + name: 'router', attachTo: { id: 'core', input: 'root' }, inputs: { signInPage: createExtensionInput( diff --git a/packages/frontend-app-api/src/extensions/CoreRoutes.tsx b/packages/frontend-app-api/src/extensions/CoreRoutes.tsx index 9acd27b6bf..d77839f7b3 100644 --- a/packages/frontend-app-api/src/extensions/CoreRoutes.tsx +++ b/packages/frontend-app-api/src/extensions/CoreRoutes.tsx @@ -26,8 +26,9 @@ import { import { useRoutes } from 'react-router-dom'; export const CoreRoutes = createExtension({ - id: 'core.routes', - attachTo: { id: 'core.layout', input: 'content' }, + namespace: 'core', + name: 'routes', + attachTo: { id: 'core/layout', input: 'content' }, inputs: { routes: createExtensionInput({ path: coreExtensionData.routePath, diff --git a/packages/frontend-app-api/src/wiring/createApp.tsx b/packages/frontend-app-api/src/wiring/createApp.tsx index 4e463fb526..4671ec239d 100644 --- a/packages/frontend-app-api/src/wiring/createApp.tsx +++ b/packages/frontend-app-api/src/wiring/createApp.tsx @@ -73,6 +73,8 @@ import { AppLanguageSelector } from '../../../core-app-api/src/apis/implementati // eslint-disable-next-line @backstage/no-relative-monorepo-imports import { I18nextTranslationApi } from '../../../core-app-api/src/apis/implementations/TranslationApi/I18nextTranslationApi'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { resolveExtensionDefinition } from '../../../frontend-plugin-api/src/wiring/resolveExtensionDefinition'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports import { apis as defaultApis, components as defaultComponents, @@ -119,7 +121,7 @@ export const builtinExtensions = [ DefaultNotFoundErrorPageComponent, LightTheme, DarkTheme, -]; +].map(def => resolveExtensionDefinition(def)); /** @public */ export interface ExtensionTreeNode { From c387f809d3dbef999b00007255e3e85a9a6f2fc7 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 22 Nov 2023 16:59:32 +0100 Subject: [PATCH 202/261] frontend-*-api: test updates for extension ID change Co-authored-by: Camila Belo Signed-off-by: Patrik Oldsberg --- .../extractRouteInfoFromAppNode.test.ts | 88 +++++++-------- .../src/tree/createAppTree.test.ts | 43 ++------ .../src/tree/readAppExtensionsConfig.test.ts | 82 +++++++------- .../src/tree/resolveAppNodeSpecs.test.ts | 103 ++++++++++++------ .../src/tree/resolveAppTree.test.ts | 18 +-- .../src/wiring/createApp.test.tsx | 28 ++--- .../frontend-app-api/src/wiring/createApp.tsx | 4 +- .../src/components/ExtensionBoundary.test.tsx | 7 +- .../wiring/createExtensionOverrides.test.ts | 45 +++++++- 9 files changed, 233 insertions(+), 185 deletions(-) diff --git a/packages/frontend-app-api/src/routing/extractRouteInfoFromAppNode.test.ts b/packages/frontend-app-api/src/routing/extractRouteInfoFromAppNode.test.ts index a06d236b77..f0ce6ac590 100644 --- a/packages/frontend-app-api/src/routing/extractRouteInfoFromAppNode.test.ts +++ b/packages/frontend-app-api/src/routing/extractRouteInfoFromAppNode.test.ts @@ -20,7 +20,7 @@ import { extractRouteInfoFromAppNode } from './extractRouteInfoFromAppNode'; import { AnyRouteRefParams, AppNode, - Extension, + ExtensionDefinition, RouteRef, coreExtensionData, createExtension, @@ -40,16 +40,16 @@ const ref5 = createRouteRef(); const refOrder: RouteRef[] = [ref1, ref2, ref3, ref4, ref5]; function createTestExtension(options: { - id: string; + name: string; parent?: string; path?: string; routeRef?: RouteRef; }) { return createExtension({ - id: options.id, + name: options.name, attachTo: options.parent - ? { id: options.parent, input: 'children' } - : { id: 'core.routes', input: 'routes' }, + ? { id: `test/${options.parent}`, input: 'children' } + : { id: 'core/routes', input: 'routes' }, output: { element: coreExtensionData.reactElement, path: coreExtensionData.routePath.optional(), @@ -70,14 +70,14 @@ function createTestExtension(options: { }); } -function routeInfoFromExtensions(extensions: Extension[]) { +function routeInfoFromExtensions(extensions: ExtensionDefinition[]) { const plugin = createPlugin({ id: 'test', extensions, }); const tree = createAppTree({ - builtinExtensions, config: new MockConfigApi({}), + builtinExtensions, features: [plugin], }); @@ -122,33 +122,33 @@ describe('discovery', () => { it('should collect routes', () => { const info = routeInfoFromExtensions([ createTestExtension({ - id: 'nothing', + name: 'nothing', path: 'nothing', }), createTestExtension({ - id: 'page1', + name: 'page1', path: 'foo', routeRef: ref1, }), createTestExtension({ - id: 'page2', + name: 'page2', parent: 'page1', path: 'bar/:id', routeRef: ref2, }), createTestExtension({ - id: 'page3', + name: 'page3', parent: 'page2', path: 'baz', routeRef: ref3, }), createTestExtension({ - id: 'page4', + name: 'page4', path: 'divsoup', routeRef: ref4, }), createTestExtension({ - id: 'page5', + name: 'page5', parent: 'page1', path: 'blop', routeRef: ref5, @@ -226,29 +226,29 @@ describe('discovery', () => { it('should handle all react router Route patterns', () => { const info = routeInfoFromExtensions([ createTestExtension({ - id: 'page1', + name: 'page1', path: 'foo', routeRef: ref1, }), createTestExtension({ - id: 'page2', + name: 'page2', parent: 'page1', path: 'bar/:id', routeRef: ref2, }), createTestExtension({ - id: 'page3', + name: 'page3', path: 'baz', routeRef: ref3, }), createTestExtension({ - id: 'page4', + name: 'page4', parent: 'page3', path: 'divsoup', routeRef: ref4, }), createTestExtension({ - id: 'page5', + name: 'page5', parent: 'page3', path: 'blop', routeRef: ref5, @@ -274,29 +274,29 @@ describe('discovery', () => { it('should strip leading slashes in route paths', () => { const info = routeInfoFromExtensions([ createTestExtension({ - id: 'page1', + name: 'page1', path: '/foo', routeRef: ref1, }), createTestExtension({ - id: 'page2', + name: 'page2', parent: 'page1', path: '/bar/:id', routeRef: ref2, }), createTestExtension({ - id: 'page3', + name: 'page3', path: '/baz', routeRef: ref3, }), createTestExtension({ - id: 'page4', + name: 'page4', parent: 'page3', path: '/divsoup', routeRef: ref4, }), createTestExtension({ - id: 'page5', + name: 'page5', parent: 'page3', path: '/blop', routeRef: ref5, @@ -322,44 +322,44 @@ describe('discovery', () => { it('should use the route aggregator key to bind child routes to the same path', () => { const info = routeInfoFromExtensions([ createTestExtension({ - id: 'foo', + name: 'foo', path: 'foo', }), createTestExtension({ - id: 'page1', + name: 'page1', parent: 'foo', routeRef: ref1, }), createTestExtension({ - id: 'fooChild', + name: 'fooChild', parent: 'foo', }), createTestExtension({ - id: 'page2', + name: 'page2', parent: 'fooChild', routeRef: ref2, }), createTestExtension({ - id: 'fooEmpty', + name: 'fooEmpty', parent: 'foo', }), createTestExtension({ - id: 'page3', + name: 'page3', path: 'bar', routeRef: ref3, }), createTestExtension({ - id: 'page3Child', + name: 'page3Child', parent: 'page3', path: '', }), createTestExtension({ - id: 'page4', + name: 'page4', parent: 'page3Child', routeRef: ref4, }), createTestExtension({ - id: 'page5', + name: 'page5', parent: 'page4', routeRef: ref5, }), @@ -411,34 +411,34 @@ describe('discovery', () => { it('should use the route aggregator but stop when encountering explicit path', () => { const info = routeInfoFromExtensions([ createTestExtension({ - id: 'page1', + name: 'page1', path: 'foo', routeRef: ref1, }), createTestExtension({ - id: 'page1Child', + name: 'page1Child', parent: 'page1', path: 'bar', }), createTestExtension({ - id: 'page2', + name: 'page2', parent: 'page1Child', routeRef: ref2, }), createTestExtension({ - id: 'page3', + name: 'page3', parent: 'page2', path: 'baz', routeRef: ref3, }), createTestExtension({ - id: 'page4', + name: 'page4', parent: 'page3', path: '/blop', routeRef: ref4, }), createTestExtension({ - id: 'page5', + name: 'page5', parent: 'page2', routeRef: ref5, }), @@ -500,34 +500,34 @@ describe('discovery', () => { it('should account for loose route paths', () => { const info = routeInfoFromExtensions([ createTestExtension({ - id: 'r', + name: 'r', path: 'r', }), createTestExtension({ - id: 'page1', + name: 'page1', parent: 'r', path: 'x', routeRef: ref1, }), createTestExtension({ - id: 'y', + name: 'y', path: 'y', parent: 'r', }), createTestExtension({ - id: 'page2', + name: 'page2', parent: 'y', path: '1', routeRef: ref2, }), createTestExtension({ - id: 'page3', + name: 'page3', parent: 'page2', path: 'a', routeRef: ref3, }), createTestExtension({ - id: 'page4', + name: 'page4', parent: 'page2', path: 'b', routeRef: ref4, diff --git a/packages/frontend-app-api/src/tree/createAppTree.test.ts b/packages/frontend-app-api/src/tree/createAppTree.test.ts index 667e3a6fc3..15c8ab4750 100644 --- a/packages/frontend-app-api/src/tree/createAppTree.test.ts +++ b/packages/frontend-app-api/src/tree/createAppTree.test.ts @@ -54,12 +54,11 @@ describe('createAppTree', () => { it('throws an error when a core extension is overridden', () => { const config = new MockConfigApi({}); const features = [ - createPlugin({ - id: 'plugin', + createExtensionOverrides({ extensions: [ createExtension({ - id: 'core', - attachTo: { id: 'core.routes', input: 'route' }, + name: 'core', + attachTo: { id: 'core/routes', input: 'route' }, inputs: {}, output: {}, factory: () => ({}), @@ -70,33 +69,7 @@ describe('createAppTree', () => { expect(() => createAppTree({ features, config, builtinExtensions: [] }), ).toThrow( - "It is forbidden to override the following extension(s): 'core', which is done by the following plugin(s): 'plugin'", - ); - }); - - it('throws an error when duplicated extensions are detected', () => { - const config = new MockConfigApi({}); - - const ExtensionA = createExtension({ ...extBase, id: 'A' }); - - const ExtensionB = createExtension({ ...extBase, id: 'B' }); - - const PluginA = createPlugin({ - id: 'A', - extensions: [ExtensionA, ExtensionA], - }); - - const PluginB = createPlugin({ - id: 'B', - extensions: [ExtensionA, ExtensionB, ExtensionB], - }); - - const features = [PluginA, PluginB]; - - expect(() => - createAppTree({ features, config, builtinExtensions: [] }), - ).toThrow( - "The following extensions are duplicated: The extension 'A' was provided 2 time(s) by the plugin 'A' and 1 time(s) by the plugin 'B', The extension 'B' was provided 2 time(s) by the plugin 'B'", + "It is forbidden to override the following extension(s): 'core', which is done by one or more extension overrides", ); }); @@ -106,13 +79,13 @@ describe('createAppTree', () => { features: [ createExtensionOverrides({ extensions: [ - createExtension({ ...extBase, id: 'a' }), - createExtension({ ...extBase, id: 'a' }), - createExtension({ ...extBase, id: 'b' }), + createExtension({ ...extBase, name: 'a' }), + createExtension({ ...extBase, name: 'a' }), + createExtension({ ...extBase, name: 'b' }), ], }), createExtensionOverrides({ - extensions: [createExtension({ ...extBase, id: 'b' })], + extensions: [createExtension({ ...extBase, name: 'b' })], }), ], config: new MockConfigApi({}), diff --git a/packages/frontend-app-api/src/tree/readAppExtensionsConfig.test.ts b/packages/frontend-app-api/src/tree/readAppExtensionsConfig.test.ts index d291df7384..504d5a6197 100644 --- a/packages/frontend-app-api/src/tree/readAppExtensionsConfig.test.ts +++ b/packages/frontend-app-api/src/tree/readAppExtensionsConfig.test.ts @@ -25,18 +25,18 @@ describe('readAppExtensionsConfig', () => { it('should disable extension with shorthand notation', () => { expect( readAppExtensionsConfig( - new ConfigReader({ app: { extensions: [{ 'core.router': false }] } }), + new ConfigReader({ app: { extensions: [{ 'core/router': false }] } }), ), ).toEqual([ { - id: 'core.router', + id: 'core/router', disabled: true, }, ]); expect( readAppExtensionsConfig( new ConfigReader({ - app: { extensions: [{ 'core.router': { disabled: true } }] }, + app: { extensions: [{ 'core/router': { disabled: true } }] }, }), ), ).toEqual([ @@ -44,7 +44,7 @@ describe('readAppExtensionsConfig', () => { at: undefined, config: undefined, disabled: true, - id: 'core.router', + id: 'core/router', }, ]); }); @@ -52,33 +52,33 @@ describe('readAppExtensionsConfig', () => { it('should enable extension with shorthand notation', () => { expect( readAppExtensionsConfig( - new ConfigReader({ app: { extensions: ['core.router'] } }), + new ConfigReader({ app: { extensions: ['core/router'] } }), ), ).toEqual([ { - id: 'core.router', + id: 'core/router', disabled: false, }, ]); expect( readAppExtensionsConfig( - new ConfigReader({ app: { extensions: [{ 'core.router': true }] } }), + new ConfigReader({ app: { extensions: [{ 'core/router': true }] } }), ), ).toEqual([ { - id: 'core.router', + id: 'core/router', disabled: false, }, ]); expect( readAppExtensionsConfig( new ConfigReader({ - app: { extensions: [{ 'core.router': { disabled: false } }] }, + app: { extensions: [{ 'core/router': { disabled: false } }] }, }), ), ).toEqual([ { - id: 'core.router', + id: 'core/router', disabled: false, }, ]); @@ -89,12 +89,12 @@ describe('readAppExtensionsConfig', () => { readAppExtensionsConfig( new ConfigReader({ app: { - extensions: [{ 'core.router': 'some-string' }], + extensions: [{ 'core/router': 'some-string' }], }, }), ), ).toThrow( - 'Invalid extension configuration at app.extensions[0][core.router], value must be a boolean or object', + 'Invalid extension configuration at app.extensions[0][core/router], value must be a boolean or object', ); }); @@ -156,8 +156,8 @@ describe('expandShorthandExtensionParameters', () => { }); it('supports string key', () => { - expect(run('core.router')).toEqual({ - id: 'core.router', + expect(run('core/router')).toEqual({ + id: 'core/router', disabled: false, }); expect(() => run('')).toThrowErrorMatchingInlineSnapshot( @@ -170,96 +170,96 @@ describe('expandShorthandExtensionParameters', () => { it('supports null value', () => { // this is the result of typing: - // - core.router: + // - core/router: // The missing value is interpreted as null by the yaml parser so we deal with that - expect(run({ 'core.router': null })).toEqual({ - id: 'core.router', + expect(run({ 'core/router': null })).toEqual({ + id: 'core/router', disabled: false, }); }); it('supports boolean value', () => { - expect(run({ 'core.router': true })).toEqual({ - id: 'core.router', + expect(run({ 'core/router': true })).toEqual({ + id: 'core/router', disabled: false, }); - expect(run({ 'core.router': false })).toEqual({ - id: 'core.router', + expect(run({ 'core/router': false })).toEqual({ + id: 'core/router', disabled: true, }); }); it('should not support string values', () => { expect(() => - run({ 'core.router': 'example-package#MyRouter' }), + run({ 'core/router': 'example-package#MyRouter' }), ).toThrowErrorMatchingInlineSnapshot( - `"Invalid extension configuration at app.extensions[1][core.router], value must be a boolean or object"`, + `"Invalid extension configuration at app.extensions[1][core/router], value must be a boolean or object"`, ); }); it('supports object id only in the key', () => { expect(() => - run({ 'core.router': { id: 'some.id' } }), + run({ 'core/router': { id: 'some.id' } }), ).toThrowErrorMatchingInlineSnapshot( - `"Invalid extension configuration at app.extensions[1][core.router].id, unknown parameter; expected one of 'attachTo', 'disabled', 'config'"`, + `"Invalid extension configuration at app.extensions[1][core/router].id, unknown parameter; expected one of 'attachTo', 'disabled', 'config'"`, ); }); it('supports object attachTo', () => { expect( run({ - 'core.router': { attachTo: { id: 'other.root', input: 'inputs' } }, + 'core/router': { attachTo: { id: 'other.root', input: 'inputs' } }, }), ).toEqual({ - id: 'core.router', + id: 'core/router', attachTo: { id: 'other.root', input: 'inputs' }, }); expect(() => run({ - 'core.router': { + 'core/router': { id: 'other-id', }, }), ).toThrowErrorMatchingInlineSnapshot( - `"Invalid extension configuration at app.extensions[1][core.router].id, unknown parameter; expected one of 'attachTo', 'disabled', 'config'"`, + `"Invalid extension configuration at app.extensions[1][core/router].id, unknown parameter; expected one of 'attachTo', 'disabled', 'config'"`, ); }); it('supports object disabled', () => { - expect(run({ 'core.router': { disabled: true } })).toEqual({ - id: 'core.router', + expect(run({ 'core/router': { disabled: true } })).toEqual({ + id: 'core/router', disabled: true, }); - expect(run({ 'core.router': { disabled: false } })).toEqual({ - id: 'core.router', + expect(run({ 'core/router': { disabled: false } })).toEqual({ + id: 'core/router', disabled: false, }); expect(() => - run({ 'core.router': { disabled: 0 } }), + run({ 'core/router': { disabled: 0 } }), ).toThrowErrorMatchingInlineSnapshot( - `"Invalid extension configuration at app.extensions[1][core.router].disabled, must be a boolean"`, + `"Invalid extension configuration at app.extensions[1][core/router].disabled, must be a boolean"`, ); }); it('supports object config', () => { expect( - run({ 'core.router': { config: { disableRedirects: true } } }), + run({ 'core/router': { config: { disableRedirects: true } } }), ).toEqual({ - id: 'core.router', + id: 'core/router', config: { disableRedirects: true }, }); expect(() => - run({ 'core.router': { config: 0 } }), + run({ 'core/router': { config: 0 } }), ).toThrowErrorMatchingInlineSnapshot( - `"Invalid extension configuration at app.extensions[1][core.router].config, must be an object"`, + `"Invalid extension configuration at app.extensions[1][core/router].config, must be an object"`, ); }); it('rejects unknown object keys', () => { expect(() => - run({ 'core.router': { foo: { settings: true } } }), + run({ 'core/router': { foo: { settings: true } } }), ).toThrowErrorMatchingInlineSnapshot( - `"Invalid extension configuration at app.extensions[1][core.router].foo, unknown parameter; expected one of 'attachTo', 'disabled', 'config'"`, + `"Invalid extension configuration at app.extensions[1][core/router].foo, unknown parameter; expected one of 'attachTo', 'disabled', 'config'"`, ); }); }); diff --git a/packages/frontend-app-api/src/tree/resolveAppNodeSpecs.test.ts b/packages/frontend-app-api/src/tree/resolveAppNodeSpecs.test.ts index 39eceaaf28..2e9f73d87b 100644 --- a/packages/frontend-app-api/src/tree/resolveAppNodeSpecs.test.ts +++ b/packages/frontend-app-api/src/tree/resolveAppNodeSpecs.test.ts @@ -18,6 +18,7 @@ import { createExtensionOverrides, createPlugin, Extension, + ExtensionDefinition, } from '@backstage/frontend-plugin-api'; import { resolveAppNodeSpecs } from './resolveAppNodeSpecs'; @@ -27,12 +28,26 @@ function makeExt( attachId: string = 'root', ) { return { + $$type: '@backstage/Extension', id, attachTo: { id: attachId, input: 'default' }, disabled: status === 'disabled', } as Extension; } +function makeExtDef( + name: string, + status: 'disabled' | 'enabled' = 'enabled', + attachId: string = 'root', +) { + return { + $$type: '@backstage/ExtensionDefinition', + name, + attachTo: { id: attachId, input: 'default' }, + disabled: status === 'disabled', + } as ExtensionDefinition; +} + describe('resolveAppNodeSpecs', () => { it('should not filter out disabled extension instances', () => { const a = makeExt('a', 'disabled'); @@ -78,9 +93,8 @@ describe('resolveAppNodeSpecs', () => { }); it('should override attachment points', () => { - const a = makeExt('a'); const b = makeExt('b'); - const pluginA = createPlugin({ id: 'test', extensions: [a] }); + const pluginA = createPlugin({ id: 'test', extensions: [makeExtDef('a')] }); expect( resolveAppNodeSpecs({ features: [pluginA], @@ -94,8 +108,8 @@ describe('resolveAppNodeSpecs', () => { }), ).toEqual([ { - id: 'a', - extension: a, + id: 'test/a', + extension: makeExt('test/a'), attachTo: { id: 'root', input: 'default' }, source: pluginA, disabled: false, @@ -110,31 +124,34 @@ describe('resolveAppNodeSpecs', () => { }); it('should fully override configuration and duplicate', () => { - const a = makeExt('a'); - const b = makeExt('b'); - const plugin = createPlugin({ id: 'test', extensions: [a, b] }); + const a = makeExt('test/a'); + const b = makeExt('test/b'); + const plugin = createPlugin({ + id: 'test', + extensions: [makeExtDef('a'), makeExtDef('b')], + }); expect( resolveAppNodeSpecs({ features: [plugin], builtinExtensions: [], parameters: [ { - id: 'a', + id: 'test/a', config: { foo: { bar: 1 } }, }, { - id: 'b', + id: 'test/b', config: { foo: { bar: 2 } }, }, { - id: 'b', + id: 'test/b', config: { foo: { qux: 3 } }, }, ], }), ).toEqual([ { - id: 'a', + id: 'test/a', extension: a, attachTo: { id: 'root', input: 'default' }, source: plugin, @@ -142,7 +159,7 @@ describe('resolveAppNodeSpecs', () => { disabled: false, }, { - id: 'b', + id: 'test/b', extension: b, attachTo: { id: 'root', input: 'default' }, source: plugin, @@ -187,11 +204,12 @@ describe('resolveAppNodeSpecs', () => { }); it('should apply extension overrides', () => { - const a = makeExt('a'); - const b = makeExt('b'); - const plugin = createPlugin({ id: 'test', extensions: [a, b] }); - const aOverride = makeExt('a', 'enabled', 'other'); - const bOverride = makeExt('b', 'disabled', 'other'); + const plugin = createPlugin({ + id: 'test', + extensions: [makeExtDef('a'), makeExtDef('b')], + }); + const aOverride = makeExt('test/a', 'enabled', 'other'); + const bOverride = makeExt('test/b', 'disabled', 'other'); const cOverride = makeExt('c'); expect( @@ -199,7 +217,11 @@ describe('resolveAppNodeSpecs', () => { features: [ plugin, createExtensionOverrides({ - extensions: [aOverride, bOverride, cOverride], + extensions: [ + makeExtDef('test/a', 'enabled', 'other'), + makeExtDef('test/b', 'disabled', 'other'), + makeExtDef('c'), + ], }), ], builtinExtensions: [], @@ -207,14 +229,14 @@ describe('resolveAppNodeSpecs', () => { }), ).toEqual([ { - id: 'a', + id: 'test/a', extension: aOverride, attachTo: { id: 'other', input: 'default' }, source: plugin, disabled: false, }, { - id: 'b', + id: 'test/b', extension: bOverride, attachTo: { id: 'other', input: 'default' }, source: plugin, @@ -231,39 +253,50 @@ describe('resolveAppNodeSpecs', () => { }); it('should use order from configuration when rather than overrides', () => { - const a = makeExt('a', 'disabled'); - const b = makeExt('b', 'disabled'); - const c = makeExt('c', 'disabled'); - const aOverride = makeExt('c', 'disabled'); - const bOverride = makeExt('b', 'disabled'); - const cOverride = makeExt('a', 'disabled'); - const result = resolveAppNodeSpecs({ features: [ - createPlugin({ id: 'test', extensions: [a, b, c] }), + createPlugin({ + id: 'test', + extensions: [ + makeExtDef('a', 'disabled'), + makeExtDef('b', 'disabled'), + makeExtDef('c', 'disabled'), + ], + }), createExtensionOverrides({ - extensions: [cOverride, bOverride, aOverride], + extensions: [ + makeExtDef('test/c', 'disabled'), + makeExtDef('test/b', 'disabled'), + makeExtDef('test/a', 'disabled'), + ], }), ], builtinExtensions: [], - parameters: ['b', 'c', 'a'].map(id => ({ id, disabled: false })), + parameters: ['test/b', 'test/c', 'test/a'].map(id => ({ + id, + disabled: false, + })), }); - expect(result.map(r => r.extension.id)).toEqual(['b', 'c', 'a']); + expect(result.map(r => r.extension.id)).toEqual([ + 'test/b', + 'test/c', + 'test/a', + ]); }); it('throws an error when a forbidden extension is overridden by a plugin', () => { expect(() => resolveAppNodeSpecs({ features: [ - createPlugin({ id: 'test', extensions: [makeExt('forbidden')] }), + createPlugin({ id: 'test', extensions: [makeExtDef('forbidden')] }), ], builtinExtensions: [], parameters: [], - forbidden: new Set(['forbidden']), + forbidden: new Set(['test/forbidden']), }), ).toThrow( - "It is forbidden to override the following extension(s): 'forbidden', which is done by the following plugin(s): 'test'", + "It is forbidden to override the following extension(s): 'test/forbidden', which is done by the following plugin(s): 'test'", ); }); @@ -271,7 +304,7 @@ describe('resolveAppNodeSpecs', () => { expect(() => resolveAppNodeSpecs({ features: [ - createExtensionOverrides({ extensions: [makeExt('forbidden')] }), + createExtensionOverrides({ extensions: [makeExtDef('forbidden')] }), ], builtinExtensions: [], parameters: [], diff --git a/packages/frontend-app-api/src/tree/resolveAppTree.test.ts b/packages/frontend-app-api/src/tree/resolveAppTree.test.ts index d84064b26a..4fca671554 100644 --- a/packages/frontend-app-api/src/tree/resolveAppTree.test.ts +++ b/packages/frontend-app-api/src/tree/resolveAppTree.test.ts @@ -16,15 +16,17 @@ import { createExtension } from '@backstage/frontend-plugin-api'; import { resolveAppTree } from './resolveAppTree'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { resolveExtensionDefinition } from '../../../frontend-plugin-api/src/wiring/resolveExtensionDefinition'; -const extBaseConfig = { - id: 'test', - attachTo: { id: 'nonexistent', input: 'nonexistent' }, - output: {}, - factory: () => ({}), -}; - -const extension = createExtension(extBaseConfig); +const extension = resolveExtensionDefinition( + createExtension({ + name: 'test', + attachTo: { id: 'nonexistent', input: 'nonexistent' }, + output: {}, + factory: () => ({}), + }), +); const baseSpec = { extension, diff --git a/packages/frontend-app-api/src/wiring/createApp.test.tsx b/packages/frontend-app-api/src/wiring/createApp.test.tsx index 232de74de4..184c6fb48a 100644 --- a/packages/frontend-app-api/src/wiring/createApp.test.tsx +++ b/packages/frontend-app-api/src/wiring/createApp.test.tsx @@ -36,7 +36,10 @@ describe('createApp', () => { configLoader: async () => new MockConfigApi({ app: { - extensions: [{ 'themes.light': false }, { 'themes.dark': false }], + extensions: [ + { 'theme:app/light': false }, + { 'theme:app/dark': false }, + ], }, }), features: [ @@ -68,7 +71,6 @@ describe('createApp', () => { id: duplicatedFeatureId, extensions: [ createPageExtension({ - id: 'test.page.first', defaultPath: '/', loader: async () =>
First Page
, }), @@ -78,7 +80,6 @@ describe('createApp', () => { id: duplicatedFeatureId, extensions: [ createPageExtension({ - id: 'test.page.last', defaultPath: '/', loader: async () =>
Last Page
, }), @@ -159,7 +160,6 @@ describe('createApp', () => { id: 'my-plugin', extensions: [ createPageExtension({ - id: 'plugin.my-plugin.page', defaultPath: '/', loader: async () => { const Component = () => { @@ -182,22 +182,22 @@ describe('createApp', () => { expect(String(tree.root)).toMatchInlineSnapshot(` " root [ - + children [ - + content [ - + routes [ - + ] - + ] nav [ - + ] - + ] - + ] components [ @@ -206,8 +206,8 @@ describe('createApp', () => { ] themes [ - - + + ] " `); diff --git a/packages/frontend-app-api/src/wiring/createApp.tsx b/packages/frontend-app-api/src/wiring/createApp.tsx index 4671ec239d..f58dfb3159 100644 --- a/packages/frontend-app-api/src/wiring/createApp.tsx +++ b/packages/frontend-app-api/src/wiring/createApp.tsx @@ -176,7 +176,7 @@ export function createExtensionTree(options: { ); }, getRootRoutes(): JSX.Element[] { - return this.getExtensionAttachments('core.routes', 'routes').map(node => { + return this.getExtensionAttachments('core/routes', 'routes').map(node => { const path = node.getData(coreExtensionData.routePath); const element = node.getData(coreExtensionData.reactElement); const routeRef = node.getData(coreExtensionData.routeRef); @@ -203,7 +203,7 @@ export function createExtensionTree(options: { ); }; - return this.getExtensionAttachments('core.nav', 'items') + return this.getExtensionAttachments('core/nav', 'items') .map((node, index) => { const target = node.getData(coreExtensionData.navTarget); if (!target) { diff --git a/packages/frontend-plugin-api/src/components/ExtensionBoundary.test.tsx b/packages/frontend-plugin-api/src/components/ExtensionBoundary.test.tsx index 49a9f95ed2..fbef6dab45 100644 --- a/packages/frontend-plugin-api/src/components/ExtensionBoundary.test.tsx +++ b/packages/frontend-plugin-api/src/components/ExtensionBoundary.test.tsx @@ -24,11 +24,10 @@ import { createRouteRef } from '../routing'; import { createExtensionTester } from '@backstage/frontend-test-utils'; const wrapInBoundaryExtension = (element: JSX.Element) => { - const id = 'plugin.extension'; const routeRef = createRouteRef(); return createExtension({ - id, - attachTo: { id: 'core.routes', input: 'routes' }, + name: 'test', + attachTo: { id: 'core/routes', input: 'routes' }, output: { element: coreExtensionData.reactElement, path: coreExtensionData.routePath, @@ -89,7 +88,7 @@ describe('ExtensionBoundary', () => { action, subject, context: { - extension: 'plugin.extension', + extension: 'test', routeRef: 'unknown', }, }), diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionOverrides.test.ts b/packages/frontend-plugin-api/src/wiring/createExtensionOverrides.test.ts index 90f878ceaa..772a214490 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtensionOverrides.test.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtensionOverrides.test.ts @@ -37,7 +37,21 @@ describe('createExtensionOverrides', () => { createExtensionOverrides({ extensions: [ createExtension({ - id: 'a', + name: 'a', + attachTo: { id: 'core', input: 'apis' }, + output: {}, + factory: () => ({}), + }), + createExtension({ + namespace: 'b', + attachTo: { id: 'core', input: 'apis' }, + output: {}, + factory: () => ({}), + }), + createExtension({ + kind: 'k', + namespace: 'c', + name: 'n', attachTo: { id: 'core', input: 'apis' }, output: {}, factory: () => ({}), @@ -54,12 +68,39 @@ describe('createExtensionOverrides', () => { "id": "core", "input": "apis", }, + "configSchema": undefined, "disabled": false, "factory": [Function], "id": "a", "inputs": {}, "output": {}, }, + { + "$$type": "@backstage/Extension", + "attachTo": { + "id": "core", + "input": "apis", + }, + "configSchema": undefined, + "disabled": false, + "factory": [Function], + "id": "b", + "inputs": {}, + "output": {}, + }, + { + "$$type": "@backstage/Extension", + "attachTo": { + "id": "core", + "input": "apis", + }, + "configSchema": undefined, + "disabled": false, + "factory": [Function], + "id": "k:c/n", + "inputs": {}, + "output": {}, + }, ], "featureFlags": [], "version": "v1", @@ -71,7 +112,7 @@ describe('createExtensionOverrides', () => { const overrides = createExtensionOverrides({ extensions: [ createExtension({ - id: 'a', + namespace: 'a', attachTo: { id: 'core', input: 'apis' }, output: {}, factory: () => ({}), From e56eb22c540d6a84185d67ef418df0c34884c679 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 22 Nov 2023 17:19:13 +0100 Subject: [PATCH 203/261] catalog: update extension names to use kebab-case Co-authored-by: Camila Belo Signed-off-by: Patrik Oldsberg --- plugins/catalog/src/alpha/apis.tsx | 1 + plugins/catalog/src/alpha/entityCards.tsx | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/plugins/catalog/src/alpha/apis.tsx b/plugins/catalog/src/alpha/apis.tsx index a887a33a04..21036d8c67 100644 --- a/plugins/catalog/src/alpha/apis.tsx +++ b/plugins/catalog/src/alpha/apis.tsx @@ -41,6 +41,7 @@ export const CatalogApi = createApiExtension({ }); export const StarredEntitiesApi = createApiExtension({ + name: 'starred-entities', factory: createApiFactory({ api: starredEntitiesApiRef, deps: { storageApi: storageApiRef }, diff --git a/plugins/catalog/src/alpha/entityCards.tsx b/plugins/catalog/src/alpha/entityCards.tsx index 6b458f282e..b6a804a576 100644 --- a/plugins/catalog/src/alpha/entityCards.tsx +++ b/plugins/catalog/src/alpha/entityCards.tsx @@ -44,7 +44,7 @@ export const EntityLabelsCard = createEntityCardExtension({ }); export const EntityDependsOnComponentsCard = createEntityCardExtension({ - name: 'dependsOnComponents', + name: 'depends-on-components', loader: async () => import('../components/DependsOnComponentsCard').then(m => ( @@ -52,7 +52,7 @@ export const EntityDependsOnComponentsCard = createEntityCardExtension({ }); export const EntityDependsOnResourcesCard = createEntityCardExtension({ - name: 'dependsOnResources', + name: 'depends-on-resources', loader: async () => import('../components/DependsOnResourcesCard').then(m => ( @@ -60,7 +60,7 @@ export const EntityDependsOnResourcesCard = createEntityCardExtension({ }); export const EntityHasComponentsCard = createEntityCardExtension({ - name: 'hasComponents', + name: 'has-components', loader: async () => import('../components/HasComponentsCard').then(m => ( @@ -68,7 +68,7 @@ export const EntityHasComponentsCard = createEntityCardExtension({ }); export const EntityHasResourcesCard = createEntityCardExtension({ - name: 'hasResources', + name: 'has-resources', loader: async () => import('../components/HasResourcesCard').then(m => ( @@ -76,7 +76,7 @@ export const EntityHasResourcesCard = createEntityCardExtension({ }); export const EntityHasSubcomponentsCard = createEntityCardExtension({ - name: 'hasSubcomponents', + name: 'has-subcomponents', loader: async () => import('../components/HasSubcomponentsCard').then(m => ( @@ -84,7 +84,7 @@ export const EntityHasSubcomponentsCard = createEntityCardExtension({ }); export const EntityHasSystemsCard = createEntityCardExtension({ - name: 'hasSystems', + name: 'has-systems', loader: async () => import('../components/HasSystemsCard').then(m => ( From a794f37a14b6334ab8b23856a9794d2979b74882 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 22 Nov 2023 19:12:53 +0100 Subject: [PATCH 204/261] API report updates for extension ID redesign Signed-off-by: Patrik Oldsberg --- packages/frontend-plugin-api/api-report.md | 91 +++++++++++++++------- packages/frontend-test-utils/api-report.md | 6 +- plugins/adr/api-report-alpha.md | 4 +- plugins/catalog-react/api-report-alpha.md | 12 +-- plugins/catalog/api-report-alpha.md | 7 +- plugins/explore/api-report-alpha.md | 4 +- plugins/graphiql/api-report-alpha.md | 15 ++-- plugins/search-react/api-report-alpha.md | 9 ++- plugins/search/api-report-alpha.md | 8 +- plugins/tech-radar/api-report-alpha.md | 7 +- plugins/tech-radar/src/alpha.tsx | 1 + plugins/techdocs/api-report-alpha.md | 4 +- 12 files changed, 108 insertions(+), 60 deletions(-) diff --git a/packages/frontend-plugin-api/api-report.md b/packages/frontend-plugin-api/api-report.md index e1ed76d82c..dcd2cbda4b 100644 --- a/packages/frontend-plugin-api/api-report.md +++ b/packages/frontend-plugin-api/api-report.md @@ -376,23 +376,18 @@ export type CoreProgressComponent = ComponentType>; export function createApiExtension< TConfig extends {}, TInputs extends AnyExtensionInputMap, ->( - options: ( - | { - api: AnyApiRef; - factory: (options: { - config: TConfig; - inputs: Expand>; - }) => AnyApiFactory; - } - | { - factory: AnyApiFactory; - } - ) & { - configSchema?: PortableSchema; - inputs?: TInputs; - }, -): Extension; +>(options: { + factory: + | AnyApiFactory + | ((options: { + config: TConfig; + inputs: Expand>; + }) => AnyApiFactory); + namespace?: string; + name?: string; + configSchema?: PortableSchema; + inputs?: TInputs; +}): ExtensionDefinition; export { createApiFactory }; @@ -430,7 +425,7 @@ export function createExtension< TConfig = never, >( options: CreateExtensionOptions, -): Extension; +): ExtensionDefinition; // @public (undocumented) export function createExtensionDataRef( @@ -477,10 +472,14 @@ export interface CreateExtensionOptions< inputs: Expand>; }): Expand>; // (undocumented) - id: string; - // (undocumented) inputs?: TInputs; // (undocumented) + kind?: string; + // (undocumented) + name?: string; + // (undocumented) + namespace?: string; + // (undocumented) output: TOutput; } @@ -516,11 +515,12 @@ export function createExternalRouteRef< // @public export function createNavItemExtension(options: { - id: string; + namespace?: string; + name?: string; routeRef: RouteRef; title: string; icon: IconComponent_2; -}): Extension<{ +}): ExtensionDefinition<{ title: string; }>; @@ -539,7 +539,8 @@ export function createPageExtension< configSchema: PortableSchema; } ) & { - id: string; + namespace?: string; + name?: string; attachTo?: { id: string; input: string; @@ -552,7 +553,7 @@ export function createPageExtension< inputs: Expand>; }) => Promise; }, -): Extension; +): ExtensionDefinition; // @public (undocumented) export function createPlugin< @@ -616,7 +617,9 @@ export function createSubRouteRef< }): MakeSubRouteRef, ParentParams>; // @public (undocumented) -export function createThemeExtension(theme: AppTheme): Extension; +export function createThemeExtension( + theme: AppTheme, +): ExtensionDefinition; export { DiscoveryApi }; @@ -703,6 +706,40 @@ export type ExtensionDataValues = { : never]?: TExtensionData[DataName]['T']; }; +// @public (undocumented) +export interface ExtensionDefinition { + // (undocumented) + $$type: '@backstage/ExtensionDefinition'; + // (undocumented) + attachTo: { + id: string; + input: string; + }; + // (undocumented) + configSchema?: PortableSchema; + // (undocumented) + disabled: boolean; + // (undocumented) + factory(options: { + node: AppNode; + config: TConfig; + inputs: Record< + string, + undefined | Record | Array> + >; + }): ExtensionDataValues; + // (undocumented) + inputs: AnyExtensionInputMap; + // (undocumented) + kind?: string; + // (undocumented) + name?: string; + // (undocumented) + namespace?: string; + // (undocumented) + output: AnyExtensionDataMap; +} + // @public (undocumented) export interface ExtensionInput< TExtensionData extends AnyExtensionDataMap, @@ -743,7 +780,7 @@ export interface ExtensionOverrides { // @public (undocumented) export interface ExtensionOverridesOptions { // (undocumented) - extensions: Extension[]; + extensions: ExtensionDefinition[]; // (undocumented) featureFlags?: FeatureFlagConfig[]; } @@ -841,7 +878,7 @@ export interface PluginOptions< ExternalRoutes extends AnyExternalRoutes, > { // (undocumented) - extensions?: Extension[]; + extensions?: ExtensionDefinition[]; // (undocumented) externalRoutes?: ExternalRoutes; // (undocumented) diff --git a/packages/frontend-test-utils/api-report.md b/packages/frontend-test-utils/api-report.md index 59f5696ddc..14e1c68c4c 100644 --- a/packages/frontend-test-utils/api-report.md +++ b/packages/frontend-test-utils/api-report.md @@ -4,7 +4,7 @@ ```ts import { ErrorWithContext } from '@backstage/test-utils'; -import { Extension } from '@backstage/frontend-plugin-api'; +import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { JsonObject } from '@backstage/types'; import { MockAnalyticsApi } from '@backstage/test-utils'; import { MockConfigApi } from '@backstage/test-utils'; @@ -24,7 +24,7 @@ import { withLogCollector } from '@backstage/test-utils'; // @public (undocumented) export function createExtensionTester( - subject: Extension, + subject: ExtensionDefinition, options?: { config?: TConfig; }, @@ -36,7 +36,7 @@ export { ErrorWithContext }; export class ExtensionTester { // (undocumented) add( - extension: Extension, + extension: ExtensionDefinition, options?: { config?: TConfig; }, diff --git a/plugins/adr/api-report-alpha.md b/plugins/adr/api-report-alpha.md index 3864c85697..4c9ac1d17e 100644 --- a/plugins/adr/api-report-alpha.md +++ b/plugins/adr/api-report-alpha.md @@ -4,11 +4,11 @@ ```ts import { BackstagePlugin } from '@backstage/frontend-plugin-api'; -import { Extension } from '@backstage/frontend-plugin-api'; +import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { TranslationRef } from '@backstage/core-plugin-api/alpha'; // @alpha (undocumented) -export const AdrSearchResultListItemExtension: Extension<{ +export const AdrSearchResultListItemExtension: ExtensionDefinition<{ lineClamp: number; noTrack: boolean; }>; diff --git a/plugins/catalog-react/api-report-alpha.md b/plugins/catalog-react/api-report-alpha.md index 913055f8b0..1be108f695 100644 --- a/plugins/catalog-react/api-report-alpha.md +++ b/plugins/catalog-react/api-report-alpha.md @@ -8,7 +8,7 @@ import { AnyExtensionInputMap } from '@backstage/frontend-plugin-api'; import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; import { Entity } from '@backstage/catalog-model'; -import { Extension } from '@backstage/frontend-plugin-api'; +import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { ExtensionInputValues } from '@backstage/frontend-plugin-api'; import { ResourcePermission } from '@backstage/plugin-permission-common'; import { RouteRef } from '@backstage/frontend-plugin-api'; @@ -17,7 +17,8 @@ import { RouteRef } from '@backstage/frontend-plugin-api'; export function createEntityCardExtension< TInputs extends AnyExtensionInputMap, >(options: { - id: string; + namespace?: string; + name?: string; attachTo?: { id: string; input: string; @@ -30,7 +31,7 @@ export function createEntityCardExtension< loader: (options: { inputs: Expand>; }) => Promise; -}): Extension<{ +}): ExtensionDefinition<{ filter?: string | undefined; }>; @@ -38,7 +39,8 @@ export function createEntityCardExtension< export function createEntityContentExtension< TInputs extends AnyExtensionInputMap, >(options: { - id: string; + namespace?: string; + name?: string; attachTo?: { id: string; input: string; @@ -54,7 +56,7 @@ export function createEntityContentExtension< loader: (options: { inputs: Expand>; }) => Promise; -}): Extension<{ +}): ExtensionDefinition<{ title: string; path: string; filter?: string | undefined; diff --git a/plugins/catalog/api-report-alpha.md b/plugins/catalog/api-report-alpha.md index 52afb0894a..3226d10270 100644 --- a/plugins/catalog/api-report-alpha.md +++ b/plugins/catalog/api-report-alpha.md @@ -7,7 +7,7 @@ import { AnyExtensionInputMap } from '@backstage/frontend-plugin-api'; import { BackstagePlugin } from '@backstage/frontend-plugin-api'; -import { Extension } from '@backstage/frontend-plugin-api'; +import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { ExternalRouteRef } from '@backstage/frontend-plugin-api'; import { PortableSchema } from '@backstage/frontend-plugin-api'; import { RouteRef } from '@backstage/frontend-plugin-api'; @@ -17,11 +17,12 @@ export function createCatalogFilterExtension< TInputs extends AnyExtensionInputMap, TConfig = never, >(options: { - id: string; + namespace?: string; + name?: string; inputs?: TInputs; configSchema?: PortableSchema; loader: (options: { config: TConfig }) => Promise; -}): Extension; +}): ExtensionDefinition; // @alpha (undocumented) const _default: BackstagePlugin< diff --git a/plugins/explore/api-report-alpha.md b/plugins/explore/api-report-alpha.md index 8670338f3e..4d1afa89bf 100644 --- a/plugins/explore/api-report-alpha.md +++ b/plugins/explore/api-report-alpha.md @@ -4,14 +4,14 @@ ```ts import { BackstagePlugin } from '@backstage/frontend-plugin-api'; -import { Extension } from '@backstage/frontend-plugin-api'; +import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; // @alpha (undocumented) const _default: BackstagePlugin<{}, {}>; export default _default; // @alpha (undocumented) -export const ExploreSearchResultListItemExtension: Extension<{ +export const ExploreSearchResultListItemExtension: ExtensionDefinition<{ noTrack?: boolean | undefined; }>; diff --git a/plugins/graphiql/api-report-alpha.md b/plugins/graphiql/api-report-alpha.md index 3362cf0a59..c5895067df 100644 --- a/plugins/graphiql/api-report-alpha.md +++ b/plugins/graphiql/api-report-alpha.md @@ -4,20 +4,21 @@ ```ts import { BackstagePlugin } from '@backstage/frontend-plugin-api'; -import { Extension } from '@backstage/frontend-plugin-api'; +import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { GraphQLEndpoint } from '@backstage/plugin-graphiql'; import { PortableSchema } from '@backstage/frontend-plugin-api'; import { RouteRef } from '@backstage/frontend-plugin-api'; // @alpha (undocumented) -export function createEndpointExtension(options: { - id: string; +export function createGraphiQLEndpointExtension(options: { + namespace?: string; + name?: string; configSchema?: PortableSchema; disabled?: boolean; factory: (options: { config: TConfig }) => { endpoint: GraphQLEndpoint; }; -}): Extension; +}): ExtensionDefinition; // @alpha (undocumented) const _default: BackstagePlugin< @@ -29,15 +30,15 @@ const _default: BackstagePlugin< export default _default; // @alpha (undocumented) -export const graphiqlBrowseApi: Extension<{}>; +export const graphiqlBrowseApi: ExtensionDefinition<{}>; // @alpha (undocumented) -export const GraphiqlPage: Extension<{ +export const GraphiqlPage: ExtensionDefinition<{ path: string; }>; // @alpha (undocumented) -export const graphiqlPageSidebarItem: Extension<{ +export const graphiqlPageSidebarItem: ExtensionDefinition<{ title: string; }>; diff --git a/plugins/search-react/api-report-alpha.md b/plugins/search-react/api-report-alpha.md index 9c1248b536..285f1232c2 100644 --- a/plugins/search-react/api-report-alpha.md +++ b/plugins/search-react/api-report-alpha.md @@ -6,7 +6,7 @@ /// import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; -import { Extension } from '@backstage/frontend-plugin-api'; +import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { ListItemProps } from '@material-ui/core'; import { PortableSchema } from '@backstage/frontend-plugin-api'; import { SearchDocument } from '@backstage/plugin-search-common'; @@ -23,7 +23,9 @@ export function createSearchResultListItemExtension< TConfig extends { noTrack?: boolean; }, ->(options: SearchResultItemExtensionOptions): Extension; +>( + options: SearchResultItemExtensionOptions, +): ExtensionDefinition; // @alpha (undocumented) export type SearchResultItemExtensionComponent = < @@ -47,7 +49,8 @@ export type SearchResultItemExtensionOptions< noTrack?: boolean; }, > = { - id: string; + namespace?: string; + name?: string; attachTo?: { id: string; input: string; diff --git a/plugins/search/api-report-alpha.md b/plugins/search/api-report-alpha.md index 99f3d07b57..533734f8e9 100644 --- a/plugins/search/api-report-alpha.md +++ b/plugins/search/api-report-alpha.md @@ -4,7 +4,7 @@ ```ts import { BackstagePlugin } from '@backstage/frontend-plugin-api'; -import { Extension } from '@backstage/frontend-plugin-api'; +import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { RouteRef } from '@backstage/frontend-plugin-api'; // @alpha (undocumented) @@ -17,15 +17,15 @@ const _default: BackstagePlugin< export default _default; // @alpha (undocumented) -export const SearchApi: Extension<{}>; +export const SearchApi: ExtensionDefinition<{}>; // @alpha (undocumented) -export const SearchNavItem: Extension<{ +export const SearchNavItem: ExtensionDefinition<{ title: string; }>; // @alpha (undocumented) -export const SearchPage: Extension<{ +export const SearchPage: ExtensionDefinition<{ path: string; noTrack: boolean; }>; diff --git a/plugins/tech-radar/api-report-alpha.md b/plugins/tech-radar/api-report-alpha.md index da8f12cf0e..bcc9142223 100644 --- a/plugins/tech-radar/api-report-alpha.md +++ b/plugins/tech-radar/api-report-alpha.md @@ -4,7 +4,7 @@ ```ts import { BackstagePlugin } from '@backstage/frontend-plugin-api'; -import { Extension } from '@backstage/frontend-plugin-api'; +import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { RouteRef } from '@backstage/frontend-plugin-api'; // @alpha (undocumented) @@ -17,7 +17,10 @@ const _default: BackstagePlugin< export default _default; // @alpha (undocumented) -export const TechRadarPage: Extension<{ +export const sampleTechRadarApi: ExtensionDefinition<{}>; + +// @alpha (undocumented) +export const TechRadarPage: ExtensionDefinition<{ height: number; width: number; title: string; diff --git a/plugins/tech-radar/src/alpha.tsx b/plugins/tech-radar/src/alpha.tsx index 295d084a9a..9920c767cd 100644 --- a/plugins/tech-radar/src/alpha.tsx +++ b/plugins/tech-radar/src/alpha.tsx @@ -47,6 +47,7 @@ export const TechRadarPage = createPageExtension({ import('./components').then(m => ), }); +/** @alpha */ export const sampleTechRadarApi = createApiExtension({ factory() { return createApiFactory(techRadarApiRef, new SampleTechRadarApi()); diff --git a/plugins/techdocs/api-report-alpha.md b/plugins/techdocs/api-report-alpha.md index 2b63d6e691..afc3202a43 100644 --- a/plugins/techdocs/api-report-alpha.md +++ b/plugins/techdocs/api-report-alpha.md @@ -4,7 +4,7 @@ ```ts import { BackstagePlugin } from '@backstage/frontend-plugin-api'; -import { Extension } from '@backstage/frontend-plugin-api'; +import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { RouteRef } from '@backstage/frontend-plugin-api'; // @alpha (undocumented) @@ -23,7 +23,7 @@ const _default: BackstagePlugin< export default _default; // @alpha (undocumented) -export const TechDocsSearchResultListItemExtension: Extension<{ +export const TechDocsSearchResultListItemExtension: ExtensionDefinition<{ lineClamp: number; noTrack: boolean; asListItem: boolean; From 8837a961c33dcc6f835a10b6c548499aff5fa9f8 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 22 Nov 2023 19:21:01 +0100 Subject: [PATCH 205/261] changesets: added changesets for frontend-*-api for extension ID changes Signed-off-by: Patrik Oldsberg --- .changeset/stale-frogs-agree.md | 5 +++++ .changeset/ten-snakes-wait.md | 7 +++++++ 2 files changed, 12 insertions(+) create mode 100644 .changeset/stale-frogs-agree.md create mode 100644 .changeset/ten-snakes-wait.md diff --git a/.changeset/stale-frogs-agree.md b/.changeset/stale-frogs-agree.md new file mode 100644 index 0000000000..84052bded8 --- /dev/null +++ b/.changeset/stale-frogs-agree.md @@ -0,0 +1,5 @@ +--- +'@backstage/frontend-app-api': patch +--- + +Updates to match the introduction of `ExtensionDefinition` and new extension ID naming patterns. diff --git a/.changeset/ten-snakes-wait.md b/.changeset/ten-snakes-wait.md new file mode 100644 index 0000000000..1c15cb8d33 --- /dev/null +++ b/.changeset/ten-snakes-wait.md @@ -0,0 +1,7 @@ +--- +'@backstage/frontend-plugin-api': minor +--- + +**BREAKING**: This version changes how extensions are created and how their IDs are determined. The `createExtension` function now accepts `kind`, `namespace` and `name` instead of `id`. All of the new options are optional, and are used to construct the final extension ID. By convention extension creators should set the `kind` to match their own name, for example `createNavItemExtension` sets the kind `nav-item`. + +The `createExtension` function as well as all extension creators now also return an `ExtensionDefinition` rather than an `Extension`, which in turn needs to be passed to `createPlugin` or `createExtensionOverrides` to be used. From dd05355e4173e302e2cc6d92e2ff0622e8ee3e37 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 23 Nov 2023 15:53:10 +0100 Subject: [PATCH 206/261] frontend-plugin-api: extension ID updates for nav-logo and sign-in-page Signed-off-by: Patrik Oldsberg --- packages/frontend-plugin-api/api-report.md | 5 +++-- .../extensions/createNavLogoExtension.test.tsx | 9 +++++---- .../src/extensions/createNavLogoExtension.tsx | 11 +++++++---- .../extensions/createSignInPageExtension.test.tsx | 4 ++-- .../src/extensions/createSignInPageExtension.tsx | 15 ++++++++------- 5 files changed, 25 insertions(+), 19 deletions(-) diff --git a/packages/frontend-plugin-api/api-report.md b/packages/frontend-plugin-api/api-report.md index dcd2cbda4b..d3c02bfc1e 100644 --- a/packages/frontend-plugin-api/api-report.md +++ b/packages/frontend-plugin-api/api-report.md @@ -593,7 +593,8 @@ export function createSignInPageExtension< TConfig extends {}, TInputs extends AnyExtensionInputMap, >(options: { - id: string; + namespace?: string; + name?: string; attachTo?: { id: string; input: string; @@ -605,7 +606,7 @@ export function createSignInPageExtension< config: TConfig; inputs: Expand>; }) => Promise>; -}): Extension; +}): ExtensionDefinition; // @public export function createSubRouteRef< diff --git a/packages/frontend-plugin-api/src/extensions/createNavLogoExtension.test.tsx b/packages/frontend-plugin-api/src/extensions/createNavLogoExtension.test.tsx index 93efadb0e1..ca95fad7bc 100644 --- a/packages/frontend-plugin-api/src/extensions/createNavLogoExtension.test.tsx +++ b/packages/frontend-plugin-api/src/extensions/createNavLogoExtension.test.tsx @@ -25,14 +25,15 @@ describe('createNavLogoExtension', () => { it('creates the extension properly', () => { expect( createNavLogoExtension({ - id: 'test', + name: 'test', logoFull:
Logo Full
, logoIcon:
Logo Icon
, }), ).toEqual({ - $$type: '@backstage/Extension', - id: 'test', - attachTo: { id: 'core.nav', input: 'logos' }, + $$type: '@backstage/ExtensionDefinition', + kind: 'nav-logo', + name: 'test', + attachTo: { id: 'core/nav', input: 'logos' }, disabled: false, inputs: {}, output: { diff --git a/packages/frontend-plugin-api/src/extensions/createNavLogoExtension.tsx b/packages/frontend-plugin-api/src/extensions/createNavLogoExtension.tsx index 5cfff81a9d..878764bad7 100644 --- a/packages/frontend-plugin-api/src/extensions/createNavLogoExtension.tsx +++ b/packages/frontend-plugin-api/src/extensions/createNavLogoExtension.tsx @@ -21,14 +21,17 @@ import { coreExtensionData, createExtension } from '../wiring'; * @public */ export function createNavLogoExtension(options: { - id: string; + name?: string; + namespace?: string; logoIcon: JSX.Element; logoFull: JSX.Element; }) { - const { id, logoIcon, logoFull } = options; + const { logoIcon, logoFull } = options; return createExtension({ - id, - attachTo: { id: 'core.nav', input: 'logos' }, + kind: 'nav-logo', + name: options?.name, + namespace: options?.namespace, + attachTo: { id: 'core/nav', input: 'logos' }, output: { logos: coreExtensionData.logoElements, }, diff --git a/packages/frontend-plugin-api/src/extensions/createSignInPageExtension.test.tsx b/packages/frontend-plugin-api/src/extensions/createSignInPageExtension.test.tsx index 964941e213..d8835ae788 100644 --- a/packages/frontend-plugin-api/src/extensions/createSignInPageExtension.test.tsx +++ b/packages/frontend-plugin-api/src/extensions/createSignInPageExtension.test.tsx @@ -23,13 +23,13 @@ import { coreExtensionData, createExtension } from '../wiring'; describe('createSignInPageExtension', () => { it('renders a sign-in page', async () => { const SignInPage = createSignInPageExtension({ - id: 'test', + name: 'test', loader: async () => () =>
, }); createExtensionTester( createExtension({ - id: 'dummy', + name: 'dummy', attachTo: { id: 'ignored', input: 'ignored' }, output: { element: coreExtensionData.reactElement, diff --git a/packages/frontend-plugin-api/src/extensions/createSignInPageExtension.tsx b/packages/frontend-plugin-api/src/extensions/createSignInPageExtension.tsx index f869ed8f13..8709403407 100644 --- a/packages/frontend-plugin-api/src/extensions/createSignInPageExtension.tsx +++ b/packages/frontend-plugin-api/src/extensions/createSignInPageExtension.tsx @@ -19,10 +19,10 @@ import { ExtensionBoundary } from '../components'; import { PortableSchema } from '../schema'; import { createExtension, - Extension, ExtensionInputValues, AnyExtensionInputMap, createExtensionDataRef, + ExtensionDefinition, } from '../wiring'; import { Expand } from '../types'; import { SignInPageProps } from '@backstage/core-plugin-api'; @@ -39,7 +39,8 @@ export function createSignInPageExtension< TConfig extends {}, TInputs extends AnyExtensionInputMap, >(options: { - id: string; + namespace?: string; + name?: string; attachTo?: { id: string; input: string }; configSchema?: PortableSchema; disabled?: boolean; @@ -48,12 +49,12 @@ export function createSignInPageExtension< config: TConfig; inputs: Expand>; }) => Promise>; -}): Extension { - const { id } = options; - +}): ExtensionDefinition { return createExtension({ - id, - attachTo: options.attachTo ?? { id: 'core.router', input: 'signInPage' }, + kind: 'sign-in-page', + namespace: options?.namespace, + name: options?.name, + attachTo: options.attachTo ?? { id: 'core/router', input: 'signInPage' }, configSchema: options.configSchema, inputs: options.inputs, disabled: options.disabled, From eb733f78a864bfaaedbe3cb8404adeac12ff97f4 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 23 Nov 2023 19:47:30 +0100 Subject: [PATCH 207/261] app-next: update signInPage declaration to use name Signed-off-by: Patrik Oldsberg --- packages/app-next/src/App.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/app-next/src/App.tsx b/packages/app-next/src/App.tsx index 22b04c3a3f..b0a73c8358 100644 --- a/packages/app-next/src/App.tsx +++ b/packages/app-next/src/App.tsx @@ -95,7 +95,7 @@ const homePageExtension = createExtension({ }); const signInPage = createSignInPageExtension({ - id: 'signInPage', + name: 'guest', loader: async () => (props: SignInPageProps) => , }); From c1d5dfbe135a5e819bb369f4f2165bbf9b3be816 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Sat, 25 Nov 2023 17:15:34 +0100 Subject: [PATCH 208/261] frontend-app-api: update createApp feature flag tests for extension ID refactor Signed-off-by: Patrik Oldsberg --- packages/frontend-app-api/src/wiring/createApp.test.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/frontend-app-api/src/wiring/createApp.test.tsx b/packages/frontend-app-api/src/wiring/createApp.test.tsx index 184c6fb48a..348b56b5fd 100644 --- a/packages/frontend-app-api/src/wiring/createApp.test.tsx +++ b/packages/frontend-app-api/src/wiring/createApp.test.tsx @@ -107,7 +107,7 @@ describe('createApp', () => { featureFlags: [{ name: 'test-1' }], extensions: [ createExtension({ - id: 'test.page.first', + name: 'first', attachTo: { id: 'core', input: 'root' }, output: { element: coreExtensionData.reactElement }, factory() { @@ -132,7 +132,8 @@ describe('createApp', () => { featureFlags: [{ name: 'test-2' }], extensions: [ createExtension({ - id: 'core.router', + namespace: 'core', + name: 'router', attachTo: { id: 'core', input: 'root' }, disabled: true, output: {}, From 1b241c3901c692bc9d2afd785340e78a64332050 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Fri, 24 Nov 2023 14:26:01 +0100 Subject: [PATCH 209/261] frontend-plugin-api: use api ref ID as namespace + allow namespace override for plugins Signed-off-by: Patrik Oldsberg --- packages/app-next/src/App.tsx | 2 - .../src/collectLegacyRoutes.test.tsx | 6 +- .../src/collectLegacyRoutes.tsx | 7 +- .../src/convertLegacyApp.test.tsx | 6 +- packages/frontend-plugin-api/api-report.md | 29 +++++---- .../src/extensions/createApiExtension.test.ts | 28 +------- .../src/extensions/createApiExtension.ts | 39 ++++++----- .../src/wiring/resolveExtensionDefinition.ts | 2 +- plugins/catalog/src/alpha/apis.tsx | 1 - plugins/graphiql/src/alpha.tsx | 2 +- plugins/tech-radar/src/alpha.tsx | 4 +- plugins/techdocs/src/alpha.tsx | 65 +++++++++---------- 12 files changed, 85 insertions(+), 106 deletions(-) diff --git a/packages/app-next/src/App.tsx b/packages/app-next/src/App.tsx index b0a73c8358..ccfeb61b58 100644 --- a/packages/app-next/src/App.tsx +++ b/packages/app-next/src/App.tsx @@ -101,12 +101,10 @@ const signInPage = createSignInPageExtension({ }); const scmAuthExtension = createApiExtension({ - name: 'scm-auth', factory: ScmAuth.createDefaultApiFactory(), }); const scmIntegrationApi = createApiExtension({ - name: 'scm-integration', factory: createApiFactory({ api: scmIntegrationsApiRef, deps: { configApi: configApiRef }, diff --git a/packages/core-compat-api/src/collectLegacyRoutes.test.tsx b/packages/core-compat-api/src/collectLegacyRoutes.test.tsx index 1238fbbcb4..3dd9f330cc 100644 --- a/packages/core-compat-api/src/collectLegacyRoutes.test.tsx +++ b/packages/core-compat-api/src/collectLegacyRoutes.test.tsx @@ -57,7 +57,7 @@ describe('collectLegacyRoutes', () => { defaultConfig: { path: 'score-board' }, }, { - id: 'api:score-card', + id: 'api:plugin.scoringdata.service', attachTo: { id: 'core', input: 'apis' }, disabled: false, }, @@ -73,7 +73,7 @@ describe('collectLegacyRoutes', () => { defaultConfig: { path: 'stackstorm' }, }, { - id: 'api:stackstorm', + id: 'api:plugin.stackstorm.service', attachTo: { id: 'core', input: 'apis' }, disabled: false, }, @@ -95,7 +95,7 @@ describe('collectLegacyRoutes', () => { defaultConfig: { path: 'puppetdb' }, }, { - id: 'api:puppetDb', + id: 'api:plugin.puppetdb.service', attachTo: { id: 'core', input: 'apis' }, disabled: false, }, diff --git a/packages/core-compat-api/src/collectLegacyRoutes.tsx b/packages/core-compat-api/src/collectLegacyRoutes.tsx index 764149948d..92bced29a2 100644 --- a/packages/core-compat-api/src/collectLegacyRoutes.tsx +++ b/packages/core-compat-api/src/collectLegacyRoutes.tsx @@ -130,11 +130,8 @@ export function collectLegacyRoutes( id: plugin.getId(), extensions: [ ...extensions, - ...Array.from(plugin.getApis()).map((factory, index) => - createApiExtension({ - factory, - name: index > 0 ? String(index + 1) : undefined, - }), + ...Array.from(plugin.getApis()).map(factory => + createApiExtension({ factory }), ), ], }), diff --git a/packages/core-compat-api/src/convertLegacyApp.test.tsx b/packages/core-compat-api/src/convertLegacyApp.test.tsx index eeb53ad998..4a5be57bc8 100644 --- a/packages/core-compat-api/src/convertLegacyApp.test.tsx +++ b/packages/core-compat-api/src/convertLegacyApp.test.tsx @@ -65,7 +65,7 @@ describe('convertLegacyApp', () => { defaultConfig: { path: 'score-board' }, }, { - id: 'api:score-card', + id: 'api:plugin.scoringdata.service', attachTo: { id: 'core', input: 'apis' }, disabled: false, }, @@ -81,7 +81,7 @@ describe('convertLegacyApp', () => { defaultConfig: { path: 'stackstorm' }, }, { - id: 'api:stackstorm', + id: 'api:plugin.stackstorm.service', attachTo: { id: 'core', input: 'apis' }, disabled: false, }, @@ -103,7 +103,7 @@ describe('convertLegacyApp', () => { defaultConfig: { path: 'puppetdb' }, }, { - id: 'api:puppetDb', + id: 'api:plugin.puppetdb.service', attachTo: { id: 'core', input: 'apis' }, disabled: false, }, diff --git a/packages/frontend-plugin-api/api-report.md b/packages/frontend-plugin-api/api-report.md index d3c02bfc1e..65c865b352 100644 --- a/packages/frontend-plugin-api/api-report.md +++ b/packages/frontend-plugin-api/api-report.md @@ -376,18 +376,23 @@ export type CoreProgressComponent = ComponentType>; export function createApiExtension< TConfig extends {}, TInputs extends AnyExtensionInputMap, ->(options: { - factory: - | AnyApiFactory - | ((options: { - config: TConfig; - inputs: Expand>; - }) => AnyApiFactory); - namespace?: string; - name?: string; - configSchema?: PortableSchema; - inputs?: TInputs; -}): ExtensionDefinition; +>( + options: ( + | { + api: AnyApiRef; + factory: (options: { + config: TConfig; + inputs: Expand>; + }) => AnyApiFactory; + } + | { + factory: AnyApiFactory; + } + ) & { + configSchema?: PortableSchema; + inputs?: TInputs; + }, +): ExtensionDefinition; export { createApiFactory }; diff --git a/packages/frontend-plugin-api/src/extensions/createApiExtension.test.ts b/packages/frontend-plugin-api/src/extensions/createApiExtension.test.ts index b2f84f05aa..2585b0d694 100644 --- a/packages/frontend-plugin-api/src/extensions/createApiExtension.test.ts +++ b/packages/frontend-plugin-api/src/extensions/createApiExtension.test.ts @@ -33,31 +33,7 @@ describe('createApiExtension', () => { ).toEqual({ $$type: '@backstage/ExtensionDefinition', kind: 'api', - attachTo: { id: 'core', input: 'apis' }, - disabled: false, - configSchema: undefined, - inputs: {}, - output: { - api: expect.objectContaining({ - $$type: '@backstage/ExtensionDataRef', - id: 'core.api.factory', - config: {}, - }), - }, - factory: expect.any(Function), - }); - - expect( - createApiExtension({ - factory, - namespace: 'ns', - name: 'n', - }), - ).toEqual({ - $$type: '@backstage/ExtensionDefinition', - kind: 'api', - namespace: 'ns', - name: 'n', + namespace: 'test', attachTo: { id: 'core', input: 'apis' }, disabled: false, configSchema: undefined, @@ -78,6 +54,7 @@ describe('createApiExtension', () => { const factory = jest.fn(() => ({ foo: 'bar' })); const extension = createApiExtension({ + api, inputs: {}, factory({ config: _config, inputs: _inputs }) { return createApiFactory({ @@ -91,6 +68,7 @@ describe('createApiExtension', () => { expect(extension).toEqual({ $$type: '@backstage/ExtensionDefinition', kind: 'api', + namespace: 'test', attachTo: { id: 'core', input: 'apis' }, disabled: false, configSchema: undefined, diff --git a/packages/frontend-plugin-api/src/extensions/createApiExtension.ts b/packages/frontend-plugin-api/src/extensions/createApiExtension.ts index fb9acf0076..0f4f721530 100644 --- a/packages/frontend-plugin-api/src/extensions/createApiExtension.ts +++ b/packages/frontend-plugin-api/src/extensions/createApiExtension.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { AnyApiFactory } from '@backstage/core-plugin-api'; +import { AnyApiFactory, AnyApiRef } from '@backstage/core-plugin-api'; import { PortableSchema } from '../schema'; import { ExtensionInputValues, @@ -28,24 +28,33 @@ import { Expand } from '../types'; export function createApiExtension< TConfig extends {}, TInputs extends AnyExtensionInputMap, ->(options: { - factory: - | AnyApiFactory - | ((options: { - config: TConfig; - inputs: Expand>; - }) => AnyApiFactory); - namespace?: string; - name?: string; - configSchema?: PortableSchema; - inputs?: TInputs; -}) { +>( + options: ( + | { + api: AnyApiRef; + factory: (options: { + config: TConfig; + inputs: Expand>; + }) => AnyApiFactory; + } + | { + factory: AnyApiFactory; + } + ) & { + configSchema?: PortableSchema; + inputs?: TInputs; + }, +) { const { factory, configSchema, inputs: extensionInputs } = options; + const apiRef = + 'api' in options ? options.api : (factory as { api: AnyApiRef }).api; + return createExtension({ kind: 'api', - namespace: options.namespace, - name: options.name, + // Since ApiRef IDs use a global namespace we use the namespace here in order to override + // potential plugin IDs and always end up with the format `api:` + namespace: apiRef.id, attachTo: { id: 'core', input: 'apis' }, inputs: extensionInputs, configSchema, diff --git a/packages/frontend-plugin-api/src/wiring/resolveExtensionDefinition.ts b/packages/frontend-plugin-api/src/wiring/resolveExtensionDefinition.ts index 3d7acb33bd..42f3a75246 100644 --- a/packages/frontend-plugin-api/src/wiring/resolveExtensionDefinition.ts +++ b/packages/frontend-plugin-api/src/wiring/resolveExtensionDefinition.ts @@ -22,7 +22,7 @@ export function resolveExtensionDefinition( context?: { namespace?: string }, ): Extension { const { name, kind, namespace: _, ...rest } = definition; - const namespace = context?.namespace ?? definition.namespace; + const namespace = definition.namespace ?? context?.namespace; const namePart = name && namespace ? `${namespace}/${name}` : namespace || name; diff --git a/plugins/catalog/src/alpha/apis.tsx b/plugins/catalog/src/alpha/apis.tsx index 21036d8c67..a887a33a04 100644 --- a/plugins/catalog/src/alpha/apis.tsx +++ b/plugins/catalog/src/alpha/apis.tsx @@ -41,7 +41,6 @@ export const CatalogApi = createApiExtension({ }); export const StarredEntitiesApi = createApiExtension({ - name: 'starred-entities', factory: createApiFactory({ api: starredEntitiesApiRef, deps: { storageApi: storageApiRef }, diff --git a/plugins/graphiql/src/alpha.tsx b/plugins/graphiql/src/alpha.tsx index 29d6877a0a..d9470b7d46 100644 --- a/plugins/graphiql/src/alpha.tsx +++ b/plugins/graphiql/src/alpha.tsx @@ -57,7 +57,7 @@ const endpointDataRef = createExtensionDataRef( /** @alpha */ export const graphiqlBrowseApi = createApiExtension({ - name: 'browse', + api: graphQlBrowseApiRef, inputs: { endpoints: createExtensionInput({ endpoint: endpointDataRef, diff --git a/plugins/tech-radar/src/alpha.tsx b/plugins/tech-radar/src/alpha.tsx index 9920c767cd..2d15e92537 100644 --- a/plugins/tech-radar/src/alpha.tsx +++ b/plugins/tech-radar/src/alpha.tsx @@ -49,9 +49,7 @@ export const TechRadarPage = createPageExtension({ /** @alpha */ export const sampleTechRadarApi = createApiExtension({ - factory() { - return createApiFactory(techRadarApiRef, new SampleTechRadarApi()); - }, + factory: createApiFactory(techRadarApiRef, new SampleTechRadarApi()), }); /** @alpha */ diff --git a/plugins/techdocs/src/alpha.tsx b/plugins/techdocs/src/alpha.tsx index cad983df3c..82bda828e2 100644 --- a/plugins/techdocs/src/alpha.tsx +++ b/plugins/techdocs/src/alpha.tsx @@ -46,45 +46,40 @@ import { createEntityContentExtension } from '@backstage/plugin-catalog-react/al /** @alpha */ const techDocsStorage = createApiExtension({ - name: 'storage', - factory() { - return createApiFactory({ - api: techdocsStorageApiRef, - deps: { - configApi: configApiRef, - discoveryApi: discoveryApiRef, - identityApi: identityApiRef, - fetchApi: fetchApiRef, - }, - factory: ({ configApi, discoveryApi, identityApi, fetchApi }) => - new TechDocsStorageClient({ - configApi, - discoveryApi, - identityApi, - fetchApi, - }), - }); - }, + factory: createApiFactory({ + api: techdocsStorageApiRef, + deps: { + configApi: configApiRef, + discoveryApi: discoveryApiRef, + identityApi: identityApiRef, + fetchApi: fetchApiRef, + }, + factory: ({ configApi, discoveryApi, identityApi, fetchApi }) => + new TechDocsStorageClient({ + configApi, + discoveryApi, + identityApi, + fetchApi, + }), + }), }); /** @alpha */ const techDocsClient = createApiExtension({ - factory() { - return createApiFactory({ - api: techdocsApiRef, - deps: { - configApi: configApiRef, - discoveryApi: discoveryApiRef, - fetchApi: fetchApiRef, - }, - factory: ({ configApi, discoveryApi, fetchApi }) => - new TechDocsClient({ - configApi, - discoveryApi, - fetchApi, - }), - }); - }, + factory: createApiFactory({ + api: techdocsApiRef, + deps: { + configApi: configApiRef, + discoveryApi: discoveryApiRef, + fetchApi: fetchApiRef, + }, + factory: ({ configApi, discoveryApi, fetchApi }) => + new TechDocsClient({ + configApi, + discoveryApi, + fetchApi, + }), + }), }); /** @alpha */ From 79753d6fe629aee6733cd9c3f481c35615bce55a Mon Sep 17 00:00:00 2001 From: Andre Wanlin Date: Tue, 28 Nov 2023 09:52:38 -0600 Subject: [PATCH 210/261] Added Node 20 note to software template section Signed-off-by: Andre Wanlin --- docs/getting-started/configuration.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/getting-started/configuration.md b/docs/getting-started/configuration.md index 17f07811c0..b7bf7d448d 100644 --- a/docs/getting-started/configuration.md +++ b/docs/getting-started/configuration.md @@ -290,6 +290,11 @@ otherwise something went terribly wrong. ## Create a new component using a software template +> Note: if you're running Backstage with Node 20 or later, you'll need to pass the flag `--no-node-snapshot` to Node in order to +> use the templates feature. +> One way to do this is to specify the `NODE_OPTIONS` environment variable before starting Backstage: +> `export NODE_OPTIONS=--no-node-snapshot` + - Go to `create` and choose to create a website with the `Example Node.js Template` - Type in a name, let's use `tutorial` and click `Next Step` From a68ee8561f5d9a8f5ba9c1799d8d03ba4d8f51bf Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 28 Nov 2023 13:59:03 +0100 Subject: [PATCH 211/261] frontend-plugin-api: update createComponentExtension for new naming pattern Signed-off-by: Patrik Oldsberg --- packages/core-compat-api/api-report.md | 4 ++-- .../src/collectLegacyComponents.test.tsx | 15 ++++++++++----- .../src/collectLegacyComponents.tsx | 4 ++-- .../src/wiring/createApp.test.tsx | 8 ++++---- packages/frontend-plugin-api/api-report.md | 3 ++- .../src/extensions/createComponentExtension.tsx | 6 ++++-- 6 files changed, 24 insertions(+), 16 deletions(-) diff --git a/packages/core-compat-api/api-report.md b/packages/core-compat-api/api-report.md index 866517b5c8..93a2fa8cf1 100644 --- a/packages/core-compat-api/api-report.md +++ b/packages/core-compat-api/api-report.md @@ -8,7 +8,7 @@ import { AnyRouteRefParams } from '@backstage/core-plugin-api'; import { AppComponents } from '@backstage/core-plugin-api'; import { BackstagePlugin } from '@backstage/frontend-plugin-api'; -import { Extension } from '@backstage/frontend-plugin-api'; +import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { ExtensionOverrides } from '@backstage/frontend-plugin-api'; import { ExternalRouteRef } from '@backstage/core-plugin-api'; import { ExternalRouteRef as ExternalRouteRef_2 } from '@backstage/frontend-plugin-api'; @@ -21,7 +21,7 @@ import { SubRouteRef as SubRouteRef_2 } from '@backstage/frontend-plugin-api'; // @public (undocumented) export function collectLegacyComponents( components: Partial, -): Extension[]; +): ExtensionDefinition[]; // @public (undocumented) export function collectLegacyRoutes( diff --git a/packages/core-compat-api/src/collectLegacyComponents.test.tsx b/packages/core-compat-api/src/collectLegacyComponents.test.tsx index 0600f58cf8..7ca11a777e 100644 --- a/packages/core-compat-api/src/collectLegacyComponents.test.tsx +++ b/packages/core-compat-api/src/collectLegacyComponents.test.tsx @@ -31,28 +31,33 @@ describe('collectLegacyComponents', () => { expect( collected.map(p => ({ - id: p.id, + kind: p.kind, + namespace: p.namespace, attachTo: p.attachTo, disabled: p.disabled, })), ).toEqual([ { - id: 'core.components.progress', + kind: 'component', + namespace: 'core.components.progress', attachTo: { id: 'core', input: 'components' }, disabled: false, }, { - id: 'core.components.bootErrorPage', + kind: 'component', + namespace: 'core.components.bootErrorPage', attachTo: { id: 'core', input: 'components' }, disabled: false, }, { - id: 'core.components.notFoundErrorPage', + kind: 'component', + namespace: 'core.components.notFoundErrorPage', attachTo: { id: 'core', input: 'components' }, disabled: false, }, { - id: 'core.components.errorBoundaryFallback', + kind: 'component', + namespace: 'core.components.errorBoundaryFallback', attachTo: { id: 'core', input: 'components' }, disabled: false, }, diff --git a/packages/core-compat-api/src/collectLegacyComponents.tsx b/packages/core-compat-api/src/collectLegacyComponents.tsx index 6092ca1be7..6ae6df7cff 100644 --- a/packages/core-compat-api/src/collectLegacyComponents.tsx +++ b/packages/core-compat-api/src/collectLegacyComponents.tsx @@ -15,10 +15,10 @@ */ import { - Extension, ComponentRef, createComponentExtension, coreComponentsRefs, + ExtensionDefinition, } from '@backstage/frontend-plugin-api'; import { AppComponents } from '@backstage/core-plugin-api'; @@ -33,7 +33,7 @@ const refs: Record> = { /** @public */ export function collectLegacyComponents(components: Partial) { - return Object.entries(components).reduce[]>( + return Object.entries(components).reduce[]>( (extensions, [name, component]) => { const ref = refs[name]; return ref diff --git a/packages/frontend-app-api/src/wiring/createApp.test.tsx b/packages/frontend-app-api/src/wiring/createApp.test.tsx index 348b56b5fd..2713a9743e 100644 --- a/packages/frontend-app-api/src/wiring/createApp.test.tsx +++ b/packages/frontend-app-api/src/wiring/createApp.test.tsx @@ -201,10 +201,10 @@ describe('createApp', () => { ] components [ - - - - + + + + ] themes [ diff --git a/packages/frontend-plugin-api/api-report.md b/packages/frontend-plugin-api/api-report.md index 65c865b352..c491579eaf 100644 --- a/packages/frontend-plugin-api/api-report.md +++ b/packages/frontend-plugin-api/api-report.md @@ -405,6 +405,7 @@ export function createComponentExtension< TInputs extends AnyExtensionInputMap, >(options: { ref: TRef; + name?: string; disabled?: boolean; inputs?: TInputs; configSchema?: PortableSchema; @@ -421,7 +422,7 @@ export function createComponentExtension< inputs: Expand>; }) => TRef['T']; }; -}): Extension; +}): ExtensionDefinition; // @public (undocumented) export function createExtension< diff --git a/packages/frontend-plugin-api/src/extensions/createComponentExtension.tsx b/packages/frontend-plugin-api/src/extensions/createComponentExtension.tsx index a20faa0b3a..c9780574b6 100644 --- a/packages/frontend-plugin-api/src/extensions/createComponentExtension.tsx +++ b/packages/frontend-plugin-api/src/extensions/createComponentExtension.tsx @@ -32,6 +32,7 @@ export function createComponentExtension< TInputs extends AnyExtensionInputMap, >(options: { ref: TRef; + name?: string; disabled?: boolean; inputs?: TInputs; configSchema?: PortableSchema; @@ -49,9 +50,10 @@ export function createComponentExtension< }) => TRef['T']; }; }) { - const id = options.ref.id; return createExtension({ - id, + kind: 'component', + namespace: options.ref.id, + name: options.name, attachTo: { id: 'core', input: 'components' }, inputs: options.inputs, disabled: options.disabled, From 4fb69fdaf6fb91cf3b36b10925f8cf63a0a8da06 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 28 Nov 2023 13:59:49 +0100 Subject: [PATCH 212/261] frontend-plugin-api: update ExtensionBoundary test + switch to extensionId Signed-off-by: Patrik Oldsberg --- .../src/components/ExtensionBoundary.test.tsx | 15 +++++++++------ .../src/components/ExtensionBoundary.tsx | 2 +- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/packages/frontend-plugin-api/src/components/ExtensionBoundary.test.tsx b/packages/frontend-plugin-api/src/components/ExtensionBoundary.test.tsx index fbef6dab45..669335d577 100644 --- a/packages/frontend-plugin-api/src/components/ExtensionBoundary.test.tsx +++ b/packages/frontend-plugin-api/src/components/ExtensionBoundary.test.tsx @@ -83,15 +83,18 @@ describe('ExtensionBoundary', () => { ), ).render(); - await waitFor(() => - expect(analyticsApiMock.getEvents()[0]).toMatchObject({ + await waitFor(() => { + const event = analyticsApiMock + .getEvents() + .find(e => e.subject === subject); + + expect(event).toMatchObject({ action, subject, context: { - extension: 'test', - routeRef: 'unknown', + extensionId: 'test', }, - }), - ); + }); + }); }); }); diff --git a/packages/frontend-plugin-api/src/components/ExtensionBoundary.tsx b/packages/frontend-plugin-api/src/components/ExtensionBoundary.tsx index c9fa75c7fa..623c875837 100644 --- a/packages/frontend-plugin-api/src/components/ExtensionBoundary.tsx +++ b/packages/frontend-plugin-api/src/components/ExtensionBoundary.tsx @@ -59,7 +59,7 @@ export function ExtensionBoundary(props: ExtensionBoundaryProps) { // Skipping "routeRef" attribute in the new system, the extension "id" should provide more insight const attributes = { - extension: node.spec.id, + extensionId: node.spec.id, pluginId: node.spec.source?.id, }; From 6a18c333f36a6ce113bd3b183fb797d78e736385 Mon Sep 17 00:00:00 2001 From: David Festal Date: Tue, 28 Nov 2023 18:40:40 +0100 Subject: [PATCH 213/261] `BackendPluginManager` use default exports for dynamic plugins on the new backend system. This allows making a plugin dynamic without any source code change (which was previously required to add a dedicated entrypoint). Signed-off-by: David Festal --- .../src/loader/CommonJSModuleLoader.ts | 2 +- .../src/manager/plugin-manager.test.ts | 94 ++++++++++++++++++- .../src/manager/plugin-manager.ts | 39 +++++++- 3 files changed, 127 insertions(+), 8 deletions(-) diff --git a/packages/backend-plugin-manager/src/loader/CommonJSModuleLoader.ts b/packages/backend-plugin-manager/src/loader/CommonJSModuleLoader.ts index 06a08117cd..66af367cea 100644 --- a/packages/backend-plugin-manager/src/loader/CommonJSModuleLoader.ts +++ b/packages/backend-plugin-manager/src/loader/CommonJSModuleLoader.ts @@ -49,6 +49,6 @@ export class CommonJSModuleLoader implements ModuleLoader { } async load(packagePath: string): Promise { - return await import(/* webpackIgnore: true */ packagePath); + return await require(/* webpackIgnore: true */ packagePath); } } diff --git a/packages/backend-plugin-manager/src/manager/plugin-manager.test.ts b/packages/backend-plugin-manager/src/manager/plugin-manager.test.ts index 4aabd2c072..5b1e1caf4d 100644 --- a/packages/backend-plugin-manager/src/manager/plugin-manager.test.ts +++ b/packages/backend-plugin-manager/src/manager/plugin-manager.test.ts @@ -113,6 +113,94 @@ describe('backend-plugin-manager', () => { >([]); }, }, + { + name: 'should successfully load a new backend plugin by the default BackendFeature', + packageManifest: { + name: 'backend-dynamic-plugin-test', + version: '0.0.0', + backstage: { + role: 'backend-plugin', + }, + main: 'dist/index.cjs.js', + }, + indexFile: { + retativePath: ['dist', 'index.cjs.js'], + content: `const alpha = { $$type: '@backstage/BackendFeature' }; exports["default"] = alpha;`, + }, + expectedLogs(location) { + return { + infos: [ + { + message: `loaded dynamic backend plugin 'backend-dynamic-plugin-test' from '${location}'`, + }, + ], + }; + }, + checkLoadedPlugins(plugins) { + expect(plugins).toMatchObject([ + { + name: 'backend-dynamic-plugin-test', + version: '0.0.0', + role: 'backend-plugin', + platform: 'node', + installer: { + kind: 'new', + }, + }, + ]); + const installer: NewBackendPluginInstaller = ( + plugins[0] as BackendDynamicPlugin + ).installer as NewBackendPluginInstaller; + expect(installer.install()).toEqual< + BackendFeature | BackendFeature[] + >({ $$type: '@backstage/BackendFeature' }); + }, + }, + { + name: 'should successfully load a new backend plugin by the default BackendFeatureFactory', + packageManifest: { + name: 'backend-dynamic-plugin-test', + version: '0.0.0', + backstage: { + role: 'backend-plugin', + }, + main: 'dist/index.cjs.js', + }, + indexFile: { + retativePath: ['dist', 'index.cjs.js'], + content: `const alpha = () => { return { $$type: '@backstage/BackendFeature' } }; + alpha.$$type = '@backstage/BackendFeatureFactory'; + exports["default"] = alpha;`, + }, + expectedLogs(location) { + return { + infos: [ + { + message: `loaded dynamic backend plugin 'backend-dynamic-plugin-test' from '${location}'`, + }, + ], + }; + }, + checkLoadedPlugins(plugins) { + expect(plugins).toMatchObject([ + { + name: 'backend-dynamic-plugin-test', + version: '0.0.0', + role: 'backend-plugin', + platform: 'node', + installer: { + kind: 'new', + }, + }, + ]); + const installer: NewBackendPluginInstaller = ( + plugins[0] as BackendDynamicPlugin + ).installer as NewBackendPluginInstaller; + expect(installer.install()).toEqual< + BackendFeature | BackendFeature[] + >({ $$type: '@backstage/BackendFeature' }); + }, + }, { name: 'should successfully load a new backend plugin module', packageManifest: { @@ -221,7 +309,7 @@ describe('backend-plugin-manager', () => { return { errors: [ { - message: `dynamic backend plugin 'backend-dynamic-plugin-test' could not be loaded from '${location}': the module should export a 'const dynamicPluginInstaller: BackendDynamicPluginInstaller' field.`, + message: `dynamic backend plugin 'backend-dynamic-plugin-test' could not be loaded from '${location}': the module should either export a 'BackendFeature' or 'BackendFeatureFactory' as default export, or export a 'const dynamicPluginInstaller: BackendDynamicPluginInstaller' field as dynamic loading entrypoint.`, }, ], }; @@ -249,7 +337,7 @@ describe('backend-plugin-manager', () => { return { errors: [ { - message: `dynamic backend plugin 'backend-dynamic-plugin-test' could not be loaded from '${location}': the module should export a 'const dynamicPluginInstaller: BackendDynamicPluginInstaller' field.`, + message: `dynamic backend plugin 'backend-dynamic-plugin-test' could not be loaded from '${location}': the module should either export a 'BackendFeature' or 'BackendFeatureFactory' as default export, or export a 'const dynamicPluginInstaller: BackendDynamicPluginInstaller' field as dynamic loading entrypoint.`, }, ], }; @@ -378,7 +466,7 @@ describe('backend-plugin-manager', () => { logger, async bootstrap(_: string, __: string[]): Promise {}, load: async (packagePath: string) => - await import(/* webpackIgnore: true */ packagePath), + await require(/* webpackIgnore: true */ packagePath), }); const loadedPlugins: DynamicPlugin[] = await pluginManager.loadPlugins(); diff --git a/packages/backend-plugin-manager/src/manager/plugin-manager.ts b/packages/backend-plugin-manager/src/manager/plugin-manager.ts index ad76c7529e..5a5caa0a89 100644 --- a/packages/backend-plugin-manager/src/manager/plugin-manager.ts +++ b/packages/backend-plugin-manager/src/manager/plugin-manager.ts @@ -140,12 +140,25 @@ export class PluginManager implements BackendPluginProvider { `${plugin.location}/${plugin.manifest.main}`, ); try { - const { dynamicPluginInstaller } = await this.moduleLoader.load( - packagePath, - ); + const pluginModule = await this.moduleLoader.load(packagePath); + + let dynamicPluginInstaller; + if (isBackendFeature(pluginModule.default)) { + dynamicPluginInstaller = { + kind: 'new', + install: () => pluginModule.default, + }; + } else if (isBackendFeatureFactory(pluginModule.default)) { + dynamicPluginInstaller = { + kind: 'new', + install: pluginModule.default, + }; + } else { + dynamicPluginInstaller = pluginModule.dynamicPluginInstaller; + } if (!isBackendDynamicPluginInstaller(dynamicPluginInstaller)) { this.logger.error( - `dynamic backend plugin '${plugin.manifest.name}' could not be loaded from '${plugin.location}': the module should export a 'const dynamicPluginInstaller: BackendDynamicPluginInstaller' field.`, + `dynamic backend plugin '${plugin.manifest.name}' could not be loaded from '${plugin.location}': the module should either export a 'BackendFeature' or 'BackendFeatureFactory' as default export, or export a 'const dynamicPluginInstaller: BackendDynamicPluginInstaller' field as dynamic loading entrypoint.`, ); return undefined; } @@ -263,3 +276,21 @@ export const dynamicPluginsFeatureDiscoveryServiceFactory = return new DynamicPluginsEnabledFeatureDiscoveryService(dynamicPlugins); }, }); + +function isBackendFeature(value: unknown): value is BackendFeature { + return ( + !!value && + typeof value === 'object' && + (value as BackendFeature).$$type === '@backstage/BackendFeature' + ); +} + +function isBackendFeatureFactory( + value: unknown, +): value is () => BackendFeature { + return ( + !!value && + typeof value === 'function' && + (value as any).$$type === '@backstage/BackendFeatureFactory' + ); +} From 8f5d6c1fbf66124353e6fdc0618eb02dacfb73f0 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Sun, 26 Nov 2023 10:48:12 +0100 Subject: [PATCH 214/261] frontend-plugin-api: wrap resolved extension inputs in an object MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Camila Belo Co-authored-by: Vincenzo Scamporlino Co-authored-by: Fredrik Adelöw Co-authored-by: Philipp Hugenroth Signed-off-by: Patrik Oldsberg --- .changeset/orange-boats-hunt.md | 6 ++ .changeset/red-readers-search.md | 10 ++++ .changeset/tasty-dolphins-unite.md | 5 ++ .../core-compat-api/src/convertLegacyApp.ts | 6 +- .../frontend-app-api/src/extensions/Core.tsx | 2 +- .../src/extensions/CoreLayout.tsx | 4 +- .../src/extensions/CoreNav.tsx | 4 +- .../src/extensions/CoreRouter.tsx | 4 +- .../src/extensions/CoreRoutes.tsx | 4 +- .../src/tree/instantiateAppNodeTree.test.ts | 17 ++++-- .../src/tree/instantiateAppNodeTree.ts | 23 +++++--- packages/frontend-plugin-api/api-report.md | 59 ++++++++++--------- .../src/extensions/createApiExtension.ts | 4 +- .../extensions/createComponentExtension.tsx | 6 +- .../src/extensions/createPageExtension.tsx | 4 +- .../extensions/createSignInPageExtension.tsx | 4 +- .../src/wiring/createExtension.test.ts | 26 ++++---- .../src/wiring/createExtension.ts | 34 ++++++----- .../src/wiring/createPlugin.test.ts | 6 +- .../frontend-plugin-api/src/wiring/index.ts | 3 +- plugins/catalog-react/api-report-alpha.md | 6 +- plugins/catalog-react/src/alpha.tsx | 6 +- plugins/catalog/src/alpha/entityContents.tsx | 2 +- plugins/catalog/src/alpha/pages.tsx | 10 ++-- plugins/graphiql/src/alpha.tsx | 2 +- plugins/home/src/alpha.tsx | 4 +- plugins/search-react/src/alpha.test.tsx | 6 +- plugins/search/src/alpha.tsx | 6 +- plugins/user-settings/src/alpha.tsx | 4 +- 29 files changed, 166 insertions(+), 111 deletions(-) create mode 100644 .changeset/orange-boats-hunt.md create mode 100644 .changeset/red-readers-search.md create mode 100644 .changeset/tasty-dolphins-unite.md diff --git a/.changeset/orange-boats-hunt.md b/.changeset/orange-boats-hunt.md new file mode 100644 index 0000000000..1a3d9b1682 --- /dev/null +++ b/.changeset/orange-boats-hunt.md @@ -0,0 +1,6 @@ +--- +'@backstage/frontend-app-api': patch +'@backstage/core-compat-api': patch +--- + +Updates to match the new extension input wrapping. diff --git a/.changeset/red-readers-search.md b/.changeset/red-readers-search.md new file mode 100644 index 0000000000..c18d9672ba --- /dev/null +++ b/.changeset/red-readers-search.md @@ -0,0 +1,10 @@ +--- +'@backstage/plugin-catalog-react': patch +'@backstage/plugin-user-settings': patch +'@backstage/plugin-graphiql': patch +'@backstage/plugin-catalog': patch +'@backstage/plugin-search': patch +'@backstage/plugin-home': patch +--- + +Updates to the `/alpha` exports to match the extension input wrapping change. diff --git a/.changeset/tasty-dolphins-unite.md b/.changeset/tasty-dolphins-unite.md new file mode 100644 index 0000000000..b367b0c554 --- /dev/null +++ b/.changeset/tasty-dolphins-unite.md @@ -0,0 +1,5 @@ +--- +'@backstage/frontend-plugin-api': minor +--- + +Extension inputs are now wrapped into an additional object when passed to the extension factory, with the previous values being available at the `output` property. The `ExtensionInputValues` type has also been replaced by `ResolvedExtensionInputs`. diff --git a/packages/core-compat-api/src/convertLegacyApp.ts b/packages/core-compat-api/src/convertLegacyApp.ts index 3b12f0e1fd..9fe07cc783 100644 --- a/packages/core-compat-api/src/convertLegacyApp.ts +++ b/packages/core-compat-api/src/convertLegacyApp.ts @@ -117,7 +117,11 @@ export function convertLegacyApp( factory({ inputs }) { // Clone the root element, this replaces the FlatRoutes declared in the app with out content input return { - element: React.cloneElement(rootEl, undefined, inputs.content.element), + element: React.cloneElement( + rootEl, + undefined, + inputs.content.output.element, + ), }; }, }); diff --git a/packages/frontend-app-api/src/extensions/Core.tsx b/packages/frontend-app-api/src/extensions/Core.tsx index 472ed4905a..d4b3b65468 100644 --- a/packages/frontend-app-api/src/extensions/Core.tsx +++ b/packages/frontend-app-api/src/extensions/Core.tsx @@ -45,7 +45,7 @@ export const Core = createExtension({ }, factory({ inputs }) { return { - root: inputs.root.element, + root: inputs.root.output.element, }; }, }); diff --git a/packages/frontend-app-api/src/extensions/CoreLayout.tsx b/packages/frontend-app-api/src/extensions/CoreLayout.tsx index 94681120db..e4f86256f2 100644 --- a/packages/frontend-app-api/src/extensions/CoreLayout.tsx +++ b/packages/frontend-app-api/src/extensions/CoreLayout.tsx @@ -47,8 +47,8 @@ export const CoreLayout = createExtension({ return { element: ( - {inputs.nav.element} - {inputs.content.element} + {inputs.nav.output.element} + {inputs.content.output.element} ), }; diff --git a/packages/frontend-app-api/src/extensions/CoreNav.tsx b/packages/frontend-app-api/src/extensions/CoreNav.tsx index 21d113d3d6..ab9f29a15d 100644 --- a/packages/frontend-app-api/src/extensions/CoreNav.tsx +++ b/packages/frontend-app-api/src/extensions/CoreNav.tsx @@ -99,10 +99,10 @@ export const CoreNav = createExtension({ return { element: ( - + {inputs.items.map((item, index) => ( - + ))} ), diff --git a/packages/frontend-app-api/src/extensions/CoreRouter.tsx b/packages/frontend-app-api/src/extensions/CoreRouter.tsx index 088fd25ae7..4dc73c91af 100644 --- a/packages/frontend-app-api/src/extensions/CoreRouter.tsx +++ b/packages/frontend-app-api/src/extensions/CoreRouter.tsx @@ -59,8 +59,8 @@ export const CoreRouter = createExtension({ factory({ inputs }) { return { element: ( - - {inputs.children.element} + + {inputs.children.output.element} ), }; diff --git a/packages/frontend-app-api/src/extensions/CoreRoutes.tsx b/packages/frontend-app-api/src/extensions/CoreRoutes.tsx index d77839f7b3..1b79231699 100644 --- a/packages/frontend-app-api/src/extensions/CoreRoutes.tsx +++ b/packages/frontend-app-api/src/extensions/CoreRoutes.tsx @@ -48,8 +48,8 @@ export const CoreRoutes = createExtension({ const element = useRoutes([ ...inputs.routes.map(route => ({ - path: `${route.path}/*`, - element: route.element, + path: `${route.output.path}/*`, + element: route.output.element, })), { path: '*', diff --git a/packages/frontend-app-api/src/tree/instantiateAppNodeTree.test.ts b/packages/frontend-app-api/src/tree/instantiateAppNodeTree.test.ts index 7167038184..0be4f0a0c4 100644 --- a/packages/frontend-app-api/src/tree/instantiateAppNodeTree.test.ts +++ b/packages/frontend-app-api/src/tree/instantiateAppNodeTree.test.ts @@ -153,7 +153,7 @@ describe('instantiateAppNodeTree', () => { expect(tree.root.instance).toBeDefined(); expect(childNode?.instance).toBeDefined(); expect(tree.root.instance?.getData(inputMirrorDataRef)).toEqual({ - test: [{ test: 'test' }], + test: [{ extensionId: 'child-node', output: { test: 'test' } }], }); // Multiple calls should have no effect @@ -296,9 +296,18 @@ describe('createAppNodeInstance', () => { expect(Array.from(instance.getDataRefs())).toEqual([inputMirrorDataRef]); expect(instance.getData(inputMirrorDataRef)).toEqual({ - optionalSingletonPresent: { test: 'optionalSingletonPresent' }, - singleton: { test: 'singleton', other: 2 }, - many: [{ test: 'many1' }, { test: 'many2', other: 3 }], + optionalSingletonPresent: { + extensionId: 'core/test', + output: { test: 'optionalSingletonPresent' }, + }, + singleton: { + extensionId: 'core/test', + output: { test: 'singleton', other: 2 }, + }, + many: [ + { extensionId: 'core/test', output: { test: 'many1' } }, + { extensionId: 'core/test', output: { test: 'many2', other: 3 } }, + ], }); }); diff --git a/packages/frontend-app-api/src/tree/instantiateAppNodeTree.ts b/packages/frontend-app-api/src/tree/instantiateAppNodeTree.ts index 2b1ab04c25..ca51f10921 100644 --- a/packages/frontend-app-api/src/tree/instantiateAppNodeTree.ts +++ b/packages/frontend-app-api/src/tree/instantiateAppNodeTree.ts @@ -18,6 +18,7 @@ import { AnyExtensionDataMap, AnyExtensionInputMap, ExtensionDataRef, + ResolvedExtensionInputs, } from '@backstage/frontend-plugin-api'; import mapValues from 'lodash/mapValues'; import { AppNode, AppNodeInstance } from '@backstage/frontend-plugin-api'; @@ -45,7 +46,7 @@ function resolveInputData( function resolveInputs( inputMap: AnyExtensionInputMap, attachments: ReadonlyMap, -) { +): ResolvedExtensionInputs { const undeclaredAttachments = Array.from(attachments.entries()).filter( ([inputName]) => inputMap[inputName] === undefined, ); @@ -84,13 +85,21 @@ function resolveInputs( } throw Error(`input '${inputName}' is required but was not received`); } - return resolveInputData(input.extensionData, attachedNodes[0], inputName); + return { + extensionId: attachedNodes[0].id, + output: resolveInputData( + input.extensionData, + attachedNodes[0], + inputName, + ), + }; } - return attachedNodes.map(attachment => - resolveInputData(input.extensionData, attachment, inputName), - ); - }); + return attachedNodes.map(attachment => ({ + extensionId: attachment.id, + output: resolveInputData(input.extensionData, attachment, inputName), + })); + }) as ResolvedExtensionInputs; } /** @internal */ @@ -135,7 +144,7 @@ export function createAppNodeInstance(options: { } catch (e) { throw new Error( `Failed to instantiate extension '${id}'${ - e.name === 'Error' ? `, ${e.message}` : `; caused by ${e}` + e.name === 'Error' ? `, ${e.message}` : `; caused by ${e.stack}` }`, ); } diff --git a/packages/frontend-plugin-api/api-report.md b/packages/frontend-plugin-api/api-report.md index c491579eaf..e8f4f16e97 100644 --- a/packages/frontend-plugin-api/api-report.md +++ b/packages/frontend-plugin-api/api-report.md @@ -382,7 +382,7 @@ export function createApiExtension< api: AnyApiRef; factory: (options: { config: TConfig; - inputs: Expand>; + inputs: Expand>; }) => AnyApiFactory; } | { @@ -413,13 +413,13 @@ export function createComponentExtension< | { lazy: (values: { config: TConfig; - inputs: Expand>; + inputs: Expand>; }) => Promise; } | { sync: (values: { config: TConfig; - inputs: Expand>; + inputs: Expand>; }) => TRef['T']; }; }): ExtensionDefinition; @@ -475,7 +475,7 @@ export interface CreateExtensionOptions< factory(options: { node: AppNode; config: TConfig; - inputs: Expand>; + inputs: Expand>; }): Expand>; // (undocumented) inputs?: TInputs; @@ -556,7 +556,7 @@ export function createPageExtension< routeRef?: RouteRef; loader: (options: { config: TConfig; - inputs: Expand>; + inputs: Expand>; }) => Promise; }, ): ExtensionDefinition; @@ -610,7 +610,7 @@ export function createSignInPageExtension< inputs?: TInputs; loader: (options: { config: TConfig; - inputs: Expand>; + inputs: Expand>; }) => Promise>; }): ExtensionDefinition; @@ -657,10 +657,7 @@ export interface Extension { factory(options: { node: AppNode; config: TConfig; - inputs: Record< - string, - undefined | Record | Array> - >; + inputs: ResolvedExtensionInputs; }): ExtensionDataValues; // (undocumented) id: string; @@ -730,10 +727,7 @@ export interface ExtensionDefinition { factory(options: { node: AppNode; config: TConfig; - inputs: Record< - string, - undefined | Record | Array> - >; + inputs: ResolvedExtensionInputs; }): ExtensionDataValues; // (undocumented) inputs: AnyExtensionInputMap; @@ -763,21 +757,6 @@ export interface ExtensionInput< extensionData: TExtensionData; } -// @public -export type ExtensionInputValues< - TInputs extends { - [name in string]: ExtensionInput; - }, -> = { - [InputName in keyof TInputs]: false extends TInputs[InputName]['config']['singleton'] - ? Array>> - : false extends TInputs[InputName]['config']['optional'] - ? Expand> - : Expand< - ExtensionDataValues | undefined - >; -}; - // @public (undocumented) export interface ExtensionOverrides { // (undocumented) @@ -906,6 +885,28 @@ export { ProfileInfo }; export { ProfileInfoApi }; +// @public +export type ResolvedExtensionInput = + { + extensionId: string; + output: ExtensionDataValues; + }; + +// @public +export type ResolvedExtensionInputs< + TInputs extends { + [name in string]: ExtensionInput; + }, +> = { + [InputName in keyof TInputs]: false extends TInputs[InputName]['config']['singleton'] + ? Array>> + : false extends TInputs[InputName]['config']['optional'] + ? Expand> + : Expand< + ResolvedExtensionInput | undefined + >; +}; + // @public export type RouteFunc = ( ...[params]: TParams extends undefined diff --git a/packages/frontend-plugin-api/src/extensions/createApiExtension.ts b/packages/frontend-plugin-api/src/extensions/createApiExtension.ts index 0f4f721530..bbaef3c849 100644 --- a/packages/frontend-plugin-api/src/extensions/createApiExtension.ts +++ b/packages/frontend-plugin-api/src/extensions/createApiExtension.ts @@ -17,7 +17,7 @@ import { AnyApiFactory, AnyApiRef } from '@backstage/core-plugin-api'; import { PortableSchema } from '../schema'; import { - ExtensionInputValues, + ResolvedExtensionInputs, createExtension, coreExtensionData, } from '../wiring'; @@ -34,7 +34,7 @@ export function createApiExtension< api: AnyApiRef; factory: (options: { config: TConfig; - inputs: Expand>; + inputs: Expand>; }) => AnyApiFactory; } | { diff --git a/packages/frontend-plugin-api/src/extensions/createComponentExtension.tsx b/packages/frontend-plugin-api/src/extensions/createComponentExtension.tsx index c9780574b6..601ee81d11 100644 --- a/packages/frontend-plugin-api/src/extensions/createComponentExtension.tsx +++ b/packages/frontend-plugin-api/src/extensions/createComponentExtension.tsx @@ -17,7 +17,7 @@ import React, { lazy } from 'react'; import { AnyExtensionInputMap, - ExtensionInputValues, + ResolvedExtensionInputs, coreExtensionData, createExtension, } from '../wiring'; @@ -40,13 +40,13 @@ export function createComponentExtension< | { lazy: (values: { config: TConfig; - inputs: Expand>; + inputs: Expand>; }) => Promise; } | { sync: (values: { config: TConfig; - inputs: Expand>; + inputs: Expand>; }) => TRef['T']; }; }) { diff --git a/packages/frontend-plugin-api/src/extensions/createPageExtension.tsx b/packages/frontend-plugin-api/src/extensions/createPageExtension.tsx index 6796fe884d..3b936ef210 100644 --- a/packages/frontend-plugin-api/src/extensions/createPageExtension.tsx +++ b/packages/frontend-plugin-api/src/extensions/createPageExtension.tsx @@ -20,7 +20,7 @@ import { createSchemaFromZod, PortableSchema } from '../schema'; import { coreExtensionData, createExtension, - ExtensionInputValues, + ResolvedExtensionInputs, AnyExtensionInputMap, } from '../wiring'; import { RouteRef } from '../routing'; @@ -52,7 +52,7 @@ export function createPageExtension< routeRef?: RouteRef; loader: (options: { config: TConfig; - inputs: Expand>; + inputs: Expand>; }) => Promise; }, ): ExtensionDefinition { diff --git a/packages/frontend-plugin-api/src/extensions/createSignInPageExtension.tsx b/packages/frontend-plugin-api/src/extensions/createSignInPageExtension.tsx index 8709403407..d04c29fb9b 100644 --- a/packages/frontend-plugin-api/src/extensions/createSignInPageExtension.tsx +++ b/packages/frontend-plugin-api/src/extensions/createSignInPageExtension.tsx @@ -19,7 +19,7 @@ import { ExtensionBoundary } from '../components'; import { PortableSchema } from '../schema'; import { createExtension, - ExtensionInputValues, + ResolvedExtensionInputs, AnyExtensionInputMap, createExtensionDataRef, ExtensionDefinition, @@ -47,7 +47,7 @@ export function createSignInPageExtension< inputs?: TInputs; loader: (options: { config: TConfig; - inputs: Expand>; + inputs: Expand>; }) => Promise>; }): ExtensionDefinition { return createExtension({ diff --git a/packages/frontend-plugin-api/src/wiring/createExtension.test.ts b/packages/frontend-plugin-api/src/wiring/createExtension.test.ts index 07d52f5bb4..22db95082a 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtension.test.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtension.test.ts @@ -251,34 +251,34 @@ describe('createExtension', () => { foo: stringData, }, factory({ inputs }) { - const a1: string = inputs.mixed?.[0].required; + const a1: string = inputs.mixed?.[0].output.required; // @ts-expect-error - const a2: number = inputs.mixed?.[0].required; + const a2: number = inputs.mixed?.[0].output.required; // @ts-expect-error - const a3: any = inputs.mixed?.[0].nonExistent; + const a3: any = inputs.mixed?.[0].output.nonExistent; unused(a1, a2, a3); - const b1: string | undefined = inputs.mixed?.[0].optional; + const b1: string | undefined = inputs.mixed?.[0].output.optional; // @ts-expect-error - const b2: string = inputs.mixed?.[0].optional; + const b2: string = inputs.mixed?.[0].output.optional; // @ts-expect-error - const b3: number = inputs.mixed?.[0].optional; + const b3: number = inputs.mixed?.[0].output.optional; // @ts-expect-error - const b4: number | undefined = inputs.mixed?.[0].optional; + const b4: number | undefined = inputs.mixed?.[0].output.optional; unused(b1, b2, b3, b4); - const c1: string = inputs.onlyRequired?.[0].required; + const c1: string = inputs.onlyRequired?.[0].output.required; // @ts-expect-error - const c2: number = inputs.onlyRequired?.[0].required; + const c2: number = inputs.onlyRequired?.[0].output.required; unused(c1, c2); - const d1: string | undefined = inputs.onlyOptional?.[0].optional; + const d1: string | undefined = inputs.onlyOptional?.[0].output.optional; // @ts-expect-error - const d2: string = inputs.onlyOptional?.[0].optional; + const d2: string = inputs.onlyOptional?.[0].output.optional; // @ts-expect-error - const d3: number = inputs.onlyOptional?.[0].optional; + const d3: number = inputs.onlyOptional?.[0].output.optional; // @ts-expect-error - const d4: number | undefined = inputs.onlyOptional?.[0].optional; + const d4: number | undefined = inputs.onlyOptional?.[0].output.optional; unused(d1, d2, d3, d4); return { diff --git a/packages/frontend-plugin-api/src/wiring/createExtension.ts b/packages/frontend-plugin-api/src/wiring/createExtension.ts index e4c79a925b..cac2ac7b49 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtension.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtension.ts @@ -52,18 +52,28 @@ export type ExtensionDataValues = { }; /** - * Converts an extension input map into the matching concrete input values type. + * Convert a single extension input into a matching resolved input. * @public */ -export type ExtensionInputValues< +export type ResolvedExtensionInput = + { + extensionId: string; + output: ExtensionDataValues; + }; + +/** + * Converts an extension input map into a matching collection of resolved inputs. + * @public + */ +export type ResolvedExtensionInputs< TInputs extends { [name in string]: ExtensionInput }, > = { [InputName in keyof TInputs]: false extends TInputs[InputName]['config']['singleton'] - ? Array>> + ? Array>> : false extends TInputs[InputName]['config']['optional'] - ? Expand> + ? Expand> : Expand< - ExtensionDataValues | undefined + ResolvedExtensionInput | undefined >; }; @@ -84,7 +94,7 @@ export interface CreateExtensionOptions< factory(options: { node: AppNode; config: TConfig; - inputs: Expand>; + inputs: Expand>; }): Expand>; } @@ -102,10 +112,7 @@ export interface ExtensionDefinition { factory(options: { node: AppNode; config: TConfig; - inputs: Record< - string, - undefined | Record | Array> - >; + inputs: ResolvedExtensionInputs; }): ExtensionDataValues; } @@ -121,10 +128,7 @@ export interface Extension { factory(options: { node: AppNode; config: TConfig; - inputs: Record< - string, - undefined | Record | Array> - >; + inputs: ResolvedExtensionInputs; }): ExtensionDataValues; } @@ -149,7 +153,7 @@ export function createExtension< factory({ inputs, ...rest }) { // TODO: Simplify this, but TS wouldn't infer the input type for some reason return options.factory({ - inputs: inputs as Expand>, + inputs: inputs as Expand>, ...rest, }); }, diff --git a/packages/frontend-plugin-api/src/wiring/createPlugin.test.ts b/packages/frontend-plugin-api/src/wiring/createPlugin.test.ts index 0653c42d7c..18054a5de2 100644 --- a/packages/frontend-plugin-api/src/wiring/createPlugin.test.ts +++ b/packages/frontend-plugin-api/src/wiring/createPlugin.test.ts @@ -65,7 +65,9 @@ const Extension3 = createExtension({ name: nameExtensionDataRef, }, factory({ inputs }) { - return { name: `extension-3:${inputs.addons.map(n => n.name).join('-')}` }; + return { + name: `extension-3:${inputs.addons.map(n => n.output.name).join('-')}`, + }; }, }); @@ -111,7 +113,7 @@ const outputExtension = createExtension({ factory({ inputs }) { return { element: React.createElement('span', {}, [ - `Names: ${inputs.names.map(n => n.name).join(', ')}`, + `Names: ${inputs.names.map(n => n.output.name).join(', ')}`, ]), }; }, diff --git a/packages/frontend-plugin-api/src/wiring/index.ts b/packages/frontend-plugin-api/src/wiring/index.ts index 24f83be6e5..3f33910ca7 100644 --- a/packages/frontend-plugin-api/src/wiring/index.ts +++ b/packages/frontend-plugin-api/src/wiring/index.ts @@ -25,7 +25,8 @@ export { type ExtensionDefinition, type CreateExtensionOptions, type ExtensionDataValues, - type ExtensionInputValues, + type ResolvedExtensionInput, + type ResolvedExtensionInputs, type AnyExtensionInputMap, type AnyExtensionDataMap, } from './createExtension'; diff --git a/plugins/catalog-react/api-report-alpha.md b/plugins/catalog-react/api-report-alpha.md index 1be108f695..27ca640bbc 100644 --- a/plugins/catalog-react/api-report-alpha.md +++ b/plugins/catalog-react/api-report-alpha.md @@ -9,7 +9,7 @@ import { AnyExtensionInputMap } from '@backstage/frontend-plugin-api'; import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; import { Entity } from '@backstage/catalog-model'; import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; -import { ExtensionInputValues } from '@backstage/frontend-plugin-api'; +import { ResolvedExtensionInputs } from '@backstage/frontend-plugin-api'; import { ResourcePermission } from '@backstage/plugin-permission-common'; import { RouteRef } from '@backstage/frontend-plugin-api'; @@ -29,7 +29,7 @@ export function createEntityCardExtension< | typeof entityFilterFunctionExtensionDataRef.T | typeof entityFilterExpressionExtensionDataRef.T; loader: (options: { - inputs: Expand>; + inputs: Expand>; }) => Promise; }): ExtensionDefinition<{ filter?: string | undefined; @@ -54,7 +54,7 @@ export function createEntityContentExtension< | typeof entityFilterFunctionExtensionDataRef.T | typeof entityFilterExpressionExtensionDataRef.T; loader: (options: { - inputs: Expand>; + inputs: Expand>; }) => Promise; }): ExtensionDefinition<{ title: string; diff --git a/plugins/catalog-react/src/alpha.tsx b/plugins/catalog-react/src/alpha.tsx index ccb0efbe6d..8f7144681b 100644 --- a/plugins/catalog-react/src/alpha.tsx +++ b/plugins/catalog-react/src/alpha.tsx @@ -17,7 +17,7 @@ import { AnyExtensionInputMap, ExtensionBoundary, - ExtensionInputValues, + ResolvedExtensionInputs, RouteRef, coreExtensionData, createExtension, @@ -59,7 +59,7 @@ export function createEntityCardExtension< | typeof entityFilterFunctionExtensionDataRef.T | typeof entityFilterExpressionExtensionDataRef.T; loader: (options: { - inputs: Expand>; + inputs: Expand>; }) => Promise; }) { return createExtension({ @@ -117,7 +117,7 @@ export function createEntityContentExtension< | typeof entityFilterFunctionExtensionDataRef.T | typeof entityFilterExpressionExtensionDataRef.T; loader: (options: { - inputs: Expand>; + inputs: Expand>; }) => Promise; }) { return createExtension({ diff --git a/plugins/catalog/src/alpha/entityContents.tsx b/plugins/catalog/src/alpha/entityContents.tsx index 72adf4ec60..b278e15735 100644 --- a/plugins/catalog/src/alpha/entityContents.tsx +++ b/plugins/catalog/src/alpha/entityContents.tsx @@ -39,7 +39,7 @@ export const OverviewEntityContent = createEntityContentExtension({ }, loader: async ({ inputs }) => import('./EntityOverviewPage').then(m => ( - + c.output)} /> )), }); diff --git a/plugins/catalog/src/alpha/pages.tsx b/plugins/catalog/src/alpha/pages.tsx index 7dd32f7748..ee1da49147 100644 --- a/plugins/catalog/src/alpha/pages.tsx +++ b/plugins/catalog/src/alpha/pages.tsx @@ -39,7 +39,7 @@ export const CatalogIndexPage = createPageExtension({ }, loader: async ({ inputs }) => { const { BaseCatalogPage } = await import('../components/CatalogPage'); - const filters = inputs.filters.map(filter => filter.element); + const filters = inputs.filters.map(filter => filter.output.element); return {filters}} />; }, }); @@ -64,11 +64,11 @@ export const CatalogEntityPage = createPageExtension({ {inputs.contents.map(content => ( - {content.element} + {content.output.element} ))} diff --git a/plugins/graphiql/src/alpha.tsx b/plugins/graphiql/src/alpha.tsx index d9470b7d46..f2c23f14e4 100644 --- a/plugins/graphiql/src/alpha.tsx +++ b/plugins/graphiql/src/alpha.tsx @@ -66,7 +66,7 @@ export const graphiqlBrowseApi = createApiExtension({ factory({ inputs }) { return createApiFactory( graphQlBrowseApiRef, - GraphQLEndpoints.from(inputs.endpoints.map(i => i.endpoint)), + GraphQLEndpoints.from(inputs.endpoints.map(i => i.output.endpoint)), ); }, }); diff --git a/plugins/home/src/alpha.tsx b/plugins/home/src/alpha.tsx index 9ccb4c8ed6..f16881de95 100644 --- a/plugins/home/src/alpha.tsx +++ b/plugins/home/src/alpha.tsx @@ -51,8 +51,8 @@ const HomepageCompositionRootExtension = createPageExtension({ loader: ({ inputs }) => import('./components/').then(m => ( )), }); diff --git a/plugins/search-react/src/alpha.test.tsx b/plugins/search-react/src/alpha.test.tsx index 6950dec664..3b05c61eb2 100644 --- a/plugins/search-react/src/alpha.test.tsx +++ b/plugins/search-react/src/alpha.test.tsx @@ -115,10 +115,10 @@ describe('createSearchResultListItemExtension', () => { ); const getResultItemComponent = (result: SearchResult) => { - const value = inputs.items.find(({ item }) => - item?.predicate?.(result), + const value = inputs.items.find(item => + item?.output.item.predicate?.(result), ); - return value?.item.component ?? DefaultResultItem; + return value?.output.item.component ?? DefaultResultItem; }; const Component = () => { diff --git a/plugins/search/src/alpha.tsx b/plugins/search/src/alpha.tsx index 3f1d307237..d18f93391c 100644 --- a/plugins/search/src/alpha.tsx +++ b/plugins/search/src/alpha.tsx @@ -112,8 +112,10 @@ export const SearchPage = createPageExtension({ }, loader: async ({ config, inputs }) => { const getResultItemComponent = (result: SearchResult) => { - const value = inputs.items.find(({ item }) => item?.predicate?.(result)); - return value?.item.component ?? DefaultResultListItem; + const value = inputs.items.find(item => + item?.output.item.predicate?.(result), + ); + return value?.output.item.component ?? DefaultResultListItem; }; const Component = () => { diff --git a/plugins/user-settings/src/alpha.tsx b/plugins/user-settings/src/alpha.tsx index dfcd1d7e2e..cda8301e82 100644 --- a/plugins/user-settings/src/alpha.tsx +++ b/plugins/user-settings/src/alpha.tsx @@ -39,7 +39,9 @@ const UserSettingsPage = createPageExtension({ }, loader: ({ inputs }) => import('./components/SettingsPage').then(m => ( - + )), }); From df2b9a97f9d968bdb802881abeefc6aed0e3eff1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 29 Nov 2023 00:32:24 +0000 Subject: [PATCH 215/261] chore(deps): update dependency @playwright/test to v1.40.1 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/yarn.lock b/yarn.lock index 6916fc4a77..a8a8bc834a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14397,13 +14397,13 @@ __metadata: linkType: hard "@playwright/test@npm:^1.32.3": - version: 1.40.0 - resolution: "@playwright/test@npm:1.40.0" + version: 1.40.1 + resolution: "@playwright/test@npm:1.40.1" dependencies: - playwright: 1.40.0 + playwright: 1.40.1 bin: playwright: cli.js - checksum: 128f05978f9f5a557f0b7924ec134d43cb70c78d74bc3bf7b18576f00e72399100ddf1f4a139e05ea8275407d8e27be0203ac34f514319a2cbeb01eaf0be5be4 + checksum: ae094e6cb809365c0707ee2b184e42d2a2542569ada020d2d44ca5866066941262bd9a67af185f86c2fb0133c9b712ea8cb73e2959a289e4261c5fd17077283c languageName: node linkType: hard @@ -37088,27 +37088,27 @@ __metadata: languageName: node linkType: hard -"playwright-core@npm:1.40.0": - version: 1.40.0 - resolution: "playwright-core@npm:1.40.0" +"playwright-core@npm:1.40.1": + version: 1.40.1 + resolution: "playwright-core@npm:1.40.1" bin: playwright-core: cli.js - checksum: 57de5c91a4c404b120ed2af8541b21cdedcbc4f27477341157666d356bbee3b3fab8e61d020f0f450708fa2e8f6dc244b9224cb1985d5426e609cebed15af095 + checksum: 84d92fb9b86e3c225b16b6886bf858eb5059b4e60fa1205ff23336e56a06dcb2eac62650992dede72f406c8e70a7b6a5303e511f9b4bc0b85022ede356a01ee0 languageName: node linkType: hard -"playwright@npm:1.40.0": - version: 1.40.0 - resolution: "playwright@npm:1.40.0" +"playwright@npm:1.40.1": + version: 1.40.1 + resolution: "playwright@npm:1.40.1" dependencies: fsevents: 2.3.2 - playwright-core: 1.40.0 + playwright-core: 1.40.1 dependenciesMeta: fsevents: optional: true bin: playwright: cli.js - checksum: 7ba49e5376a6cfd1d32048dbdb2fd38e09182aa2e4619fdb23d3e6530fa6987f2f3fd34ad1d9d906fb4ec2da69ee7536eeb881982d60750fde809183caa607fc + checksum: 9e36791c1b4a649c104aa365fdd9d049924eeb518c5967c0e921aa38b9b00994aa6ee54784d6c2af194b3b494b6f69772673081ef53c6c4a4b2065af9955c4ba languageName: node linkType: hard From 634795f33931a8180279845d4bb460ca649fbeb5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 29 Nov 2023 01:23:00 +0000 Subject: [PATCH 216/261] fix(deps): update dependency react-use to v17.4.1 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 74 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 44 insertions(+), 30 deletions(-) diff --git a/yarn.lock b/yarn.lock index a8a8bc834a..fdb7bb8279 100644 --- a/yarn.lock +++ b/yarn.lock @@ -23847,13 +23847,12 @@ __metadata: languageName: node linkType: hard -"css-in-js-utils@npm:^2.0.0": - version: 2.0.1 - resolution: "css-in-js-utils@npm:2.0.1" +"css-in-js-utils@npm:^3.1.0": + version: 3.1.0 + resolution: "css-in-js-utils@npm:3.1.0" dependencies: - hyphenate-style-name: ^1.0.2 - isobject: ^3.0.1 - checksum: c9964c4708216954c468b69bbee2d971fd759ada4f40637b8ca4d3f79caba4818d0532a4f190ac560227c08742ad063ffec7a30afddc4d96b66a18c3a008f0d8 + hyphenate-style-name: ^1.0.3 + checksum: 066318e918c04a5e5bce46b38fe81052ea6ac051bcc6d3c369a1d59ceb1546cb2b6086901ab5d22be084122ee3732169996a3dfb04d3406eaee205af77aec61b languageName: node linkType: hard @@ -24079,7 +24078,7 @@ __metadata: languageName: node linkType: hard -"csstype@npm:^3.0.2, csstype@npm:^3.0.6, csstype@npm:^3.1.2": +"csstype@npm:^3.0.2, csstype@npm:^3.1.2": version: 3.0.9 resolution: "csstype@npm:3.0.9" checksum: 199f9af7e673f9f188525c3102a329d637ff46c52f6385a4427ff5cb17adcb736189150170a7af7c5701d18d7704bdad130273f4aa7e44c6c4f9967e6115dc93 @@ -27212,6 +27211,13 @@ __metadata: languageName: node linkType: hard +"fast-loops@npm:^1.1.3": + version: 1.1.3 + resolution: "fast-loops@npm:1.1.3" + checksum: b674378ba2ed8364ca1a00768636e88b22201c8d010fa62a8588a4cace04f90bac46714c13cf638be82b03438d2fe813600da32291fb47297a1bd7fa6cef0cee + languageName: node + linkType: hard + "fast-memoize@npm:^2.5.2": version: 2.5.2 resolution: "fast-memoize@npm:2.5.2" @@ -29764,12 +29770,13 @@ __metadata: languageName: node linkType: hard -"inline-style-prefixer@npm:^6.0.0": - version: 6.0.0 - resolution: "inline-style-prefixer@npm:6.0.0" +"inline-style-prefixer@npm:^7.0.0": + version: 7.0.0 + resolution: "inline-style-prefixer@npm:7.0.0" dependencies: - css-in-js-utils: ^2.0.0 - checksum: 1331a6184bed03d145e3b9a98363fc7a245590ea1a495df7376a99386737893d4318f8ecf873e2be8431cff1de91512b7a4b9e36326933d5647db0088b63ef4f + css-in-js-utils: ^3.1.0 + fast-loops: ^1.1.3 + checksum: 89fd73eb06e7392e24032ea33b8b33ae7f9a24298f2d9ebbf7b31a3a3934247270047f4f49a454a363aace14e25c3a20fd97465405b0399cc888e5a2bc04ec05 languageName: node linkType: hard @@ -34913,22 +34920,22 @@ __metadata: languageName: node linkType: hard -"nano-css@npm:^5.3.1": - version: 5.3.1 - resolution: "nano-css@npm:5.3.1" +"nano-css@npm:^5.6.1": + version: 5.6.1 + resolution: "nano-css@npm:5.6.1" dependencies: + "@jridgewell/sourcemap-codec": ^1.4.15 css-tree: ^1.1.2 - csstype: ^3.0.6 + csstype: ^3.1.2 fastest-stable-stringify: ^2.0.2 - inline-style-prefixer: ^6.0.0 - rtl-css-js: ^1.14.0 - sourcemap-codec: ^1.4.8 + inline-style-prefixer: ^7.0.0 + rtl-css-js: ^1.16.1 stacktrace-js: ^2.0.2 - stylis: ^4.0.6 + stylis: ^4.3.0 peerDependencies: react: "*" react-dom: "*" - checksum: 45517871e8c15a00769bfc9eb5e466d9c193b0a7423050eb77eb21003a1ccfd13863f01bf68490be830de019f4a0ae945d5b91eb23c5898d341ac8968ba3f18b + checksum: 735f02c030a9416bb6060503d24f18f2b2c9f43e4893c2d8714508d00f9d114b8a134df3623e94e376b0b1d794b0cacac6a48f8e5fb2b7fa8996071bcad590b8 languageName: node linkType: hard @@ -39035,8 +39042,8 @@ __metadata: linkType: hard "react-use@npm:^17.2.4, react-use@npm:^17.3.1, react-use@npm:^17.3.2, react-use@npm:^17.4.0": - version: 17.4.0 - resolution: "react-use@npm:17.4.0" + version: 17.4.1 + resolution: "react-use@npm:17.4.1" dependencies: "@types/js-cookie": ^2.2.6 "@xobotyi/scrollbar-width": ^1.9.5 @@ -39044,7 +39051,7 @@ __metadata: fast-deep-equal: ^3.1.3 fast-shallow-equal: ^1.0.0 js-cookie: ^2.2.1 - nano-css: ^5.3.1 + nano-css: ^5.6.1 react-universal-interface: ^0.6.2 resize-observer-polyfill: ^1.5.1 screenfull: ^5.1.0 @@ -39055,7 +39062,7 @@ __metadata: peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: 0889da919b49a186de375ec15d2778b954ae981c523acd17dd496e4a4da7b6190efe7993491e1b85fdd6de3e745d08a4eaba4caa35408d570b5f1de550f35d11 + checksum: 75c4c63b97d50293b021aa3c6c66d3613151ca350e9ed47e0636d49679662e5841e100599d921c63604c9b4d11603261f5a232770069324734bae372718e2391 languageName: node linkType: hard @@ -40175,12 +40182,12 @@ __metadata: languageName: node linkType: hard -"rtl-css-js@npm:^1.14.0": - version: 1.14.0 - resolution: "rtl-css-js@npm:1.14.0" +"rtl-css-js@npm:^1.16.1": + version: 1.16.1 + resolution: "rtl-css-js@npm:1.16.1" dependencies: "@babel/runtime": ^7.1.2 - checksum: 46e7f52058d7ac2dc7a6271f6858ce2e05f64be4d6a3eae712b52bf29c4de97fda8e30490c425bed620db87cc0b8a3ab4a457489ab0dba0868724bac27e6f893 + checksum: 7d9ab942098eee565784ccf957f6b7dfa78ea1eec7c6bffedc6641575d274189e90752537c7bdba1f43ae6534648144f467fd6d581527455ba626a4300e62c7a languageName: node linkType: hard @@ -41895,13 +41902,20 @@ __metadata: languageName: node linkType: hard -"stylis@npm:4.2.0, stylis@npm:^4.0.6": +"stylis@npm:4.2.0": version: 4.2.0 resolution: "stylis@npm:4.2.0" checksum: 0eb6cc1b866dc17a6037d0a82ac7fa877eba6a757443e79e7c4f35bacedbf6421fadcab4363b39667b43355cbaaa570a3cde850f776498e5450f32ed2f9b7584 languageName: node linkType: hard +"stylis@npm:^4.3.0": + version: 4.3.0 + resolution: "stylis@npm:4.3.0" + checksum: 6120de3f03eacf3b5adc8e7919c4cca991089156a6badc5248752a3088106afaaf74996211a6817a7760ebeadca09004048eea31875bd8d4df51386365c50025 + languageName: node + linkType: hard + "subscriptions-transport-ws@npm:^0.11.0": version: 0.11.0 resolution: "subscriptions-transport-ws@npm:0.11.0" From 6570a778e2503ba3a6c9fc85c513005a936aea4a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 29 Nov 2023 02:11:32 +0000 Subject: [PATCH 217/261] fix(deps): update dependency zod-to-json-schema to v3.22.1 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index fdb7bb8279..81a89a820b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -45345,11 +45345,11 @@ __metadata: linkType: hard "zod-to-json-schema@npm:^3.20.4, zod-to-json-schema@npm:^3.21.4": - version: 3.22.0 - resolution: "zod-to-json-schema@npm:3.22.0" + version: 3.22.1 + resolution: "zod-to-json-schema@npm:3.22.1" peerDependencies: zod: ^3.22.4 - checksum: 79ba2f120e16bb38a44b6c20a3afa5e61c40f2d48749b08be68692005af1aed897c808f59be1fe722c2c40c5c3e9c38cd8ca4bfefdae089822de5948fe7d7cc5 + checksum: 7c0cdcf0acac81a9b69b26e44bc45e43aefacd5759e12f89856f0a4b957b66be27560671473ef7ab4a5883a871b6990a7f61fce3cee96ecad3823c5b7e524fa5 languageName: node linkType: hard From e7312494b0469189becc34ed0818c804a80da979 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 29 Nov 2023 03:22:22 +0000 Subject: [PATCH 218/261] chore(deps): update jamesives/github-pages-deploy-action action to v4.5.0 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/deploy_microsite.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy_microsite.yml b/.github/workflows/deploy_microsite.yml index d8e5789a09..21a15ae475 100644 --- a/.github/workflows/deploy_microsite.yml +++ b/.github/workflows/deploy_microsite.yml @@ -66,7 +66,7 @@ jobs: run: ls microsite/build && ls microsite/build/storybook - name: Deploy both microsite and storybook to gh-pages - uses: JamesIves/github-pages-deploy-action@a1ea191d508feb8485aceba848389d49f80ca2dc # v4.4.3 + uses: JamesIves/github-pages-deploy-action@65b5dfd4f5bcd3a7403bbc2959c144256167464e # v4.5.0 with: branch: gh-pages folder: microsite/build From 50ee804d36762d08399f957a73fd5ee438df164a Mon Sep 17 00:00:00 2001 From: Tomasz Szuba Date: Fri, 24 Nov 2023 19:02:35 +0100 Subject: [PATCH 219/261] Wrap task pipeline loop in a span This makes traces from `DefaultCatalogProcessingEngine` nicer Signed-off-by: Tomasz Szuba --- .changeset/late-eyes-serve.md | 5 ++ .../src/processing/TaskPipeline.ts | 58 ++++++++++--------- 2 files changed, 37 insertions(+), 26 deletions(-) create mode 100644 .changeset/late-eyes-serve.md diff --git a/.changeset/late-eyes-serve.md b/.changeset/late-eyes-serve.md new file mode 100644 index 0000000000..37d8e7a22a --- /dev/null +++ b/.changeset/late-eyes-serve.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': patch +--- + +Wrap single `pipelineLoop` of TaskPipeline in a span for better traces diff --git a/plugins/catalog-backend/src/processing/TaskPipeline.ts b/plugins/catalog-backend/src/processing/TaskPipeline.ts index 44030be9e0..98cf221b6e 100644 --- a/plugins/catalog-backend/src/processing/TaskPipeline.ts +++ b/plugins/catalog-backend/src/processing/TaskPipeline.ts @@ -14,7 +14,11 @@ * limitations under the License. */ +import { TRACER_ID, withActiveSpan } from '../util/opentelemetry'; +import { trace } from '@opentelemetry/api'; + const DEFAULT_POLLING_INTERVAL_MS = 1000; +const tracer = trace.getTracer(TRACER_ID); type Options = { /** @@ -85,34 +89,36 @@ export function startTaskPipeline(options: Options) { async function pipelineLoop() { while (!abortSignal.aborted) { - if (state.inFlightCount <= lowWatermark) { - const loadCount = highWatermark - state.inFlightCount; - const loadedItems = await Promise.resolve() - .then(() => loadTasks(loadCount)) - .catch(() => { - // Silently swallow errors and go back to sleep to try again; we - // delegate to the loadTasks function itself to catch errors and log - // if it so desires - return []; - }); - if (loadedItems.length && !abortSignal.aborted) { - state.inFlightCount += loadedItems.length; - for (const item of loadedItems) { - Promise.resolve() - .then(() => processTask(item)) - .catch(() => { - // Silently swallow errors and go back to sleep to try again; we - // delegate to the processTask function itself to catch errors - // and log if it so desires - }) - .finally(() => { - state.inFlightCount -= 1; - barrier.release(); - }); + await withActiveSpan(tracer, 'TaskPipelineLoop', async span => { + if (state.inFlightCount <= lowWatermark) { + const loadCount = highWatermark - state.inFlightCount; + const loadedItems = await Promise.resolve(loadCount) + .then(loadTasks) + .catch(() => { + // Silently swallow errors and go back to sleep to try again; we + // delegate to the loadTasks function itself to catch errors and log + // if it so desires + return []; + }); + span.setAttribute('itemCount', loadedItems.length); + if (loadedItems.length && !abortSignal.aborted) { + state.inFlightCount += loadedItems.length; + for (const item of loadedItems) { + Promise.resolve(item) + .then(processTask) + .catch(() => { + // Silently swallow errors and go back to sleep to try again; we + // delegate to the processTask function itself to catch errors + // and log if it so desires + }) + .finally(() => { + state.inFlightCount -= 1; + barrier.release(); + }); + } } } - } - + }); await barrier.wait(); } } From c08e2151e833a7760046f968513090a0c9ad7662 Mon Sep 17 00:00:00 2001 From: Tomasz Szuba Date: Wed, 29 Nov 2023 09:08:06 +0100 Subject: [PATCH 220/261] Fix review comments Signed-off-by: Tomasz Szuba --- .../src/processing/TaskPipeline.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/plugins/catalog-backend/src/processing/TaskPipeline.ts b/plugins/catalog-backend/src/processing/TaskPipeline.ts index 98cf221b6e..b808e41ce4 100644 --- a/plugins/catalog-backend/src/processing/TaskPipeline.ts +++ b/plugins/catalog-backend/src/processing/TaskPipeline.ts @@ -89,11 +89,11 @@ export function startTaskPipeline(options: Options) { async function pipelineLoop() { while (!abortSignal.aborted) { - await withActiveSpan(tracer, 'TaskPipelineLoop', async span => { - if (state.inFlightCount <= lowWatermark) { + if (state.inFlightCount <= lowWatermark) { + await withActiveSpan(tracer, 'TaskPipelineLoop', async span => { const loadCount = highWatermark - state.inFlightCount; - const loadedItems = await Promise.resolve(loadCount) - .then(loadTasks) + const loadedItems = await Promise.resolve() + .then(() => loadTasks(loadCount)) .catch(() => { // Silently swallow errors and go back to sleep to try again; we // delegate to the loadTasks function itself to catch errors and log @@ -104,8 +104,8 @@ export function startTaskPipeline(options: Options) { if (loadedItems.length && !abortSignal.aborted) { state.inFlightCount += loadedItems.length; for (const item of loadedItems) { - Promise.resolve(item) - .then(processTask) + Promise.resolve() + .then(() => processTask(item)) .catch(() => { // Silently swallow errors and go back to sleep to try again; we // delegate to the processTask function itself to catch errors @@ -117,8 +117,8 @@ export function startTaskPipeline(options: Options) { }); } } - } - }); + }); + } await barrier.wait(); } } From f89b5b414353d188704d22c141616587efec1f3b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 29 Nov 2023 08:33:06 +0000 Subject: [PATCH 221/261] fix(deps): update dependency recharts to v2.10.2 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 81a89a820b..19ca7d4edc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -39272,8 +39272,8 @@ __metadata: linkType: hard "recharts@npm:^2.5.0": - version: 2.10.1 - resolution: "recharts@npm:2.10.1" + version: 2.10.2 + resolution: "recharts@npm:2.10.2" dependencies: clsx: ^2.0.0 eventemitter3: ^4.0.1 @@ -39287,7 +39287,7 @@ __metadata: prop-types: ^15.6.0 react: ^16.0.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 - checksum: f1ee4dfe000c18f3c74855ea559e87d805c86f3b127441684187416ff4d22df4f92a6298259dfd9869d355d03291516ac75aaa6620f623b7b79c53f48fe6c9fb + checksum: da0383c4b9c2dae76cd415bd1678285ce5975545cd2d305054189b21ce7c9559ad7233941152a8bab0897196281c8bb142710c815d93ebe828901b8799c7528a languageName: node linkType: hard From b2402af2575f05003496d88c4592518f3f42df6e Mon Sep 17 00:00:00 2001 From: rtriesscheijn Date: Wed, 29 Nov 2023 09:37:48 +0100 Subject: [PATCH 222/261] fix: missing return statement in KeyStore.ts Signed-off-by: rtriesscheijn --- plugins/auth-backend/src/identity/KeyStores.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/auth-backend/src/identity/KeyStores.ts b/plugins/auth-backend/src/identity/KeyStores.ts index 7242530c57..16f25817a9 100644 --- a/plugins/auth-backend/src/identity/KeyStores.ts +++ b/plugins/auth-backend/src/identity/KeyStores.ts @@ -76,7 +76,7 @@ export class KeyStores { } if (provider === 'static') { - await StaticKeyStore.fromConfig(config); + return await StaticKeyStore.fromConfig(config); } throw new Error(`Unknown KeyStore provider: ${provider}`); From 783797a0280859900ff5cdc0cd46573a871cc509 Mon Sep 17 00:00:00 2001 From: rtriesscheijn Date: Wed, 29 Nov 2023 09:41:45 +0100 Subject: [PATCH 223/261] fix: add changeset Signed-off-by: rtriesscheijn --- .changeset/nervous-ladybugs-end.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/nervous-ladybugs-end.md diff --git a/.changeset/nervous-ladybugs-end.md b/.changeset/nervous-ladybugs-end.md new file mode 100644 index 0000000000..5ee94ec637 --- /dev/null +++ b/.changeset/nervous-ladybugs-end.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-auth-backend': patch +--- + +fix static token issuer not being able to initialize From a3edc180b9c095c57949be761daf42ae255c0f01 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 29 Nov 2023 10:24:51 +0000 Subject: [PATCH 224/261] chore(deps): update dependency vite-plugin-node-polyfills to ^0.17.0 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .changeset/renovate-0392ef9.md | 5 +++++ packages/app/package.json | 2 +- packages/cli/package.json | 2 +- yarn.lock | 14 +++++++------- 4 files changed, 14 insertions(+), 9 deletions(-) create mode 100644 .changeset/renovate-0392ef9.md diff --git a/.changeset/renovate-0392ef9.md b/.changeset/renovate-0392ef9.md new file mode 100644 index 0000000000..3ee3fb0361 --- /dev/null +++ b/.changeset/renovate-0392ef9.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Updated dependency `vite-plugin-node-polyfills` to `^0.17.0`. diff --git a/packages/app/package.json b/packages/app/package.json index 63a2bdc4b5..e47388a7e1 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -102,7 +102,7 @@ "react-use": "^17.2.4", "vite": "^4.4.9", "vite-plugin-html": "^3.2.0", - "vite-plugin-node-polyfills": "^0.16.0", + "vite-plugin-node-polyfills": "^0.17.0", "zen-observable": "^0.10.0" }, "devDependencies": { diff --git a/packages/cli/package.json b/packages/cli/package.json index 38ff54a63f..6ccceb79c4 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -177,7 +177,7 @@ "@vitejs/plugin-react": "^4.0.4", "vite": "^4.4.9", "vite-plugin-html": "^3.2.0", - "vite-plugin-node-polyfills": "^0.16.0" + "vite-plugin-node-polyfills": "^0.17.0" }, "peerDependenciesMeta": { "@vitejs/plugin-react": { diff --git a/yarn.lock b/yarn.lock index 19ca7d4edc..76f7bbe3a1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3732,7 +3732,7 @@ __metadata: "@vitejs/plugin-react": ^4.0.4 vite: ^4.4.9 vite-plugin-html: ^3.2.0 - vite-plugin-node-polyfills: ^0.16.0 + vite-plugin-node-polyfills: ^0.17.0 peerDependenciesMeta: "@vitejs/plugin-react": optional: true @@ -26725,7 +26725,7 @@ __metadata: react-use: ^17.2.4 vite: ^4.4.9 vite-plugin-html: ^3.2.0 - vite-plugin-node-polyfills: ^0.16.0 + vite-plugin-node-polyfills: ^0.17.0 zen-observable: ^0.10.0 languageName: unknown linkType: soft @@ -44137,17 +44137,17 @@ __metadata: languageName: node linkType: hard -"vite-plugin-node-polyfills@npm:^0.16.0": - version: 0.16.0 - resolution: "vite-plugin-node-polyfills@npm:0.16.0" +"vite-plugin-node-polyfills@npm:^0.17.0": + version: 0.17.0 + resolution: "vite-plugin-node-polyfills@npm:0.17.0" dependencies: "@rollup/plugin-inject": ^5.0.5 buffer-polyfill: "npm:buffer@^6.0.3" node-stdlib-browser: ^1.2.0 process: ^0.11.10 peerDependencies: - vite: ^2.0.0 || ^3.0.0 || ^4.0.0 - checksum: c4b3767e29a7c95efccde7d8adeac7963fb9b30677d88e348eda1c1d407c0d821d58c9ea651cb5db0aa010c93fd1971d8b671fea2417edd15a707861be772861 + vite: ^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 + checksum: 760d29c25adfa72b5fc731c1bb0826f9c6cc495afc856d38f634ac811566b158a11b1ea968e5d9d536889072470666e9b933ca38ea0c533854375806503b1729 languageName: node linkType: hard From 40a9c5984329c1a019de428148479593488cbe14 Mon Sep 17 00:00:00 2001 From: David Festal Date: Wed, 29 Nov 2023 12:07:11 +0100 Subject: [PATCH 225/261] Attempt to fix a flaky test in the `backend-plugin-manager` Signed-off-by: David Festal --- .../scanner/plugin-scanner-watcher.test.ts | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/packages/backend-plugin-manager/src/scanner/plugin-scanner-watcher.test.ts b/packages/backend-plugin-manager/src/scanner/plugin-scanner-watcher.test.ts index e346bf749f..7b795aee4f 100644 --- a/packages/backend-plugin-manager/src/scanner/plugin-scanner-watcher.test.ts +++ b/packages/backend-plugin-manager/src/scanner/plugin-scanner-watcher.test.ts @@ -229,6 +229,7 @@ describe('plugin-scanner', () => { logger.logs = {}; const debug = jest.spyOn(logger, 'debug'); + const info = jest.spyOn(logger, 'info'); // Check that not all file changes trigger a new scan of plugins await mkdir( @@ -240,8 +241,11 @@ describe('plugin-scanner', () => { ), ); await waitForExpect(() => { - expect(debug).toHaveBeenCalledTimes(1); + expect(debug).toHaveBeenCalled(); }); + expect(info).toHaveBeenCalledTimes(0); + debug.mockClear(); + await writeFile( join( backstageRootDirectory, @@ -252,8 +256,11 @@ describe('plugin-scanner', () => { 'content', ); await waitForExpect(() => { - expect(debug).toHaveBeenCalledTimes(2); + expect(debug).toHaveBeenCalled(); }); + expect(info).toHaveBeenCalledTimes(0); + debug.mockClear(); + await rm( join( backstageRootDirectory, @@ -263,8 +270,11 @@ describe('plugin-scanner', () => { ), ); await waitForExpect(() => { - expect(debug).toHaveBeenCalledTimes(3); + expect(debug).toHaveBeenCalled(); }); + expect(info).toHaveBeenCalledTimes(0); + debug.mockClear(); + await rm( join( backstageRootDirectory, @@ -275,8 +285,10 @@ describe('plugin-scanner', () => { { recursive: true }, ); await waitForExpect(() => { - expect(debug).toHaveBeenCalledTimes(4); + expect(debug).toHaveBeenCalled(); }); + expect(info).toHaveBeenCalledTimes(0); + debug.mockClear(); const onWindows = path.sep === '\\'; // Order of events is not fixed on Windows. From af196964d7cb732995922b20264d0ab07ffef69c Mon Sep 17 00:00:00 2001 From: Frida Jacobsson Date: Wed, 29 Nov 2023 13:30:01 +0100 Subject: [PATCH 226/261] Adding Jira Dashboard plugin Added the Jira Dashboard plugin to the Directory. Signed-off-by: Frida Jacobsson --- microsite/data/plugins/jira-dashboard | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 microsite/data/plugins/jira-dashboard diff --git a/microsite/data/plugins/jira-dashboard b/microsite/data/plugins/jira-dashboard new file mode 100644 index 0000000000..8838af8492 --- /dev/null +++ b/microsite/data/plugins/jira-dashboard @@ -0,0 +1,10 @@ +--- +title: Jira Dashboard +author: AxisCommunications +authorUrl: https://github.com/AxisCommunications +category: Agile Planning +description: Allows you to fetch and display Jira issues for your entity. You get quickly access to issue summaries to achieve better task visibility and more efficient project management. +documentation: https://github.com/AxisCommunications/backstage-plugins +iconUrl: https://github.com/AxisCommunications/backstage-plugins/blob/main/plugins/jira-dashboard/media/jira-logo.png +npmPackageName: '@axis-backstage/plugin-jira-dashboard' +addedDate: '2023-11-29' From a6be465ee68edcbd7f3e2895882a3117ea77230e Mon Sep 17 00:00:00 2001 From: Djam Date: Wed, 29 Nov 2023 16:29:20 +0100 Subject: [PATCH 227/261] fix: export oauth2Proxy as default so DI discovers it Signed-off-by: djamaile --- .changeset/chilly-lies-collect.md | 5 +++++ .../auth-backend-module-oauth2-proxy-provider/api-report.md | 3 ++- .../auth-backend-module-oauth2-proxy-provider/src/index.ts | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 .changeset/chilly-lies-collect.md diff --git a/.changeset/chilly-lies-collect.md b/.changeset/chilly-lies-collect.md new file mode 100644 index 0000000000..9af0c41099 --- /dev/null +++ b/.changeset/chilly-lies-collect.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-auth-backend-module-oauth2-proxy-provider': patch +--- + +Exported the plugin as default so it gets discovered by using `featureDiscoveryServiceFactory()` diff --git a/plugins/auth-backend-module-oauth2-proxy-provider/api-report.md b/plugins/auth-backend-module-oauth2-proxy-provider/api-report.md index a07db4ce11..1a4c1ee6d6 100644 --- a/plugins/auth-backend-module-oauth2-proxy-provider/api-report.md +++ b/plugins/auth-backend-module-oauth2-proxy-provider/api-report.md @@ -10,7 +10,8 @@ import { IncomingHttpHeaders } from 'http'; import { ProxyAuthenticator } from '@backstage/plugin-auth-node'; // @public (undocumented) -export const authModuleOauth2ProxyProvider: () => BackendFeature; +const authModuleOauth2ProxyProvider: () => BackendFeature; +export default authModuleOauth2ProxyProvider; // @public export const OAUTH2_PROXY_JWT_HEADER = 'X-OAUTH2-PROXY-ID-TOKEN'; diff --git a/plugins/auth-backend-module-oauth2-proxy-provider/src/index.ts b/plugins/auth-backend-module-oauth2-proxy-provider/src/index.ts index db0da00a16..b804f666c7 100644 --- a/plugins/auth-backend-module-oauth2-proxy-provider/src/index.ts +++ b/plugins/auth-backend-module-oauth2-proxy-provider/src/index.ts @@ -19,7 +19,7 @@ * * @packageDocumentation */ -export { authModuleOauth2ProxyProvider } from './module'; +export { authModuleOauth2ProxyProvider as default } from './module'; export { oauth2ProxyAuthenticator, OAUTH2_PROXY_JWT_HEADER, From 07f8cf0bb75e6c69c1190e914e959a188708a6d8 Mon Sep 17 00:00:00 2001 From: Djam Date: Wed, 29 Nov 2023 16:53:32 +0100 Subject: [PATCH 228/261] Update chilly-lies-collect.md Signed-off-by: Djam --- .changeset/chilly-lies-collect.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/chilly-lies-collect.md b/.changeset/chilly-lies-collect.md index 9af0c41099..c84e6cebd4 100644 --- a/.changeset/chilly-lies-collect.md +++ b/.changeset/chilly-lies-collect.md @@ -2,4 +2,4 @@ '@backstage/plugin-auth-backend-module-oauth2-proxy-provider': patch --- -Exported the plugin as default so it gets discovered by using `featureDiscoveryServiceFactory()` +Exported the provider as default so it gets discovered when using `featureDiscoveryServiceFactory()` From 7804597717f52cd7cb427e24fb44073e809fd83c Mon Sep 17 00:00:00 2001 From: lshwayne96 Date: Tue, 14 Nov 2023 16:51:42 +0800 Subject: [PATCH 229/261] Enable addition of permission rules for Catalog plugin through CatalogProcessingExtensionPoint Signed-off-by: lshwayne96 --- .changeset/wild-knives-wait.md | 6 ++++++ .../catalog-backend/src/service/CatalogPlugin.ts | 16 +++++++++++++++- plugins/catalog-node/package.json | 1 + plugins/catalog-node/src/extensions.ts | 6 ++++++ yarn.lock | 1 + 5 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 .changeset/wild-knives-wait.md diff --git a/.changeset/wild-knives-wait.md b/.changeset/wild-knives-wait.md new file mode 100644 index 0000000000..460712b5d9 --- /dev/null +++ b/.changeset/wild-knives-wait.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-catalog-backend': minor +'@backstage/plugin-catalog-node': minor +--- + +Permission rules can now be added for the Catalog plugin through the `CatalogProcessingExtensionPoint` interface. diff --git a/plugins/catalog-backend/src/service/CatalogPlugin.ts b/plugins/catalog-backend/src/service/CatalogPlugin.ts index fa53ef510b..844f56e766 100644 --- a/plugins/catalog-backend/src/service/CatalogPlugin.ts +++ b/plugins/catalog-backend/src/service/CatalogPlugin.ts @@ -17,7 +17,7 @@ import { createBackendPlugin, coreServices, } from '@backstage/backend-plugin-api'; -import { CatalogBuilder } from './CatalogBuilder'; +import { CatalogBuilder, CatalogPermissionRuleInput } from './CatalogBuilder'; import { CatalogAnalysisExtensionPoint, catalogAnalysisExtensionPoint, @@ -38,6 +38,7 @@ class CatalogProcessingExtensionPointImpl #processors = new Array(); #entityProviders = new Array(); #placeholderResolvers: Record = {}; + #permissionRules = new Array(); addProcessor( ...processors: Array> @@ -59,6 +60,14 @@ class CatalogProcessingExtensionPointImpl this.#placeholderResolvers[key] = resolver; } + addPermissionRules( + ...rules: Array< + CatalogPermissionRuleInput | Array + > + ): void { + this.#permissionRules.push(...rules.flat()); + } + get processors() { return this.#processors; } @@ -70,6 +79,10 @@ class CatalogProcessingExtensionPointImpl get placeholderResolvers() { return this.#placeholderResolvers; } + + get permissionRules() { + return this.#permissionRules; + } } class CatalogAnalysisExtensionPointImpl @@ -142,6 +155,7 @@ export const catalogPlugin = createBackendPlugin({ ([key, resolver]) => builder.setPlaceholderResolver(key, resolver), ); builder.addLocationAnalyzers(...analysisExtensions.locationAnalyzers); + builder.addPermissionRules(...processingExtensions.permissionRules); const { processingEngine, router } = await builder.build(); diff --git a/plugins/catalog-node/package.json b/plugins/catalog-node/package.json index f76fde6ecf..841a7be4a5 100644 --- a/plugins/catalog-node/package.json +++ b/plugins/catalog-node/package.json @@ -46,6 +46,7 @@ "@backstage/catalog-client": "workspace:^", "@backstage/catalog-model": "workspace:^", "@backstage/errors": "workspace:^", + "@backstage/plugin-catalog-backend": "workspace:^", "@backstage/plugin-catalog-common": "workspace:^", "@backstage/types": "workspace:^" }, diff --git a/plugins/catalog-node/src/extensions.ts b/plugins/catalog-node/src/extensions.ts index 247ef142ad..02a18774cd 100644 --- a/plugins/catalog-node/src/extensions.ts +++ b/plugins/catalog-node/src/extensions.ts @@ -14,6 +14,7 @@ * limitations under the License. */ import { createExtensionPoint } from '@backstage/backend-plugin-api'; +import { CatalogPermissionRuleInput } from '@backstage/plugin-catalog-backend'; import { EntityProvider, CatalogProcessor, @@ -32,6 +33,11 @@ export interface CatalogProcessingExtensionPoint { ...providers: Array> ): void; addPlaceholderResolver(key: string, resolver: PlaceholderResolver): void; + addPermissionRules( + ...rules: Array< + CatalogPermissionRuleInput | Array + > + ): void; } /** diff --git a/yarn.lock b/yarn.lock index 19ca7d4edc..1d47eb1e10 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5939,6 +5939,7 @@ __metadata: "@backstage/catalog-model": "workspace:^" "@backstage/cli": "workspace:^" "@backstage/errors": "workspace:^" + "@backstage/plugin-catalog-backend": "workspace:^" "@backstage/plugin-catalog-common": "workspace:^" "@backstage/types": "workspace:^" languageName: unknown From 447a1b8975bbe4a034331038764c82ce86d31704 Mon Sep 17 00:00:00 2001 From: lshwayne96 Date: Tue, 14 Nov 2023 17:42:00 +0800 Subject: [PATCH 230/261] Updated API report for plugins/catalog-node Signed-off-by: lshwayne96 --- plugins/catalog-node/api-report-alpha.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/plugins/catalog-node/api-report-alpha.md b/plugins/catalog-node/api-report-alpha.md index c4dc6b12e1..e4918c93aa 100644 --- a/plugins/catalog-node/api-report-alpha.md +++ b/plugins/catalog-node/api-report-alpha.md @@ -4,6 +4,7 @@ ```ts import { CatalogApi } from '@backstage/catalog-client'; +import { CatalogPermissionRuleInput } from '@backstage/plugin-catalog-backend'; import { CatalogProcessor } from '@backstage/plugin-catalog-node'; import { EntityProvider } from '@backstage/plugin-catalog-node'; import { ExtensionPoint } from '@backstage/backend-plugin-api'; @@ -27,6 +28,12 @@ export interface CatalogProcessingExtensionPoint { ...providers: Array> ): void; // (undocumented) + addPermissionRules( + ...rules: Array< + CatalogPermissionRuleInput | Array + > + ): void; + // (undocumented) addPlaceholderResolver(key: string, resolver: PlaceholderResolver): void; // (undocumented) addProcessor( From 2815828be53645d7dda95e8f591061d5cf54dd9d Mon Sep 17 00:00:00 2001 From: lshwayne96 Date: Wed, 15 Nov 2023 11:32:55 +0800 Subject: [PATCH 231/261] Remove catalog-backend dependency from catalog-node plugin Signed-off-by: lshwayne96 --- plugins/catalog-node/package.json | 1 - yarn.lock | 1 - 2 files changed, 2 deletions(-) diff --git a/plugins/catalog-node/package.json b/plugins/catalog-node/package.json index 841a7be4a5..f76fde6ecf 100644 --- a/plugins/catalog-node/package.json +++ b/plugins/catalog-node/package.json @@ -46,7 +46,6 @@ "@backstage/catalog-client": "workspace:^", "@backstage/catalog-model": "workspace:^", "@backstage/errors": "workspace:^", - "@backstage/plugin-catalog-backend": "workspace:^", "@backstage/plugin-catalog-common": "workspace:^", "@backstage/types": "workspace:^" }, diff --git a/yarn.lock b/yarn.lock index 1d47eb1e10..19ca7d4edc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5939,7 +5939,6 @@ __metadata: "@backstage/catalog-model": "workspace:^" "@backstage/cli": "workspace:^" "@backstage/errors": "workspace:^" - "@backstage/plugin-catalog-backend": "workspace:^" "@backstage/plugin-catalog-common": "workspace:^" "@backstage/types": "workspace:^" languageName: unknown From c94ed08d16cc10a1fb8e47ef2c3665688b1a1512 Mon Sep 17 00:00:00 2001 From: lshwayne96 Date: Thu, 16 Nov 2023 13:27:16 +0800 Subject: [PATCH 232/261] Define CatalogPermissionRuleInput type in catalog-node plugin Signed-off-by: lshwayne96 --- plugins/catalog-node/package.json | 2 ++ plugins/catalog-node/src/extensions.ts | 12 +++++++++++- yarn.lock | 2 ++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/plugins/catalog-node/package.json b/plugins/catalog-node/package.json index f76fde6ecf..85ca35831c 100644 --- a/plugins/catalog-node/package.json +++ b/plugins/catalog-node/package.json @@ -47,6 +47,8 @@ "@backstage/catalog-model": "workspace:^", "@backstage/errors": "workspace:^", "@backstage/plugin-catalog-common": "workspace:^", + "@backstage/plugin-permission-common": "workspace:^", + "@backstage/plugin-permission-node": "workspace:^", "@backstage/types": "workspace:^" }, "devDependencies": { diff --git a/plugins/catalog-node/src/extensions.ts b/plugins/catalog-node/src/extensions.ts index 02a18774cd..6516653150 100644 --- a/plugins/catalog-node/src/extensions.ts +++ b/plugins/catalog-node/src/extensions.ts @@ -14,7 +14,9 @@ * limitations under the License. */ import { createExtensionPoint } from '@backstage/backend-plugin-api'; -import { CatalogPermissionRuleInput } from '@backstage/plugin-catalog-backend'; +import { Entity } from '@backstage/catalog-model'; +import { PermissionRuleParams } from '@backstage/plugin-permission-common'; +import { PermissionRule } from '@backstage/plugin-permission-node'; import { EntityProvider, CatalogProcessor, @@ -22,6 +24,14 @@ import { ScmLocationAnalyzer, } from '@backstage/plugin-catalog-node'; +type EntitiesSearchFilter = { + key: string; + values?: string[]; +}; +type CatalogPermissionRuleInput< + TParams extends PermissionRuleParams = PermissionRuleParams, +> = PermissionRule; + /** * @alpha */ diff --git a/yarn.lock b/yarn.lock index 19ca7d4edc..35345de358 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5940,6 +5940,8 @@ __metadata: "@backstage/cli": "workspace:^" "@backstage/errors": "workspace:^" "@backstage/plugin-catalog-common": "workspace:^" + "@backstage/plugin-permission-common": "workspace:^" + "@backstage/plugin-permission-node": "workspace:^" "@backstage/types": "workspace:^" languageName: unknown linkType: soft From 24ab4464e70419e3d2a6e30ff9fb03bc53fc0b0d Mon Sep 17 00:00:00 2001 From: lshwayne96 Date: Thu, 16 Nov 2023 14:14:23 +0800 Subject: [PATCH 233/261] Export new types and update API report Signed-off-by: lshwayne96 --- plugins/catalog-node/api-report-alpha.md | 15 ++++++++++++++- plugins/catalog-node/src/alpha.ts | 4 ++++ plugins/catalog-node/src/extensions.ts | 11 +++++++++-- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/plugins/catalog-node/api-report-alpha.md b/plugins/catalog-node/api-report-alpha.md index e4918c93aa..676115c4d9 100644 --- a/plugins/catalog-node/api-report-alpha.md +++ b/plugins/catalog-node/api-report-alpha.md @@ -4,10 +4,12 @@ ```ts import { CatalogApi } from '@backstage/catalog-client'; -import { CatalogPermissionRuleInput } from '@backstage/plugin-catalog-backend'; import { CatalogProcessor } from '@backstage/plugin-catalog-node'; +import { Entity } from '@backstage/catalog-model'; import { EntityProvider } from '@backstage/plugin-catalog-node'; import { ExtensionPoint } from '@backstage/backend-plugin-api'; +import { PermissionRule } from '@backstage/plugin-permission-node'; +import { PermissionRuleParams } from '@backstage/plugin-permission-common'; import { PlaceholderResolver } from '@backstage/plugin-catalog-node'; import { ScmLocationAnalyzer } from '@backstage/plugin-catalog-node'; import { ServiceRef } from '@backstage/backend-plugin-api'; @@ -21,6 +23,11 @@ export interface CatalogAnalysisExtensionPoint { // @alpha (undocumented) export const catalogAnalysisExtensionPoint: ExtensionPoint; +// @alpha (undocumented) +export type CatalogPermissionRuleInput< + TParams extends PermissionRuleParams = PermissionRuleParams, +> = PermissionRule; + // @alpha (undocumented) export interface CatalogProcessingExtensionPoint { // (undocumented) @@ -47,5 +54,11 @@ export const catalogProcessingExtensionPoint: ExtensionPoint; +// @alpha (undocumented) +export type EntitiesSearchFilter = { + key: string; + values?: string[]; +}; + // (No @packageDocumentation comment for this package) ``` diff --git a/plugins/catalog-node/src/alpha.ts b/plugins/catalog-node/src/alpha.ts index cec1a0eedb..3d6194f986 100644 --- a/plugins/catalog-node/src/alpha.ts +++ b/plugins/catalog-node/src/alpha.ts @@ -19,3 +19,7 @@ export type { CatalogProcessingExtensionPoint } from './extensions'; export { catalogProcessingExtensionPoint } from './extensions'; export type { CatalogAnalysisExtensionPoint } from './extensions'; export { catalogAnalysisExtensionPoint } from './extensions'; +export type { + EntitiesSearchFilter, + CatalogPermissionRuleInput, +} from './extensions'; diff --git a/plugins/catalog-node/src/extensions.ts b/plugins/catalog-node/src/extensions.ts index 6516653150..a165cd15cc 100644 --- a/plugins/catalog-node/src/extensions.ts +++ b/plugins/catalog-node/src/extensions.ts @@ -24,11 +24,18 @@ import { ScmLocationAnalyzer, } from '@backstage/plugin-catalog-node'; -type EntitiesSearchFilter = { +/** + * @alpha + */ +export type EntitiesSearchFilter = { key: string; values?: string[]; }; -type CatalogPermissionRuleInput< + +/** + * @alpha + */ +export type CatalogPermissionRuleInput< TParams extends PermissionRuleParams = PermissionRuleParams, > = PermissionRule; From 1663303ab8446b008cfd0547af588605248a11ad Mon Sep 17 00:00:00 2001 From: lshwayne96 Date: Thu, 23 Nov 2023 10:50:23 +0800 Subject: [PATCH 234/261] Add new extension point for catalog permissions Signed-off-by: lshwayne96 --- .changeset/wild-knives-wait.md | 2 +- .../src/service/CatalogPlugin.ts | 41 ++++++++----- plugins/catalog-node/api-report-alpha.md | 19 ++++-- plugins/catalog-node/src/alpha.ts | 2 + plugins/catalog-node/src/extensions.ts | 60 ++++++++++++------- 5 files changed, 80 insertions(+), 44 deletions(-) diff --git a/.changeset/wild-knives-wait.md b/.changeset/wild-knives-wait.md index 460712b5d9..6aafbe7acd 100644 --- a/.changeset/wild-knives-wait.md +++ b/.changeset/wild-knives-wait.md @@ -3,4 +3,4 @@ '@backstage/plugin-catalog-node': minor --- -Permission rules can now be added for the Catalog plugin through the `CatalogProcessingExtensionPoint` interface. +Permission rules can now be added for the Catalog plugin through the `CatalogPermissionExtensionPoint` interface. diff --git a/plugins/catalog-backend/src/service/CatalogPlugin.ts b/plugins/catalog-backend/src/service/CatalogPlugin.ts index 844f56e766..0800d41340 100644 --- a/plugins/catalog-backend/src/service/CatalogPlugin.ts +++ b/plugins/catalog-backend/src/service/CatalogPlugin.ts @@ -23,6 +23,8 @@ import { catalogAnalysisExtensionPoint, CatalogProcessingExtensionPoint, catalogProcessingExtensionPoint, + CatalogPermissionExtensionPoint, + catalogPermissionExtensionPoint, } from '@backstage/plugin-catalog-node/alpha'; import { CatalogProcessor, @@ -38,7 +40,6 @@ class CatalogProcessingExtensionPointImpl #processors = new Array(); #entityProviders = new Array(); #placeholderResolvers: Record = {}; - #permissionRules = new Array(); addProcessor( ...processors: Array> @@ -60,14 +61,6 @@ class CatalogProcessingExtensionPointImpl this.#placeholderResolvers[key] = resolver; } - addPermissionRules( - ...rules: Array< - CatalogPermissionRuleInput | Array - > - ): void { - this.#permissionRules.push(...rules.flat()); - } - get processors() { return this.#processors; } @@ -79,10 +72,6 @@ class CatalogProcessingExtensionPointImpl get placeholderResolvers() { return this.#placeholderResolvers; } - - get permissionRules() { - return this.#permissionRules; - } } class CatalogAnalysisExtensionPointImpl @@ -99,6 +88,24 @@ class CatalogAnalysisExtensionPointImpl } } +class CatalogPermissionExtensionPointImpl + implements CatalogPermissionExtensionPoint +{ + #permissionRules = new Array(); + + addPermissionRules( + ...rules: Array< + CatalogPermissionRuleInput | Array + > + ): void { + this.#permissionRules.push(...rules.flat()); + } + + get permissionRules() { + return this.#permissionRules; + } +} + /** * Catalog plugin * @alpha @@ -119,6 +126,12 @@ export const catalogPlugin = createBackendPlugin({ analysisExtensions, ); + const permissionExtensions = new CatalogPermissionExtensionPointImpl(); + env.registerExtensionPoint( + catalogPermissionExtensionPoint, + permissionExtensions, + ); + env.registerInit({ deps: { logger: coreServices.logger, @@ -155,7 +168,7 @@ export const catalogPlugin = createBackendPlugin({ ([key, resolver]) => builder.setPlaceholderResolver(key, resolver), ); builder.addLocationAnalyzers(...analysisExtensions.locationAnalyzers); - builder.addPermissionRules(...processingExtensions.permissionRules); + builder.addPermissionRules(...permissionExtensions.permissionRules); const { processingEngine, router } = await builder.build(); diff --git a/plugins/catalog-node/api-report-alpha.md b/plugins/catalog-node/api-report-alpha.md index 676115c4d9..7350f9262c 100644 --- a/plugins/catalog-node/api-report-alpha.md +++ b/plugins/catalog-node/api-report-alpha.md @@ -23,6 +23,19 @@ export interface CatalogAnalysisExtensionPoint { // @alpha (undocumented) export const catalogAnalysisExtensionPoint: ExtensionPoint; +// @alpha (undocumented) +export interface CatalogPermissionExtensionPoint { + // (undocumented) + addPermissionRules( + ...rules: Array< + CatalogPermissionRuleInput | Array + > + ): void; +} + +// @alpha (undocumented) +export const catalogPermissionExtensionPoint: ExtensionPoint; + // @alpha (undocumented) export type CatalogPermissionRuleInput< TParams extends PermissionRuleParams = PermissionRuleParams, @@ -35,12 +48,6 @@ export interface CatalogProcessingExtensionPoint { ...providers: Array> ): void; // (undocumented) - addPermissionRules( - ...rules: Array< - CatalogPermissionRuleInput | Array - > - ): void; - // (undocumented) addPlaceholderResolver(key: string, resolver: PlaceholderResolver): void; // (undocumented) addProcessor( diff --git a/plugins/catalog-node/src/alpha.ts b/plugins/catalog-node/src/alpha.ts index 3d6194f986..f7b2ceac12 100644 --- a/plugins/catalog-node/src/alpha.ts +++ b/plugins/catalog-node/src/alpha.ts @@ -23,3 +23,5 @@ export type { EntitiesSearchFilter, CatalogPermissionRuleInput, } from './extensions'; +export type { CatalogPermissionExtensionPoint } from './extensions'; +export { catalogPermissionExtensionPoint } from './extensions'; diff --git a/plugins/catalog-node/src/extensions.ts b/plugins/catalog-node/src/extensions.ts index a165cd15cc..2dd0915ccf 100644 --- a/plugins/catalog-node/src/extensions.ts +++ b/plugins/catalog-node/src/extensions.ts @@ -14,30 +14,15 @@ * limitations under the License. */ import { createExtensionPoint } from '@backstage/backend-plugin-api'; -import { Entity } from '@backstage/catalog-model'; -import { PermissionRuleParams } from '@backstage/plugin-permission-common'; -import { PermissionRule } from '@backstage/plugin-permission-node'; import { EntityProvider, CatalogProcessor, PlaceholderResolver, ScmLocationAnalyzer, } from '@backstage/plugin-catalog-node'; - -/** - * @alpha - */ -export type EntitiesSearchFilter = { - key: string; - values?: string[]; -}; - -/** - * @alpha - */ -export type CatalogPermissionRuleInput< - TParams extends PermissionRuleParams = PermissionRuleParams, -> = PermissionRule; +import { Entity } from '@backstage/catalog-model'; +import { PermissionRuleParams } from '@backstage/plugin-permission-common'; +import { PermissionRule } from '@backstage/plugin-permission-node'; /** * @alpha @@ -50,11 +35,6 @@ export interface CatalogProcessingExtensionPoint { ...providers: Array> ): void; addPlaceholderResolver(key: string, resolver: PlaceholderResolver): void; - addPermissionRules( - ...rules: Array< - CatalogPermissionRuleInput | Array - > - ): void; } /** @@ -79,3 +59,37 @@ export const catalogAnalysisExtensionPoint = createExtensionPoint({ id: 'catalog.analysis', }); + +/** + * @alpha + */ +export type EntitiesSearchFilter = { + key: string; + values?: string[]; +}; + +/** + * @alpha + */ +export type CatalogPermissionRuleInput< + TParams extends PermissionRuleParams = PermissionRuleParams, +> = PermissionRule; + +/** + * @alpha + */ +export interface CatalogPermissionExtensionPoint { + addPermissionRules( + ...rules: Array< + CatalogPermissionRuleInput | Array + > + ): void; +} + +/** + * @alpha + */ +export const catalogPermissionExtensionPoint = + createExtensionPoint({ + id: 'catalog.permission', + }); From fdb2a51fa39fb4680002992399a2426dc3fdd206 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 29 Nov 2023 18:56:18 +0000 Subject: [PATCH 235/261] fix(deps): update aws-sdk-js-v3 monorepo Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 562 +++++++++++++++++++++++++++--------------------------- 1 file changed, 283 insertions(+), 279 deletions(-) diff --git a/yarn.lock b/yarn.lock index d300613993..1f74e5c7e7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -397,25 +397,25 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/client-cognito-identity@npm:3.458.0": - version: 3.458.0 - resolution: "@aws-sdk/client-cognito-identity@npm:3.458.0" +"@aws-sdk/client-cognito-identity@npm:3.461.0": + version: 3.461.0 + resolution: "@aws-sdk/client-cognito-identity@npm:3.461.0" dependencies: "@aws-crypto/sha256-browser": 3.0.0 "@aws-crypto/sha256-js": 3.0.0 - "@aws-sdk/client-sts": 3.458.0 + "@aws-sdk/client-sts": 3.461.0 "@aws-sdk/core": 3.451.0 - "@aws-sdk/credential-provider-node": 3.458.0 - "@aws-sdk/middleware-host-header": 3.451.0 - "@aws-sdk/middleware-logger": 3.451.0 - "@aws-sdk/middleware-recursion-detection": 3.451.0 - "@aws-sdk/middleware-signing": 3.451.0 - "@aws-sdk/middleware-user-agent": 3.451.0 + "@aws-sdk/credential-provider-node": 3.460.0 + "@aws-sdk/middleware-host-header": 3.460.0 + "@aws-sdk/middleware-logger": 3.460.0 + "@aws-sdk/middleware-recursion-detection": 3.460.0 + "@aws-sdk/middleware-signing": 3.461.0 + "@aws-sdk/middleware-user-agent": 3.460.0 "@aws-sdk/region-config-resolver": 3.451.0 - "@aws-sdk/types": 3.451.0 - "@aws-sdk/util-endpoints": 3.451.0 - "@aws-sdk/util-user-agent-browser": 3.451.0 - "@aws-sdk/util-user-agent-node": 3.451.0 + "@aws-sdk/types": 3.460.0 + "@aws-sdk/util-endpoints": 3.460.0 + "@aws-sdk/util-user-agent-browser": 3.460.0 + "@aws-sdk/util-user-agent-node": 3.460.0 "@smithy/config-resolver": ^2.0.18 "@smithy/fetch-http-handler": ^2.2.6 "@smithy/hash-node": ^2.0.15 @@ -440,29 +440,29 @@ __metadata: "@smithy/util-retry": ^2.0.6 "@smithy/util-utf8": ^2.0.2 tslib: ^2.5.0 - checksum: 2376be696bfabf2ebb1d868af8bbd9d49a0a8962ec0d49b8adb156b9c45313db066af4339967d3d572d0ccc55b3a1a993665ffc7627c5b0a2f4639ab352f27cd + checksum: 8f898c4469516e2f0d835d31f071213769405085123628c73c7ca70c8edc1d8f9551778bd7ac74d31f73bddc60929d0f7623ed65d49fcc2786d76c2a81b20e8d languageName: node linkType: hard "@aws-sdk/client-eks@npm:^3.350.0": - version: 3.458.0 - resolution: "@aws-sdk/client-eks@npm:3.458.0" + version: 3.461.0 + resolution: "@aws-sdk/client-eks@npm:3.461.0" dependencies: "@aws-crypto/sha256-browser": 3.0.0 "@aws-crypto/sha256-js": 3.0.0 - "@aws-sdk/client-sts": 3.458.0 + "@aws-sdk/client-sts": 3.461.0 "@aws-sdk/core": 3.451.0 - "@aws-sdk/credential-provider-node": 3.458.0 - "@aws-sdk/middleware-host-header": 3.451.0 - "@aws-sdk/middleware-logger": 3.451.0 - "@aws-sdk/middleware-recursion-detection": 3.451.0 - "@aws-sdk/middleware-signing": 3.451.0 - "@aws-sdk/middleware-user-agent": 3.451.0 + "@aws-sdk/credential-provider-node": 3.460.0 + "@aws-sdk/middleware-host-header": 3.460.0 + "@aws-sdk/middleware-logger": 3.460.0 + "@aws-sdk/middleware-recursion-detection": 3.460.0 + "@aws-sdk/middleware-signing": 3.461.0 + "@aws-sdk/middleware-user-agent": 3.460.0 "@aws-sdk/region-config-resolver": 3.451.0 - "@aws-sdk/types": 3.451.0 - "@aws-sdk/util-endpoints": 3.451.0 - "@aws-sdk/util-user-agent-browser": 3.451.0 - "@aws-sdk/util-user-agent-node": 3.451.0 + "@aws-sdk/types": 3.460.0 + "@aws-sdk/util-endpoints": 3.460.0 + "@aws-sdk/util-user-agent-browser": 3.460.0 + "@aws-sdk/util-user-agent-node": 3.460.0 "@smithy/config-resolver": ^2.0.18 "@smithy/fetch-http-handler": ^2.2.6 "@smithy/hash-node": ^2.0.15 @@ -489,29 +489,29 @@ __metadata: "@smithy/util-waiter": ^2.0.13 tslib: ^2.5.0 uuid: ^8.3.2 - checksum: 7bbafbab55c92633f19d6e53abc9e3d76f36533b68eee7c367c21c8ca72e43e7a4bae4bc33a102228bdc773d0d6fb8633855bc2034c3cbf539befe6d4c30996c + checksum: 7bf17138ac0e14f2381c4fc275b7287453749b70e12d2b74168b62ec78f90f13e83b552c08ee10accfd7344367c6d49a1e5ac2f513d3da5a7e9cb9d2524fe262 languageName: node linkType: hard "@aws-sdk/client-organizations@npm:^3.350.0": - version: 3.458.0 - resolution: "@aws-sdk/client-organizations@npm:3.458.0" + version: 3.461.0 + resolution: "@aws-sdk/client-organizations@npm:3.461.0" dependencies: "@aws-crypto/sha256-browser": 3.0.0 "@aws-crypto/sha256-js": 3.0.0 - "@aws-sdk/client-sts": 3.458.0 + "@aws-sdk/client-sts": 3.461.0 "@aws-sdk/core": 3.451.0 - "@aws-sdk/credential-provider-node": 3.458.0 - "@aws-sdk/middleware-host-header": 3.451.0 - "@aws-sdk/middleware-logger": 3.451.0 - "@aws-sdk/middleware-recursion-detection": 3.451.0 - "@aws-sdk/middleware-signing": 3.451.0 - "@aws-sdk/middleware-user-agent": 3.451.0 + "@aws-sdk/credential-provider-node": 3.460.0 + "@aws-sdk/middleware-host-header": 3.460.0 + "@aws-sdk/middleware-logger": 3.460.0 + "@aws-sdk/middleware-recursion-detection": 3.460.0 + "@aws-sdk/middleware-signing": 3.461.0 + "@aws-sdk/middleware-user-agent": 3.460.0 "@aws-sdk/region-config-resolver": 3.451.0 - "@aws-sdk/types": 3.451.0 - "@aws-sdk/util-endpoints": 3.451.0 - "@aws-sdk/util-user-agent-browser": 3.451.0 - "@aws-sdk/util-user-agent-node": 3.451.0 + "@aws-sdk/types": 3.460.0 + "@aws-sdk/util-endpoints": 3.460.0 + "@aws-sdk/util-user-agent-browser": 3.460.0 + "@aws-sdk/util-user-agent-node": 3.460.0 "@smithy/config-resolver": ^2.0.18 "@smithy/fetch-http-handler": ^2.2.6 "@smithy/hash-node": ^2.0.15 @@ -536,37 +536,37 @@ __metadata: "@smithy/util-retry": ^2.0.6 "@smithy/util-utf8": ^2.0.2 tslib: ^2.5.0 - checksum: 396453eb2a76c4a99d2250f43acc32f7db73bf19ff6f7580da6756f0beaaff01b9b94dc2dfb3aa60c244cedcf61901b7339d29a5a4b2e3615006d7a62b510be2 + checksum: 38cfcf405e4061c5ebd88c6726fdd2cfcd8f6a6c68a896b5590cc37d36d5b9ad32a4699ae8b4e2f39a94d4abb7fc16f2acebcf047062ff95ef95dc6a3d6042d5 languageName: node linkType: hard "@aws-sdk/client-s3@npm:^3.350.0": - version: 3.458.0 - resolution: "@aws-sdk/client-s3@npm:3.458.0" + version: 3.461.0 + resolution: "@aws-sdk/client-s3@npm:3.461.0" dependencies: "@aws-crypto/sha1-browser": 3.0.0 "@aws-crypto/sha256-browser": 3.0.0 "@aws-crypto/sha256-js": 3.0.0 - "@aws-sdk/client-sts": 3.458.0 + "@aws-sdk/client-sts": 3.461.0 "@aws-sdk/core": 3.451.0 - "@aws-sdk/credential-provider-node": 3.458.0 - "@aws-sdk/middleware-bucket-endpoint": 3.451.0 - "@aws-sdk/middleware-expect-continue": 3.451.0 - "@aws-sdk/middleware-flexible-checksums": 3.451.0 - "@aws-sdk/middleware-host-header": 3.451.0 - "@aws-sdk/middleware-location-constraint": 3.451.0 - "@aws-sdk/middleware-logger": 3.451.0 - "@aws-sdk/middleware-recursion-detection": 3.451.0 - "@aws-sdk/middleware-sdk-s3": 3.451.0 - "@aws-sdk/middleware-signing": 3.451.0 - "@aws-sdk/middleware-ssec": 3.451.0 - "@aws-sdk/middleware-user-agent": 3.451.0 + "@aws-sdk/credential-provider-node": 3.460.0 + "@aws-sdk/middleware-bucket-endpoint": 3.460.0 + "@aws-sdk/middleware-expect-continue": 3.460.0 + "@aws-sdk/middleware-flexible-checksums": 3.461.0 + "@aws-sdk/middleware-host-header": 3.460.0 + "@aws-sdk/middleware-location-constraint": 3.461.0 + "@aws-sdk/middleware-logger": 3.460.0 + "@aws-sdk/middleware-recursion-detection": 3.460.0 + "@aws-sdk/middleware-sdk-s3": 3.461.0 + "@aws-sdk/middleware-signing": 3.461.0 + "@aws-sdk/middleware-ssec": 3.460.0 + "@aws-sdk/middleware-user-agent": 3.460.0 "@aws-sdk/region-config-resolver": 3.451.0 - "@aws-sdk/signature-v4-multi-region": 3.451.0 - "@aws-sdk/types": 3.451.0 - "@aws-sdk/util-endpoints": 3.451.0 - "@aws-sdk/util-user-agent-browser": 3.451.0 - "@aws-sdk/util-user-agent-node": 3.451.0 + "@aws-sdk/signature-v4-multi-region": 3.461.0 + "@aws-sdk/types": 3.460.0 + "@aws-sdk/util-endpoints": 3.460.0 + "@aws-sdk/util-user-agent-browser": 3.460.0 + "@aws-sdk/util-user-agent-node": 3.460.0 "@aws-sdk/xml-builder": 3.310.0 "@smithy/config-resolver": ^2.0.18 "@smithy/eventstream-serde-browser": ^2.0.13 @@ -601,30 +601,30 @@ __metadata: "@smithy/util-waiter": ^2.0.13 fast-xml-parser: 4.2.5 tslib: ^2.5.0 - checksum: 7b4ec3928262688224bc2ca68a5319e888847d9657cf12fef15cd579e266f8d0c03d6965e482f2b528ad3e1e93b5495c9dd45b064c9e35151615deac74608cd7 + checksum: e7411d29b59fa19a3d960bb4dbbca967e8ef8b31c682c2cb9630511af19e9788471bc987700b39857f95687c25db1ec73661a9b20507c4260f5f10539be3f9d9 languageName: node linkType: hard "@aws-sdk/client-sqs@npm:^3.350.0": - version: 3.458.0 - resolution: "@aws-sdk/client-sqs@npm:3.458.0" + version: 3.461.0 + resolution: "@aws-sdk/client-sqs@npm:3.461.0" dependencies: "@aws-crypto/sha256-browser": 3.0.0 "@aws-crypto/sha256-js": 3.0.0 - "@aws-sdk/client-sts": 3.458.0 + "@aws-sdk/client-sts": 3.461.0 "@aws-sdk/core": 3.451.0 - "@aws-sdk/credential-provider-node": 3.458.0 - "@aws-sdk/middleware-host-header": 3.451.0 - "@aws-sdk/middleware-logger": 3.451.0 - "@aws-sdk/middleware-recursion-detection": 3.451.0 - "@aws-sdk/middleware-sdk-sqs": 3.451.0 - "@aws-sdk/middleware-signing": 3.451.0 - "@aws-sdk/middleware-user-agent": 3.451.0 + "@aws-sdk/credential-provider-node": 3.460.0 + "@aws-sdk/middleware-host-header": 3.460.0 + "@aws-sdk/middleware-logger": 3.460.0 + "@aws-sdk/middleware-recursion-detection": 3.460.0 + "@aws-sdk/middleware-sdk-sqs": 3.460.0 + "@aws-sdk/middleware-signing": 3.461.0 + "@aws-sdk/middleware-user-agent": 3.460.0 "@aws-sdk/region-config-resolver": 3.451.0 - "@aws-sdk/types": 3.451.0 - "@aws-sdk/util-endpoints": 3.451.0 - "@aws-sdk/util-user-agent-browser": 3.451.0 - "@aws-sdk/util-user-agent-node": 3.451.0 + "@aws-sdk/types": 3.460.0 + "@aws-sdk/util-endpoints": 3.460.0 + "@aws-sdk/util-user-agent-browser": 3.460.0 + "@aws-sdk/util-user-agent-node": 3.460.0 "@smithy/config-resolver": ^2.0.18 "@smithy/fetch-http-handler": ^2.2.6 "@smithy/hash-node": ^2.0.15 @@ -650,26 +650,26 @@ __metadata: "@smithy/util-retry": ^2.0.6 "@smithy/util-utf8": ^2.0.2 tslib: ^2.5.0 - checksum: 7352d83ea0ac3d846911e20329f8817efb42a38391a7f627331be6b42e6fed41cbbaa800e3177c4ab850faae25a435d3da864b100a587ab515da115899f4b2e4 + checksum: c72dd8822d25646200db96b506f770a8d12480bf25a42d6780289feb0f4eb4b49967615b96de4e28e9fb6b034d5f050f40b279fde58dd75c0cb769d948de243c languageName: node linkType: hard -"@aws-sdk/client-sso@npm:3.458.0": - version: 3.458.0 - resolution: "@aws-sdk/client-sso@npm:3.458.0" +"@aws-sdk/client-sso@npm:3.460.0": + version: 3.460.0 + resolution: "@aws-sdk/client-sso@npm:3.460.0" dependencies: "@aws-crypto/sha256-browser": 3.0.0 "@aws-crypto/sha256-js": 3.0.0 "@aws-sdk/core": 3.451.0 - "@aws-sdk/middleware-host-header": 3.451.0 - "@aws-sdk/middleware-logger": 3.451.0 - "@aws-sdk/middleware-recursion-detection": 3.451.0 - "@aws-sdk/middleware-user-agent": 3.451.0 + "@aws-sdk/middleware-host-header": 3.460.0 + "@aws-sdk/middleware-logger": 3.460.0 + "@aws-sdk/middleware-recursion-detection": 3.460.0 + "@aws-sdk/middleware-user-agent": 3.460.0 "@aws-sdk/region-config-resolver": 3.451.0 - "@aws-sdk/types": 3.451.0 - "@aws-sdk/util-endpoints": 3.451.0 - "@aws-sdk/util-user-agent-browser": 3.451.0 - "@aws-sdk/util-user-agent-node": 3.451.0 + "@aws-sdk/types": 3.460.0 + "@aws-sdk/util-endpoints": 3.460.0 + "@aws-sdk/util-user-agent-browser": 3.460.0 + "@aws-sdk/util-user-agent-node": 3.460.0 "@smithy/config-resolver": ^2.0.18 "@smithy/fetch-http-handler": ^2.2.6 "@smithy/hash-node": ^2.0.15 @@ -694,29 +694,29 @@ __metadata: "@smithy/util-retry": ^2.0.6 "@smithy/util-utf8": ^2.0.2 tslib: ^2.5.0 - checksum: fd10ceb68526320f7302c206901f432fd7e09a7c65301f05b3e4c6d36764a7241f2984e2fb7c95cbece0d2e9a65aaa672121b1847cf368cc4c7fa0e5c1805bba + checksum: 902edb7c8ff29c68a6e179473b3a5431b73182d2492d2b9d69617717d9ef365aad9286ae33a57fc8c42206bea29da29e63d7a36c5969f5b6039e49e535f2d2f3 languageName: node linkType: hard -"@aws-sdk/client-sts@npm:3.458.0, @aws-sdk/client-sts@npm:^3.350.0": - version: 3.458.0 - resolution: "@aws-sdk/client-sts@npm:3.458.0" +"@aws-sdk/client-sts@npm:3.461.0, @aws-sdk/client-sts@npm:^3.350.0": + version: 3.461.0 + resolution: "@aws-sdk/client-sts@npm:3.461.0" dependencies: "@aws-crypto/sha256-browser": 3.0.0 "@aws-crypto/sha256-js": 3.0.0 "@aws-sdk/core": 3.451.0 - "@aws-sdk/credential-provider-node": 3.458.0 - "@aws-sdk/middleware-host-header": 3.451.0 - "@aws-sdk/middleware-logger": 3.451.0 - "@aws-sdk/middleware-recursion-detection": 3.451.0 - "@aws-sdk/middleware-sdk-sts": 3.451.0 - "@aws-sdk/middleware-signing": 3.451.0 - "@aws-sdk/middleware-user-agent": 3.451.0 + "@aws-sdk/credential-provider-node": 3.460.0 + "@aws-sdk/middleware-host-header": 3.460.0 + "@aws-sdk/middleware-logger": 3.460.0 + "@aws-sdk/middleware-recursion-detection": 3.460.0 + "@aws-sdk/middleware-sdk-sts": 3.461.0 + "@aws-sdk/middleware-signing": 3.461.0 + "@aws-sdk/middleware-user-agent": 3.460.0 "@aws-sdk/region-config-resolver": 3.451.0 - "@aws-sdk/types": 3.451.0 - "@aws-sdk/util-endpoints": 3.451.0 - "@aws-sdk/util-user-agent-browser": 3.451.0 - "@aws-sdk/util-user-agent-node": 3.451.0 + "@aws-sdk/types": 3.460.0 + "@aws-sdk/util-endpoints": 3.460.0 + "@aws-sdk/util-user-agent-browser": 3.460.0 + "@aws-sdk/util-user-agent-node": 3.460.0 "@smithy/config-resolver": ^2.0.18 "@smithy/fetch-http-handler": ^2.2.6 "@smithy/hash-node": ^2.0.15 @@ -742,7 +742,7 @@ __metadata: "@smithy/util-utf8": ^2.0.2 fast-xml-parser: 4.2.5 tslib: ^2.5.0 - checksum: 167a07c100103ef12e74c83be1dd115f583843308e1f3430eec030b2932edecfb665df2158c9131f7eeb0df41e665b7419a443e8689b1aa732bc5a413a0b4fad + checksum: c5a665212815ae606c48b11b38cea41bfbc7f6c422f44eb51d71bf748cd8275ac4ac7e03207b992e58e43c46f7f4070d551dcd4dd3cbe704a72fa7d7b3efe613 languageName: node linkType: hard @@ -756,36 +756,36 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/credential-provider-cognito-identity@npm:3.458.0": - version: 3.458.0 - resolution: "@aws-sdk/credential-provider-cognito-identity@npm:3.458.0" +"@aws-sdk/credential-provider-cognito-identity@npm:3.461.0": + version: 3.461.0 + resolution: "@aws-sdk/credential-provider-cognito-identity@npm:3.461.0" dependencies: - "@aws-sdk/client-cognito-identity": 3.458.0 - "@aws-sdk/types": 3.451.0 + "@aws-sdk/client-cognito-identity": 3.461.0 + "@aws-sdk/types": 3.460.0 "@smithy/property-provider": ^2.0.0 "@smithy/types": ^2.5.0 tslib: ^2.5.0 - checksum: a2e59ac5743913eb828ca520c7dd972994c9a9f5e63a1f5df49deba1264acffbe35dc6418dd03198dd1bc888855666c7646d9811694bc4aa00fd12984b2ec55e + checksum: 3448131b14b652726a2298b8ce9bb5eb5fac403eb381d70292ca879c4a4d9ccf834f9768033d0913b6f74d8654cacf5fc8493963bc675d521f371654c67daca2 languageName: node linkType: hard -"@aws-sdk/credential-provider-env@npm:3.451.0": - version: 3.451.0 - resolution: "@aws-sdk/credential-provider-env@npm:3.451.0" +"@aws-sdk/credential-provider-env@npm:3.460.0": + version: 3.460.0 + resolution: "@aws-sdk/credential-provider-env@npm:3.460.0" dependencies: - "@aws-sdk/types": 3.451.0 + "@aws-sdk/types": 3.460.0 "@smithy/property-provider": ^2.0.0 "@smithy/types": ^2.5.0 tslib: ^2.5.0 - checksum: 20268e3d30317ab92cfce042fbaf751959d8da8e5669b822f8089df26bf5ea4972bab04eb0653fd903a4ab6c41118fae57f589a7e05fd3022e0154cb0cd71ed7 + checksum: a5b3bb0c9d9b05f9b55738b99db33bc894b6b1e30c1ec62b9124f5a3878b24f23b1f26d38fb0ade06bf12c0ea1c4a0d67d197e43f45bb4fd88bdb19249078e72 languageName: node linkType: hard -"@aws-sdk/credential-provider-http@npm:3.451.0": - version: 3.451.0 - resolution: "@aws-sdk/credential-provider-http@npm:3.451.0" +"@aws-sdk/credential-provider-http@npm:3.460.0": + version: 3.460.0 + resolution: "@aws-sdk/credential-provider-http@npm:3.460.0" dependencies: - "@aws-sdk/types": 3.451.0 + "@aws-sdk/types": 3.460.0 "@smithy/fetch-http-handler": ^2.2.6 "@smithy/node-http-handler": ^2.1.9 "@smithy/property-provider": ^2.0.0 @@ -794,108 +794,108 @@ __metadata: "@smithy/types": ^2.5.0 "@smithy/util-stream": ^2.0.20 tslib: ^2.5.0 - checksum: 72d6c1487a24a95e765b665a0d2fb337fc86bb426f1fc999f7a2789a826302a649850791ec428eff13e250b4bf0e33f9d333dc3c34cfb15c83c863c254f601df + checksum: 3e43978179dc869920ce2cc7b4e075bde4e5e948b6c0533ac58393790bed49be38c336233cadc4b52c13aa2df442693a29f0067026f178f2d0ba8034c4de14d9 languageName: node linkType: hard -"@aws-sdk/credential-provider-ini@npm:3.458.0": - version: 3.458.0 - resolution: "@aws-sdk/credential-provider-ini@npm:3.458.0" +"@aws-sdk/credential-provider-ini@npm:3.460.0": + version: 3.460.0 + resolution: "@aws-sdk/credential-provider-ini@npm:3.460.0" dependencies: - "@aws-sdk/credential-provider-env": 3.451.0 - "@aws-sdk/credential-provider-process": 3.451.0 - "@aws-sdk/credential-provider-sso": 3.458.0 - "@aws-sdk/credential-provider-web-identity": 3.451.0 - "@aws-sdk/types": 3.451.0 + "@aws-sdk/credential-provider-env": 3.460.0 + "@aws-sdk/credential-provider-process": 3.460.0 + "@aws-sdk/credential-provider-sso": 3.460.0 + "@aws-sdk/credential-provider-web-identity": 3.460.0 + "@aws-sdk/types": 3.460.0 "@smithy/credential-provider-imds": ^2.0.0 "@smithy/property-provider": ^2.0.0 "@smithy/shared-ini-file-loader": ^2.0.6 "@smithy/types": ^2.5.0 tslib: ^2.5.0 - checksum: 23d4d9e5007a3b6214a027cc7a64f50879bdecf3702d799157f586427c9862cbde166512e52aa86e6306ab12058f06178d268d4ef8cc40aedf822d6d4d90e901 + checksum: dcb6d94dfaa98971188102ac277746b8226cba4d76d589b47dbd17af271cba52d97606863912699c123d9671ae2b32a92d05a2306b749c909ebeaf1f95a566fb languageName: node linkType: hard -"@aws-sdk/credential-provider-node@npm:3.458.0, @aws-sdk/credential-provider-node@npm:^3.350.0": - version: 3.458.0 - resolution: "@aws-sdk/credential-provider-node@npm:3.458.0" +"@aws-sdk/credential-provider-node@npm:3.460.0, @aws-sdk/credential-provider-node@npm:^3.350.0": + version: 3.460.0 + resolution: "@aws-sdk/credential-provider-node@npm:3.460.0" dependencies: - "@aws-sdk/credential-provider-env": 3.451.0 - "@aws-sdk/credential-provider-ini": 3.458.0 - "@aws-sdk/credential-provider-process": 3.451.0 - "@aws-sdk/credential-provider-sso": 3.458.0 - "@aws-sdk/credential-provider-web-identity": 3.451.0 - "@aws-sdk/types": 3.451.0 + "@aws-sdk/credential-provider-env": 3.460.0 + "@aws-sdk/credential-provider-ini": 3.460.0 + "@aws-sdk/credential-provider-process": 3.460.0 + "@aws-sdk/credential-provider-sso": 3.460.0 + "@aws-sdk/credential-provider-web-identity": 3.460.0 + "@aws-sdk/types": 3.460.0 "@smithy/credential-provider-imds": ^2.0.0 "@smithy/property-provider": ^2.0.0 "@smithy/shared-ini-file-loader": ^2.0.6 "@smithy/types": ^2.5.0 tslib: ^2.5.0 - checksum: 94dad3e9df77e565bb689a76e819e7250e0d4698e49452d761664444347da41816305f77d03464a1f1b447cdb5078269a4b350a896244a769958f792f1a5d040 + checksum: e8ba989a219c75abfcdb9447622a933fd7c601bcbc41e535627d0bee514773c970dd86342baf23e0d241695c96d3e90d19bc028c598b87fdad6a025c16690bf5 languageName: node linkType: hard -"@aws-sdk/credential-provider-process@npm:3.451.0": - version: 3.451.0 - resolution: "@aws-sdk/credential-provider-process@npm:3.451.0" +"@aws-sdk/credential-provider-process@npm:3.460.0": + version: 3.460.0 + resolution: "@aws-sdk/credential-provider-process@npm:3.460.0" dependencies: - "@aws-sdk/types": 3.451.0 + "@aws-sdk/types": 3.460.0 "@smithy/property-provider": ^2.0.0 "@smithy/shared-ini-file-loader": ^2.0.6 "@smithy/types": ^2.5.0 tslib: ^2.5.0 - checksum: 2c01b893d03f9a001bb970553bad14061e807445ec96002bb85d37445fa28403a5adbfc68036f01fc20d7c5310e88ccbcd96cd54d5ba9326640a18d6c96b93a2 + checksum: 67115399ef754dd46138ce086936f0bf680cc701ed12939a059c9fae7dda870829247e6f73c0f5e0d07353d151b77fe070ff50d5946cd21583b78dcbf25b2aab languageName: node linkType: hard -"@aws-sdk/credential-provider-sso@npm:3.458.0": - version: 3.458.0 - resolution: "@aws-sdk/credential-provider-sso@npm:3.458.0" +"@aws-sdk/credential-provider-sso@npm:3.460.0": + version: 3.460.0 + resolution: "@aws-sdk/credential-provider-sso@npm:3.460.0" dependencies: - "@aws-sdk/client-sso": 3.458.0 - "@aws-sdk/token-providers": 3.451.0 - "@aws-sdk/types": 3.451.0 + "@aws-sdk/client-sso": 3.460.0 + "@aws-sdk/token-providers": 3.460.0 + "@aws-sdk/types": 3.460.0 "@smithy/property-provider": ^2.0.0 "@smithy/shared-ini-file-loader": ^2.0.6 "@smithy/types": ^2.5.0 tslib: ^2.5.0 - checksum: fca1283a4203874f6416ccdf3ba541fee62cbdf95677e5bcfeca9bb9a86c57ee37f204e30729ceb0cc17c51d531b5072d753364fd103e5fe2fef6ac330b2ee44 + checksum: 5536ef6c8c5f2792e26f19e1d9a3a3503b5c38bc02da65372be805eb1ea69498a81759b3701fd9e0714c628a054d6a52de3d9b98430b23d8b1402f25760b3c54 languageName: node linkType: hard -"@aws-sdk/credential-provider-web-identity@npm:3.451.0": - version: 3.451.0 - resolution: "@aws-sdk/credential-provider-web-identity@npm:3.451.0" +"@aws-sdk/credential-provider-web-identity@npm:3.460.0": + version: 3.460.0 + resolution: "@aws-sdk/credential-provider-web-identity@npm:3.460.0" dependencies: - "@aws-sdk/types": 3.451.0 + "@aws-sdk/types": 3.460.0 "@smithy/property-provider": ^2.0.0 "@smithy/types": ^2.5.0 tslib: ^2.5.0 - checksum: 2f677b9e4f727b6c24ed64d1ba23f524d8d136394dc62376db7b60acf57938a911d178bcdc33688a0cb17b5f55e2cc4aa455473a4393864568cacd202a50ce44 + checksum: 76a069b1f0dce14234afed3bab3ed6c3d63f0fcfb7a2d63343d2b2c63526fb7c14de5e8943eafec451b89ff9899f5b0d327b36409bc4661165f5e429b495fc85 languageName: node linkType: hard "@aws-sdk/credential-providers@npm:^3.350.0": - version: 3.458.0 - resolution: "@aws-sdk/credential-providers@npm:3.458.0" + version: 3.461.0 + resolution: "@aws-sdk/credential-providers@npm:3.461.0" dependencies: - "@aws-sdk/client-cognito-identity": 3.458.0 - "@aws-sdk/client-sso": 3.458.0 - "@aws-sdk/client-sts": 3.458.0 - "@aws-sdk/credential-provider-cognito-identity": 3.458.0 - "@aws-sdk/credential-provider-env": 3.451.0 - "@aws-sdk/credential-provider-http": 3.451.0 - "@aws-sdk/credential-provider-ini": 3.458.0 - "@aws-sdk/credential-provider-node": 3.458.0 - "@aws-sdk/credential-provider-process": 3.451.0 - "@aws-sdk/credential-provider-sso": 3.458.0 - "@aws-sdk/credential-provider-web-identity": 3.451.0 - "@aws-sdk/types": 3.451.0 + "@aws-sdk/client-cognito-identity": 3.461.0 + "@aws-sdk/client-sso": 3.460.0 + "@aws-sdk/client-sts": 3.461.0 + "@aws-sdk/credential-provider-cognito-identity": 3.461.0 + "@aws-sdk/credential-provider-env": 3.460.0 + "@aws-sdk/credential-provider-http": 3.460.0 + "@aws-sdk/credential-provider-ini": 3.460.0 + "@aws-sdk/credential-provider-node": 3.460.0 + "@aws-sdk/credential-provider-process": 3.460.0 + "@aws-sdk/credential-provider-sso": 3.460.0 + "@aws-sdk/credential-provider-web-identity": 3.460.0 + "@aws-sdk/types": 3.460.0 "@smithy/credential-provider-imds": ^2.0.0 "@smithy/property-provider": ^2.0.0 "@smithy/types": ^2.5.0 tslib: ^2.5.0 - checksum: 5b57f869b96f90cdaf5f005f7cfd5a3e03e8a27f7763089b4d9942f586dc55996dfb90ddd66e5b1eb3a277f4d1333a50180adb68a437e054d92eed310b79c47a + checksum: da0f30eb3e3462740406cbcdd88798c54735f2de1dbaef387a1774b49ee41686cff90836e5a07ab234f2b64981244b818c2635b4a1278fc3ff4ede33b735e775 languageName: node linkType: hard @@ -921,8 +921,8 @@ __metadata: linkType: hard "@aws-sdk/lib-storage@npm:^3.350.0": - version: 3.458.0 - resolution: "@aws-sdk/lib-storage@npm:3.458.0" + version: 3.461.0 + resolution: "@aws-sdk/lib-storage@npm:3.461.0" dependencies: "@smithy/abort-controller": ^2.0.1 "@smithy/middleware-endpoint": ^2.2.0 @@ -933,22 +933,22 @@ __metadata: tslib: ^2.5.0 peerDependencies: "@aws-sdk/client-s3": ^3.0.0 - checksum: c05dde775ba46cb03a35e362ffb69eb4aafd08d80dbb8a514a20ebf0604e8e35f19df2a732165fa62a843edb9cb3ba66625ca366326608205071a36d26580dc8 + checksum: 46b3363880c1214c9d549b771a5c20405a6ca5535e0e6004254d30f9dce042297b85d800e72cec105dd643ebbb98e02bed4f414ed66f7122b0b8cf0a80dacf35 languageName: node linkType: hard -"@aws-sdk/middleware-bucket-endpoint@npm:3.451.0": - version: 3.451.0 - resolution: "@aws-sdk/middleware-bucket-endpoint@npm:3.451.0" +"@aws-sdk/middleware-bucket-endpoint@npm:3.460.0": + version: 3.460.0 + resolution: "@aws-sdk/middleware-bucket-endpoint@npm:3.460.0" dependencies: - "@aws-sdk/types": 3.451.0 + "@aws-sdk/types": 3.460.0 "@aws-sdk/util-arn-parser": 3.310.0 "@smithy/node-config-provider": ^2.1.5 "@smithy/protocol-http": ^3.0.9 "@smithy/types": ^2.5.0 "@smithy/util-config-provider": ^2.0.0 tslib: ^2.5.0 - checksum: 4fba4c2ca560fe9a482d59a374239b5c6bf63a9f49373b91d9b1ed3aced648f0198b7d3b82c14fa896ec5f465562871bf9c59c29ff2e3f94df88f4641ff2bf78 + checksum: c0c6bb73a6fe64718d438225176b07b6a84e41ddd83ca306fb1aaa92f21b17915497861853b79f4af52e0915bf8859cf3a425c9a2ad270e42bbf409031f70b95 languageName: node linkType: hard @@ -965,116 +965,119 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/middleware-expect-continue@npm:3.451.0": - version: 3.451.0 - resolution: "@aws-sdk/middleware-expect-continue@npm:3.451.0" +"@aws-sdk/middleware-expect-continue@npm:3.460.0": + version: 3.460.0 + resolution: "@aws-sdk/middleware-expect-continue@npm:3.460.0" dependencies: - "@aws-sdk/types": 3.451.0 + "@aws-sdk/types": 3.460.0 "@smithy/protocol-http": ^3.0.9 "@smithy/types": ^2.5.0 tslib: ^2.5.0 - checksum: 3bfe5a1fc8f3e8baaec650aa085cb7a1c79d8d5af41bd940c005ba9c3c6d4feca2b65513d3494fe986276f43154e829f95ce1de4d852a741d7900cd95b864c1a + checksum: b18d117ae409a4d219b796bed5cb8e0ae7ac6e5e5085efdf66f1a4790d312a9d5988b0f74f843337b3e0deff867712482c7a0d813effe70ec9c41f40007e7d28 languageName: node linkType: hard -"@aws-sdk/middleware-flexible-checksums@npm:3.451.0": - version: 3.451.0 - resolution: "@aws-sdk/middleware-flexible-checksums@npm:3.451.0" +"@aws-sdk/middleware-flexible-checksums@npm:3.461.0": + version: 3.461.0 + resolution: "@aws-sdk/middleware-flexible-checksums@npm:3.461.0" dependencies: "@aws-crypto/crc32": 3.0.0 "@aws-crypto/crc32c": 3.0.0 - "@aws-sdk/types": 3.451.0 + "@aws-sdk/types": 3.460.0 "@smithy/is-array-buffer": ^2.0.0 "@smithy/protocol-http": ^3.0.9 "@smithy/types": ^2.5.0 "@smithy/util-utf8": ^2.0.2 tslib: ^2.5.0 - checksum: 24f69c68437899286c19e68caf417e263529190f4e663c8e886a032090452c9cbaa0d6d25887a65a7234edb9d2657f847b2ff589aec2341852d727a174c94cf2 + checksum: 1e0af49e58b809400df1ffc7b72a5d694d6a35aab4f819d4fec3570a867d93fca101bd1a64e78d1b3838cfb6f753178ab98e7f6ed526d75184bf5760a9cb7948 languageName: node linkType: hard -"@aws-sdk/middleware-host-header@npm:3.451.0": - version: 3.451.0 - resolution: "@aws-sdk/middleware-host-header@npm:3.451.0" +"@aws-sdk/middleware-host-header@npm:3.460.0": + version: 3.460.0 + resolution: "@aws-sdk/middleware-host-header@npm:3.460.0" dependencies: - "@aws-sdk/types": 3.451.0 + "@aws-sdk/types": 3.460.0 "@smithy/protocol-http": ^3.0.9 "@smithy/types": ^2.5.0 tslib: ^2.5.0 - checksum: ba06894d88f5fdd06762de839e7542b1605c73474d7bf93e6b0b74a62e77c5f3f4dd612daaf76e9eff59447c95a73cfa69b29f9856f7282227eea31173db99ca + checksum: ff3f3bf367a6db742e4f3dc05a100e51f49eadbc19602b3f44ab97dad6002baa2e905d7575fe87a86dc32da4063395098e282336f7c56aad61cc04592d4fb61e languageName: node linkType: hard -"@aws-sdk/middleware-location-constraint@npm:3.451.0": - version: 3.451.0 - resolution: "@aws-sdk/middleware-location-constraint@npm:3.451.0" +"@aws-sdk/middleware-location-constraint@npm:3.461.0": + version: 3.461.0 + resolution: "@aws-sdk/middleware-location-constraint@npm:3.461.0" dependencies: - "@aws-sdk/types": 3.451.0 + "@aws-sdk/types": 3.460.0 "@smithy/types": ^2.5.0 tslib: ^2.5.0 - checksum: d47ea96b28c429196352f2e99cbd5a3ab57726e0be0bfdb2d9ef7acb1e492a4a318f7c40e54bd14ce3b8d3f6f340e1fa89fcd5e3c62cf4e1f8edf08edd78b98b + checksum: 5d9a206dde792df6d703fa5edc0902fed658a1be0c75adb1ebe10018edff5eb3be7ab58a78d71d0112fd96648c1ef2879a5b2f4a1f449133b2ebb0281aeafe4f languageName: node linkType: hard -"@aws-sdk/middleware-logger@npm:3.451.0": - version: 3.451.0 - resolution: "@aws-sdk/middleware-logger@npm:3.451.0" +"@aws-sdk/middleware-logger@npm:3.460.0": + version: 3.460.0 + resolution: "@aws-sdk/middleware-logger@npm:3.460.0" dependencies: - "@aws-sdk/types": 3.451.0 + "@aws-sdk/types": 3.460.0 "@smithy/types": ^2.5.0 tslib: ^2.5.0 - checksum: 34342389013ab83407c34eb58a5e162fb7b294050030f494a2b538e85492828a2719642365af1f7e5b89f847888fd936469c4bdb6843b81887edb89896b0a926 + checksum: 21b5835cb19d9dade6a1a07ac9566b8c0519cd5b1c632f36a707345292fbbfe6f5914bf0a37c7384ecdde469b01996cb42efe77dfa6f7b63ac7c131383001660 languageName: node linkType: hard -"@aws-sdk/middleware-recursion-detection@npm:3.451.0": - version: 3.451.0 - resolution: "@aws-sdk/middleware-recursion-detection@npm:3.451.0" +"@aws-sdk/middleware-recursion-detection@npm:3.460.0": + version: 3.460.0 + resolution: "@aws-sdk/middleware-recursion-detection@npm:3.460.0" dependencies: - "@aws-sdk/types": 3.451.0 + "@aws-sdk/types": 3.460.0 "@smithy/protocol-http": ^3.0.9 "@smithy/types": ^2.5.0 tslib: ^2.5.0 - checksum: 70625b5c9e9f61d4c58a05a8aa616ec31c7bb23f45e8187fffe30003861fd3fe0bce96e6b120b4bb3937c0c66e04c96c8e024a4c42dd0524f0a0b6dc73b7e1d5 + checksum: 45786cb548d8e5f823a911bc443f596ddf16db1bfd2a5e017fd4c6c098021ed2ba21e4b505df3a1839f5ffd9976f3a01b2743d02fbdaacfbc7fd94dd65fdc6da languageName: node linkType: hard -"@aws-sdk/middleware-sdk-s3@npm:3.451.0": - version: 3.451.0 - resolution: "@aws-sdk/middleware-sdk-s3@npm:3.451.0" +"@aws-sdk/middleware-sdk-s3@npm:3.461.0": + version: 3.461.0 + resolution: "@aws-sdk/middleware-sdk-s3@npm:3.461.0" dependencies: - "@aws-sdk/types": 3.451.0 + "@aws-sdk/types": 3.460.0 "@aws-sdk/util-arn-parser": 3.310.0 + "@smithy/node-config-provider": ^2.1.5 "@smithy/protocol-http": ^3.0.9 + "@smithy/signature-v4": ^2.0.0 "@smithy/smithy-client": ^2.1.15 "@smithy/types": ^2.5.0 + "@smithy/util-config-provider": ^2.0.0 tslib: ^2.5.0 - checksum: e8ba5b5d5918223b4f76113dcfabf7f342880f0ef5a0ebae861f142f2d74748f1aadd47270d61c591e31ba88c52cfca0cf7ba992384b34271e13ca144edf48a6 + checksum: bab702b64227960239bde83021c964f34ee93d398b6a9db4c3550af81d19450ada72d0bab5f27a710b5eceea2b19874f62543f52279ee734407239c3552a99da languageName: node linkType: hard -"@aws-sdk/middleware-sdk-sqs@npm:3.451.0": - version: 3.451.0 - resolution: "@aws-sdk/middleware-sdk-sqs@npm:3.451.0" +"@aws-sdk/middleware-sdk-sqs@npm:3.460.0": + version: 3.460.0 + resolution: "@aws-sdk/middleware-sdk-sqs@npm:3.460.0" dependencies: - "@aws-sdk/types": 3.451.0 + "@aws-sdk/types": 3.460.0 "@smithy/types": ^2.5.0 "@smithy/util-hex-encoding": ^2.0.0 "@smithy/util-utf8": ^2.0.2 tslib: ^2.5.0 - checksum: 4ef20e1ebffb3a2fe6ddc77a5ca18203ef405e71f77b3167cbee8241e5ff77be08d3ca43fb25c3582454ddc53d42b44f38c6942c95d706ac4c4f6111d062910a + checksum: 6c60fa8d80b12ab658b20f28d9991434853fcf64dd683c6ac29c0a405113d9aea96c072576bf5ccf016391af24f32309e5c15d1083aba8518b06d9983e8f6731 languageName: node linkType: hard -"@aws-sdk/middleware-sdk-sts@npm:3.451.0": - version: 3.451.0 - resolution: "@aws-sdk/middleware-sdk-sts@npm:3.451.0" +"@aws-sdk/middleware-sdk-sts@npm:3.461.0": + version: 3.461.0 + resolution: "@aws-sdk/middleware-sdk-sts@npm:3.461.0" dependencies: - "@aws-sdk/middleware-signing": 3.451.0 - "@aws-sdk/types": 3.451.0 + "@aws-sdk/middleware-signing": 3.461.0 + "@aws-sdk/types": 3.460.0 "@smithy/types": ^2.5.0 tslib: ^2.5.0 - checksum: 8aef507f62ffc342bbf70f3ecb24e96d286526aa23040a13a1f4761059b1a57f3d2bed9b14caef0bde53dd440584ef9fea6947ff18cfdae7498b028beefa9ec5 + checksum: c9b04d9be26357d493475564134a9d3e03bb9291ccc5ff3209b143c6e5495123fcaa4af92ec030bd8959ede9c45182f8bf9aa1d6502a1603f9d4a08d5e6e27b5 languageName: node linkType: hard @@ -1088,42 +1091,42 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/middleware-signing@npm:3.451.0": - version: 3.451.0 - resolution: "@aws-sdk/middleware-signing@npm:3.451.0" +"@aws-sdk/middleware-signing@npm:3.461.0": + version: 3.461.0 + resolution: "@aws-sdk/middleware-signing@npm:3.461.0" dependencies: - "@aws-sdk/types": 3.451.0 + "@aws-sdk/types": 3.460.0 "@smithy/property-provider": ^2.0.0 "@smithy/protocol-http": ^3.0.9 "@smithy/signature-v4": ^2.0.0 "@smithy/types": ^2.5.0 "@smithy/util-middleware": ^2.0.6 tslib: ^2.5.0 - checksum: 6a2900bdad76733fec5155af97f9f2b3448451bf15357d0dfbc35f646a321120dc6b5d5e3c5690b0bfc5294044c139ce28b3a07c149f33dd9572399f5ae0999d + checksum: 5a202e6fe8f9482aecc455843d5b97d42198cb6e98d6b739eff6a769742220f925876981b67c0d15963fd59b9a4a79d374505d28ac4f33be8ac9599908dbe528 languageName: node linkType: hard -"@aws-sdk/middleware-ssec@npm:3.451.0": - version: 3.451.0 - resolution: "@aws-sdk/middleware-ssec@npm:3.451.0" +"@aws-sdk/middleware-ssec@npm:3.460.0": + version: 3.460.0 + resolution: "@aws-sdk/middleware-ssec@npm:3.460.0" dependencies: - "@aws-sdk/types": 3.451.0 + "@aws-sdk/types": 3.460.0 "@smithy/types": ^2.5.0 tslib: ^2.5.0 - checksum: f9666c4aba9085eb6257e49636e0d4eae61ce9be1411965cb2212a0ce1bf63f89365db5b4710a9154e1001dba8ac0be09a46d6e38c13f6b9dc2b73b8a4efdce4 + checksum: 48cf9b1c5a1f17dca62c448335a6191b592435522754b8edfc52ee281a47c951703af5cd8bb235a8ca8d51e0571e74c9770d5b418f2273fa3638611196b6166d languageName: node linkType: hard -"@aws-sdk/middleware-user-agent@npm:3.451.0": - version: 3.451.0 - resolution: "@aws-sdk/middleware-user-agent@npm:3.451.0" +"@aws-sdk/middleware-user-agent@npm:3.460.0": + version: 3.460.0 + resolution: "@aws-sdk/middleware-user-agent@npm:3.460.0" dependencies: - "@aws-sdk/types": 3.451.0 - "@aws-sdk/util-endpoints": 3.451.0 + "@aws-sdk/types": 3.460.0 + "@aws-sdk/util-endpoints": 3.460.0 "@smithy/protocol-http": ^3.0.9 "@smithy/types": ^2.5.0 tslib: ^2.5.0 - checksum: d547fb999a6f657d8806165102b57a082a4e5464666c928148292e233be38a53209c1b9a39eac7e0c403a77e0336159b9a72e89daad86365306421058b0c4f92 + checksum: a65daeece1071de6fe6e3ce3b9426905febda16906236f982bfc09b57d0e1837e1b47a7467b9b9f69fcf900938d29b030380a38fc76d4dde4147dca4b571f54c languageName: node linkType: hard @@ -1184,16 +1187,17 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/signature-v4-multi-region@npm:3.451.0": - version: 3.451.0 - resolution: "@aws-sdk/signature-v4-multi-region@npm:3.451.0" +"@aws-sdk/signature-v4-multi-region@npm:3.461.0": + version: 3.461.0 + resolution: "@aws-sdk/signature-v4-multi-region@npm:3.461.0" dependencies: - "@aws-sdk/types": 3.451.0 + "@aws-sdk/middleware-sdk-s3": 3.461.0 + "@aws-sdk/types": 3.460.0 "@smithy/protocol-http": ^3.0.9 "@smithy/signature-v4": ^2.0.0 "@smithy/types": ^2.5.0 tslib: ^2.5.0 - checksum: d0c9e434e28c4c06a78d6d12ebe0067bf4d299b73e106ef336dd730a63941dcdb443147a998603c0f64ec8a1a9f53c0b8ad7f0e67fe36959c154c1dcf664a485 + checksum: f0fe24b52e57950c5930fb5aec446d6f82f1ef42b9d48c50a92d47bd70569cac99d0927069be6a23e28d760028a9a00ea5eaf542452a1899ecb50150afbad98d languageName: node linkType: hard @@ -1213,21 +1217,21 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/token-providers@npm:3.451.0": - version: 3.451.0 - resolution: "@aws-sdk/token-providers@npm:3.451.0" +"@aws-sdk/token-providers@npm:3.460.0": + version: 3.460.0 + resolution: "@aws-sdk/token-providers@npm:3.460.0" dependencies: "@aws-crypto/sha256-browser": 3.0.0 "@aws-crypto/sha256-js": 3.0.0 - "@aws-sdk/middleware-host-header": 3.451.0 - "@aws-sdk/middleware-logger": 3.451.0 - "@aws-sdk/middleware-recursion-detection": 3.451.0 - "@aws-sdk/middleware-user-agent": 3.451.0 + "@aws-sdk/middleware-host-header": 3.460.0 + "@aws-sdk/middleware-logger": 3.460.0 + "@aws-sdk/middleware-recursion-detection": 3.460.0 + "@aws-sdk/middleware-user-agent": 3.460.0 "@aws-sdk/region-config-resolver": 3.451.0 - "@aws-sdk/types": 3.451.0 - "@aws-sdk/util-endpoints": 3.451.0 - "@aws-sdk/util-user-agent-browser": 3.451.0 - "@aws-sdk/util-user-agent-node": 3.451.0 + "@aws-sdk/types": 3.460.0 + "@aws-sdk/util-endpoints": 3.460.0 + "@aws-sdk/util-user-agent-browser": 3.460.0 + "@aws-sdk/util-user-agent-node": 3.460.0 "@smithy/config-resolver": ^2.0.18 "@smithy/fetch-http-handler": ^2.2.6 "@smithy/hash-node": ^2.0.15 @@ -1254,7 +1258,7 @@ __metadata: "@smithy/util-retry": ^2.0.6 "@smithy/util-utf8": ^2.0.2 tslib: ^2.5.0 - checksum: 1c2d3927e33eedcfc0482744f065c44f632d13fb7a03152dd4d5b04546ab06fed6373f2e8432caf332c0ab93ac9a64bf88cc5071702f6f1adacc8aed53ed3e3b + checksum: f459533489ef191afae6a7bb5cf6676ec4685b382880e6058c8861a7e8f45931aa4c323dfac5f17c45f390fc6997250e3b7063eb58054eae1c7919e3b940cdb2 languageName: node linkType: hard @@ -1268,13 +1272,13 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/types@npm:3.451.0, @aws-sdk/types@npm:^3.222.0, @aws-sdk/types@npm:^3.347.0": - version: 3.451.0 - resolution: "@aws-sdk/types@npm:3.451.0" +"@aws-sdk/types@npm:3.460.0, @aws-sdk/types@npm:^3.222.0, @aws-sdk/types@npm:^3.347.0": + version: 3.460.0 + resolution: "@aws-sdk/types@npm:3.460.0" dependencies: "@smithy/types": ^2.5.0 tslib: ^2.5.0 - checksum: 0f66eccf707ece1f21af6c8099a6b13191a119f48dacebd8794d74263628b95dcf0bfa479493ec1774c902fe7bb8867cfcbd1cf7d908653fe0e0759168970d19 + checksum: 6e3b367bebb2840a7e6efca2bbf74afeea4ce6df2a96095f1641bf0424838ae9fd12da6cbe669f4f58244963e61f38216f7f80709feb71a521d68fbb17b18f4c languageName: node linkType: hard @@ -1308,14 +1312,14 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/util-endpoints@npm:3.451.0": - version: 3.451.0 - resolution: "@aws-sdk/util-endpoints@npm:3.451.0" +"@aws-sdk/util-endpoints@npm:3.460.0": + version: 3.460.0 + resolution: "@aws-sdk/util-endpoints@npm:3.460.0" dependencies: - "@aws-sdk/types": 3.451.0 + "@aws-sdk/types": 3.460.0 "@smithy/util-endpoints": ^1.0.4 tslib: ^2.5.0 - checksum: ebb558cadb896754f2f0078b31720441bf8d8f4735372950a00c677b2db1a9076a3aefa3c14148e39708b593f148a12930e1b29ecce6e4ed653ea10ab26f3c80 + checksum: 4b0d3c4fe38a9c28b38ad4d575d600d1a29de7b829ac579a674f79b058473467dd0f31afbae03dd13c453fee48f3decb026259714051faf54161429a3b713124 languageName: node linkType: hard @@ -1367,23 +1371,23 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/util-user-agent-browser@npm:3.451.0": - version: 3.451.0 - resolution: "@aws-sdk/util-user-agent-browser@npm:3.451.0" +"@aws-sdk/util-user-agent-browser@npm:3.460.0": + version: 3.460.0 + resolution: "@aws-sdk/util-user-agent-browser@npm:3.460.0" dependencies: - "@aws-sdk/types": 3.451.0 + "@aws-sdk/types": 3.460.0 "@smithy/types": ^2.5.0 bowser: ^2.11.0 tslib: ^2.5.0 - checksum: 83e6a74aca3575b385db09787021bbd40589afdff0fcad1d4ea33c7a4711f3147d61fa6465a629838d8d093609d43097bedb4bfc6e12e3695179f4c244b691e3 + checksum: 6cdbf7c0159ce0d74964ac6c751fc256084c1388720cb4f70c1a2602762270fb2f04e8ff7dc187b2975248a965f1834adfd1bc74a2769bbde7722bbf04773764 languageName: node linkType: hard -"@aws-sdk/util-user-agent-node@npm:3.451.0": - version: 3.451.0 - resolution: "@aws-sdk/util-user-agent-node@npm:3.451.0" +"@aws-sdk/util-user-agent-node@npm:3.460.0": + version: 3.460.0 + resolution: "@aws-sdk/util-user-agent-node@npm:3.460.0" dependencies: - "@aws-sdk/types": 3.451.0 + "@aws-sdk/types": 3.460.0 "@smithy/node-config-provider": ^2.1.5 "@smithy/types": ^2.5.0 tslib: ^2.5.0 @@ -1392,7 +1396,7 @@ __metadata: peerDependenciesMeta: aws-crt: optional: true - checksum: 94ccacf05776b558f965d8081602435565be59a62e0ec61946a49c2519f742ae2552df407b9ba9b37d8cbac1ef8ea5538bb72c96bc1e1c55ab9ecb6be187fe67 + checksum: 12eb5ae7e6fd0d60d188ae24f2eba746fdf9a612cc28d317c4a2762b0dc8ef4427ff82def11c964600f329edd6b14076bc6d4d8a65877ca0c42ebacfcb34c5f7 languageName: node linkType: hard From a62764b94c62119da6142b8e7fe392eddaec1118 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 29 Nov 2023 18:56:44 +0000 Subject: [PATCH 236/261] fix(deps): update dependency passport to ^0.7.0 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .changeset/renovate-c727667.md | 12 ++++++++++ .../package.json | 2 +- .../package.json | 2 +- .../package.json | 2 +- .../package.json | 2 +- .../package.json | 2 +- .../package.json | 2 +- plugins/auth-backend/package.json | 2 +- plugins/auth-node/package.json | 2 +- yarn.lock | 24 +++++++++---------- 10 files changed, 32 insertions(+), 20 deletions(-) create mode 100644 .changeset/renovate-c727667.md diff --git a/.changeset/renovate-c727667.md b/.changeset/renovate-c727667.md new file mode 100644 index 0000000000..82b7d0a8f5 --- /dev/null +++ b/.changeset/renovate-c727667.md @@ -0,0 +1,12 @@ +--- +'@backstage/plugin-auth-backend-module-atlassian-provider': patch +'@backstage/plugin-auth-backend-module-gitlab-provider': patch +'@backstage/plugin-auth-backend-module-microsoft-provider': patch +'@backstage/plugin-auth-backend-module-oauth2-provider': patch +'@backstage/plugin-auth-backend-module-okta-provider': patch +'@backstage/plugin-auth-backend-module-pinniped-provider': patch +'@backstage/plugin-auth-backend': patch +'@backstage/plugin-auth-node': patch +--- + +Updated dependency `passport` to `^0.7.0`. diff --git a/plugins/auth-backend-module-atlassian-provider/package.json b/plugins/auth-backend-module-atlassian-provider/package.json index 9cfc21ba6a..c2bfc37c02 100644 --- a/plugins/auth-backend-module-atlassian-provider/package.json +++ b/plugins/auth-backend-module-atlassian-provider/package.json @@ -27,7 +27,7 @@ "@backstage/backend-plugin-api": "workspace:^", "@backstage/plugin-auth-node": "workspace:^", "express": "^4.18.2", - "passport": "^0.6.0", + "passport": "^0.7.0", "passport-atlassian-oauth2": "^2.1.0" }, "devDependencies": { diff --git a/plugins/auth-backend-module-gitlab-provider/package.json b/plugins/auth-backend-module-gitlab-provider/package.json index fee472b198..56c6b43af3 100644 --- a/plugins/auth-backend-module-gitlab-provider/package.json +++ b/plugins/auth-backend-module-gitlab-provider/package.json @@ -27,7 +27,7 @@ "@backstage/backend-plugin-api": "workspace:^", "@backstage/plugin-auth-node": "workspace:^", "express": "^4.18.2", - "passport": "^0.6.0", + "passport": "^0.7.0", "passport-gitlab2": "^5.0.0" }, "devDependencies": { diff --git a/plugins/auth-backend-module-microsoft-provider/package.json b/plugins/auth-backend-module-microsoft-provider/package.json index ea016cfcf7..47324f9ab9 100644 --- a/plugins/auth-backend-module-microsoft-provider/package.json +++ b/plugins/auth-backend-module-microsoft-provider/package.json @@ -29,7 +29,7 @@ "express": "^4.18.2", "jose": "^4.6.0", "node-fetch": "^2.6.7", - "passport": "^0.6.0", + "passport": "^0.7.0", "passport-microsoft": "^1.0.0" }, "devDependencies": { diff --git a/plugins/auth-backend-module-oauth2-provider/package.json b/plugins/auth-backend-module-oauth2-provider/package.json index e31e64c3f5..f46428f4f3 100644 --- a/plugins/auth-backend-module-oauth2-provider/package.json +++ b/plugins/auth-backend-module-oauth2-provider/package.json @@ -27,7 +27,7 @@ "@backstage/backend-plugin-api": "workspace:^", "@backstage/plugin-auth-node": "workspace:^", "express": "^4.18.2", - "passport": "^0.6.0", + "passport": "^0.7.0", "passport-oauth2": "^1.6.1" }, "devDependencies": { diff --git a/plugins/auth-backend-module-okta-provider/package.json b/plugins/auth-backend-module-okta-provider/package.json index fcbf37ccd7..178ebf1465 100644 --- a/plugins/auth-backend-module-okta-provider/package.json +++ b/plugins/auth-backend-module-okta-provider/package.json @@ -28,7 +28,7 @@ "@backstage/plugin-auth-node": "workspace:^", "@davidzemon/passport-okta-oauth": "^0.0.5", "express": "^4.18.2", - "passport": "^0.6.0" + "passport": "^0.7.0" }, "devDependencies": { "@backstage/backend-defaults": "workspace:^", diff --git a/plugins/auth-backend-module-pinniped-provider/package.json b/plugins/auth-backend-module-pinniped-provider/package.json index c55c89eda2..3358a9d747 100644 --- a/plugins/auth-backend-module-pinniped-provider/package.json +++ b/plugins/auth-backend-module-pinniped-provider/package.json @@ -41,7 +41,7 @@ "express-session": "^1.17.3", "jose": "^4.14.6", "msw": "^1.3.0", - "passport": "^0.6.0", + "passport": "^0.7.0", "supertest": "^6.3.3" }, "files": [ diff --git a/plugins/auth-backend/package.json b/plugins/auth-backend/package.json index 5060390d9a..2ce075087f 100644 --- a/plugins/auth-backend/package.json +++ b/plugins/auth-backend/package.json @@ -71,7 +71,7 @@ "node-cache": "^5.1.2", "node-fetch": "^2.6.7", "openid-client": "^5.2.1", - "passport": "^0.6.0", + "passport": "^0.7.0", "passport-auth0": "^1.4.3", "passport-bitbucket-oauth2": "^0.1.2", "passport-github2": "^0.1.12", diff --git a/plugins/auth-node/package.json b/plugins/auth-node/package.json index 025d3c0eb6..ceb1a587ce 100644 --- a/plugins/auth-node/package.json +++ b/plugins/auth-node/package.json @@ -41,7 +41,7 @@ "jose": "^4.6.0", "lodash": "^4.17.21", "node-fetch": "^2.6.7", - "passport": "^0.6.0", + "passport": "^0.7.0", "winston": "^3.2.1", "zod": "^3.21.4", "zod-to-json-schema": "^3.21.4" diff --git a/yarn.lock b/yarn.lock index d300613993..f07d029671 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4771,7 +4771,7 @@ __metadata: "@backstage/plugin-auth-backend": "workspace:^" "@backstage/plugin-auth-node": "workspace:^" express: ^4.18.2 - passport: ^0.6.0 + passport: ^0.7.0 passport-atlassian-oauth2: ^2.1.0 supertest: ^6.3.3 languageName: unknown @@ -4822,7 +4822,7 @@ __metadata: "@backstage/plugin-auth-backend": "workspace:^" "@backstage/plugin-auth-node": "workspace:^" express: ^4.18.2 - passport: ^0.6.0 + passport: ^0.7.0 passport-gitlab2: ^5.0.0 supertest: ^6.3.3 languageName: unknown @@ -4862,7 +4862,7 @@ __metadata: jose: ^4.6.0 msw: ^1.0.0 node-fetch: ^2.6.7 - passport: ^0.6.0 + passport: ^0.7.0 passport-microsoft: ^1.0.0 supertest: ^6.3.3 languageName: unknown @@ -4880,7 +4880,7 @@ __metadata: "@backstage/plugin-auth-backend": "workspace:^" "@backstage/plugin-auth-node": "workspace:^" express: ^4.18.2 - passport: ^0.6.0 + passport: ^0.7.0 passport-oauth2: ^1.6.1 supertest: ^6.3.3 languageName: unknown @@ -4913,7 +4913,7 @@ __metadata: "@backstage/plugin-auth-node": "workspace:^" "@davidzemon/passport-okta-oauth": ^0.0.5 express: ^4.18.2 - passport: ^0.6.0 + passport: ^0.7.0 supertest: ^6.3.3 languageName: unknown linkType: soft @@ -4938,7 +4938,7 @@ __metadata: luxon: ^3.4.3 msw: ^1.3.0 openid-client: ^5.4.3 - passport: ^0.6.0 + passport: ^0.7.0 supertest: ^6.3.3 languageName: unknown linkType: soft @@ -5023,7 +5023,7 @@ __metadata: node-cache: ^5.1.2 node-fetch: ^2.6.7 openid-client: ^5.2.1 - passport: ^0.6.0 + passport: ^0.7.0 passport-auth0: ^1.4.3 passport-bitbucket-oauth2: ^0.1.2 passport-github2: ^0.1.12 @@ -5062,7 +5062,7 @@ __metadata: lodash: ^4.17.21 msw: ^1.0.0 node-fetch: ^2.6.7 - passport: ^0.6.0 + passport: ^0.7.0 supertest: ^6.1.3 uuid: ^8.0.0 winston: ^3.2.1 @@ -36564,14 +36564,14 @@ __metadata: languageName: node linkType: hard -"passport@npm:^0.6.0": - version: 0.6.0 - resolution: "passport@npm:0.6.0" +"passport@npm:^0.7.0": + version: 0.7.0 + resolution: "passport@npm:0.7.0" dependencies: passport-strategy: 1.x.x pause: 0.0.1 utils-merge: ^1.0.1 - checksum: ef932ad671d50de34765c7a53cd1e058d8331a82a6df09265a9c6c1168911aee4a7b5215803d0101110ab7f317e096b4954ca7e18fb2c33b9929f0bd17dbe159 + checksum: 5080b46df2df7a84f7ba4a8a20437ce71a1346fd27ab47b62df3251a666af9f3430d6c8a1beda3174f6a9d91edc823b57b88050d423a6cff9831848a2d97725c languageName: node linkType: hard From c07cee52f345d717b1706d65b39303f2f3e0a748 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 29 Nov 2023 18:57:08 +0000 Subject: [PATCH 237/261] fix(deps): update dependency @rollup/plugin-json to v6 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .changeset/renovate-19742c3.md | 5 +++++ packages/cli/package.json | 2 +- yarn.lock | 12 ++++++------ 3 files changed, 12 insertions(+), 7 deletions(-) create mode 100644 .changeset/renovate-19742c3.md diff --git a/.changeset/renovate-19742c3.md b/.changeset/renovate-19742c3.md new file mode 100644 index 0000000000..2dfee1ad96 --- /dev/null +++ b/.changeset/renovate-19742c3.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Updated dependency `@rollup/plugin-json` to `^6.0.0`. diff --git a/packages/cli/package.json b/packages/cli/package.json index c6b411b0f4..6561ffb63d 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -47,7 +47,7 @@ "@octokit/request": "^6.0.0", "@pmmmwh/react-refresh-webpack-plugin": "^0.5.7", "@rollup/plugin-commonjs": "^25.0.0", - "@rollup/plugin-json": "^5.0.0", + "@rollup/plugin-json": "^6.0.0", "@rollup/plugin-node-resolve": "^15.0.0", "@rollup/plugin-yaml": "^4.0.0", "@spotify/eslint-config-base": "^14.0.0", diff --git a/yarn.lock b/yarn.lock index d300613993..6f49835cba 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3615,7 +3615,7 @@ __metadata: "@octokit/request": ^6.0.0 "@pmmmwh/react-refresh-webpack-plugin": ^0.5.7 "@rollup/plugin-commonjs": ^25.0.0 - "@rollup/plugin-json": ^5.0.0 + "@rollup/plugin-json": ^6.0.0 "@rollup/plugin-node-resolve": ^15.0.0 "@rollup/plugin-yaml": ^4.0.0 "@spotify/eslint-config-base": ^14.0.0 @@ -15361,17 +15361,17 @@ __metadata: languageName: node linkType: hard -"@rollup/plugin-json@npm:^5.0.0": - version: 5.0.2 - resolution: "@rollup/plugin-json@npm:5.0.2" +"@rollup/plugin-json@npm:^6.0.0": + version: 6.0.1 + resolution: "@rollup/plugin-json@npm:6.0.1" dependencies: "@rollup/pluginutils": ^5.0.1 peerDependencies: - rollup: ^1.20.0||^2.0.0||^3.0.0 + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 peerDependenciesMeta: rollup: optional: true - checksum: 9b5f90ea311dfcfacf0f38af39bbb1954ea56d6faecdee3d528f73d0e02da96a0706ab21fae0c8eef9bb5d756f6f50b40b5a252ffd9800397012b5bac6764b6f + checksum: 86995e3ceec0205bd0b5ae3075f4592e0ab3e6e6327a5dcfc825b44113eaae5819d26d5403d29b177ac59299e0b08c641c8d030e0c72805b92805ededc9cac44 languageName: node linkType: hard From bc3e6c707803c3aa1b5645de0b2615729abf8446 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 29 Nov 2023 19:33:20 +0000 Subject: [PATCH 238/261] fix(deps): update typescript-eslint monorepo to v6.13.1 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 96 +++++++++++++++++++++++++++---------------------------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/yarn.lock b/yarn.lock index 1f74e5c7e7..00cd2021f1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -19499,14 +19499,14 @@ __metadata: linkType: hard "@typescript-eslint/eslint-plugin@npm:^6.12.0": - version: 6.12.0 - resolution: "@typescript-eslint/eslint-plugin@npm:6.12.0" + version: 6.13.1 + resolution: "@typescript-eslint/eslint-plugin@npm:6.13.1" dependencies: "@eslint-community/regexpp": ^4.5.1 - "@typescript-eslint/scope-manager": 6.12.0 - "@typescript-eslint/type-utils": 6.12.0 - "@typescript-eslint/utils": 6.12.0 - "@typescript-eslint/visitor-keys": 6.12.0 + "@typescript-eslint/scope-manager": 6.13.1 + "@typescript-eslint/type-utils": 6.13.1 + "@typescript-eslint/utils": 6.13.1 + "@typescript-eslint/visitor-keys": 6.13.1 debug: ^4.3.4 graphemer: ^1.4.0 ignore: ^5.2.4 @@ -19519,25 +19519,25 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: a791ebe432a6cac50a15c9e98502b62e874de0c7e35fd320b9bdca21afd4ae88c88cff45ee50a95362da14e98965d946e57b15965f5522f1153568a3fe45db8a + checksum: 568093d76c200a8502047d74f29300110a59b9f2a5cbf995a6cbe419c803a7ec22220e9592a884401d2dde72c79346b4cc0ee393e7b422924ad4a8a2040af3b0 languageName: node linkType: hard "@typescript-eslint/parser@npm:^6.7.2": - version: 6.12.0 - resolution: "@typescript-eslint/parser@npm:6.12.0" + version: 6.13.1 + resolution: "@typescript-eslint/parser@npm:6.13.1" dependencies: - "@typescript-eslint/scope-manager": 6.12.0 - "@typescript-eslint/types": 6.12.0 - "@typescript-eslint/typescript-estree": 6.12.0 - "@typescript-eslint/visitor-keys": 6.12.0 + "@typescript-eslint/scope-manager": 6.13.1 + "@typescript-eslint/types": 6.13.1 + "@typescript-eslint/typescript-estree": 6.13.1 + "@typescript-eslint/visitor-keys": 6.13.1 debug: ^4.3.4 peerDependencies: eslint: ^7.0.0 || ^8.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 92923b7ee61f52d6b74f515640fe6bbb6b0a922d20dabeb6b59bc73f3c132bf750a2b706bb40fbe6d233c6ecc1abe905c99aa062280bb78e5724334f5b6c4ac5 + checksum: 58b7fef6f2d02c8f4737f9908a8d335a20bee20dba648233a69f28e7b39237791d2b9fbb818e628dcc053ddf16507b161ace7f1139e093d72365f1270c426de3 languageName: node linkType: hard @@ -19551,22 +19551,22 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:6.12.0": - version: 6.12.0 - resolution: "@typescript-eslint/scope-manager@npm:6.12.0" +"@typescript-eslint/scope-manager@npm:6.13.1": + version: 6.13.1 + resolution: "@typescript-eslint/scope-manager@npm:6.13.1" dependencies: - "@typescript-eslint/types": 6.12.0 - "@typescript-eslint/visitor-keys": 6.12.0 - checksum: 4cc4eb1bcd04ba7b0a1de4284521cde5f3f25f2530f78dfcb3f098396b142fd30a45f615a87dc7a3adddbd131a6255cb12b1df19aacff71a3f766992ddef183f + "@typescript-eslint/types": 6.13.1 + "@typescript-eslint/visitor-keys": 6.13.1 + checksum: 109a213f82719e10f8c6a0168f2e105dc1369c7e0c075c1f30af137030fc866a3a585a77ff78a9a3538afc213061c8aedbb4462a91f26cbd90eefbab8b89ea10 languageName: node linkType: hard -"@typescript-eslint/type-utils@npm:6.12.0": - version: 6.12.0 - resolution: "@typescript-eslint/type-utils@npm:6.12.0" +"@typescript-eslint/type-utils@npm:6.13.1": + version: 6.13.1 + resolution: "@typescript-eslint/type-utils@npm:6.13.1" dependencies: - "@typescript-eslint/typescript-estree": 6.12.0 - "@typescript-eslint/utils": 6.12.0 + "@typescript-eslint/typescript-estree": 6.13.1 + "@typescript-eslint/utils": 6.13.1 debug: ^4.3.4 ts-api-utils: ^1.0.1 peerDependencies: @@ -19574,7 +19574,7 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: c345c45f1262eee4b9f6960a59b3aba960643d0004094a3d8fb9682ab79af2fae864695029246dc9e0d4fdb2f3d017a56b7dc034e551d263deba75c2ef048d39 + checksum: e39d28dd2f3b47a26b4f6aa2c7a301bdd769ce9148d734be93441a813c3d1111eba1d655677355bba5519f3d4dbe93e4ff4e46830216b0302df0070bf7a80057 languageName: node linkType: hard @@ -19585,10 +19585,10 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/types@npm:6.12.0": - version: 6.12.0 - resolution: "@typescript-eslint/types@npm:6.12.0" - checksum: d3b40f9d400f6455ce5ae610651597c9e9ec85d46ca6d3c1025597a76305c557ebc5b88340ec6db0e694c9c79f1299d375b87a1a5b9314b22231dbbb5ce54695 +"@typescript-eslint/types@npm:6.13.1": + version: 6.13.1 + resolution: "@typescript-eslint/types@npm:6.13.1" + checksum: bb1d52f1646bab9acd3ec874567ffbaaaf7fe4a5f79845bdacbfea46d15698e58d45797da05b08c23f9496a17229b7f2c1363d000fd89ce4e79874fd57ba1d4a languageName: node linkType: hard @@ -19610,12 +19610,12 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:6.12.0": - version: 6.12.0 - resolution: "@typescript-eslint/typescript-estree@npm:6.12.0" +"@typescript-eslint/typescript-estree@npm:6.13.1": + version: 6.13.1 + resolution: "@typescript-eslint/typescript-estree@npm:6.13.1" dependencies: - "@typescript-eslint/types": 6.12.0 - "@typescript-eslint/visitor-keys": 6.12.0 + "@typescript-eslint/types": 6.13.1 + "@typescript-eslint/visitor-keys": 6.13.1 debug: ^4.3.4 globby: ^11.1.0 is-glob: ^4.0.3 @@ -19624,24 +19624,24 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 943f7ff2e164d812f6ae0a2d5096836aff00b1fda39937b03f126f266f03f3655794f5fc4643b49b71c312126d9422dfd764744bd1ba41ee6821a5bac1511aa2 + checksum: 09aa0f5cbd60e84df4f58f3d479be352549600b24dbefe75c686ea89252526c52c1c06ce1ae56c0405dd7337002e741c2ba02b71fb1caa3b94a740a70fcc8699 languageName: node linkType: hard -"@typescript-eslint/utils@npm:6.12.0": - version: 6.12.0 - resolution: "@typescript-eslint/utils@npm:6.12.0" +"@typescript-eslint/utils@npm:6.13.1": + version: 6.13.1 + resolution: "@typescript-eslint/utils@npm:6.13.1" dependencies: "@eslint-community/eslint-utils": ^4.4.0 "@types/json-schema": ^7.0.12 "@types/semver": ^7.5.0 - "@typescript-eslint/scope-manager": 6.12.0 - "@typescript-eslint/types": 6.12.0 - "@typescript-eslint/typescript-estree": 6.12.0 + "@typescript-eslint/scope-manager": 6.13.1 + "@typescript-eslint/types": 6.13.1 + "@typescript-eslint/typescript-estree": 6.13.1 semver: ^7.5.4 peerDependencies: eslint: ^7.0.0 || ^8.0.0 - checksum: dad05bd0e4db7a88c2716f9ee83c7c28c30d71e57392e58dc0db66b5f5c4c86b9db14142c6a1a82cf1650da294d31980c56a118015d3a2a645acb8b8a5ebc315 + checksum: 14f64840869c8755af4d287cfc74abc424dc139559e87ca1a8b0e850f4fa56311d99dfb61a43dd4433eae5914be12b4b3390e55de1f236dce6701830d17e31c9 languageName: node linkType: hard @@ -19673,13 +19673,13 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:6.12.0": - version: 6.12.0 - resolution: "@typescript-eslint/visitor-keys@npm:6.12.0" +"@typescript-eslint/visitor-keys@npm:6.13.1": + version: 6.13.1 + resolution: "@typescript-eslint/visitor-keys@npm:6.13.1" dependencies: - "@typescript-eslint/types": 6.12.0 + "@typescript-eslint/types": 6.13.1 eslint-visitor-keys: ^3.4.1 - checksum: 3d8dc74ae748a95fe60b48dbaecca8d9c0c8df344d8034e3843057251fba24f06a3d29dbb9f525c9540b538d8c24221d3cf119ac483e9de38149a978051c72f3 + checksum: d15d362203a2fe995ea62a59d5b44c15c8fb1fb30ff59dd1542a980f75b3b62035303dfb781d83709921613f6ac8cc5bf57b70f6e20d820aec8b7911f07152e9 languageName: node linkType: hard From a1685073dfec4ace3165c0e17d908d1f3b6948f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Wed, 29 Nov 2023 20:46:56 +0100 Subject: [PATCH 239/261] deprecate the filter types and move to catalog-node MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .changeset/eighty-dodos-sing.md | 5 +++ .changeset/witty-cars-wash.md | 5 +++ plugins/catalog-backend/api-report-alpha.md | 7 +--- plugins/catalog-backend/api-report.md | 25 ++++--------- plugins/catalog-backend/src/alpha.ts | 6 ---- plugins/catalog-backend/src/catalog/index.ts | 17 --------- plugins/catalog-backend/src/catalog/types.ts | 35 +------------------ plugins/catalog-backend/src/deprecated.ts | 12 +++++++ plugins/catalog-backend/src/index.ts | 1 - .../src/permissions/rules/isEntityKind.ts | 4 +-- .../src/permissions/rules/util.ts | 2 +- .../service/AuthorizedEntitiesCatalog.test.ts | 3 +- .../src/service/AuthorizedEntitiesCatalog.ts | 2 +- .../src/service/CatalogBuilder.ts | 2 +- .../src/service/DefaultEntitiesCatalog.ts | 6 ++-- .../src/service/request/basicEntityFilter.ts | 5 ++- .../request/parseEntityFilterParams.ts | 5 ++- plugins/catalog-backend/src/service/util.ts | 2 +- plugins/catalog-node/api-report-alpha.md | 7 +--- plugins/catalog-node/api-report.md | 19 ++++++++++ plugins/catalog-node/src/alpha.ts | 5 +-- plugins/catalog-node/src/api/common.ts | 33 +++++++++++++++++ plugins/catalog-node/src/api/index.ts | 7 +++- plugins/catalog-node/src/extensions.ts | 14 +++----- 24 files changed, 115 insertions(+), 114 deletions(-) create mode 100644 .changeset/eighty-dodos-sing.md create mode 100644 .changeset/witty-cars-wash.md delete mode 100644 plugins/catalog-backend/src/catalog/index.ts diff --git a/.changeset/eighty-dodos-sing.md b/.changeset/eighty-dodos-sing.md new file mode 100644 index 0000000000..b7af0da473 --- /dev/null +++ b/.changeset/eighty-dodos-sing.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-node': minor +--- + +Added `EntitiesSearchFilter` and `EntityFilter` from `@backstage/plugin-catalog-backend`, for reuse diff --git a/.changeset/witty-cars-wash.md b/.changeset/witty-cars-wash.md new file mode 100644 index 0000000000..301ed5e35a --- /dev/null +++ b/.changeset/witty-cars-wash.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': patch +--- + +Deprecated `EntitiesSearchFilter` and `EntityFilter`, which can now be imported from `@backstage/plugin-catalog-node` instead diff --git a/plugins/catalog-backend/api-report-alpha.md b/plugins/catalog-backend/api-report-alpha.md index 1682d1cbae..51a2ec6114 100644 --- a/plugins/catalog-backend/api-report-alpha.md +++ b/plugins/catalog-backend/api-report-alpha.md @@ -6,6 +6,7 @@ import { BackendFeature } from '@backstage/backend-plugin-api'; import { ConditionalPolicyDecision } from '@backstage/plugin-permission-common'; import { Conditions } from '@backstage/plugin-permission-node'; +import { EntitiesSearchFilter } from '@backstage/plugin-catalog-node'; import { Entity } from '@backstage/catalog-model'; import { PermissionCondition } from '@backstage/plugin-permission-common'; import { PermissionCriteria } from '@backstage/plugin-permission-common'; @@ -90,12 +91,6 @@ export const createCatalogPermissionRule: < rule: PermissionRule, ) => PermissionRule; -// @public -export type EntitiesSearchFilter = { - key: string; - values?: string[]; -}; - // @alpha export const permissionRules: { hasAnnotation: PermissionRule< diff --git a/plugins/catalog-backend/api-report.md b/plugins/catalog-backend/api-report.md index 1aed0ea8b0..8b7565bd1f 100644 --- a/plugins/catalog-backend/api-report.md +++ b/plugins/catalog-backend/api-report.md @@ -28,7 +28,9 @@ import { Config } from '@backstage/config'; import { DefaultCatalogCollatorFactory as DefaultCatalogCollatorFactory_2 } from '@backstage/plugin-search-backend-module-catalog'; import type { DefaultCatalogCollatorFactoryOptions as DefaultCatalogCollatorFactoryOptions_2 } from '@backstage/plugin-search-backend-module-catalog'; import { DeferredEntity as DeferredEntity_2 } from '@backstage/plugin-catalog-node'; +import { EntitiesSearchFilter as EntitiesSearchFilter_2 } from '@backstage/plugin-catalog-node'; import { Entity } from '@backstage/catalog-model'; +import { EntityFilter as EntityFilter_2 } from '@backstage/plugin-catalog-node'; import { EntityPolicy } from '@backstage/catalog-model'; import { EntityProvider as EntityProvider_2 } from '@backstage/plugin-catalog-node'; import { EntityProviderConnection as EntityProviderConnection_2 } from '@backstage/plugin-catalog-node'; @@ -191,7 +193,7 @@ export type CatalogEnvironment = { // @public export type CatalogPermissionRuleInput< TParams extends PermissionRuleParams = PermissionRuleParams, -> = PermissionRule; +> = PermissionRule; // @public export interface CatalogProcessingEngine { @@ -313,24 +315,11 @@ export type DefaultCatalogCollatorFactoryOptions = // @public @deprecated (undocumented) export type DeferredEntity = DeferredEntity_2; -// @public -export type EntitiesSearchFilter = { - key: string; - values?: string[]; -}; +// @public @deprecated (undocumented) +export type EntitiesSearchFilter = EntitiesSearchFilter_2; -// @public -export type EntityFilter = - | { - allOf: EntityFilter[]; - } - | { - anyOf: EntityFilter[]; - } - | { - not: EntityFilter; - } - | EntitiesSearchFilter; +// @public @deprecated (undocumented) +export type EntityFilter = EntityFilter_2; // @public @deprecated (undocumented) export type EntityProvider = EntityProvider_2; diff --git a/plugins/catalog-backend/src/alpha.ts b/plugins/catalog-backend/src/alpha.ts index 06c9571bfa..f85ef02c80 100644 --- a/plugins/catalog-backend/src/alpha.ts +++ b/plugins/catalog-backend/src/alpha.ts @@ -14,11 +14,5 @@ * limitations under the License. */ -// TODO(Rugvip): Re-exported for alpha types as the API report will otherwise -// produce warnings due to the indirect dependency. Would be nice to avoid. -import type { EntitiesSearchFilter } from './catalog/types'; - -export type { /** @alpha */ EntitiesSearchFilter }; - export * from './permissions'; export { catalogPlugin as default } from './service/CatalogPlugin'; diff --git a/plugins/catalog-backend/src/catalog/index.ts b/plugins/catalog-backend/src/catalog/index.ts deleted file mode 100644 index ba34673bba..0000000000 --- a/plugins/catalog-backend/src/catalog/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* - * 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. - */ - -export type { EntitiesSearchFilter, EntityFilter } from './types'; diff --git a/plugins/catalog-backend/src/catalog/types.ts b/plugins/catalog-backend/src/catalog/types.ts index 156b8aa64d..e9f5f154c2 100644 --- a/plugins/catalog-backend/src/catalog/types.ts +++ b/plugins/catalog-backend/src/catalog/types.ts @@ -15,19 +15,7 @@ */ import { Entity } from '@backstage/catalog-model'; - -/** - * A filter expression for entities. - * - * Any (at least one) of the outer sets must match, within which all of the - * individual filters must match. - * @public - */ -export type EntityFilter = - | { allOf: EntityFilter[] } - | { anyOf: EntityFilter[] } - | { not: EntityFilter } - | EntitiesSearchFilter; +import { EntityFilter } from '@backstage/plugin-catalog-node'; /** * A pagination rule for entities. @@ -46,27 +34,6 @@ export type EntityOrder = { order: 'asc' | 'desc'; }; -/** - * Matches rows in the search table. - * @public - */ -export type EntitiesSearchFilter = { - /** - * The key to match on. - * - * Matches are always case insensitive. - */ - key: string; - - /** - * Match on plain equality of values. - * - * Match on values that are equal to any of the given array items. Matches are - * always case insensitive. - */ - values?: string[]; -}; - export type PageInfo = | { hasNextPage: false; diff --git a/plugins/catalog-backend/src/deprecated.ts b/plugins/catalog-backend/src/deprecated.ts index f3c199cbd3..2201bbbab4 100644 --- a/plugins/catalog-backend/src/deprecated.ts +++ b/plugins/catalog-backend/src/deprecated.ts @@ -18,6 +18,8 @@ import { locationSpecToMetadataName as _locationSpecToMetadataName, locationSpecToLocationEntity as _locationSpecToLocationEntity, processingResult as _processingResult, + type EntitiesSearchFilter as _EntitiesSearchFilter, + type EntityFilter as _EntityFilter, type DeferredEntity as _DeferredEntity, type EntityRelationSpec as _EntityRelationSpec, type CatalogProcessor as _CatalogProcessor, @@ -53,6 +55,16 @@ export const locationSpecToLocationEntity = _locationSpecToLocationEntity; * @deprecated import from `@backstage/plugin-catalog-node` instead */ export const processingResult = _processingResult; +/** + * @public + * @deprecated import from `@backstage/plugin-catalog-node` instead + */ +export type EntitiesSearchFilter = _EntitiesSearchFilter; +/** + * @public + * @deprecated import from `@backstage/plugin-catalog-node` instead + */ +export type EntityFilter = _EntityFilter; /** * @public * @deprecated import from `@backstage/plugin-catalog-node` instead diff --git a/plugins/catalog-backend/src/index.ts b/plugins/catalog-backend/src/index.ts index 55c1c672d3..d2f20d24d8 100644 --- a/plugins/catalog-backend/src/index.ts +++ b/plugins/catalog-backend/src/index.ts @@ -20,7 +20,6 @@ * @packageDocumentation */ -export * from './catalog'; export * from './ingestion'; export * from './modules'; export * from './processing'; diff --git a/plugins/catalog-backend/src/permissions/rules/isEntityKind.ts b/plugins/catalog-backend/src/permissions/rules/isEntityKind.ts index 8ebad5521c..568aae4838 100644 --- a/plugins/catalog-backend/src/permissions/rules/isEntityKind.ts +++ b/plugins/catalog-backend/src/permissions/rules/isEntityKind.ts @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import { RESOURCE_TYPE_CATALOG_ENTITY } from '@backstage/plugin-catalog-common/alpha'; import { z } from 'zod'; -import { EntitiesSearchFilter } from '../../catalog/types'; import { createCatalogPermissionRule } from './util'; /** @@ -36,7 +36,7 @@ export const isEntityKind = createCatalogPermissionRule({ const resourceKind = resource.kind.toLocaleLowerCase('en-US'); return kinds.some(kind => kind.toLocaleLowerCase('en-US') === resourceKind); }, - toQuery({ kinds }): EntitiesSearchFilter { + toQuery({ kinds }) { return { key: 'kind', values: kinds.map(kind => kind.toLocaleLowerCase('en-US')), diff --git a/plugins/catalog-backend/src/permissions/rules/util.ts b/plugins/catalog-backend/src/permissions/rules/util.ts index 466f5ce70b..c3e642490c 100644 --- a/plugins/catalog-backend/src/permissions/rules/util.ts +++ b/plugins/catalog-backend/src/permissions/rules/util.ts @@ -16,12 +16,12 @@ import { Entity } from '@backstage/catalog-model'; import { RESOURCE_TYPE_CATALOG_ENTITY } from '@backstage/plugin-catalog-common/alpha'; +import { EntitiesSearchFilter } from '@backstage/plugin-catalog-node'; import { PermissionRuleParams } from '@backstage/plugin-permission-common'; import { makeCreatePermissionRule, PermissionRule, } from '@backstage/plugin-permission-node'; -import { EntitiesSearchFilter } from '../../catalog/types'; /** * Convenience type for {@link @backstage/plugin-permission-node#PermissionRule} diff --git a/plugins/catalog-backend/src/service/AuthorizedEntitiesCatalog.test.ts b/plugins/catalog-backend/src/service/AuthorizedEntitiesCatalog.test.ts index 2ee47dae19..ce9221e16e 100644 --- a/plugins/catalog-backend/src/service/AuthorizedEntitiesCatalog.test.ts +++ b/plugins/catalog-backend/src/service/AuthorizedEntitiesCatalog.test.ts @@ -20,8 +20,9 @@ import { createConditionTransformer } from '@backstage/plugin-permission-node'; import { isEntityKind } from '../permissions/rules/isEntityKind'; import { CatalogPermissionRule } from '../permissions/rules'; import { AuthorizedEntitiesCatalog } from './AuthorizedEntitiesCatalog'; -import { Cursor, EntityFilter, QueryEntitiesResponse } from '../catalog/types'; +import { Cursor, QueryEntitiesResponse } from '../catalog/types'; import { Entity } from '@backstage/catalog-model'; +import { EntityFilter } from '@backstage/plugin-catalog-node'; describe('AuthorizedEntitiesCatalog', () => { const fakeCatalog = { diff --git a/plugins/catalog-backend/src/service/AuthorizedEntitiesCatalog.ts b/plugins/catalog-backend/src/service/AuthorizedEntitiesCatalog.ts index 0ce1ee87e7..6a04c4d7a1 100644 --- a/plugins/catalog-backend/src/service/AuthorizedEntitiesCatalog.ts +++ b/plugins/catalog-backend/src/service/AuthorizedEntitiesCatalog.ts @@ -35,12 +35,12 @@ import { EntityAncestryResponse, EntityFacetsRequest, EntityFacetsResponse, - EntityFilter, QueryEntitiesRequest, QueryEntitiesResponse, } from '../catalog/types'; import { basicEntityFilter } from './request/basicEntityFilter'; import { isQueryEntitiesCursorRequest } from './util'; +import { EntityFilter } from '@backstage/plugin-catalog-node'; export class AuthorizedEntitiesCatalog implements EntitiesCatalog { constructor( diff --git a/plugins/catalog-backend/src/service/CatalogBuilder.ts b/plugins/catalog-backend/src/service/CatalogBuilder.ts index 5cf76ee1ac..f8ed166118 100644 --- a/plugins/catalog-backend/src/service/CatalogBuilder.ts +++ b/plugins/catalog-backend/src/service/CatalogBuilder.ts @@ -37,6 +37,7 @@ import lodash, { keyBy } from 'lodash'; import { CatalogProcessor, CatalogProcessorParser, + EntitiesSearchFilter, EntityProvider, ScmLocationAnalyzer, } from '@backstage/plugin-catalog-node'; @@ -79,7 +80,6 @@ import { Config, readDurationFromConfig } from '@backstage/config'; import { Logger } from 'winston'; import { connectEntityProviders } from '../processing/connectEntityProviders'; import { PermissionRuleParams } from '@backstage/plugin-permission-common'; -import { EntitiesSearchFilter } from '../catalog/types'; import { permissionRules as catalogPermissionRules } from '../permissions/rules'; import { PermissionRule } from '@backstage/plugin-permission-node'; import { diff --git a/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.ts b/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.ts index 24f0432419..0245fe1d4e 100644 --- a/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.ts +++ b/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.ts @@ -31,11 +31,9 @@ import { EntitiesCatalog, EntitiesRequest, EntitiesResponse, - EntitiesSearchFilter, EntityAncestryResponse, EntityFacetsRequest, EntityFacetsResponse, - EntityFilter, EntityPagination, QueryEntitiesRequest, QueryEntitiesResponse, @@ -55,6 +53,10 @@ import { isQueryEntitiesCursorRequest, isQueryEntitiesInitialRequest, } from './util'; +import { + EntitiesSearchFilter, + EntityFilter, +} from '@backstage/plugin-catalog-node'; const defaultSortField: EntityOrder = { field: 'metadata.uid', diff --git a/plugins/catalog-backend/src/service/request/basicEntityFilter.ts b/plugins/catalog-backend/src/service/request/basicEntityFilter.ts index 36448e0304..43824160a2 100644 --- a/plugins/catalog-backend/src/service/request/basicEntityFilter.ts +++ b/plugins/catalog-backend/src/service/request/basicEntityFilter.ts @@ -14,7 +14,10 @@ * limitations under the License. */ -import { EntitiesSearchFilter, EntityFilter } from '../../catalog'; +import { + EntitiesSearchFilter, + EntityFilter, +} from '@backstage/plugin-catalog-node'; /** * Forms a full EntityFilter based on a single key-value(s) object. diff --git a/plugins/catalog-backend/src/service/request/parseEntityFilterParams.ts b/plugins/catalog-backend/src/service/request/parseEntityFilterParams.ts index 767a36ce71..cfd9aa0aa5 100644 --- a/plugins/catalog-backend/src/service/request/parseEntityFilterParams.ts +++ b/plugins/catalog-backend/src/service/request/parseEntityFilterParams.ts @@ -15,8 +15,11 @@ */ import { InputError } from '@backstage/errors'; -import { EntitiesSearchFilter, EntityFilter } from '../../catalog'; import { parseStringsParam } from './common'; +import { + EntitiesSearchFilter, + EntityFilter, +} from '@backstage/plugin-catalog-node'; /** * Parses the filtering part of a query, like diff --git a/plugins/catalog-backend/src/service/util.ts b/plugins/catalog-backend/src/service/util.ts index 699bca2fc9..af1279a59a 100644 --- a/plugins/catalog-backend/src/service/util.ts +++ b/plugins/catalog-backend/src/service/util.ts @@ -20,11 +20,11 @@ import lodash from 'lodash'; import { z } from 'zod'; import { Cursor, - EntityFilter, QueryEntitiesCursorRequest, QueryEntitiesInitialRequest, QueryEntitiesRequest, } from '../catalog/types'; +import { EntityFilter } from '@backstage/plugin-catalog-node'; export async function requireRequestBody(req: Request): Promise { const contentType = req.header('content-type'); diff --git a/plugins/catalog-node/api-report-alpha.md b/plugins/catalog-node/api-report-alpha.md index 7350f9262c..74339b1bc9 100644 --- a/plugins/catalog-node/api-report-alpha.md +++ b/plugins/catalog-node/api-report-alpha.md @@ -5,6 +5,7 @@ ```ts import { CatalogApi } from '@backstage/catalog-client'; import { CatalogProcessor } from '@backstage/plugin-catalog-node'; +import { EntitiesSearchFilter } from '@backstage/plugin-catalog-node'; import { Entity } from '@backstage/catalog-model'; import { EntityProvider } from '@backstage/plugin-catalog-node'; import { ExtensionPoint } from '@backstage/backend-plugin-api'; @@ -61,11 +62,5 @@ export const catalogProcessingExtensionPoint: ExtensionPoint; -// @alpha (undocumented) -export type EntitiesSearchFilter = { - key: string; - values?: string[]; -}; - // (No @packageDocumentation comment for this package) ``` diff --git a/plugins/catalog-node/api-report.md b/plugins/catalog-node/api-report.md index ef2c09e61f..a4ba95073f 100644 --- a/plugins/catalog-node/api-report.md +++ b/plugins/catalog-node/api-report.md @@ -105,6 +105,25 @@ export type DeferredEntity = { locationKey?: string; }; +// @public +export type EntitiesSearchFilter = { + key: string; + values?: string[]; +}; + +// @public +export type EntityFilter = + | { + allOf: EntityFilter[]; + } + | { + anyOf: EntityFilter[]; + } + | { + not: EntityFilter; + } + | EntitiesSearchFilter; + // @public export interface EntityProvider { connect(connection: EntityProviderConnection): Promise; diff --git a/plugins/catalog-node/src/alpha.ts b/plugins/catalog-node/src/alpha.ts index f7b2ceac12..3e958d1df1 100644 --- a/plugins/catalog-node/src/alpha.ts +++ b/plugins/catalog-node/src/alpha.ts @@ -19,9 +19,6 @@ export type { CatalogProcessingExtensionPoint } from './extensions'; export { catalogProcessingExtensionPoint } from './extensions'; export type { CatalogAnalysisExtensionPoint } from './extensions'; export { catalogAnalysisExtensionPoint } from './extensions'; -export type { - EntitiesSearchFilter, - CatalogPermissionRuleInput, -} from './extensions'; +export type { CatalogPermissionRuleInput } from './extensions'; export type { CatalogPermissionExtensionPoint } from './extensions'; export { catalogPermissionExtensionPoint } from './extensions'; diff --git a/plugins/catalog-node/src/api/common.ts b/plugins/catalog-node/src/api/common.ts index c91aeca2d9..7f9bd3eabf 100644 --- a/plugins/catalog-node/src/api/common.ts +++ b/plugins/catalog-node/src/api/common.ts @@ -52,3 +52,36 @@ export type EntityRelationSpec = { */ target: CompoundEntityRef; }; + +/** + * A filter expression for entities. + * + * @public + */ +export type EntityFilter = + | { allOf: EntityFilter[] } + | { anyOf: EntityFilter[] } + | { not: EntityFilter } + | EntitiesSearchFilter; + +/** + * Matches rows in the search table. + * + * @public + */ +export type EntitiesSearchFilter = { + /** + * The key to match on. + * + * Matches are always case insensitive. + */ + key: string; + + /** + * Match on plain equality of values. + * + * Match on values that are equal to any of the given array items. Matches are + * always case insensitive. + */ + values?: string[]; +}; diff --git a/plugins/catalog-node/src/api/index.ts b/plugins/catalog-node/src/api/index.ts index 66e8d6bd21..292a6cd872 100644 --- a/plugins/catalog-node/src/api/index.ts +++ b/plugins/catalog-node/src/api/index.ts @@ -15,7 +15,12 @@ */ export { processingResult } from './processingResult'; -export type { EntityRelationSpec, LocationSpec } from './common'; +export type { + EntityRelationSpec, + LocationSpec, + EntitiesSearchFilter, + EntityFilter, +} from './common'; export type { CatalogProcessor, CatalogProcessorParser, diff --git a/plugins/catalog-node/src/extensions.ts b/plugins/catalog-node/src/extensions.ts index 2dd0915ccf..7aa9264030 100644 --- a/plugins/catalog-node/src/extensions.ts +++ b/plugins/catalog-node/src/extensions.ts @@ -13,14 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import { createExtensionPoint } from '@backstage/backend-plugin-api'; +import { Entity } from '@backstage/catalog-model'; import { - EntityProvider, CatalogProcessor, + EntitiesSearchFilter, + EntityProvider, PlaceholderResolver, ScmLocationAnalyzer, } from '@backstage/plugin-catalog-node'; -import { Entity } from '@backstage/catalog-model'; import { PermissionRuleParams } from '@backstage/plugin-permission-common'; import { PermissionRule } from '@backstage/plugin-permission-node'; @@ -60,14 +62,6 @@ export const catalogAnalysisExtensionPoint = id: 'catalog.analysis', }); -/** - * @alpha - */ -export type EntitiesSearchFilter = { - key: string; - values?: string[]; -}; - /** * @alpha */ From d14ac048973013d851712bc8050d7951431f8825 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 29 Nov 2023 20:07:52 +0000 Subject: [PATCH 240/261] chore(deps): update dependency @types/node to v16.18.66 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/yarn.lock b/yarn.lock index 00cd2021f1..523367c015 100644 --- a/yarn.lock +++ b/yarn.lock @@ -18637,11 +18637,11 @@ __metadata: linkType: hard "@types/node@npm:*, @types/node@npm:>=12.12.47, @types/node@npm:>=13.7.0, @types/node@npm:^20.1.1": - version: 20.9.5 - resolution: "@types/node@npm:20.9.5" + version: 20.10.1 + resolution: "@types/node@npm:20.10.1" dependencies: undici-types: ~5.26.4 - checksum: 050ebd958e31ad21143f93614a25b15a8de5d0004338359409f76a661f734c4549698d852f21176c62f5661dacb572a090669cffef93cf6361c959e4d27d8d95 + checksum: 9dfdcd2496ce535dba0ae496985d6e991a8a5d70a180db3a94c947a2123d99318a95dce4aa2a192f7e57c3afa3fdb44d6fd63e18efd49568950d6c239dadcc39 languageName: node linkType: hard @@ -18660,9 +18660,9 @@ __metadata: linkType: hard "@types/node@npm:^16.11.26, @types/node@npm:^16.7.10, @types/node@npm:^16.9.2": - version: 16.18.65 - resolution: "@types/node@npm:16.18.65" - checksum: c53cd5bfff0b6868c2735c7afb24008b23ce204ce090cc4fd1bbe0515de32f1088d401183ecb1a329ea69ab81591ca4935875d0744abb4bd60f4f85810d8446e + version: 16.18.66 + resolution: "@types/node@npm:16.18.66" + checksum: 84408652068f8c7e3aa1fa6f333be8044ae802a700eb3b4101fc27d047eefcc742e636809a6318fb0100b1355658649f4a0fc2398fb04f27b1a357f6f3579cd0 languageName: node linkType: hard @@ -18674,11 +18674,11 @@ __metadata: linkType: hard "@types/node@npm:^18.17.8": - version: 18.18.13 - resolution: "@types/node@npm:18.18.13" + version: 18.18.14 + resolution: "@types/node@npm:18.18.14" dependencies: undici-types: ~5.26.4 - checksum: e36d7a0ea6ce8fb771fd84dc2412935408448c1fed098205d3103be661852fc40d22a987e6c6c926a20719a15266e3071c8d4fd2548a96ad6c3c74eb474b5e63 + checksum: 3a77e6819e50fd22196b08d542433e1513c855f4993a200bc0e7be076445c61ce2a9e5f7f202f060c46130b2b2f98643461fb7999f874475e6bb322c4534c580 languageName: node linkType: hard From f230f8728c212eeb03cd7bef6f2118c759c4b715 Mon Sep 17 00:00:00 2001 From: Florian JUDITH Date: Wed, 29 Nov 2023 15:26:40 -0500 Subject: [PATCH 241/261] Added configSchema Signed-off-by: Florian JUDITH --- plugins/lighthouse-backend/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/lighthouse-backend/package.json b/plugins/lighthouse-backend/package.json index 89d9b2f8ec..f1a81a8342 100644 --- a/plugins/lighthouse-backend/package.json +++ b/plugins/lighthouse-backend/package.json @@ -27,6 +27,7 @@ "dist", "config.d.ts" ], + "configSchema": "config.d.ts", "scripts": { "build": "backstage-cli package build", "lint": "backstage-cli package lint", From 7b276e339edba8c91180e2f75b0e2c3d3a580f62 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 29 Nov 2023 20:49:11 +0000 Subject: [PATCH 242/261] fix(deps): update aws-sdk-js-v3 monorepo to v3.462.0 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 78 +++++++++++++++++++++++++++---------------------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/yarn.lock b/yarn.lock index 523367c015..1cd654b9c6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -397,13 +397,13 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/client-cognito-identity@npm:3.461.0": - version: 3.461.0 - resolution: "@aws-sdk/client-cognito-identity@npm:3.461.0" +"@aws-sdk/client-cognito-identity@npm:3.462.0": + version: 3.462.0 + resolution: "@aws-sdk/client-cognito-identity@npm:3.462.0" dependencies: "@aws-crypto/sha256-browser": 3.0.0 "@aws-crypto/sha256-js": 3.0.0 - "@aws-sdk/client-sts": 3.461.0 + "@aws-sdk/client-sts": 3.462.0 "@aws-sdk/core": 3.451.0 "@aws-sdk/credential-provider-node": 3.460.0 "@aws-sdk/middleware-host-header": 3.460.0 @@ -440,17 +440,17 @@ __metadata: "@smithy/util-retry": ^2.0.6 "@smithy/util-utf8": ^2.0.2 tslib: ^2.5.0 - checksum: 8f898c4469516e2f0d835d31f071213769405085123628c73c7ca70c8edc1d8f9551778bd7ac74d31f73bddc60929d0f7623ed65d49fcc2786d76c2a81b20e8d + checksum: e1f7839e977dfafb1d99df9fd781c6fe0830f3e8383ca975dc06cda5a31b25e5dcd95da37f524ed3665b2d46616f7660085bec31dfb79f73471170fa960b0aa2 languageName: node linkType: hard "@aws-sdk/client-eks@npm:^3.350.0": - version: 3.461.0 - resolution: "@aws-sdk/client-eks@npm:3.461.0" + version: 3.462.0 + resolution: "@aws-sdk/client-eks@npm:3.462.0" dependencies: "@aws-crypto/sha256-browser": 3.0.0 "@aws-crypto/sha256-js": 3.0.0 - "@aws-sdk/client-sts": 3.461.0 + "@aws-sdk/client-sts": 3.462.0 "@aws-sdk/core": 3.451.0 "@aws-sdk/credential-provider-node": 3.460.0 "@aws-sdk/middleware-host-header": 3.460.0 @@ -489,17 +489,17 @@ __metadata: "@smithy/util-waiter": ^2.0.13 tslib: ^2.5.0 uuid: ^8.3.2 - checksum: 7bf17138ac0e14f2381c4fc275b7287453749b70e12d2b74168b62ec78f90f13e83b552c08ee10accfd7344367c6d49a1e5ac2f513d3da5a7e9cb9d2524fe262 + checksum: 92b89f2850784250c529dd041f3d7e59293130dc8f6a941851513fbbf8c44097cab1e6b6caedbd659668b8f9232f9c8818c3e991bc5f05e8dae10694c46de3ae languageName: node linkType: hard "@aws-sdk/client-organizations@npm:^3.350.0": - version: 3.461.0 - resolution: "@aws-sdk/client-organizations@npm:3.461.0" + version: 3.462.0 + resolution: "@aws-sdk/client-organizations@npm:3.462.0" dependencies: "@aws-crypto/sha256-browser": 3.0.0 "@aws-crypto/sha256-js": 3.0.0 - "@aws-sdk/client-sts": 3.461.0 + "@aws-sdk/client-sts": 3.462.0 "@aws-sdk/core": 3.451.0 "@aws-sdk/credential-provider-node": 3.460.0 "@aws-sdk/middleware-host-header": 3.460.0 @@ -536,18 +536,18 @@ __metadata: "@smithy/util-retry": ^2.0.6 "@smithy/util-utf8": ^2.0.2 tslib: ^2.5.0 - checksum: 38cfcf405e4061c5ebd88c6726fdd2cfcd8f6a6c68a896b5590cc37d36d5b9ad32a4699ae8b4e2f39a94d4abb7fc16f2acebcf047062ff95ef95dc6a3d6042d5 + checksum: cf3db6fb3b4f06a4fdec3d6d2bbd5e23f8e66f476cda2fa9821b484de03572016685864ac2229ac14eb348105cdcd86c18030afa2973691ab79f586bdd4a84f9 languageName: node linkType: hard "@aws-sdk/client-s3@npm:^3.350.0": - version: 3.461.0 - resolution: "@aws-sdk/client-s3@npm:3.461.0" + version: 3.462.0 + resolution: "@aws-sdk/client-s3@npm:3.462.0" dependencies: "@aws-crypto/sha1-browser": 3.0.0 "@aws-crypto/sha256-browser": 3.0.0 "@aws-crypto/sha256-js": 3.0.0 - "@aws-sdk/client-sts": 3.461.0 + "@aws-sdk/client-sts": 3.462.0 "@aws-sdk/core": 3.451.0 "@aws-sdk/credential-provider-node": 3.460.0 "@aws-sdk/middleware-bucket-endpoint": 3.460.0 @@ -601,17 +601,17 @@ __metadata: "@smithy/util-waiter": ^2.0.13 fast-xml-parser: 4.2.5 tslib: ^2.5.0 - checksum: e7411d29b59fa19a3d960bb4dbbca967e8ef8b31c682c2cb9630511af19e9788471bc987700b39857f95687c25db1ec73661a9b20507c4260f5f10539be3f9d9 + checksum: dc48dd3b956f1ba2d3942e4806eb7d35d8c3c54b056cd3c704d83227642fe5f4d6d4545f14e6dad8b0d0a1b347884e28cabf8abe7d8385bbdbf15a5b860a7a0e languageName: node linkType: hard "@aws-sdk/client-sqs@npm:^3.350.0": - version: 3.461.0 - resolution: "@aws-sdk/client-sqs@npm:3.461.0" + version: 3.462.0 + resolution: "@aws-sdk/client-sqs@npm:3.462.0" dependencies: "@aws-crypto/sha256-browser": 3.0.0 "@aws-crypto/sha256-js": 3.0.0 - "@aws-sdk/client-sts": 3.461.0 + "@aws-sdk/client-sts": 3.462.0 "@aws-sdk/core": 3.451.0 "@aws-sdk/credential-provider-node": 3.460.0 "@aws-sdk/middleware-host-header": 3.460.0 @@ -650,7 +650,7 @@ __metadata: "@smithy/util-retry": ^2.0.6 "@smithy/util-utf8": ^2.0.2 tslib: ^2.5.0 - checksum: c72dd8822d25646200db96b506f770a8d12480bf25a42d6780289feb0f4eb4b49967615b96de4e28e9fb6b034d5f050f40b279fde58dd75c0cb769d948de243c + checksum: 4112bd08a25daee6250d6d60f8787cc70f0a02938e7e0eae9bd87dc24c5f7872ae34f2e53791bb097d34590da457a2303bb8a3d1f35277f0e51427e166a77f0f languageName: node linkType: hard @@ -698,9 +698,9 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/client-sts@npm:3.461.0, @aws-sdk/client-sts@npm:^3.350.0": - version: 3.461.0 - resolution: "@aws-sdk/client-sts@npm:3.461.0" +"@aws-sdk/client-sts@npm:3.462.0, @aws-sdk/client-sts@npm:^3.350.0": + version: 3.462.0 + resolution: "@aws-sdk/client-sts@npm:3.462.0" dependencies: "@aws-crypto/sha256-browser": 3.0.0 "@aws-crypto/sha256-js": 3.0.0 @@ -742,7 +742,7 @@ __metadata: "@smithy/util-utf8": ^2.0.2 fast-xml-parser: 4.2.5 tslib: ^2.5.0 - checksum: c5a665212815ae606c48b11b38cea41bfbc7f6c422f44eb51d71bf748cd8275ac4ac7e03207b992e58e43c46f7f4070d551dcd4dd3cbe704a72fa7d7b3efe613 + checksum: 7e1882a815b90c406b5104cb9f38edffd215af1bf092848531a9bf0b623461e53da36736b04de35e8582a68cb3641ec8f7dbecd364a699426bf32f235a08b5b0 languageName: node linkType: hard @@ -756,16 +756,16 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/credential-provider-cognito-identity@npm:3.461.0": - version: 3.461.0 - resolution: "@aws-sdk/credential-provider-cognito-identity@npm:3.461.0" +"@aws-sdk/credential-provider-cognito-identity@npm:3.462.0": + version: 3.462.0 + resolution: "@aws-sdk/credential-provider-cognito-identity@npm:3.462.0" dependencies: - "@aws-sdk/client-cognito-identity": 3.461.0 + "@aws-sdk/client-cognito-identity": 3.462.0 "@aws-sdk/types": 3.460.0 "@smithy/property-provider": ^2.0.0 "@smithy/types": ^2.5.0 tslib: ^2.5.0 - checksum: 3448131b14b652726a2298b8ce9bb5eb5fac403eb381d70292ca879c4a4d9ccf834f9768033d0913b6f74d8654cacf5fc8493963bc675d521f371654c67daca2 + checksum: 02afd72dc4addc86c33120f574a2e1b97d91f387535406af26ee5bea10aa74da005dae4eac0b6632d9d21d368d42587ff117f20da269669e9b7bb2c56c5fbc05 languageName: node linkType: hard @@ -876,13 +876,13 @@ __metadata: linkType: hard "@aws-sdk/credential-providers@npm:^3.350.0": - version: 3.461.0 - resolution: "@aws-sdk/credential-providers@npm:3.461.0" + version: 3.462.0 + resolution: "@aws-sdk/credential-providers@npm:3.462.0" dependencies: - "@aws-sdk/client-cognito-identity": 3.461.0 + "@aws-sdk/client-cognito-identity": 3.462.0 "@aws-sdk/client-sso": 3.460.0 - "@aws-sdk/client-sts": 3.461.0 - "@aws-sdk/credential-provider-cognito-identity": 3.461.0 + "@aws-sdk/client-sts": 3.462.0 + "@aws-sdk/credential-provider-cognito-identity": 3.462.0 "@aws-sdk/credential-provider-env": 3.460.0 "@aws-sdk/credential-provider-http": 3.460.0 "@aws-sdk/credential-provider-ini": 3.460.0 @@ -895,7 +895,7 @@ __metadata: "@smithy/property-provider": ^2.0.0 "@smithy/types": ^2.5.0 tslib: ^2.5.0 - checksum: da0f30eb3e3462740406cbcdd88798c54735f2de1dbaef387a1774b49ee41686cff90836e5a07ab234f2b64981244b818c2635b4a1278fc3ff4ede33b735e775 + checksum: 5b552c761baf459c502afba5b7e600d9f70a155d8a3892c17559db06b6cb653363c88f4ad581d896b9bfb33d3e233d08e0ede69883cf3bc910157059c8ac5ce0 languageName: node linkType: hard @@ -921,8 +921,8 @@ __metadata: linkType: hard "@aws-sdk/lib-storage@npm:^3.350.0": - version: 3.461.0 - resolution: "@aws-sdk/lib-storage@npm:3.461.0" + version: 3.462.0 + resolution: "@aws-sdk/lib-storage@npm:3.462.0" dependencies: "@smithy/abort-controller": ^2.0.1 "@smithy/middleware-endpoint": ^2.2.0 @@ -933,7 +933,7 @@ __metadata: tslib: ^2.5.0 peerDependencies: "@aws-sdk/client-s3": ^3.0.0 - checksum: 46b3363880c1214c9d549b771a5c20405a6ca5535e0e6004254d30f9dce042297b85d800e72cec105dd643ebbb98e02bed4f414ed66f7122b0b8cf0a80dacf35 + checksum: 1d294ebc76f822397f8594c6c7e998532d71f0f5dd32b36641b55185f7298855377952e179e65d3c725a4286be2d09bd83a39da4f12a18457080a07abf92fb9f languageName: node linkType: hard From 1d775d7c3cacea6a3d617743ef979f2c5391e3cf Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 29 Nov 2023 21:27:02 +0000 Subject: [PATCH 243/261] fix(deps): update material-ui monorepo to v5.14.19 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 120 +++++++++++++++++++++++++++--------------------------- 1 file changed, 60 insertions(+), 60 deletions(-) diff --git a/yarn.lock b/yarn.lock index 1cd654b9c6..e7a25fbcd2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3175,12 +3175,12 @@ __metadata: languageName: node linkType: hard -"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.1, @babel/runtime@npm:^7.12.1, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.13.10, @babel/runtime@npm:^7.15.4, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.18.6, @babel/runtime@npm:^7.2.0, @babel/runtime@npm:^7.20.1, @babel/runtime@npm:^7.20.13, @babel/runtime@npm:^7.20.6, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.23.2, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.4.4, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.6.0, @babel/runtime@npm:^7.7.6, @babel/runtime@npm:^7.8.3, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2": - version: 7.23.2 - resolution: "@babel/runtime@npm:7.23.2" +"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.1, @babel/runtime@npm:^7.12.1, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.13.10, @babel/runtime@npm:^7.15.4, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.18.6, @babel/runtime@npm:^7.2.0, @babel/runtime@npm:^7.20.1, @babel/runtime@npm:^7.20.13, @babel/runtime@npm:^7.20.6, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.23.2, @babel/runtime@npm:^7.23.4, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.4.4, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.6.0, @babel/runtime@npm:^7.7.6, @babel/runtime@npm:^7.8.3, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2": + version: 7.23.5 + resolution: "@babel/runtime@npm:7.23.5" dependencies: regenerator-runtime: ^0.14.0 - checksum: 6c4df4839ec75ca10175f636d6362f91df8a3137f86b38f6cd3a4c90668a0fe8e9281d320958f4fbd43b394988958585a17c3aab2a4ea6bf7316b22916a371fb + checksum: 164d9802424f06908e62d29b8fd3a87db55accf82f46f964ac481dcead11ff7df8391e3696e5fa91a8ca10ea8845bf650acd730fa88cf13f8026cd8d5eec6936 languageName: node linkType: hard @@ -13297,14 +13297,14 @@ __metadata: languageName: node linkType: hard -"@mui/base@npm:5.0.0-beta.24": - version: 5.0.0-beta.24 - resolution: "@mui/base@npm:5.0.0-beta.24" +"@mui/base@npm:5.0.0-beta.25": + version: 5.0.0-beta.25 + resolution: "@mui/base@npm:5.0.0-beta.25" dependencies: - "@babel/runtime": ^7.23.2 + "@babel/runtime": ^7.23.4 "@floating-ui/react-dom": ^2.0.4 - "@mui/types": ^7.2.9 - "@mui/utils": ^5.14.18 + "@mui/types": ^7.2.10 + "@mui/utils": ^5.14.19 "@popperjs/core": ^2.11.8 clsx: ^2.0.0 prop-types: ^15.8.1 @@ -13315,28 +13315,28 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: dbd6eb0af7cb89389b1dccd6a84d07128c41f60d297d8f1d484919950c9b45a5d8767042b622c74e311bce0368ee3f760afb34d80ad97af61f5b5650ae990c60 + checksum: ce22c38593db1bbbb162574bd297bc3f2f5040ed6e304965e17aff55e4d15782e813196bd67c9b82757ee67675ad6d557e22541f84e4d7a4b6f3349dc83741f3 languageName: node linkType: hard -"@mui/core-downloads-tracker@npm:^5.14.18": - version: 5.14.18 - resolution: "@mui/core-downloads-tracker@npm:5.14.18" - checksum: 3d367797282e4b93eacee997667d62bc4eeac979e9664724e9db8d632278d8629f2a141894cf53d706f1d2a9f19965bffe2858aa2bc9833722e674cd560b896e +"@mui/core-downloads-tracker@npm:^5.14.19": + version: 5.14.19 + resolution: "@mui/core-downloads-tracker@npm:5.14.19" + checksum: e71c886f12bbd83791638545017c0b8439c3c6b51125979fea105f938f2f5b109629d4deddd38448c05b8be10b3249334324f1505c1306c52a2b8d315a1005c3 languageName: node linkType: hard "@mui/material@npm:^5.12.2": - version: 5.14.18 - resolution: "@mui/material@npm:5.14.18" + version: 5.14.19 + resolution: "@mui/material@npm:5.14.19" dependencies: - "@babel/runtime": ^7.23.2 - "@mui/base": 5.0.0-beta.24 - "@mui/core-downloads-tracker": ^5.14.18 - "@mui/system": ^5.14.18 - "@mui/types": ^7.2.9 - "@mui/utils": ^5.14.18 - "@types/react-transition-group": ^4.4.8 + "@babel/runtime": ^7.23.4 + "@mui/base": 5.0.0-beta.25 + "@mui/core-downloads-tracker": ^5.14.19 + "@mui/system": ^5.14.19 + "@mui/types": ^7.2.10 + "@mui/utils": ^5.14.19 + "@types/react-transition-group": ^4.4.9 clsx: ^2.0.0 csstype: ^3.1.2 prop-types: ^15.8.1 @@ -13355,16 +13355,16 @@ __metadata: optional: true "@types/react": optional: true - checksum: 488322f09638a71bb5d4bb5c027dde69d5cf89bcfd433594e3b90fea9fefa302bc85b9d2bf386493bf68d360107b59c6d148f46a68477e7f472f4f2d14d698a3 + checksum: 8fc63b7ecb98c5eb8f67190cde096f83100af9271fe2113e1d3edb13a08650f611e7ff186b04c66695958cc88480011ab31dc950cf0fd6e0fbb6c727ec834cbd languageName: node linkType: hard -"@mui/private-theming@npm:^5.14.18": - version: 5.14.18 - resolution: "@mui/private-theming@npm:5.14.18" +"@mui/private-theming@npm:^5.14.18, @mui/private-theming@npm:^5.14.19": + version: 5.14.19 + resolution: "@mui/private-theming@npm:5.14.19" dependencies: - "@babel/runtime": ^7.23.2 - "@mui/utils": ^5.14.18 + "@babel/runtime": ^7.23.4 + "@mui/utils": ^5.14.19 prop-types: ^15.8.1 peerDependencies: "@types/react": ^17.0.0 || ^18.0.0 @@ -13372,15 +13372,15 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: e7ba8e945f589db16ed05d507b0821d2e07b3d760bf78c9f745a75d75b5a94d1e546278629de15b090de289a9244591bfa2c09bb9f9f8679fb4e1d8cec360833 + checksum: ee17fa123ae671fcfb6e59787e9a5b6d650d4a53ea575f5d5519dd187c9b04fbb50f12f2da5a663d3ba3a82d503086faa18bf3b68923237de78f44e401e04935 languageName: node linkType: hard -"@mui/styled-engine@npm:^5.14.18": - version: 5.14.18 - resolution: "@mui/styled-engine@npm:5.14.18" +"@mui/styled-engine@npm:^5.14.19": + version: 5.14.19 + resolution: "@mui/styled-engine@npm:5.14.19" dependencies: - "@babel/runtime": ^7.23.2 + "@babel/runtime": ^7.23.4 "@emotion/cache": ^11.11.0 csstype: ^3.1.2 prop-types: ^15.8.1 @@ -13393,7 +13393,7 @@ __metadata: optional: true "@emotion/styled": optional: true - checksum: 6eba307d95ef462f8b80aaa50ec1db7409d19cead985eba28e86aec066ad4bc70b0daa6d89158a7aae88ea43d614cace5f890cbebe0d8636573e894b7da9cae1 + checksum: 2b8dc8e08e47e18ad6345d25539d5978ef153cb23abff3d98c3cf2795f836e446279021392c2071142ffbae17e19906235acfb3e73dc0f14440b138f919a26a4 languageName: node linkType: hard @@ -13428,15 +13428,15 @@ __metadata: languageName: node linkType: hard -"@mui/system@npm:^5.14.18": - version: 5.14.18 - resolution: "@mui/system@npm:5.14.18" +"@mui/system@npm:^5.14.19": + version: 5.14.19 + resolution: "@mui/system@npm:5.14.19" dependencies: - "@babel/runtime": ^7.23.2 - "@mui/private-theming": ^5.14.18 - "@mui/styled-engine": ^5.14.18 - "@mui/types": ^7.2.9 - "@mui/utils": ^5.14.18 + "@babel/runtime": ^7.23.4 + "@mui/private-theming": ^5.14.19 + "@mui/styled-engine": ^5.14.19 + "@mui/types": ^7.2.10 + "@mui/utils": ^5.14.19 clsx: ^2.0.0 csstype: ^3.1.2 prop-types: ^15.8.1 @@ -13452,28 +13452,28 @@ __metadata: optional: true "@types/react": optional: true - checksum: 8f7c4f3555ee64467826e1a40cfdb34b5c02520fd9f27779b8e6aa97cb9bbd27d98386a194d2e4c44b148babe5f67e3a715f8a09c03a1d71f2f14ddf60045174 + checksum: aea4935cf72a7c4fe3d03eb040491204b0c20fbae19fc73173ec925c9025375601f6b7007e53b5ab6ea44a4dd74b94e9acc9ada85461db1deae9062f8506a99a languageName: node linkType: hard -"@mui/types@npm:^7.2.9": - version: 7.2.9 - resolution: "@mui/types@npm:7.2.9" +"@mui/types@npm:^7.2.10, @mui/types@npm:^7.2.9": + version: 7.2.10 + resolution: "@mui/types@npm:7.2.10" peerDependencies: "@types/react": ^17.0.0 || ^18.0.0 peerDependenciesMeta: "@types/react": optional: true - checksum: 4888a1cf9a1adbae1c2f53ba9f8a0cf23eb5e0954bca00b958c240c87b5287771cb5e99bedb61a2c04f5dcbdef13a5b1f238153e98d8959ba51c5470db2c4b32 + checksum: b9c4629929450e243015d79cf6b102824336db07b852e55f114aca85dbad0b39f831e9c65ad94b028a65c08d33be9f7de1afb530a4e6a80be5702b396ccb90b1 languageName: node linkType: hard -"@mui/utils@npm:^5.14.15, @mui/utils@npm:^5.14.18": - version: 5.14.18 - resolution: "@mui/utils@npm:5.14.18" +"@mui/utils@npm:^5.14.15, @mui/utils@npm:^5.14.18, @mui/utils@npm:^5.14.19": + version: 5.14.19 + resolution: "@mui/utils@npm:5.14.19" dependencies: - "@babel/runtime": ^7.23.2 - "@types/prop-types": ^15.7.10 + "@babel/runtime": ^7.23.4 + "@types/prop-types": ^15.7.11 prop-types: ^15.8.1 react-is: ^18.2.0 peerDependencies: @@ -13482,7 +13482,7 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: f24badcb6b026b392b94919f65c7f3bea6cfb0f741c1b8ebd74b02bba9ffc61f72e35bdea887e47dfd97d37ff465863aa29c7c5cfd33fb83224f4ff2300432b3 + checksum: f53f746eb33bc5d700b9f2b454e211ca17f5aa320cd30f54a82a347e4da0c61b872f323f01ff4b5247d3f992ac4f72a69ac79974300a6dedf01ff6b8f6d75b49 languageName: node linkType: hard @@ -18839,7 +18839,7 @@ __metadata: languageName: node linkType: hard -"@types/prop-types@npm:*, @types/prop-types@npm:^15.0.0, @types/prop-types@npm:^15.7.10, @types/prop-types@npm:^15.7.3": +"@types/prop-types@npm:*, @types/prop-types@npm:^15.0.0, @types/prop-types@npm:^15.7.11, @types/prop-types@npm:^15.7.3": version: 15.7.11 resolution: "@types/prop-types@npm:15.7.11" checksum: 7519ff11d06fbf6b275029fe03fff9ec377b4cb6e864cac34d87d7146c7f5a7560fd164bdc1d2dbe00b60c43713631251af1fd3d34d46c69cd354602bc0c7c54 @@ -18962,12 +18962,12 @@ __metadata: languageName: node linkType: hard -"@types/react-transition-group@npm:^4.2.0, @types/react-transition-group@npm:^4.4.8": - version: 4.4.8 - resolution: "@types/react-transition-group@npm:4.4.8" +"@types/react-transition-group@npm:^4.2.0, @types/react-transition-group@npm:^4.4.9": + version: 4.4.9 + resolution: "@types/react-transition-group@npm:4.4.9" dependencies: "@types/react": "*" - checksum: ad7ba2bce97631fda9d89b4ed9772489bd050fec3ccd7563041b206dbe219d37d22e0d7731b1f90f56e89daf40e69ba16beba8066c42165bf8a584533feb6a2c + checksum: be9e256e53919a7cf3b4a075f6d01c0a2dd3a67911dd28276aa6158be4beade4ca5327cbf1f096c28b413e04989f069122319b02e5a09c280d903a0accea9ead languageName: node linkType: hard From 4c2c7308c72aaa136a5aaacab1a7c08984fc7ddd Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 29 Nov 2023 22:01:42 +0000 Subject: [PATCH 244/261] chore(deps): update dependency @mui/styles to v5.14.19 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/yarn.lock b/yarn.lock index e7a25fbcd2..e4a2828d94 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13359,7 +13359,7 @@ __metadata: languageName: node linkType: hard -"@mui/private-theming@npm:^5.14.18, @mui/private-theming@npm:^5.14.19": +"@mui/private-theming@npm:^5.14.19": version: 5.14.19 resolution: "@mui/private-theming@npm:5.14.19" dependencies: @@ -13398,14 +13398,14 @@ __metadata: linkType: hard "@mui/styles@npm:^5.14.18": - version: 5.14.18 - resolution: "@mui/styles@npm:5.14.18" + version: 5.14.19 + resolution: "@mui/styles@npm:5.14.19" dependencies: - "@babel/runtime": ^7.23.2 + "@babel/runtime": ^7.23.4 "@emotion/hash": ^0.9.1 - "@mui/private-theming": ^5.14.18 - "@mui/types": ^7.2.9 - "@mui/utils": ^5.14.18 + "@mui/private-theming": ^5.14.19 + "@mui/types": ^7.2.10 + "@mui/utils": ^5.14.19 clsx: ^2.0.0 csstype: ^3.1.2 hoist-non-react-statics: ^3.3.2 @@ -13424,7 +13424,7 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: c3a50ff3ab96e931f1506431de70c173af49c7a7d9410a2d132f65ef789f38f4cc742f456cfc16b24ecb7cb492b30dc1afb653cf31318b7059fd52fa790983b5 + checksum: 03780cba63ee5dca4bd3f81aa8634039e6a18291eb2f89cdcee236669e4b05a2593a3e5e74c21378950cc34a790163d2d3b80d2b649fd368a5b09439f198489e languageName: node linkType: hard @@ -13456,7 +13456,7 @@ __metadata: languageName: node linkType: hard -"@mui/types@npm:^7.2.10, @mui/types@npm:^7.2.9": +"@mui/types@npm:^7.2.10": version: 7.2.10 resolution: "@mui/types@npm:7.2.10" peerDependencies: @@ -13468,7 +13468,7 @@ __metadata: languageName: node linkType: hard -"@mui/utils@npm:^5.14.15, @mui/utils@npm:^5.14.18, @mui/utils@npm:^5.14.19": +"@mui/utils@npm:^5.14.15, @mui/utils@npm:^5.14.19": version: 5.14.19 resolution: "@mui/utils@npm:5.14.19" dependencies: From 60ee2448d08e485ad9bee1e9c92183b16acb0fb5 Mon Sep 17 00:00:00 2001 From: Florian JUDITH Date: Wed, 29 Nov 2023 22:29:06 -0500 Subject: [PATCH 245/261] Fixed scheduled defaults Signed-off-by: Florian JUDITH --- plugins/lighthouse-backend/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/lighthouse-backend/README.md b/plugins/lighthouse-backend/README.md index e2d1917f22..687467f1d5 100644 --- a/plugins/lighthouse-backend/README.md +++ b/plugins/lighthouse-backend/README.md @@ -87,7 +87,7 @@ You can define how often and when the scheduler should run the audits: lighthouse: schedule: frequency: - hours: 12 # Default: days 1 + hours: 12 # Default: 1 day timeout: - minutes: 30 # Default: null + minutes: 30 # Default: 10 minutes ``` From 5bb52409eea6a1c2b1dd457c445af1e667a40a11 Mon Sep 17 00:00:00 2001 From: Jasper Boeijenga Date: Thu, 30 Nov 2023 09:10:18 +0100 Subject: [PATCH 246/261] Fixed issue for showing undefined for hidden form items Signed-off-by: Jasper Boeijenga --- .changeset/wet-bananas-agree.md | 5 ++ .../ReviewState/ReviewState.test.tsx | 4 +- .../components/ReviewState/ReviewState.tsx | 62 ++++++++++--------- 3 files changed, 39 insertions(+), 32 deletions(-) create mode 100644 .changeset/wet-bananas-agree.md diff --git a/.changeset/wet-bananas-agree.md b/.changeset/wet-bananas-agree.md new file mode 100644 index 0000000000..4bf47ca664 --- /dev/null +++ b/.changeset/wet-bananas-agree.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-react': patch +--- + +Fixed issue for showing undefined for hidden form items diff --git a/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.test.tsx b/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.test.tsx index 7493a3fdbe..e9277b2230 100644 --- a/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.test.tsx +++ b/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.test.tsx @@ -94,10 +94,10 @@ describe('ReviewState', () => { }, ]; - const { queryByRole } = render( + const { queryByRole, getAllByRole } = render( , ); - + expect(getAllByRole('row').length).toEqual(1); expect(queryByRole('row', { name: 'Name ******' })).not.toBeInTheDocument(); }); diff --git a/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.tsx b/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.tsx index 38f1913ced..b601f77bf6 100644 --- a/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.tsx +++ b/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.tsx @@ -34,42 +34,44 @@ export type ReviewStateProps = { */ export const ReviewState = (props: ReviewStateProps) => { const reviewData = Object.fromEntries( - Object.entries(props.formState).map(([key, value]) => { - for (const step of props.schemas) { - const parsedSchema = new JSONSchema(step.mergedSchema); - const definitionInSchema = parsedSchema.getSchema( - `#/${key}`, - props.formState, - ); - if (definitionInSchema) { - const backstageReviewOptions = - definitionInSchema['ui:backstage']?.review; + Object.entries(props.formState) + .map(([key, value]) => { + for (const step of props.schemas) { + const parsedSchema = new JSONSchema(step.mergedSchema); + const definitionInSchema = parsedSchema.getSchema( + `#/${key}`, + props.formState, + ); + if (definitionInSchema) { + const backstageReviewOptions = + definitionInSchema['ui:backstage']?.review; - if (backstageReviewOptions) { - if (backstageReviewOptions.mask) { - return [key, backstageReviewOptions.mask]; + if (backstageReviewOptions) { + if (backstageReviewOptions.mask) { + return [key, backstageReviewOptions.mask]; + } + if (backstageReviewOptions.show === false) { + return []; + } } - if (backstageReviewOptions.show === false) { - return []; + + if (definitionInSchema['ui:widget'] === 'password') { + return [key, '******']; } - } - if (definitionInSchema['ui:widget'] === 'password') { - return [key, '******']; - } - - if (definitionInSchema.enum && definitionInSchema.enumNames) { - return [ - key, - definitionInSchema.enumNames[ - definitionInSchema.enum.indexOf(value) - ] || value, - ]; + if (definitionInSchema.enum && definitionInSchema.enumNames) { + return [ + key, + definitionInSchema.enumNames[ + definitionInSchema.enum.indexOf(value) + ] || value, + ]; + } } } - } - return [key, value]; - }), + return [key, value]; + }) + .filter(prop => prop.length > 0), ); return ; }; From 510dab47dc4706d99cfac1389211c44fd2e32b20 Mon Sep 17 00:00:00 2001 From: djamaile Date: Thu, 30 Nov 2023 12:56:23 +0100 Subject: [PATCH 247/261] fix: change provider id from oauth2ProxyProvider to oauth2Proxy Signed-off-by: djamaile --- .changeset/itchy-camels-cough.md | 5 +++++ .../auth-backend-module-oauth2-proxy-provider/src/module.ts | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 .changeset/itchy-camels-cough.md diff --git a/.changeset/itchy-camels-cough.md b/.changeset/itchy-camels-cough.md new file mode 100644 index 0000000000..2ec70c945c --- /dev/null +++ b/.changeset/itchy-camels-cough.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-auth-backend-module-oauth2-proxy-provider': patch +--- + +Change provider id from `oauth2ProxyProvider` to `oauth2Proxy` diff --git a/plugins/auth-backend-module-oauth2-proxy-provider/src/module.ts b/plugins/auth-backend-module-oauth2-proxy-provider/src/module.ts index 9ca6be4688..70ce506d73 100644 --- a/plugins/auth-backend-module-oauth2-proxy-provider/src/module.ts +++ b/plugins/auth-backend-module-oauth2-proxy-provider/src/module.ts @@ -34,7 +34,7 @@ export const authModuleOauth2ProxyProvider = createBackendModule({ }, async init({ providers }) { providers.registerProvider({ - providerId: 'oauth2ProxyProvider', + providerId: 'oauth2Proxy', factory: createProxyAuthProviderFactory({ authenticator: oauth2ProxyAuthenticator, signInResolverFactories: { From f1812e111ca9139f680734d6f794f85a7e21d349 Mon Sep 17 00:00:00 2001 From: Frida Jacobsson Date: Thu, 30 Nov 2023 13:35:13 +0100 Subject: [PATCH 248/261] Update jira-dashboard documenation Signed-off-by: Frida Jacobsson --- microsite/data/plugins/jira-dashboard | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/microsite/data/plugins/jira-dashboard b/microsite/data/plugins/jira-dashboard index 8838af8492..2e67deb4a9 100644 --- a/microsite/data/plugins/jira-dashboard +++ b/microsite/data/plugins/jira-dashboard @@ -4,7 +4,7 @@ author: AxisCommunications authorUrl: https://github.com/AxisCommunications category: Agile Planning description: Allows you to fetch and display Jira issues for your entity. You get quickly access to issue summaries to achieve better task visibility and more efficient project management. -documentation: https://github.com/AxisCommunications/backstage-plugins +documentation: https://github.com/AxisCommunications/backstage-plugins/blob/main/plugins/jira-dashboard/README.md iconUrl: https://github.com/AxisCommunications/backstage-plugins/blob/main/plugins/jira-dashboard/media/jira-logo.png npmPackageName: '@axis-backstage/plugin-jira-dashboard' addedDate: '2023-11-29' From 899d71a37c08623446dfa471339b23eb48a4f632 Mon Sep 17 00:00:00 2001 From: Tomasz Szuba Date: Thu, 30 Nov 2023 20:37:14 +0100 Subject: [PATCH 249/261] [k8s] async formatClusterLink (#21535) This is a refactor PR for formatClusterLink. It rewrites it to be an API and allows async creation of cluster link. Signed-off-by: Tomasz Szuba --- .changeset/fair-plants-attack.md | 9 + plugins/kubernetes-react/api-report.md | 87 ++++++++-- .../KubernetesClusterLinkFormatter.test.ts | 76 +++++++++ .../src/api/KubernetesClusterLinkFormatter.ts | 59 +++++++ .../AksClusterLinksFormatter.test.ts} | 39 ++--- .../formatters/AksClusterLinksFormatter.ts | 59 +++++++ .../EksClusterLinksFormatter.test.ts} | 14 +- .../formatters/EksClusterLinksFormatter.ts} | 16 +- .../GkeClusterLinksFormatter.test.ts} | 65 +++---- .../formatters/GkeClusterLinksFormatter.ts | 73 ++++++++ .../OpenshiftClusterLinksFormatter.test.ts} | 48 +++--- .../OpenshiftClusterLinksFormatter.ts | 60 +++++++ .../RancherClusterLinksFormatter.test.ts} | 40 ++--- .../RancherClusterLinksFormatter.ts | 55 ++++++ .../StandardClusterLinksFormatter.test.ts} | 52 +++--- .../StandardClusterLinksFormatter.ts | 56 +++++++ .../src/api/formatters/index.ts | 50 ++++++ plugins/kubernetes-react/src/api/index.ts | 15 +- plugins/kubernetes-react/src/api/types.ts | 25 +++ .../CronJobsDrawer.test.tsx | 14 +- .../DeploymentDrawer.test.tsx | 35 ++-- .../HorizontalPodAutoscalerDrawer.test.tsx | 11 +- .../IngressDrawer.test.tsx | 11 +- .../JobsAccordions/JobsDrawer.test.tsx | 7 +- ...ubernetesStructuredMetadataTableDrawer.tsx | 45 +++-- .../ServicesAccordions/ServiceDrawer.test.tsx | 11 +- .../StatefulSetDrawer.test.tsx | 35 ++-- plugins/kubernetes-react/src/index.ts | 1 - plugins/kubernetes-react/src/types/types.ts | 6 +- .../clusterLinks/formatClusterLink.test.ts | 158 ------------------ .../utils/clusterLinks/formatClusterLink.ts | 55 ------ .../src/utils/clusterLinks/formatters/aks.ts | 53 ------ .../src/utils/clusterLinks/formatters/gke.ts | 67 -------- .../utils/clusterLinks/formatters/index.ts | 35 ---- .../clusterLinks/formatters/openshift.ts | 57 ------- .../utils/clusterLinks/formatters/rancher.ts | 49 ------ .../utils/clusterLinks/formatters/standard.ts | 50 ------ .../src/utils/clusterLinks/index.ts | 21 --- plugins/kubernetes-react/src/utils/index.ts | 16 -- plugins/kubernetes/src/plugin.ts | 15 ++ 40 files changed, 882 insertions(+), 768 deletions(-) create mode 100644 .changeset/fair-plants-attack.md create mode 100644 plugins/kubernetes-react/src/api/KubernetesClusterLinkFormatter.test.ts create mode 100644 plugins/kubernetes-react/src/api/KubernetesClusterLinkFormatter.ts rename plugins/kubernetes-react/src/{utils/clusterLinks/formatters/aks.test.ts => api/formatters/AksClusterLinksFormatter.test.ts} (82%) create mode 100644 plugins/kubernetes-react/src/api/formatters/AksClusterLinksFormatter.ts rename plugins/kubernetes-react/src/{utils/clusterLinks/formatters/eks.test.ts => api/formatters/EksClusterLinksFormatter.test.ts} (75%) rename plugins/kubernetes-react/src/{utils/clusterLinks/formatters/eks.ts => api/formatters/EksClusterLinksFormatter.ts} (62%) rename plugins/kubernetes-react/src/{utils/clusterLinks/formatters/gke.test.ts => api/formatters/GkeClusterLinksFormatter.test.ts} (80%) create mode 100644 plugins/kubernetes-react/src/api/formatters/GkeClusterLinksFormatter.ts rename plugins/kubernetes-react/src/{utils/clusterLinks/formatters/openshift.test.ts => api/formatters/OpenshiftClusterLinksFormatter.test.ts} (75%) create mode 100644 plugins/kubernetes-react/src/api/formatters/OpenshiftClusterLinksFormatter.ts rename plugins/kubernetes-react/src/{utils/clusterLinks/formatters/rancher.test.ts => api/formatters/RancherClusterLinksFormatter.test.ts} (74%) create mode 100644 plugins/kubernetes-react/src/api/formatters/RancherClusterLinksFormatter.ts rename plugins/kubernetes-react/src/{utils/clusterLinks/formatters/standard.test.ts => api/formatters/StandardClusterLinksFormatter.test.ts} (76%) create mode 100644 plugins/kubernetes-react/src/api/formatters/StandardClusterLinksFormatter.ts create mode 100644 plugins/kubernetes-react/src/api/formatters/index.ts delete mode 100644 plugins/kubernetes-react/src/utils/clusterLinks/formatClusterLink.test.ts delete mode 100644 plugins/kubernetes-react/src/utils/clusterLinks/formatClusterLink.ts delete mode 100644 plugins/kubernetes-react/src/utils/clusterLinks/formatters/aks.ts delete mode 100644 plugins/kubernetes-react/src/utils/clusterLinks/formatters/gke.ts delete mode 100644 plugins/kubernetes-react/src/utils/clusterLinks/formatters/index.ts delete mode 100644 plugins/kubernetes-react/src/utils/clusterLinks/formatters/openshift.ts delete mode 100644 plugins/kubernetes-react/src/utils/clusterLinks/formatters/rancher.ts delete mode 100644 plugins/kubernetes-react/src/utils/clusterLinks/formatters/standard.ts delete mode 100644 plugins/kubernetes-react/src/utils/clusterLinks/index.ts delete mode 100644 plugins/kubernetes-react/src/utils/index.ts diff --git a/.changeset/fair-plants-attack.md b/.changeset/fair-plants-attack.md new file mode 100644 index 0000000000..2e36ba6284 --- /dev/null +++ b/.changeset/fair-plants-attack.md @@ -0,0 +1,9 @@ +--- +'@backstage/plugin-kubernetes-react': minor +'@backstage/plugin-kubernetes': patch +--- + +Change `formatClusterLink` to be an API and make it async for further customization possibilities. + +**BREAKING** +If you have a custom k8s page and used `formatClusterLink` directly, you need to migrate to new `kubernetesClusterLinkFormatterApiRef` diff --git a/plugins/kubernetes-react/api-report.md b/plugins/kubernetes-react/api-report.md index ca1df34b40..cf9f6de664 100644 --- a/plugins/kubernetes-react/api-report.md +++ b/plugins/kubernetes-react/api-report.md @@ -22,7 +22,7 @@ import { IContainerStatus } from 'kubernetes-models/v1'; import { IdentityApi } from '@backstage/core-plugin-api'; import { IIoK8sApimachineryPkgApisMetaV1ObjectMeta } from '@kubernetes-models/apimachinery/apis/meta/v1/ObjectMeta'; import { IObjectMeta } from '@kubernetes-models/apimachinery/apis/meta/v1/ObjectMeta'; -import type { JsonObject } from '@backstage/types'; +import { JsonObject } from '@backstage/types'; import { KubernetesRequestBody } from '@backstage/plugin-kubernetes-common'; import { OAuthApi } from '@backstage/core-plugin-api'; import { ObjectsByEntityResponse } from '@backstage/plugin-kubernetes-common'; @@ -38,6 +38,12 @@ import { V1ObjectMeta } from '@kubernetes/client-node'; import { V1Pod } from '@kubernetes/client-node'; import { WorkloadsByEntityRequest } from '@backstage/plugin-kubernetes-common'; +// @public (undocumented) +export class AksClusterLinksFormatter implements ClusterLinksFormatter { + // (undocumented) + formatClusterLink(options: ClusterLinksFormatterOptions): Promise; +} + // @public (undocumented) export class AksKubernetesAuthProvider implements KubernetesAuthProvider { constructor(microsoftAuthApi: OAuthApi); @@ -61,9 +67,10 @@ export const Cluster: ({ export const ClusterContext: React_2.Context; // @public (undocumented) -export type ClusterLinksFormatter = ( - options: ClusterLinksFormatterOptions, -) => URL; +export interface ClusterLinksFormatter { + // (undocumented) + formatClusterLink(options: ClusterLinksFormatterOptions): Promise; +} // @public (undocumented) export interface ClusterLinksFormatterOptions { @@ -77,9 +84,6 @@ export interface ClusterLinksFormatterOptions { object: any; } -// @public (undocumented) -export const clusterLinksFormatters: Record; - // @public export type ClusterProps = { clusterObjects: ClusterObjects; @@ -125,9 +129,18 @@ export interface CustomResourcesProps { children?: React_2.ReactNode; } +// @public (undocumented) +export const DEFAULT_FORMATTER_NAME = 'standard'; + // @public export const DetectedErrorsContext: React_2.Context; +// @public (undocumented) +export class EksClusterLinksFormatter implements ClusterLinksFormatter { + // (undocumented) + formatClusterLink(_options: ClusterLinksFormatterOptions): Promise; +} + // @public export const ErrorList: ({ podAndErrors, @@ -228,11 +241,6 @@ export interface FixDialogProps { pod: Pod_2; } -// @public (undocumented) -export function formatClusterLink( - options: FormatClusterLinkOptions, -): string | undefined; - // @public (undocumented) export type FormatClusterLinkOptions = { dashboardUrl?: string; @@ -242,6 +250,18 @@ export type FormatClusterLinkOptions = { kind: string; }; +// @public (undocumented) +export function getDefaultFormatters(_deps: {}): Record< + string, + ClusterLinksFormatter +>; + +// @public (undocumented) +export class GkeClusterLinksFormatter implements ClusterLinksFormatter { + // (undocumented) + formatClusterLink(options: ClusterLinksFormatterOptions): Promise; +} + // @public (undocumented) export class GoogleKubernetesAuthProvider implements KubernetesAuthProvider { constructor(authProvider: OAuthApi); @@ -415,6 +435,31 @@ export class KubernetesBackendClient implements KubernetesApi { }): Promise; } +// @public (undocumented) +export class KubernetesClusterLinkFormatter + implements KubernetesClusterLinkFormatterApi +{ + constructor(options: { + formatters: Record; + defaultFormatterName: string; + }); + // (undocumented) + formatClusterLink( + options: FormatClusterLinkOptions, + ): Promise; +} + +// @public (undocumented) +export interface KubernetesClusterLinkFormatterApi { + // (undocumented) + formatClusterLink( + options: FormatClusterLinkOptions, + ): Promise; +} + +// @public (undocumented) +export const kubernetesClusterLinkFormatterApiRef: ApiRef; + // @public export const KubernetesDrawer: ({ open, @@ -587,6 +632,12 @@ export class OidcKubernetesAuthProvider implements KubernetesAuthProvider { providerName: string; } +// @public (undocumented) +export class OpenshiftClusterLinksFormatter { + // (undocumented) + formatClusterLink(options: ClusterLinksFormatterOptions): Promise; +} + // @public export const PendingPodContent: ({ pod, @@ -716,6 +767,12 @@ export type PodsTablesProps = { children?: React_2.ReactNode; }; +// @public (undocumented) +export class RancherClusterLinksFormatter implements ClusterLinksFormatter { + // (undocumented) + formatClusterLink(options: ClusterLinksFormatterOptions): Promise; +} + // @public (undocumented) export const READY_COLUMNS: PodColumns; @@ -763,6 +820,12 @@ export const ServicesAccordions: ({}: ServicesAccordionsProps) => React_2.JSX.El // @public (undocumented) export type ServicesAccordionsProps = {}; +// @public (undocumented) +export class StandardClusterLinksFormatter implements ClusterLinksFormatter { + // (undocumented) + formatClusterLink(options: ClusterLinksFormatterOptions): Promise; +} + // @public export const useCustomResources: ( entity: Entity, diff --git a/plugins/kubernetes-react/src/api/KubernetesClusterLinkFormatter.test.ts b/plugins/kubernetes-react/src/api/KubernetesClusterLinkFormatter.test.ts new file mode 100644 index 0000000000..05b1709c75 --- /dev/null +++ b/plugins/kubernetes-react/src/api/KubernetesClusterLinkFormatter.test.ts @@ -0,0 +1,76 @@ +/* + * 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 { KubernetesClusterLinkFormatter } from './KubernetesClusterLinkFormatter'; + +const dashboardUrl = new URL('http://dashboard/url'); +describe('KubernetesClusterLinkFormatter', () => { + const formatter = new KubernetesClusterLinkFormatter({ + formatters: { + standard: { formatClusterLink: async _ => dashboardUrl }, + }, + defaultFormatterName: 'standard', + }); + describe('formatter.formatClusterLink', () => { + it('should not return an url when there is no dashboard url', async () => { + const url = await formatter.formatClusterLink({ + object: {}, + kind: 'foo', + }); + expect(url).toBeUndefined(); + }); + it('should return an url even when there is no object', async () => { + const url = await formatter.formatClusterLink({ + dashboardUrl: 'https://k8s.foo.com', + object: undefined, + kind: 'foo', + }); + expect(url).toBe('https://k8s.foo.com'); + }); + it('should throw when the app is not recognized', async () => { + await expect( + formatter.formatClusterLink({ + dashboardUrl: 'https://k8s.foo.com', + dashboardApp: 'unknownapp', + object: { + metadata: { + name: 'foobar', + namespace: 'bar', + }, + }, + kind: 'Deployment', + }), + ).rejects.toThrow( + "Could not find Kubernetes dashboard app named 'unknownapp'", + ); + }); + + describe('default app', () => { + it('should use default app', async () => { + const url = await formatter.formatClusterLink({ + dashboardUrl: 'https://k8s.foo.com/', + object: { + metadata: { + name: 'foobar', + namespace: 'bar', + }, + }, + kind: 'Deployment', + }); + expect(url).toBe(dashboardUrl.toString()); + }); + }); + }); +}); diff --git a/plugins/kubernetes-react/src/api/KubernetesClusterLinkFormatter.ts b/plugins/kubernetes-react/src/api/KubernetesClusterLinkFormatter.ts new file mode 100644 index 0000000000..45dd6e6fa1 --- /dev/null +++ b/plugins/kubernetes-react/src/api/KubernetesClusterLinkFormatter.ts @@ -0,0 +1,59 @@ +/* + * 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 { + KubernetesClusterLinkFormatterApi, + FormatClusterLinkOptions, +} from './types'; +import { ClusterLinksFormatter } from '../types'; + +/** @public */ +export class KubernetesClusterLinkFormatter + implements KubernetesClusterLinkFormatterApi +{ + private readonly formatters: Record; + private readonly defaultFormatterName: string; + + constructor(options: { + formatters: Record; + defaultFormatterName: string; + }) { + this.formatters = options.formatters; + this.defaultFormatterName = options.defaultFormatterName; + } + async formatClusterLink(options: FormatClusterLinkOptions) { + if (!options.dashboardUrl && !options.dashboardParameters) { + return undefined; + } + if (options.dashboardUrl && !options.object) { + return options.dashboardUrl; + } + const app = options.dashboardApp ?? this.defaultFormatterName; + const formatter = this.formatters[app]; + if (!formatter) { + throw new Error(`Could not find Kubernetes dashboard app named '${app}'`); + } + const url = await formatter.formatClusterLink({ + dashboardUrl: options.dashboardUrl + ? new URL(options.dashboardUrl) + : undefined, + dashboardParameters: options.dashboardParameters, + object: options.object, + kind: options.kind, + }); + return url.toString(); + } +} diff --git a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/aks.test.ts b/plugins/kubernetes-react/src/api/formatters/AksClusterLinksFormatter.test.ts similarity index 82% rename from plugins/kubernetes-react/src/utils/clusterLinks/formatters/aks.test.ts rename to plugins/kubernetes-react/src/api/formatters/AksClusterLinksFormatter.test.ts index 18db618686..b7bdc3d7e8 100644 --- a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/aks.test.ts +++ b/plugins/kubernetes-react/src/api/formatters/AksClusterLinksFormatter.test.ts @@ -13,12 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { aksFormatter } from './aks'; +import { AksClusterLinksFormatter } from './AksClusterLinksFormatter'; describe('clusterLinks - AKS formatter', () => { - it('should provide a dashboardParameters in the options', () => { - expect(() => - aksFormatter({ + const formatter = new AksClusterLinksFormatter(); + it('should provide a dashboardParameters in the options', async () => { + await expect(() => + formatter.formatClusterLink({ object: { metadata: { name: 'foobar', @@ -27,11 +28,11 @@ describe('clusterLinks - AKS formatter', () => { }, kind: 'Deployment', }), - ).toThrow('AKS dashboard requires a dashboardParameters option'); + ).rejects.toThrow('AKS dashboard requires a dashboardParameters option'); }); - it('should provide a subscriptionId in the dashboardParameters options', () => { - expect(() => - aksFormatter({ + it('should provide a subscriptionId in the dashboardParameters options', async () => { + await expect( + formatter.formatClusterLink({ dashboardParameters: { resourceGroup: 'rg-1', clusterName: 'cluster-1', @@ -44,13 +45,13 @@ describe('clusterLinks - AKS formatter', () => { }, kind: 'Deployment', }), - ).toThrow( + ).rejects.toThrow( 'AKS dashboard requires a "subscriptionId" of type string in the dashboardParameters option', ); }); - it('should provide a resourceGroup in the dashboardParameters options', () => { - expect(() => - aksFormatter({ + it('should provide a resourceGroup in the dashboardParameters options', async () => { + await expect( + formatter.formatClusterLink({ dashboardParameters: { subscriptionId: '1234-GUID-5678', clusterName: 'cluster-1', @@ -63,13 +64,13 @@ describe('clusterLinks - AKS formatter', () => { }, kind: 'Deployment', }), - ).toThrow( + ).rejects.toThrow( 'AKS dashboard requires a "resourceGroup" of type string in the dashboardParameters option', ); }); - it('should provide a clusterName in the dashboardParameters options', () => { - expect(() => - aksFormatter({ + it('should provide a clusterName in the dashboardParameters options', async () => { + await expect( + formatter.formatClusterLink({ dashboardParameters: { subscriptionId: '1234-GUID-5678', resourceGroup: 'us-east1-c', @@ -82,12 +83,12 @@ describe('clusterLinks - AKS formatter', () => { }, kind: 'Deployment', }), - ).toThrow( + ).rejects.toThrow( 'AKS dashboard requires a "clusterName" of type string in the dashboardParameters option', ); }); - it('should return an url on the cluster with object details', () => { - const url = aksFormatter({ + it('should return an url on the cluster with object details', async () => { + const url = await formatter.formatClusterLink({ dashboardParameters: { subscriptionId: '1234-GUID-5678', resourceGroup: 'rg-1', diff --git a/plugins/kubernetes-react/src/api/formatters/AksClusterLinksFormatter.ts b/plugins/kubernetes-react/src/api/formatters/AksClusterLinksFormatter.ts new file mode 100644 index 0000000000..1e7bb0ff9e --- /dev/null +++ b/plugins/kubernetes-react/src/api/formatters/AksClusterLinksFormatter.ts @@ -0,0 +1,59 @@ +/* + * 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 { + ClusterLinksFormatter, + ClusterLinksFormatterOptions, +} from '../../types'; + +const basePath = + 'https://portal.azure.com/#blade/Microsoft_Azure_ContainerService/AksK8ResourceMenuBlade/overview-Deployment/aksClusterId'; + +const requiredParams = ['subscriptionId', 'resourceGroup', 'clusterName']; + +/** @public */ +export class AksClusterLinksFormatter implements ClusterLinksFormatter { + async formatClusterLink(options: ClusterLinksFormatterOptions) { + if (!options.dashboardParameters) { + throw new Error('AKS dashboard requires a dashboardParameters option'); + } + const args = options.dashboardParameters; + for (const param of requiredParams) { + if (typeof args[param] !== 'string') { + throw new Error( + `AKS dashboard requires a "${param}" of type string in the dashboardParameters option`, + ); + } + } + + const path = `/subscriptions/${args.subscriptionId}/resourceGroups/${args.resourceGroup}/providers/Microsoft.ContainerService/managedClusters/${args.clusterName}`; + + const { name, namespace, uid } = options.object.metadata; + const { selector } = options.object.spec; + const params = { + kind: options.kind, + metadata: { name, namespace, uid }, + spec: { + selector, + }, + }; + + return new URL( + `${basePath}/${encodeURIComponent(path)}/resource/${encodeURIComponent( + JSON.stringify(params), + )}`, + ); + } +} diff --git a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/eks.test.ts b/plugins/kubernetes-react/src/api/formatters/EksClusterLinksFormatter.test.ts similarity index 75% rename from plugins/kubernetes-react/src/utils/clusterLinks/formatters/eks.test.ts rename to plugins/kubernetes-react/src/api/formatters/EksClusterLinksFormatter.test.ts index d0ae73753f..738da9fb94 100644 --- a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/eks.test.ts +++ b/plugins/kubernetes-react/src/api/formatters/EksClusterLinksFormatter.test.ts @@ -13,12 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { eksFormatter } from './eks'; + +import { EksClusterLinksFormatter } from './EksClusterLinksFormatter'; describe('clusterLinks - EKS formatter', () => { - it('should return an url on the workloads when there is a namespace only', () => { - expect(() => - eksFormatter({ + const formatter = new EksClusterLinksFormatter(); + it('should return an url on the workloads when there is a namespace only', async () => { + await expect( + formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com'), object: { metadata: { @@ -28,6 +30,8 @@ describe('clusterLinks - EKS formatter', () => { }, kind: 'Deployment', }), - ).toThrow('EKS formatter is not yet implemented. Please, contribute!'); + ).rejects.toThrow( + 'EKS formatter is not yet implemented. Please, contribute!', + ); }); }); diff --git a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/eks.ts b/plugins/kubernetes-react/src/api/formatters/EksClusterLinksFormatter.ts similarity index 62% rename from plugins/kubernetes-react/src/utils/clusterLinks/formatters/eks.ts rename to plugins/kubernetes-react/src/api/formatters/EksClusterLinksFormatter.ts index 975c39797c..d65b619639 100644 --- a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/eks.ts +++ b/plugins/kubernetes-react/src/api/formatters/EksClusterLinksFormatter.ts @@ -13,8 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { ClusterLinksFormatterOptions } from '../../../types/types'; +import { + ClusterLinksFormatter, + ClusterLinksFormatterOptions, +} from '../../types'; -export function eksFormatter(_options: ClusterLinksFormatterOptions): URL { - throw new Error('EKS formatter is not yet implemented. Please, contribute!'); +/** @public */ +export class EksClusterLinksFormatter implements ClusterLinksFormatter { + async formatClusterLink( + _options: ClusterLinksFormatterOptions, + ): Promise { + throw new Error( + 'EKS formatter is not yet implemented. Please, contribute!', + ); + } } diff --git a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/gke.test.ts b/plugins/kubernetes-react/src/api/formatters/GkeClusterLinksFormatter.test.ts similarity index 80% rename from plugins/kubernetes-react/src/utils/clusterLinks/formatters/gke.test.ts rename to plugins/kubernetes-react/src/api/formatters/GkeClusterLinksFormatter.test.ts index 7fd0814267..250be75214 100644 --- a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/gke.test.ts +++ b/plugins/kubernetes-react/src/api/formatters/GkeClusterLinksFormatter.test.ts @@ -13,12 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { gkeFormatter } from './gke'; + +import { GkeClusterLinksFormatter } from './GkeClusterLinksFormatter'; describe('clusterLinks - GKE formatter', () => { - it('should provide a dashboardParameters in the options', () => { - expect(() => - gkeFormatter({ + const formatter = new GkeClusterLinksFormatter(); + + it('should provide a dashboardParameters in the options', async () => { + await expect( + formatter.formatClusterLink({ object: { metadata: { name: 'foobar', @@ -27,11 +30,11 @@ describe('clusterLinks - GKE formatter', () => { }, kind: 'Deployment', }), - ).toThrow('GKE dashboard requires a dashboardParameters option'); + ).rejects.toThrow('GKE dashboard requires a dashboardParameters option'); }); - it('should provide a projectId in the dashboardParameters options', () => { - expect(() => - gkeFormatter({ + it('should provide a projectId in the dashboardParameters options', async () => { + await expect( + formatter.formatClusterLink({ dashboardParameters: { region: 'us-east1-c', clusterName: 'cluster-1', @@ -44,13 +47,13 @@ describe('clusterLinks - GKE formatter', () => { }, kind: 'Deployment', }), - ).toThrow( + ).rejects.toThrow( 'GKE dashboard requires a "projectId" of type string in the dashboardParameters option', ); }); - it('should provide a region in the dashboardParameters options', () => { - expect(() => - gkeFormatter({ + it('should provide a region in the dashboardParameters options', async () => { + await expect( + formatter.formatClusterLink({ dashboardParameters: { projectId: 'foobar-333614', clusterName: 'cluster-1', @@ -63,13 +66,13 @@ describe('clusterLinks - GKE formatter', () => { }, kind: 'Deployment', }), - ).toThrow( + ).rejects.toThrow( 'GKE dashboard requires a "region" of type string in the dashboardParameters option', ); }); - it('should provide a clusterName in the dashboardParameters options', () => { - expect(() => - gkeFormatter({ + it('should provide a clusterName in the dashboardParameters options', async () => { + await expect(() => + formatter.formatClusterLink({ dashboardParameters: { projectId: 'foobar-333614', region: 'us-east1-c', @@ -82,12 +85,12 @@ describe('clusterLinks - GKE formatter', () => { }, kind: 'Deployment', }), - ).toThrow( + ).rejects.toThrow( 'GKE dashboard requires a "clusterName" of type string in the dashboardParameters option', ); }); - it('should return an url on the cluster when there is a namespace only', () => { - const url = gkeFormatter({ + it('should return an url on the cluster when there is a namespace only', async () => { + const url = await formatter.formatClusterLink({ dashboardParameters: { projectId: 'foobar-333614', region: 'us-east1-c', @@ -104,8 +107,8 @@ describe('clusterLinks - GKE formatter', () => { 'https://console.cloud.google.com/kubernetes/clusters/details/us-east1-c/cluster-1/details?project=foobar-333614', ); }); - it('should return an url on the cluster when the kind is not recognizeed', () => { - const url = gkeFormatter({ + it('should return an url on the cluster when the kind is not recognizeed', async () => { + const url = await formatter.formatClusterLink({ dashboardParameters: { projectId: 'foobar-333614', region: 'us-east1-c', @@ -123,8 +126,8 @@ describe('clusterLinks - GKE formatter', () => { 'https://console.cloud.google.com/kubernetes/clusters/details/us-east1-c/cluster-1/details?project=foobar-333614', ); }); - it('should return an url on the deployment', () => { - const url = gkeFormatter({ + it('should return an url on the deployment', async () => { + const url = await formatter.formatClusterLink({ dashboardParameters: { projectId: 'foobar-333614', region: 'us-east1-c', @@ -143,8 +146,8 @@ describe('clusterLinks - GKE formatter', () => { ); }); - it('should return an url on the service', () => { - const url = gkeFormatter({ + it('should return an url on the service', async () => { + const url = await formatter.formatClusterLink({ dashboardParameters: { projectId: 'foobar-333614', region: 'us-east1-c', @@ -162,8 +165,8 @@ describe('clusterLinks - GKE formatter', () => { 'https://console.cloud.google.com/kubernetes/service/us-east1-c/cluster-1/bar/foobar/overview?project=foobar-333614', ); }); - it('should return an url on the pod', () => { - const url = gkeFormatter({ + it('should return an url on the pod', async () => { + const url = await formatter.formatClusterLink({ dashboardParameters: { projectId: 'foobar-333614', region: 'us-east1-c', @@ -181,8 +184,8 @@ describe('clusterLinks - GKE formatter', () => { 'https://console.cloud.google.com/kubernetes/pod/us-east1-c/cluster-1/bar/foobar/details?project=foobar-333614', ); }); - it('should return an url on the ingress', () => { - const url = gkeFormatter({ + it('should return an url on the ingress', async () => { + const url = await formatter.formatClusterLink({ dashboardParameters: { projectId: 'foobar-333614', region: 'us-east1-c', @@ -200,8 +203,8 @@ describe('clusterLinks - GKE formatter', () => { 'https://console.cloud.google.com/kubernetes/ingress/us-east1-c/cluster-1/bar/foobar/details?project=foobar-333614', ); }); - it('should return an url on the deployment for a hpa', () => { - const url = gkeFormatter({ + it('should return an url on the deployment for a hpa', async () => { + const url = await formatter.formatClusterLink({ dashboardParameters: { projectId: 'foobar-333614', region: 'us-east1-c', diff --git a/plugins/kubernetes-react/src/api/formatters/GkeClusterLinksFormatter.ts b/plugins/kubernetes-react/src/api/formatters/GkeClusterLinksFormatter.ts new file mode 100644 index 0000000000..c8dec85f71 --- /dev/null +++ b/plugins/kubernetes-react/src/api/formatters/GkeClusterLinksFormatter.ts @@ -0,0 +1,73 @@ +/* + * 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 { + ClusterLinksFormatter, + ClusterLinksFormatterOptions, +} from '../../types'; + +const kindMappings: Record = { + deployment: 'deployment', + pod: 'pod', + ingress: 'ingress', + service: 'service', + horizontalpodautoscaler: 'deployment', +}; + +/** @public */ +export class GkeClusterLinksFormatter implements ClusterLinksFormatter { + async formatClusterLink(options: ClusterLinksFormatterOptions): Promise { + if (!options.dashboardParameters) { + throw new Error('GKE dashboard requires a dashboardParameters option'); + } + const args = options.dashboardParameters; + if (typeof args.projectId !== 'string') { + throw new Error( + 'GKE dashboard requires a "projectId" of type string in the dashboardParameters option', + ); + } + if (typeof args.region !== 'string') { + throw new Error( + 'GKE dashboard requires a "region" of type string in the dashboardParameters option', + ); + } + if (typeof args.clusterName !== 'string') { + throw new Error( + 'GKE dashboard requires a "clusterName" of type string in the dashboardParameters option', + ); + } + const basePath = new URL('https://console.cloud.google.com/'); + const region = encodeURIComponent(args.region); + const clusterName = encodeURIComponent(args.clusterName); + const name = encodeURIComponent(options.object.metadata?.name ?? ''); + const namespace = encodeURIComponent( + options.object.metadata?.namespace ?? '', + ); + const validKind = kindMappings[options.kind.toLocaleLowerCase('en-US')]; + let path: string; + if (namespace && name && validKind) { + const kindsWithDetails = ['ingress', 'pod']; + const landingPage = kindsWithDetails.includes(validKind) + ? 'details' + : 'overview'; + path = `kubernetes/${validKind}/${region}/${clusterName}/${namespace}/${name}/${landingPage}`; + } else { + path = `kubernetes/clusters/details/${region}/${clusterName}/details`; + } + const result = new URL(path, basePath); + result.searchParams.set('project', args.projectId); + return result; + } +} diff --git a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/openshift.test.ts b/plugins/kubernetes-react/src/api/formatters/OpenshiftClusterLinksFormatter.test.ts similarity index 75% rename from plugins/kubernetes-react/src/utils/clusterLinks/formatters/openshift.test.ts rename to plugins/kubernetes-react/src/api/formatters/OpenshiftClusterLinksFormatter.test.ts index 945553e340..1adb688757 100644 --- a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/openshift.test.ts +++ b/plugins/kubernetes-react/src/api/formatters/OpenshiftClusterLinksFormatter.test.ts @@ -13,12 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { openshiftFormatter } from './openshift'; + +import { OpenshiftClusterLinksFormatter } from './OpenshiftClusterLinksFormatter'; describe('clusterLinks - OpenShift formatter', () => { - it('should provide a dashboardUrl in the options', () => { - expect(() => - openshiftFormatter({ + const formatter = new OpenshiftClusterLinksFormatter(); + it('should provide a dashboardUrl in the options', async () => { + await expect(() => + formatter.formatClusterLink({ object: { metadata: { name: 'foobar', @@ -27,10 +29,10 @@ describe('clusterLinks - OpenShift formatter', () => { }, kind: 'Deployment', }), - ).toThrow('OpenShift dashboard requires a dashboardUrl option'); + ).rejects.toThrow('OpenShift dashboard requires a dashboardUrl option'); }); - it('should return an url on the workloads when there is a namespace only', () => { - const url = openshiftFormatter({ + it('should return an url on the workloads when there is a namespace only', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com'), object: { metadata: { @@ -41,8 +43,8 @@ describe('clusterLinks - OpenShift formatter', () => { }); expect(url.href).toBe('https://k8s.foo.com/k8s/cluster/projects/bar'); }); - it('should return an url on the workloads when the kind is not recognizeed', () => { - const url = openshiftFormatter({ + it('should return an url on the workloads when the kind is not recognizeed', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com'), object: { metadata: { @@ -54,8 +56,8 @@ describe('clusterLinks - OpenShift formatter', () => { }); expect(url.href).toBe('https://k8s.foo.com/k8s/cluster/projects/bar'); }); - it('should return an url on the deployment', () => { - const url = openshiftFormatter({ + it('should return an url on the deployment', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com/'), object: { metadata: { @@ -67,8 +69,8 @@ describe('clusterLinks - OpenShift formatter', () => { }); expect(url.href).toBe('https://k8s.foo.com/k8s/ns/bar/deployments/foobar'); }); - it('should return an url on the deployment and keep the path prefix 1', () => { - const url = openshiftFormatter({ + it('should return an url on the deployment and keep the path prefix 1', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com/some/prefix/'), object: { metadata: { @@ -82,8 +84,8 @@ describe('clusterLinks - OpenShift formatter', () => { 'https://k8s.foo.com/some/prefix/k8s/ns/bar/deployments/foobar', ); }); - it('should return an url on the deployment and keep the path prefix 2', () => { - const url = openshiftFormatter({ + it('should return an url on the deployment and keep the path prefix 2', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com/some/prefix'), object: { metadata: { @@ -97,8 +99,8 @@ describe('clusterLinks - OpenShift formatter', () => { 'https://k8s.foo.com/some/prefix/k8s/ns/bar/deployments/foobar', ); }); - it('should return an url on the service', () => { - const url = openshiftFormatter({ + it('should return an url on the service', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com/'), object: { metadata: { @@ -110,8 +112,8 @@ describe('clusterLinks - OpenShift formatter', () => { }); expect(url.href).toBe('https://k8s.foo.com/k8s/ns/bar/services/foobar'); }); - it('should return an url on the ingress', () => { - const url = openshiftFormatter({ + it('should return an url on the ingress', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com/'), object: { metadata: { @@ -123,8 +125,8 @@ describe('clusterLinks - OpenShift formatter', () => { }); expect(url.href).toBe('https://k8s.foo.com/k8s/ns/bar/ingresses/foobar'); }); - it('should return an url on the deployment for a hpa', () => { - const url = openshiftFormatter({ + it('should return an url on the deployment for a hpa', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com/'), object: { metadata: { @@ -138,8 +140,8 @@ describe('clusterLinks - OpenShift formatter', () => { 'https://k8s.foo.com/k8s/ns/bar/horizontalpodautoscalers/foobar', ); }); - it('should return an url on the PV', () => { - const url = openshiftFormatter({ + it('should return an url on the PV', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com/'), object: { metadata: { diff --git a/plugins/kubernetes-react/src/api/formatters/OpenshiftClusterLinksFormatter.ts b/plugins/kubernetes-react/src/api/formatters/OpenshiftClusterLinksFormatter.ts new file mode 100644 index 0000000000..228ff3d1ac --- /dev/null +++ b/plugins/kubernetes-react/src/api/formatters/OpenshiftClusterLinksFormatter.ts @@ -0,0 +1,60 @@ +/* + * 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 { ClusterLinksFormatterOptions } from '../../types'; + +const kindMappings: Record = { + deployment: 'deployments', + ingress: 'ingresses', + service: 'services', + horizontalpodautoscaler: 'horizontalpodautoscalers', + persistentvolume: 'persistentvolumes', +}; + +/** @public */ +export class OpenshiftClusterLinksFormatter { + async formatClusterLink(options: ClusterLinksFormatterOptions): Promise { + if (!options.dashboardUrl) { + throw new Error('OpenShift dashboard requires a dashboardUrl option'); + } + const basePath = new URL(options.dashboardUrl.href); + const name = encodeURIComponent(options.object.metadata?.name ?? ''); + const namespace = encodeURIComponent( + options.object.metadata?.namespace ?? '', + ); + const validKind = kindMappings[options.kind.toLocaleLowerCase('en-US')]; + if (!basePath.pathname.endsWith('/')) { + // a dashboard url with a path should end with a slash otherwise + // the new combined URL will replace the last segment with the appended path! + // https://foobar.com/abc/def + k8s/cluster/projects/test --> https://foobar.com/abc/k8s/cluster/projects/test + // https://foobar.com/abc/def/ + k8s/cluster/projects/test --> https://foobar.com/abc/def/k8s/cluster/projects/test + basePath.pathname += '/'; + } + let path = ''; + if (namespace) { + if (name && validKind) { + path = `k8s/ns/${namespace}/${validKind}/${name}`; + } else { + path = `k8s/cluster/projects/${namespace}`; + } + } else if (validKind) { + path = `k8s/cluster/${validKind}`; + if (name) { + path += `/${name}`; + } + } + return new URL(path, basePath); + } +} diff --git a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/rancher.test.ts b/plugins/kubernetes-react/src/api/formatters/RancherClusterLinksFormatter.test.ts similarity index 74% rename from plugins/kubernetes-react/src/utils/clusterLinks/formatters/rancher.test.ts rename to plugins/kubernetes-react/src/api/formatters/RancherClusterLinksFormatter.test.ts index bb26da3ab0..228340eb16 100644 --- a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/rancher.test.ts +++ b/plugins/kubernetes-react/src/api/formatters/RancherClusterLinksFormatter.test.ts @@ -13,12 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { rancherFormatter } from './rancher'; + +import { RancherClusterLinksFormatter } from './RancherClusterLinksFormatter'; describe('clusterLinks - rancher formatter', () => { - it('should provide a dashboardUrl in the options', () => { - expect(() => - rancherFormatter({ + const formatter = new RancherClusterLinksFormatter(); + it('should provide a dashboardUrl in the options', async () => { + await expect(() => + formatter.formatClusterLink({ object: { metadata: { name: 'foobar', @@ -27,10 +29,10 @@ describe('clusterLinks - rancher formatter', () => { }, kind: 'Deployment', }), - ).toThrow('Rancher dashboard requires a dashboardUrl option'); + ).rejects.toThrow('Rancher dashboard requires a dashboardUrl option'); }); - it('should return a url on the workloads when there is a namespace only', () => { - const url = rancherFormatter({ + it('should return a url on the workloads when there is a namespace only', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com'), object: { metadata: { @@ -41,8 +43,8 @@ describe('clusterLinks - rancher formatter', () => { }); expect(url.href).toBe('https://k8s.foo.com/explorer/workload'); }); - it('should return a url on the workloads when the kind is not recognized', () => { - const url = rancherFormatter({ + it('should return a url on the workloads when the kind is not recognized', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com'), object: { metadata: { @@ -54,8 +56,8 @@ describe('clusterLinks - rancher formatter', () => { }); expect(url.href).toBe('https://k8s.foo.com/explorer/workload'); }); - it('should return a url on the deployment', () => { - const url = rancherFormatter({ + it('should return a url on the deployment', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com/'), object: { metadata: { @@ -69,8 +71,8 @@ describe('clusterLinks - rancher formatter', () => { 'https://k8s.foo.com/explorer/apps.deployment/bar/foobar', ); }); - it('should return a url on the service', () => { - const url = rancherFormatter({ + it('should return a url on the service', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com/'), object: { metadata: { @@ -82,8 +84,8 @@ describe('clusterLinks - rancher formatter', () => { }); expect(url.href).toBe('https://k8s.foo.com/explorer/service/bar/foobar'); }); - it('should return a url on the ingress', () => { - const url = rancherFormatter({ + it('should return a url on the ingress', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com/'), object: { metadata: { @@ -97,8 +99,8 @@ describe('clusterLinks - rancher formatter', () => { 'https://k8s.foo.com/explorer/networking.k8s.io.ingress/bar/foobar', ); }); - it('should return a url on the deployment for a hpa', () => { - const url = rancherFormatter({ + it('should return a url on the deployment for a hpa', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com/'), object: { metadata: { @@ -112,8 +114,8 @@ describe('clusterLinks - rancher formatter', () => { 'https://k8s.foo.com/explorer/autoscaling.horizontalpodautoscaler/bar/foobar', ); }); - it('should support subpaths in dashboardUrl', () => { - const url = rancherFormatter({ + it('should support subpaths in dashboardUrl', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com/dashboard/c/c-28a4b/'), object: { metadata: { diff --git a/plugins/kubernetes-react/src/api/formatters/RancherClusterLinksFormatter.ts b/plugins/kubernetes-react/src/api/formatters/RancherClusterLinksFormatter.ts new file mode 100644 index 0000000000..e607d98972 --- /dev/null +++ b/plugins/kubernetes-react/src/api/formatters/RancherClusterLinksFormatter.ts @@ -0,0 +1,55 @@ +/* + * 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 { + ClusterLinksFormatter, + ClusterLinksFormatterOptions, +} from '../../types'; + +const kindMappings: Record = { + deployment: 'apps.deployment', + ingress: 'networking.k8s.io.ingress', + service: 'service', + horizontalpodautoscaler: 'autoscaling.horizontalpodautoscaler', +}; + +/** @public */ +export class RancherClusterLinksFormatter implements ClusterLinksFormatter { + async formatClusterLink(options: ClusterLinksFormatterOptions): Promise { + if (!options.dashboardUrl) { + throw new Error('Rancher dashboard requires a dashboardUrl option'); + } + const basePath = new URL(options.dashboardUrl.href); + const name = encodeURIComponent(options.object.metadata?.name ?? ''); + const namespace = encodeURIComponent( + options.object.metadata?.namespace ?? '', + ); + const validKind = kindMappings[options.kind.toLocaleLowerCase('en-US')]; + if (!basePath.pathname.endsWith('/')) { + // a dashboard url with a path should end with a slash otherwise + // the new combined URL will replace the last segment with the appended path! + // https://foobar.com/abc/def + explorer/service/test --> https://foobar.com/abc/explorer/service/test + // https://foobar.com/abc/def/ + explorer/service/test --> https://foobar.com/abc/def/explorer/service/test + basePath.pathname += '/'; + } + let path = ''; + if (validKind && name && namespace) { + path = `explorer/${validKind}/${namespace}/${name}`; + } else if (namespace) { + path = 'explorer/workload'; + } + return new URL(path, basePath); + } +} diff --git a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/standard.test.ts b/plugins/kubernetes-react/src/api/formatters/StandardClusterLinksFormatter.test.ts similarity index 76% rename from plugins/kubernetes-react/src/utils/clusterLinks/formatters/standard.test.ts rename to plugins/kubernetes-react/src/api/formatters/StandardClusterLinksFormatter.test.ts index 280de6bfde..fe1b2be4f5 100644 --- a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/standard.test.ts +++ b/plugins/kubernetes-react/src/api/formatters/StandardClusterLinksFormatter.test.ts @@ -13,7 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { standardFormatter } from './standard'; + +import { StandardClusterLinksFormatter } from './StandardClusterLinksFormatter'; function formatUrl(url: URL) { // Note that we can't rely on 'url.href' since it will put the search before the hash @@ -23,9 +24,10 @@ function formatUrl(url: URL) { } describe('clusterLinks - standard formatter', () => { - it('should provide a dashboardUrl in the options', () => { - expect(() => - standardFormatter({ + const formatter = new StandardClusterLinksFormatter(); + it('should provide a dashboardUrl in the options', async () => { + await expect(() => + formatter.formatClusterLink({ object: { metadata: { name: 'foobar', @@ -34,10 +36,10 @@ describe('clusterLinks - standard formatter', () => { }, kind: 'Deployment', }), - ).toThrow('standard dashboard requires a dashboardUrl option'); + ).rejects.toThrow('standard dashboard requires a dashboardUrl option'); }); - it('should return an url on the workloads when there is a namespace only', () => { - const url = standardFormatter({ + it('should return an url on the workloads when there is a namespace only', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com'), object: { metadata: { @@ -50,8 +52,8 @@ describe('clusterLinks - standard formatter', () => { 'https://k8s.foo.com/#/workloads?namespace=bar', ); }); - it('should return an url on the workloads when the kind is not recognizeed', () => { - const url = standardFormatter({ + it('should return an url on the workloads when the kind is not recognizeed', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com'), object: { metadata: { @@ -65,8 +67,8 @@ describe('clusterLinks - standard formatter', () => { 'https://k8s.foo.com/#/workloads?namespace=bar', ); }); - it('should return an url on the deployment', () => { - const url = standardFormatter({ + it('should return an url on the deployment', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com/'), object: { metadata: { @@ -80,8 +82,8 @@ describe('clusterLinks - standard formatter', () => { 'https://k8s.foo.com/#/deployment/bar/foobar?namespace=bar', ); }); - it('should return an url on the pod', () => { - const url = standardFormatter({ + it('should return an url on the pod', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com/'), object: { metadata: { @@ -95,8 +97,8 @@ describe('clusterLinks - standard formatter', () => { 'https://k8s.foo.com/#/pod/bar/foobar?namespace=bar', ); }); - it('should return an url on the deployment with a prefix 1', () => { - const url = standardFormatter({ + it('should return an url on the deployment with a prefix 1', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com/some/prefix'), object: { metadata: { @@ -110,8 +112,8 @@ describe('clusterLinks - standard formatter', () => { 'https://k8s.foo.com/some/prefix/#/deployment/bar/foobar?namespace=bar', ); }); - it('should return an url on the deployment with a prefix 2', () => { - const url = standardFormatter({ + it('should return an url on the deployment with a prefix 2', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com/some/prefix/'), object: { metadata: { @@ -125,8 +127,8 @@ describe('clusterLinks - standard formatter', () => { 'https://k8s.foo.com/some/prefix/#/deployment/bar/foobar?namespace=bar', ); }); - it('should return an url on the deployment properly url encoded', () => { - const url = standardFormatter({ + it('should return an url on the deployment properly url encoded', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com/'), object: { metadata: { @@ -140,8 +142,8 @@ describe('clusterLinks - standard formatter', () => { 'https://k8s.foo.com/#/deployment/bar%20bar/foobar?namespace=bar%20bar', ); }); - it('should return an url on the service', () => { - const url = standardFormatter({ + it('should return an url on the service', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com/'), object: { metadata: { @@ -155,8 +157,8 @@ describe('clusterLinks - standard formatter', () => { 'https://k8s.foo.com/#/service/bar/foobar?namespace=bar', ); }); - it('should return an url on the ingress', () => { - const url = standardFormatter({ + it('should return an url on the ingress', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com/'), object: { metadata: { @@ -170,8 +172,8 @@ describe('clusterLinks - standard formatter', () => { 'https://k8s.foo.com/#/ingress/bar/foobar?namespace=bar', ); }); - it('should return an url on the deployment for a hpa', () => { - const url = standardFormatter({ + it('should return an url on the deployment for a hpa', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com/'), object: { metadata: { diff --git a/plugins/kubernetes-react/src/api/formatters/StandardClusterLinksFormatter.ts b/plugins/kubernetes-react/src/api/formatters/StandardClusterLinksFormatter.ts new file mode 100644 index 0000000000..76537c5a4e --- /dev/null +++ b/plugins/kubernetes-react/src/api/formatters/StandardClusterLinksFormatter.ts @@ -0,0 +1,56 @@ +/* + * 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 { + ClusterLinksFormatter, + ClusterLinksFormatterOptions, +} from '../../types'; + +const kindMappings: Record = { + deployment: 'deployment', + pod: 'pod', + ingress: 'ingress', + service: 'service', + horizontalpodautoscaler: 'deployment', + statefulset: 'statefulset', +}; + +/** @public */ +export class StandardClusterLinksFormatter implements ClusterLinksFormatter { + async formatClusterLink(options: ClusterLinksFormatterOptions): Promise { + if (!options.dashboardUrl) { + throw new Error('standard dashboard requires a dashboardUrl option'); + } + const result = new URL(options.dashboardUrl.href); + const name = encodeURIComponent(options.object.metadata?.name ?? ''); + const namespace = encodeURIComponent( + options.object.metadata?.namespace ?? '', + ); + const validKind = kindMappings[options.kind.toLocaleLowerCase('en-US')]; + if (!result.pathname.endsWith('/')) { + result.pathname += '/'; + } + if (validKind && name && namespace) { + result.hash = `/${validKind}/${namespace}/${name}`; + } else if (namespace) { + result.hash = '/workloads'; + } + if (namespace) { + // Note that Angular SPA requires a hash and the query parameter should be part of it + result.hash += `?namespace=${namespace}`; + } + return result; + } +} diff --git a/plugins/kubernetes-react/src/api/formatters/index.ts b/plugins/kubernetes-react/src/api/formatters/index.ts new file mode 100644 index 0000000000..97a3140d50 --- /dev/null +++ b/plugins/kubernetes-react/src/api/formatters/index.ts @@ -0,0 +1,50 @@ +/* + * 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 { AksClusterLinksFormatter } from './AksClusterLinksFormatter'; +import { ClusterLinksFormatter } from '../../types'; +import { EksClusterLinksFormatter } from './EksClusterLinksFormatter'; +import { GkeClusterLinksFormatter } from './GkeClusterLinksFormatter'; +import { StandardClusterLinksFormatter } from './StandardClusterLinksFormatter'; +import { OpenshiftClusterLinksFormatter } from './OpenshiftClusterLinksFormatter'; +import { RancherClusterLinksFormatter } from './RancherClusterLinksFormatter'; + +export { + StandardClusterLinksFormatter, + AksClusterLinksFormatter, + EksClusterLinksFormatter, + GkeClusterLinksFormatter, + OpenshiftClusterLinksFormatter, + RancherClusterLinksFormatter, +}; + +/** @public */ +export const DEFAULT_FORMATTER_NAME = 'standard'; + +/** @public */ +export function getDefaultFormatters(_deps: {}): Record< + string, + ClusterLinksFormatter +> { + return { + standard: new StandardClusterLinksFormatter(), + aks: new AksClusterLinksFormatter(), + eks: new EksClusterLinksFormatter(), + gke: new GkeClusterLinksFormatter(), + openshift: new OpenshiftClusterLinksFormatter(), + rancher: new RancherClusterLinksFormatter(), + }; +} diff --git a/plugins/kubernetes-react/src/api/index.ts b/plugins/kubernetes-react/src/api/index.ts index ec8843937a..42fbcf1618 100644 --- a/plugins/kubernetes-react/src/api/index.ts +++ b/plugins/kubernetes-react/src/api/index.ts @@ -14,7 +14,18 @@ * limitations under the License. */ -export { kubernetesApiRef, kubernetesProxyApiRef } from './types'; -export type { KubernetesApi, KubernetesProxyApi } from './types'; +export { + kubernetesApiRef, + kubernetesProxyApiRef, + kubernetesClusterLinkFormatterApiRef, +} from './types'; +export type { + KubernetesApi, + KubernetesProxyApi, + FormatClusterLinkOptions, + KubernetesClusterLinkFormatterApi, +} from './types'; export { KubernetesBackendClient } from './KubernetesBackendClient'; +export { KubernetesClusterLinkFormatter } from './KubernetesClusterLinkFormatter'; export { KubernetesProxyClient } from './KubernetesProxyClient'; +export * from './formatters'; diff --git a/plugins/kubernetes-react/src/api/types.ts b/plugins/kubernetes-react/src/api/types.ts index 28cf2dde55..cc27bf9dd4 100644 --- a/plugins/kubernetes-react/src/api/types.ts +++ b/plugins/kubernetes-react/src/api/types.ts @@ -22,6 +22,7 @@ import { } from '@backstage/plugin-kubernetes-common'; import { createApiRef } from '@backstage/core-plugin-api'; import { Event } from 'kubernetes-models/v1'; +import { JsonObject } from '@backstage/types'; /** @public */ export const kubernetesApiRef = createApiRef({ @@ -33,6 +34,12 @@ export const kubernetesProxyApiRef = createApiRef({ id: 'plugin.kubernetes.proxy-service', }); +/** @public */ +export const kubernetesClusterLinkFormatterApiRef = + createApiRef({ + id: 'plugin.kubernetes.cluster-link-formatter-service', + }); + /** @public */ export interface KubernetesApi { getObjectsByEntity( @@ -82,3 +89,21 @@ export interface KubernetesProxyApi { namespace: string; }): Promise; } + +/** + * @public + */ +export type FormatClusterLinkOptions = { + dashboardUrl?: string; + dashboardApp?: string; + dashboardParameters?: JsonObject; + object: any; + kind: string; +}; + +/** @public */ +export interface KubernetesClusterLinkFormatterApi { + formatClusterLink( + options: FormatClusterLinkOptions, + ): Promise; +} diff --git a/plugins/kubernetes-react/src/components/CronJobsAccordions/CronJobsDrawer.test.tsx b/plugins/kubernetes-react/src/components/CronJobsAccordions/CronJobsDrawer.test.tsx index b16e83ee50..75506476ea 100644 --- a/plugins/kubernetes-react/src/components/CronJobsAccordions/CronJobsDrawer.test.tsx +++ b/plugins/kubernetes-react/src/components/CronJobsAccordions/CronJobsDrawer.test.tsx @@ -15,16 +15,20 @@ */ import React from 'react'; import * as oneCronJobsFixture from '../../__fixtures__/1-cronjobs.json'; -import { renderInTestApp } from '@backstage/test-utils'; +import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; import { CronJobDrawer } from './CronJobsDrawer'; +import { kubernetesClusterLinkFormatterApiRef } from '../../api'; describe('CronJobDrawer', () => { it('should render cronJob drawer', async () => { const { getByText, getAllByText } = await renderInTestApp( - , + + + , + , ); expect(getAllByText('dice-roller-cronjob')).toHaveLength(2); diff --git a/plugins/kubernetes-react/src/components/DeploymentsAccordions/DeploymentDrawer.test.tsx b/plugins/kubernetes-react/src/components/DeploymentsAccordions/DeploymentDrawer.test.tsx index f221a36cee..1e8515f81a 100644 --- a/plugins/kubernetes-react/src/components/DeploymentsAccordions/DeploymentDrawer.test.tsx +++ b/plugins/kubernetes-react/src/components/DeploymentsAccordions/DeploymentDrawer.test.tsx @@ -16,16 +16,24 @@ import React from 'react'; import * as deployments from '../../__fixtures__/2-deployments.json'; -import { renderInTestApp, textContentMatcher } from '@backstage/test-utils'; +import { + renderInTestApp, + TestApiProvider, + textContentMatcher, +} from '@backstage/test-utils'; import { DeploymentDrawer } from './DeploymentDrawer'; +import { kubernetesClusterLinkFormatterApiRef } from '../../api'; describe('DeploymentDrawer', () => { it('should render deployment drawer', async () => { const { getByText, getAllByText } = await renderInTestApp( - , + + + , + , ); expect(getAllByText('dice-roller')).toHaveLength(2); @@ -53,13 +61,16 @@ describe('DeploymentDrawer', () => { it('should render deployment drawer without namespace', async () => { const deployment = (deployments as any).deployments[0]; const { queryByText } = await renderInTestApp( - , + + + , + , ); expect(queryByText('namespace: default')).not.toBeInTheDocument(); diff --git a/plugins/kubernetes-react/src/components/HorizontalPodAutoscalers/HorizontalPodAutoscalerDrawer.test.tsx b/plugins/kubernetes-react/src/components/HorizontalPodAutoscalers/HorizontalPodAutoscalerDrawer.test.tsx index beb0db1e2b..6599a2041f 100644 --- a/plugins/kubernetes-react/src/components/HorizontalPodAutoscalers/HorizontalPodAutoscalerDrawer.test.tsx +++ b/plugins/kubernetes-react/src/components/HorizontalPodAutoscalers/HorizontalPodAutoscalerDrawer.test.tsx @@ -17,15 +17,18 @@ import React from 'react'; import { screen } from '@testing-library/react'; import * as hpas from './__fixtures__/horizontalpodautoscalers.json'; -import { renderInTestApp } from '@backstage/test-utils'; +import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; import { HorizontalPodAutoscalerDrawer } from './HorizontalPodAutoscalerDrawer'; +import { kubernetesClusterLinkFormatterApiRef } from '../../api'; describe('HorizontalPodAutoscalersDrawer', () => { it('should render hpa drawer', async () => { await renderInTestApp( - -

CHILD

-
, + + +

CHILD

+
+
, ); expect(screen.getByText('dice-roller')).toBeInTheDocument(); diff --git a/plugins/kubernetes-react/src/components/IngressesAccordions/IngressDrawer.test.tsx b/plugins/kubernetes-react/src/components/IngressesAccordions/IngressDrawer.test.tsx index 8619e362b7..cfacb24ee4 100644 --- a/plugins/kubernetes-react/src/components/IngressesAccordions/IngressDrawer.test.tsx +++ b/plugins/kubernetes-react/src/components/IngressesAccordions/IngressDrawer.test.tsx @@ -14,16 +14,23 @@ * limitations under the License. */ -import { renderInTestApp, textContentMatcher } from '@backstage/test-utils'; +import { + renderInTestApp, + TestApiProvider, + textContentMatcher, +} from '@backstage/test-utils'; import { screen } from '@testing-library/react'; import React from 'react'; import { IngressDrawer } from './IngressDrawer'; import * as ingresses from './__fixtures__/2-ingresses.json'; +import { kubernetesClusterLinkFormatterApiRef } from '../../api'; describe('IngressDrawer', () => { it('should render ingress drawer', async () => { await renderInTestApp( - , + + + , ); expect(screen.getAllByText('awesome-service')).toHaveLength(4); diff --git a/plugins/kubernetes-react/src/components/JobsAccordions/JobsDrawer.test.tsx b/plugins/kubernetes-react/src/components/JobsAccordions/JobsDrawer.test.tsx index 48a4e6fe7e..23f49a2118 100644 --- a/plugins/kubernetes-react/src/components/JobsAccordions/JobsDrawer.test.tsx +++ b/plugins/kubernetes-react/src/components/JobsAccordions/JobsDrawer.test.tsx @@ -15,13 +15,16 @@ */ import React from 'react'; import * as oneCronJobsFixture from '../../__fixtures__/1-cronjobs.json'; -import { renderInTestApp } from '@backstage/test-utils'; +import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; import { JobDrawer } from './JobsDrawer'; +import { kubernetesClusterLinkFormatterApiRef } from '../../api'; describe('JobDrawer', () => { it('should render job drawer', async () => { const { getByText, getAllByText } = await renderInTestApp( - , + + , + , ); expect(getAllByText('dice-roller-cronjob-1637025000')).toHaveLength(2); diff --git a/plugins/kubernetes-react/src/components/KubernetesDrawer/KubernetesStructuredMetadataTableDrawer.tsx b/plugins/kubernetes-react/src/components/KubernetesDrawer/KubernetesStructuredMetadataTableDrawer.tsx index 65001c658e..0b6cfa26b4 100644 --- a/plugins/kubernetes-react/src/components/KubernetesDrawer/KubernetesStructuredMetadataTableDrawer.tsx +++ b/plugins/kubernetes-react/src/components/KubernetesDrawer/KubernetesStructuredMetadataTableDrawer.tsx @@ -37,10 +37,11 @@ import { WarningPanel, } from '@backstage/core-components'; import { ClusterContext } from '../../hooks'; -import { formatClusterLink } from '../../utils/clusterLinks'; import { ClusterAttributes } from '@backstage/plugin-kubernetes-common'; -import { FormatClusterLinkOptions } from '../../utils/clusterLinks/formatClusterLink'; import { ManifestYaml } from './ManifestYaml'; +import { useApi } from '@backstage/core-plugin-api'; +import { kubernetesClusterLinkFormatterApiRef } from '../../api'; +import useAsync from 'react-use/lib/useAsync'; const useDrawerStyles = makeStyles((theme: Theme) => createStyles({ @@ -147,20 +148,6 @@ function replaceNullsWithUndefined(someObj: any) { return JSON.parse(JSON.stringify(someObj, replacer)); } -function tryFormatClusterLink(options: FormatClusterLinkOptions) { - try { - return { - clusterLink: formatClusterLink(options), - errorMessage: '', - }; - } catch (err) { - return { - clusterLink: '', - errorMessage: err.message || err.toString(), - }; - } -} - const KubernetesStructuredMetadataTableDrawerContent = < T extends KubernetesDrawerable, >({ @@ -171,15 +158,20 @@ const KubernetesStructuredMetadataTableDrawerContent = < }: KubernetesStructuredMetadataTableDrawerContentProps) => { const [isYaml, setIsYaml] = useState(false); + const formatter = useApi(kubernetesClusterLinkFormatterApiRef); const classes = useDrawerContentStyles(); const cluster = useContext(ClusterContext); - const { clusterLink, errorMessage } = tryFormatClusterLink({ - dashboardUrl: cluster.dashboardUrl, - dashboardApp: cluster.dashboardApp, - dashboardParameters: cluster.dashboardParameters, - object, - kind, - }); + const { value: clusterLink, error } = useAsync( + async () => + formatter.formatClusterLink({ + dashboardUrl: cluster.dashboardUrl, + dashboardApp: cluster.dashboardApp, + dashboardParameters: cluster.dashboardParameters, + object, + kind, + }), + [cluster, object, kind, formatter], + ); return ( <> @@ -221,9 +213,12 @@ const KubernetesStructuredMetadataTableDrawerContent = <
- {errorMessage && ( + {error && (
- +
)}
diff --git a/plugins/kubernetes-react/src/components/ServicesAccordions/ServiceDrawer.test.tsx b/plugins/kubernetes-react/src/components/ServicesAccordions/ServiceDrawer.test.tsx index dda5e300eb..7eec2926c4 100644 --- a/plugins/kubernetes-react/src/components/ServicesAccordions/ServiceDrawer.test.tsx +++ b/plugins/kubernetes-react/src/components/ServicesAccordions/ServiceDrawer.test.tsx @@ -17,13 +17,20 @@ import React from 'react'; import { screen } from '@testing-library/react'; import * as services from './__fixtures__/2-services.json'; -import { textContentMatcher, renderInTestApp } from '@backstage/test-utils'; +import { + textContentMatcher, + renderInTestApp, + TestApiProvider, +} from '@backstage/test-utils'; import { ServiceDrawer } from './ServiceDrawer'; +import { kubernetesClusterLinkFormatterApiRef } from '../../api'; describe('ServiceDrawer', () => { it('should render deployment drawer', async () => { await renderInTestApp( - , + + , + , ); expect(screen.getAllByText('awesome-service-grpc')).toHaveLength(2); diff --git a/plugins/kubernetes-react/src/components/StatefulSetsAccordions/StatefulSetDrawer.test.tsx b/plugins/kubernetes-react/src/components/StatefulSetsAccordions/StatefulSetDrawer.test.tsx index c187c7d05d..d69ab15f1a 100644 --- a/plugins/kubernetes-react/src/components/StatefulSetsAccordions/StatefulSetDrawer.test.tsx +++ b/plugins/kubernetes-react/src/components/StatefulSetsAccordions/StatefulSetDrawer.test.tsx @@ -16,16 +16,24 @@ import React from 'react'; import * as statefulsets from '../../__fixtures__/2-statefulsets.json'; -import { renderInTestApp, textContentMatcher } from '@backstage/test-utils'; +import { + renderInTestApp, + TestApiProvider, + textContentMatcher, +} from '@backstage/test-utils'; import { StatefulSetDrawer } from './StatefulSetDrawer'; +import { kubernetesClusterLinkFormatterApiRef } from '../../api'; describe('StatefulSetDrawer', () => { it('should render statefulset drawer', async () => { const { getByText, getAllByText } = await renderInTestApp( - , + + + , + , ); expect(getAllByText('dice-roller')).toHaveLength(4); @@ -55,13 +63,16 @@ describe('StatefulSetDrawer', () => { it('should render statefulset drawer without namespace', async () => { const statefulset = (statefulsets as any).statefulsets[0]; const { queryByText } = await renderInTestApp( - , + + + , + , ); expect(queryByText('namespace: default')).not.toBeInTheDocument(); diff --git a/plugins/kubernetes-react/src/index.ts b/plugins/kubernetes-react/src/index.ts index 4fb8614091..326b363b05 100644 --- a/plugins/kubernetes-react/src/index.ts +++ b/plugins/kubernetes-react/src/index.ts @@ -27,5 +27,4 @@ export * from './hooks'; export * from './api'; export * from './kubernetes-auth-provider'; export * from './components'; -export * from './utils'; export * from './types'; diff --git a/plugins/kubernetes-react/src/types/types.ts b/plugins/kubernetes-react/src/types/types.ts index ad8df040ac..5db2e281f4 100644 --- a/plugins/kubernetes-react/src/types/types.ts +++ b/plugins/kubernetes-react/src/types/types.ts @@ -29,6 +29,6 @@ export interface ClusterLinksFormatterOptions { /** * @public */ -export type ClusterLinksFormatter = ( - options: ClusterLinksFormatterOptions, -) => URL; +export interface ClusterLinksFormatter { + formatClusterLink(options: ClusterLinksFormatterOptions): Promise; +} diff --git a/plugins/kubernetes-react/src/utils/clusterLinks/formatClusterLink.test.ts b/plugins/kubernetes-react/src/utils/clusterLinks/formatClusterLink.test.ts deleted file mode 100644 index 254b9fc51b..0000000000 --- a/plugins/kubernetes-react/src/utils/clusterLinks/formatClusterLink.test.ts +++ /dev/null @@ -1,158 +0,0 @@ -/* - * 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 { formatClusterLink } from './formatClusterLink'; - -describe('clusterLinks', () => { - describe('formatClusterLink', () => { - it('should not return an url when there is no dashboard url', () => { - const url = formatClusterLink({ object: {}, kind: 'foo' }); - expect(url).toBeUndefined(); - }); - it('should return an url even when there is no object', () => { - const url = formatClusterLink({ - dashboardUrl: 'https://k8s.foo.com', - object: undefined, - kind: 'foo', - }); - expect(url).toBe('https://k8s.foo.com'); - }); - it('should throw when the app is not recognized', () => { - expect(() => - formatClusterLink({ - dashboardUrl: 'https://k8s.foo.com', - dashboardApp: 'unknownapp', - object: { - metadata: { - name: 'foobar', - namespace: 'bar', - }, - }, - kind: 'Deployment', - }), - ).toThrow("Could not find Kubernetes dashboard app named 'unknownapp'"); - }); - - describe('default app', () => { - it('should return an url on the deployment', () => { - const url = formatClusterLink({ - dashboardUrl: 'https://k8s.foo.com/', - object: { - metadata: { - name: 'foobar', - namespace: 'bar', - }, - }, - kind: 'Deployment', - }); - expect(url).toBe( - 'https://k8s.foo.com/#/deployment/bar/foobar?namespace=bar', - ); - }); - it('should return an url on the service', () => { - const url = formatClusterLink({ - dashboardUrl: 'https://k8s.foo.com/', - object: { - metadata: { - name: 'foobar', - namespace: 'bar', - }, - }, - kind: 'Service', - }); - expect(url).toBe( - 'https://k8s.foo.com/#/service/bar/foobar?namespace=bar', - ); - }); - }); - - describe('standard app', () => { - it('should return an url on the deployment', () => { - const url = formatClusterLink({ - dashboardUrl: 'https://k8s.foo.com/', - dashboardApp: 'standard', - object: { - metadata: { - name: 'foobar', - namespace: 'bar', - }, - }, - kind: 'Deployment', - }); - expect(url).toBe( - 'https://k8s.foo.com/#/deployment/bar/foobar?namespace=bar', - ); - }); - it('should return an url on the service', () => { - const url = formatClusterLink({ - dashboardUrl: 'https://k8s.foo.com/', - dashboardApp: 'standard', - object: { - metadata: { - name: 'foobar', - namespace: 'bar', - }, - }, - kind: 'Service', - }); - expect(url).toBe( - 'https://k8s.foo.com/#/service/bar/foobar?namespace=bar', - ); - }); - }); - describe('GKE app', () => { - it('should return an url on the deployment', () => { - const url = formatClusterLink({ - dashboardApp: 'gke', - dashboardParameters: { - projectId: 'foobar-333614', - region: 'us-east1-c', - clusterName: 'cluster-1', - }, - object: { - metadata: { - name: 'foobar', - namespace: 'bar', - }, - }, - kind: 'Deployment', - }); - expect(url).toBe( - 'https://console.cloud.google.com/kubernetes/deployment/us-east1-c/cluster-1/bar/foobar/overview?project=foobar-333614', - ); - }); - it('should return an url on the service', () => { - const url = formatClusterLink({ - dashboardApp: 'gke', - dashboardParameters: { - projectId: 'foobar-333614', - region: 'us-east1-c', - clusterName: 'cluster-1', - }, - object: { - metadata: { - name: 'foobar', - namespace: 'bar', - }, - }, - kind: 'Service', - }); - expect(url).toBe( - 'https://console.cloud.google.com/kubernetes/service/us-east1-c/cluster-1/bar/foobar/overview?project=foobar-333614', - ); - }); - }); - }); -}); diff --git a/plugins/kubernetes-react/src/utils/clusterLinks/formatClusterLink.ts b/plugins/kubernetes-react/src/utils/clusterLinks/formatClusterLink.ts deleted file mode 100644 index 8f7e43a121..0000000000 --- a/plugins/kubernetes-react/src/utils/clusterLinks/formatClusterLink.ts +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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 type { JsonObject } from '@backstage/types'; -import { defaultFormatterName, clusterLinksFormatters } from './formatters'; - -/** - * @public - */ -export type FormatClusterLinkOptions = { - dashboardUrl?: string; - dashboardApp?: string; - dashboardParameters?: JsonObject; - object: any; - kind: string; -}; - -/** - * @public - */ -export function formatClusterLink(options: FormatClusterLinkOptions) { - if (!options.dashboardUrl && !options.dashboardParameters) { - return undefined; - } - if (options.dashboardUrl && !options.object) { - return options.dashboardUrl; - } - const app = options.dashboardApp || defaultFormatterName; - const formatter = clusterLinksFormatters[app]; - if (!formatter) { - throw new Error(`Could not find Kubernetes dashboard app named '${app}'`); - } - const url = formatter({ - dashboardUrl: options.dashboardUrl - ? new URL(options.dashboardUrl) - : undefined, - dashboardParameters: options.dashboardParameters, - object: options.object, - kind: options.kind, - }); - return url.toString(); -} diff --git a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/aks.ts b/plugins/kubernetes-react/src/utils/clusterLinks/formatters/aks.ts deleted file mode 100644 index 71fffb00e6..0000000000 --- a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/aks.ts +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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 { ClusterLinksFormatterOptions } from '../../../types/types'; - -const basePath = - 'https://portal.azure.com/#blade/Microsoft_Azure_ContainerService/AksK8ResourceMenuBlade/overview-Deployment/aksClusterId'; - -const requiredParams = ['subscriptionId', 'resourceGroup', 'clusterName']; - -export function aksFormatter(options: ClusterLinksFormatterOptions): URL { - if (!options.dashboardParameters) { - throw new Error('AKS dashboard requires a dashboardParameters option'); - } - const args = options.dashboardParameters; - for (const param of requiredParams) { - if (typeof args[param] !== 'string') { - throw new Error( - `AKS dashboard requires a "${param}" of type string in the dashboardParameters option`, - ); - } - } - - const path = `/subscriptions/${args.subscriptionId}/resourceGroups/${args.resourceGroup}/providers/Microsoft.ContainerService/managedClusters/${args.clusterName}`; - - const { name, namespace, uid } = options.object.metadata; - const { selector } = options.object.spec; - const params = { - kind: options.kind, - metadata: { name, namespace, uid }, - spec: { - selector, - }, - }; - - return new URL( - `${basePath}/${encodeURIComponent(path)}/resource/${encodeURIComponent( - JSON.stringify(params), - )}`, - ); -} diff --git a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/gke.ts b/plugins/kubernetes-react/src/utils/clusterLinks/formatters/gke.ts deleted file mode 100644 index 957032e6e2..0000000000 --- a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/gke.ts +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 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 { ClusterLinksFormatterOptions } from '../../../types/types'; - -const kindMappings: Record = { - deployment: 'deployment', - pod: 'pod', - ingress: 'ingress', - service: 'service', - horizontalpodautoscaler: 'deployment', -}; - -export function gkeFormatter(options: ClusterLinksFormatterOptions): URL { - if (!options.dashboardParameters) { - throw new Error('GKE dashboard requires a dashboardParameters option'); - } - const args = options.dashboardParameters; - if (typeof args.projectId !== 'string') { - throw new Error( - 'GKE dashboard requires a "projectId" of type string in the dashboardParameters option', - ); - } - if (typeof args.region !== 'string') { - throw new Error( - 'GKE dashboard requires a "region" of type string in the dashboardParameters option', - ); - } - if (typeof args.clusterName !== 'string') { - throw new Error( - 'GKE dashboard requires a "clusterName" of type string in the dashboardParameters option', - ); - } - const basePath = new URL('https://console.cloud.google.com/'); - const region = encodeURIComponent(args.region); - const clusterName = encodeURIComponent(args.clusterName); - const name = encodeURIComponent(options.object.metadata?.name ?? ''); - const namespace = encodeURIComponent( - options.object.metadata?.namespace ?? '', - ); - const validKind = kindMappings[options.kind.toLocaleLowerCase('en-US')]; - let path = ''; - if (namespace && name && validKind) { - const kindsWithDetails = ['ingress', 'pod']; - const landingPage = kindsWithDetails.includes(validKind) - ? 'details' - : 'overview'; - path = `kubernetes/${validKind}/${region}/${clusterName}/${namespace}/${name}/${landingPage}`; - } else { - path = `kubernetes/clusters/details/${region}/${clusterName}/details`; - } - const result = new URL(path, basePath); - result.searchParams.set('project', args.projectId); - return result; -} diff --git a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/index.ts b/plugins/kubernetes-react/src/utils/clusterLinks/formatters/index.ts deleted file mode 100644 index b75e45cc7f..0000000000 --- a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/index.ts +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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 { ClusterLinksFormatter } from '../../../types/types'; -import { standardFormatter } from './standard'; -import { rancherFormatter } from './rancher'; -import { openshiftFormatter } from './openshift'; -import { aksFormatter } from './aks'; -import { eksFormatter } from './eks'; -import { gkeFormatter } from './gke'; - -/** - * @public - */ -export const clusterLinksFormatters: Record = { - standard: standardFormatter, - rancher: rancherFormatter, - openshift: openshiftFormatter, - aks: aksFormatter, - eks: eksFormatter, - gke: gkeFormatter, -}; -export const defaultFormatterName = 'standard'; diff --git a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/openshift.ts b/plugins/kubernetes-react/src/utils/clusterLinks/formatters/openshift.ts deleted file mode 100644 index c5b7313061..0000000000 --- a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/openshift.ts +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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 { ClusterLinksFormatterOptions } from '../../../types/types'; - -const kindMappings: Record = { - deployment: 'deployments', - ingress: 'ingresses', - service: 'services', - horizontalpodautoscaler: 'horizontalpodautoscalers', - persistentvolume: 'persistentvolumes', -}; - -export function openshiftFormatter(options: ClusterLinksFormatterOptions): URL { - if (!options.dashboardUrl) { - throw new Error('OpenShift dashboard requires a dashboardUrl option'); - } - const basePath = new URL(options.dashboardUrl.href); - const name = encodeURIComponent(options.object.metadata?.name ?? ''); - const namespace = encodeURIComponent( - options.object.metadata?.namespace ?? '', - ); - const validKind = kindMappings[options.kind.toLocaleLowerCase('en-US')]; - if (!basePath.pathname.endsWith('/')) { - // a dashboard url with a path should end with a slash otherwise - // the new combined URL will replace the last segment with the appended path! - // https://foobar.com/abc/def + k8s/cluster/projects/test --> https://foobar.com/abc/k8s/cluster/projects/test - // https://foobar.com/abc/def/ + k8s/cluster/projects/test --> https://foobar.com/abc/def/k8s/cluster/projects/test - basePath.pathname += '/'; - } - let path = ''; - if (namespace) { - if (name && validKind) { - path = `k8s/ns/${namespace}/${validKind}/${name}`; - } else { - path = `k8s/cluster/projects/${namespace}`; - } - } else if (validKind) { - path = `k8s/cluster/${validKind}`; - if (name) { - path += `/${name}`; - } - } - return new URL(path, basePath); -} diff --git a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/rancher.ts b/plugins/kubernetes-react/src/utils/clusterLinks/formatters/rancher.ts deleted file mode 100644 index 6c72730181..0000000000 --- a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/rancher.ts +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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 { ClusterLinksFormatterOptions } from '../../../types/types'; - -const kindMappings: Record = { - deployment: 'apps.deployment', - ingress: 'networking.k8s.io.ingress', - service: 'service', - horizontalpodautoscaler: 'autoscaling.horizontalpodautoscaler', -}; - -export function rancherFormatter(options: ClusterLinksFormatterOptions): URL { - if (!options.dashboardUrl) { - throw new Error('Rancher dashboard requires a dashboardUrl option'); - } - const basePath = new URL(options.dashboardUrl.href); - const name = encodeURIComponent(options.object.metadata?.name ?? ''); - const namespace = encodeURIComponent( - options.object.metadata?.namespace ?? '', - ); - const validKind = kindMappings[options.kind.toLocaleLowerCase('en-US')]; - if (!basePath.pathname.endsWith('/')) { - // a dashboard url with a path should end with a slash otherwise - // the new combined URL will replace the last segment with the appended path! - // https://foobar.com/abc/def + explorer/service/test --> https://foobar.com/abc/explorer/service/test - // https://foobar.com/abc/def/ + explorer/service/test --> https://foobar.com/abc/def/explorer/service/test - basePath.pathname += '/'; - } - let path = ''; - if (validKind && name && namespace) { - path = `explorer/${validKind}/${namespace}/${name}`; - } else if (namespace) { - path = 'explorer/workload'; - } - return new URL(path, basePath); -} diff --git a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/standard.ts b/plugins/kubernetes-react/src/utils/clusterLinks/formatters/standard.ts deleted file mode 100644 index e26adf98e6..0000000000 --- a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/standard.ts +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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 { ClusterLinksFormatterOptions } from '../../../types/types'; - -const kindMappings: Record = { - deployment: 'deployment', - pod: 'pod', - ingress: 'ingress', - service: 'service', - horizontalpodautoscaler: 'deployment', - statefulset: 'statefulset', -}; - -export function standardFormatter(options: ClusterLinksFormatterOptions) { - if (!options.dashboardUrl) { - throw new Error('standard dashboard requires a dashboardUrl option'); - } - const result = new URL(options.dashboardUrl.href); - const name = encodeURIComponent(options.object.metadata?.name ?? ''); - const namespace = encodeURIComponent( - options.object.metadata?.namespace ?? '', - ); - const validKind = kindMappings[options.kind.toLocaleLowerCase('en-US')]; - if (!result.pathname.endsWith('/')) { - result.pathname += '/'; - } - if (validKind && name && namespace) { - result.hash = `/${validKind}/${namespace}/${name}`; - } else if (namespace) { - result.hash = '/workloads'; - } - if (namespace) { - // Note that Angular SPA requires a hash and the query parameter should be part of it - result.hash += `?namespace=${namespace}`; - } - return result; -} diff --git a/plugins/kubernetes-react/src/utils/clusterLinks/index.ts b/plugins/kubernetes-react/src/utils/clusterLinks/index.ts deleted file mode 100644 index 90a30e8277..0000000000 --- a/plugins/kubernetes-react/src/utils/clusterLinks/index.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* - * 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. - */ - -export { - formatClusterLink, - type FormatClusterLinkOptions, -} from './formatClusterLink'; -export { clusterLinksFormatters } from './formatters'; diff --git a/plugins/kubernetes-react/src/utils/index.ts b/plugins/kubernetes-react/src/utils/index.ts deleted file mode 100644 index d47afaf668..0000000000 --- a/plugins/kubernetes-react/src/utils/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * 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. - */ -export * from './clusterLinks'; diff --git a/plugins/kubernetes/src/plugin.ts b/plugins/kubernetes/src/plugin.ts index ac55dbbf23..c479f99aa0 100644 --- a/plugins/kubernetes/src/plugin.ts +++ b/plugins/kubernetes/src/plugin.ts @@ -20,6 +20,10 @@ import { kubernetesAuthProvidersApiRef, KubernetesAuthProviders, KubernetesProxyClient, + kubernetesClusterLinkFormatterApiRef, + getDefaultFormatters, + KubernetesClusterLinkFormatter, + DEFAULT_FORMATTER_NAME, } from '@backstage/plugin-kubernetes-react'; import { createApiFactory, @@ -97,6 +101,17 @@ export const kubernetesPlugin = createPlugin({ }); }, }), + createApiFactory({ + api: kubernetesClusterLinkFormatterApiRef, + deps: {}, + factory: deps => { + const formatters = getDefaultFormatters(deps); + return new KubernetesClusterLinkFormatter({ + formatters, + defaultFormatterName: DEFAULT_FORMATTER_NAME, + }); + }, + }), ], routes: { entityContent: rootCatalogKubernetesRouteRef, From cdf6cc2591cb0b2de82ca891012ed1c5393b2c7c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 30 Nov 2023 20:53:08 +0000 Subject: [PATCH 250/261] chore(deps): update dependency @testing-library/jest-dom to v6.1.5 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 65e69c6324..bf75efe2ed 100644 --- a/yarn.lock +++ b/yarn.lock @@ -17409,8 +17409,8 @@ __metadata: linkType: hard "@testing-library/jest-dom@npm:^6.0.0": - version: 6.1.4 - resolution: "@testing-library/jest-dom@npm:6.1.4" + version: 6.1.5 + resolution: "@testing-library/jest-dom@npm:6.1.5" dependencies: "@adobe/css-tools": ^4.3.1 "@babel/runtime": ^7.9.2 @@ -17434,7 +17434,7 @@ __metadata: optional: true vitest: optional: true - checksum: c6bd9469554136a25d94b55ea16736d56b8c5d200526023774dbf35ca35551a721257e6734f1b404bbd07ae0a1950f1912b5be60e113db2ff2ff50af14f7085c + checksum: 67f1433c7eb8649db6676df97d1144cf288e2d94c61e89531c05c587b56f2277454c558c97bcca567d5060ebd39caba5ba01d49dc57b3f005837477a401ad113 languageName: node linkType: hard From 2638acd49e7b0b353562fbedd873dcc00eca213b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 30 Nov 2023 20:54:47 +0000 Subject: [PATCH 251/261] chore(deps): update dependency @types/luxon to v3.3.6 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- microsite/yarn.lock | 6 +++--- yarn.lock | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/microsite/yarn.lock b/microsite/yarn.lock index 0eed7b6eb3..928b81ab16 100644 --- a/microsite/yarn.lock +++ b/microsite/yarn.lock @@ -3045,9 +3045,9 @@ __metadata: linkType: hard "@types/luxon@npm:^3.0.0": - version: 3.3.5 - resolution: "@types/luxon@npm:3.3.5" - checksum: 7fd31c673600dd494dedefe8c405d2e6957c0ba101f8445f7eaf9afcf4a1fa1ca649cab01c9777523ff9de58c3c35e2589a1a004a0c629cd7953033115ac74f5 + version: 3.3.6 + resolution: "@types/luxon@npm:3.3.6" + checksum: 44fd3e617fb5d9e370a8d5529de3e703b295bfe225936e786e0b5e7fce662ef82012a6ec29cd2763afbd59bf9a9ab43186bad5c51aa552d963cd5e8c8f4e1d4f languageName: node linkType: hard diff --git a/yarn.lock b/yarn.lock index 65e69c6324..bfb24513b9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -18509,9 +18509,9 @@ __metadata: linkType: hard "@types/luxon@npm:*, @types/luxon@npm:^3.0.0, @types/luxon@npm:~3.3.0": - version: 3.3.5 - resolution: "@types/luxon@npm:3.3.5" - checksum: 7fd31c673600dd494dedefe8c405d2e6957c0ba101f8445f7eaf9afcf4a1fa1ca649cab01c9777523ff9de58c3c35e2589a1a004a0c629cd7953033115ac74f5 + version: 3.3.6 + resolution: "@types/luxon@npm:3.3.6" + checksum: 44fd3e617fb5d9e370a8d5529de3e703b295bfe225936e786e0b5e7fce662ef82012a6ec29cd2763afbd59bf9a9ab43186bad5c51aa552d963cd5e8c8f4e1d4f languageName: node linkType: hard From a4b747db3faa0e096c1d8cb3b87d416abf22a138 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 30 Nov 2023 22:10:33 +0000 Subject: [PATCH 252/261] chore(deps): update dependency @types/node to v18.19.0 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index faa574d1e7..9624c405f3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -18684,11 +18684,11 @@ __metadata: linkType: hard "@types/node@npm:^18.17.8": - version: 18.18.14 - resolution: "@types/node@npm:18.18.14" + version: 18.19.0 + resolution: "@types/node@npm:18.19.0" dependencies: undici-types: ~5.26.4 - checksum: 3a77e6819e50fd22196b08d542433e1513c855f4993a200bc0e7be076445c61ce2a9e5f7f202f060c46130b2b2f98643461fb7999f874475e6bb322c4534c580 + checksum: cf91c4dd7c219e101dee820c69dc5ad497acbcc0a44a7d5efb00fdea4bede247446ce5f4bbd3d115ca539dd21321d840ad42eaacce3321cde1f732b29a621fb8 languageName: node linkType: hard From 68f261da76f12514f45a8da6c72d8de7bbe1f7a2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 30 Nov 2023 22:10:39 +0000 Subject: [PATCH 253/261] chore(deps): update docker/metadata-action action to v5.2.0 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/uffizzi-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/uffizzi-build.yml b/.github/workflows/uffizzi-build.yml index 6bc36c796a..4eaf2c2dc0 100644 --- a/.github/workflows/uffizzi-build.yml +++ b/.github/workflows/uffizzi-build.yml @@ -60,7 +60,7 @@ jobs: - name: Docker metadata id: meta - uses: docker/metadata-action@96383f45573cb7f253c731d3b3ab81c87ef81934 # v5.0.0 + uses: docker/metadata-action@e6428a5c4e294a61438ed7f43155db912025b6b3 # v5.2.0 with: images: registry.uffizzi.com/${{ env.UUID_TAG_APP }} tags: type=raw,value=60d From 2c01c9245f4a434237beabeaf3cd7a25aa5d5bda Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 1 Dec 2023 00:38:10 +0000 Subject: [PATCH 254/261] fix(deps): update dependency @google-cloud/storage to v7.7.0 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 9624c405f3..9fc32232d1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11638,8 +11638,8 @@ __metadata: linkType: hard "@google-cloud/storage@npm:^7.0.0": - version: 7.6.0 - resolution: "@google-cloud/storage@npm:7.6.0" + version: 7.7.0 + resolution: "@google-cloud/storage@npm:7.7.0" dependencies: "@google-cloud/paginator": ^5.0.0 "@google-cloud/projectify": ^4.0.0 @@ -11658,7 +11658,7 @@ __metadata: retry-request: ^7.0.0 teeny-request: ^9.0.0 uuid: ^8.0.0 - checksum: 0ab71792ddafef3ce3634e2428fe3508572611caa436c4e6315f5f8657f48fa5714f0410383f8b006b469d7e71b7ef2dd2c0d68323753bcd0b381b06bdd3e1f4 + checksum: b63069b7e591e55f9132aab9e8f9cd03b72a5b6e531c1f37fc44c4cd34eb02dd50e8007739dad6f0ac2ddb216eb5a80bc3b062d1d8c42aad7351e6cc6008d27f languageName: node linkType: hard From bc67498b100a68605a5d360837085f2c580fc1e4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 1 Dec 2023 01:21:52 +0000 Subject: [PATCH 255/261] fix(deps): update dependency archiver to v6 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .changeset/renovate-12c95fb.md | 6 ++ packages/backend-common/package.json | 4 +- yarn.lock | 123 +++++++++++++++++++++++++-- 3 files changed, 126 insertions(+), 7 deletions(-) create mode 100644 .changeset/renovate-12c95fb.md diff --git a/.changeset/renovate-12c95fb.md b/.changeset/renovate-12c95fb.md new file mode 100644 index 0000000000..814817b8c2 --- /dev/null +++ b/.changeset/renovate-12c95fb.md @@ -0,0 +1,6 @@ +--- +'@backstage/backend-common': patch +--- + +Updated dependency `archiver` to `^6.0.0`. +Updated dependency `@types/archiver` to `^6.0.0`. diff --git a/packages/backend-common/package.json b/packages/backend-common/package.json index 8b30d1ed0f..357c929e6c 100644 --- a/packages/backend-common/package.json +++ b/packages/backend-common/package.json @@ -75,7 +75,7 @@ "@types/express": "^4.17.6", "@types/luxon": "^3.0.0", "@types/webpack-env": "^1.15.2", - "archiver": "^5.0.2", + "archiver": "^6.0.0", "base64-stream": "^1.0.0", "compression": "^1.7.4", "concat-stream": "^2.0.0", @@ -118,7 +118,7 @@ "@aws-sdk/util-stream-node": "^3.350.0", "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", - "@types/archiver": "^5.1.0", + "@types/archiver": "^6.0.0", "@types/base64-stream": "^1.0.2", "@types/compression": "^1.7.0", "@types/concat-stream": "^2.0.0", diff --git a/yarn.lock b/yarn.lock index 9fc32232d1..4521f62b0c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3322,7 +3322,7 @@ __metadata: "@kubernetes/client-node": 0.20.0 "@manypkg/get-packages": ^1.1.3 "@octokit/rest": ^19.0.3 - "@types/archiver": ^5.1.0 + "@types/archiver": ^6.0.0 "@types/base64-stream": ^1.0.2 "@types/compression": ^1.7.0 "@types/concat-stream": ^2.0.0 @@ -3337,7 +3337,7 @@ __metadata: "@types/tar": ^6.1.1 "@types/webpack-env": ^1.15.2 "@types/yauzl": ^2.10.0 - archiver: ^5.0.2 + archiver: ^6.0.0 aws-sdk-client-mock: ^3.0.0 base64-stream: ^1.0.0 better-sqlite3: ^9.0.0 @@ -17589,7 +17589,7 @@ __metadata: languageName: node linkType: hard -"@types/archiver@npm:^5.1.0, @types/archiver@npm:^5.3.1": +"@types/archiver@npm:^5.3.1": version: 5.3.4 resolution: "@types/archiver@npm:5.3.4" dependencies: @@ -17598,6 +17598,15 @@ __metadata: languageName: node linkType: hard +"@types/archiver@npm:^6.0.0": + version: 6.0.2 + resolution: "@types/archiver@npm:6.0.2" + dependencies: + "@types/readdir-glob": "*" + checksum: 4bef71e5b95863be9880339275ad92c2513dd78d56587653614dc5a74af1d078f5f5926ec996de06e7071a1003e0c2764d0e9d2bb0893a2ffb14ab1718eaf5ca + languageName: node + linkType: hard + "@types/argparse@npm:1.0.38": version: 1.0.38 resolution: "@types/argparse@npm:1.0.38" @@ -20666,7 +20675,21 @@ __metadata: languageName: node linkType: hard -"archiver@npm:^5.0.2, archiver@npm:^5.3.1": +"archiver-utils@npm:^4.0.1": + version: 4.0.1 + resolution: "archiver-utils@npm:4.0.1" + dependencies: + glob: ^8.0.0 + graceful-fs: ^4.2.0 + lazystream: ^1.0.0 + lodash: ^4.17.15 + normalize-path: ^3.0.0 + readable-stream: ^3.6.0 + checksum: 2917cdf63a912c74002a4a1e6de3076a4691030b4e722efdd6d862447b61cd64c8b7688d331b1d35f8d4fc661d6e34f91bc1ffc79478fca2e48ad060acece18c + languageName: node + linkType: hard + +"archiver@npm:^5.3.1": version: 5.3.2 resolution: "archiver@npm:5.3.2" dependencies: @@ -20681,6 +20704,21 @@ __metadata: languageName: node linkType: hard +"archiver@npm:^6.0.0": + version: 6.0.1 + resolution: "archiver@npm:6.0.1" + dependencies: + archiver-utils: ^4.0.1 + async: ^3.2.4 + buffer-crc32: ^0.2.1 + readable-stream: ^3.6.0 + readdir-glob: ^1.1.2 + tar-stream: ^3.0.0 + zip-stream: ^5.0.1 + checksum: 20549eef7366173440a86873387412226568744a410626f826998b0dda85fe84e739c542d9db9aca3923b772436eb795eafdff29c2983e683355fdd9faaa0fdb + languageName: node + linkType: hard + "are-we-there-yet@npm:^2.0.0": version: 2.0.0 resolution: "are-we-there-yet@npm:2.0.0" @@ -21232,6 +21270,13 @@ __metadata: languageName: node linkType: hard +"b4a@npm:^1.6.4": + version: 1.6.4 + resolution: "b4a@npm:1.6.4" + checksum: 81b086f9af1f8845fbef4476307236bda3d660c158c201db976f19cdce05f41f93110ab6b12fd7a2696602a490cc43d5410ee36a56d6eef93afb0d6ca69ac3b2 + languageName: node + linkType: hard + "babel-core@npm:^7.0.0-bridge.0": version: 7.0.0-bridge.0 resolution: "babel-core@npm:7.0.0-bridge.0" @@ -23153,6 +23198,18 @@ __metadata: languageName: node linkType: hard +"compress-commons@npm:^5.0.1": + version: 5.0.1 + resolution: "compress-commons@npm:5.0.1" + dependencies: + crc-32: ^1.2.0 + crc32-stream: ^5.0.0 + normalize-path: ^3.0.0 + readable-stream: ^3.6.0 + checksum: 65a68e56211a8d1dbe9dab0d35f1bd60a4df27aa01e6c3f0883080263e228c460758bab4f083637a380d4a96d2326722972a42ea1951360cc69728a3915f209f + languageName: node + linkType: hard + "compressible@npm:^2.0.12, compressible@npm:~2.0.16": version: 2.0.18 resolution: "compressible@npm:2.0.18" @@ -23610,6 +23667,16 @@ __metadata: languageName: node linkType: hard +"crc32-stream@npm:^5.0.0": + version: 5.0.0 + resolution: "crc32-stream@npm:5.0.0" + dependencies: + crc-32: ^1.2.0 + readable-stream: ^3.4.0 + checksum: 8e5dd04f22f3fbecc623492395107fbed2114f225bd606e39e8ed338f2fc1c454ac02a05741243620ab526473cb867fa86411a44a7ffcd88457cc1c2af82d0bc + languageName: node + linkType: hard + "create-ecdh@npm:^4.0.0": version: 4.0.3 resolution: "create-ecdh@npm:4.0.3" @@ -27167,6 +27234,13 @@ __metadata: languageName: node linkType: hard +"fast-fifo@npm:^1.1.0, fast-fifo@npm:^1.2.0": + version: 1.3.2 + resolution: "fast-fifo@npm:1.3.2" + checksum: 6bfcba3e4df5af7be3332703b69a7898a8ed7020837ec4395bb341bd96cc3a6d86c3f6071dd98da289618cf2234c70d84b2a6f09a33dd6f988b1ff60d8e54275 + languageName: node + linkType: hard + "fast-glob@npm:^3.2.11, fast-glob@npm:^3.2.12, fast-glob@npm:^3.2.9": version: 3.2.12 resolution: "fast-glob@npm:3.2.12" @@ -28397,7 +28471,7 @@ __metadata: languageName: node linkType: hard -"glob@npm:^8.0.1, glob@npm:^8.0.3": +"glob@npm:^8.0.0, glob@npm:^8.0.1, glob@npm:^8.0.3": version: 8.1.0 resolution: "glob@npm:8.1.0" dependencies: @@ -38158,6 +38232,13 @@ __metadata: languageName: node linkType: hard +"queue-tick@npm:^1.0.1": + version: 1.0.1 + resolution: "queue-tick@npm:1.0.1" + checksum: 57c3292814b297f87f792fbeb99ce982813e4e54d7a8bdff65cf53d5c084113913289d4a48ec8bbc964927a74b847554f9f4579df43c969a6c8e0f026457ad01 + languageName: node + linkType: hard + "quick-format-unescaped@npm:^3.0.3": version: 3.0.3 resolution: "quick-format-unescaped@npm:3.0.3" @@ -41520,6 +41601,16 @@ __metadata: languageName: node linkType: hard +"streamx@npm:^2.15.0": + version: 2.15.5 + resolution: "streamx@npm:2.15.5" + dependencies: + fast-fifo: ^1.1.0 + queue-tick: ^1.0.1 + checksum: 52e0ec94026d67c9e2e2e1090f05e5b138c2f2822462d9a8ef4a4805625a31d103e55ea5267fcd9bfe041374926424e42aec2dda28a85cb9de42c2a16d416d94 + languageName: node + linkType: hard + "strict-event-emitter@npm:^0.2.4": version: 0.2.8 resolution: "strict-event-emitter@npm:0.2.8" @@ -42195,6 +42286,17 @@ __metadata: languageName: node linkType: hard +"tar-stream@npm:^3.0.0": + version: 3.1.6 + resolution: "tar-stream@npm:3.1.6" + dependencies: + b4a: ^1.6.4 + fast-fifo: ^1.2.0 + streamx: ^2.15.0 + checksum: f3627f918581976e954ff03cb8d370551053796b82564f8c7ca8fac84c48e4d042026d0854fc222171a34ff9c682b72fae91be9c9b0a112d4c54f9e4f443e9c5 + languageName: node + linkType: hard + "tar@npm:^6.0.2, tar@npm:^6.1.0, tar@npm:^6.1.11, tar@npm:^6.1.12, tar@npm:^6.1.2": version: 6.2.0 resolution: "tar@npm:6.2.0" @@ -45332,6 +45434,17 @@ __metadata: languageName: node linkType: hard +"zip-stream@npm:^5.0.1": + version: 5.0.1 + resolution: "zip-stream@npm:5.0.1" + dependencies: + archiver-utils: ^4.0.1 + compress-commons: ^5.0.1 + readable-stream: ^3.6.0 + checksum: 116cee5a2c1ecce7aa440b665470653f58ef56670c6aafa1b5491c9f9335992352145502af5fa865ac82f46336905e37fb7cbc649c2be72e2152c6b91802995c + languageName: node + linkType: hard + "zod-to-json-schema@npm:^3.20.4, zod-to-json-schema@npm:^3.21.4": version: 3.22.1 resolution: "zod-to-json-schema@npm:3.22.1" From ebf15857bc7b8fb284e026e549f43b310fb02099 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 1 Dec 2023 02:31:31 +0000 Subject: [PATCH 256/261] fix(deps): update dependency recharts to v2.10.3 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 9fc32232d1..b1aad2e355 100644 --- a/yarn.lock +++ b/yarn.lock @@ -39260,8 +39260,8 @@ __metadata: linkType: hard "recharts@npm:^2.5.0": - version: 2.10.2 - resolution: "recharts@npm:2.10.2" + version: 2.10.3 + resolution: "recharts@npm:2.10.3" dependencies: clsx: ^2.0.0 eventemitter3: ^4.0.1 @@ -39275,7 +39275,7 @@ __metadata: prop-types: ^15.6.0 react: ^16.0.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 - checksum: da0383c4b9c2dae76cd415bd1678285ce5975545cd2d305054189b21ce7c9559ad7233941152a8bab0897196281c8bb142710c815d93ebe828901b8799c7528a + checksum: 503c9fefa8648e0e8834a11ccc09fdcc310d391807438f4c0567b1888d7cd5f7a1f65f020afb981ec54ad6f96d31ebe757ab9025e93782edabc5c741f1aa946a languageName: node linkType: hard From eb7a28731f0be51b242a909d96bfa0f27dfd967a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 1 Dec 2023 08:19:58 +0000 Subject: [PATCH 257/261] fix(deps): update dependency @roadiehq/backstage-plugin-buildkite to v2.1.17 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/yarn.lock b/yarn.lock index 0a626b0ea5..ce5bcdac45 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5950,7 +5950,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-catalog-react@npm:^1.2.4, @backstage/plugin-catalog-react@npm:^1.8.5": +"@backstage/plugin-catalog-react@npm:^1.2.4, @backstage/plugin-catalog-react@npm:^1.8.5, @backstage/plugin-catalog-react@npm:^1.9.1": version: 1.9.1 resolution: "@backstage/plugin-catalog-react@npm:1.9.1" dependencies: @@ -15224,14 +15224,14 @@ __metadata: linkType: hard "@roadiehq/backstage-plugin-buildkite@npm:^2.0.8": - version: 2.1.16 - resolution: "@roadiehq/backstage-plugin-buildkite@npm:2.1.16" + version: 2.1.17 + resolution: "@roadiehq/backstage-plugin-buildkite@npm:2.1.17" dependencies: "@backstage/catalog-model": ^1.4.3 - "@backstage/core-components": ^0.13.7 - "@backstage/core-plugin-api": ^1.7.0 - "@backstage/plugin-catalog-react": ^1.8.5 - "@backstage/theme": ^0.4.3 + "@backstage/core-components": ^0.13.8 + "@backstage/core-plugin-api": ^1.8.0 + "@backstage/plugin-catalog-react": ^1.9.1 + "@backstage/theme": ^0.4.4 "@material-ui/core": ^4.12.1 "@material-ui/icons": ^4.11.2 "@material-ui/lab": 4.0.0-alpha.57 @@ -15243,7 +15243,7 @@ __metadata: react-dom: ^16.13.1 || ^17.0.0 react-router: 6.0.0-beta.0 || ^6.3.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 - checksum: 716755abfc85c452382ca1535d819a7ebb9a52d024557c51d240df7193a15b98567dad5fe0dcbbf72df0b27f773f1be0f25a5e876024f3a1f03c0eff99fc7a2c + checksum: 218a614d81ee89b2a1613979258788d612c675da2af7ffdcecaa6e47206d6aa4f463defc376f5c4a53ba2136038d0e0659ba80182bd8001c144323e40f3ff5ab languageName: node linkType: hard From 728f033874e3758728209f4acc8d6d72eba89581 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 1 Dec 2023 08:55:05 +0000 Subject: [PATCH 258/261] fix(deps): update dependency @roadiehq/backstage-plugin-github-insights to v2.3.23 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/yarn.lock b/yarn.lock index 0f00bd520f..8be16f5aba 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4287,7 +4287,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/integration-react@npm:^1.1.20, @backstage/integration-react@npm:^1.1.21": +"@backstage/integration-react@npm:^1.1.21": version: 1.1.21 resolution: "@backstage/integration-react@npm:1.1.21" dependencies: @@ -15248,15 +15248,15 @@ __metadata: linkType: hard "@roadiehq/backstage-plugin-github-insights@npm:^2.0.5": - version: 2.3.22 - resolution: "@roadiehq/backstage-plugin-github-insights@npm:2.3.22" + version: 2.3.23 + resolution: "@roadiehq/backstage-plugin-github-insights@npm:2.3.23" dependencies: "@backstage/catalog-model": ^1.4.3 - "@backstage/core-components": ^0.13.7 - "@backstage/core-plugin-api": ^1.7.0 - "@backstage/integration-react": ^1.1.20 - "@backstage/plugin-catalog-react": ^1.8.5 - "@backstage/theme": ^0.4.3 + "@backstage/core-components": ^0.13.8 + "@backstage/core-plugin-api": ^1.8.0 + "@backstage/integration-react": ^1.1.21 + "@backstage/plugin-catalog-react": ^1.9.1 + "@backstage/theme": ^0.4.4 "@date-io/core": 2.10.7 "@material-ui/core": ^4.11.0 "@material-ui/icons": ^4.9.1 @@ -15271,7 +15271,7 @@ __metadata: react: ^16.13.1 || ^17.0.0 react-dom: ^16.13.1 || ^17.0.0 react-router: 6.0.0-beta.0 || ^6.3.0 - checksum: 1bdfa2dc1fca12f5a47a11a2df54a774992c1a91d294e646b70f1a197575b96c34da78356d230d0a65695348a1caef6ab62f2553e7e75a01504e58407108135a + checksum: 07dd3df1d8f99ea6f2910d343c361bd27b249fbd1e982fc42630ddc8e530901ef42e9a3cf5a944c80abd0c5be25cca716c12a838057ec1e83ad538a9462033e4 languageName: node linkType: hard From 495628ddc99dbf010d4fc9fb817e8aaac4bb69d7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 1 Dec 2023 09:35:18 +0000 Subject: [PATCH 259/261] fix(deps): update dependency @roadiehq/backstage-plugin-github-pull-requests to v2.5.20 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/yarn.lock b/yarn.lock index 8be16f5aba..88c55ed9b3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7325,7 +7325,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-home-react@npm:^0.1.4": +"@backstage/plugin-home-react@npm:^0.1.5": version: 0.1.5 resolution: "@backstage/plugin-home-react@npm:0.1.5" dependencies: @@ -15276,14 +15276,14 @@ __metadata: linkType: hard "@roadiehq/backstage-plugin-github-pull-requests@npm:^2.2.7": - version: 2.5.19 - resolution: "@roadiehq/backstage-plugin-github-pull-requests@npm:2.5.19" + version: 2.5.20 + resolution: "@roadiehq/backstage-plugin-github-pull-requests@npm:2.5.20" dependencies: "@backstage/catalog-model": ^1.4.3 - "@backstage/core-components": ^0.13.7 - "@backstage/core-plugin-api": ^1.7.0 - "@backstage/plugin-catalog-react": ^1.8.5 - "@backstage/plugin-home-react": ^0.1.4 + "@backstage/core-components": ^0.13.8 + "@backstage/core-plugin-api": ^1.8.0 + "@backstage/plugin-catalog-react": ^1.9.1 + "@backstage/plugin-home-react": ^0.1.5 "@material-ui/core": ^4.11.0 "@material-ui/icons": ^4.9.1 "@material-ui/lab": ^4.0.0-alpha.60 @@ -15300,7 +15300,7 @@ __metadata: react: ^16.13.1 || ^17.0.0 react-dom: ^16.13.1 || ^17.0.0 react-router: 6.0.0-beta.0 || ^6.3.0 - checksum: 35d760d22626d6d76438db66e36610aff8f1b171ae4d60944edcd631427b55f2a0489339db761764d2d406c5d3480ec8786db16ffb803d28eb96544b8c8e75a7 + checksum: f9ac5bbff5173eff98002f3f8bd7b7fe349723039481651b1e81b7aa5bbaaa799f4cd51d5425a5d74cebf3d0f5bb7340a0c4091b858addc45791881c3802f7a7 languageName: node linkType: hard From c5bbed656cd3f605a3e1e55f1880e98772597cec Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 1 Dec 2023 09:35:48 +0000 Subject: [PATCH 260/261] fix(deps): update dependency @roadiehq/backstage-plugin-travis-ci to v2.1.17 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/yarn.lock b/yarn.lock index 8be16f5aba..bea6e17a90 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10173,7 +10173,7 @@ __metadata: languageName: node linkType: hard -"@backstage/theme@npm:^0.4.3, @backstage/theme@npm:^0.4.4": +"@backstage/theme@npm:^0.4.4": version: 0.4.4 resolution: "@backstage/theme@npm:0.4.4" dependencies: @@ -15305,14 +15305,14 @@ __metadata: linkType: hard "@roadiehq/backstage-plugin-travis-ci@npm:^2.0.5": - version: 2.1.16 - resolution: "@roadiehq/backstage-plugin-travis-ci@npm:2.1.16" + version: 2.1.17 + resolution: "@roadiehq/backstage-plugin-travis-ci@npm:2.1.17" dependencies: "@backstage/catalog-model": ^1.4.3 - "@backstage/core-components": ^0.13.7 - "@backstage/core-plugin-api": ^1.7.0 - "@backstage/plugin-catalog-react": ^1.8.5 - "@backstage/theme": ^0.4.3 + "@backstage/core-components": ^0.13.8 + "@backstage/core-plugin-api": ^1.8.0 + "@backstage/plugin-catalog-react": ^1.9.1 + "@backstage/theme": ^0.4.4 "@material-ui/core": ^4.11.3 "@material-ui/icons": ^4.11.2 "@material-ui/lab": 4.0.0-alpha.57 @@ -15326,7 +15326,7 @@ __metadata: react-dom: ^16.13.1 || ^17.0.0 react-router: 6.0.0-beta.0 || ^6.3.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 - checksum: 175cbae49d6f990cdc0c0d75d27dfe36717f615fea1d4faf350d618bfa4420995c378e3735546ec403ad3c726d18c6ab2bdfc0f72edea26001eb4798e4093305 + checksum: fcf0b788a2f004a6eff181ff9f9babd07aceb630333b1a3e8ce7fb37b6e9a303444ecc9521a920f6aced2c9a081fa3024ee9079d1bb9f453e2d322af04f57113 languageName: node linkType: hard From 5849a8d330458581d60f61e8ae8574c9463c1653 Mon Sep 17 00:00:00 2001 From: Philipp Hugenroth Date: Fri, 1 Dec 2023 14:29:42 +0100 Subject: [PATCH 261/261] Fix diff in yarn.lock on install Signed-off-by: Philipp Hugenroth --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 0d8d076b45..9759cf8787 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3916,7 +3916,7 @@ __metadata: languageName: node linkType: hard -"@backstage/core-components@npm:^0.13.7, @backstage/core-components@npm:^0.13.8": +"@backstage/core-components@npm:^0.13.8": version: 0.13.8 resolution: "@backstage/core-components@npm:0.13.8" dependencies: @@ -4042,7 +4042,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/core-plugin-api@npm:^1.3.0, @backstage/core-plugin-api@npm:^1.5.0, @backstage/core-plugin-api@npm:^1.7.0, @backstage/core-plugin-api@npm:^1.8.0": +"@backstage/core-plugin-api@npm:^1.3.0, @backstage/core-plugin-api@npm:^1.5.0, @backstage/core-plugin-api@npm:^1.8.0": version: 1.8.0 resolution: "@backstage/core-plugin-api@npm:1.8.0" dependencies: @@ -5950,7 +5950,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-catalog-react@npm:^1.2.4, @backstage/plugin-catalog-react@npm:^1.8.5, @backstage/plugin-catalog-react@npm:^1.9.1": +"@backstage/plugin-catalog-react@npm:^1.2.4, @backstage/plugin-catalog-react@npm:^1.9.1": version: 1.9.1 resolution: "@backstage/plugin-catalog-react@npm:1.9.1" dependencies: