From 3731cbf1a081281a92aac58c531623a2350fe748 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl?= <61149845+RaphaelSve@users.noreply.github.com> Date: Wed, 1 May 2024 21:18:46 +0200 Subject: [PATCH 001/416] Create README-fr_FR.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Raphaël <61149845+RaphaelSve@users.noreply.github.com> --- README-fr_FR.md | 76 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 README-fr_FR.md diff --git a/README-fr_FR.md b/README-fr_FR.md new file mode 100644 index 0000000000..316344024e --- /dev/null +++ b/README-fr_FR.md @@ -0,0 +1,76 @@ +[![headline](docs/assets/headline.png)](https://backstage.io/) + +# [Backstage](https://backstage.io) + +Français \| English(README.md) \| [한국어](README-ko_kr.md) \| [中文版](README-zh_Hans.md) + +[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) +[![CNCF Status](https://img.shields.io/badge/cncf%20status-incubation-blue.svg)](https://www.cncf.io/projects) +[![Discord](https://img.shields.io/discord/687207715902193673?logo=discord&label=Discord&color=5865F2&logoColor=white)](https://discord.gg/backstage-687207715902193673) +![Code style](https://img.shields.io/badge/code_style-prettier-ff69b4.svg) +[![Codecov](https://img.shields.io/codecov/c/github/backstage/backstage)](https://codecov.io/gh/backstage/backstage) +[![](https://img.shields.io/github/v/release/backstage/backstage)](https://github.com/backstage/backstage/releases) +[![Uffizzi](https://img.shields.io/endpoint?url=https%3A%2F%2Fapp.uffizzi.com%2Fapi%2Fv1%2Fpublic%2Fshields%2Fgithub.com%2Fbackstage%2Fbackstage)](https://app.uffizzi.com/ephemeral-environments/backstage/backstage) +[![OpenSSF Best Practices](https://bestpractices.coreinfrastructure.org/projects/7678/badge)](https://bestpractices.coreinfrastructure.org/projects/7678) +[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/backstage/backstage/badge)](https://securityscorecards.dev/viewer/?uri=github.com/backstage/backstage) + +## Qu'est-ce que Backstage? + +[Backstage](https://backstage.io/) est un framework open source conçu pour créer des portails à destination des développeur. Avec l'idée de fournir un catalogue d'applications centralisé, Backstage remet de l'ordre dans vos microservices et votre infrastructure, ce qui permet à vos équipes produit de coder rapidement et de manière efficace sans perdre en autonomie. + +Backstage rassemble tous vos outils d'infrastructure, services et documentation pour créer un environnement de développement fluide de bout en bout. + +![software-catalog](docs/assets/header.png) + +Out-of-the-box, Backstage comprend : + +- [Backstage Software Catalog](https://backstage.io/docs/features/software-catalog/) pour gérer tous vos logiciels tels que les microservices, les bibliothèques, les pipelines de données, les sites web et les modèles ML. +- [Backstage Software Templates](https://backstage.io/docs/features/software-templates/) pour créer rapidement de nouveaux projets et uniformiser vos outils selon les meilleures pratiques de votre organisation. +- [Backstage TechDocs](https://backstage.io/docs/features/techdocs/) pour faciliter la création, la maintenance, la recherche et l'utilisation de la documentation technique, en adoptant une approche "docs like code". +- De plus, un écosystème croissant de [plugins open source](https://github.com/backstage/backstage/tree/master/plugins) qui étendent davantage la personnalisation et les fonctionnalités de Backstage. + +Backstage a été initialement développé par Spotify, mais il est désormais hébergé par la [Cloud Native Computing Foundation (CNCF)](https://www.cncf.io) en tant que projet en stade d'incubation. Pour en savoir plus, consultez l'[annonce](https://backstage.io/blog/2022/03/16/backstage-turns-two#out-of-the-sandbox-and-into-incubation). + +## Roadmap du projet + +Pour des informations sur la roadmap détaillée du projet, y compris les jalons atteints, consultez [la Roadmap](https://backstage.io/docs/overview/roadmap). + +## Démarrage + +Pour commencer à utiliser Backstage, consultez [Getting Started documentation](https://backstage.io/docs/getting-started). + +## Documentation + +La documentation de Backstage inclus: + +- [Main documentation](https://backstage.io/docs) +- [Software Catalog](https://backstage.io/docs/features/software-catalog/) +- [Architecture](https://backstage.io/docs/overview/architecture-overview) ([Decisions](https://backstage.io/docs/architecture-decisions/)) +- [Designing for Backstage](https://backstage.io/docs/dls/design) +- [Storybook - UI components](https://backstage.io/storybook) + +## Communauté + +Si vous voulez contribuer et vous impliquer dans notre communauté, voici les ressources à votre disposition : + +- [Discord chatroom](https://discord.gg/backstage-687207715902193673) - Pour obtenir de l'aide ou discuter du projet +- [Contributing to Backstage](https://github.com/backstage/backstage/blob/master/CONTRIBUTING.md) - Rendez-vous ici si vous souhaitez contribuer +- [RFCs](https://github.com/backstage/backstage/labels/rfc) - Contribuez à définir la direction technique +- [FAQ](https://backstage.io/docs/FAQ) - FAQ +- [Code of Conduct](CODE_OF_CONDUCT.md) - C'est comme ça qu'on fonctionne +- [Adopters](ADOPTERS.md) - Les entreprises utilisent déjà Backstage +- [Blog](https://backstage.io/blog/) - Annonces et mises à jour +- [Newsletter](https://spoti.fi/backstagenewsletter) - Abonnez-vous à notre newsletter par e-mail +- [Backstage Community Sessions](https://github.com/backstage/community) - Participez aux rencontres mensuelles et découvrez la communauté Backstage +- Donnez-nous une étoile ⭐️ - Si vous utilisez Backstage ou si vous trouvez que c'est un projet intéressant, nous apprécierions beaucoup votre soutien. ❤️ + +## Licence + +Copyright 2020-2024 © Les auteurs de Backstage. Tous droits réservés. La Linux Foundation détient des marques déposées et utilise des marques commerciales. Pour une liste des marques de commerce de la Linux Foundation, veuillez consulter notre page d'utilisation des marques : +Sous licence Apache, version 2.0 : http://www.apache.org/licenses/LICENSE-2.0 + +## Sécurité + +Veuillez signaler les problèmes de sécurité sensibles en utilisant le [programme de bug-bounty](https://hackerone.com/spotify) de Spotify plutôt que GitHub. + +Pour plus de détails, consultez notre processus complet de [publication de sécurité](SECURITY.md). From cd3cb0d1d28f2c3bb3a00bd42f271dda88c0ee08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl?= <61149845+RaphaelSve@users.noreply.github.com> Date: Wed, 1 May 2024 21:22:21 +0200 Subject: [PATCH 002/416] Add French to language choices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Raphaël <61149845+RaphaelSve@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6cea4235e0..2c4defc971 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ # [Backstage](https://backstage.io) -English \| [한국어](README-ko_kr.md) \| [中文版](README-zh_Hans.md) +English \| [한국어](README-ko_kr.md) \| [中文版](README-zh_Hans.md) \| [Français](README-fr_FR.md) [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![CNCF Status](https://img.shields.io/badge/cncf%20status-incubation-blue.svg)](https://www.cncf.io/projects) From 13098239c84286a8b7a1ca917878a9725738820d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl?= <61149845+RaphaelSve@users.noreply.github.com> Date: Wed, 1 May 2024 21:24:24 +0200 Subject: [PATCH 003/416] Update README-fr_FR.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Raphaël <61149845+RaphaelSve@users.noreply.github.com> --- README-fr_FR.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README-fr_FR.md b/README-fr_FR.md index 316344024e..c923b467e9 100644 --- a/README-fr_FR.md +++ b/README-fr_FR.md @@ -56,13 +56,13 @@ Si vous voulez contribuer et vous impliquer dans notre communauté, voici les re - [Discord chatroom](https://discord.gg/backstage-687207715902193673) - Pour obtenir de l'aide ou discuter du projet - [Contributing to Backstage](https://github.com/backstage/backstage/blob/master/CONTRIBUTING.md) - Rendez-vous ici si vous souhaitez contribuer - [RFCs](https://github.com/backstage/backstage/labels/rfc) - Contribuez à définir la direction technique -- [FAQ](https://backstage.io/docs/FAQ) - FAQ +- [FAQ](https://backstage.io/docs/FAQ) - [Code of Conduct](CODE_OF_CONDUCT.md) - C'est comme ça qu'on fonctionne - [Adopters](ADOPTERS.md) - Les entreprises utilisent déjà Backstage - [Blog](https://backstage.io/blog/) - Annonces et mises à jour - [Newsletter](https://spoti.fi/backstagenewsletter) - Abonnez-vous à notre newsletter par e-mail - [Backstage Community Sessions](https://github.com/backstage/community) - Participez aux rencontres mensuelles et découvrez la communauté Backstage -- Donnez-nous une étoile ⭐️ - Si vous utilisez Backstage ou si vous trouvez que c'est un projet intéressant, nous apprécierions beaucoup votre soutien. ❤️ +- Donnez-nous une étoile ⭐️ - Si vous utilisez Backstage ou si vous trouvez que c'est un projet intéressant, nous apprécierions beaucoup votre soutien ❤️ ## Licence From d64aa610152bf1563f2f739eb2c569669cf4279b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl?= <61149845+RaphaelSve@users.noreply.github.com> Date: Wed, 1 May 2024 21:24:51 +0200 Subject: [PATCH 004/416] Update README-fr_FR.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Raphaël <61149845+RaphaelSve@users.noreply.github.com> --- README-fr_FR.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README-fr_FR.md b/README-fr_FR.md index c923b467e9..8e756b417c 100644 --- a/README-fr_FR.md +++ b/README-fr_FR.md @@ -2,7 +2,7 @@ # [Backstage](https://backstage.io) -Français \| English(README.md) \| [한국어](README-ko_kr.md) \| [中文版](README-zh_Hans.md) +Français \| [English](README.md) \| [한국어](README-ko_kr.md) \| [中文版](README-zh_Hans.md) [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![CNCF Status](https://img.shields.io/badge/cncf%20status-incubation-blue.svg)](https://www.cncf.io/projects) From 9d486f61bd05980f7369206bc6e2d9960b2a500f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl?= <61149845+RaphaelSve@users.noreply.github.com> Date: Wed, 1 May 2024 21:31:32 +0200 Subject: [PATCH 005/416] Update README-fr_FR.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Raphaël <61149845+RaphaelSve@users.noreply.github.com> --- README-fr_FR.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README-fr_FR.md b/README-fr_FR.md index 8e756b417c..2eb06393c6 100644 --- a/README-fr_FR.md +++ b/README-fr_FR.md @@ -60,14 +60,15 @@ Si vous voulez contribuer et vous impliquer dans notre communauté, voici les re - [Code of Conduct](CODE_OF_CONDUCT.md) - C'est comme ça qu'on fonctionne - [Adopters](ADOPTERS.md) - Les entreprises utilisent déjà Backstage - [Blog](https://backstage.io/blog/) - Annonces et mises à jour -- [Newsletter](https://spoti.fi/backstagenewsletter) - Abonnez-vous à notre newsletter par e-mail +- [Newsletter](https://spoti.fi/backstagenewsletter) - Abonnez-vous à notre newsletter par mail - [Backstage Community Sessions](https://github.com/backstage/community) - Participez aux rencontres mensuelles et découvrez la communauté Backstage - Donnez-nous une étoile ⭐️ - Si vous utilisez Backstage ou si vous trouvez que c'est un projet intéressant, nous apprécierions beaucoup votre soutien ❤️ ## Licence -Copyright 2020-2024 © Les auteurs de Backstage. Tous droits réservés. La Linux Foundation détient des marques déposées et utilise des marques commerciales. Pour une liste des marques de commerce de la Linux Foundation, veuillez consulter notre page d'utilisation des marques : -Sous licence Apache, version 2.0 : http://www.apache.org/licenses/LICENSE-2.0 +Copyright 2020-2024 © Les auteurs de Backstage. Tous droits réservés. La Linux Foundation détient des marques déposées et utilise des marques commerciales. Pour une liste des marques de commerce de la Linux Foundation, veuillez consulter notre page d'utilisation des marques: https://www.linuxfoundation.org/trademark-usage + +Sous licence Apache, version 2.0: http://www.apache.org/licenses/LICENSE-2.0 ## Sécurité From 743c07f19c61e36a98ce9713207b8c72439e3582 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl?= <61149845+RaphaelSve@users.noreply.github.com> Date: Thu, 9 May 2024 09:40:10 +0200 Subject: [PATCH 006/416] Update README-fr_FR.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Thomas Cardonne Signed-off-by: Raphaël <61149845+RaphaelSve@users.noreply.github.com> --- README-fr_FR.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README-fr_FR.md b/README-fr_FR.md index 2eb06393c6..3363c21ef0 100644 --- a/README-fr_FR.md +++ b/README-fr_FR.md @@ -16,7 +16,7 @@ Français \| [English](README.md) \| [한국어](README-ko_kr.md) \| [中文版] ## Qu'est-ce que Backstage? -[Backstage](https://backstage.io/) est un framework open source conçu pour créer des portails à destination des développeur. Avec l'idée de fournir un catalogue d'applications centralisé, Backstage remet de l'ordre dans vos microservices et votre infrastructure, ce qui permet à vos équipes produit de coder rapidement et de manière efficace sans perdre en autonomie. +[Backstage](https://backstage.io/) est un framework open source conçu pour créer des portails à destination des développeurs. Avec l'idée de fournir un catalogue d'applications centralisé, Backstage remet de l'ordre dans vos microservices et votre infrastructure, ce qui permet à vos équipes produit de coder rapidement et de manière efficace sans perdre en autonomie. Backstage rassemble tous vos outils d'infrastructure, services et documentation pour créer un environnement de développement fluide de bout en bout. From bb96ccf110db93aa4182e85f6db459b5e6a95c6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl?= <61149845+RaphaelSve@users.noreply.github.com> Date: Thu, 9 May 2024 09:40:47 +0200 Subject: [PATCH 007/416] Update README-fr_FR.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Thomas Cardonne Signed-off-by: Raphaël <61149845+RaphaelSve@users.noreply.github.com> --- README-fr_FR.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README-fr_FR.md b/README-fr_FR.md index 3363c21ef0..e91f30d991 100644 --- a/README-fr_FR.md +++ b/README-fr_FR.md @@ -18,7 +18,7 @@ Français \| [English](README.md) \| [한국어](README-ko_kr.md) \| [中文版] [Backstage](https://backstage.io/) est un framework open source conçu pour créer des portails à destination des développeurs. Avec l'idée de fournir un catalogue d'applications centralisé, Backstage remet de l'ordre dans vos microservices et votre infrastructure, ce qui permet à vos équipes produit de coder rapidement et de manière efficace sans perdre en autonomie. -Backstage rassemble tous vos outils d'infrastructure, services et documentation pour créer un environnement de développement fluide de bout en bout. +Backstage rassemble tous vos outils d'infrastructure, services et documentations pour créer un environnement de développement fluide de bout en bout. ![software-catalog](docs/assets/header.png) From 9b4852c27a691967044eb4200fa893fae023143c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl?= <61149845+RaphaelSve@users.noreply.github.com> Date: Thu, 9 May 2024 09:41:10 +0200 Subject: [PATCH 008/416] Update README-fr_FR.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Thomas Cardonne Signed-off-by: Raphaël <61149845+RaphaelSve@users.noreply.github.com> --- README-fr_FR.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README-fr_FR.md b/README-fr_FR.md index e91f30d991..e0cffaa5c5 100644 --- a/README-fr_FR.md +++ b/README-fr_FR.md @@ -58,7 +58,7 @@ Si vous voulez contribuer et vous impliquer dans notre communauté, voici les re - [RFCs](https://github.com/backstage/backstage/labels/rfc) - Contribuez à définir la direction technique - [FAQ](https://backstage.io/docs/FAQ) - [Code of Conduct](CODE_OF_CONDUCT.md) - C'est comme ça qu'on fonctionne -- [Adopters](ADOPTERS.md) - Les entreprises utilisent déjà Backstage +- [Adopters](ADOPTERS.md) - Les entreprises utilisant déjà Backstage - [Blog](https://backstage.io/blog/) - Annonces et mises à jour - [Newsletter](https://spoti.fi/backstagenewsletter) - Abonnez-vous à notre newsletter par mail - [Backstage Community Sessions](https://github.com/backstage/community) - Participez aux rencontres mensuelles et découvrez la communauté Backstage From fe47a3e15ea2af602b8bef6a6f5ba3db43071f74 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Tue, 28 May 2024 16:29:51 +0200 Subject: [PATCH 009/416] refactor: rename service config to options Signed-off-by: Camila Belo --- .changeset/tall-walls-learn.md | 9 +++ packages/backend-plugin-api/api-report.md | 47 +++++++++++--- packages/backend-plugin-api/src/deprecated.ts | 52 ++++++++++++++++ packages/backend-plugin-api/src/index.ts | 1 + .../src/services/system/index.ts | 6 +- .../src/services/system/types.ts | 62 ++++++++++--------- 6 files changed, 135 insertions(+), 42 deletions(-) create mode 100644 .changeset/tall-walls-learn.md create mode 100644 packages/backend-plugin-api/src/deprecated.ts diff --git a/.changeset/tall-walls-learn.md b/.changeset/tall-walls-learn.md new file mode 100644 index 0000000000..d79c439221 --- /dev/null +++ b/.changeset/tall-walls-learn.md @@ -0,0 +1,9 @@ +--- +'@backstage/backend-plugin-api': patch +--- + +All service config types were renamed to option types in order to standardize frontend and backend `create*` function signatures: + +- The `ServiceRefConfig` type was renamed to`ServiceRefOptions`; +- The `RootServiceFactoryConfig` type was renamed to `RootServiceFactoryOptions`; +- The `PluginServiceFactoryConfig` type was renamed to `PluginServiceFactoryOptions` diff --git a/packages/backend-plugin-api/api-report.md b/packages/backend-plugin-api/api-report.md index 5e59378760..e157187d26 100644 --- a/packages/backend-plugin-api/api-report.md +++ b/packages/backend-plugin-api/api-report.md @@ -256,7 +256,7 @@ export function createServiceFactory< }, TOpts extends object | undefined = undefined, >( - config: RootServiceFactoryConfig, + options: RootServiceFactoryOptions, ): () => ServiceFactory; // @public @@ -268,7 +268,9 @@ export function createServiceFactory< }, TOpts extends object | undefined = undefined, >( - config: (options?: TOpts) => RootServiceFactoryConfig, + options: ( + options?: TOpts, + ) => RootServiceFactoryOptions, ): (options?: TOpts) => ServiceFactory; // @public @@ -281,7 +283,7 @@ export function createServiceFactory< TContext = undefined, TOpts extends object | undefined = undefined, >( - config: PluginServiceFactoryConfig, + options: PluginServiceFactoryOptions, ): () => ServiceFactory; // @public @@ -294,19 +296,19 @@ export function createServiceFactory< TContext = undefined, TOpts extends object | undefined = undefined, >( - config: ( + options: ( options?: TOpts, - ) => PluginServiceFactoryConfig, + ) => PluginServiceFactoryOptions, ): (options?: TOpts) => ServiceFactory; // @public export function createServiceRef( - config: ServiceRefConfig, + options: ServiceRefOptions, ): ServiceRef; // @public export function createServiceRef( - config: ServiceRefConfig, + options: ServiceRefOptions, ): ServiceRef; // @public @@ -450,8 +452,18 @@ export interface PluginMetadataService { getId(): string; } +// @public @deprecated (undocumented) +export type PluginServiceFactoryConfig< + TService, + TContext, + TImpl extends TService, + TDeps extends { + [name in string]: ServiceRef; + }, +> = PluginServiceFactoryOptions; + // @public (undocumented) -export interface PluginServiceFactoryConfig< +export interface PluginServiceFactoryOptions< TService, TContext, TImpl extends TService, @@ -549,8 +561,17 @@ export interface RootLifecycleService extends LifecycleService {} // @public (undocumented) export interface RootLoggerService extends LoggerService {} +// @public @deprecated (undocumented) +export type RootServiceFactoryConfig< + TService, + TImpl extends TService, + TDeps extends { + [name in string]: ServiceRef; + }, +> = RootServiceFactoryOptions; + // @public (undocumented) -export interface RootServiceFactoryConfig< +export interface RootServiceFactoryOptions< TService, TImpl extends TService, TDeps extends { @@ -674,8 +695,14 @@ export type ServiceRef< $$type: '@backstage/ServiceRef'; }; +// @public @deprecated (undocumented) +export type ServiceRefConfig< + TService, + TScope extends 'root' | 'plugin', +> = ServiceRefOptions; + // @public (undocumented) -export interface ServiceRefConfig { +export interface ServiceRefOptions { // (undocumented) defaultFactory?: ( service: ServiceRef, diff --git a/packages/backend-plugin-api/src/deprecated.ts b/packages/backend-plugin-api/src/deprecated.ts new file mode 100644 index 0000000000..17ccccf320 --- /dev/null +++ b/packages/backend-plugin-api/src/deprecated.ts @@ -0,0 +1,52 @@ +/* + * Copyright 2024 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 { + ServiceRef, + ServiceRefOptions, + RootServiceFactoryOptions, + PluginServiceFactoryOptions, +} from './services'; + +/** + * @public + * @deprecated Use {@link ServiceRefOptions} instead + */ +export type ServiceRefConfig< + TService, + TScope extends 'root' | 'plugin', +> = ServiceRefOptions; + +/** + * @public + * @deprecated Use {@link RootServiceFactoryOptions} instead + */ +export type RootServiceFactoryConfig< + TService, + TImpl extends TService, + TDeps extends { [name in string]: ServiceRef }, +> = RootServiceFactoryOptions; + +/** + * @public + * @deprecated Use {@link PluginServiceFactoryOptions} instead + */ +export type PluginServiceFactoryConfig< + TService, + TContext, + TImpl extends TService, + TDeps extends { [name in string]: ServiceRef }, +> = PluginServiceFactoryOptions; diff --git a/packages/backend-plugin-api/src/index.ts b/packages/backend-plugin-api/src/index.ts index c2e2a13a89..342b33dd2e 100644 --- a/packages/backend-plugin-api/src/index.ts +++ b/packages/backend-plugin-api/src/index.ts @@ -24,3 +24,4 @@ export * from './services'; export type { BackendFeature } from './types'; export * from './paths'; export * from './wiring'; +export * from './deprecated'; diff --git a/packages/backend-plugin-api/src/services/system/index.ts b/packages/backend-plugin-api/src/services/system/index.ts index 2b91758cbc..9f62968ecd 100644 --- a/packages/backend-plugin-api/src/services/system/index.ts +++ b/packages/backend-plugin-api/src/services/system/index.ts @@ -16,10 +16,10 @@ export type { ServiceRef, - ServiceRefConfig, + ServiceRefOptions, ServiceFactory, - PluginServiceFactoryConfig, - RootServiceFactoryConfig, + PluginServiceFactoryOptions, + RootServiceFactoryOptions, ServiceFactoryOrFunction, } from './types'; export { createServiceRef, createServiceFactory } from './types'; diff --git a/packages/backend-plugin-api/src/services/system/types.ts b/packages/backend-plugin-api/src/services/system/types.ts index 13252ba6e4..2d6951ffea 100644 --- a/packages/backend-plugin-api/src/services/system/types.ts +++ b/packages/backend-plugin-api/src/services/system/types.ts @@ -78,7 +78,7 @@ export interface InternalServiceFactory< export type ServiceFactoryOrFunction = ServiceFactory | (() => ServiceFactory); /** @public */ -export interface ServiceRefConfig { +export interface ServiceRefOptions { id: string; scope?: TScope; defaultFactory?: ( @@ -92,7 +92,7 @@ export interface ServiceRefConfig { * @public */ export function createServiceRef( - config: ServiceRefConfig, + options: ServiceRefOptions, ): ServiceRef; /** @@ -101,12 +101,13 @@ export function createServiceRef( * @public */ export function createServiceRef( - config: ServiceRefConfig, + options: ServiceRefOptions, ): ServiceRef; + export function createServiceRef( - config: ServiceRefConfig, + options: ServiceRefOptions, ): ServiceRef { - const { id, scope = 'plugin', defaultFactory } = config; + const { id, scope = 'plugin', defaultFactory } = options; return { id, scope, @@ -114,7 +115,7 @@ export function createServiceRef( throw new Error(`tried to read ServiceRef.T of ${this}`); }, toString() { - return `serviceRef{${config.id}}`; + return `serviceRef{${options.id}}`; }, $$type: '@backstage/ServiceRef', __defaultFactory: defaultFactory, @@ -134,7 +135,7 @@ type ServiceRefsToInstances< }; /** @public */ -export interface RootServiceFactoryConfig< +export interface RootServiceFactoryOptions< TService, TImpl extends TService, TDeps extends { [name in string]: ServiceRef }, @@ -156,7 +157,7 @@ export interface RootServiceFactoryConfig< } /** @public */ -export interface PluginServiceFactoryConfig< +export interface PluginServiceFactoryOptions< TService, TContext, TImpl extends TService, @@ -188,7 +189,7 @@ export interface PluginServiceFactoryConfig< * Creates a root scoped service factory without options. * * @public - * @param config - The service factory configuration. + * @param options - The service factory configuration. */ export function createServiceFactory< TService, @@ -196,13 +197,13 @@ export function createServiceFactory< TDeps extends { [name in string]: ServiceRef }, TOpts extends object | undefined = undefined, >( - config: RootServiceFactoryConfig, + options: RootServiceFactoryOptions, ): () => ServiceFactory; /** * Creates a root scoped service factory with optional options. * * @public - * @param config - The service factory configuration. + * @param options - The service factory configuration. */ export function createServiceFactory< TService, @@ -210,13 +211,15 @@ export function createServiceFactory< TDeps extends { [name in string]: ServiceRef }, TOpts extends object | undefined = undefined, >( - config: (options?: TOpts) => RootServiceFactoryConfig, + options: ( + options?: TOpts, + ) => RootServiceFactoryOptions, ): (options?: TOpts) => ServiceFactory; /** * Creates a plugin scoped service factory without options. * * @public - * @param config - The service factory configuration. + * @param options - The service factory configuration. */ export function createServiceFactory< TService, @@ -225,13 +228,13 @@ export function createServiceFactory< TContext = undefined, TOpts extends object | undefined = undefined, >( - config: PluginServiceFactoryConfig, + options: PluginServiceFactoryOptions, ): () => ServiceFactory; /** * Creates a plugin scoped service factory with optional options. * * @public - * @param config - The service factory configuration. + * @param options - The service factory configuration. */ export function createServiceFactory< TService, @@ -240,9 +243,9 @@ export function createServiceFactory< TContext = undefined, TOpts extends object | undefined = undefined, >( - config: ( + options: ( options?: TOpts, - ) => PluginServiceFactoryConfig, + ) => PluginServiceFactoryOptions, ): (options?: TOpts) => ServiceFactory; export function createServiceFactory< TService, @@ -251,23 +254,24 @@ export function createServiceFactory< TContext, TOpts extends object | undefined = undefined, >( - config: - | RootServiceFactoryConfig - | PluginServiceFactoryConfig - | ((options: TOpts) => RootServiceFactoryConfig) + options: + | RootServiceFactoryOptions + | PluginServiceFactoryOptions + | ((options: TOpts) => RootServiceFactoryOptions) | (( options: TOpts, - ) => PluginServiceFactoryConfig) - | (() => RootServiceFactoryConfig) - | (() => PluginServiceFactoryConfig), + ) => PluginServiceFactoryOptions) + | (() => RootServiceFactoryOptions) + | (() => PluginServiceFactoryOptions), ): (options: TOpts) => ServiceFactory { - const configCallback = typeof config === 'function' ? config : () => config; + const configCallback = + typeof options === 'function' ? options : () => options; const factory = ( - options: TOpts, + o: TOpts, ): InternalServiceFactory => { - const anyConf = configCallback(options); + const anyConf = configCallback(o); if (anyConf.service.scope === 'root') { - const c = anyConf as RootServiceFactoryConfig; + const c = anyConf as RootServiceFactoryOptions; return { $$type: '@backstage/BackendFeature', version: 'v1', @@ -277,7 +281,7 @@ export function createServiceFactory< factory: async (deps: TDeps) => c.factory(deps), }; } - const c = anyConf as PluginServiceFactoryConfig< + const c = anyConf as PluginServiceFactoryOptions< TService, TContext, TImpl, From 90a7340efd87f1174018093dc671f07bff02e733 Mon Sep 17 00:00:00 2001 From: Ooi Yee Fei Date: Sat, 1 Jun 2024 15:09:02 +0800 Subject: [PATCH 010/416] fix: Prefer accountId for AwsOrganizationCloudAccountProcessor authentication Signed-off-by: Ooi Yee Fei --- .changeset/swift-kings-sparkle.md | 5 +++ .../catalog-backend-module-aws/config.d.ts | 6 +++ .../src/awsOrganization/config.test.ts | 2 + .../src/awsOrganization/config.ts | 7 +++ .../AwsOrganizationCloudAccountProcessor.ts | 44 ++++++++++++------- 5 files changed, 48 insertions(+), 16 deletions(-) create mode 100644 .changeset/swift-kings-sparkle.md diff --git a/.changeset/swift-kings-sparkle.md b/.changeset/swift-kings-sparkle.md new file mode 100644 index 0000000000..18a37b82f1 --- /dev/null +++ b/.changeset/swift-kings-sparkle.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend-module-aws': patch +--- + +AwsOrganizationCloudAccountProcessor configuration field roleArn is deprecated in favor of new field accountId diff --git a/plugins/catalog-backend-module-aws/config.d.ts b/plugins/catalog-backend-module-aws/config.d.ts index 4c9c98512e..0a9d9c97db 100644 --- a/plugins/catalog-backend-module-aws/config.d.ts +++ b/plugins/catalog-backend-module-aws/config.d.ts @@ -26,8 +26,14 @@ export interface Config { provider: { /** * The role to be assumed by this processor + * @deprecated Use `accountId` instead. */ roleArn?: string; + + /** + * The AWS account ID to query for organizational data + */ + accountId?: string; }; }; }; diff --git a/plugins/catalog-backend-module-aws/src/awsOrganization/config.test.ts b/plugins/catalog-backend-module-aws/src/awsOrganization/config.test.ts index 7e0dc58559..a84c65abda 100644 --- a/plugins/catalog-backend-module-aws/src/awsOrganization/config.test.ts +++ b/plugins/catalog-backend-module-aws/src/awsOrganization/config.test.ts @@ -22,11 +22,13 @@ describe('readAwsOrganizationConfig', () => { const config = { provider: { roleArn: 'aws::arn::foo', + accountId: '111111111111', }, }; const actual = readAwsOrganizationConfig(new ConfigReader(config)); const expected = { roleArn: 'aws::arn::foo', + accountId: '111111111111', }; expect(actual).toEqual(expected); }); diff --git a/plugins/catalog-backend-module-aws/src/awsOrganization/config.ts b/plugins/catalog-backend-module-aws/src/awsOrganization/config.ts index e6096b932b..ff00af48e4 100644 --- a/plugins/catalog-backend-module-aws/src/awsOrganization/config.ts +++ b/plugins/catalog-backend-module-aws/src/awsOrganization/config.ts @@ -24,6 +24,11 @@ export type AwsOrganizationProviderConfig = { * The role to assume for the processor. */ roleArn?: string; + + /** + * The AWS accountId + */ + accountId?: string; }; export function readAwsOrganizationConfig( @@ -32,7 +37,9 @@ export function readAwsOrganizationConfig( const providerConfig = config.getOptionalConfig('provider'); const roleArn = providerConfig?.getOptionalString('roleArn'); + const accountId = providerConfig?.getOptionalString('accountId'); return { roleArn, + accountId, }; } diff --git a/plugins/catalog-backend-module-aws/src/processors/AwsOrganizationCloudAccountProcessor.ts b/plugins/catalog-backend-module-aws/src/processors/AwsOrganizationCloudAccountProcessor.ts index 4a454fce6f..b843503a28 100644 --- a/plugins/catalog-backend-module-aws/src/processors/AwsOrganizationCloudAccountProcessor.ts +++ b/plugins/catalog-backend-module-aws/src/processors/AwsOrganizationCloudAccountProcessor.ts @@ -59,10 +59,18 @@ export class AwsOrganizationCloudAccountProcessor implements CatalogProcessor { static async fromConfig(config: Config, options: { logger: LoggerService }) { const c = config.getOptionalConfig('catalog.processors.awsOrganization'); const orgConfig = c ? readAwsOrganizationConfig(c) : undefined; + + if (orgConfig?.roleArn) { + options.logger.warn( + 'The roleArn configuration for AwsOrganizationCloudAccountProcessor ignores the role name, use accountId configuration instead', + ); + } + const awsCredentialsManager = DefaultAwsCredentialsManager.fromConfig(config); const credProvider = await awsCredentialsManager.getCredentialProvider({ arn: orgConfig?.roleArn, + accountId: orgConfig?.accountId, }); return new AwsOrganizationCloudAccountProcessor( credProvider, @@ -98,23 +106,27 @@ export class AwsOrganizationCloudAccountProcessor implements CatalogProcessor { this.logger?.info('Discovering AWS Organization Account objects'); - (await this.getAwsAccounts()) - .map(account => this.mapAccountToComponent(account)) - .filter(entity => { - if (location.target !== '') { - if (entity.metadata.annotations) { - return ( - entity.metadata.annotations[ORGANIZATION_ANNOTATION] === - location.target - ); + try { + (await this.getAwsAccounts()) + .map(account => this.mapAccountToComponent(account)) + .filter(entity => { + if (location.target !== '') { + if (entity.metadata.annotations) { + return ( + entity.metadata.annotations[ORGANIZATION_ANNOTATION] === + location.target + ); + } + return false; } - return false; - } - return true; - }) - .forEach(entity => { - emit(processingResult.entity(location, entity)); - }); + return true; + }) + .forEach(entity => { + emit(processingResult.entity(location, entity)); + }); + } catch (e) { + this.logger?.error(e); + } return true; } From 3ddd51dc36c3189d8561588613bd176dc3c1f1b6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 3 Jun 2024 15:38:15 +0000 Subject: [PATCH 011/416] fix(deps): update dependency @pmmmwh/react-refresh-webpack-plugin to v0.5.15 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/yarn.lock b/yarn.lock index 72587183c5..3cdf50a03c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13331,15 +13331,15 @@ __metadata: linkType: hard "@pmmmwh/react-refresh-webpack-plugin@npm:^0.5.7": - version: 0.5.13 - resolution: "@pmmmwh/react-refresh-webpack-plugin@npm:0.5.13" + version: 0.5.15 + resolution: "@pmmmwh/react-refresh-webpack-plugin@npm:0.5.15" dependencies: - ansi-html-community: ^0.0.8 + ansi-html: ^0.0.9 core-js-pure: ^3.23.3 error-stack-parser: ^2.0.6 html-entities: ^2.1.0 loader-utils: ^2.0.4 - schema-utils: ^3.0.0 + schema-utils: ^4.2.0 source-map: ^0.7.3 peerDependencies: "@types/webpack": 4.x || 5.x @@ -13363,7 +13363,7 @@ __metadata: optional: true webpack-plugin-serve: optional: true - checksum: 9f931cf79945f58ee31569b83f4b294ae0849ea8232b6c79e690b46a3d7f2b981aa72718a4bd7517ab82657dddfed2a691c9d9e37295a87dfd0b18b2693d4aa6 + checksum: 82df6244146209d63a12f0ca2e70b05274ee058c7e6d6eb4ced1228afde3b039a7f3f3cc0c76f1bb4b28deadbcf08bc2821c814f0bfee06979128578300fff3d languageName: node linkType: hard @@ -19681,6 +19681,15 @@ __metadata: languageName: node linkType: hard +"ansi-html@npm:^0.0.9": + version: 0.0.9 + resolution: "ansi-html@npm:0.0.9" + bin: + ansi-html: bin/ansi-html + checksum: a03754d6f66bae33938ed8bb3dd98174b7f4895ebe45226185036ed4a1388a7aaf2f2b9581608f0626432ba7add92cfc590aa6475a78bbb90d9d1e1d1af8cbe6 + languageName: node + linkType: hard + "ansi-regex@npm:*, ansi-regex@npm:^6.0.1": version: 6.0.1 resolution: "ansi-regex@npm:6.0.1" @@ -39180,7 +39189,7 @@ __metadata: languageName: node linkType: hard -"schema-utils@npm:^3.0.0, schema-utils@npm:^3.1.1, schema-utils@npm:^3.2.0": +"schema-utils@npm:^3.1.1, schema-utils@npm:^3.2.0": version: 3.3.0 resolution: "schema-utils@npm:3.3.0" dependencies: From f7bdceae07bf08f9ac80e8285063bb10db0e81bd Mon Sep 17 00:00:00 2001 From: Adam Wallis Date: Wed, 29 May 2024 16:59:04 -0400 Subject: [PATCH 012/416] Adds ProviderTransformer to msgraph catalog plugin for dynamic config Signed-off-by: Adam Wallis --- .changeset/clever-geese-jump.md | 5 +++ docs/integrations/azure/org.md | 34 ++++++++++++++++++- .../api-report-alpha.md | 6 ++++ .../api-report.md | 10 ++++++ .../src/microsoftGraph/index.ts | 1 + .../src/microsoftGraph/types.ts | 14 +++++++- ...ogModuleMicrosoftGraphOrgEntityProvider.ts | 24 +++++++++++++ .../MicrosoftGraphOrgEntityProvider.ts | 23 ++++++++++++- 8 files changed, 114 insertions(+), 3 deletions(-) create mode 100644 .changeset/clever-geese-jump.md diff --git a/.changeset/clever-geese-jump.md b/.changeset/clever-geese-jump.md new file mode 100644 index 0000000000..1c4694fa33 --- /dev/null +++ b/.changeset/clever-geese-jump.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend-module-msgraph': patch +--- + +Adds a dynamic provider for the plugin-catalog-backend-module-msgraph. Configuration is now runtime configurable through the ProviderConfigTransformer. diff --git a/docs/integrations/azure/org.md b/docs/integrations/azure/org.md index 89abd4813b..6a72527b94 100644 --- a/docs/integrations/azure/org.md +++ b/docs/integrations/azure/org.md @@ -169,6 +169,23 @@ microsoftGraphOrg: select: ['id', 'displayName', 'description'] ``` +### Using Provider Config Transformer + +Dynamic configuration scaling allows the `msgraph` catalog plugin to adjust its settings at runtime without requiring a redeploy. This feature is useful for scenarios where configuration needs to be updated based on real-time events or changing conditions. For example, you can dynamically adjust synchronization schedules, filters, and search parameters to optimize performance and responsiveness. + +:::note +Adjusting fields that are not used on each scheduled ingestion (e.g., `id`, `schedule`) will have no effect. +::: + +:::warning +Dynamically changing configuration on the fly can introduce unintended consequences, such as system instability and configuration errors. Please review your transformer carefully to ensure that it is working as anticipated! +::: + +#### Example Use Cases: + +- **Filter Scaling**: Adjust filters like `userGroupMember` and `groupFilter` dynamically. +- **Search Parameter Adjustment**: Change search parameters such as `groupSearch` and `userSelect` on-the-fly. + ### Using Custom Transformers Transformers can be configured by extending `microsoftGraphOrgEntityProviderTransformExtensionPoint`. Here is an example: @@ -180,6 +197,7 @@ import { myUserTransformer, myGroupTransformer, myOrganizationTransformer, + myProviderConfigTransformer, } from './transformers'; backend.add( @@ -201,6 +219,9 @@ backend.add( microsoftGraphTransformers.setOrganizationTransformer( myOrganizationTransformer, ); + microsoftGraphTransformers.setProviderConfigTransformer( + myProviderConfigTransformer, + ); /* highlight-add-end */ }, }); @@ -209,7 +230,7 @@ backend.add( ); ``` -The `myUserTransformer`, `myGroupTransformer`, and `myOrganizationTransformer` transformer functions are from the examples in the section below. +The `myUserTransformer`, `myGroupTransformer`, `myOrganizationTransformer`, and `myProviderConfigTransformer` transformer functions are from the examples in the section below. ### Transformer Examples @@ -221,6 +242,7 @@ import { defaultGroupTransformer, defaultUserTransformer, defaultOrganizationTransformer, + MicrosoftGraphProviderConfig, } from '@backstage/plugin-catalog-backend-module-msgraph'; import { GroupEntity, UserEntity } from '@backstage/catalog-model'; @@ -263,6 +285,16 @@ export async function myOrganizationTransformer( ): Promise { return undefined; } + +// Example config transformer that expands the group filter to also include 'azure-group-a' +export async function myProviderConfigTransformer( + provider: MicrosoftGraphProviderConfig, +): Promise { + if (!provider.groupFilter?.includes('azure-group-a')) { + provider.groupFilter = `${provider.groupFilter} or displayName eq 'azure-group-a'`; + } + return provider; +} ``` ## Troubleshooting diff --git a/plugins/catalog-backend-module-msgraph/api-report-alpha.md b/plugins/catalog-backend-module-msgraph/api-report-alpha.md index b9c96e7798..7b0ced8625 100644 --- a/plugins/catalog-backend-module-msgraph/api-report-alpha.md +++ b/plugins/catalog-backend-module-msgraph/api-report-alpha.md @@ -7,6 +7,7 @@ import { BackendFeature } from '@backstage/backend-plugin-api'; import { ExtensionPoint } from '@backstage/backend-plugin-api'; import { GroupTransformer } from '@backstage/plugin-catalog-backend-module-msgraph'; import { OrganizationTransformer } from '@backstage/plugin-catalog-backend-module-msgraph'; +import { ProviderConfigTransformer } from '@backstage/plugin-catalog-backend-module-msgraph'; import { UserTransformer } from '@backstage/plugin-catalog-backend-module-msgraph'; // @alpha @@ -26,6 +27,11 @@ export interface MicrosoftGraphOrgEntityProviderTransformsExtensionPoint { | OrganizationTransformer | Record, ): void; + setProviderConfigTransformer( + transformer: + | ProviderConfigTransformer + | Record, + ): void; setUserTransformer( transformer: UserTransformer | Record, ): void; diff --git a/plugins/catalog-backend-module-msgraph/api-report.md b/plugins/catalog-backend-module-msgraph/api-report.md index 86170e2910..9640f3708b 100644 --- a/plugins/catalog-backend-module-msgraph/api-report.md +++ b/plugins/catalog-backend-module-msgraph/api-report.md @@ -126,6 +126,7 @@ export class MicrosoftGraphOrgEntityProvider implements EntityProvider { userTransformer?: UserTransformer; groupTransformer?: GroupTransformer; organizationTransformer?: OrganizationTransformer; + providerConfigTransformer?: ProviderConfigTransformer; }); // (undocumented) connect(connection: EntityProviderConnection): Promise; @@ -145,6 +146,7 @@ export interface MicrosoftGraphOrgEntityProviderLegacyOptions { id: string; logger: LoggerService; organizationTransformer?: OrganizationTransformer; + providerConfigTransformer?: ProviderConfigTransformer; schedule: 'manual' | TaskRunner; target: string; userTransformer?: UserTransformer; @@ -162,6 +164,9 @@ export type MicrosoftGraphOrgEntityProviderOptions = organizationTransformer?: | OrganizationTransformer | Record; + providerConfigTransformer?: + | ProviderConfigTransformer + | Record; }; // @public @deprecated @@ -233,6 +238,11 @@ export type OrganizationTransformer = ( organization: MicrosoftGraph.Organization, ) => Promise; +// @public +export type ProviderConfigTransformer = ( + provider: MicrosoftGraphProviderConfig, +) => Promise; + // @public @deprecated export function readMicrosoftGraphConfig( config: Config, diff --git a/plugins/catalog-backend-module-msgraph/src/microsoftGraph/index.ts b/plugins/catalog-backend-module-msgraph/src/microsoftGraph/index.ts index 4db3fb69c6..81f6f21ce2 100644 --- a/plugins/catalog-backend-module-msgraph/src/microsoftGraph/index.ts +++ b/plugins/catalog-backend-module-msgraph/src/microsoftGraph/index.ts @@ -39,4 +39,5 @@ export type { GroupTransformer, OrganizationTransformer, UserTransformer, + ProviderConfigTransformer, } from './types'; diff --git a/plugins/catalog-backend-module-msgraph/src/microsoftGraph/types.ts b/plugins/catalog-backend-module-msgraph/src/microsoftGraph/types.ts index ef60d7b018..bc9270238b 100644 --- a/plugins/catalog-backend-module-msgraph/src/microsoftGraph/types.ts +++ b/plugins/catalog-backend-module-msgraph/src/microsoftGraph/types.ts @@ -16,7 +16,7 @@ import { GroupEntity, UserEntity } from '@backstage/catalog-model'; import * as MicrosoftGraph from '@microsoft/microsoft-graph-types'; - +import { MicrosoftGraphProviderConfig } from './config'; /** * Customize the ingested User entity * @@ -45,3 +45,15 @@ export type GroupTransformer = ( group: MicrosoftGraph.Group, groupPhoto?: string, ) => Promise; + +/** + * Customize the MSGraph Provider Config Dynamically + * + * Transforming fields that are not used for each scheduled ingestion (e.g., id, schedule) + * will have no effect. + * + * @public + */ +export type ProviderConfigTransformer = ( + provider: MicrosoftGraphProviderConfig, +) => Promise; diff --git a/plugins/catalog-backend-module-msgraph/src/module/catalogModuleMicrosoftGraphOrgEntityProvider.ts b/plugins/catalog-backend-module-msgraph/src/module/catalogModuleMicrosoftGraphOrgEntityProvider.ts index 193f07889f..e1a15a3468 100644 --- a/plugins/catalog-backend-module-msgraph/src/module/catalogModuleMicrosoftGraphOrgEntityProvider.ts +++ b/plugins/catalog-backend-module-msgraph/src/module/catalogModuleMicrosoftGraphOrgEntityProvider.ts @@ -23,6 +23,7 @@ import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/ import { GroupTransformer, OrganizationTransformer, + ProviderConfigTransformer, UserTransformer, } from '@backstage/plugin-catalog-backend-module-msgraph'; import { MicrosoftGraphOrgEntityProvider } from '../processors'; @@ -58,6 +59,18 @@ export interface MicrosoftGraphOrgEntityProviderTransformsExtensionPoint { | OrganizationTransformer | Record, ): void; + + /** + * Set the function that transforms provider config dynamically. + * Optionally, you can pass separate transformers per provider ID. + * Note: adjusting fields that are not used on each scheduled ingestion + * (e.g., id, schedule) will have no effect. + */ + setProviderConfigTransformer( + transformer: + | ProviderConfigTransformer + | Record, + ): void; } /** @@ -94,6 +107,10 @@ export const catalogModuleMicrosoftGraphOrgEntityProvider = createBackendModule( | OrganizationTransformer | Record | undefined; + let providerConfigTransformer: + | ProviderConfigTransformer + | Record + | undefined; env.registerExtensionPoint( microsoftGraphOrgEntityProviderTransformExtensionPoint, @@ -116,6 +133,12 @@ export const catalogModuleMicrosoftGraphOrgEntityProvider = createBackendModule( } organizationTransformer = transformer; }, + setProviderConfigTransformer(transformer) { + if (providerConfigTransformer) { + throw new Error('Provider transformer may only be set once'); + } + providerConfigTransformer = transformer; + }, }, ); @@ -134,6 +157,7 @@ export const catalogModuleMicrosoftGraphOrgEntityProvider = createBackendModule( userTransformer: userTransformer, groupTransformer: groupTransformer, organizationTransformer: organizationTransformer, + providerConfigTransformer: providerConfigTransformer, }), ); }, diff --git a/plugins/catalog-backend-module-msgraph/src/processors/MicrosoftGraphOrgEntityProvider.ts b/plugins/catalog-backend-module-msgraph/src/processors/MicrosoftGraphOrgEntityProvider.ts index 3c8b903e69..21995d2b8d 100644 --- a/plugins/catalog-backend-module-msgraph/src/processors/MicrosoftGraphOrgEntityProvider.ts +++ b/plugins/catalog-backend-module-msgraph/src/processors/MicrosoftGraphOrgEntityProvider.ts @@ -34,6 +34,7 @@ import { MICROSOFT_GRAPH_USER_ID_ANNOTATION, MicrosoftGraphClient, MicrosoftGraphProviderConfig, + ProviderConfigTransformer, OrganizationTransformer, readMicrosoftGraphConfig, readMicrosoftGraphOrg, @@ -94,6 +95,13 @@ export type MicrosoftGraphOrgEntityProviderOptions = organizationTransformer?: | OrganizationTransformer | Record; + + /** + * The function that transforms provider config dynamically. + */ + providerConfigTransformer?: + | ProviderConfigTransformer + | Record; }; /** @@ -152,6 +160,11 @@ export interface MicrosoftGraphOrgEntityProviderLegacyOptions { * The function that transforms an organization entry in msgraph to an entity. */ organizationTransformer?: OrganizationTransformer; + + /** + * The function that transforms provider config dynamically. + */ + providerConfigTransformer?: ProviderConfigTransformer; } /** @@ -216,6 +229,10 @@ export class MicrosoftGraphOrgEntityProvider implements EntityProvider { providerConfig.id, options.organizationTransformer, ), + providerConfigTransformer: getTransformer( + providerConfig.id, + options.providerConfigTransformer, + ), }); if (taskRunner !== 'manual') { @@ -257,6 +274,7 @@ export class MicrosoftGraphOrgEntityProvider implements EntityProvider { userTransformer: options.userTransformer, groupTransformer: options.groupTransformer, organizationTransformer: options.organizationTransformer, + providerConfigTransformer: options.providerConfigTransformer, logger, provider, }); @@ -276,6 +294,7 @@ export class MicrosoftGraphOrgEntityProvider implements EntityProvider { userTransformer?: UserTransformer; groupTransformer?: GroupTransformer; organizationTransformer?: OrganizationTransformer; + providerConfigTransformer?: ProviderConfigTransformer; }, ) {} @@ -300,7 +319,9 @@ export class MicrosoftGraphOrgEntityProvider implements EntityProvider { } const logger = options?.logger ?? this.options.logger; - const provider = this.options.provider; + const provider = this.options.providerConfigTransformer + ? await this.options.providerConfigTransformer(this.options.provider) + : this.options.provider; const { markReadComplete } = trackProgress(logger); const client = MicrosoftGraphClient.create(this.options.provider); const { users, groups } = await readMicrosoftGraphOrg( From 771a4c2cf4f77e5f63f8cf82177e35c4b8062c36 Mon Sep 17 00:00:00 2001 From: Martin Marosi Date: Mon, 27 May 2024 13:50:45 +0200 Subject: [PATCH 013/416] beps/0002: add dynamic FE plugins cli,backend,loading proposals Signed-off-by: Martin Marosi --- beps/0002-dynamic-frontend-plugins/README.md | 754 +++++++++++++----- .../dependency-sharing-schema.json | 43 + .../share-config-sample.json | 17 + 3 files changed, 633 insertions(+), 181 deletions(-) create mode 100644 beps/0002-dynamic-frontend-plugins/dependency-sharing-schema.json create mode 100644 beps/0002-dynamic-frontend-plugins/share-config-sample.json diff --git a/beps/0002-dynamic-frontend-plugins/README.md b/beps/0002-dynamic-frontend-plugins/README.md index f26a3b488d..34c6e2d435 100644 --- a/beps/0002-dynamic-frontend-plugins/README.md +++ b/beps/0002-dynamic-frontend-plugins/README.md @@ -156,12 +156,247 @@ Each plugin is required to provide manifest file (metadata) in predefined format Plugin discovery is a pre-requisite for Plugin registry. This should be responsible for scanning for available plugins and generating/modifying the plugin registry to always keep it up to date. +### CLI + +The following sections contains proposal of new CLI scripts to support the dynamic frontend plugins. + +#### Static and Dynamic Plugin Build Differences + +The major difference between static and dynamic plugins lies in their dependencies and how they are "installed" into a Backstage instance and whether they are bundled into final JS output during the build. + +While static plugins can define their dependencies using the dependencies field inside `package.json`, dynamic (module federation-based) plugins can't. + +A dynamic plugin requires all dependencies to be present in the build output. Module sharing is then used to optimize the "output size" at runtime. If a shared package is not found in the browser scope, or if the version range does not match the requirement, it falls back and loads additional JS assets from the "private" build and adds them to the scope. + +Webpack is also not the best tool for building traditional NPM packages. Dependencies can be externalized, but Webpack brings additional code into the bundles. Using Webpack external dependencies also conflicts with module federation shared modules. Externals will not be included even as a shared module fallback. As a result, such shared module can't be used because the dependency will not be defined in the init container. + +If the vision is to still support "static" plugins installed via NPM, it makes sense to keep the static and dynamic plugin builds separate and build two different bundles. Both can still be published as a single NPM package (not recommended), but to achieve optimal performance for both, there cannot be a shared output. + +#### Dynamic export CLI + +```sh +backstage-cli plugin export-dynamic +``` + +Similar to the current build command, instead of producing static plugin output, it builds a dynamic plugin using Webpack and module federation plugins. + +**Internal arguments** + +Some configuration is required, but they can be internal using the script `cwd`. + +- _path_ + - path to the plugin `package.json` +- _export-name_ + - Export name from where the plugin root is accessible + - defaults to `pluginEntry` + +**Shared modules** + +> NOTE: Details of module sharing are described in the [Module sharing](#module-sharing) section. + +Short summary of dependency sharing: + +- Predefined set of singleton packages +- Generated granular config of modules for MUI dependencies +- Share all other dependencies listed in package.json + +To allow additional customization of module sharing, extra configuration will be required. The extra module haring configuration can be embedded inside `package.json`. + +- [Schema proposal draft](./dependency-sharing-schema.json) +- [Config draft](./share-config-sample.json) + +#### Generate module sharing map + +> NOTE: RedHat has similar internal generators that are used in combination with Scalprum. These can be built upon, moved to Scalprum, and exposed. If there is interest, the Backstage maintainers do not have to be responsible for maintaining the source code. + +A simple program to traverse the AST and find exports from the `main` or `module` script of a dependency. Any exposed modules from the dependency entry will be traced to their source files, and a module map can be generated. + +> NOTE: It is important that import paths in source code are also directly targeting the "traced" modules or are transformed at build time. + +**The script should be triggered by the plugin build cli** + +Generates a module map (exported module source file location) for module sharing. + +**Arguments** + +- _path_ + - path to the module root (directory with package.json) + +[module map generator using TS example](#simplistic-minimal-example-of-module-map-generator) + +### Dynamic assets server + +A simple static asset server is sufficient to serve the dynamic assets. The asset server can collect the necessary metadata at boot or runtime. The asset server can be added to the `app-backend` + +It's important to consider old deployments as part of this storage, to make sure that dynamic chunks are still available to users who have not yet refreshed the page to load the latest version of the app. + +#### Plugin separation + +- Each plugin should be separated into a directory. +- Each plugin can be viewed as a `private` workspace package in a npm workspaces environment. + +```sh +path/to/assets/plugin/dynamic-plugins/ +└── dynamic-backstage.plugin-user-settings + ├── dist + ├── package.json + └── plugin-manifest.json +``` + +#### Boot time initialization + +**Dynamically build plugins** + +Only dynamic plugins can be hosted in the backend. The plugins has to provide the [manifest](#plugin-manifest). It the manifest is not found, plugin will not be considered dynamic and will be enabled for loading. + +**File system assets management** + +Once plugins are installed and fully dynamic, the asset server has to "discover" what plugins are loadable. + +This can be done by scanning the "assets" (dynamic-plugins in the dir example) for individual plugin manifests. Simple `glob` lookup for `path/dynamic-plugins/**/plugins-manifest.json` pattern should give required results. + +With this data the assets server should be able to generate a "plugin registry" with necessary metadata for the frontend. See the [Plugin Registry](#plugin-registry-1) for format details. + +The during the collection, the program can also add the `assetHost` prefix to the manifest location attribute described in the [webpack configuration](#sample-webpack-configuration) section. + +**Alternative means of assets management** + +To manage the assets by other means than just using filesystem, the file system should be treated only as an entry point for the plugins. Leveraging other means such as DB/cache/object storage should be also an option. The storage method should be mandated as long as a plugin registry and assets are available. + +**Singleton dependencies verification (optional)** + +With [module sharing](#module-sharing) and its singleton option, it is critical that the singleton dependencies versions are matching. + +The singleton configuration from the shell application can be extracted as well as from all dynamic plugins (included in the generated [manifest](#plugin-manifest)). A semver check can be used to prevent a plugin from initializing if a version mismatch is found. A version check also has to be made between plugins. New plugin singleton dependencies must match both the shell and all previously loaded plugins. + +#### Runtime updates + +It is fully expected that plugins can be added or removed at the asset server runtime. The same tasks can be performed as during boot time initialization. It is critical that the plugin registry is not cached and updated immediately if assets change. + +The server **should not remove older JS/CSS assets** immediately after updates. It is highly likely user can have older version still loaded in their browsers. A retention period is required for the assets. Using proper content hashes for builds will help with keep the duplicate assets to a minimum. + +#### Asset server API + +> NOTE Routes names are purely arbitrary at this point. + +The API can be very simplistic + +_GET /dynamic-plugins/plugin-registry_ + +Returns generated [Plugin Registry](#plugin-registry-1). + +\*GET /dynamic-plugins/assets/\*\* + +Static assets endpoint. Can be handled via the `express.static` middleware. + +### Plugin loading + +> NOTE: Only viable for the new frontend plugin system. + +The feature loader is a perfect place to initialize a new dynamic plugin as it already accepts async loaders. + +An example of [integration with scalprum](https://github.com/backstage/backstage/commit/23085aa8dfbc73d4648c100cf06b6b67e8e31764). + +#### Integration to core + +**Dynamic Feature configuration** + +The dynamic remote loading can be added directly into the [`createApp`](https://github.com/backstage/backstage/blob/master/packages/frontend-app-api/src/wiring/createApp.tsx#L234) function. + +The current `feature` type can be expanded with a `DynamicFrontendFeature` type: + +```ts +// current +type Features: (FrontendFeature | CreateAppFeatureLoader)[]; + +// with dynamic plugins +type DynamicFrontendFeature = { + name: string; + manifestLocation: string // URI with host enhanced with the "DEFAULT_API_PATH" or "assetHost" prefix +} + +type Features: (FrontendFeature | CreateAppFeatureLoader | DynamicFrontendFeature)[]; +``` + +**Dynamic Feature boot loading** + +Scalprum can be initialized with the metadata originating from the dynamic backend plugin. In order to properly load a plugin with `publicPath` set to `auto`, a small transformation of the manifest has to happen before it is loaded. A sample Scalprum config with such transformation: + +```TS +import { initialize } from '@scalprum/core'; +import { ScalprumProviderProps } from '@scalprum/react-core'; + +// get the pluginRegistry from the backend plugin +const pluginRegistry = await loadRemoteConfig() + +const pluginSDKOptions: ScalprumProviderProps['pluginSDKOptions'] = { + pluginLoaderOptions: { + transformPluginManifest: manifest => { + return { + ...manifest, + loadScripts: manifest.loadScripts.map(script => { + // Any additional transformations can happen here in case the manifest format needs to be adjusted further. + // the init scripts URL is enhanced with the asset location to add the host: + return `${manifest.customProperties.assetHost ?? DEFAULT_API_PATH}${script}`; + }), + }; + }, + }, +}; + +// Initialize Scalprum instance +const scalprum = initialize({ + appsConfig: pluginRegistry, + pluginLoaderOptions: pluginSDKOptions.pluginLoaderOptions, +}); +``` + +Because the [`appLoader`](https://github.com/backstage/backstage/blob/master/packages/frontend-app-api/src/wiring/createApp.tsx#L193) is already async, it is a perfect place to load the plugin registry and init the dynamic plugins. + +Initializing the dynamic feature is just a case of mapping the `DynamicFrontendFeature` to `FrontendFeature` via Scalprum: + +```ts +import { processManifest, getModule } from '@scalprum/core'; +// a ID of the module withing module federation container, can be customized, depends on the build +const DEFAULT_MODULE_NAME = 'pluginEntry'; + +async function loadScalprumFeature({ manifestLocation, name }) { + // initialize dynamic remote within scalprum cache + await processManifest(manifestLocation, name, DEFAULT_MODULE_NAME); + // gets the actual JS module from scalprum + const feature = await getModule(name, DEFAULT_MODULE_NAME); + + return feature; +} +const providedFeatures: FrontendFeature[] = []; +for (const entry of options?.features ?? []) { + if ('manifestLocation' in entry && 'name' in entry) { + // some error handling required + const dynamicFeature = loadScalprumFeature(entry); + providedFeatures.push(dynamicFeature); + } else if ('load' in entry) { + // plugin with load function + } else { + // #static plugin + } +} + +const app = createSpecializedApp({ + icons: options?.icons, + config, + features: [...discoveredFeatures, ...providedFeatures], + bindRoutes: options?.bindRoutes, +}).createRoot(); +``` + +The federated modules are now available as if they were static plugins. + ## Design Details -> NOTE The details are based on the Janus implementation of dynamic frontend plugins. The implementation leverages [Scalprum](https://github.com/scalprum/scaffolding) which is a Webpack based dynamic plugin manager for React applications. - ### Module federation implementation experiments +> NOTE Experiments were tested and documented. Decision was mated to leverage [Scalprum](https://github.com/scalprum/scaffolding) and [dynamic-plugins-sdk](https://github.com/openshift/dynamic-plugin-sdk). Instead of native webpack module federation the [@module-federation/enhanced](https://www.npmjs.com/package/@module-federation/enhanced) plugin will be used to ensure future compatibility with other bundlers. + Test should consist of trying to run permutations of webpack/Rspack/vite based shell apps/plugins and discover if we can freely choose any tool, or if we should restrict the tooling to just a subset of the available options. The outcome of initial testing is positive and it is possible to mix and match different build tools and consume different remote modules in a single shell application. @@ -217,70 +452,7 @@ This config ensures that only those modules (from @mui/material) that are used i This can be checked by debugging network traffic and shared scopes: -![notifications system architecture diagram](./scope-sharing.png) - -#### Limitations - -A limitation of module sharing is that each module name can only appear once in each context. This means that if you're trying to build a bundle of shared modules with a deeper dependency tree, you may end up needing to resolve conflicts by renaming some modules that appear multiple times with different versions. This will in turn limit sharing of those modules with other bundles. - -There is also a conflict with the chunk splitting currently used in the Backstage CLI that means that some singleton modules need to be configured to be eagerly loaded. More broadly we may also want to re-evaluate the chunk splitting strategy in the Backstage CLI when adding support for module federation. - -### Plugin manifest - -Each plugin should have a manifest file with important metadata. This metadata is used to load the remote assets to browser. The plugin manifest should be part of a build output. - -A manifest should have: - -- name of plugin -- how can be the init container accessed -- what is the base URL (assets pathname) -- name of the entry script(s) - -#### Scalprum compatible manifest - -```TS -type PluginManifest = { - name: string; - version: string; - dependencies?: Record; - customProperties?: AnyObject; - baseURL: string; - extensions: Extension[]; - loadScripts: string[]; - registrationMethod: 'callback' | 'custom'; - buildHash?: string; -} -``` - -```js -{ - "name": "backstage.plugin-github-actions", - "version": "0.6.6", - "extensions": [], - "registrationMethod": "callback", // where container init is available in browser - "baseURL": "auto", - "loadScripts": [ - "backstage.plugin-github-actions.804b91040fcbca6585ce.js" - ], - "buildHash": "804b91040fcbca6585ce1bcd4b1f8aa2" -} -``` - -##### `registrationMethod` - -Refers to [webpack output.libraryTarget](https://webpack.js.org/configuration/output/#outputlibrarytarget). - -Callback refers to `jsonp` and a the `custom` is used if other available target configuration has been picked. - -It is recommended to use either `global` or `jsonp` as these are environment agnostic (browser VS node). `jsonp` requires additional configurations. The `global` is preferable due to its simplicity. - -##### `baseURL` - -The `baseURL` is derived from [webpack public path](https://webpack.js.org/configuration/output/#outputpublicpath) - -The public path can also be set to `auto` to remove the need to specify origin or pathname and resolve the pathname at runtime. - -In Scalprum, some manifest [post processing](https://github.com/janus-idp/backstage-showcase/blob/main/packages/app/src/components/DynamicRoot/DynamicRoot.tsx#L323) is required to load the initial scripts if the `auto` baseURL is chosen. +![scope sharing sample](./scope-sharing.png) ### Plugin registry @@ -290,6 +462,7 @@ Plugin registry can be fairly simplistic. It can be as simple as JSON file conta type RegistryEntry = { name: string // plugin name manifestLocation: string // path to the manifest resource + assetHost: string // host part of URL to deal with the `auto` publicPath } // object for easy access @@ -308,7 +481,8 @@ Example of such registry { "backstage.plugin-github-actions": { "name": "backstage.plugin-github-actions", - "manifestLocation": "https://foo-bar.com/api/plugin-storage/plugin-manifest.json" + "manifestLocation": "/api/plugin-storage/plugin-manifest.json", + "assetHost": "https://foo-bar.com" }, // ..rest of plugins } @@ -318,6 +492,7 @@ Example of such registry { "name": "backstage.plugin-github-actions", "manifestLocation": "https://foo-bar.com/api/plugin-storage/plugin-manifest.json" + "assetHost": "https://foo-bar.com" }, // ...rest of plugins ] @@ -353,7 +528,6 @@ Example of registry with embedded manifests "pluginManifest": { "name": "backstage.plugin-github-actions", "version": "0.6.6", - "extensions": [], "registrationMethod": "callback", "baseURL": "auto", "loadScripts": [ @@ -372,7 +546,6 @@ Example of registry with embedded manifests "pluginManifest": { "name": "backstage.plugin-github-actions", "version": "0.6.6", - "extensions": [], "registrationMethod": "callback", "baseURL": "auto", "loadScripts": [ @@ -386,155 +559,374 @@ Example of registry with embedded manifests ``` -### Webpack build configuration +### Frontend plugin build configuration -> NOTE This is a sample current configuration in the Janus project. It uses Scalprum webpack based build plugin to generate the output. It does not take the [all options](#Module-federation-implementation-experiments) in consideration. This section will likely change considerably. +#### Build tooling -Part of a Scalprum tooling is also [dynamic-plugins-sdk](https://github.com/openshift/dynamic-plugin-sdk). Right now the package is a part of a different project, but that is about to change. More details in the [Scalprum roadmap](https://github.com/scalprum/scaffolding/blob/main/ROADMAP.md). +- webpack module bundler as a base +- use `@openshift/dynamic-plugin-sdk-webpack` to build dynamic frontend output + - with `@module-federation/enhanced` plugins instead of native webpack -#### Sample plugin configuration using Scalprum SDK +#### Module sharing + +Webpack allows for dependency/module sharing across different remote modules. For performance's sake, all dependencies should be shared. The sharing is version-restricted, and there can be multiple versions of the same package at the same time. This ensures that remote modules will have the necessary dependency version available, either from the shared scope or as a fallback from the respective build. + +**Singleton sharing** + +Singleton sharing is necessary for context sharing between remote modules and between remote modules and shell application. + +Only a minimal set of dependencies should be shared as singletons as it gives access to all packages to the parent context. Also **version checking is disabled for singleton packages!** + +Singleton "must have" list: + +- @scalprum/core +- @scalprum/react-core +- @openshift/dynamic-plugin-sdk +- react +- react-dom +- react-router-dom + +Singleton "might have to" list: + +- @material-ui/core/styles +- @material-ui/styles + +**@mui/_ and @material-ui/_ like packages** + +> NOTE: Can leverage [Generate module sharing map](#generate-module-sharing-map). + +Component libraries are usually large (thousands of svg icons in @mui/icons) and it is inefficient to share them as a whole. **Tree shaking is disabled for shared modules**. That means sharing large packages in multiple versions will result in a bloated JS in browsers. + +Sharing components like these can be done on module level. Instead of sharing the entire package, share its individual components: + +```js +const shared = { + // will result in bloated bundles and degraded performance + '@mui/material': { + requiredVersion: 'x.x.x', // semver + }, + // sharing per module level, only button module is included in the output + '@mui/material/Button': { + version: 'x.x.x', // might have to specifically set the version + requiredVersion: 'x.x.x', // semver + }, +}; +``` + +Sharing dependencies on module level leads to optimal bundle size. Even if all modules from a dependency are listed, Webpack will only bundle modules that are discovered in the source files. That means the list can be generated at build time with no risk of bloating the output with unused modules. + +The module sharing "matching" is based on import paths. If relative import paths are used `import {foo} from 'bar'` it will not be matched to the absolute import path of a shared module `import foo from 'bar/foo'`. Therefore absolute import paths have to enforced or path transformation has to happen at build time. For JS builds, babel can be used, for ts builds a `ts-patch` utility with custom plugins is an option. + +#### Limitations + +A limitation of module sharing is that each module name can only appear once in each context. This means that if you're trying to build a bundle of shared modules with a deeper dependency tree, you may end up needing to resolve conflicts by renaming some modules that appear multiple times with different versions. This will in turn limit sharing of those modules with other bundles. + +There is also a conflict with the chunk splitting currently used in the Backstage CLI that means that some singleton modules need to be configured to be eagerly loaded. More broadly we may also want to re-evaluate the chunk splitting strategy in the Backstage CLI when adding support for module federation. + +#### Webpack chunk optimization + +Custom webpack chunk splitting configuration can be problematic, especially when modifying runtime and vendor chunks. Module federation creates its own chunks. Shared modules that are not set up to be eagerly loaded (using the `eager` configuration) **cannot be included inside the entry script**. With a custom chunk splitting setup, they can potentially be forced into the entry script, causing runtime errors. On the other hand, some critical runtime code that has to be in the entry script, cna be forced out of it. This is particularly problematic for the "shell" application. + +Chunk optimization should be disabled for the initial implementation. + +#### Webpack Public path option + +The `publicPath` output config in webpack is a mandatory attribute for federated modules. However, at build time, it is impossible to guess where the assets are served from. From origin to the pathname, this is specific to each installation. + +We can leverage the [auto](https://webpack.js.org/guides/public-path/#automatic-publicpath) option. However this means that some manifest transformation has to happen at runtime when entry scripts are loaded into the browser. More on that in the [Plugin manifest](#plugin-manifest), [CDN Plugin](#dynamic-assets-server-plugin), and [Plugin loading](#plugin-loading) sections. + +#### Sample webpack configuration ```TS -import { DynamicRemotePlugin } from '@openshift/dynamic-plugin-sdk-webpack'; -const sharedModules = { - /** - * Mandatory singleton packages for sharing - */ - react: { - singleton: true, - requiredVersion: '*', - }, - 'react-dom': { - singleton: true, - requiredVersion: '*', - }, - 'react-router-dom': { - singleton: true, - requiredVersion: '*', - }, - 'react-router': { - singleton: true, - requiredVersion: '*', - }, - ... - /** - * Full list of shared modules in Janus - * https://github.com/janus-idp/backstage-plugins/blob/87a6b045c7b0f301ebed8b8f99dc1741fa2b044b/packages/cli/src/lib/bundler/scalprumConfig.ts#L16 - */ +type DynamicPluginConfig = { + name: string; + version?: string; +}; +// { name: "@backstage/plugin-api-docs", version: "1.0.0" } +// generates "dynamic-backstage.plugin-api-docs" +const getName = (plugin: DynamicPluginConfig) => { + let pluginName: string; + if (plugin.name.includes('/')) { + const fragments = plugin.name.split('/'); + pluginName = `${fragments[0].replace('@', '')}.${fragments[1]}`; + } else { + pluginName = plugin.name; + } + return `dynamic-${pluginName}`; } + +// plugin = { name: "@backstage/plugin-api-docs", version: "1.0.0" } based on package.json +const pluginName = getName(plugin); + +const { ModuleFederationPlugin, ContainerPlugin } = require('@module-federation/enhanced'); + const dynamicPluginPlugin = new DynamicRemotePlugin({ extensions: [], - sharedModules, - entryScriptFilename: `${options.pluginMetadata.name}.[contenthash].js`, - pluginMetadata: { - // version cna be used from the package.json version field - version: '1.0.0', - /** - * Name can be easily derived from the plugin name - * https://github.com/janus-idp/backstage-plugins/blob/87a6b045c7b0f301ebed8b8f99dc1741fa2b044b/packages/cli/src/commands/export-dynamic-plugin/frontend.ts#L40 - */ - name: 'backstage.plugin-github-actions', - /** - * Path to the plugin entry point. - * It can default to the same entry point as in regular build. - * Plugins can expose multiple modules. We have found that one is sufficient from backstage plugins. - */ - exposedModules: { - PluginRoot: './src/index.ts' + sharedModules, // from shared config and generated from `package.json` dependencies + entryScriptFilename: `[name].[contenthash].js`, // using contenthash for cashing purposes + moduleFederationSettings: { + libraryType: 'global', // use the globalThis object rather than jsonp + // instruct the sdk plugin to use @module-federation/enhanced tooling + pluginOverride: { + ModuleFederationPlugin, + ContainerPlugin, } }, -}); -``` - -The `DynamicRemotePlugin` webpack plugin takes care of the rest, including the manifest generation. - -#### Sample plugin raw webpack configuration - -The Scalprum config translates to a following base webpack plugin configuration: - -```JS -import { container } from 'webpack'; - -const dynamicPlugin = new container.ModuleFederationPlugin({ - name: 'backstage.plugin-github-actions', - library: { - type: 'global', - /** - * Some library.type has name limitation - * for example, if "type": "var" is used, the library.name can contain the "-" character - */ - name: 'backstage.plugin-github-actions' + pluginMetadata: { + name: pluginName, + version: plugin.version || '0.0.0', + exposedModules: { + // path to the default export of the frontend plugin entry point + // the path should be sourced from the "main" attribute withing package.json + pluginEntry: './src/index.ts', + }, }, - filename: 'backstage.plugin-github-actions.[contenthash].js', - exposes: { - PluginRoot: './src/index.ts' - }, - // list of shared modules like "react", "react-dom", etc - shared: sharedModules, }); + + +const config: Configuration = { + context: pluginRoot, + output: { + chunkFilename: `${pluginName}.[contenthash].js`, + path: path.resolve(pluginRoot, 'dist'), + publicPath: 'auto', + }, + entry: {}, + resolve: { + extensions: ['.js', '.jsx', '.ts', '.tsx'], + }, + // extend existing webpack plugins that are relevant for dynamic plugins + plugins: [dynamicPluginPlugin, ...], + module: { + rules: [ + { + // needs TS config as well + test: /\.js$/, + exclude: /(node_modules)/, + use: { + loader: 'swc-loader', + }, + }, + { + test: /\.(png|svg|jpg|jpeg|gif)$/i, + type: 'asset/resource', + }, + // additional loaders for CSS if necessary, can use the same as the current backstage shell app + ], + }, + }; + return config; ``` -Additional plugin would have to be written from scratch to generate the plugin manifest file. +**Webpack plugins** -### Sample shell application webpack configuration +Existing webpack plugins can be used. Subset of shared plugins should be identified from current configurations and shared between the dynamic plugins and the shell application. -Shell application (backstage) has very simple module federation configuration. It does not require anything special to be able to inject plugins. Main requirement is to provide core shared packages like react and react-dom. +### Plugin manifest -```JS -import { container } from 'webpack'; +Plugin manifest is a simple JSON file containing critical metadata to initialize a remote plugin. -const scalprumPlugin = new container.ModuleFederationPlugin({ - name: 'backstageHost', - filename: 'backstageHost.[contenthash].js', - // same share modules list as with plugin config - shared: [sharedModules], -}); +The `@openshift/dynamic-plugin-sdk-webpack` plugin will output manifest file in the following format: + +```ts +type PluginManifest = { + name: string; + version: string; + dependencies?: Record; + customProperties?: AnyObject; + baseURL: string; + loadScripts: string[]; + registrationMethod: 'callback' | 'custom'; + buildHash?: string; +}; ``` -Nothing else is required. +This manifest is directly usable in Scalprum at runtime. -### Plugin storage +**baseURL** -Where will the dynamic plugin assets be hosted? Module federation does not strictly require the remote assets to be all hosted on the same origin. +This attribute is populated by the `output.publicPath` configuration. In this case, it will be a value of `auto`. That is not usable by the Scalprum loader. It has to be a URL. -Theoretically plugins can be hosted on some "public CDN" which is detached from individual backstage instances. +Because the origin can't be reliably "guessed" at build time, the value has to be filled by the CDN server. The attribute can be either overridden or, preferably, added to the `customProperties` attribute. -Assets can be also be hosted in the same way as they have always been. +A default`DEFAULT_API_PATH` should be used. Covering majority of the use cases. -It's important to consider old deployments as part of this storage, to make sure that dynamic chunks are still available to users who have not yet refreshed the page to load the latest version of the app. +```ts +type CustomProperties = { + assetHost?: string; // for local development should be http://localhost:PORT + // for deployment, should match the api host https://backstage.company.org +}; +``` -### Plugin discovery +Any additional metadata about plugins, can be also stored to the `customProperties`. Either at build time or runtime. That depends on the use case. The values can be read at runtime during plugin initialization. -How to notify/send data to browser +```ts +type CustomProperties = { + backstage: Record; +}; +``` -### Plugin initialization +**Exposing singleton packages config** -Currently all plugins have to be initialized at UI bootstrap (page refresh). The new UI async API can be used to initialize the remote assets. +Singleton shared packages do not follow the version matching strategy. It is a weak point in the dependency sharing strategy. Exposing the data in the manifest files provides the option to check the singleton configuration at runtime and prevent runtime crashes of plugins. -The `CreateAppFeatureLoader` can be leveraged to initialize the remote container. +```ts +type SingletonShareConfig = { + singleton: true; + version: string; + packageName: string; +}; -```TS -const allPluginManifests = {...} // get this from the config +type SingletonShareObject = { + [packageName: string]: SingletonShareConfig; +}; +``` -const asyncFeatureLoaders: CreateAppFeatureLoader[] = Object.values(allPluginManifests).map(({ manifest }) => { - return { - getLoaderName: () => manifest.name, - load: (options) => { - // initialize the remote container, depends on tooling - const plugin = initDynamicPlugin(manifest) - } +**Backstage plugin manifest** + +The plugin manifest for backstage with the additional attributes: + +```ts +type SingletonShareConfig = { + singleton: true; + version: string; + packageName: string; +}; + +type SingletonShareObject = { + [packageName: string]: SingletonShareConfig; +}; + +type CustomProperties = { + assetHost?: string; + backstage: Record; + singletonPackages: SingletonShareObject; +}; + +type PluginManifest = { + name: string; + version: string; + dependencies?: Record; + customProperties: CustomProperties; + baseURL: 'auto'; + loadScripts: string[]; + registrationMethod: 'custom'; + buildHash?: string; +}; +``` + +### Simplistic minimal example of module map generator + +```js +const path = require('path'); +const typescript = require('typescript'); +const fs = require('fs'); + +/** @type {typescript.CompilerOptions} */ +const defaultCompilerOptions = { + targe: 'es2015', + module: 'es2015', + esModuleInterop: true, + allowJs: true, + strict: false, + skipLibCheck: true, + noEmit: true, + // needs to be configured to the root directory dependency + rootDir: path.resolve(__dirname, 'dist'), + baseUrl: path.resolve(__dirname, 'dist'), +}; + +// these need to be configured, usually getting metadata from the lib package.json +const rootDit = path.resolve(__dirname, 'dist'); +const base = path.resolve(__dirname, 'dist', 'index.js'); + +function getDynamicModuleMap(libName) { + const compiler = typescript.createCompilerHost(defaultCompilerOptions, [ + rootDit, + ]); + const program = typescript.createProgram( + [base], + defaultCompilerOptions, + compiler, + ); + + const moduleResolutionCache = typescript.createModuleResolutionCache( + rootDit, + x => x, + defaultCompilerOptions, + ); + const errorDiagnostics = typescript + .getPreEmitDiagnostics(program) + .filter(d => d.category === typescript.DiagnosticCategory.Error); + if (errorDiagnostics.length > 0) { + const { getCanonicalFileName, getCurrentDirectory, getNewLine } = compiler; + + console.error( + typescript.formatDiagnostics(errorDiagnostics, { + getCanonicalFileName, + getCurrentDirectory, + getNewLine, + }), + ); + + throw new Error(`Detected TypeScript errors while parsing modules`); } -}) + const typeChecker = program.getTypeChecker(); -const app = createApp({ - features: [ - ...asyncFeatureLoaders, - // rest of classic features - ] -}) + /** @param {typescript.SourceFile} sourceFile */ + const getExportNames = sourceFile => + typeChecker + .getExportsOfModule(typeChecker.getSymbolAtLocation(sourceFile)) + .map(symbol => symbol.getName()); + + const baseExports = getExportNames(program.getSourceFile(base)); + const compilerDir = compiler.getCurrentDirectory(); + const resolvedModules = baseExports + .map(name => { + const res = typescript.resolveModuleName( + name, + base, + defaultCompilerOptions, + compiler, + moduleResolutionCache, + ); + if (res.resolvedModule?.resolvedFileName) { + return { + name, + file: + libName + + res.resolvedModule.resolvedFileName + .replace(compilerDir, '') + .replace(/\.js$/, ''), + }; + } + return undefined; + }) + .filter(x => x !== undefined); + + const moduleMapFileName = path.resolve(__dirname, 'module-map.json'); + fs.writeFileSync(moduleMapFileName, JSON.stringify(resolvedModules, null, 2)); +} + +const libName = '@mui/foo'; + +getDynamicModuleMap(libName); + +/** + * [ + * { + * "name": "foo", + * "file": "@mui/foo/dist/foo" + * }, + * { + * "name": "baz", + * "file": "@mui/foo/dist/baz" + * } + * ] + */ ``` ### Plugin declarative configuration diff --git a/beps/0002-dynamic-frontend-plugins/dependency-sharing-schema.json b/beps/0002-dynamic-frontend-plugins/dependency-sharing-schema.json new file mode 100644 index 0000000000..4777f81f78 --- /dev/null +++ b/beps/0002-dynamic-frontend-plugins/dependency-sharing-schema.json @@ -0,0 +1,43 @@ +{ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "type": "object", + "additionalProperties": false, + "properties": { + "shareModules": { + "type": "object", + "patternProperties": { + "^(@[^/]+/)?[^/]+$": { + "$ref": "#/definitions/sharedModule" + } + }, + "additionalProperties": false + }, + "excludeModules": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "definitions": { + "sharedModule": { + "type": "object", + "required": ["requiredVersion"], + "properties": { + "requiredVersion": { + "$ref": "#/definitions/semverString" + }, + "version": { + "$ref": "#/definitions/semverString" + }, + "singleton": { + "type": "boolean" + } + } + }, + "semverString": { + "type": "string", + "pattern": "^(\\^|\\~)?(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$" + } + } +} diff --git a/beps/0002-dynamic-frontend-plugins/share-config-sample.json b/beps/0002-dynamic-frontend-plugins/share-config-sample.json new file mode 100644 index 0000000000..fe5c9943ad --- /dev/null +++ b/beps/0002-dynamic-frontend-plugins/share-config-sample.json @@ -0,0 +1,17 @@ +{ + "$schema": "./dependency-sharing-schema.json", + "shareModules": { + "foo-bar": { + "requiredVersion": "1.0.0" + }, + "@bax/foo-bar": { + "requiredVersion": "1.0.0", + "singleton": true + }, + "@bax-baz/foo-bar2": { + "requiredVersion": "^1.2.0", + "version": "1.4.0" + } + }, + "excludeModules": ["foo-bar-baz"] +} From a0fd89c3ef77677404cfb46e973000ef4061d2b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20St=C3=B6rkle?= Date: Thu, 15 Feb 2024 14:54:48 +0100 Subject: [PATCH 014/416] fix: use correct odata type in TypeScript MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Florian Störkle --- .../src/microsoftGraph/client.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/catalog-backend-module-msgraph/src/microsoftGraph/client.ts b/plugins/catalog-backend-module-msgraph/src/microsoftGraph/client.ts index 1233b1e2f9..c190e2a959 100644 --- a/plugins/catalog-backend-module-msgraph/src/microsoftGraph/client.ts +++ b/plugins/catalog-backend-module-msgraph/src/microsoftGraph/client.ts @@ -64,8 +64,8 @@ export type ODataQuery = { * @public */ export type GroupMember = - | (MicrosoftGraph.Group & { '@odata.type': '#microsoft.graph.user' }) - | (MicrosoftGraph.User & { '@odata.type': '#microsoft.graph.group' }); + | (MicrosoftGraph.Group & { '@odata.type': '#microsoft.graph.group' }) + | (MicrosoftGraph.User & { '@odata.type': '#microsoft.graph.user' }); /** * A HTTP Client that communicates with Microsoft Graph API. From da7651605a6c78e8e4a89ab89fc2d0e30291d06b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20St=C3=B6rkle?= Date: Fri, 16 Feb 2024 13:15:50 +0100 Subject: [PATCH 015/416] feat(catalog): ingest member groups if configured MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Florian Störkle --- .../config.d.ts | 5 + .../src/microsoftGraph/config.test.ts | 2 + .../src/microsoftGraph/config.ts | 10 ++ .../src/microsoftGraph/read.test.ts | 114 ++++++++++++++++++ .../src/microsoftGraph/read.ts | 28 +++++ .../MicrosoftGraphOrgEntityProvider.ts | 1 + 6 files changed, 160 insertions(+) diff --git a/plugins/catalog-backend-module-msgraph/config.d.ts b/plugins/catalog-backend-module-msgraph/config.d.ts index 5a1f56a03f..a470c075f0 100644 --- a/plugins/catalog-backend-module-msgraph/config.d.ts +++ b/plugins/catalog-backend-module-msgraph/config.d.ts @@ -192,6 +192,11 @@ export interface Config { * E.g. ["id", "displayName", "description"] */ select?: string[]; + /** + * Whether to ingest groups that are members of the found/filtered/searched groups. + * Default value is `false`. + */ + includeSubGroups?: boolean; }; userGroupMember?: { diff --git a/plugins/catalog-backend-module-msgraph/src/microsoftGraph/config.test.ts b/plugins/catalog-backend-module-msgraph/src/microsoftGraph/config.test.ts index b02894dfd9..e1c81662a3 100644 --- a/plugins/catalog-backend-module-msgraph/src/microsoftGraph/config.test.ts +++ b/plugins/catalog-backend-module-msgraph/src/microsoftGraph/config.test.ts @@ -175,6 +175,7 @@ describe('readProviderConfigs', () => { expand: 'member', filter: 'securityEnabled eq false', select: ['id', 'displayName', 'description'], + includeSubGroups: true, }, schedule: { frequency: 'PT30M', @@ -203,6 +204,7 @@ describe('readProviderConfigs', () => { groupExpand: 'member', groupSelect: ['id', 'displayName', 'description'], groupFilter: 'securityEnabled eq false', + groupIncludeSubGroups: true, schedule: { frequency: Duration.fromISO('PT30M'), timeout: { diff --git a/plugins/catalog-backend-module-msgraph/src/microsoftGraph/config.ts b/plugins/catalog-backend-module-msgraph/src/microsoftGraph/config.ts index 1545114e45..257a7d5736 100644 --- a/plugins/catalog-backend-module-msgraph/src/microsoftGraph/config.ts +++ b/plugins/catalog-backend-module-msgraph/src/microsoftGraph/config.ts @@ -116,6 +116,12 @@ export type MicrosoftGraphProviderConfig = { */ groupSelect?: string[]; + /** + * Whether to ingest groups that are members of the found/filtered/searched groups. + * Default value is `false`. + */ + groupIncludeSubGroups?: boolean; + /** * By default, the Microsoft Graph API only provides the basic feature set * for querying. Certain features are limited to advanced query capabilities @@ -292,6 +298,9 @@ export function readProviderConfig( const groupFilter = config.getOptionalString('group.filter'); const groupSearch = config.getOptionalString('group.search'); const groupSelect = config.getOptionalStringArray('group.select'); + const groupIncludeSubGroups = config.getOptionalBoolean( + 'group.includeSubGroups', + ); const queryMode = config.getOptionalString('queryMode'); if ( @@ -347,6 +356,7 @@ export function readProviderConfig( groupFilter, groupSearch, groupSelect, + groupIncludeSubGroups, queryMode, userGroupMemberFilter, userGroupMemberSearch, diff --git a/plugins/catalog-backend-module-msgraph/src/microsoftGraph/read.test.ts b/plugins/catalog-backend-module-msgraph/src/microsoftGraph/read.test.ts index 8821ffd2db..b83597653f 100644 --- a/plugins/catalog-backend-module-msgraph/src/microsoftGraph/read.test.ts +++ b/plugins/catalog-backend-module-msgraph/src/microsoftGraph/read.test.ts @@ -90,6 +90,9 @@ describe('read microsoft graph', () => { yield { '@odata.type': '#microsoft.graph.group', id: 'childgroupid', + displayName: 'Child Group Name', + description: 'Child Group Description', + mail: 'childgroup@example.com', }; yield { '@odata.type': '#microsoft.graph.user', @@ -770,6 +773,117 @@ describe('read microsoft graph', () => { top: 999, }); }); + + it('should read groups and their sub groups', async () => { + async function* getExampleGroupMembersForSubGroup(): AsyncIterable { + yield { + '@odata.type': '#microsoft.graph.user', + id: 'userid2', + }; + } + + client.getGroups.mockImplementation(getExampleGroups); + client.getGroupMembers.mockImplementationOnce(getExampleGroupMembers); + client.getGroupMembers.mockImplementationOnce( + getExampleGroupMembersForSubGroup, + ); + client.getOrganization.mockResolvedValue({ + id: 'tenantid', + displayName: 'Organization Name', + }); + client.getGroupPhotoWithSizeLimit.mockResolvedValue( + 'data:image/jpeg;base64,...', + ); + + const { groups, groupMember, groupMemberOf, rootGroup } = + await readMicrosoftGraphGroups(client, 'tenantid', { + groupIncludeSubGroups: true, + }); + + const expectedRootGroup = group({ + metadata: { + annotations: { + 'graph.microsoft.com/tenant-id': 'tenantid', + }, + name: 'organization_name', + description: 'Organization Name', + }, + spec: { + type: 'root', + profile: { + displayName: 'Organization Name', + }, + children: [], + }, + }); + expect(groups).toEqual([ + expectedRootGroup, + group({ + metadata: { + annotations: { + 'graph.microsoft.com/group-id': 'childgroupid', + }, + name: 'child_group_name', + description: 'Child Group Description', + }, + spec: { + type: 'team', + profile: { + displayName: 'Child Group Name', + email: 'childgroup@example.com', + // TODO: Loading groups photos doesn't work right now as Microsoft + // Graph doesn't allows this yet + /* picture: 'data:image/jpeg;base64,...',*/ + }, + children: [], + }, + }), + group({ + metadata: { + annotations: { + 'graph.microsoft.com/group-id': 'groupid', + }, + name: 'group_name', + description: 'Group Description', + }, + spec: { + type: 'team', + profile: { + displayName: 'Group Name', + email: 'group@example.com', + // TODO: Loading groups photos doesn't work right now as Microsoft + // Graph doesn't allows this yet + /* picture: 'data:image/jpeg;base64,...',*/ + }, + children: [], + }, + }), + ]); + expect(rootGroup).toEqual(expectedRootGroup); + expect(groupMember.get('groupid')).toEqual(new Set(['childgroupid'])); + expect(groupMemberOf.get('userid')).toEqual(new Set(['groupid'])); + expect(groupMemberOf.get('userid2')).toEqual(new Set(['childgroupid'])); + expect(groupMember.get('organization_name')).toEqual(new Set()); + + expect(client.getGroups).toHaveBeenCalledTimes(1); + expect(client.getGroups).toHaveBeenCalledWith( + { + top: 999, + }, + undefined, + ); + expect(client.getGroupMembers).toHaveBeenCalledTimes(2); + expect(client.getGroupMembers).toHaveBeenCalledWith('groupid', { + top: 999, + }); + expect(client.getGroupMembers).toHaveBeenCalledWith('childgroupid', { + top: 999, + }); + // TODO: Loading groups photos doesn't work right now as Microsoft Graph + // doesn't allows this yet + // expect(client.getGroupPhotoWithSizeLimit).toBeCalledTimes(1); + // expect(client.getGroupPhotoWithSizeLimit).toBeCalledWith('groupid', 120); + }); }); describe('resolveRelations', () => { diff --git a/plugins/catalog-backend-module-msgraph/src/microsoftGraph/read.ts b/plugins/catalog-backend-module-msgraph/src/microsoftGraph/read.ts index 2ca21fca9c..60e5c3d79b 100644 --- a/plugins/catalog-backend-module-msgraph/src/microsoftGraph/read.ts +++ b/plugins/catalog-backend-module-msgraph/src/microsoftGraph/read.ts @@ -178,6 +178,7 @@ export async function readMicrosoftGraphGroups( groupFilter?: string; groupSearch?: string; groupSelect?: string[]; + groupIncludeSubGroups?: boolean; groupTransformer?: GroupTransformer; organizationTransformer?: OrganizationTransformer; }, @@ -244,6 +245,31 @@ export async function readMicrosoftGraphGroups( if (member['@odata.type'] === '#microsoft.graph.group') { ensureItem(groupMember, group.id!, member.id); + + if (options?.groupIncludeSubGroups) { + const groupMemberEntity = await transformer(member); + + if (groupMemberEntity) { + groups.push(groupMemberEntity); + + for await (const subMember of client.getGroupMembers( + member.id!, + { top: PAGE_SIZE }, + )) { + if (!subMember.id) { + continue; + } + + if (subMember['@odata.type'] === '#microsoft.graph.user') { + ensureItem(groupMemberOf, subMember.id, member.id!); + } + + if (subMember['@odata.type'] === '#microsoft.graph.group') { + ensureItem(groupMember, member.id!, subMember.id); + } + } + } + } } } @@ -377,6 +403,7 @@ export async function readMicrosoftGraphOrg( groupSearch?: string; groupFilter?: string; groupSelect?: string[]; + groupIncludeSubGroups?: boolean; queryMode?: 'basic' | 'advanced'; userTransformer?: UserTransformer; groupTransformer?: GroupTransformer; @@ -421,6 +448,7 @@ export async function readMicrosoftGraphOrg( groupFilter: options.groupFilter, groupSearch: options.groupSearch, groupSelect: options.groupSelect, + groupIncludeSubGroups: options.groupIncludeSubGroups, groupTransformer: options.groupTransformer, organizationTransformer: options.organizationTransformer, }); diff --git a/plugins/catalog-backend-module-msgraph/src/processors/MicrosoftGraphOrgEntityProvider.ts b/plugins/catalog-backend-module-msgraph/src/processors/MicrosoftGraphOrgEntityProvider.ts index 3c8b903e69..c48ee18ffe 100644 --- a/plugins/catalog-backend-module-msgraph/src/processors/MicrosoftGraphOrgEntityProvider.ts +++ b/plugins/catalog-backend-module-msgraph/src/processors/MicrosoftGraphOrgEntityProvider.ts @@ -317,6 +317,7 @@ export class MicrosoftGraphOrgEntityProvider implements EntityProvider { groupFilter: provider.groupFilter, groupSearch: provider.groupSearch, groupSelect: provider.groupSelect, + groupIncludeSubGroups: provider.groupIncludeSubGroups, queryMode: provider.queryMode, groupTransformer: this.options.groupTransformer, userTransformer: this.options.userTransformer, From 24b3a3141b2eec8f89e4f76aa3cfc7328d28ea6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20St=C3=B6rkle?= Date: Mon, 19 Feb 2024 08:35:18 +0100 Subject: [PATCH 016/416] docs: document `includeSubGroups` config option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Florian Störkle --- docs/integrations/azure/org.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/integrations/azure/org.md b/docs/integrations/azure/org.md index 89abd4813b..b1719a63da 100644 --- a/docs/integrations/azure/org.md +++ b/docs/integrations/azure/org.md @@ -112,6 +112,17 @@ microsoftGraphOrg: search: '"description:One" AND ("displayName:Video" OR "displayName:Drive")' ``` +If you don't want to only ingest groups matching the `search` and/or `filter` query, but also the groups which are members of the matched groups, you can use the `includeSubGroups` configuration: + +```yaml +microsoftGraphOrg: + providerId: + group: + filter: securityEnabled eq false and mailEnabled eq true and groupTypes/any(c:c+eq+'Unified') + search: '"description:One" AND ("displayName:Video" OR "displayName:Drive")' + includeSubGroups: true +``` + In addition to these groups, one additional group will be created for your organization. All imported groups will be a child of this group. From d9cf697afda7543d72610e59f656ca05e2c9c3d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20St=C3=B6rkle?= Date: Mon, 19 Feb 2024 08:40:38 +0100 Subject: [PATCH 017/416] chore: generate API report MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Florian Störkle --- plugins/catalog-backend-module-msgraph/api-report.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/plugins/catalog-backend-module-msgraph/api-report.md b/plugins/catalog-backend-module-msgraph/api-report.md index 86170e2910..87402eedb1 100644 --- a/plugins/catalog-backend-module-msgraph/api-report.md +++ b/plugins/catalog-backend-module-msgraph/api-report.md @@ -39,10 +39,10 @@ export function defaultUserTransformer( // @public export type GroupMember = | (MicrosoftGraph.Group & { - '@odata.type': '#microsoft.graph.user'; + '@odata.type': '#microsoft.graph.group'; }) | (MicrosoftGraph.User & { - '@odata.type': '#microsoft.graph.group'; + '@odata.type': '#microsoft.graph.user'; }); // @public @@ -210,6 +210,7 @@ export type MicrosoftGraphProviderConfig = { groupFilter?: string; groupSearch?: string; groupSelect?: string[]; + groupIncludeSubGroups?: boolean; queryMode?: 'basic' | 'advanced'; loadUserPhotos?: boolean; schedule?: TaskScheduleDefinition; @@ -253,6 +254,7 @@ export function readMicrosoftGraphOrg( groupSearch?: string; groupFilter?: string; groupSelect?: string[]; + groupIncludeSubGroups?: boolean; queryMode?: 'basic' | 'advanced'; userTransformer?: UserTransformer; groupTransformer?: GroupTransformer; From 58dff4d5e574428090ec09a4fbc7de3e08224c4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20St=C3=B6rkle?= Date: Tue, 16 Apr 2024 10:01:13 +0200 Subject: [PATCH 018/416] chore: add changeset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Florian Störkle --- .changeset/little-suns-fly.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/little-suns-fly.md diff --git a/.changeset/little-suns-fly.md b/.changeset/little-suns-fly.md new file mode 100644 index 0000000000..887df4be6d --- /dev/null +++ b/.changeset/little-suns-fly.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend-module-msgraph': patch +--- + +Added option to ingest groups based on their group membership in Azure Entra ID From 4e4ef2ba78a8ead2fdf3bd674ac1ef5dcf313eb0 Mon Sep 17 00:00:00 2001 From: Heikki Hellgren Date: Wed, 5 Jun 2024 13:33:31 +0300 Subject: [PATCH 019/416] chore: move notification processor filters to common package Signed-off-by: Heikki Hellgren --- .changeset/weak-emus-doubt.md | 7 +++ .../processor/NotificationsEmailProcessor.ts | 30 ++---------- plugins/notifications-common/api-report.md | 14 ++++++ plugins/notifications-common/package.json | 1 + plugins/notifications-common/src/filters.ts | 47 +++++++++++++++++++ plugins/notifications-common/src/index.ts | 1 + plugins/notifications-common/src/types.ts | 9 ++++ plugins/notifications-node/api-report.md | 10 ++-- plugins/notifications-node/src/extensions.ts | 9 ++-- yarn.lock | 1 + 10 files changed, 89 insertions(+), 40 deletions(-) create mode 100644 .changeset/weak-emus-doubt.md create mode 100644 plugins/notifications-common/src/filters.ts diff --git a/.changeset/weak-emus-doubt.md b/.changeset/weak-emus-doubt.md new file mode 100644 index 0000000000..cd3b4a836b --- /dev/null +++ b/.changeset/weak-emus-doubt.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-notifications-backend-module-email': patch +'@backstage/plugin-notifications-common': patch +'@backstage/plugin-notifications-node': patch +--- + +Move notification processor filter parsing to common package diff --git a/plugins/notifications-backend-module-email/src/processor/NotificationsEmailProcessor.ts b/plugins/notifications-backend-module-email/src/processor/NotificationsEmailProcessor.ts index a78ebd3260..8689afc065 100644 --- a/plugins/notifications-backend-module-email/src/processor/NotificationsEmailProcessor.ts +++ b/plugins/notifications-backend-module-email/src/processor/NotificationsEmailProcessor.ts @@ -15,7 +15,6 @@ */ import { NotificationProcessor, - NotificationProcessorFilters, NotificationSendOptions, } from '@backstage/plugin-notifications-node'; import { @@ -30,9 +29,9 @@ import { CatalogClient, } from '@backstage/catalog-client'; import { + getProcessorFiltersFromConfig, Notification, - notificationSeverities, - NotificationSeverity, + NotificationProcessorFilters, } from '@backstage/plugin-notifications-common'; import { createSendmailTransport, @@ -86,30 +85,7 @@ export class NotificationsEmailProcessor implements NotificationProcessor { ? durationToMilliseconds(readDurationFromConfig(cacheConfig)) : 3_600_000; this.frontendBaseUrl = config.getString('app.baseUrl'); - this.filter = {}; - const minSeverity = emailProcessorConfig.getOptionalString( - 'filter.minSeverity', - ) as NotificationSeverity; - if (minSeverity) { - if (notificationSeverities.includes(minSeverity)) { - this.filter.minSeverity = minSeverity; - } else { - throw new Error(`Invalid minSeverity: ${minSeverity}`); - } - } - const maxSeverity = emailProcessorConfig.getOptionalString( - 'filter.maxSeverity', - ) as NotificationSeverity; - if (maxSeverity) { - if (notificationSeverities.includes(maxSeverity)) { - this.filter.maxSeverity = maxSeverity; - } else { - throw new Error(`Invalid maxSeverity: ${maxSeverity}`); - } - } - this.filter.excludedTopics = emailProcessorConfig.getOptionalStringArray( - 'filter.excludedTopics', - ); + this.filter = getProcessorFiltersFromConfig(emailProcessorConfig); } private async getTransporter() { diff --git a/plugins/notifications-common/api-report.md b/plugins/notifications-common/api-report.md index 3ddce24393..0f59a85849 100644 --- a/plugins/notifications-common/api-report.md +++ b/plugins/notifications-common/api-report.md @@ -3,6 +3,13 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +import { Config } from '@backstage/config'; + +// @public (undocumented) +export const getProcessorFiltersFromConfig: ( + config: Config, +) => NotificationProcessorFilters; + // @public (undocumented) export type NewNotificationSignal = { action: 'new_notification'; @@ -33,6 +40,13 @@ export type NotificationPayload = { icon?: string; }; +// @public (undocumented) +export type NotificationProcessorFilters = { + minSeverity?: NotificationSeverity; + maxSeverity?: NotificationSeverity; + excludedTopics?: string[]; +}; + // @public (undocumented) export type NotificationReadSignal = { action: 'notification_read' | 'notification_unread'; diff --git a/plugins/notifications-common/package.json b/plugins/notifications-common/package.json index 2745230a4a..eaec75cb5e 100644 --- a/plugins/notifications-common/package.json +++ b/plugins/notifications-common/package.json @@ -32,6 +32,7 @@ "test": "backstage-cli package test" }, "dependencies": { + "@backstage/config": "workspace:^", "@material-ui/icons": "^4.9.1" }, "devDependencies": { diff --git a/plugins/notifications-common/src/filters.ts b/plugins/notifications-common/src/filters.ts new file mode 100644 index 0000000000..725cfcf714 --- /dev/null +++ b/plugins/notifications-common/src/filters.ts @@ -0,0 +1,47 @@ +/* + * Copyright 2024 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 { Config } from '@backstage/config'; +import { NotificationProcessorFilters, NotificationSeverity } from './types'; +import { notificationSeverities } from './constants'; + +/** @public */ +export const getProcessorFiltersFromConfig = (config: Config) => { + const filter: NotificationProcessorFilters = {}; + const minSeverity = config.getOptionalString( + 'filter.minSeverity', + ) as NotificationSeverity; + if (minSeverity) { + if (notificationSeverities.includes(minSeverity)) { + filter.minSeverity = minSeverity; + } else { + throw new Error(`Invalid minSeverity: ${minSeverity}`); + } + } + const maxSeverity = config.getOptionalString( + 'filter.maxSeverity', + ) as NotificationSeverity; + if (maxSeverity) { + if (notificationSeverities.includes(maxSeverity)) { + filter.maxSeverity = maxSeverity; + } else { + throw new Error(`Invalid maxSeverity: ${maxSeverity}`); + } + } + filter.excludedTopics = config.getOptionalStringArray( + 'filter.excludedTopics', + ); + return filter; +}; diff --git a/plugins/notifications-common/src/index.ts b/plugins/notifications-common/src/index.ts index 7d74c75be8..9fc7bde2b8 100644 --- a/plugins/notifications-common/src/index.ts +++ b/plugins/notifications-common/src/index.ts @@ -22,3 +22,4 @@ export * from './types'; export * from './constants'; +export * from './filters'; diff --git a/plugins/notifications-common/src/types.ts b/plugins/notifications-common/src/types.ts index b9c9f63489..a4be3e4255 100644 --- a/plugins/notifications-common/src/types.ts +++ b/plugins/notifications-common/src/types.ts @@ -116,3 +116,12 @@ export type NotificationReadSignal = { /** @public */ export type NotificationSignal = NewNotificationSignal | NotificationReadSignal; + +/** + * @public + */ +export type NotificationProcessorFilters = { + minSeverity?: NotificationSeverity; + maxSeverity?: NotificationSeverity; + excludedTopics?: string[]; +}; diff --git a/plugins/notifications-node/api-report.md b/plugins/notifications-node/api-report.md index 27e6422f8a..37f28fec35 100644 --- a/plugins/notifications-node/api-report.md +++ b/plugins/notifications-node/api-report.md @@ -8,7 +8,7 @@ import { DiscoveryService } from '@backstage/backend-plugin-api'; import { ExtensionPoint } from '@backstage/backend-plugin-api'; import { Notification as Notification_2 } from '@backstage/plugin-notifications-common'; import { NotificationPayload } from '@backstage/plugin-notifications-common'; -import { NotificationSeverity } from '@backstage/plugin-notifications-common'; +import { NotificationProcessorFilters as NotificationProcessorFilters_2 } from '@backstage/plugin-notifications-common'; import { ServiceRef } from '@backstage/backend-plugin-api'; // @public (undocumented) @@ -38,12 +38,8 @@ export interface NotificationProcessor { ): Promise; } -// @public (undocumented) -export type NotificationProcessorFilters = { - minSeverity?: NotificationSeverity; - maxSeverity?: NotificationSeverity; - excludedTopics?: string[]; -}; +// @public @deprecated (undocumented) +export type NotificationProcessorFilters = NotificationProcessorFilters_2; // @public (undocumented) export type NotificationRecipients = diff --git a/plugins/notifications-node/src/extensions.ts b/plugins/notifications-node/src/extensions.ts index 7adb6caf50..03ce47fea6 100644 --- a/plugins/notifications-node/src/extensions.ts +++ b/plugins/notifications-node/src/extensions.ts @@ -16,7 +16,7 @@ import { createExtensionPoint } from '@backstage/backend-plugin-api'; import { Notification, - NotificationSeverity, + NotificationProcessorFilters as NotificationProcessorFiltersCommon, } from '@backstage/plugin-notifications-common'; import { NotificationSendOptions } from './service'; @@ -119,9 +119,6 @@ export const notificationsProcessingExtensionPoint = /** * @public + * @deprecated Please import from `@backstage/plugin-notifications-common` instead */ -export type NotificationProcessorFilters = { - minSeverity?: NotificationSeverity; - maxSeverity?: NotificationSeverity; - excludedTopics?: string[]; -}; +export type NotificationProcessorFilters = NotificationProcessorFiltersCommon; diff --git a/yarn.lock b/yarn.lock index 2ad2995d52..7c2b1ac7fe 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6240,6 +6240,7 @@ __metadata: resolution: "@backstage/plugin-notifications-common@workspace:plugins/notifications-common" dependencies: "@backstage/cli": "workspace:^" + "@backstage/config": "workspace:^" "@material-ui/icons": ^4.9.1 languageName: unknown linkType: soft From 3a5d011ded51423947b861f0d0b0663e34944a78 Mon Sep 17 00:00:00 2001 From: AmbrishRamachandiran Date: Fri, 7 Jun 2024 11:51:14 +0530 Subject: [PATCH 020/416] Updated docs of technical faq Signed-off-by: AmbrishRamachandiran --- docs/faq/technical.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/faq/technical.md b/docs/faq/technical.md index d64d81d499..32511351f0 100644 --- a/docs/faq/technical.md +++ b/docs/faq/technical.md @@ -116,7 +116,7 @@ This makes it easier to create, find, and update documentation. [TechDocs is now open source.](https://backstage.io/docs/features/techdocs/) (See also: "[Will Spotify's internal plugins be open sourced, too?](https://backstage.io/docs/faq/product#will-spotifys-internal-plugins-be-open-sourced-too)" -above) +above). ### Are you planning to have plugins baked into the repo? Or should they be developed in separate repos? From acf66e727a21ffce6797bb473eef7810dd863618 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl?= <61149845+RaphaelSve@users.noreply.github.com> Date: Mon, 10 Jun 2024 11:29:51 +0200 Subject: [PATCH 021/416] Update check-docs-quality.js MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add new regex for README files Signed-off-by: Raphaël <61149845+RaphaelSve@users.noreply.github.com> --- scripts/check-docs-quality.js | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/check-docs-quality.js b/scripts/check-docs-quality.js index 9a9336b3e9..0fd374ef23 100755 --- a/scripts/check-docs-quality.js +++ b/scripts/check-docs-quality.js @@ -30,6 +30,7 @@ const IGNORED_WHEN_LISTING = [ /^.*[/\\]knip-report\.md$/, /^docs[/\\]releases[/\\].*-changelog\.md$/, /^docs[/\\]reference[/\\]/, + /^README-[a-z]{2}_[A-Z]{2}\.md$/, ]; const IGNORED_WHEN_EXPLICIT = [ From ffdfd558980f0c9ec3005e16292f03860c728cf8 Mon Sep 17 00:00:00 2001 From: Jack Green Date: Tue, 11 Jun 2024 09:43:55 +0100 Subject: [PATCH 022/416] Update `README.md` FAQ link The [FAQ link](https://backstage.io/docs/FAQ) returns 404: ``` curl -I https://backstage.io/docs/FAQ HTTP/2 404 ``` It does redirect to [a working page](https://backstage.io/docs/FAQ), but intermediately shows a `Page Not Found` error. Signed-off-by: Jack Green --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 47ae539b6b..65b9187ac7 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ To engage with our community, you can use the following resources: - [Discord chatroom](https://discord.gg/backstage-687207715902193673) - Get support or discuss the project - [Contributing to Backstage](https://github.com/backstage/backstage/blob/master/CONTRIBUTING.md) - Start here if you want to contribute - [RFCs](https://github.com/backstage/backstage/labels/rfc) - Help shape the technical direction -- [FAQ](https://backstage.io/docs/FAQ) - Frequently Asked Questions +- [FAQ](https://backstage.io/docs/faq) - Frequently Asked Questions - [Code of Conduct](CODE_OF_CONDUCT.md) - This is how we roll - [Adopters](ADOPTERS.md) - Companies already using Backstage - [Blog](https://backstage.io/blog/) - Announcements and updates From 2b8b4f115a1f3052dc5db9ff14c33b8d0afd8d20 Mon Sep 17 00:00:00 2001 From: Niall Thomson Date: Tue, 11 Jun 2024 22:19:44 -0400 Subject: [PATCH 023/416] Removed code that catches error and formatted changeset markdown Signed-off-by: Niall Thomson --- .changeset/swift-kings-sparkle.md | 2 +- .../AwsOrganizationCloudAccountProcessor.ts | 36 +++++++++---------- 2 files changed, 17 insertions(+), 21 deletions(-) diff --git a/.changeset/swift-kings-sparkle.md b/.changeset/swift-kings-sparkle.md index 18a37b82f1..84ceae962b 100644 --- a/.changeset/swift-kings-sparkle.md +++ b/.changeset/swift-kings-sparkle.md @@ -2,4 +2,4 @@ '@backstage/plugin-catalog-backend-module-aws': patch --- -AwsOrganizationCloudAccountProcessor configuration field roleArn is deprecated in favor of new field accountId +`AwsOrganizationCloudAccountProcessor` configuration field `roleArn` is deprecated in favor of new field `accountId` diff --git a/plugins/catalog-backend-module-aws/src/processors/AwsOrganizationCloudAccountProcessor.ts b/plugins/catalog-backend-module-aws/src/processors/AwsOrganizationCloudAccountProcessor.ts index b843503a28..73d7a63e2b 100644 --- a/plugins/catalog-backend-module-aws/src/processors/AwsOrganizationCloudAccountProcessor.ts +++ b/plugins/catalog-backend-module-aws/src/processors/AwsOrganizationCloudAccountProcessor.ts @@ -106,27 +106,23 @@ export class AwsOrganizationCloudAccountProcessor implements CatalogProcessor { this.logger?.info('Discovering AWS Organization Account objects'); - try { - (await this.getAwsAccounts()) - .map(account => this.mapAccountToComponent(account)) - .filter(entity => { - if (location.target !== '') { - if (entity.metadata.annotations) { - return ( - entity.metadata.annotations[ORGANIZATION_ANNOTATION] === - location.target - ); - } - return false; + (await this.getAwsAccounts()) + .map(account => this.mapAccountToComponent(account)) + .filter(entity => { + if (location.target !== '') { + if (entity.metadata.annotations) { + return ( + entity.metadata.annotations[ORGANIZATION_ANNOTATION] === + location.target + ); } - return true; - }) - .forEach(entity => { - emit(processingResult.entity(location, entity)); - }); - } catch (e) { - this.logger?.error(e); - } + return false; + } + return true; + }) + .forEach(entity => { + emit(processingResult.entity(location, entity)); + }); return true; } From 0e61a3c09172129843b739ebfb5112b8b262f1d3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 12 Jun 2024 09:47:55 +0000 Subject: [PATCH 024/416] fix(deps): update dependency core-js to v3.37.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 2d508b5bff..869b26ae5e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -23630,9 +23630,9 @@ __metadata: linkType: hard "core-js@npm:^3.6.5": - version: 3.37.0 - resolution: "core-js@npm:3.37.0" - checksum: 212c3e9b3fc277dbb63739ef58a61c5709ccd0b36f09c3ce6946aa91fa180c60f57f976d4a5fdb9cda0c6cb55417379ba5a008fc3a1384ec94ec8ec61826469d + version: 3.37.1 + resolution: "core-js@npm:3.37.1" + checksum: 2d58a5c599f05c3e04abc8bc5e64b88eb17d914c0f552f670fb800afa74ec54b4fcc7f231ad6bd45badaf62c0fb0ce30e6fe89cedb6bb6d54e6f19115c3c17ff languageName: node linkType: hard From 6c5c94aaef0e1a668eee8acad4c17c75e671c1fb Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 12 Jun 2024 20:19:12 +0000 Subject: [PATCH 025/416] fix(deps): update material-ui monorepo to v5.15.20 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 60 +++++++++++++++++++++++++++---------------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/yarn.lock b/yarn.lock index 8e35710b7f..c0caa1600a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11019,23 +11019,23 @@ __metadata: languageName: node linkType: hard -"@mui/core-downloads-tracker@npm:^5.15.15": - version: 5.15.15 - resolution: "@mui/core-downloads-tracker@npm:5.15.15" - checksum: 3e99a04e03f66d5fa5f0c23cdce0f9fa2331ba08c99a75dc2347ccaa1c6ed520153e04aaeb0d613c9dca099a3e6242558a6284c33d93f95cc65e3243b17860bc +"@mui/core-downloads-tracker@npm:^5.15.20": + version: 5.15.20 + resolution: "@mui/core-downloads-tracker@npm:5.15.20" + checksum: 8cc71169ce1201c5a37fad6c5c58739850694e90c7bda636c692d47a79fd4c7884eab2c24b0084d6732a3d28c9a4a6d222dd5747f9d91f5075614700a3a3282a languageName: node linkType: hard "@mui/material@npm:^5.12.2": - version: 5.15.15 - resolution: "@mui/material@npm:5.15.15" + version: 5.15.20 + resolution: "@mui/material@npm:5.15.20" dependencies: "@babel/runtime": ^7.23.9 "@mui/base": 5.0.0-beta.40 - "@mui/core-downloads-tracker": ^5.15.15 - "@mui/system": ^5.15.15 + "@mui/core-downloads-tracker": ^5.15.20 + "@mui/system": ^5.15.20 "@mui/types": ^7.2.14 - "@mui/utils": ^5.15.14 + "@mui/utils": ^5.15.20 "@types/react-transition-group": ^4.4.10 clsx: ^2.1.0 csstype: ^3.1.3 @@ -11055,16 +11055,16 @@ __metadata: optional: true "@types/react": optional: true - checksum: ee0dc22fc4d617f7cf69f2451b6d5139978e6c5319e3056e7719159aff786ee3b80abd07691e230371811d9b5b574aef4559d7855bfe2f8493d596d960a91ab7 + checksum: 0d0e29682fa8f4ff03746efabb4b480da9dfe004e68982a36662ff0d40d76f5840ebf8ef3b0f9629056afb3030145dd5eb3bd2b0ab96d201fac7a300fef155b0 languageName: node linkType: hard -"@mui/private-theming@npm:^5.15.14": - version: 5.15.14 - resolution: "@mui/private-theming@npm:5.15.14" +"@mui/private-theming@npm:^5.15.20": + version: 5.15.20 + resolution: "@mui/private-theming@npm:5.15.20" dependencies: "@babel/runtime": ^7.23.9 - "@mui/utils": ^5.15.14 + "@mui/utils": ^5.15.20 prop-types: ^15.8.1 peerDependencies: "@types/react": ^17.0.0 || ^18.0.0 @@ -11072,7 +11072,7 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 1b1ef54e8281c9b13fcc58f4c39682efc610946a68402283c19fcfbce8a7d7a231d61b536d6df9bf7a59a1426591bd403a453a59eb8efb9689437fb58554dc8c + checksum: 5c70a9ebca3827cea11d67b3f8ed24d18a10c44f30f14d8d1c37b3f1e74d7a5e91cec5ffb7f24e8b2d974b38e4d046a93473c20a0cd7c7a880580e5df3d1afb7 languageName: node linkType: hard @@ -11098,14 +11098,14 @@ __metadata: linkType: hard "@mui/styles@npm:^5.14.18": - version: 5.15.15 - resolution: "@mui/styles@npm:5.15.15" + version: 5.15.20 + resolution: "@mui/styles@npm:5.15.20" dependencies: "@babel/runtime": ^7.23.9 "@emotion/hash": ^0.9.1 - "@mui/private-theming": ^5.15.14 + "@mui/private-theming": ^5.15.20 "@mui/types": ^7.2.14 - "@mui/utils": ^5.15.14 + "@mui/utils": ^5.15.20 clsx: ^2.1.0 csstype: ^3.1.3 hoist-non-react-statics: ^3.3.2 @@ -11124,19 +11124,19 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 5e436a8a22ae9a2e6fcb63ead3a6eff2092cc9731fce0b22d04ab9c67639a173a0e27fb617628e7720592862118a32248be458bedfabaf1de5448543a97b0307 + checksum: bdc19d66caf3fb3272dd1c67d6a40b0e77bca2c3c7a5b9112ebed2cf3d6795932401bcb9ddfb9daba9c3e293455cf9cb2c24975eff15c75a2ce3d40ed30d59d7 languageName: node linkType: hard -"@mui/system@npm:^5.15.15": - version: 5.15.15 - resolution: "@mui/system@npm:5.15.15" +"@mui/system@npm:^5.15.20": + version: 5.15.20 + resolution: "@mui/system@npm:5.15.20" dependencies: "@babel/runtime": ^7.23.9 - "@mui/private-theming": ^5.15.14 + "@mui/private-theming": ^5.15.20 "@mui/styled-engine": ^5.15.14 "@mui/types": ^7.2.14 - "@mui/utils": ^5.15.14 + "@mui/utils": ^5.15.20 clsx: ^2.1.0 csstype: ^3.1.3 prop-types: ^15.8.1 @@ -11152,7 +11152,7 @@ __metadata: optional: true "@types/react": optional: true - checksum: 9ca96d5f66b2a9d6471909cc98c671eea5ec0a6d58a7ec071073b9e5200b95c3f017f0ca5cc946abc7f83074bd11830ca18f5e30bc98e25cd6ca217bd1b3a26f + checksum: e9e79b6a905845aef87939de8ac7990d73a2f92bba02e41905dcb9f44e53727bdfa52a978cf59a2a2cfa73d2512df78c4351eb130d7c25af1880bb8b7ebfc686 languageName: node linkType: hard @@ -11168,9 +11168,9 @@ __metadata: languageName: node linkType: hard -"@mui/utils@npm:^5.14.15, @mui/utils@npm:^5.15.14": - version: 5.15.14 - resolution: "@mui/utils@npm:5.15.14" +"@mui/utils@npm:^5.14.15, @mui/utils@npm:^5.15.14, @mui/utils@npm:^5.15.20": + version: 5.15.20 + resolution: "@mui/utils@npm:5.15.20" dependencies: "@babel/runtime": ^7.23.9 "@types/prop-types": ^15.7.11 @@ -11182,7 +11182,7 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 36543ba7e3b65fb3219ed27e8f1455aff15b47a74c9b642c63e60774e22baa6492a196079e72bcfa5a570421dab32160398f892110bd444428bcf8b266b11893 + checksum: 8f8c7f9129e0eb1bf55c1d675c647da1fa4acf1c7f50e0ce2ce750cc0603e62fdc21b76e8ef8ff9bf06bce054e9cf97210ed737f55887b0ef939bd6605b4e537 languageName: node linkType: hard From 0568962439c3a91f1d1d43c53cd2302496d507a4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 12 Jun 2024 22:50:31 +0000 Subject: [PATCH 026/416] chore(deps): update alpine docker tag to v3.20 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- plugins/scaffolder-backend/scripts/Cookiecutter.dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/scaffolder-backend/scripts/Cookiecutter.dockerfile b/plugins/scaffolder-backend/scripts/Cookiecutter.dockerfile index ecaefee183..0c8b305de5 100644 --- a/plugins/scaffolder-backend/scripts/Cookiecutter.dockerfile +++ b/plugins/scaffolder-backend/scripts/Cookiecutter.dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.19 +FROM alpine:3.20 RUN apk add --update \ git \ From 605b6916cf153ea41106e3a09ef4b33fd42abc4f Mon Sep 17 00:00:00 2001 From: "Stephen A. Wilson" Date: Thu, 13 Jun 2024 10:58:22 -0400 Subject: [PATCH 027/416] Allow for searching TechDocs by Title Signed-off-by: Stephen A. Wilson --- .changeset/fuzzy-socks-do.md | 6 + app-config.yaml | 3 + .../catalog-info.yaml | 12 ++ .../docs/code/code-sample.md | 31 +++++ .../docs/extensions.md | 112 ++++++++++++++++++ .../docs/images/backstage-logo-cncf.svg | 1 + .../docs/index.md | 55 +++++++++ .../docs/sub-page.md | 12 ++ .../mkdocs.yml | 12 ++ .../src/home/components/Tables/DocsTable.tsx | 1 + .../src/home/components/Tables/columns.tsx | 34 +++++- 11 files changed, 274 insertions(+), 5 deletions(-) create mode 100644 .changeset/fuzzy-socks-do.md create mode 100644 plugins/techdocs-backend/examples/documented-component-with-title/catalog-info.yaml create mode 100644 plugins/techdocs-backend/examples/documented-component-with-title/docs/code/code-sample.md create mode 100644 plugins/techdocs-backend/examples/documented-component-with-title/docs/extensions.md create mode 100644 plugins/techdocs-backend/examples/documented-component-with-title/docs/images/backstage-logo-cncf.svg create mode 100644 plugins/techdocs-backend/examples/documented-component-with-title/docs/index.md create mode 100644 plugins/techdocs-backend/examples/documented-component-with-title/docs/sub-page.md create mode 100644 plugins/techdocs-backend/examples/documented-component-with-title/mkdocs.yml diff --git a/.changeset/fuzzy-socks-do.md b/.changeset/fuzzy-socks-do.md new file mode 100644 index 0000000000..02d2e4dca9 --- /dev/null +++ b/.changeset/fuzzy-socks-do.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-techdocs-backend': patch +'@backstage/plugin-techdocs': patch +--- + +Allow for searching TechDocs by entity title diff --git a/app-config.yaml b/app-config.yaml index cb70170541..69145cd896 100644 --- a/app-config.yaml +++ b/app-config.yaml @@ -297,6 +297,9 @@ catalog: # Example component for TechDocs - type: file target: ../../plugins/techdocs-backend/examples/documented-component/catalog-info.yaml + # Example component for TechDocs with a title + - type: file + target: ../../plugins/techdocs-backend/examples/documented-component-with-title/catalog-info.yaml # Example component for ADRs - type: file target: ../../plugins/adr/examples/component/catalog-info.yaml diff --git a/plugins/techdocs-backend/examples/documented-component-with-title/catalog-info.yaml b/plugins/techdocs-backend/examples/documented-component-with-title/catalog-info.yaml new file mode 100644 index 0000000000..1a1d65ba39 --- /dev/null +++ b/plugins/techdocs-backend/examples/documented-component-with-title/catalog-info.yaml @@ -0,0 +1,12 @@ +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: documented-with-title + title: Fizzbuzz Docs + description: A TechDocs with a title different than it's name + annotations: + backstage.io/techdocs-ref: dir:. +spec: + type: service + lifecycle: experimental + owner: user:guest diff --git a/plugins/techdocs-backend/examples/documented-component-with-title/docs/code/code-sample.md b/plugins/techdocs-backend/examples/documented-component-with-title/docs/code/code-sample.md new file mode 100644 index 0000000000..f41ab1d506 --- /dev/null +++ b/plugins/techdocs-backend/examples/documented-component-with-title/docs/code/code-sample.md @@ -0,0 +1,31 @@ +# Sample Code + +This page provides some sample code which may be used in your example component. + +This code uses TypeScript, and the Markdown code fence to wrap the code. + +```typescript +const serviceEntityPage = ( + + + + + + + + + + + + +); +``` + +Here is an example of Python code: + +```python +def getUsersInGroup(targetGroup, secure=False): + + if __debug__: + print('targetGroup=[' + targetGroup + ']') +``` diff --git a/plugins/techdocs-backend/examples/documented-component-with-title/docs/extensions.md b/plugins/techdocs-backend/examples/documented-component-with-title/docs/extensions.md new file mode 100644 index 0000000000..eb9abca74a --- /dev/null +++ b/plugins/techdocs-backend/examples/documented-component-with-title/docs/extensions.md @@ -0,0 +1,112 @@ +# Plugins & Extensions + +Just by including the TechDocs Core Plugin to your MkDocs site included with Backstage, +you gain the immediate use of a variety of popular plugins and extensions to MkDocs. + +For more information and full details of the available features, see the +[`mkdocs-techdocs-core` repository](https://github.com/backstage/mkdocs-techdocs-core#mkdocs-plugins-and-extensions). + +This page provides a demonstration of some of the available features. + +## Admonitions + +Admonitions are call outs that help catch a users attention. + +To define an admonition simply put the following Markdown into your content: + +``` +!!! warn + Defining admonitions can be addicting. +``` + +And they end up looking like this: + + +!!! warn + Defining admonitions can be addicting. + + +!!! note + You can learn a lot about TechDocs by just visiting the Backstage web site at + https://backstage.io/docs. + + +!!! info + TechDocs is the core feature that supports documentation as code in Backstage. + + +!!! tip + Don't forget to spell check your documentation. + +## PlantUML + +You can create dynamic UML diagrams on the fly by just specifying flow via text, +using [PlantUML](https://pypi.org/project/plantuml-markdown/). + +```plantuml format="svg" classes="uml myDiagram" alt="Backstage sample PlantUML" title="Backstage sample PlantUML" width="500px" height="250px" +User -> SCMProvider: stores +TechDocs -> SCMProvider: prepares +TechDocs -> TechDocs: generates +TechDocs -> CloudStorage: publishes +CloudStorage -> Backstage: displays +``` + +## Pymdownx Extensions + +Pymdownx (Python Markdown extensions) are a variety of smaller additions. + +### Details + + +??? note "What is the answer to life, the universe, and everything? (click me for the answer)" + The answer is 42. + + +??? note "What is 4 plus 4?" + The answer is 8. + + +???+ note "How do I get support?" + You can get support by opening an issue in this repository. This detail is open by default + so it's more easily visible without requiring the user to click to open it. + +### Task Lists + +Automatic rendering of Markdown task lists. + +- [x] Phase 1 +- [x] Phase 2 +- [ ] Phase 3 + +### Emojis + +Very nice job on documentation! :thumbsup: + +I've read a lot of documentation, but I love :heart: this document. + +Weather: :sunny: :umbrella: :cloud: :snowflake: + +Animals: :tiger: :horse: :turtle: :wolf: :frog: + +### Attributes + +[A Download Link](./images/backstage-logo-cncf.svg){: download } + +![A Scaled Image](./images/backstage-logo-cncf.svg){: style="width: 100px" } + +### MDX truly sane lists + +- `attributes` + +- `customer` + - `first_name` + - `test` + - `family_name` + - `email` +- `person` + - `first_name` + - `family_name` + - `birth_date` +- `subscription_id` + +- `request` diff --git a/plugins/techdocs-backend/examples/documented-component-with-title/docs/images/backstage-logo-cncf.svg b/plugins/techdocs-backend/examples/documented-component-with-title/docs/images/backstage-logo-cncf.svg new file mode 100644 index 0000000000..b5ff591d1b --- /dev/null +++ b/plugins/techdocs-backend/examples/documented-component-with-title/docs/images/backstage-logo-cncf.svg @@ -0,0 +1 @@ +05 Logo_Black \ No newline at end of file diff --git a/plugins/techdocs-backend/examples/documented-component-with-title/docs/index.md b/plugins/techdocs-backend/examples/documented-component-with-title/docs/index.md new file mode 100644 index 0000000000..6295a69406 --- /dev/null +++ b/plugins/techdocs-backend/examples/documented-component-with-title/docs/index.md @@ -0,0 +1,55 @@ +# Welcome! + +This is a basic example of documentation. It is intended as a showcase of some of the +features that TechDocs provides out of the box. + +You can see also: + +- [A sub page](sub-page.md) +- [Inline code examples](code/code-sample.md) +- [Plugin & Extension examples](extensions.md) - Diagrams, emojis, visual formatting. + +## Basic Markdown + +Headings: + +# h1 + +## h2 + +### h3 + +#### h4 + +##### h5 + +###### h6 + +Here is a bulleted list: + +- Item one +- Item two +- Item Three + +Check out the [Markdown Guide](https://www.markdownguide.org/) to learn more about how to +simply create documentation. + +You can also learn more about how to configure and setup this documentation in Backstage, +[read up on the TechDocs Overview](https://backstage.io/docs/features/techdocs/). + +## Image Example + +This documentation is powered by Backstage's TechDocs feature: + +![Backstage Logo](images/backstage-logo-cncf.svg) + +## Table Example + +While this documentation isn't comprehensive, in the future it should cover the following +topics outlined in this example table: + +| Topic | Description | +| ------- | ------------------------------------------------------------ | +| Topic 1 | An introductory topic to help you learn about the component. | +| Topic 2 | A more detailed topic that explains more information. | +| Topic 3 | A final topic that provides conclusions and lessons learned. | diff --git a/plugins/techdocs-backend/examples/documented-component-with-title/docs/sub-page.md b/plugins/techdocs-backend/examples/documented-component-with-title/docs/sub-page.md new file mode 100644 index 0000000000..987f5e8a95 --- /dev/null +++ b/plugins/techdocs-backend/examples/documented-component-with-title/docs/sub-page.md @@ -0,0 +1,12 @@ +# Another page in our documentation + +This sub-page can be used to elaborate on a specific part of the component. + +## Details + +It is linked off the main page, and due to its inclusion in the `mkdocs.yml` file, +becomes part of the auto-generated site navigation. + +## MkDocs + +Visit https://www.mkdocs.org for more information about the MkDocs tool. diff --git a/plugins/techdocs-backend/examples/documented-component-with-title/mkdocs.yml b/plugins/techdocs-backend/examples/documented-component-with-title/mkdocs.yml new file mode 100644 index 0000000000..1a159a4d12 --- /dev/null +++ b/plugins/techdocs-backend/examples/documented-component-with-title/mkdocs.yml @@ -0,0 +1,12 @@ +site_name: 'Example Documentation' +repo_url: https://github.com/backstage/backstage +edit_uri: edit/master/plugins/techdocs-backend/examples/documented-component/docs + +nav: + - Home: index.md + - Subpage: sub-page.md + - 'Code Sample': code/code-sample.md + - Extensions: extensions.md + +plugins: + - techdocs-core diff --git a/plugins/techdocs/src/home/components/Tables/DocsTable.tsx b/plugins/techdocs/src/home/components/Tables/DocsTable.tsx index c0b39878cd..59abd9b278 100644 --- a/plugins/techdocs/src/home/components/Tables/DocsTable.tsx +++ b/plugins/techdocs/src/home/components/Tables/DocsTable.tsx @@ -85,6 +85,7 @@ export const DocsTable = (props: DocsTableProps) => { }); const defaultColumns: TableColumn[] = [ + columnFactories.createTitleColumn({ hidden: true }), columnFactories.createNameColumn(), columnFactories.createOwnerColumn(), columnFactories.createKindColumn(), diff --git a/plugins/techdocs/src/home/components/Tables/columns.tsx b/plugins/techdocs/src/home/components/Tables/columns.tsx index bc85bb7a63..3deb4d9b33 100644 --- a/plugins/techdocs/src/home/components/Tables/columns.tsx +++ b/plugins/techdocs/src/home/components/Tables/columns.tsx @@ -24,17 +24,20 @@ function customTitle(entity: Entity): string { return entity.metadata.title || entity.metadata.name; } +type ColumnOptions = Partial>; + /** * Not directly exported, but through DocsTable.columns and EntityListDocsTable.columns * * @public */ export const columnFactories = { - createNameColumn(): TableColumn { + createTitleColumn(overrides: ColumnOptions = {}): TableColumn { return { title: 'Document', - field: 'entity.metadata.name', + field: 'entity.metadata.title', highlight: true, + searchable: true, render: (row: DocsTableRow) => ( ), + ...overrides, }; }, - createOwnerColumn(): TableColumn { + createNameColumn(overrides: ColumnOptions = {}): TableColumn { + return { + title: 'Document', + field: 'entity.metadata.name', + highlight: true, + searchable: true, + render: (row: DocsTableRow) => ( + {customTitle(row.entity)} + } + subvalue={row.entity.metadata.description} + /> + ), + ...overrides, + }; + }, + createOwnerColumn(overrides: ColumnOptions = {}): TableColumn { return { title: 'Owner', field: 'resolved.ownedByRelationsTitle', @@ -55,18 +76,21 @@ export const columnFactories = { defaultKind="group" /> ), + ...overrides, }; }, - createKindColumn(): TableColumn { + createKindColumn(overrides: ColumnOptions = {}): TableColumn { return { title: 'Kind', field: 'entity.kind', + ...overrides, }; }, - createTypeColumn(): TableColumn { + createTypeColumn(overrides: ColumnOptions = {}): TableColumn { return { title: 'Type', field: 'entity.spec.type', + ...overrides, }; }, }; From edcd757d14708cb8de75278dd28a7d9c68a6dbe0 Mon Sep 17 00:00:00 2001 From: "Stephen A. Wilson" Date: Thu, 13 Jun 2024 11:13:36 -0400 Subject: [PATCH 028/416] remove techdocs-backend from changeset Signed-off-by: Stephen A. Wilson --- .changeset/fuzzy-socks-do.md | 1 - 1 file changed, 1 deletion(-) diff --git a/.changeset/fuzzy-socks-do.md b/.changeset/fuzzy-socks-do.md index 02d2e4dca9..aabc10f0cd 100644 --- a/.changeset/fuzzy-socks-do.md +++ b/.changeset/fuzzy-socks-do.md @@ -1,5 +1,4 @@ --- -'@backstage/plugin-techdocs-backend': patch '@backstage/plugin-techdocs': patch --- From e9551a759824d57c4c8a62dd832de4e65e27d253 Mon Sep 17 00:00:00 2001 From: "Stephen A. Wilson" Date: Thu, 13 Jun 2024 13:05:09 -0400 Subject: [PATCH 029/416] revert changes to match prior work in CatalogTable Signed-off-by: Stephen A. Wilson --- plugins/techdocs/api-report.md | 14 ++++++++++++++ .../src/home/components/Tables/columns.tsx | 18 ++++++------------ 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/plugins/techdocs/api-report.md b/plugins/techdocs/api-report.md index ebd6adcd3c..90834c6fcb 100644 --- a/plugins/techdocs/api-report.md +++ b/plugins/techdocs/api-report.md @@ -78,6 +78,13 @@ export type DocsGroupConfig = { export const DocsTable: { (props: DocsTableProps): React_2.JSX.Element | null; columns: { + createTitleColumn( + options?: + | { + hidden?: boolean | undefined; + } + | undefined, + ): TableColumn; createNameColumn(): TableColumn; createOwnerColumn(): TableColumn; createKindColumn(): TableColumn; @@ -142,6 +149,13 @@ export type EntityListDocsGridPageProps = { export const EntityListDocsTable: { (props: EntityListDocsTableProps): React_2.JSX.Element; columns: { + createTitleColumn( + options?: + | { + hidden?: boolean | undefined; + } + | undefined, + ): TableColumn; createNameColumn(): TableColumn; createOwnerColumn(): TableColumn; createKindColumn(): TableColumn; diff --git a/plugins/techdocs/src/home/components/Tables/columns.tsx b/plugins/techdocs/src/home/components/Tables/columns.tsx index 3deb4d9b33..b9d22705d3 100644 --- a/plugins/techdocs/src/home/components/Tables/columns.tsx +++ b/plugins/techdocs/src/home/components/Tables/columns.tsx @@ -24,18 +24,17 @@ function customTitle(entity: Entity): string { return entity.metadata.title || entity.metadata.name; } -type ColumnOptions = Partial>; - /** * Not directly exported, but through DocsTable.columns and EntityListDocsTable.columns * * @public */ export const columnFactories = { - createTitleColumn(overrides: ColumnOptions = {}): TableColumn { + createTitleColumn(options?: { hidden?: boolean }): TableColumn { return { title: 'Document', field: 'entity.metadata.title', + hidden: options?.hidden, highlight: true, searchable: true, render: (row: DocsTableRow) => ( @@ -46,10 +45,9 @@ export const columnFactories = { subvalue={row.entity.metadata.description} /> ), - ...overrides, }; }, - createNameColumn(overrides: ColumnOptions = {}): TableColumn { + createNameColumn(): TableColumn { return { title: 'Document', field: 'entity.metadata.name', @@ -63,10 +61,9 @@ export const columnFactories = { subvalue={row.entity.metadata.description} /> ), - ...overrides, }; }, - createOwnerColumn(overrides: ColumnOptions = {}): TableColumn { + createOwnerColumn(): TableColumn { return { title: 'Owner', field: 'resolved.ownedByRelationsTitle', @@ -76,21 +73,18 @@ export const columnFactories = { defaultKind="group" /> ), - ...overrides, }; }, - createKindColumn(overrides: ColumnOptions = {}): TableColumn { + createKindColumn(): TableColumn { return { title: 'Kind', field: 'entity.kind', - ...overrides, }; }, - createTypeColumn(overrides: ColumnOptions = {}): TableColumn { + createTypeColumn(): TableColumn { return { title: 'Type', field: 'entity.spec.type', - ...overrides, }; }, }; From a5576b2f024761f714886fed15d89e07da7724ad Mon Sep 17 00:00:00 2001 From: Jente Sondervorst Date: Sat, 15 Jun 2024 22:41:39 +0200 Subject: [PATCH 030/416] Added support for only users or only groups and multiple users or multiple groups bindings Closes: #25256 Signed-off-by: Jente Sondervorst --- .changeset/friendly-bulldogs-pay.md | 5 + .../src/ldap/config.test.ts | 68 ++++++++-- .../src/ldap/config.ts | 78 +++++++++--- .../src/ldap/read.test.ts | 118 +++++++++++++++++- .../src/ldap/read.ts | 86 +++++++------ 5 files changed, 298 insertions(+), 57 deletions(-) create mode 100644 .changeset/friendly-bulldogs-pay.md diff --git a/.changeset/friendly-bulldogs-pay.md b/.changeset/friendly-bulldogs-pay.md new file mode 100644 index 0000000000..9c7ab8f9cb --- /dev/null +++ b/.changeset/friendly-bulldogs-pay.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend-module-ldap': minor +--- + +Added support for single ldap catalog provider to provide list and undefined user and group bindings next to standard single one. diff --git a/plugins/catalog-backend-module-ldap/src/ldap/config.test.ts b/plugins/catalog-backend-module-ldap/src/ldap/config.test.ts index ddea9de03f..8cd41e0b70 100644 --- a/plugins/catalog-backend-module-ldap/src/ldap/config.test.ts +++ b/plugins/catalog-backend-module-ldap/src/ldap/config.test.ts @@ -15,7 +15,7 @@ */ import { ConfigReader } from '@backstage/config'; -import { readProviderConfigs } from './config'; +import { readProviderConfigs, UserConfig } from './config'; describe('readLdapConfig', () => { it('applies all of the defaults', () => { @@ -247,7 +247,7 @@ describe('readLdapConfig', () => { const actual = readProviderConfigs(new ConfigReader(config)); const expected = '(|(cn=foo bar)(cn=bar))'; - expect(actual[0].users.options.filter).toEqual(expected); + expect((actual[0].users!! as UserConfig).options.filter).toEqual(expected); }); it('supports a dot nested set structure', () => { @@ -284,7 +284,9 @@ describe('readLdapConfig', () => { }; const actual = readProviderConfigs(new ConfigReader(config)); - expect(actual[0].users.set).toEqual({ 'metadata.annotations': { a: 'b' } }); + expect((actual[0].users!! as UserConfig).set).toEqual({ + 'metadata.annotations': { a: 'b' }, + }); }); it('throws on attempts to modify the set structure', () => { @@ -320,25 +322,77 @@ describe('readLdapConfig', () => { const actual = readProviderConfigs(new ConfigReader(config)); expect(() => { - (actual[0].users.set as any).y = 2; + ((actual[0].users!! as UserConfig).set as any).y = 2; }).toThrowErrorMatchingInlineSnapshot( `"Cannot add property y, object is not extensible"`, ); expect(() => { - (actual[0].users.set as any).x.b = 2; + ((actual[0].users!! as UserConfig).set as any).x.b = 2; }).toThrowErrorMatchingInlineSnapshot( `"Cannot add property b, object is not extensible"`, ); expect(() => { - (actual[0].groups.set as any).y = 2; + ((actual[0].users!! as UserConfig).set as any).y = 2; }).toThrowErrorMatchingInlineSnapshot( `"Cannot add property y, object is not extensible"`, ); expect(() => { - (actual[0].groups.set as any).x.b = 2; + ((actual[0].users!! as UserConfig).set as any).x.b = 2; }).toThrowErrorMatchingInlineSnapshot( `"Cannot add property b, object is not extensible"`, ); }); + + it('supports users/groups config as list', () => { + const config = { + catalog: { + providers: { + ldapOrg: { + default: { + target: 'target', + users: [ + { + dn: 'udn1', + }, + { + dn: 'udn2', + }, + ], + groups: [ + { + dn: 'gdn1', + }, + { + dn: 'gdn2', + }, + ], + }, + }, + }, + }, + }; + const actual = readProviderConfigs(new ConfigReader(config)); + + expect(actual[0].users).toHaveLength(2); + expect(actual[0].groups).toHaveLength(2); + }); + + it('supports users/groups config as undefined', () => { + const config = { + catalog: { + providers: { + ldapOrg: { + default: { + target: 'target', + }, + }, + }, + }, + }; + const actual = readProviderConfigs(new ConfigReader(config)); + + expect(actual[0].users).toBeUndefined(); + expect(actual[0].groups).toBeUndefined(); + }); }); diff --git a/plugins/catalog-backend-module-ldap/src/ldap/config.ts b/plugins/catalog-backend-module-ldap/src/ldap/config.ts index 2bd21fd166..7a5b2828e2 100644 --- a/plugins/catalog-backend-module-ldap/src/ldap/config.ts +++ b/plugins/catalog-backend-module-ldap/src/ldap/config.ts @@ -42,9 +42,9 @@ export type LdapProviderConfig = { // command is not issued. bind?: BindConfig; // The settings that govern the reading and interpretation of users - users: UserConfig; + users: UserConfigList; // The settings that govern the reading and interpretation of groups - groups: GroupConfig; + groups: GroupConfigList; // Schedule configuration for refresh tasks. schedule?: TaskScheduleDefinition; }; @@ -81,6 +81,8 @@ export type BindConfig = { * * @public */ +export type UserConfigList = UserConfig | UserConfig[] | undefined; + export type UserConfig = { // The DN under which users are stored. dn: string; @@ -121,6 +123,8 @@ export type UserConfig = { * * @public */ +export type GroupConfigList = GroupConfig | GroupConfig[] | undefined; + export type GroupConfig = { // The DN under which groups are stored. dn: string; @@ -272,9 +276,7 @@ function readSetConfig( return c.get(); } -function readUserMapConfig( - c: Config | undefined, -): Partial { +function readUserMapConfig(c: Config | undefined): Partial { if (!c) { return {}; } @@ -292,7 +294,7 @@ function readUserMapConfig( function readGroupMapConfig( c: Config | undefined, -): Partial { +): Partial { if (!c) { return {}; } @@ -311,8 +313,21 @@ function readGroupMapConfig( } function readUserConfig( - c: Config, + c: Config | Config[] | undefined, ): RecursivePartial { + if (!c) { + return undefined; + } + if (Array.isArray(c)) { + return c.map(it => { + return { + dn: it.getString('dn'), + options: readOptionsConfig(it.getOptionalConfig('options')), + set: readSetConfig(it.getOptionalConfig('set')), + map: readUserMapConfig(it.getOptionalConfig('map')), + }; + }); + } return { dn: c.getString('dn'), options: readOptionsConfig(c.getOptionalConfig('options')), @@ -322,8 +337,21 @@ function readUserConfig( } function readGroupConfig( - c: Config, + c: Config | Config[] | undefined, ): RecursivePartial { + if (!c) { + return undefined; + } + if (Array.isArray(c)) { + return c.map(it => { + return { + dn: it.getString('dn'), + options: readOptionsConfig(it.getOptionalConfig('options')), + set: readSetConfig(it.getOptionalConfig('set')), + map: readGroupMapConfig(it.getOptionalConfig('map')), + }; + }); + } return { dn: c.getString('dn'), options: readOptionsConfig(c.getOptionalConfig('options')), @@ -383,19 +411,41 @@ export function readProviderConfigs(config: Config): LdapProviderConfig[] { ? readTaskScheduleDefinitionFromConfig(c.getConfig('schedule')) : undefined; + const isUserList = Array.isArray(c.getOptional('users')); + const isGroupList = Array.isArray(c.getOptional('groups')); + const newConfig = { id, target: trimEnd(c.getString('target'), '/'), tls: readTlsConfig(c.getOptionalConfig('tls')), bind: readBindConfig(c.getOptionalConfig('bind')), - users: readUserConfig(c.getConfig('users')), - groups: readGroupConfig(c.getConfig('groups')), + users: readUserConfig( + isUserList + ? c.getOptionalConfigArray('users') + : c.getOptionalConfig('users'), + ), + groups: readGroupConfig( + isGroupList + ? c.getOptionalConfigArray('groups') + : c.getOptionalConfig('groups'), + ), schedule, }; - const merged = mergeWith({}, defaultConfig, newConfig, (_into, from) => { - // Replace arrays instead of merging, otherwise default behavior - return Array.isArray(from) ? from : undefined; - }); + + const merged = mergeWith( + {}, + defaultConfig, + newConfig, + (_value, srcValue, key, object, _source) => { + // Remove users and groups from default if they are not set in the new config + if ((key === 'users' || key === 'groups') && !srcValue) { + return (object[key] = srcValue); + } + // Replace arrays instead of merging, otherwise default behavior + return Array.isArray(srcValue) ? srcValue : undefined; + }, + ); + return freeze(merged) as LdapProviderConfig; }); } diff --git a/plugins/catalog-backend-module-ldap/src/ldap/read.test.ts b/plugins/catalog-backend-module-ldap/src/ldap/read.test.ts index fc451fde97..33c52477aa 100644 --- a/plugins/catalog-backend-module-ldap/src/ldap/read.test.ts +++ b/plugins/catalog-backend-module-ldap/src/ldap/read.test.ts @@ -18,7 +18,12 @@ import { GroupEntity, UserEntity } from '@backstage/catalog-model'; import { SearchEntry } from 'ldapjs'; import merge from 'lodash/merge'; import { LdapClient } from './client'; -import { GroupConfig, UserConfig } from './config'; +import { + GroupConfig, + GroupConfigList, + UserConfig, + UserConfigList, +} from './config'; import { LDAP_DN_ANNOTATION, LDAP_RDN_ANNOTATION, @@ -255,6 +260,58 @@ describe('readLdapUsers', () => { new Map([['dn-value', new Set(['x', 'y', 'z'])]]), ); }); + it('can process a list of UserConfigs', async () => { + client.getVendor.mockResolvedValue(DefaultLdapVendor); + client.searchStreaming.mockImplementation(async (_dn, _opts, fn) => { + await fn( + searchEntry({ + uid: ['uid-value'], + description: ['description-value'], + cn: ['cn-value'], + mail: ['mail-value'], + avatarUrl: ['avatarUrl-value'], + memberOf: ['x', 'y', 'z'], + entryDN: ['dn-value'], + entryUUID: ['uuid-value'], + }), + ); + }); + const config: UserConfigList = [ + { + dn: 'ddd', + options: {}, + map: { + rdn: 'uid', + name: 'uid', + description: 'description', + displayName: 'cn', + email: 'mail', + picture: 'avatarUrl', + memberOf: 'memberOf', + }, + }, + { + dn: 'ddd', + options: {}, + map: { + rdn: 'uid', + name: 'uid', + description: 'description', + displayName: 'cn', + email: 'mail', + picture: 'avatarUrl', + memberOf: 'memberOf', + }, + }, + ]; + const { users } = await readLdapUsers(client, config); + expect(users).toHaveLength(2); + }); + it('can process no UserConfigs', async () => { + const config: UserConfigList = undefined; + const { users } = await readLdapUsers(client, config); + expect(users).toHaveLength(0); + }); }); describe('readLdapGroups', () => { @@ -401,6 +458,65 @@ describe('readLdapGroups', () => { new Map([['dn-value', new Set(['x', 'y', 'z'])]]), ); }); + + it('can process a list of GroupConfigs', async () => { + client.getVendor.mockResolvedValue(DefaultLdapVendor); + client.searchStreaming.mockImplementation(async (_dn, _opts, fn) => { + await fn( + searchEntry({ + cn: ['cn-value'], + description: ['description-value'], + tt: ['type-value'], + mail: ['mail-value'], + avatarUrl: ['avatarUrl-value'], + memberOf: ['x', 'y', 'z'], + member: ['e', 'f', 'g'], + entryDN: ['dn-value'], + entryUUID: ['uuid-value'], + }), + ); + }); + const config: GroupConfigList = [ + { + dn: 'ddd', + options: {}, + map: { + rdn: 'cn', + name: 'cn', + description: 'description', + displayName: 'cn', + email: 'mail', + picture: 'avatarUrl', + type: 'tt', + memberOf: 'memberOf', + members: 'member', + }, + }, + { + dn: 'ddd', + options: {}, + map: { + rdn: 'cn', + name: 'cn', + description: 'description', + displayName: 'cn', + email: 'mail', + picture: 'avatarUrl', + type: 'tt', + memberOf: 'memberOf', + members: 'member', + }, + }, + ]; + const { groups } = await readLdapGroups(client, config); + expect(groups).toHaveLength(2); + }); + + it('can process no GroupConfigs', async () => { + const config: GroupConfigList = undefined; + const { groups } = await readLdapGroups(client, config); + expect(groups).toHaveLength(0); + }); }); describe('resolveRelations', () => { diff --git a/plugins/catalog-backend-module-ldap/src/ldap/read.ts b/plugins/catalog-backend-module-ldap/src/ldap/read.ts index 50036b94b0..5dadcaede2 100644 --- a/plugins/catalog-backend-module-ldap/src/ldap/read.ts +++ b/plugins/catalog-backend-module-ldap/src/ldap/read.ts @@ -24,7 +24,12 @@ import lodashSet from 'lodash/set'; import cloneDeep from 'lodash/cloneDeep'; import { buildOrgHierarchy } from './org'; import { LdapClient } from './client'; -import { GroupConfig, UserConfig } from './config'; +import { + GroupConfig, + GroupConfigList, + UserConfig, + UserConfigList, +} from './config'; import { LDAP_DN_ANNOTATION, LDAP_RDN_ANNOTATION, @@ -104,32 +109,37 @@ export async function defaultUserTransformer( */ export async function readLdapUsers( client: LdapClient, - config: UserConfig, + config: UserConfigList, opts?: { transformer?: UserTransformer }, ): Promise<{ users: UserEntity[]; // With all relations empty userMemberOf: Map>; // DN -> DN or UUID of groups }> { - const { dn, options, map } = config; - const vendor = await client.getVendor(); - + if (!config) { + return { users: [], userMemberOf: new Map() }; + } + const configs = Array.isArray(config) ? config : [config]; const entities: UserEntity[] = []; const userMemberOf: Map> = new Map(); + const vendor = await client.getVendor(); const transformer = opts?.transformer ?? defaultUserTransformer; - await client.searchStreaming(dn, options, async user => { - const entity = await transformer(vendor, config, user); + for (const cfg of configs) { + const { dn, options, map } = cfg; + await client.searchStreaming(dn, options, async user => { + const entity = await transformer(vendor, cfg, user); - if (!entity) { - return; - } + if (!entity) { + return; + } - mapReferencesAttr(user, vendor, map.memberOf, (myDn, vs) => { - ensureItems(userMemberOf, myDn, vs); + mapReferencesAttr(user, vendor, map.memberOf, (myDn, vs) => { + ensureItems(userMemberOf, myDn, vs); + }); + entities.push(entity); }); - entities.push(entity); - }); + } return { users: entities, userMemberOf }; } @@ -206,7 +216,7 @@ export async function defaultGroupTransformer( */ export async function readLdapGroups( client: LdapClient, - config: GroupConfig, + config: GroupConfigList, opts?: { transformer?: GroupTransformer; }, @@ -215,35 +225,41 @@ export async function readLdapGroups( groupMemberOf: Map>; // DN -> DN or UUID of groups groupMember: Map>; // DN -> DN or UUID of groups & users }> { + if (!config) { + return { groups: [], groupMemberOf: new Map(), groupMember: new Map() }; + } + const configs = Array.isArray(config) ? config : [config]; const groups: GroupEntity[] = []; const groupMemberOf: Map> = new Map(); const groupMember: Map> = new Map(); - const { dn, map, options } = config; const vendor = await client.getVendor(); - const transformer = opts?.transformer ?? defaultGroupTransformer; - await client.searchStreaming(dn, options, async entry => { - if (!entry) { - return; - } + for (const cfg of configs) { + const { dn, map, options } = cfg; - const entity = await transformer(vendor, config, entry); + await client.searchStreaming(dn, options, async entry => { + if (!entry) { + return; + } - if (!entity) { - return; - } + const entity = await transformer(vendor, cfg, entry); - mapReferencesAttr(entry, vendor, map.memberOf, (myDn, vs) => { - ensureItems(groupMemberOf, myDn, vs); + if (!entity) { + return; + } + + mapReferencesAttr(entry, vendor, map.memberOf, (myDn, vs) => { + ensureItems(groupMemberOf, myDn, vs); + }); + mapReferencesAttr(entry, vendor, map.members, (myDn, vs) => { + ensureItems(groupMember, myDn, vs); + }); + + groups.push(entity); }); - mapReferencesAttr(entry, vendor, map.members, (myDn, vs) => { - ensureItems(groupMember, myDn, vs); - }); - - groups.push(entity); - }); + } return { groups, @@ -264,8 +280,8 @@ export async function readLdapGroups( */ export async function readLdapOrg( client: LdapClient, - userConfig: UserConfig, - groupConfig: GroupConfig, + userConfig: UserConfigList, + groupConfig: GroupConfigList, options: { groupTransformer?: GroupTransformer; userTransformer?: UserTransformer; From cb32ca7bac6a2023e34ac3c3b87071b9c587825a Mon Sep 17 00:00:00 2001 From: Jente Sondervorst Date: Sat, 15 Jun 2024 22:41:39 +0200 Subject: [PATCH 031/416] Added support for only users or only groups and multiple users or multiple groups bindings Closes: #25256 Signed-off-by: Jente Sondervorst --- .changeset/friendly-bulldogs-pay.md | 5 + docs/integrations/ldap/org.md | 8 ++ .../src/ldap/config.test.ts | 68 ++++++++-- .../src/ldap/config.ts | 78 +++++++++--- .../src/ldap/read.test.ts | 118 +++++++++++++++++- .../src/ldap/read.ts | 86 +++++++------ 6 files changed, 306 insertions(+), 57 deletions(-) create mode 100644 .changeset/friendly-bulldogs-pay.md diff --git a/.changeset/friendly-bulldogs-pay.md b/.changeset/friendly-bulldogs-pay.md new file mode 100644 index 0000000000..9c7ab8f9cb --- /dev/null +++ b/.changeset/friendly-bulldogs-pay.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend-module-ldap': minor +--- + +Added support for single ldap catalog provider to provide list and undefined user and group bindings next to standard single one. diff --git a/docs/integrations/ldap/org.md b/docs/integrations/ldap/org.md index f70d02afed..f839516d9a 100644 --- a/docs/integrations/ldap/org.md +++ b/docs/integrations/ldap/org.md @@ -86,6 +86,14 @@ catalog: These config blocks have a lot of options in them, so we will describe each "root" key within the block separately. +> NOTE: +> +> If you want to import users and groups from different LDAP servers, you can define multiple providers with different names. +> If they should come from the same server, you can define multiple users and groups blocks within the same provider using an array of users / groups. +> Entries coming from the same block will be able to detect group memberships based on the `memberOf` attribute. +> +> If you want only to import users or groups, you can omit the groups or users block. + ### target This is the URL of the targeted server, typically on the form diff --git a/plugins/catalog-backend-module-ldap/src/ldap/config.test.ts b/plugins/catalog-backend-module-ldap/src/ldap/config.test.ts index ddea9de03f..8cd41e0b70 100644 --- a/plugins/catalog-backend-module-ldap/src/ldap/config.test.ts +++ b/plugins/catalog-backend-module-ldap/src/ldap/config.test.ts @@ -15,7 +15,7 @@ */ import { ConfigReader } from '@backstage/config'; -import { readProviderConfigs } from './config'; +import { readProviderConfigs, UserConfig } from './config'; describe('readLdapConfig', () => { it('applies all of the defaults', () => { @@ -247,7 +247,7 @@ describe('readLdapConfig', () => { const actual = readProviderConfigs(new ConfigReader(config)); const expected = '(|(cn=foo bar)(cn=bar))'; - expect(actual[0].users.options.filter).toEqual(expected); + expect((actual[0].users!! as UserConfig).options.filter).toEqual(expected); }); it('supports a dot nested set structure', () => { @@ -284,7 +284,9 @@ describe('readLdapConfig', () => { }; const actual = readProviderConfigs(new ConfigReader(config)); - expect(actual[0].users.set).toEqual({ 'metadata.annotations': { a: 'b' } }); + expect((actual[0].users!! as UserConfig).set).toEqual({ + 'metadata.annotations': { a: 'b' }, + }); }); it('throws on attempts to modify the set structure', () => { @@ -320,25 +322,77 @@ describe('readLdapConfig', () => { const actual = readProviderConfigs(new ConfigReader(config)); expect(() => { - (actual[0].users.set as any).y = 2; + ((actual[0].users!! as UserConfig).set as any).y = 2; }).toThrowErrorMatchingInlineSnapshot( `"Cannot add property y, object is not extensible"`, ); expect(() => { - (actual[0].users.set as any).x.b = 2; + ((actual[0].users!! as UserConfig).set as any).x.b = 2; }).toThrowErrorMatchingInlineSnapshot( `"Cannot add property b, object is not extensible"`, ); expect(() => { - (actual[0].groups.set as any).y = 2; + ((actual[0].users!! as UserConfig).set as any).y = 2; }).toThrowErrorMatchingInlineSnapshot( `"Cannot add property y, object is not extensible"`, ); expect(() => { - (actual[0].groups.set as any).x.b = 2; + ((actual[0].users!! as UserConfig).set as any).x.b = 2; }).toThrowErrorMatchingInlineSnapshot( `"Cannot add property b, object is not extensible"`, ); }); + + it('supports users/groups config as list', () => { + const config = { + catalog: { + providers: { + ldapOrg: { + default: { + target: 'target', + users: [ + { + dn: 'udn1', + }, + { + dn: 'udn2', + }, + ], + groups: [ + { + dn: 'gdn1', + }, + { + dn: 'gdn2', + }, + ], + }, + }, + }, + }, + }; + const actual = readProviderConfigs(new ConfigReader(config)); + + expect(actual[0].users).toHaveLength(2); + expect(actual[0].groups).toHaveLength(2); + }); + + it('supports users/groups config as undefined', () => { + const config = { + catalog: { + providers: { + ldapOrg: { + default: { + target: 'target', + }, + }, + }, + }, + }; + const actual = readProviderConfigs(new ConfigReader(config)); + + expect(actual[0].users).toBeUndefined(); + expect(actual[0].groups).toBeUndefined(); + }); }); diff --git a/plugins/catalog-backend-module-ldap/src/ldap/config.ts b/plugins/catalog-backend-module-ldap/src/ldap/config.ts index 2bd21fd166..7a5b2828e2 100644 --- a/plugins/catalog-backend-module-ldap/src/ldap/config.ts +++ b/plugins/catalog-backend-module-ldap/src/ldap/config.ts @@ -42,9 +42,9 @@ export type LdapProviderConfig = { // command is not issued. bind?: BindConfig; // The settings that govern the reading and interpretation of users - users: UserConfig; + users: UserConfigList; // The settings that govern the reading and interpretation of groups - groups: GroupConfig; + groups: GroupConfigList; // Schedule configuration for refresh tasks. schedule?: TaskScheduleDefinition; }; @@ -81,6 +81,8 @@ export type BindConfig = { * * @public */ +export type UserConfigList = UserConfig | UserConfig[] | undefined; + export type UserConfig = { // The DN under which users are stored. dn: string; @@ -121,6 +123,8 @@ export type UserConfig = { * * @public */ +export type GroupConfigList = GroupConfig | GroupConfig[] | undefined; + export type GroupConfig = { // The DN under which groups are stored. dn: string; @@ -272,9 +276,7 @@ function readSetConfig( return c.get(); } -function readUserMapConfig( - c: Config | undefined, -): Partial { +function readUserMapConfig(c: Config | undefined): Partial { if (!c) { return {}; } @@ -292,7 +294,7 @@ function readUserMapConfig( function readGroupMapConfig( c: Config | undefined, -): Partial { +): Partial { if (!c) { return {}; } @@ -311,8 +313,21 @@ function readGroupMapConfig( } function readUserConfig( - c: Config, + c: Config | Config[] | undefined, ): RecursivePartial { + if (!c) { + return undefined; + } + if (Array.isArray(c)) { + return c.map(it => { + return { + dn: it.getString('dn'), + options: readOptionsConfig(it.getOptionalConfig('options')), + set: readSetConfig(it.getOptionalConfig('set')), + map: readUserMapConfig(it.getOptionalConfig('map')), + }; + }); + } return { dn: c.getString('dn'), options: readOptionsConfig(c.getOptionalConfig('options')), @@ -322,8 +337,21 @@ function readUserConfig( } function readGroupConfig( - c: Config, + c: Config | Config[] | undefined, ): RecursivePartial { + if (!c) { + return undefined; + } + if (Array.isArray(c)) { + return c.map(it => { + return { + dn: it.getString('dn'), + options: readOptionsConfig(it.getOptionalConfig('options')), + set: readSetConfig(it.getOptionalConfig('set')), + map: readGroupMapConfig(it.getOptionalConfig('map')), + }; + }); + } return { dn: c.getString('dn'), options: readOptionsConfig(c.getOptionalConfig('options')), @@ -383,19 +411,41 @@ export function readProviderConfigs(config: Config): LdapProviderConfig[] { ? readTaskScheduleDefinitionFromConfig(c.getConfig('schedule')) : undefined; + const isUserList = Array.isArray(c.getOptional('users')); + const isGroupList = Array.isArray(c.getOptional('groups')); + const newConfig = { id, target: trimEnd(c.getString('target'), '/'), tls: readTlsConfig(c.getOptionalConfig('tls')), bind: readBindConfig(c.getOptionalConfig('bind')), - users: readUserConfig(c.getConfig('users')), - groups: readGroupConfig(c.getConfig('groups')), + users: readUserConfig( + isUserList + ? c.getOptionalConfigArray('users') + : c.getOptionalConfig('users'), + ), + groups: readGroupConfig( + isGroupList + ? c.getOptionalConfigArray('groups') + : c.getOptionalConfig('groups'), + ), schedule, }; - const merged = mergeWith({}, defaultConfig, newConfig, (_into, from) => { - // Replace arrays instead of merging, otherwise default behavior - return Array.isArray(from) ? from : undefined; - }); + + const merged = mergeWith( + {}, + defaultConfig, + newConfig, + (_value, srcValue, key, object, _source) => { + // Remove users and groups from default if they are not set in the new config + if ((key === 'users' || key === 'groups') && !srcValue) { + return (object[key] = srcValue); + } + // Replace arrays instead of merging, otherwise default behavior + return Array.isArray(srcValue) ? srcValue : undefined; + }, + ); + return freeze(merged) as LdapProviderConfig; }); } diff --git a/plugins/catalog-backend-module-ldap/src/ldap/read.test.ts b/plugins/catalog-backend-module-ldap/src/ldap/read.test.ts index fc451fde97..33c52477aa 100644 --- a/plugins/catalog-backend-module-ldap/src/ldap/read.test.ts +++ b/plugins/catalog-backend-module-ldap/src/ldap/read.test.ts @@ -18,7 +18,12 @@ import { GroupEntity, UserEntity } from '@backstage/catalog-model'; import { SearchEntry } from 'ldapjs'; import merge from 'lodash/merge'; import { LdapClient } from './client'; -import { GroupConfig, UserConfig } from './config'; +import { + GroupConfig, + GroupConfigList, + UserConfig, + UserConfigList, +} from './config'; import { LDAP_DN_ANNOTATION, LDAP_RDN_ANNOTATION, @@ -255,6 +260,58 @@ describe('readLdapUsers', () => { new Map([['dn-value', new Set(['x', 'y', 'z'])]]), ); }); + it('can process a list of UserConfigs', async () => { + client.getVendor.mockResolvedValue(DefaultLdapVendor); + client.searchStreaming.mockImplementation(async (_dn, _opts, fn) => { + await fn( + searchEntry({ + uid: ['uid-value'], + description: ['description-value'], + cn: ['cn-value'], + mail: ['mail-value'], + avatarUrl: ['avatarUrl-value'], + memberOf: ['x', 'y', 'z'], + entryDN: ['dn-value'], + entryUUID: ['uuid-value'], + }), + ); + }); + const config: UserConfigList = [ + { + dn: 'ddd', + options: {}, + map: { + rdn: 'uid', + name: 'uid', + description: 'description', + displayName: 'cn', + email: 'mail', + picture: 'avatarUrl', + memberOf: 'memberOf', + }, + }, + { + dn: 'ddd', + options: {}, + map: { + rdn: 'uid', + name: 'uid', + description: 'description', + displayName: 'cn', + email: 'mail', + picture: 'avatarUrl', + memberOf: 'memberOf', + }, + }, + ]; + const { users } = await readLdapUsers(client, config); + expect(users).toHaveLength(2); + }); + it('can process no UserConfigs', async () => { + const config: UserConfigList = undefined; + const { users } = await readLdapUsers(client, config); + expect(users).toHaveLength(0); + }); }); describe('readLdapGroups', () => { @@ -401,6 +458,65 @@ describe('readLdapGroups', () => { new Map([['dn-value', new Set(['x', 'y', 'z'])]]), ); }); + + it('can process a list of GroupConfigs', async () => { + client.getVendor.mockResolvedValue(DefaultLdapVendor); + client.searchStreaming.mockImplementation(async (_dn, _opts, fn) => { + await fn( + searchEntry({ + cn: ['cn-value'], + description: ['description-value'], + tt: ['type-value'], + mail: ['mail-value'], + avatarUrl: ['avatarUrl-value'], + memberOf: ['x', 'y', 'z'], + member: ['e', 'f', 'g'], + entryDN: ['dn-value'], + entryUUID: ['uuid-value'], + }), + ); + }); + const config: GroupConfigList = [ + { + dn: 'ddd', + options: {}, + map: { + rdn: 'cn', + name: 'cn', + description: 'description', + displayName: 'cn', + email: 'mail', + picture: 'avatarUrl', + type: 'tt', + memberOf: 'memberOf', + members: 'member', + }, + }, + { + dn: 'ddd', + options: {}, + map: { + rdn: 'cn', + name: 'cn', + description: 'description', + displayName: 'cn', + email: 'mail', + picture: 'avatarUrl', + type: 'tt', + memberOf: 'memberOf', + members: 'member', + }, + }, + ]; + const { groups } = await readLdapGroups(client, config); + expect(groups).toHaveLength(2); + }); + + it('can process no GroupConfigs', async () => { + const config: GroupConfigList = undefined; + const { groups } = await readLdapGroups(client, config); + expect(groups).toHaveLength(0); + }); }); describe('resolveRelations', () => { diff --git a/plugins/catalog-backend-module-ldap/src/ldap/read.ts b/plugins/catalog-backend-module-ldap/src/ldap/read.ts index 50036b94b0..5dadcaede2 100644 --- a/plugins/catalog-backend-module-ldap/src/ldap/read.ts +++ b/plugins/catalog-backend-module-ldap/src/ldap/read.ts @@ -24,7 +24,12 @@ import lodashSet from 'lodash/set'; import cloneDeep from 'lodash/cloneDeep'; import { buildOrgHierarchy } from './org'; import { LdapClient } from './client'; -import { GroupConfig, UserConfig } from './config'; +import { + GroupConfig, + GroupConfigList, + UserConfig, + UserConfigList, +} from './config'; import { LDAP_DN_ANNOTATION, LDAP_RDN_ANNOTATION, @@ -104,32 +109,37 @@ export async function defaultUserTransformer( */ export async function readLdapUsers( client: LdapClient, - config: UserConfig, + config: UserConfigList, opts?: { transformer?: UserTransformer }, ): Promise<{ users: UserEntity[]; // With all relations empty userMemberOf: Map>; // DN -> DN or UUID of groups }> { - const { dn, options, map } = config; - const vendor = await client.getVendor(); - + if (!config) { + return { users: [], userMemberOf: new Map() }; + } + const configs = Array.isArray(config) ? config : [config]; const entities: UserEntity[] = []; const userMemberOf: Map> = new Map(); + const vendor = await client.getVendor(); const transformer = opts?.transformer ?? defaultUserTransformer; - await client.searchStreaming(dn, options, async user => { - const entity = await transformer(vendor, config, user); + for (const cfg of configs) { + const { dn, options, map } = cfg; + await client.searchStreaming(dn, options, async user => { + const entity = await transformer(vendor, cfg, user); - if (!entity) { - return; - } + if (!entity) { + return; + } - mapReferencesAttr(user, vendor, map.memberOf, (myDn, vs) => { - ensureItems(userMemberOf, myDn, vs); + mapReferencesAttr(user, vendor, map.memberOf, (myDn, vs) => { + ensureItems(userMemberOf, myDn, vs); + }); + entities.push(entity); }); - entities.push(entity); - }); + } return { users: entities, userMemberOf }; } @@ -206,7 +216,7 @@ export async function defaultGroupTransformer( */ export async function readLdapGroups( client: LdapClient, - config: GroupConfig, + config: GroupConfigList, opts?: { transformer?: GroupTransformer; }, @@ -215,35 +225,41 @@ export async function readLdapGroups( groupMemberOf: Map>; // DN -> DN or UUID of groups groupMember: Map>; // DN -> DN or UUID of groups & users }> { + if (!config) { + return { groups: [], groupMemberOf: new Map(), groupMember: new Map() }; + } + const configs = Array.isArray(config) ? config : [config]; const groups: GroupEntity[] = []; const groupMemberOf: Map> = new Map(); const groupMember: Map> = new Map(); - const { dn, map, options } = config; const vendor = await client.getVendor(); - const transformer = opts?.transformer ?? defaultGroupTransformer; - await client.searchStreaming(dn, options, async entry => { - if (!entry) { - return; - } + for (const cfg of configs) { + const { dn, map, options } = cfg; - const entity = await transformer(vendor, config, entry); + await client.searchStreaming(dn, options, async entry => { + if (!entry) { + return; + } - if (!entity) { - return; - } + const entity = await transformer(vendor, cfg, entry); - mapReferencesAttr(entry, vendor, map.memberOf, (myDn, vs) => { - ensureItems(groupMemberOf, myDn, vs); + if (!entity) { + return; + } + + mapReferencesAttr(entry, vendor, map.memberOf, (myDn, vs) => { + ensureItems(groupMemberOf, myDn, vs); + }); + mapReferencesAttr(entry, vendor, map.members, (myDn, vs) => { + ensureItems(groupMember, myDn, vs); + }); + + groups.push(entity); }); - mapReferencesAttr(entry, vendor, map.members, (myDn, vs) => { - ensureItems(groupMember, myDn, vs); - }); - - groups.push(entity); - }); + } return { groups, @@ -264,8 +280,8 @@ export async function readLdapGroups( */ export async function readLdapOrg( client: LdapClient, - userConfig: UserConfig, - groupConfig: GroupConfig, + userConfig: UserConfigList, + groupConfig: GroupConfigList, options: { groupTransformer?: GroupTransformer; userTransformer?: UserTransformer; From 66d852407e16bab4cdf3fff171e9f50171d02acc Mon Sep 17 00:00:00 2001 From: Jente Sondervorst Date: Sun, 16 Jun 2024 14:08:57 +0200 Subject: [PATCH 032/416] Added api-reports Closes: #25256 Signed-off-by: Jente Sondervorst --- plugins/catalog-backend-module-ldap/api-report.md | 14 ++++++++++---- .../catalog-backend-module-ldap/src/ldap/config.ts | 10 ++++++++++ .../catalog-backend-module-ldap/src/ldap/index.ts | 2 ++ 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/plugins/catalog-backend-module-ldap/api-report.md b/plugins/catalog-backend-module-ldap/api-report.md index 5fcbbc3091..7bc53eb7b2 100644 --- a/plugins/catalog-backend-module-ldap/api-report.md +++ b/plugins/catalog-backend-module-ldap/api-report.md @@ -68,6 +68,9 @@ export type GroupConfig = { }; }; +// @public +export type GroupConfigList = GroupConfig | GroupConfig[] | undefined; + // @public export type GroupTransformer = ( vendor: LdapVendor, @@ -197,8 +200,8 @@ export type LdapProviderConfig = { target: string; tls?: TLSConfig; bind?: BindConfig; - users: UserConfig; - groups: GroupConfig; + users: UserConfigList; + groups: GroupConfigList; schedule?: TaskScheduleDefinition; }; @@ -223,8 +226,8 @@ export function readLdapLegacyConfig(config: Config): LdapProviderConfig[]; // @public export function readLdapOrg( client: LdapClient, - userConfig: UserConfig, - groupConfig: GroupConfig, + userConfig: UserConfigList, + groupConfig: GroupConfigList, options: { groupTransformer?: GroupTransformer; userTransformer?: UserTransformer; @@ -263,6 +266,9 @@ export type UserConfig = { }; }; +// @public +export type UserConfigList = UserConfig | UserConfig[] | undefined; + // @public export type UserTransformer = ( vendor: LdapVendor, diff --git a/plugins/catalog-backend-module-ldap/src/ldap/config.ts b/plugins/catalog-backend-module-ldap/src/ldap/config.ts index 7a5b2828e2..d31de61605 100644 --- a/plugins/catalog-backend-module-ldap/src/ldap/config.ts +++ b/plugins/catalog-backend-module-ldap/src/ldap/config.ts @@ -83,6 +83,11 @@ export type BindConfig = { */ export type UserConfigList = UserConfig | UserConfig[] | undefined; +/** + * The settings that govern the reading and interpretation of users. + * + * @public + */ export type UserConfig = { // The DN under which users are stored. dn: string; @@ -125,6 +130,11 @@ export type UserConfig = { */ export type GroupConfigList = GroupConfig | GroupConfig[] | undefined; +/** + * The settings that govern the reading and interpretation of groups. + * + * @public + */ export type GroupConfig = { // The DN under which groups are stored. dn: string; diff --git a/plugins/catalog-backend-module-ldap/src/ldap/index.ts b/plugins/catalog-backend-module-ldap/src/ldap/index.ts index cfab5a4444..81cab40b75 100644 --- a/plugins/catalog-backend-module-ldap/src/ldap/index.ts +++ b/plugins/catalog-backend-module-ldap/src/ldap/index.ts @@ -20,7 +20,9 @@ export { readProviderConfigs, readLdapLegacyConfig } from './config'; export type { LdapProviderConfig, GroupConfig, + GroupConfigList, UserConfig, + UserConfigList, BindConfig, TLSConfig, } from './config'; From 561083b716ea71f8387dc00345e30fc15052a1b5 Mon Sep 17 00:00:00 2001 From: David Weber Date: Wed, 15 May 2024 22:09:21 +0200 Subject: [PATCH 033/416] chore: add relations plugin to plugin page Signed-off-by: David Weber Signed-off-by: David Weber --- microsite/data/plugins/relations.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 microsite/data/plugins/relations.yaml diff --git a/microsite/data/plugins/relations.yaml b/microsite/data/plugins/relations.yaml new file mode 100644 index 0000000000..61ce052453 --- /dev/null +++ b/microsite/data/plugins/relations.yaml @@ -0,0 +1,10 @@ +--- +title: Relations +author: dweber019 +authorUrl: https://github.com/dweber019 +category: Catalog +description: This plugin enables you to configure additional relations between entities, which aren't supported out of box. +documentation: https://github.com/dweber019/backstage-plugins/tree/main/plugins/relations +iconUrl: https://raw.githubusercontent.com/dweber019/backstage-plugins/main/plugins/relations-backend/docs/pluginIcon.png +npmPackageName: '@dweber019/backstage-plugin-relations' +addedDate: '2024-05-15' From 82434ee7b5f8fdd414c8ed7e624f52ee4d43b5f7 Mon Sep 17 00:00:00 2001 From: Jente Sondervorst Date: Mon, 17 Jun 2024 22:37:31 +0200 Subject: [PATCH 034/416] Review comments Closes: #25256 Signed-off-by: Jente Sondervorst --- .../catalog-backend-module-ldap/api-report.md | 14 +- .../catalog-backend-module-ldap/config.d.ts | 512 ++++++++++++------ .../src/ldap/config.test.ts | 182 ++++--- .../src/ldap/config.ts | 145 ++--- .../src/ldap/index.ts | 2 - .../src/ldap/read.test.ts | 153 +++--- .../src/ldap/read.ts | 25 +- 7 files changed, 589 insertions(+), 444 deletions(-) diff --git a/plugins/catalog-backend-module-ldap/api-report.md b/plugins/catalog-backend-module-ldap/api-report.md index 7bc53eb7b2..9013f75450 100644 --- a/plugins/catalog-backend-module-ldap/api-report.md +++ b/plugins/catalog-backend-module-ldap/api-report.md @@ -68,9 +68,6 @@ export type GroupConfig = { }; }; -// @public -export type GroupConfigList = GroupConfig | GroupConfig[] | undefined; - // @public export type GroupTransformer = ( vendor: LdapVendor, @@ -200,8 +197,8 @@ export type LdapProviderConfig = { target: string; tls?: TLSConfig; bind?: BindConfig; - users: UserConfigList; - groups: GroupConfigList; + users: UserConfig[]; + groups: GroupConfig[]; schedule?: TaskScheduleDefinition; }; @@ -226,8 +223,8 @@ export function readLdapLegacyConfig(config: Config): LdapProviderConfig[]; // @public export function readLdapOrg( client: LdapClient, - userConfig: UserConfigList, - groupConfig: GroupConfigList, + userConfig: UserConfig[], + groupConfig: GroupConfig[], options: { groupTransformer?: GroupTransformer; userTransformer?: UserTransformer; @@ -266,9 +263,6 @@ export type UserConfig = { }; }; -// @public -export type UserConfigList = UserConfig | UserConfig[] | undefined; - // @public export type UserTransformer = ( vendor: LdapVendor, diff --git a/plugins/catalog-backend-module-ldap/config.d.ts b/plugins/catalog-backend-module-ldap/config.d.ts index a585471033..65914fdf74 100644 --- a/plugins/catalog-backend-module-ldap/config.d.ts +++ b/plugins/catalog-backend-module-ldap/config.d.ts @@ -63,180 +63,352 @@ export interface Config { /** * The settings that govern the reading and interpretation of users. */ - users: { - /** - * The DN under which users are stored. - * - * E.g. "ou=people,ou=example,dc=example,dc=net" - */ - dn: string; - /** - * The search options to use. The default is scope "one" and - * attributes "*" and "+". - * - * It is common to want to specify a filter, to narrow down the set - * of matching items. - */ - options: { - scope?: 'base' | 'one' | 'sub'; - filter?: string; - attributes?: string | string[]; - sizeLimit?: number; - timeLimit?: number; - derefAliases?: number; - typesOnly?: boolean; - paged?: - | boolean - | { - pageSize?: number; - pagePause?: boolean; - }; - }; - /** - * JSON paths (on a.b.c form) and hard coded values to set on those - * paths. - * - * This can be useful for example if you want to hard code a - * namespace or similar on the generated entities. - */ - set?: { [key: string]: JsonValue }; - /** - * Mappings from well known entity fields, to LDAP attribute names - */ - map?: { - /** - * The name of the attribute that holds the relative - * distinguished name of each entry. Defaults to "uid". - */ - rdn?: string; - /** - * The name of the attribute that shall be used for the value of - * the metadata.name field of the entity. Defaults to "uid". - */ - name?: string; - /** - * The name of the attribute that shall be used for the value of - * the metadata.description field of the entity. - */ - description?: string; - /** - * The name of the attribute that shall be used for the value of - * the spec.profile.displayName field of the entity. Defaults to - * "cn". - */ - displayName?: string; - /** - * The name of the attribute that shall be used for the value of - * the spec.profile.email field of the entity. Defaults to - * "mail". - */ - email?: string; - /** - * The name of the attribute that shall be used for the value of - * the spec.profile.picture field of the entity. - */ - picture?: string; - /** - * The name of the attribute that shall be used for the values of - * the spec.memberOf field of the entity. Defaults to "memberOf". - */ - memberOf?: string; - }; - }; + users?: + | { + /** + * The DN under which users are stored. + * + * E.g. "ou=people,ou=example,dc=example,dc=net" + */ + dn: string; + /** + * The search options to use. The default is scope "one" and + * attributes "*" and "+". + * + * It is common to want to specify a filter, to narrow down the set + * of matching items. + */ + options: { + scope?: 'base' | 'one' | 'sub'; + filter?: string; + attributes?: string | string[]; + sizeLimit?: number; + timeLimit?: number; + derefAliases?: number; + typesOnly?: boolean; + paged?: + | boolean + | { + pageSize?: number; + pagePause?: boolean; + }; + }; + /** + * JSON paths (on a.b.c form) and hard coded values to set on those + * paths. + * + * This can be useful for example if you want to hard code a + * namespace or similar on the generated entities. + */ + set?: { [key: string]: JsonValue }; + /** + * Mappings from well known entity fields, to LDAP attribute names + */ + map?: { + /** + * The name of the attribute that holds the relative + * distinguished name of each entry. Defaults to "uid". + */ + rdn?: string; + /** + * The name of the attribute that shall be used for the value of + * the metadata.name field of the entity. Defaults to "uid". + */ + name?: string; + /** + * The name of the attribute that shall be used for the value of + * the metadata.description field of the entity. + */ + description?: string; + /** + * The name of the attribute that shall be used for the value of + * the spec.profile.displayName field of the entity. Defaults to + * "cn". + */ + displayName?: string; + /** + * The name of the attribute that shall be used for the value of + * the spec.profile.email field of the entity. Defaults to + * "mail". + */ + email?: string; + /** + * The name of the attribute that shall be used for the value of + * the spec.profile.picture field of the entity. + */ + picture?: string; + /** + * The name of the attribute that shall be used for the values of + * the spec.memberOf field of the entity. Defaults to "memberOf". + */ + memberOf?: string; + }; + } + | Array<{ + /** + * The DN under which users are stored. + * + * E.g. "ou=people,ou=example,dc=example,dc=net" + */ + dn: string; + /** + * The search options to use. The default is scope "one" and + * attributes "*" and "+". + * + * It is common to want to specify a filter, to narrow down the set + * of matching items. + */ + options: { + scope?: 'base' | 'one' | 'sub'; + filter?: string; + attributes?: string | string[]; + sizeLimit?: number; + timeLimit?: number; + derefAliases?: number; + typesOnly?: boolean; + paged?: + | boolean + | { + pageSize?: number; + pagePause?: boolean; + }; + }; + /** + * JSON paths (on a.b.c form) and hard coded values to set on those + * paths. + * + * This can be useful for example if you want to hard code a + * namespace or similar on the generated entities. + */ + set?: { [key: string]: JsonValue }; + /** + * Mappings from well known entity fields, to LDAP attribute names + */ + map?: { + /** + * The name of the attribute that holds the relative + * distinguished name of each entry. Defaults to "uid". + */ + rdn?: string; + /** + * The name of the attribute that shall be used for the value of + * the metadata.name field of the entity. Defaults to "uid". + */ + name?: string; + /** + * The name of the attribute that shall be used for the value of + * the metadata.description field of the entity. + */ + description?: string; + /** + * The name of the attribute that shall be used for the value of + * the spec.profile.displayName field of the entity. Defaults to + * "cn". + */ + displayName?: string; + /** + * The name of the attribute that shall be used for the value of + * the spec.profile.email field of the entity. Defaults to + * "mail". + */ + email?: string; + /** + * The name of the attribute that shall be used for the value of + * the spec.profile.picture field of the entity. + */ + picture?: string; + /** + * The name of the attribute that shall be used for the values of + * the spec.memberOf field of the entity. Defaults to "memberOf". + */ + memberOf?: string; + }; + }>; /** * The settings that govern the reading and interpretation of groups. */ - groups: { - /** - * The DN under which groups are stored. - * - * E.g. "ou=people,ou=example,dc=example,dc=net" - */ - dn: string; - /** - * The search options to use. The default is scope "one" and - * attributes "*" and "+". - * - * It is common to want to specify a filter, to narrow down the set - * of matching items. - */ - options: { - scope?: 'base' | 'one' | 'sub'; - filter?: string; - attributes?: string | string[]; - sizeLimit?: number; - timeLimit?: number; - derefAliases?: number; - typesOnly?: boolean; - paged?: - | boolean - | { - pageSize?: number; - pagePause?: boolean; - }; - }; - /** - * JSON paths (on a.b.c form) and hard coded values to set on those - * paths. - * - * This can be useful for example if you want to hard code a - * namespace or similar on the generated entities. - */ - set?: { [key: string]: JsonValue }; - /** - * Mappings from well known entity fields, to LDAP attribute names - */ - map?: { - /** - * The name of the attribute that holds the relative - * distinguished name of each entry. Defaults to "cn". - */ - rdn?: string; - /** - * The name of the attribute that shall be used for the value of - * the metadata.name field of the entity. Defaults to "cn". - */ - name?: string; - /** - * The name of the attribute that shall be used for the value of - * the metadata.description field of the entity. Defaults to - * "description". - */ - description?: string; - /** - * The name of the attribute that shall be used for the value of - * the spec.type field of the entity. Defaults to "groupType". - */ - type?: string; - /** - * The name of the attribute that shall be used for the value of - * the spec.profile.displayName field of the entity. Defaults to - * "cn". - */ - displayName?: string; - /** - * The name of the attribute that shall be used for the value of - * the spec.profile.email field of the entity. - */ - email?: string; - /** - * The name of the attribute that shall be used for the value of - * the spec.profile.picture field of the entity. - */ - picture?: string; - /** - * The name of the attribute that shall be used for the values of - * the spec.parent field of the entity. Defaults to "memberOf". - */ - memberOf?: string; - /** - * The name of the attribute that shall be used for the values of - * the spec.children field of the entity. Defaults to "member". - */ - members?: string; - }; - }; + groups?: + | { + /** + * The DN under which groups are stored. + * + * E.g. "ou=people,ou=example,dc=example,dc=net" + */ + dn: string; + /** + * The search options to use. The default is scope "one" and + * attributes "*" and "+". + * + * It is common to want to specify a filter, to narrow down the set + * of matching items. + */ + options: { + scope?: 'base' | 'one' | 'sub'; + filter?: string; + attributes?: string | string[]; + sizeLimit?: number; + timeLimit?: number; + derefAliases?: number; + typesOnly?: boolean; + paged?: + | boolean + | { + pageSize?: number; + pagePause?: boolean; + }; + }; + /** + * JSON paths (on a.b.c form) and hard coded values to set on those + * paths. + * + * This can be useful for example if you want to hard code a + * namespace or similar on the generated entities. + */ + set?: { [key: string]: JsonValue }; + /** + * Mappings from well known entity fields, to LDAP attribute names + */ + map?: { + /** + * The name of the attribute that holds the relative + * distinguished name of each entry. Defaults to "cn". + */ + rdn?: string; + /** + * The name of the attribute that shall be used for the value of + * the metadata.name field of the entity. Defaults to "cn". + */ + name?: string; + /** + * The name of the attribute that shall be used for the value of + * the metadata.description field of the entity. Defaults to + * "description". + */ + description?: string; + /** + * The name of the attribute that shall be used for the value of + * the spec.type field of the entity. Defaults to "groupType". + */ + type?: string; + /** + * The name of the attribute that shall be used for the value of + * the spec.profile.displayName field of the entity. Defaults to + * "cn". + */ + displayName?: string; + /** + * The name of the attribute that shall be used for the value of + * the spec.profile.email field of the entity. + */ + email?: string; + /** + * The name of the attribute that shall be used for the value of + * the spec.profile.picture field of the entity. + */ + picture?: string; + /** + * The name of the attribute that shall be used for the values of + * the spec.parent field of the entity. Defaults to "memberOf". + */ + memberOf?: string; + /** + * The name of the attribute that shall be used for the values of + * the spec.children field of the entity. Defaults to "member". + */ + members?: string; + }; + } + | Array<{ + /** + * The DN under which groups are stored. + * + * E.g. "ou=people,ou=example,dc=example,dc=net" + */ + dn: string; + /** + * The search options to use. The default is scope "one" and + * attributes "*" and "+". + * + * It is common to want to specify a filter, to narrow down the set + * of matching items. + */ + options: { + scope?: 'base' | 'one' | 'sub'; + filter?: string; + attributes?: string | string[]; + sizeLimit?: number; + timeLimit?: number; + derefAliases?: number; + typesOnly?: boolean; + paged?: + | boolean + | { + pageSize?: number; + pagePause?: boolean; + }; + }; + /** + * JSON paths (on a.b.c form) and hard coded values to set on those + * paths. + * + * This can be useful for example if you want to hard code a + * namespace or similar on the generated entities. + */ + set?: { [key: string]: JsonValue }; + /** + * Mappings from well known entity fields, to LDAP attribute names + */ + map?: { + /** + * The name of the attribute that holds the relative + * distinguished name of each entry. Defaults to "cn". + */ + rdn?: string; + /** + * The name of the attribute that shall be used for the value of + * the metadata.name field of the entity. Defaults to "cn". + */ + name?: string; + /** + * The name of the attribute that shall be used for the value of + * the metadata.description field of the entity. Defaults to + * "description". + */ + description?: string; + /** + * The name of the attribute that shall be used for the value of + * the spec.type field of the entity. Defaults to "groupType". + */ + type?: string; + /** + * The name of the attribute that shall be used for the value of + * the spec.profile.displayName field of the entity. Defaults to + * "cn". + */ + displayName?: string; + /** + * The name of the attribute that shall be used for the value of + * the spec.profile.email field of the entity. + */ + email?: string; + /** + * The name of the attribute that shall be used for the value of + * the spec.profile.picture field of the entity. + */ + picture?: string; + /** + * The name of the attribute that shall be used for the values of + * the spec.parent field of the entity. Defaults to "memberOf". + */ + memberOf?: string; + /** + * The name of the attribute that shall be used for the values of + * the spec.children field of the entity. Defaults to "member". + */ + members?: string; + }; + }>; }>; }; diff --git a/plugins/catalog-backend-module-ldap/src/ldap/config.test.ts b/plugins/catalog-backend-module-ldap/src/ldap/config.test.ts index 8cd41e0b70..553bf3c525 100644 --- a/plugins/catalog-backend-module-ldap/src/ldap/config.test.ts +++ b/plugins/catalog-backend-module-ldap/src/ldap/config.test.ts @@ -15,7 +15,7 @@ */ import { ConfigReader } from '@backstage/config'; -import { readProviderConfigs, UserConfig } from './config'; +import { readProviderConfigs } from './config'; describe('readLdapConfig', () => { it('applies all of the defaults', () => { @@ -42,38 +42,42 @@ describe('readLdapConfig', () => { id: 'default', target: 'target', bind: undefined, - users: { - dn: 'udn', - options: { - scope: 'one', - attributes: ['*', '+'], + users: [ + { + dn: 'udn', + options: { + scope: 'one', + attributes: ['*', '+'], + }, + set: undefined, + map: { + rdn: 'uid', + name: 'uid', + displayName: 'cn', + email: 'mail', + memberOf: 'memberOf', + }, }, - set: undefined, - map: { - rdn: 'uid', - name: 'uid', - displayName: 'cn', - email: 'mail', - memberOf: 'memberOf', + ], + groups: [ + { + dn: 'gdn', + options: { + scope: 'one', + attributes: ['*', '+'], + }, + set: undefined, + map: { + rdn: 'cn', + name: 'cn', + description: 'description', + type: 'groupType', + displayName: 'cn', + memberOf: 'memberOf', + members: 'member', + }, }, - }, - groups: { - dn: 'gdn', - options: { - scope: 'one', - attributes: ['*', '+'], - }, - set: undefined, - map: { - rdn: 'cn', - name: 'cn', - description: 'description', - type: 'groupType', - displayName: 'cn', - memberOf: 'memberOf', - members: 'member', - }, - }, + ], }, ]; expect(actual).toEqual(expected); @@ -159,57 +163,61 @@ describe('readLdapConfig', () => { keys: '/tmp/keys.pem', certs: '/tmp/certs.pem', }, - users: { - dn: 'udn', - options: { - scope: 'base', - attributes: ['*'], - filter: 'f', - paged: true, - timeLimit: 42, - sizeLimit: 100, - derefAliases: 0, - typesOnly: false, - }, - set: { p: 'v' }, - map: { - rdn: 'u', - name: 'v', - description: 'd', - displayName: 'c', - email: 'm', - picture: 'p', - memberOf: 'm', - }, - }, - groups: { - dn: 'gdn', - options: { - scope: 'base', - attributes: ['*'], - filter: 'f', - paged: { - pageSize: 7, - pagePause: true, + users: [ + { + dn: 'udn', + options: { + scope: 'base', + attributes: ['*'], + filter: 'f', + paged: true, + timeLimit: 42, + sizeLimit: 100, + derefAliases: 0, + typesOnly: false, + }, + set: { p: 'v' }, + map: { + rdn: 'u', + name: 'v', + description: 'd', + displayName: 'c', + email: 'm', + picture: 'p', + memberOf: 'm', }, - timeLimit: 42, - sizeLimit: 100, - derefAliases: 1, - typesOnly: true, }, - set: { p: 'v' }, - map: { - rdn: 'u', - name: 'v', - description: 'd', - type: 't', - displayName: 'c', - email: 'm', - picture: 'p', - memberOf: 'm', - members: 'n', + ], + groups: [ + { + dn: 'gdn', + options: { + scope: 'base', + attributes: ['*'], + filter: 'f', + paged: { + pageSize: 7, + pagePause: true, + }, + timeLimit: 42, + sizeLimit: 100, + derefAliases: 1, + typesOnly: true, + }, + set: { p: 'v' }, + map: { + rdn: 'u', + name: 'v', + description: 'd', + type: 't', + displayName: 'c', + email: 'm', + picture: 'p', + memberOf: 'm', + members: 'n', + }, }, - }, + ], }, ]; expect(actual).toEqual(expected); @@ -247,7 +255,7 @@ describe('readLdapConfig', () => { const actual = readProviderConfigs(new ConfigReader(config)); const expected = '(|(cn=foo bar)(cn=bar))'; - expect((actual[0].users!! as UserConfig).options.filter).toEqual(expected); + expect(actual[0].users[0].options.filter).toEqual(expected); }); it('supports a dot nested set structure', () => { @@ -284,7 +292,7 @@ describe('readLdapConfig', () => { }; const actual = readProviderConfigs(new ConfigReader(config)); - expect((actual[0].users!! as UserConfig).set).toEqual({ + expect(actual[0].users[0].set).toEqual({ 'metadata.annotations': { a: 'b' }, }); }); @@ -322,23 +330,23 @@ describe('readLdapConfig', () => { const actual = readProviderConfigs(new ConfigReader(config)); expect(() => { - ((actual[0].users!! as UserConfig).set as any).y = 2; + (actual[0].users[0].set as any).y = 2; }).toThrowErrorMatchingInlineSnapshot( `"Cannot add property y, object is not extensible"`, ); expect(() => { - ((actual[0].users!! as UserConfig).set as any).x.b = 2; + (actual[0].users[0].set as any).x.b = 2; }).toThrowErrorMatchingInlineSnapshot( `"Cannot add property b, object is not extensible"`, ); expect(() => { - ((actual[0].users!! as UserConfig).set as any).y = 2; + (actual[0].users[0].set as any).y = 2; }).toThrowErrorMatchingInlineSnapshot( `"Cannot add property y, object is not extensible"`, ); expect(() => { - ((actual[0].users!! as UserConfig).set as any).x.b = 2; + (actual[0].users[0].set as any).x.b = 2; }).toThrowErrorMatchingInlineSnapshot( `"Cannot add property b, object is not extensible"`, ); @@ -392,7 +400,7 @@ describe('readLdapConfig', () => { }; const actual = readProviderConfigs(new ConfigReader(config)); - expect(actual[0].users).toBeUndefined(); - expect(actual[0].groups).toBeUndefined(); + expect(actual[0].users).toHaveLength(0); + expect(actual[0].groups).toHaveLength(0); }); }); diff --git a/plugins/catalog-backend-module-ldap/src/ldap/config.ts b/plugins/catalog-backend-module-ldap/src/ldap/config.ts index d31de61605..9295639cae 100644 --- a/plugins/catalog-backend-module-ldap/src/ldap/config.ts +++ b/plugins/catalog-backend-module-ldap/src/ldap/config.ts @@ -42,9 +42,9 @@ export type LdapProviderConfig = { // command is not issued. bind?: BindConfig; // The settings that govern the reading and interpretation of users - users: UserConfigList; + users: UserConfig[]; // The settings that govern the reading and interpretation of groups - groups: GroupConfigList; + groups: GroupConfig[]; // Schedule configuration for refresh tasks. schedule?: TaskScheduleDefinition; }; @@ -76,13 +76,6 @@ export type BindConfig = { secret: string; }; -/** - * The settings that govern the reading and interpretation of users. - * - * @public - */ -export type UserConfigList = UserConfig | UserConfig[] | undefined; - /** * The settings that govern the reading and interpretation of users. * @@ -123,13 +116,6 @@ export type UserConfig = { }; }; -/** - * The settings that govern the reading and interpretation of groups. - * - * @public - */ -export type GroupConfigList = GroupConfig | GroupConfig[] | undefined; - /** * The settings that govern the reading and interpretation of groups. * @@ -175,34 +161,33 @@ export type GroupConfig = { }; }; -const defaultConfig = { - users: { - options: { - scope: 'one', - attributes: ['*', '+'], - }, - map: { - rdn: 'uid', - name: 'uid', - displayName: 'cn', - email: 'mail', - memberOf: 'memberOf', - }, +const defaultUserConfig = { + options: { + scope: 'one', + attributes: ['*', '+'], }, - groups: { - options: { - scope: 'one', - attributes: ['*', '+'], - }, - map: { - rdn: 'cn', - name: 'cn', - description: 'description', - displayName: 'cn', - type: 'groupType', - memberOf: 'memberOf', - members: 'member', - }, + map: { + rdn: 'uid', + name: 'uid', + displayName: 'cn', + email: 'mail', + memberOf: 'memberOf', + }, +}; + +const defaultGroupConfig = { + options: { + scope: 'one', + attributes: ['*', '+'], + }, + map: { + rdn: 'cn', + name: 'cn', + description: 'description', + displayName: 'cn', + type: 'groupType', + memberOf: 'memberOf', + members: 'member', }, }; @@ -326,18 +311,15 @@ function readUserConfig( c: Config | Config[] | undefined, ): RecursivePartial { if (!c) { - return undefined; + return []; } if (Array.isArray(c)) { - return c.map(it => { - return { - dn: it.getString('dn'), - options: readOptionsConfig(it.getOptionalConfig('options')), - set: readSetConfig(it.getOptionalConfig('set')), - map: readUserMapConfig(it.getOptionalConfig('map')), - }; - }); + return c.map(it => readSingleUserConfig(it)); } + return [readSingleUserConfig(c)]; +} + +function readSingleUserConfig(c: Config): RecursivePartial { return { dn: c.getString('dn'), options: readOptionsConfig(c.getOptionalConfig('options')), @@ -350,18 +332,15 @@ function readGroupConfig( c: Config | Config[] | undefined, ): RecursivePartial { if (!c) { - return undefined; + return []; } if (Array.isArray(c)) { - return c.map(it => { - return { - dn: it.getString('dn'), - options: readOptionsConfig(it.getOptionalConfig('options')), - set: readSetConfig(it.getOptionalConfig('set')), - map: readGroupMapConfig(it.getOptionalConfig('map')), - }; - }); + return c.map(it => readSingleGroupConfig(it)); } + return [readSingleGroupConfig(c)]; +} + +function readSingleGroupConfig(c: Config): RecursivePartial { return { dn: c.getString('dn'), options: readOptionsConfig(c.getOptionalConfig('options')), @@ -390,14 +369,15 @@ export function readLdapLegacyConfig(config: Config): LdapProviderConfig[] { target: trimEnd(c.getString('target'), '/'), tls: readTlsConfig(c.getOptionalConfig('tls')), bind: readBindConfig(c.getOptionalConfig('bind')), - users: readUserConfig(c.getConfig('users')), - groups: readGroupConfig(c.getConfig('groups')), + users: readUserConfig(c.getConfig('users')).map(it => { + return mergeWith({}, defaultUserConfig, it, replaceArraysIfPresent); + }), + groups: readGroupConfig(c.getConfig('groups')).map(it => { + return mergeWith({}, defaultGroupConfig, it, replaceArraysIfPresent); + }), }; - const merged = mergeWith({}, defaultConfig, newConfig, (_into, from) => { - // Replace arrays instead of merging, otherwise default behavior - return Array.isArray(from) ? from : undefined; - }); - return freeze(merged) as LdapProviderConfig; + + return freeze(newConfig) as LdapProviderConfig; }); } @@ -433,29 +413,24 @@ export function readProviderConfigs(config: Config): LdapProviderConfig[] { isUserList ? c.getOptionalConfigArray('users') : c.getOptionalConfig('users'), - ), + ).map(it => { + return mergeWith({}, defaultUserConfig, it, replaceArraysIfPresent); + }), groups: readGroupConfig( isGroupList ? c.getOptionalConfigArray('groups') : c.getOptionalConfig('groups'), - ), + ).map(it => { + return mergeWith({}, defaultGroupConfig, it, replaceArraysIfPresent); + }), schedule, }; - const merged = mergeWith( - {}, - defaultConfig, - newConfig, - (_value, srcValue, key, object, _source) => { - // Remove users and groups from default if they are not set in the new config - if ((key === 'users' || key === 'groups') && !srcValue) { - return (object[key] = srcValue); - } - // Replace arrays instead of merging, otherwise default behavior - return Array.isArray(srcValue) ? srcValue : undefined; - }, - ); - - return freeze(merged) as LdapProviderConfig; + return freeze(newConfig) as LdapProviderConfig; }); } + +function replaceArraysIfPresent(_into: any, from: any) { + // Replace arrays instead of merging, otherwise default behavior + return Array.isArray(from) ? from : undefined; +} diff --git a/plugins/catalog-backend-module-ldap/src/ldap/index.ts b/plugins/catalog-backend-module-ldap/src/ldap/index.ts index 81cab40b75..cfab5a4444 100644 --- a/plugins/catalog-backend-module-ldap/src/ldap/index.ts +++ b/plugins/catalog-backend-module-ldap/src/ldap/index.ts @@ -20,9 +20,7 @@ export { readProviderConfigs, readLdapLegacyConfig } from './config'; export type { LdapProviderConfig, GroupConfig, - GroupConfigList, UserConfig, - UserConfigList, BindConfig, TLSConfig, } from './config'; diff --git a/plugins/catalog-backend-module-ldap/src/ldap/read.test.ts b/plugins/catalog-backend-module-ldap/src/ldap/read.test.ts index 33c52477aa..1c3dfb179a 100644 --- a/plugins/catalog-backend-module-ldap/src/ldap/read.test.ts +++ b/plugins/catalog-backend-module-ldap/src/ldap/read.test.ts @@ -18,12 +18,7 @@ import { GroupEntity, UserEntity } from '@backstage/catalog-model'; import { SearchEntry } from 'ldapjs'; import merge from 'lodash/merge'; import { LdapClient } from './client'; -import { - GroupConfig, - GroupConfigList, - UserConfig, - UserConfigList, -} from './config'; +import { GroupConfig, UserConfig } from './config'; import { LDAP_DN_ANNOTATION, LDAP_RDN_ANNOTATION, @@ -104,19 +99,21 @@ describe('readLdapUsers', () => { }), ); }); - const config: UserConfig = { - dn: 'ddd', - options: {}, - map: { - rdn: 'uid', - name: 'uid', - description: 'description', - displayName: 'cn', - email: 'mail', - picture: 'avatarUrl', - memberOf: 'memberOf', + const config: UserConfig[] = [ + { + dn: 'ddd', + options: {}, + map: { + rdn: 'uid', + name: 'uid', + description: 'description', + displayName: 'cn', + email: 'mail', + picture: 'avatarUrl', + memberOf: 'memberOf', + }, }, - }; + ]; const { users, userMemberOf } = await readLdapUsers(client, config); expect(users).toEqual([ expect.objectContaining({ @@ -165,19 +162,21 @@ describe('readLdapUsers', () => { }), ); }); - const config: UserConfig = { - dn: 'ddd', - options: {}, - map: { - rdn: 'uid', - name: 'uid', - description: 'description', - displayName: 'cn', - email: 'mail', - picture: 'avatarUrl', - memberOf: 'memberOf', + const config: UserConfig[] = [ + { + dn: 'ddd', + options: {}, + map: { + rdn: 'uid', + name: 'uid', + description: 'description', + displayName: 'cn', + email: 'mail', + picture: 'avatarUrl', + memberOf: 'memberOf', + }, }, - }; + ]; const { users, userMemberOf } = await readLdapUsers(client, config); expect(users).toEqual([ expect.objectContaining({ @@ -221,19 +220,21 @@ describe('readLdapUsers', () => { }), ); }); - const config: UserConfig = { - dn: 'ddd', - options: {}, - map: { - rdn: 'uid', - name: 'uid', - description: 'description', - displayName: 'cn', - email: 'mail', - picture: 'avatarUrl', - memberOf: 'memberOf', + const config: UserConfig[] = [ + { + dn: 'ddd', + options: {}, + map: { + rdn: 'uid', + name: 'uid', + description: 'description', + displayName: 'cn', + email: 'mail', + picture: 'avatarUrl', + memberOf: 'memberOf', + }, }, - }; + ]; const { users, userMemberOf } = await readLdapUsers(client, config); expect(users).toEqual([ expect.objectContaining({ @@ -276,7 +277,7 @@ describe('readLdapUsers', () => { }), ); }); - const config: UserConfigList = [ + const config: UserConfig[] = [ { dn: 'ddd', options: {}, @@ -308,7 +309,7 @@ describe('readLdapUsers', () => { expect(users).toHaveLength(2); }); it('can process no UserConfigs', async () => { - const config: UserConfigList = undefined; + const config: UserConfig[] = []; const { users } = await readLdapUsers(client, config); expect(users).toHaveLength(0); }); @@ -339,21 +340,23 @@ describe('readLdapGroups', () => { }), ); }); - const config: GroupConfig = { - dn: 'ddd', - options: {}, - map: { - rdn: 'cn', - name: 'cn', - description: 'description', - displayName: 'cn', - email: 'mail', - picture: 'avatarUrl', - type: 'tt', - memberOf: 'memberOf', - members: 'member', + const config: GroupConfig[] = [ + { + dn: 'ddd', + options: {}, + map: { + rdn: 'cn', + name: 'cn', + description: 'description', + displayName: 'cn', + email: 'mail', + picture: 'avatarUrl', + type: 'tt', + memberOf: 'memberOf', + members: 'member', + }, }, - }; + ]; const { groups, groupMember, groupMemberOf } = await readLdapGroups( client, config, @@ -410,21 +413,23 @@ describe('readLdapGroups', () => { }), ); }); - const config: GroupConfig = { - dn: 'ddd', - options: {}, - map: { - rdn: 'cn', - name: 'cn', - description: 'description', - displayName: 'cn', - email: 'mail', - picture: 'avatarUrl', - type: 'tt', - memberOf: 'memberOf', - members: 'member', + const config: GroupConfig[] = [ + { + dn: 'ddd', + options: {}, + map: { + rdn: 'cn', + name: 'cn', + description: 'description', + displayName: 'cn', + email: 'mail', + picture: 'avatarUrl', + type: 'tt', + memberOf: 'memberOf', + members: 'member', + }, }, - }; + ]; const { groups, groupMember, groupMemberOf } = await readLdapGroups( client, config, @@ -476,7 +481,7 @@ describe('readLdapGroups', () => { }), ); }); - const config: GroupConfigList = [ + const config: GroupConfig[] = [ { dn: 'ddd', options: {}, @@ -513,7 +518,7 @@ describe('readLdapGroups', () => { }); it('can process no GroupConfigs', async () => { - const config: GroupConfigList = undefined; + const config: GroupConfig[] = []; const { groups } = await readLdapGroups(client, config); expect(groups).toHaveLength(0); }); diff --git a/plugins/catalog-backend-module-ldap/src/ldap/read.ts b/plugins/catalog-backend-module-ldap/src/ldap/read.ts index 5dadcaede2..9e6e11a0bc 100644 --- a/plugins/catalog-backend-module-ldap/src/ldap/read.ts +++ b/plugins/catalog-backend-module-ldap/src/ldap/read.ts @@ -24,12 +24,7 @@ import lodashSet from 'lodash/set'; import cloneDeep from 'lodash/cloneDeep'; import { buildOrgHierarchy } from './org'; import { LdapClient } from './client'; -import { - GroupConfig, - GroupConfigList, - UserConfig, - UserConfigList, -} from './config'; +import { GroupConfig, UserConfig } from './config'; import { LDAP_DN_ANNOTATION, LDAP_RDN_ANNOTATION, @@ -109,23 +104,22 @@ export async function defaultUserTransformer( */ export async function readLdapUsers( client: LdapClient, - config: UserConfigList, + config: UserConfig[], opts?: { transformer?: UserTransformer }, ): Promise<{ users: UserEntity[]; // With all relations empty userMemberOf: Map>; // DN -> DN or UUID of groups }> { - if (!config) { + if (config.length === 0) { return { users: [], userMemberOf: new Map() }; } - const configs = Array.isArray(config) ? config : [config]; const entities: UserEntity[] = []; const userMemberOf: Map> = new Map(); const vendor = await client.getVendor(); const transformer = opts?.transformer ?? defaultUserTransformer; - for (const cfg of configs) { + for (const cfg of config) { const { dn, options, map } = cfg; await client.searchStreaming(dn, options, async user => { const entity = await transformer(vendor, cfg, user); @@ -216,7 +210,7 @@ export async function defaultGroupTransformer( */ export async function readLdapGroups( client: LdapClient, - config: GroupConfigList, + config: GroupConfig[], opts?: { transformer?: GroupTransformer; }, @@ -225,10 +219,9 @@ export async function readLdapGroups( groupMemberOf: Map>; // DN -> DN or UUID of groups groupMember: Map>; // DN -> DN or UUID of groups & users }> { - if (!config) { + if (config.length === 0) { return { groups: [], groupMemberOf: new Map(), groupMember: new Map() }; } - const configs = Array.isArray(config) ? config : [config]; const groups: GroupEntity[] = []; const groupMemberOf: Map> = new Map(); const groupMember: Map> = new Map(); @@ -236,7 +229,7 @@ export async function readLdapGroups( const vendor = await client.getVendor(); const transformer = opts?.transformer ?? defaultGroupTransformer; - for (const cfg of configs) { + for (const cfg of config) { const { dn, map, options } = cfg; await client.searchStreaming(dn, options, async entry => { @@ -280,8 +273,8 @@ export async function readLdapGroups( */ export async function readLdapOrg( client: LdapClient, - userConfig: UserConfigList, - groupConfig: GroupConfigList, + userConfig: UserConfig[], + groupConfig: GroupConfig[], options: { groupTransformer?: GroupTransformer; userTransformer?: UserTransformer; From 427ae454727b9d16de844166838564527ee5bfcd Mon Sep 17 00:00:00 2001 From: Jente Sondervorst Date: Mon, 17 Jun 2024 22:45:18 +0200 Subject: [PATCH 035/416] adapt test Closes: #25256 Signed-off-by: Jente Sondervorst --- plugins/catalog-backend-module-ldap/src/ldap/config.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/catalog-backend-module-ldap/src/ldap/config.test.ts b/plugins/catalog-backend-module-ldap/src/ldap/config.test.ts index 553bf3c525..b81339c325 100644 --- a/plugins/catalog-backend-module-ldap/src/ldap/config.test.ts +++ b/plugins/catalog-backend-module-ldap/src/ldap/config.test.ts @@ -341,12 +341,12 @@ describe('readLdapConfig', () => { ); expect(() => { - (actual[0].users[0].set as any).y = 2; + (actual[0].groups[0].set as any).y = 2; }).toThrowErrorMatchingInlineSnapshot( `"Cannot add property y, object is not extensible"`, ); expect(() => { - (actual[0].users[0].set as any).x.b = 2; + (actual[0].groups[0].set as any).x.b = 2; }).toThrowErrorMatchingInlineSnapshot( `"Cannot add property b, object is not extensible"`, ); From c324de8ccd2fcf63da0049c0643b9850dffa91e8 Mon Sep 17 00:00:00 2001 From: mario ma Date: Mon, 4 Mar 2024 20:07:29 +0800 Subject: [PATCH 036/416] feat: add i18n to plugin-catalog Signed-off-by: mario ma --- .../src/components/AboutCard/AboutCard.tsx | 21 +-- .../src/components/AboutCard/AboutContent.tsx | 47 +++--- .../CatalogPage/DefaultCatalogPage.tsx | 2 +- .../CatalogSearchResultListItem.tsx | 13 +- .../components/CatalogTable/CatalogTable.tsx | 13 +- .../DependencyOfComponentsCard.tsx | 10 +- .../DependsOnComponentsCard.tsx | 7 +- .../DependsOnResourcesCard.tsx | 7 +- .../EntityContextMenu/EntityContextMenu.tsx | 13 +- .../EntityContextMenu/UnregisterEntity.tsx | 5 +- .../EntityLabelsCard/EntityLabelsCard.tsx | 5 +- .../EntityLabelsEmptyState.tsx | 8 +- .../components/EntityLayout/EntityLayout.tsx | 10 +- .../EntityLinksCard/EntityLinksCard.tsx | 5 +- .../EntityLinksCard/EntityLinksEmptyState.tsx | 8 +- .../EntityNotFound/EntityNotFound.tsx | 10 +- .../DeleteEntityDialog.tsx | 9 +- .../EntityOrphanWarning.tsx | 6 +- .../EntityProcessingErrorsPanel.tsx | 5 +- .../EntityRelationWarning.tsx | 9 +- .../HasComponentsCard/HasComponentsCard.tsx | 7 +- .../HasResourcesCard/HasResourcesCard.tsx | 7 +- .../HasSubcomponentsCard.tsx | 7 +- .../HasSystemsCard/HasSystemsCard.tsx | 7 +- .../RelatedEntitiesCard.tsx | 7 +- .../SystemDiagramCard/SystemDiagramCard.tsx | 17 ++- plugins/catalog/src/translation.ts | 135 ++++++++++++++++++ 27 files changed, 314 insertions(+), 86 deletions(-) diff --git a/plugins/catalog/src/components/AboutCard/AboutCard.tsx b/plugins/catalog/src/components/AboutCard/AboutCard.tsx index ee6147c54e..ed196fe3e0 100644 --- a/plugins/catalog/src/components/AboutCard/AboutCard.tsx +++ b/plugins/catalog/src/components/AboutCard/AboutCard.tsx @@ -64,6 +64,8 @@ import { catalogEntityRefreshPermission } from '@backstage/plugin-catalog-common import { useSourceTemplateCompoundEntityRef } from './hooks'; import { taskCreatePermission } from '@backstage/plugin-scaffolder-common/alpha'; import { usePermission } from '@backstage/plugin-permission-react'; +import { catalogTranslationRef } from '../../translation'; +import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; const TECHDOCS_ANNOTATION = 'backstage.io/techdocs-ref'; @@ -116,6 +118,7 @@ export function AboutCard(props: AboutCardProps) { const { allowed: canRefresh } = useEntityPermission( catalogEntityRefreshPermission, ); + const { t } = useTranslationRef(catalogTranslationRef); const { allowed: canCreateTemplateTask } = usePermission({ permission: taskCreatePermission, @@ -142,13 +145,13 @@ export function AboutCard(props: AboutCardProps) { } const viewInSource: IconLinkVerticalProps = { - label: 'View Source', + label: t('aboutCard.viewSource'), disabled: !entitySourceLocation, icon: , href: entitySourceLocation?.locationTargetUrl, }; const viewInTechDocs: IconLinkVerticalProps = { - label: 'View TechDocs', + label: t('aboutCard.viewTechdocs'), disabled: !( entity.metadata.annotations?.[TECHDOCS_ANNOTATION] || @@ -176,7 +179,7 @@ export function AboutCard(props: AboutCardProps) { const Icon = app.getSystemIcon('scaffolder') ?? CreateComponentIcon; const launchTemplate: IconLinkVerticalProps = { - label: 'Launch Template', + label: t('aboutCard.launchTemplate'), icon: , disabled: !templateRoute || !canCreateTemplateTask, href: @@ -212,25 +215,25 @@ export function AboutCard(props: AboutCardProps) { try { await catalogApi.refreshEntity(stringifyEntityRef(entity)); alertApi.post({ - message: 'Refresh scheduled', + message: t('aboutCard.refreshScheduledMessage'), severity: 'info', display: 'transient', }); } catch (e) { errorApi.post(e); } - }, [catalogApi, alertApi, errorApi, entity]); + }, [catalogApi, entity, alertApi, t, errorApi]); return ( {allowRefresh && canRefresh && ( @@ -240,7 +243,7 @@ export function AboutCard(props: AboutCardProps) { component={Link} aria-label="Edit" disabled={!entityMetadataEditUrl} - title="Edit Metadata" + title={t('aboutCard.editButtonTitle')} to={entityMetadataEditUrl ?? '#'} > @@ -248,7 +251,7 @@ export function AboutCard(props: AboutCardProps) { {sourceTemplateRef && templateRoute && ( - + {ownedByRelations.length > 0 && ( @@ -130,8 +140,8 @@ export function AboutContent(props: AboutContentProps) { {(isSystem || partOfDomainRelations.length > 0) && ( {partOfDomainRelations.length > 0 && ( @@ -147,8 +157,8 @@ export function AboutContent(props: AboutContentProps) { isResource || partOfSystemRelations.length > 0) && ( {partOfSystemRelations.length > 0 && ( @@ -161,8 +171,8 @@ export function AboutContent(props: AboutContentProps) { )} {isComponent && partOfComponentRelations.length > 0 && ( @@ -188,22 +198,25 @@ export function AboutContent(props: AboutContentProps) { isComponent || typeof entity?.spec?.lifecycle === 'string') && ( )} - {(entity?.metadata?.tags || []).map(t => ( - + {(entity?.metadata?.tags || []).map(tag => ( + ))} {isLocation && (entity?.spec?.targets || entity?.spec?.target) && ( - + )} - All your software catalog entities + {t('indexPage.supportButtonContent')} diff --git a/plugins/catalog/src/components/CatalogSearchResultListItem/CatalogSearchResultListItem.tsx b/plugins/catalog/src/components/CatalogSearchResultListItem/CatalogSearchResultListItem.tsx index 32c86f38b7..1a596f8b9b 100644 --- a/plugins/catalog/src/components/CatalogSearchResultListItem/CatalogSearchResultListItem.tsx +++ b/plugins/catalog/src/components/CatalogSearchResultListItem/CatalogSearchResultListItem.tsx @@ -27,6 +27,8 @@ import { ResultHighlight, } from '@backstage/plugin-search-common'; import { HighlightedSearchResultText } from '@backstage/plugin-search-react'; +import { catalogTranslationRef } from '../../translation'; +import { useTranslationRef } from '@backstage/frontend-plugin-api'; const useStyles = makeStyles( { @@ -66,6 +68,7 @@ export function CatalogSearchResultListItem( const highlight = props.highlight as ResultHighlight; const classes = useStyles(); + const { t } = useTranslationRef(catalogTranslationRef); if (!result) return null; @@ -121,10 +124,16 @@ export function CatalogSearchResultListItem( {result.kind && } {result.type && } {result.lifecycle && ( - + )} {result.owner && ( - + )} diff --git a/plugins/catalog/src/components/CatalogTable/CatalogTable.tsx b/plugins/catalog/src/components/CatalogTable/CatalogTable.tsx index b1590bdff3..e18467249a 100644 --- a/plugins/catalog/src/components/CatalogTable/CatalogTable.tsx +++ b/plugins/catalog/src/components/CatalogTable/CatalogTable.tsx @@ -48,6 +48,8 @@ import { columnFactories } from './columns'; import { CatalogTableColumnsFunc, CatalogTableRow } from './types'; import { PaginatedCatalogTable } from './PaginatedCatalogTable'; import { defaultCatalogTableColumnsFunc } from './defaultCatalogTableColumnsFunc'; +import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; +import { catalogTranslationRef } from '../../translation'; /** * Props for {@link CatalogTable}. @@ -96,13 +98,14 @@ export const CatalogTable = (props: CatalogTableProps) => { typeof columns === 'function' ? columns(entityListContext) : columns, [columns, entityListContext], ); + const { t } = useTranslationRef(catalogTranslationRef); if (error) { return (
@@ -113,7 +116,7 @@ export const CatalogTable = (props: CatalogTableProps) => { const defaultActions: TableProps['actions'] = [ ({ entity }) => { const url = entity.metadata.annotations?.[ANNOTATION_VIEW_URL]; - const title = 'View'; + const title = t('catalogTable.viewActionTitle'); return { icon: () => ( @@ -132,7 +135,7 @@ export const CatalogTable = (props: CatalogTableProps) => { }, ({ entity }) => { const url = entity.metadata.annotations?.[ANNOTATION_EDIT_URL]; - const title = 'Edit'; + const title = t('catalogTable.editActionTitle'); return { icon: () => ( @@ -151,7 +154,9 @@ export const CatalogTable = (props: CatalogTableProps) => { }, ({ entity }) => { const isStarred = isStarredEntity(entity); - const title = isStarred ? 'Remove from favorites' : 'Add to favorites'; + const title = isStarred + ? t('catalogTable.unStarActionTitle') + : t('catalogTable.starActionTitle'); return { cellStyle: { paddingLeft: '1em' }, diff --git a/plugins/catalog/src/components/DependencyOfComponentsCard/DependencyOfComponentsCard.tsx b/plugins/catalog/src/components/DependencyOfComponentsCard/DependencyOfComponentsCard.tsx index d87b558048..617d009d4f 100644 --- a/plugins/catalog/src/components/DependencyOfComponentsCard/DependencyOfComponentsCard.tsx +++ b/plugins/catalog/src/components/DependencyOfComponentsCard/DependencyOfComponentsCard.tsx @@ -23,6 +23,8 @@ import { componentEntityHelpLink, RelatedEntitiesCard, } from '../RelatedEntitiesCard'; +import { catalogTranslationRef } from '../../translation'; +import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; /** @public */ export interface DependencyOfComponentsCardProps { @@ -33,7 +35,11 @@ export interface DependencyOfComponentsCardProps { export function DependencyOfComponentsCard( props: DependencyOfComponentsCardProps, ) { - const { variant = 'gridItem', title = 'Dependency of components' } = props; + const { t } = useTranslationRef(catalogTranslationRef); + const { + variant = 'gridItem', + title = t('dependencyOfComponentsCard.title'), + } = props; return ( diff --git a/plugins/catalog/src/components/DependsOnComponentsCard/DependsOnComponentsCard.tsx b/plugins/catalog/src/components/DependsOnComponentsCard/DependsOnComponentsCard.tsx index f4ea850b9b..fe56ea582b 100644 --- a/plugins/catalog/src/components/DependsOnComponentsCard/DependsOnComponentsCard.tsx +++ b/plugins/catalog/src/components/DependsOnComponentsCard/DependsOnComponentsCard.tsx @@ -27,6 +27,8 @@ import { componentEntityHelpLink, RelatedEntitiesCard, } from '../RelatedEntitiesCard'; +import { catalogTranslationRef } from '../../translation'; +import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; /** @public */ export interface DependsOnComponentsCardProps { @@ -37,9 +39,10 @@ export interface DependsOnComponentsCardProps { } export function DependsOnComponentsCard(props: DependsOnComponentsCardProps) { + const { t } = useTranslationRef(catalogTranslationRef); const { variant = 'gridItem', - title = 'Depends on components', + title = t('dependsOnComponentsCard.title'), columns = componentEntityColumns, tableOptions = {}, } = props; @@ -50,7 +53,7 @@ export function DependsOnComponentsCard(props: DependsOnComponentsCardProps) { entityKind="Component" relationType={RELATION_DEPENDS_ON} columns={columns} - emptyMessage="No component is a dependency of this component" + emptyMessage={t('dependsOnComponentsCard.emptyMessage')} emptyHelpLink={componentEntityHelpLink} asRenderableEntities={asComponentEntities} tableOptions={tableOptions} diff --git a/plugins/catalog/src/components/DependsOnResourcesCard/DependsOnResourcesCard.tsx b/plugins/catalog/src/components/DependsOnResourcesCard/DependsOnResourcesCard.tsx index d99a9df387..281bfd8766 100644 --- a/plugins/catalog/src/components/DependsOnResourcesCard/DependsOnResourcesCard.tsx +++ b/plugins/catalog/src/components/DependsOnResourcesCard/DependsOnResourcesCard.tsx @@ -27,6 +27,8 @@ import { RelatedEntitiesCard, resourceEntityColumns, } from '../RelatedEntitiesCard'; +import { catalogTranslationRef } from '../../translation'; +import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; /** @public */ export interface DependsOnResourcesCardProps { @@ -37,9 +39,10 @@ export interface DependsOnResourcesCardProps { } export function DependsOnResourcesCard(props: DependsOnResourcesCardProps) { + const { t } = useTranslationRef(catalogTranslationRef); const { variant = 'gridItem', - title = 'Depends on resources', + title = t('dependsOnResourcesCard.title'), columns = resourceEntityColumns, tableOptions = {}, } = props; @@ -50,7 +53,7 @@ export function DependsOnResourcesCard(props: DependsOnResourcesCardProps) { entityKind="Resource" relationType={RELATION_DEPENDS_ON} columns={columns} - emptyMessage="No resource is a dependency of this component" + emptyMessage={t('dependsOnResourcesCard.emptyMessage')} emptyHelpLink={componentEntityHelpLink} asRenderableEntities={asResourceEntities} tableOptions={tableOptions} diff --git a/plugins/catalog/src/components/EntityContextMenu/EntityContextMenu.tsx b/plugins/catalog/src/components/EntityContextMenu/EntityContextMenu.tsx index a173773e35..5b740038a1 100644 --- a/plugins/catalog/src/components/EntityContextMenu/EntityContextMenu.tsx +++ b/plugins/catalog/src/components/EntityContextMenu/EntityContextMenu.tsx @@ -33,6 +33,8 @@ import { catalogEntityDeletePermission } from '@backstage/plugin-catalog-common/ import { UnregisterEntity, UnregisterEntityOptions } from './UnregisterEntity'; import { useApi, alertApiRef } from '@backstage/core-plugin-api'; import useCopyToClipboard from 'react-use/esm/useCopyToClipboard'; +import { catalogTranslationRef } from '../../translation'; +import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; /** @public */ export type EntityContextMenuClassKey = 'button'; @@ -70,6 +72,7 @@ export function EntityContextMenu(props: EntityContextMenuProps) { onUnregisterEntity, onInspectEntity, } = props; + const { t } = useTranslationRef(catalogTranslationRef); const [anchorEl, setAnchorEl] = useState(); const classes = useStyles(); const unregisterPermission = useEntityPermission( @@ -90,12 +93,12 @@ export function EntityContextMenu(props: EntityContextMenuProps) { useEffect(() => { if (!copyState.error && copyState.value) { alertApi.post({ - message: 'Copied!', + message: t('entityContextMenu.copiedMessage'), severity: 'info', display: 'transient', }); } - }, [copyState, alertApi]); + }, [copyState, alertApi, t]); const extraItems = UNSTABLE_extraContextMenuItems && [ ...UNSTABLE_extraContextMenuItems.map(item => ( @@ -117,7 +120,7 @@ export function EntityContextMenu(props: EntityContextMenuProps) { return ( <> - + - + { @@ -168,7 +171,7 @@ export function EntityContextMenu(props: EntityContextMenuProps) { - + diff --git a/plugins/catalog/src/components/EntityContextMenu/UnregisterEntity.tsx b/plugins/catalog/src/components/EntityContextMenu/UnregisterEntity.tsx index 3de890097b..08496d4819 100644 --- a/plugins/catalog/src/components/EntityContextMenu/UnregisterEntity.tsx +++ b/plugins/catalog/src/components/EntityContextMenu/UnregisterEntity.tsx @@ -19,6 +19,8 @@ import ListItemIcon from '@material-ui/core/ListItemIcon'; import ListItemText from '@material-ui/core/ListItemText'; import MenuItem from '@material-ui/core/MenuItem'; import CancelIcon from '@material-ui/icons/Cancel'; +import { catalogTranslationRef } from '../../translation'; +import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; type VisibleType = 'visible' | 'hidden' | 'disable'; @@ -40,6 +42,7 @@ export function UnregisterEntity(props: UnregisterEntityProps) { onUnregisterEntity, onClose, } = props; + const { t } = useTranslationRef(catalogTranslationRef); const isBoolean = typeof unregisterEntityOptions?.disableUnregister === 'boolean'; @@ -65,7 +68,7 @@ export function UnregisterEntity(props: UnregisterEntityProps) { - + ); } diff --git a/plugins/catalog/src/components/EntityLabelsCard/EntityLabelsCard.tsx b/plugins/catalog/src/components/EntityLabelsCard/EntityLabelsCard.tsx index 0b1448bb1f..d48b45f054 100644 --- a/plugins/catalog/src/components/EntityLabelsCard/EntityLabelsCard.tsx +++ b/plugins/catalog/src/components/EntityLabelsCard/EntityLabelsCard.tsx @@ -25,6 +25,8 @@ import { import { EntityLabelsEmptyState } from './EntityLabelsEmptyState'; import Typography from '@material-ui/core/Typography'; import { makeStyles } from '@material-ui/core/styles'; +import { catalogTranslationRef } from '../../translation'; +import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; /** @public */ export interface EntityLabelsCardProps { @@ -42,6 +44,7 @@ export const EntityLabelsCard = (props: EntityLabelsCardProps) => { const { variant, title } = props; const { entity } = useEntity(); const classes = useStyles(); + const { t } = useTranslationRef(catalogTranslationRef); const columns: TableColumn<{ key: string; value: string }>[] = [ { @@ -61,7 +64,7 @@ export const EntityLabelsCard = (props: EntityLabelsCardProps) => { const labels = entity?.metadata?.labels; return ( - + {!labels || Object.keys(labels).length === 0 ? ( ) : ( diff --git a/plugins/catalog/src/components/EntityLabelsCard/EntityLabelsEmptyState.tsx b/plugins/catalog/src/components/EntityLabelsCard/EntityLabelsEmptyState.tsx index 5f5db0baa5..16d0a3a897 100644 --- a/plugins/catalog/src/components/EntityLabelsCard/EntityLabelsEmptyState.tsx +++ b/plugins/catalog/src/components/EntityLabelsCard/EntityLabelsEmptyState.tsx @@ -19,6 +19,8 @@ import Typography from '@material-ui/core/Typography'; import { makeStyles } from '@material-ui/core/styles'; import React from 'react'; import { CodeSnippet } from '@backstage/core-components'; +import { catalogTranslationRef } from '../../translation'; +import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; const ENTITY_YAML = `metadata: name: example @@ -39,12 +41,12 @@ const useStyles = makeStyles( export function EntityLabelsEmptyState() { const classes = useStyles(); + const { t } = useTranslationRef(catalogTranslationRef); return ( <> - No labels defined for this entity. You can add labels to your entity - YAML as shown in the highlighted example below: + {t('entityLabelsCard.emptyDescription')}
- Read more + {t('entityLabelsCard.readMoreButtonTitle')} ); diff --git a/plugins/catalog/src/components/EntityLayout/EntityLayout.tsx b/plugins/catalog/src/components/EntityLayout/EntityLayout.tsx index 274972283f..bbc7792acb 100644 --- a/plugins/catalog/src/components/EntityLayout/EntityLayout.tsx +++ b/plugins/catalog/src/components/EntityLayout/EntityLayout.tsx @@ -53,6 +53,8 @@ import React, { useEffect, useState } from 'react'; import { useLocation, useNavigate } from 'react-router-dom'; import { EntityContextMenu } from '../EntityContextMenu/EntityContextMenu'; import { rootRouteRef, unregisterRedirectRouteRef } from '../../routes'; +import { catalogTranslationRef } from '../../translation'; +import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; /** @public */ export type EntityLayoutRouteProps = { @@ -117,11 +119,12 @@ function headerProps( function EntityLabels(props: { entity: Entity }) { const { entity } = props; const ownedByRelations = getEntityRelations(entity, RELATION_OWNED_BY); + const { t } = useTranslationRef(catalogTranslationRef); return ( <> {ownedByRelations.length > 0 && ( )} @@ -234,6 +237,7 @@ export const EntityLayout = (props: EntityLayoutProps) => { const navigate = useNavigate(); const catalogRoute = useRouteRef(rootRouteRef); const unregisterRedirectRoute = useRouteRef(unregisterRedirectRouteRef); + const { t } = useTranslationRef(catalogTranslationRef); const cleanUpAfterRemoval = async () => { setConfirmationDialogOpen(false); @@ -286,7 +290,7 @@ export const EntityLayout = (props: EntityLayoutProps) => { {NotFoundComponent ? ( NotFoundComponent ) : ( - + There is no {kind} with the requested{' '} kind, namespace, and name diff --git a/plugins/catalog/src/components/EntityLinksCard/EntityLinksCard.tsx b/plugins/catalog/src/components/EntityLinksCard/EntityLinksCard.tsx index ebc551c29f..b5d8269a0b 100644 --- a/plugins/catalog/src/components/EntityLinksCard/EntityLinksCard.tsx +++ b/plugins/catalog/src/components/EntityLinksCard/EntityLinksCard.tsx @@ -22,6 +22,8 @@ import { LinksGridList } from './LinksGridList'; import { ColumnBreakpoints } from './types'; import { IconComponent, useApp } from '@backstage/core-plugin-api'; import { InfoCard, InfoCardVariants } from '@backstage/core-components'; +import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; +import { catalogTranslationRef } from '../../translation'; /** @public */ export interface EntityLinksCardProps { @@ -33,6 +35,7 @@ export const EntityLinksCard = (props: EntityLinksCardProps) => { const { cols = undefined, variant } = props; const { entity } = useEntity(); const app = useApp(); + const { t } = useTranslationRef(catalogTranslationRef); const iconResolver = (key?: string): IconComponent => key ? app.getSystemIcon(key) ?? LanguageIcon : LanguageIcon; @@ -40,7 +43,7 @@ export const EntityLinksCard = (props: EntityLinksCardProps) => { const links = entity?.metadata?.links; return ( - + {!links || links.length === 0 ? ( ) : ( diff --git a/plugins/catalog/src/components/EntityLinksCard/EntityLinksEmptyState.tsx b/plugins/catalog/src/components/EntityLinksCard/EntityLinksEmptyState.tsx index 81009c5393..09362385f9 100644 --- a/plugins/catalog/src/components/EntityLinksCard/EntityLinksEmptyState.tsx +++ b/plugins/catalog/src/components/EntityLinksCard/EntityLinksEmptyState.tsx @@ -19,6 +19,8 @@ import Typography from '@material-ui/core/Typography'; import { makeStyles } from '@material-ui/core/styles'; import React from 'react'; import { CodeSnippet } from '@backstage/core-components'; +import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; +import { catalogTranslationRef } from '../../translation'; const ENTITY_YAML = `metadata: name: example @@ -44,12 +46,12 @@ const useStyles = makeStyles( export function EntityLinksEmptyState() { const classes = useStyles(); + const { t } = useTranslationRef(catalogTranslationRef); return ( <> - No links defined for this entity. You can add links to your entity YAML - as shown in the highlighted example below: + {t('entityLinksCard.emptyDescription')}
- Read more + {t('entityLinksCard.readMoreButtonTitle')} ); diff --git a/plugins/catalog/src/components/EntityNotFound/EntityNotFound.tsx b/plugins/catalog/src/components/EntityNotFound/EntityNotFound.tsx index 479edf3984..252005dff5 100644 --- a/plugins/catalog/src/components/EntityNotFound/EntityNotFound.tsx +++ b/plugins/catalog/src/components/EntityNotFound/EntityNotFound.tsx @@ -20,6 +20,8 @@ import Button from '@material-ui/core/Button'; import Typography from '@material-ui/core/Typography'; import { makeStyles } from '@material-ui/core/styles'; import { Illo } from './Illo'; +import { catalogTranslationRef } from '../../translation'; +import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; const useStyles = makeStyles(theme => ({ container: { @@ -45,24 +47,24 @@ const useStyles = makeStyles(theme => ({ export function EntityNotFound() { const classes = useStyles(); + const { t } = useTranslationRef(catalogTranslationRef); return ( - Entity was not found + {t('entityNotFound.title')} - Want to help us build this? Check out our Getting Started - documentation. + {t('entityNotFound.description')} diff --git a/plugins/catalog/src/components/EntityOrphanWarning/DeleteEntityDialog.tsx b/plugins/catalog/src/components/EntityOrphanWarning/DeleteEntityDialog.tsx index 603f2040d9..c9c24a14a1 100644 --- a/plugins/catalog/src/components/EntityOrphanWarning/DeleteEntityDialog.tsx +++ b/plugins/catalog/src/components/EntityOrphanWarning/DeleteEntityDialog.tsx @@ -23,6 +23,8 @@ import DialogTitle from '@material-ui/core/DialogTitle'; import React, { useState } from 'react'; import { alertApiRef, useApi } from '@backstage/core-plugin-api'; import { assertError } from '@backstage/errors'; +import { catalogTranslationRef } from '../../translation'; +import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; interface DeleteEntityDialogProps { open: boolean; @@ -36,6 +38,7 @@ export function DeleteEntityDialog(props: DeleteEntityDialogProps) { const [busy, setBusy] = useState(false); const catalogApi = useApi(catalogApiRef); const alertApi = useApi(alertApiRef); + const { t } = useTranslationRef(catalogTranslationRef); const onDelete = async () => { setBusy(true); @@ -54,7 +57,7 @@ export function DeleteEntityDialog(props: DeleteEntityDialogProps) { return ( - Are you sure you want to delete this entity? + {t('deleteEntity.dialogTitle')} diff --git a/plugins/catalog/src/components/EntityOrphanWarning/EntityOrphanWarning.tsx b/plugins/catalog/src/components/EntityOrphanWarning/EntityOrphanWarning.tsx index 8a17559681..10a10e54fd 100644 --- a/plugins/catalog/src/components/EntityOrphanWarning/EntityOrphanWarning.tsx +++ b/plugins/catalog/src/components/EntityOrphanWarning/EntityOrphanWarning.tsx @@ -22,6 +22,8 @@ import { useNavigate } from 'react-router-dom'; import { DeleteEntityDialog } from './DeleteEntityDialog'; import { useRouteRef } from '@backstage/core-plugin-api'; import { rootRouteRef } from '../../routes'; +import { catalogTranslationRef } from '../../translation'; +import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; /** * Returns true if the given entity has the orphan annotation given by the @@ -44,6 +46,7 @@ export function EntityOrphanWarning() { const catalogLink = useRouteRef(rootRouteRef); const [confirmationDialogOpen, setConfirmationDialogOpen] = useState(false); const { entity } = useEntity(); + const { t } = useTranslationRef(catalogTranslationRef); const cleanUpAfterRemoval = async () => { setConfirmationDialogOpen(false); @@ -53,8 +56,7 @@ export function EntityOrphanWarning() { return ( <> setConfirmationDialogOpen(true)}> - This entity is not referenced by any location and is therefore not - receiving updates. Click here to delete. + {t('deleteEntity.description')} i.error && @@ -95,6 +97,7 @@ export function EntityProcessingErrorsPanel() { const { loading, error, value } = useAsync(async () => { return getOwnAndAncestorsErrors(entityRef, catalogApi); }, [entityRef, catalogApi]); + const { t } = useTranslationRef(catalogTranslationRef); if (error) { return ( @@ -115,7 +118,7 @@ export function EntityProcessingErrorsPanel() { {stringifyEntityRef(entity) !== stringifyEntityRef(ancestorError.entity) && ( - The error below originates from{' '} + {t('entityProcessingErrorsDescription')}{' '} )} diff --git a/plugins/catalog/src/components/EntityRelationWarning/EntityRelationWarning.tsx b/plugins/catalog/src/components/EntityRelationWarning/EntityRelationWarning.tsx index 13542a32b4..2ce9120bf0 100644 --- a/plugins/catalog/src/components/EntityRelationWarning/EntityRelationWarning.tsx +++ b/plugins/catalog/src/components/EntityRelationWarning/EntityRelationWarning.tsx @@ -26,6 +26,8 @@ import useAsync from 'react-use/esm/useAsync'; import Box from '@material-ui/core/Box'; import { ResponseErrorPanel } from '@backstage/core-components'; import { useApi, ApiHolder } from '@backstage/core-plugin-api'; +import { catalogTranslationRef } from '../../translation'; +import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; async function getRelationWarnings(entity: Entity, catalogApi: CatalogApi) { const entityRefRelations = entity.relations?.map( @@ -80,6 +82,7 @@ export function EntityRelationWarning() { const { loading, error, value } = useAsync(async () => { return getRelationWarnings(entity, catalogApi); }, [entity, catalogApi]); + const { t } = useTranslationRef(catalogTranslationRef); if (error) { return ( @@ -95,10 +98,8 @@ export function EntityRelationWarning() { return ( <> - - This entity has relations to other entities, which can't be found in the - catalog.
- Entities not found are: {value.join(', ')} + + {t('entityRelationWarningDescription')} {value.join(', ')} ); diff --git a/plugins/catalog/src/components/HasComponentsCard/HasComponentsCard.tsx b/plugins/catalog/src/components/HasComponentsCard/HasComponentsCard.tsx index 9071dac030..917543dd12 100644 --- a/plugins/catalog/src/components/HasComponentsCard/HasComponentsCard.tsx +++ b/plugins/catalog/src/components/HasComponentsCard/HasComponentsCard.tsx @@ -23,6 +23,8 @@ import { componentEntityHelpLink, RelatedEntitiesCard, } from '../RelatedEntitiesCard'; +import { catalogTranslationRef } from '../../translation'; +import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; /** @public */ export interface HasComponentsCardProps { @@ -31,7 +33,8 @@ export interface HasComponentsCardProps { } export function HasComponentsCard(props: HasComponentsCardProps) { - const { variant = 'gridItem', title = 'Has components' } = props; + const { t } = useTranslationRef(catalogTranslationRef); + const { variant = 'gridItem', title = t('hasComponentsCard.title') } = props; return ( diff --git a/plugins/catalog/src/components/HasResourcesCard/HasResourcesCard.tsx b/plugins/catalog/src/components/HasResourcesCard/HasResourcesCard.tsx index 5af7eec258..d11f10c882 100644 --- a/plugins/catalog/src/components/HasResourcesCard/HasResourcesCard.tsx +++ b/plugins/catalog/src/components/HasResourcesCard/HasResourcesCard.tsx @@ -23,6 +23,8 @@ import { resourceEntityColumns, resourceEntityHelpLink, } from '../RelatedEntitiesCard'; +import { catalogTranslationRef } from '../../translation'; +import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; /** @public */ export interface HasResourcesCardProps { @@ -31,7 +33,8 @@ export interface HasResourcesCardProps { } export function HasResourcesCard(props: HasResourcesCardProps) { - const { variant = 'gridItem', title = 'Has resources' } = props; + const { t } = useTranslationRef(catalogTranslationRef); + const { variant = 'gridItem', title = t('hasResourcesCard.title') } = props; return ( ); diff --git a/plugins/catalog/src/components/HasSubcomponentsCard/HasSubcomponentsCard.tsx b/plugins/catalog/src/components/HasSubcomponentsCard/HasSubcomponentsCard.tsx index ac40c82435..d81349794a 100644 --- a/plugins/catalog/src/components/HasSubcomponentsCard/HasSubcomponentsCard.tsx +++ b/plugins/catalog/src/components/HasSubcomponentsCard/HasSubcomponentsCard.tsx @@ -22,6 +22,8 @@ import { componentEntityColumns, RelatedEntitiesCard, } from '../RelatedEntitiesCard'; +import { catalogTranslationRef } from '../../translation'; +import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; /** @public */ export interface HasSubcomponentsCardProps { @@ -31,10 +33,11 @@ export interface HasSubcomponentsCardProps { } export function HasSubcomponentsCard(props: HasSubcomponentsCardProps) { + const { t } = useTranslationRef(catalogTranslationRef); const { variant = 'gridItem', tableOptions = {}, - title = 'Has subcomponents', + title = t('hasSubcomponentsCard.title'), } = props; return ( diff --git a/plugins/catalog/src/components/HasSystemsCard/HasSystemsCard.tsx b/plugins/catalog/src/components/HasSystemsCard/HasSystemsCard.tsx index d6da465ffa..cee45a95c5 100644 --- a/plugins/catalog/src/components/HasSystemsCard/HasSystemsCard.tsx +++ b/plugins/catalog/src/components/HasSystemsCard/HasSystemsCard.tsx @@ -23,6 +23,8 @@ import { systemEntityColumns, systemEntityHelpLink, } from '../RelatedEntitiesCard'; +import { catalogTranslationRef } from '../../translation'; +import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; /** @public */ export interface HasSystemsCardProps { @@ -31,7 +33,8 @@ export interface HasSystemsCardProps { } export function HasSystemsCard(props: HasSystemsCardProps) { - const { variant = 'gridItem', title = 'Has systems' } = props; + const { t } = useTranslationRef(catalogTranslationRef); + const { variant = 'gridItem', title = t('hasSystemsCard.title') } = props; return ( ); diff --git a/plugins/catalog/src/components/RelatedEntitiesCard/RelatedEntitiesCard.tsx b/plugins/catalog/src/components/RelatedEntitiesCard/RelatedEntitiesCard.tsx index eb37973c27..dd1359482d 100644 --- a/plugins/catalog/src/components/RelatedEntitiesCard/RelatedEntitiesCard.tsx +++ b/plugins/catalog/src/components/RelatedEntitiesCard/RelatedEntitiesCard.tsx @@ -31,6 +31,8 @@ import { TableColumn, TableOptions, } from '@backstage/core-components'; +import { catalogTranslationRef } from '../../translation'; +import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; /** @public */ export type RelatedEntitiesCardProps = { @@ -72,6 +74,7 @@ export function RelatedEntitiesCard( tableOptions = {}, } = props; + const { t } = useTranslationRef(catalogTranslationRef); const { entity } = useEntity(); const { entities, loading, error } = useRelatedEntities(entity, { type: relationType, @@ -102,7 +105,9 @@ export function RelatedEntitiesCard(
{emptyMessage} - Learn how to change this. + + {t('relatedEntitiesCard.emptyHelpLinkTitle')} +
} diff --git a/plugins/catalog/src/components/SystemDiagramCard/SystemDiagramCard.tsx b/plugins/catalog/src/components/SystemDiagramCard/SystemDiagramCard.tsx index 22466b1464..5e485d672b 100644 --- a/plugins/catalog/src/components/SystemDiagramCard/SystemDiagramCard.tsx +++ b/plugins/catalog/src/components/SystemDiagramCard/SystemDiagramCard.tsx @@ -46,6 +46,8 @@ import { } from '@backstage/core-components'; import { useApi, useRouteRef } from '@backstage/core-plugin-api'; +import { catalogTranslationRef } from '../../translation'; +import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; /** @public */ export type SystemDiagramCardClassKey = @@ -164,6 +166,7 @@ function RenderNode(props: DependencyGraphTypes.RenderNodeProps) { export function SystemDiagramCard() { const { entity } = useEntity(); const theme = useTheme(); + const { t } = useTranslationRef(catalogTranslationRef); const currentSystemName = entity.metadata.name; const currentSystemNode = stringifyEntityRef(entity); const systemNodes = new Array<{ id: string; kind: string; name: string }>(); @@ -211,7 +214,7 @@ export function SystemDiagramCard() { systemEdges.push({ from: currentSystemNode, to: stringifyEntityRef(foundDomain), - label: 'part of', + label: t('systemDiagramCard.edgeLabels.partOf'), }), ); @@ -235,7 +238,7 @@ export function SystemDiagramCard() { systemEdges.push({ from: stringifyEntityRef(catalogItem), to: stringifyEntityRef(foundRelation), - label: 'part of', + label: t('systemDiagramCard.edgeLabels.partOf'), }), ); @@ -247,7 +250,7 @@ export function SystemDiagramCard() { systemEdges.push({ from: stringifyEntityRef(catalogItem), to: stringifyEntityRef(foundRelation), - label: 'provides', + label: t('systemDiagramCard.edgeLabels.provides'), }), ); @@ -259,7 +262,7 @@ export function SystemDiagramCard() { systemEdges.push({ from: stringifyEntityRef(catalogItem), to: stringifyEntityRef(foundRelation), - label: 'depends on', + label: t('systemDiagramCard.edgeLabels.dependsOn'), }), ); } @@ -272,7 +275,7 @@ export function SystemDiagramCard() { } return ( - + - Use pinch & zoom - to move around the diagram. + + {t('systemDiagramCard.description')} ); diff --git a/plugins/catalog/src/translation.ts b/plugins/catalog/src/translation.ts index bd27069fde..2699b58542 100644 --- a/plugins/catalog/src/translation.ts +++ b/plugins/catalog/src/translation.ts @@ -23,6 +23,141 @@ export const catalogTranslationRef = createTranslationRef({ indexPage: { title: `{{orgName}} Catalog`, createButtonTitle: 'Create', + supportButtonContent: 'All your software catalog entities', + }, + aboutCard: { + title: 'About', + refreshButtonTitle: 'Schedule entity refresh', + editButtonTitle: 'Edit Metadata', + createSimilarButtonTitle: 'Create something similar', + refreshScheduledMessage: 'Refresh scheduled', + launchTemplate: 'Launch Template', + viewTechdocs: 'View TechDocs', + viewSource: 'View Source', + descriptionField: { + label: 'Description', + value: 'No description', + }, + ownerField: { + label: 'Owner', + value: 'No Owner', + }, + domainField: { + label: 'Domain', + value: 'No Domain', + }, + systemField: { + label: 'System', + value: 'No System', + }, + parentComponentField: { + label: 'Parent Component', + value: 'No Parent Component', + }, + typeField: { + label: 'Type', + }, + lifecycleField: { + label: 'Lifecycle', + }, + tagsField: { + label: 'Tags', + value: 'No Tags', + }, + targetsField: { + label: 'Targets', + }, + }, + searchResultItem: { + lifecycle: 'Lifecycle', + Owner: 'Owner', + }, + catalogTable: { + warningPanelTitle: 'Could not fetch catalog entities.', + viewActionTitle: 'View', + editActionTitle: 'Edit', + starActionTitle: 'Add to favorites', + unStarActionTitle: 'Remove from favorites', + }, + dependencyOfComponentsCard: { + title: 'Dependency of components', + emptyMessage: 'No component depends on this component', + }, + dependsOnComponentsCard: { + title: 'Depends on components', + emptyMessage: 'No component is a dependency of this component', + }, + dependsOnResourcesCard: { + title: 'Depends on resources', + emptyMessage: 'No resource is a dependency of this component', + }, + entityContextMenu: { + copiedMessage: 'Copied!', + moreButtonTitle: 'More', + inspectMenuTitle: 'Inspect entity', + copyURLMenuTitle: 'Copy entity URL', + unregisterMenuTitle: 'Unregister entity', + }, + entityLabelsCard: { + title: 'Labels', + emptyDescription: + 'No labels defined for this entity. You can add labels to your entity YAML as shown in the highlighted example below:', + readMoreButtonTitle: 'Read more', + }, + entityLabels: { + warningPanelTitle: 'Entity not found', + ownerLabel: 'Owner', + lifecycleLabel: 'Lifecycle', + }, + entityLinksCard: { + title: 'Links', + emptyDescription: + 'No links defined for this entity. You can add links to your entity YAML as shown in the highlighted example below:', + readMoreButtonTitle: 'Read more', + }, + entityNotFound: { + title: 'Entity was not found', + description: + 'Want to help us build this? Check out our Getting Started documentation.', + docButtonTitle: 'DOCS', + }, + deleteEntity: { + dialogTitle: 'Are you sure you want to delete this entity?', + deleteButtonTitle: 'Delete', + cancelButtonTitle: 'Cancel', + description: + 'This entity is not referenced by any location and is therefore not receiving updates. Click here to delete.', + }, + entityProcessingErrorsDescription: 'The error below originates from', + entityRelationWarningDescription: + "This entity has relations to other entities, which can't be found in the catalog.\n Entities not found are: ", + hasComponentsCard: { + title: 'Has components', + emptyMessage: 'No component is part of this system', + }, + hasResourcesCard: { + title: 'Has resources', + emptyMessage: 'No resource is part of this system', + }, + hasSubcomponentsCard: { + title: 'Has subcomponents', + emptyMessage: 'No subcomponent is part of this component', + }, + hasSystemsCard: { + title: 'Has systems', + emptyMessage: 'No system is part of this domain', + }, + relatedEntitiesCard: { + emptyHelpLinkTitle: 'Learn how to change this.', + }, + systemDiagramCard: { + title: 'System Diagram', + description: 'Use pinch & zoo to move around the diagram.', + edgeLabels: { + partOf: 'part of', + provides: 'provides', + dependsOn: 'depends on', + }, }, }, }); From 06c09562079e9d1b31c6af4b85ba5991301f675b Mon Sep 17 00:00:00 2001 From: mario ma Date: Tue, 5 Mar 2024 17:24:27 +0800 Subject: [PATCH 037/416] feat: add i18n to plugin-catalog-react Signed-off-by: mario ma --- .changeset/friendly-oranges-greet.md | 7 ++ plugins/catalog-react/api-report-alpha.md | 59 +++++++++ plugins/catalog-react/src/alpha.tsx | 1 + .../CatalogFilterLayout.tsx | 7 +- .../EntityKindPicker.test.tsx | 14 +-- .../EntityKindPicker/EntityKindPicker.tsx | 9 +- .../EntityLifecyclePicker.test.tsx | 18 +-- .../EntityLifecyclePicker.tsx | 5 +- .../EntityNamespacePicker.test.tsx | 20 +-- .../EntityNamespacePicker.tsx | 6 +- .../EntityOwnerPicker.test.tsx | 24 ++-- .../EntityOwnerPicker/EntityOwnerPicker.tsx | 5 +- .../CardActionComponents/EmailCardAction.tsx | 11 +- .../EntityCardActions.tsx | 5 +- .../EntityPeekAheadPopover.tsx | 6 +- .../EntityProcessingStatusPicker.test.tsx | 23 ++-- .../EntityProcessingStatusPicker.tsx | 5 +- .../EntitySearchBar/EntitySearchBar.test.tsx | 7 +- .../EntitySearchBar/EntitySearchBar.tsx | 5 +- .../src/components/EntityTable/columns.tsx | 2 + .../EntityTagPicker/EntityTagPicker.test.tsx | 28 ++--- .../EntityTagPicker/EntityTagPicker.tsx | 5 +- .../EntityTypePicker.test.tsx | 10 +- .../EntityTypePicker/EntityTypePicker.tsx | 11 +- .../FavoriteEntity/FavoriteEntity.tsx | 9 +- .../InspectEntityDialog.tsx | 7 +- .../components/AncestryPage.tsx | 7 +- .../components/ColocatedPage.tsx | 18 ++- .../components/JsonPage.tsx | 9 +- .../components/OverviewPage.tsx | 7 +- .../components/YamlPage.tsx | 9 +- .../UnregisterEntityDialog.tsx | 63 +++++----- .../UserListPicker/UserListPicker.test.tsx | 44 ++++--- .../UserListPicker/UserListPicker.tsx | 27 ++-- .../src/hooks/useEntityListProvider.test.tsx | 5 + plugins/catalog-react/src/translation.ts | 116 ++++++++++++++++++ plugins/catalog/api-report-alpha.md | 75 +++++++++++ plugins/catalog/src/alpha.ts | 1 + .../TemplateCard/CardHeader.test.tsx | 6 +- 39 files changed, 526 insertions(+), 170 deletions(-) create mode 100644 .changeset/friendly-oranges-greet.md create mode 100644 plugins/catalog-react/src/translation.ts diff --git a/.changeset/friendly-oranges-greet.md b/.changeset/friendly-oranges-greet.md new file mode 100644 index 0000000000..4fbabf76f5 --- /dev/null +++ b/.changeset/friendly-oranges-greet.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-scaffolder-react': patch +'@backstage/plugin-catalog-react': patch +'@backstage/plugin-catalog': patch +--- + +Support i18n for catalog and catalog-react plugins diff --git a/plugins/catalog-react/api-report-alpha.md b/plugins/catalog-react/api-report-alpha.md index fb807d947d..ea01122ccc 100644 --- a/plugins/catalog-react/api-report-alpha.md +++ b/plugins/catalog-react/api-report-alpha.md @@ -13,6 +13,7 @@ import { PortableSchema } 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'; +import { TranslationRef } from '@backstage/core-plugin-api/alpha'; // @alpha (undocumented) export const catalogExtensionData: { @@ -24,6 +25,64 @@ export const catalogExtensionData: { entityFilterExpression: ConfigurableExtensionDataRef; }; +// @alpha (undocumented) +export const catalogReactTranslationRef: TranslationRef< + 'catalog-react', + { + readonly 'catalogFilter.title': 'Filters'; + readonly 'catalogFilter.buttonTitle': 'Filters'; + readonly 'entityKindPicker.title': 'Kind'; + readonly 'entityKindPicker.errorMessage': 'Failed to load entity kinds'; + readonly entityLifecyclePickerTitle: 'Lifecycle'; + readonly entityNamespacePickerTitle: 'Namespace'; + readonly entityOwnerPickerTitle: 'Owner'; + readonly 'entityPeekAheadPopover.title': 'Drill into the entity to see all of the tags.'; + readonly 'entityPeekAheadPopover.entityCardActionsTitle': 'Show details'; + readonly 'entityPeekAheadPopover.emailCardAction.title': 'Email {{email}}'; + readonly 'entityPeekAheadPopover.emailCardAction.subTitle': 'mailto {{email}}'; + readonly entityProcessingStatusPickerTitle: 'Processing Status'; + readonly entitySearchBarPlaceholder: 'Search'; + readonly entityTagPickerTitle: 'Tags'; + readonly 'entityTypePicker.title': 'Type'; + readonly 'entityTypePicker.errorMessage': 'Failed to load entity types'; + readonly 'entityTypePicker.optionAllTitle': 'all'; + readonly 'favoriteEntity.addToFavorites': 'Add to favorites'; + readonly 'favoriteEntity.RemoveFromFavorites': 'Remove from favorites'; + readonly 'inspectEntityDialog.title': 'Entity Inspector'; + readonly 'inspectEntityDialog.closeButtonTitle': 'Close'; + readonly 'inspectEntityDialog.ancestryPage.title': 'Ancestry'; + readonly 'inspectEntityDialog.colocatedPage.title': 'Colocated'; + readonly 'inspectEntityDialog.colocatedPage.description': 'These are the entities that are colocated with this entity - as in, they originated from the same data source (e.g. came from the same YAML file), or from the same origin (e.g. the originally registered URL).'; + readonly 'inspectEntityDialog.colocatedPage.alertNoLocation': 'Entity had no location information.'; + readonly 'inspectEntityDialog.colocatedPage.alertNoEntity': 'There were no other entities on this location.'; + readonly 'inspectEntityDialog.jsonPage.title': 'Entity as JSON'; + readonly 'inspectEntityDialog.jsonPage.description': 'This is the raw entity data as received from the catalog, on JSON form.'; + readonly 'inspectEntityDialog.overviewPage.title': 'Overview'; + readonly 'inspectEntityDialog.yamlPage.title': 'Entity as YAML'; + readonly 'inspectEntityDialog.yamlPage.description': 'This is the raw entity data as received from the catalog, on YAML form.'; + readonly 'unregisterEntityDialog.title': 'Are you sure you want to unregister this entity?'; + readonly 'unregisterEntityDialog.cancelButtonTitle': 'Cancel'; + readonly 'unregisterEntityDialog.deleteButtonTitle': 'Delete Entity'; + readonly 'unregisterEntityDialog.deleteEntitySuccessMessage': 'Removed entity {{entityName}}'; + readonly 'unregisterEntityDialog.onlyDeleteStateTitle': 'This entity does not seem to originate from a registered location. You therefore only have the option to delete it outright from the catalog.'; + readonly 'unregisterEntityDialog.errorStateTitle': 'Internal error: Unknown state'; + readonly 'unregisterEntityDialog.bootstrapState.title': 'You cannot unregister this entity, since it originates from a protected Backstage configuration (location "{{location}}"). If you believe this is in error, please contact the {{appTitle}} integrator.'; + readonly 'unregisterEntityDialog.bootstrapState.advancedDescription': 'You have the option to delete the entity itself from the catalog. Note that this should only be done if you know that the catalog file has been deleted at, or moved from, its origin location. If that is not the case, the entity will reappear shortly as the next refresh round is performed by the catalog.'; + readonly 'unregisterEntityDialog.bootstrapState.advancedOptions': 'Advanced Options'; + readonly 'unregisterEntityDialog.unregisterState.title': 'This action will unregister the following entities:'; + readonly 'unregisterEntityDialog.unregisterState.description': 'To undo, just re-register the entity in {{appTitle}}.'; + readonly 'unregisterEntityDialog.unregisterState.subTitle': 'Located at the following location:'; + readonly 'unregisterEntityDialog.unregisterState.advancedDescription': 'You also have the option to delete the entity itself from the catalog. Note that this should only be done if you know that the catalog file has been deleted at, or moved from, its origin location. If that is not the case, the entity will reappear shortly as the next refresh round is performed by the catalog.'; + readonly 'unregisterEntityDialog.unregisterState.advancedOptions': 'Advanced Options'; + readonly 'unregisterEntityDialog.unregisterState.unregisterButtonTitle': 'Unregister Location'; + readonly 'userListPicker.defaultOrgName': 'Company'; + readonly 'userListPicker.orgFilterAllLabel': 'All'; + readonly 'userListPicker.personalFilter.title': 'Personal'; + readonly 'userListPicker.personalFilter.ownedLabel': 'Owned'; + readonly 'userListPicker.personalFilter.starredLabel': 'Starred'; + } +>; + // @alpha (undocumented) export function createEntityCardExtension< TConfig extends { diff --git a/plugins/catalog-react/src/alpha.tsx b/plugins/catalog-react/src/alpha.tsx index f5f4dfdb74..b1650d1f5b 100644 --- a/plugins/catalog-react/src/alpha.tsx +++ b/plugins/catalog-react/src/alpha.tsx @@ -32,6 +32,7 @@ import { Expand } from '../../../packages/frontend-plugin-api/src/types'; export { useEntityPermission } from './hooks/useEntityPermission'; export { isOwnerOf } from './utils'; +export * from './translation'; /** @alpha */ export const catalogExtensionData = { diff --git a/plugins/catalog-react/src/components/CatalogFilterLayout/CatalogFilterLayout.tsx b/plugins/catalog-react/src/components/CatalogFilterLayout/CatalogFilterLayout.tsx index 7583520412..ee51020cbb 100644 --- a/plugins/catalog-react/src/components/CatalogFilterLayout/CatalogFilterLayout.tsx +++ b/plugins/catalog-react/src/components/CatalogFilterLayout/CatalogFilterLayout.tsx @@ -23,6 +23,8 @@ import Typography from '@material-ui/core/Typography'; import useMediaQuery from '@material-ui/core/useMediaQuery'; import { Theme, useTheme } from '@material-ui/core/styles'; import FilterListIcon from '@material-ui/icons/FilterList'; +import { catalogReactTranslationRef } from '../../translation'; +import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; /** @public */ export const Filters = (props: { @@ -37,6 +39,7 @@ export const Filters = (props: { ); const theme = useTheme(); const [filterDrawerOpen, setFilterDrawerOpen] = useState(false); + const { t } = useTranslationRef(catalogReactTranslationRef); return isScreenSmallerThanBreakpoint ? ( <> @@ -45,7 +48,7 @@ export const Filters = (props: { onClick={() => setFilterDrawerOpen(true)} startIcon={} > - Filters + {t('catalogFilter.buttonTitle')} - Filters + {t('catalogFilter.title')} {props.children} diff --git a/plugins/catalog-react/src/components/EntityKindPicker/EntityKindPicker.test.tsx b/plugins/catalog-react/src/components/EntityKindPicker/EntityKindPicker.test.tsx index 2513f8dca9..612c515d28 100644 --- a/plugins/catalog-react/src/components/EntityKindPicker/EntityKindPicker.test.tsx +++ b/plugins/catalog-react/src/components/EntityKindPicker/EntityKindPicker.test.tsx @@ -18,7 +18,7 @@ import { GetEntityFacetsResponse } from '@backstage/catalog-client'; import { Entity } from '@backstage/catalog-model'; import { ApiProvider } from '@backstage/core-app-api'; import { alertApiRef } from '@backstage/core-plugin-api'; -import { renderWithEffects, TestApiRegistry } from '@backstage/test-utils'; +import { renderInTestApp, TestApiRegistry } from '@backstage/test-utils'; import { fireEvent, waitFor, screen, within } from '@testing-library/react'; import { capitalize } from 'lodash'; import { default as React } from 'react'; @@ -75,7 +75,7 @@ describe('', () => { ); it('renders available entity kinds', async () => { - await renderWithEffects( + await renderInTestApp( ', () => { it('sets the selected kind filter', async () => { const updateFilters = jest.fn(); - await renderWithEffects( + await renderInTestApp( ', () => { it('respects the query parameter filter value', async () => { const updateFilters = jest.fn(); const queryParameters = { kind: 'group' }; - await renderWithEffects( + await renderInTestApp( ', () => { }); it('renders unknown kinds provided in query parameters', async () => { - await renderWithEffects( + await renderInTestApp( ', () => { }); it('limits kinds when allowedKinds is set', async () => { - await renderWithEffects( + await renderInTestApp( @@ -183,7 +183,7 @@ describe('', () => { }); it('renders kind from the query parameter even when not in allowedKinds', async () => { - await renderWithEffects( + await renderInTestApp( { const { allowedKinds, hidden, initialFilter = 'component' } = props; + const { t } = useTranslationRef(catalogReactTranslationRef); const alertApi = useApi(alertApiRef); @@ -106,11 +109,11 @@ export const EntityKindPicker = (props: EntityKindPickerProps) => { useEffect(() => { if (error) { alertApi.post({ - message: `Failed to load entity kinds`, + message: t('entityKindPicker.errorMessage'), severity: 'error', }); } - }, [error, alertApi]); + }, [error, alertApi, t]); if (error) return null; @@ -124,7 +127,7 @@ export const EntityKindPicker = (props: EntityKindPickerProps) => { return hidden ? null : ( 1 ? selectedTypes[0] : undefined) ?? 'all'} onChange={value => diff --git a/plugins/catalog-react/src/components/FavoriteEntity/FavoriteEntity.tsx b/plugins/catalog-react/src/components/FavoriteEntity/FavoriteEntity.tsx index fd0a656317..b788579e41 100644 --- a/plugins/catalog-react/src/components/FavoriteEntity/FavoriteEntity.tsx +++ b/plugins/catalog-react/src/components/FavoriteEntity/FavoriteEntity.tsx @@ -22,6 +22,8 @@ import Star from '@material-ui/icons/Star'; import StarBorder from '@material-ui/icons/StarBorder'; import React, { ComponentProps } from 'react'; import { useStarredEntity } from '../../hooks/useStarredEntity'; +import { catalogReactTranslationRef } from '../../translation'; +import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; /** @public */ export type FavoriteEntityProps = ComponentProps & { @@ -43,6 +45,7 @@ export const FavoriteEntity = (props: FavoriteEntityProps) => { const { toggleStarredEntity, isStarredEntity } = useStarredEntity( props.entity, ); + const { t } = useTranslationRef(catalogReactTranslationRef); return ( { onClick={() => toggleStarredEntity()} > {isStarredEntity ? : } diff --git a/plugins/catalog-react/src/components/InspectEntityDialog/InspectEntityDialog.tsx b/plugins/catalog-react/src/components/InspectEntityDialog/InspectEntityDialog.tsx index f155c3f164..644167acbb 100644 --- a/plugins/catalog-react/src/components/InspectEntityDialog/InspectEntityDialog.tsx +++ b/plugins/catalog-react/src/components/InspectEntityDialog/InspectEntityDialog.tsx @@ -30,6 +30,8 @@ import { ColocatedPage } from './components/ColocatedPage'; import { JsonPage } from './components/JsonPage'; import { OverviewPage } from './components/OverviewPage'; import { YamlPage } from './components/YamlPage'; +import { catalogReactTranslationRef } from '../../translation'; +import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; const useStyles = makeStyles(theme => ({ fullHeightDialog: { @@ -95,6 +97,7 @@ export function InspectEntityDialog(props: { }) { const classes = useStyles(); const [activeTab, setActiveTab] = React.useState(0); + const { t } = useTranslationRef(catalogReactTranslationRef); useEffect(() => { setActiveTab(0); @@ -114,7 +117,7 @@ export function InspectEntityDialog(props: { PaperProps={{ className: classes.fullHeightDialog }} > - Entity Inspector + {t('inspectEntityDialog.title')}
@@ -152,7 +155,7 @@ export function InspectEntityDialog(props: { diff --git a/plugins/catalog-react/src/components/InspectEntityDialog/components/AncestryPage.tsx b/plugins/catalog-react/src/components/InspectEntityDialog/components/AncestryPage.tsx index e08bac06e8..98bd27bd77 100644 --- a/plugins/catalog-react/src/components/InspectEntityDialog/components/AncestryPage.tsx +++ b/plugins/catalog-react/src/components/InspectEntityDialog/components/AncestryPage.tsx @@ -38,6 +38,8 @@ import { catalogApiRef } from '../../../api'; import { humanizeEntityRef } from '../../EntityRefLink'; import { entityRouteRef } from '../../../routes'; import { EntityKindIcon } from './EntityKindIcon'; +import { catalogReactTranslationRef } from '../../../translation'; +import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; const useStyles = makeStyles(theme => ({ node: { @@ -198,6 +200,7 @@ function CustomNode({ node }: DependencyGraphTypes.RenderNodeProps) { export function AncestryPage(props: { entity: Entity }) { const { loading, error, nodes, edges } = useAncestry(props.entity); + const { t } = useTranslationRef(catalogReactTranslationRef); if (loading) { return ; } else if (error) { @@ -206,7 +209,9 @@ export function AncestryPage(props: { entity: Entity }) { return ( <> - Ancestry + + {t('inspectEntityDialog.ancestryPage.title')} + This is the ancestry of entities above the current one - as in, the chain(s) of entities down to the current one, where{' '} diff --git a/plugins/catalog-react/src/components/InspectEntityDialog/components/ColocatedPage.tsx b/plugins/catalog-react/src/components/InspectEntityDialog/components/ColocatedPage.tsx index 97bf0f3cb8..6f89ff2c9f 100644 --- a/plugins/catalog-react/src/components/InspectEntityDialog/components/ColocatedPage.tsx +++ b/plugins/catalog-react/src/components/InspectEntityDialog/components/ColocatedPage.tsx @@ -32,6 +32,8 @@ import useAsync from 'react-use/esm/useAsync'; import { catalogApiRef } from '../../../api'; import { EntityRefLink } from '../../EntityRefLink'; import { KeyValueListItem, ListItemText } from './common'; +import { catalogReactTranslationRef } from '../../../translation'; +import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; const useStyles = makeStyles({ root: { @@ -95,6 +97,7 @@ function EntityList(props: { entities: Entity[]; header?: [string, string] }) { function Contents(props: { entity: Entity }) { const { entity } = props; + const { t } = useTranslationRef(catalogReactTranslationRef); const { loading, error, location, originLocation, colocatedEntities } = useColocated(entity); @@ -106,12 +109,14 @@ function Contents(props: { entity: Entity }) { if (!location && !originLocation) { return ( - Entity had no location information. + + {t('inspectEntityDialog.colocatedPage.alertNoLocation')} + ); } else if (!colocatedEntities?.length) { return ( - There were no other entities on this location. + {t('inspectEntityDialog.colocatedPage.alertNoEntity')} ); } @@ -148,13 +153,14 @@ function Contents(props: { entity: Entity }) { export function ColocatedPage(props: { entity: Entity }) { const classes = useStyles(); + const { t } = useTranslationRef(catalogReactTranslationRef); return ( <> - Colocated + + {t('inspectEntityDialog.colocatedPage.title')} + - These are the entities that are colocated with this entity - as in, they - originated from the same data source (e.g. came from the same YAML - file), or from the same origin (e.g. the originally registered URL). + {t('inspectEntityDialog.colocatedPage.description')}
diff --git a/plugins/catalog-react/src/components/InspectEntityDialog/components/JsonPage.tsx b/plugins/catalog-react/src/components/InspectEntityDialog/components/JsonPage.tsx index b6bda65229..af8a724729 100644 --- a/plugins/catalog-react/src/components/InspectEntityDialog/components/JsonPage.tsx +++ b/plugins/catalog-react/src/components/InspectEntityDialog/components/JsonPage.tsx @@ -19,13 +19,18 @@ import { CodeSnippet } from '@backstage/core-components'; import DialogContentText from '@material-ui/core/DialogContentText'; import React from 'react'; import { sortKeys } from './util'; +import { catalogReactTranslationRef } from '../../../translation'; +import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; export function JsonPage(props: { entity: Entity }) { + const { t } = useTranslationRef(catalogReactTranslationRef); return ( <> - Entity as JSON + + {t('inspectEntityDialog.jsonPage.title')} + - This is the raw entity data as received from the catalog, on JSON form. + {t('inspectEntityDialog.jsonPage.description')}
diff --git a/plugins/catalog-react/src/components/InspectEntityDialog/components/OverviewPage.tsx b/plugins/catalog-react/src/components/InspectEntityDialog/components/OverviewPage.tsx index ad742459de..361910b2cd 100644 --- a/plugins/catalog-react/src/components/InspectEntityDialog/components/OverviewPage.tsx +++ b/plugins/catalog-react/src/components/InspectEntityDialog/components/OverviewPage.tsx @@ -36,6 +36,8 @@ import { } from './common'; import { stringifyEntityRef } from '@backstage/catalog-model'; import { CopyTextButton } from '@backstage/core-components'; +import { catalogReactTranslationRef } from '../../../translation'; +import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; const useStyles = makeStyles({ root: { @@ -59,11 +61,14 @@ export function OverviewPage(props: { entity: AlphaEntity }) { sortBy(relations, r => r.targetRef), 'type', ); + const { t } = useTranslationRef(catalogReactTranslationRef); const entityRef = stringifyEntityRef(props.entity); return ( <> - Overview + + {t('inspectEntityDialog.overviewPage.title')} +
diff --git a/plugins/catalog-react/src/components/InspectEntityDialog/components/YamlPage.tsx b/plugins/catalog-react/src/components/InspectEntityDialog/components/YamlPage.tsx index ad74611ec5..4e56b9b42a 100644 --- a/plugins/catalog-react/src/components/InspectEntityDialog/components/YamlPage.tsx +++ b/plugins/catalog-react/src/components/InspectEntityDialog/components/YamlPage.tsx @@ -20,13 +20,18 @@ import DialogContentText from '@material-ui/core/DialogContentText'; import React from 'react'; import YAML from 'yaml'; import { sortKeys } from './util'; +import { catalogReactTranslationRef } from '../../../translation'; +import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; export function YamlPage(props: { entity: Entity }) { + const { t } = useTranslationRef(catalogReactTranslationRef); return ( <> - Entity as YAML + + {t('inspectEntityDialog.yamlPage.title')} + - This is the raw entity data as received from the catalog, on YAML form. + {t('inspectEntityDialog.yamlPage.description')}
diff --git a/plugins/catalog-react/src/components/UnregisterEntityDialog/UnregisterEntityDialog.tsx b/plugins/catalog-react/src/components/UnregisterEntityDialog/UnregisterEntityDialog.tsx index 7f41badca5..e2ed9387e1 100644 --- a/plugins/catalog-react/src/components/UnregisterEntityDialog/UnregisterEntityDialog.tsx +++ b/plugins/catalog-react/src/components/UnregisterEntityDialog/UnregisterEntityDialog.tsx @@ -32,6 +32,8 @@ import { useUnregisterEntityDialogState } from './useUnregisterEntityDialogState import { alertApiRef, configApiRef, useApi } from '@backstage/core-plugin-api'; import { Progress, ResponseErrorPanel } from '@backstage/core-components'; import { assertError } from '@backstage/errors'; +import { catalogReactTranslationRef } from '../../translation'; +import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; const useStyles = makeStyles({ advancedButton: { @@ -58,6 +60,7 @@ const Contents = ({ const [showDelete, setShowDelete] = useState(false); const [busy, setBusy] = useState(false); const appTitle = configApi.getOptionalString('app.title') ?? 'Backstage'; + const { t } = useTranslationRef(catalogReactTranslationRef); const onUnregister = useCallback( async function onUnregisterFn() { @@ -86,7 +89,9 @@ const Contents = ({ const entityName = entity.metadata.title ?? entity.metadata.name; onConfirm(); alertApi.post({ - message: `Removed entity ${entityName}`, + message: t('unregisterEntityDialog.deleteEntitySuccessMessage', { + entityName, + }), severity: 'success', display: 'transient', }); @@ -98,13 +103,13 @@ const Contents = ({ } } }, - [alertApi, onConfirm, state, entity], + [alertApi, onConfirm, state, entity, t], ); const DialogActionsPanel = () => ( ); @@ -121,10 +126,10 @@ const Contents = ({ return ( <> - You cannot unregister this entity, since it originates from a - protected Backstage configuration (location "{state.location}"). If - you believe this is in error, please contact the {appTitle}{' '} - integrator. + {t('unregisterEntityDialog.bootstrapState.title', { + appTitle, + location: state.location, + })} @@ -137,7 +142,7 @@ const Contents = ({ className={classes.advancedButton} onClick={() => setShowDelete(true)} > - Advanced Options + {t('unregisterEntityDialog.bootstrapState.advancedOptions')} @@ -146,11 +151,7 @@ const Contents = ({ {showDelete && ( <> - You have the option to delete the entity itself from the - catalog. Note that this should only be done if you know that the - catalog file has been deleted at, or moved from, its origin - location. If that is not the case, the entity will reappear - shortly as the next refresh round is performed by the catalog. + {t('unregisterEntityDialog.bootstrapState.advancedDescription')} @@ -172,8 +173,7 @@ const Contents = ({ return ( <> - This entity does not seem to originate from a registered location. You - therefore only have the option to delete it outright from the catalog. + {t('unregisterEntityDialog.onlyDeleteStateTitle')} @@ -192,7 +192,7 @@ const Contents = ({ return ( <> - This action will unregister the following entities: + {t('unregisterEntityDialog.unregisterState.title')} {state.colocatedEntities.map(e => ( @@ -202,13 +202,15 @@ const Contents = ({ ))} - Located at the following location: + {t('unregisterEntityDialog.unregisterState.subTitle')}
  • {state.location}
  • - To undo, just re-register the entity in {appTitle}. + {t('unregisterEntityDialog.unregisterState.description', { + appTitle, + })} {!showDelete && ( @@ -228,7 +230,7 @@ const Contents = ({ className={classes.advancedButton} onClick={() => setShowDelete(true)} > - Advanced Options + {t('unregisterEntityDialog.unregisterState.advancedOptions')} )} @@ -240,11 +242,7 @@ const Contents = ({ - You also have the option to delete the entity itself from the - catalog. Note that this should only be done if you know that the - catalog file has been deleted at, or moved from, its origin - location. If that is not the case, the entity will reappear - shortly as the next refresh round is performed by the catalog. + {t('unregisterEntityDialog.unregisterState.advancedDescription')} )} @@ -260,7 +258,11 @@ const Contents = ({ ); } - return Internal error: Unknown state; + return ( + + {t('unregisterEntityDialog.errorStateTitle')} + + ); }; /** @public */ @@ -274,10 +276,11 @@ export type UnregisterEntityDialogProps = { /** @public */ export const UnregisterEntityDialog = (props: UnregisterEntityDialogProps) => { const { open, onConfirm, onClose, entity } = props; + const { t } = useTranslationRef(catalogReactTranslationRef); return ( - Are you sure you want to unregister this entity? + {t('unregisterEntityDialog.title')} diff --git a/plugins/catalog-react/src/components/UserListPicker/UserListPicker.test.tsx b/plugins/catalog-react/src/components/UserListPicker/UserListPicker.test.tsx index 5667447503..0b101e8174 100644 --- a/plugins/catalog-react/src/components/UserListPicker/UserListPicker.test.tsx +++ b/plugins/catalog-react/src/components/UserListPicker/UserListPicker.test.tsx @@ -15,7 +15,7 @@ */ import React from 'react'; -import { fireEvent, render, waitFor, screen } from '@testing-library/react'; +import { fireEvent, waitFor, screen } from '@testing-library/react'; import { UserEntity } from '@backstage/catalog-model'; import { UserListPicker, UserListPickerProps } from './UserListPicker'; import { MockEntityListContextProvider } from '../../testUtils/providers'; @@ -30,7 +30,11 @@ import { QueryEntitiesInitialRequest, } from '@backstage/catalog-client'; import { catalogApiRef } from '../../api'; -import { MockStorageApi, TestApiRegistry } from '@backstage/test-utils'; +import { + MockStorageApi, + TestApiRegistry, + renderInTestApp, +} from '@backstage/test-utils'; import { ApiProvider } from '@backstage/core-app-api'; import { ConfigApi, @@ -145,7 +149,7 @@ describe('', () => { }); it('renders filter groups', async () => { - render( + await renderInTestApp( @@ -164,7 +168,7 @@ describe('', () => { }); it('renders filters', async () => { - render( + await renderInTestApp( ', () => { }); it('respects other frontend filters in counts', async () => { - render( + await renderInTestApp( ', () => { it('respects the query parameter filter value', async () => { const updateFilters = jest.fn(); const queryParameters = { user: 'owned', kind: 'component' }; - render( + await renderInTestApp( ', () => { it('updates user filter when a menuitem is selected', async () => { const updateFilters = jest.fn(); - render( + await renderInTestApp( ', () => { it('responds to external queryParameters changes', async () => { const updateFilters = jest.fn(); - const rendered = render( + const rendered = await renderInTestApp( ', () => { it('does not reset the filter while entities are loading', async () => { mockCatalogApi.queryEntities?.mockReturnValue(new Promise(() => {})); - render(); + await renderInTestApp(); await waitFor(() => expect(mockCatalogApi.queryEntities).toHaveBeenCalled(), @@ -433,7 +437,7 @@ describe('', () => { return mockQueryEntitiesImplementation(request); }); - render(); + await renderInTestApp(); await waitFor(() => expect(mockCatalogApi.queryEntities).toHaveBeenCalledTimes(3), @@ -444,7 +448,7 @@ describe('', () => { }); it('does not reset the filter when request is empty', async () => { - render(); + await renderInTestApp(); await waitFor(() => { expect(mockCatalogApi.queryEntities).toHaveBeenCalledTimes(1); @@ -473,7 +477,7 @@ describe('', () => { return mockQueryEntitiesImplementation(request); }); - render(); + await renderInTestApp(); await waitFor(() => expect(updateFilters).toHaveBeenLastCalledWith({ @@ -489,7 +493,7 @@ describe('', () => { () => new Promise(() => {}), ); - render(); + await renderInTestApp(); await waitFor(() => expect(mockCatalogApi.queryEntities).toHaveBeenCalled(), @@ -512,7 +516,7 @@ describe('', () => { return mockQueryEntitiesImplementation(request); }); - render(); + await renderInTestApp(); await waitFor(() => expect(mockCatalogApi.queryEntities).toHaveBeenCalledTimes(3), @@ -537,7 +541,7 @@ describe('', () => { return mockQueryEntitiesImplementation(request); }); - render(); + await renderInTestApp(); await waitFor(() => expect(updateFilters).toHaveBeenLastCalledWith({ @@ -563,7 +567,7 @@ describe('', () => { return mockQueryEntitiesImplementation(request); }); - render(); + await renderInTestApp(); await waitFor(() => expect(mockCatalogApi.queryEntities).toHaveBeenCalledTimes(3), @@ -574,7 +578,7 @@ describe('', () => { }); it('does not reset the filter when entities are loaded', async () => { - render(); + await renderInTestApp(); await waitFor(() => expect(mockCatalogApi.queryEntities).toHaveBeenCalledTimes(3), @@ -588,7 +592,7 @@ describe('', () => { }); it('does not reset the filter when request is empty xxxx', async () => { - render(); + await renderInTestApp(); await waitFor(() => { expect(mockCatalogApi.queryEntities).toHaveBeenCalledTimes(1); @@ -619,7 +623,7 @@ describe('', () => { return mockQueryEntitiesImplementation(request); }); - render(); + await renderInTestApp(); await waitFor(() => expect(mockCatalogApi.queryEntities).toHaveBeenCalledTimes(3), @@ -630,7 +634,7 @@ describe('', () => { }); it('does not reset the filter when entities are loaded', async () => { - render(); + await renderInTestApp(); await waitFor(() => expect(mockCatalogApi.queryEntities).toHaveBeenCalledTimes(3), diff --git a/plugins/catalog-react/src/components/UserListPicker/UserListPicker.tsx b/plugins/catalog-react/src/components/UserListPicker/UserListPicker.tsx index 1e46258885..7f0ff8be74 100644 --- a/plugins/catalog-react/src/components/UserListPicker/UserListPicker.tsx +++ b/plugins/catalog-react/src/components/UserListPicker/UserListPicker.tsx @@ -36,6 +36,11 @@ import { UserListFilterKind } from '../../types'; import { useOwnedEntitiesCount } from './useOwnedEntitiesCount'; import { useAllEntitiesCount } from './useAllEntitiesCount'; import { useStarredEntitiesCount } from './useStarredEntitiesCount'; +import { + TranslationFunction, + useTranslationRef, +} from '@backstage/core-plugin-api/alpha'; +import { catalogReactTranslationRef } from '../../translation'; /** @public */ export type CatalogReactUserListPickerClassKey = @@ -83,29 +88,32 @@ export type ButtonGroup = { }[]; }; -function getFilterGroups(orgName: string | undefined): ButtonGroup[] { +function getFilterGroups( + orgName: string, + t: TranslationFunction, +): ButtonGroup[] { return [ { - name: 'Personal', + name: t('userListPicker.personalFilter.title'), items: [ { id: 'owned', - label: 'Owned', + label: t('userListPicker.personalFilter.ownedLabel'), icon: SettingsIcon, }, { id: 'starred', - label: 'Starred', + label: t('userListPicker.personalFilter.starredLabel'), icon: StarIcon, }, ], }, { - name: orgName ?? 'Company', + name: orgName, items: [ { id: 'all', - label: 'All', + label: t('userListPicker.orgFilterAllLabel'), }, ], }, @@ -123,7 +131,10 @@ export const UserListPicker = (props: UserListPickerProps) => { const { initialFilter, availableFilters } = props; const classes = useStyles(); const configApi = useApi(configApiRef); - const orgName = configApi.getOptionalString('organization.name') ?? 'Company'; + const { t } = useTranslationRef(catalogReactTranslationRef); + const orgName = + configApi.getOptionalString('organization.name') ?? + t('userListPicker.defaultOrgName'); const { filters, updateFilters, @@ -133,7 +144,7 @@ export const UserListPicker = (props: UserListPickerProps) => { // Remove group items that aren't in availableFilters and exclude // any now-empty groups. const userAndGroupFilterIds = ['starred', 'all']; - const filterGroups = getFilterGroups(orgName) + const filterGroups = getFilterGroups(orgName, t) .map(filterGroup => ({ ...filterGroup, items: filterGroup.items.filter(({ id }) => diff --git a/plugins/catalog-react/src/hooks/useEntityListProvider.test.tsx b/plugins/catalog-react/src/hooks/useEntityListProvider.test.tsx index bc8e6b6038..9afa81e2dd 100644 --- a/plugins/catalog-react/src/hooks/useEntityListProvider.test.tsx +++ b/plugins/catalog-react/src/hooks/useEntityListProvider.test.tsx @@ -20,6 +20,7 @@ import { alertApiRef, ConfigApi, configApiRef, + errorApiRef, IdentityApi, identityApiRef, storageApiRef, @@ -39,6 +40,8 @@ import { } from '../filters'; import { EntityListProvider, useEntityList } from './useEntityListProvider'; import { useMountEffect } from '@react-hookz/web'; +import { translationApiRef } from '@backstage/core-plugin-api/alpha'; +import { MockTranslationApi } from '@backstage/test-utils/alpha'; const entities: Entity[] = [ { @@ -110,6 +113,8 @@ const createWrapper = [storageApiRef, MockStorageApi.create()], [starredEntitiesApiRef, new MockStarredEntitiesApi()], [alertApiRef, { post: jest.fn() }], + [translationApiRef, MockTranslationApi.create()], + [errorApiRef, { error$: jest.fn(), post: jest.fn() }], ]} > diff --git a/plugins/catalog-react/src/translation.ts b/plugins/catalog-react/src/translation.ts new file mode 100644 index 0000000000..685bf1fd00 --- /dev/null +++ b/plugins/catalog-react/src/translation.ts @@ -0,0 +1,116 @@ +/* + * Copyright 2024 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 { createTranslationRef } from '@backstage/core-plugin-api/alpha'; + +/** @alpha */ +export const catalogReactTranslationRef = createTranslationRef({ + id: 'catalog-react', + messages: { + catalogFilter: { + title: 'Filters', + buttonTitle: 'Filters', + }, + entityKindPicker: { + title: 'Kind', + errorMessage: 'Failed to load entity kinds', + }, + entityLifecyclePickerTitle: 'Lifecycle', + entityNamespacePickerTitle: 'Namespace', + entityOwnerPickerTitle: 'Owner', + entityPeekAheadPopover: { + title: 'Drill into the entity to see all of the tags.', + emailCardAction: { + title: 'Email {{email}}', + subTitle: 'mailto {{email}}', + }, + entityCardActionsTitle: 'Show details', + }, + entityProcessingStatusPickerTitle: 'Processing Status', + entitySearchBarPlaceholder: 'Search', + entityTagPickerTitle: 'Tags', + entityTypePicker: { + title: 'Type', + errorMessage: 'Failed to load entity types', + optionAllTitle: 'all', + }, + favoriteEntity: { + addToFavorites: 'Add to favorites', + RemoveFromFavorites: 'Remove from favorites', + }, + inspectEntityDialog: { + title: 'Entity Inspector', + closeButtonTitle: 'Close', + ancestryPage: { + title: 'Ancestry', + }, + colocatedPage: { + title: 'Colocated', + description: + 'These are the entities that are colocated with this entity - as in, they originated from the same data source (e.g. came from the same YAML file), or from the same origin (e.g. the originally registered URL).', + alertNoLocation: 'Entity had no location information.', + alertNoEntity: 'There were no other entities on this location.', + }, + jsonPage: { + title: 'Entity as JSON', + description: + 'This is the raw entity data as received from the catalog, on JSON form.', + }, + overviewPage: { + title: 'Overview', + }, + yamlPage: { + title: 'Entity as YAML', + description: + 'This is the raw entity data as received from the catalog, on YAML form.', + }, + }, + unregisterEntityDialog: { + title: 'Are you sure you want to unregister this entity?', + cancelButtonTitle: 'Cancel', + deleteButtonTitle: 'Delete Entity', + deleteEntitySuccessMessage: 'Removed entity {{entityName}}', + bootstrapState: { + title: + 'You cannot unregister this entity, since it originates from a protected Backstage configuration (location "{{location}}"). If you believe this is in error, please contact the {{appTitle}} integrator.', + advancedDescription: + 'You have the option to delete the entity itself from the catalog. Note that this should only be done if you know that the catalog file has been deleted at, or moved from, its origin location. If that is not the case, the entity will reappear shortly as the next refresh round is performed by the catalog.', + advancedOptions: 'Advanced Options', + }, + onlyDeleteStateTitle: + 'This entity does not seem to originate from a registered location. You therefore only have the option to delete it outright from the catalog.', + unregisterState: { + title: 'This action will unregister the following entities:', + subTitle: 'Located at the following location:', + description: 'To undo, just re-register the entity in {{appTitle}}.', + unregisterButtonTitle: 'Unregister Location', + advancedOptions: 'Advanced Options', + advancedDescription: + 'You also have the option to delete the entity itself from the catalog. Note that this should only be done if you know that the catalog file has been deleted at, or moved from, its origin location. If that is not the case, the entity will reappear shortly as the next refresh round is performed by the catalog.', + }, + errorStateTitle: 'Internal error: Unknown state', + }, + userListPicker: { + defaultOrgName: 'Company', + personalFilter: { + title: 'Personal', + ownedLabel: 'Owned', + starredLabel: 'Starred', + }, + orgFilterAllLabel: 'All', + }, + }, +}); diff --git a/plugins/catalog/api-report-alpha.md b/plugins/catalog/api-report-alpha.md index 75d7e53873..642eeb3225 100644 --- a/plugins/catalog/api-report-alpha.md +++ b/plugins/catalog/api-report-alpha.md @@ -19,6 +19,81 @@ export const catalogTranslationRef: TranslationRef< { readonly 'indexPage.title': '{{orgName}} Catalog'; readonly 'indexPage.createButtonTitle': 'Create'; + readonly 'deleteEntity.description': 'This entity is not referenced by any location and is therefore not receiving updates. Click here to delete.'; + readonly 'deleteEntity.cancelButtonTitle': 'Cancel'; + readonly 'deleteEntity.deleteButtonTitle': 'Delete'; + readonly 'deleteEntity.dialogTitle': 'Are you sure you want to delete this entity?'; + readonly 'indexPage.title': '{{orgName}} Catalog'; + readonly 'indexPage.createButtonTitle': 'Create'; + readonly 'indexPage.supportButtonContent': 'All your software catalog entities'; + readonly 'aboutCard.title': 'About'; + readonly 'aboutCard.refreshButtonTitle': 'Schedule entity refresh'; + readonly 'aboutCard.editButtonTitle': 'Edit Metadata'; + readonly 'aboutCard.refreshScheduledMessage': 'Refresh scheduled'; + readonly 'aboutCard.launchTemplate': 'Launch Template'; + readonly 'aboutCard.viewTechdocs': 'View TechDocs'; + readonly 'aboutCard.viewSource': 'View Source'; + readonly 'aboutCard.descriptionField.value': 'No description'; + readonly 'aboutCard.descriptionField.label': 'Description'; + readonly 'aboutCard.ownerField.value': 'No Owner'; + readonly 'aboutCard.ownerField.label': 'Owner'; + readonly 'aboutCard.domainField.value': 'No Domain'; + readonly 'aboutCard.domainField.label': 'Domain'; + readonly 'aboutCard.systemField.value': 'No System'; + readonly 'aboutCard.systemField.label': 'System'; + readonly 'aboutCard.parentComponentField.value': 'No Parent Component'; + readonly 'aboutCard.parentComponentField.label': 'Parent Component'; + readonly 'aboutCard.typeField.label': 'Type'; + readonly 'aboutCard.lifecycleField.label': 'Lifecycle'; + readonly 'aboutCard.tagsField.value': 'No Tags'; + readonly 'aboutCard.tagsField.label': 'Tags'; + readonly 'aboutCard.targetsField.label': 'Targets'; + readonly 'searchResultItem.lifecycle': 'Lifecycle'; + readonly 'searchResultItem.Owner': 'Owner'; + readonly 'catalogTable.warningPanelTitle': 'Could not fetch catalog entities.'; + readonly 'catalogTable.viewActionTitle': 'View'; + readonly 'catalogTable.editActionTitle': 'Edit'; + readonly 'catalogTable.starActionTitle': 'Add to favorites'; + readonly 'catalogTable.unStarActionTitle': 'Remove from favorites'; + readonly 'dependencyOfComponentsCard.title': 'Dependency of components'; + readonly 'dependencyOfComponentsCard.emptyMessage': 'No component depends on this component'; + readonly 'dependsOnComponentsCard.title': 'Depends on components'; + readonly 'dependsOnComponentsCard.emptyMessage': 'No component is a dependency of this component'; + readonly 'dependsOnResourcesCard.title': 'Depends on resources'; + readonly 'dependsOnResourcesCard.emptyMessage': 'No resource is a dependency of this component'; + readonly 'entityContextMenu.copiedMessage': 'Copied!'; + readonly 'entityContextMenu.moreButtonTitle': 'More'; + readonly 'entityContextMenu.inspectMenuTitle': 'Inspect entity'; + readonly 'entityContextMenu.copyURLMenuTitle': 'Copy entity URL'; + readonly 'entityContextMenu.unregisterMenuTitle': 'Unregister entity'; + readonly 'entityLabelsCard.title': 'Labels'; + readonly 'entityLabelsCard.emptyDescription': 'No labels defined for this entity. You can add labels to your entity YAML as shown in the highlighted example below:'; + readonly 'entityLabelsCard.readMoreButtonTitle': 'Read more'; + readonly 'entityLabels.warningPanelTitle': 'Entity not found'; + readonly 'entityLabels.ownerLabel': 'Owner'; + readonly 'entityLabels.lifecycleLabel': 'Lifecycle'; + readonly 'entityLinksCard.title': 'Links'; + readonly 'entityLinksCard.emptyDescription': 'No links defined for this entity. You can add links to your entity YAML as shown in the highlighted example below:'; + readonly 'entityLinksCard.readMoreButtonTitle': 'Read more'; + readonly 'entityNotFound.title': 'Entity was not found'; + readonly 'entityNotFound.description': 'Want to help us build this? Check out our Getting Started documentation.'; + readonly 'entityNotFound.docButtonTitle': 'DOCS'; + readonly entityProcessingErrorsDescription: 'The error below originates from'; + readonly entityRelationWarningDescription: "This entity has relations to other entities, which can't be found in the catalog.\n Entities not found are: "; + readonly 'hasComponentsCard.title': 'Has components'; + readonly 'hasComponentsCard.emptyMessage': 'No component is part of this system'; + readonly 'hasResourcesCard.title': 'Has resources'; + readonly 'hasResourcesCard.emptyMessage': 'No resource is part of this system'; + readonly 'hasSubcomponentsCard.title': 'Has subcomponents'; + readonly 'hasSubcomponentsCard.emptyMessage': 'No subcomponent is part of this component'; + readonly 'hasSystemsCard.title': 'Has systems'; + readonly 'hasSystemsCard.emptyMessage': 'No system is part of this domain'; + readonly 'relatedEntitiesCard.emptyHelpLinkTitle': 'Learn how to change this.'; + readonly 'systemDiagramCard.title': 'System Diagram'; + readonly 'systemDiagramCard.description': 'Use pinch & zoo to move around the diagram.'; + readonly 'systemDiagramCard.edgeLabels.dependsOn': 'depends on'; + readonly 'systemDiagramCard.edgeLabels.partOf': 'part of'; + readonly 'systemDiagramCard.edgeLabels.provides': 'provides'; } >; diff --git a/plugins/catalog/src/alpha.ts b/plugins/catalog/src/alpha.ts index 927d5362b4..b78a5e6225 100644 --- a/plugins/catalog/src/alpha.ts +++ b/plugins/catalog/src/alpha.ts @@ -17,3 +17,4 @@ export * from './alpha/index'; export { default } from './alpha/index'; export { catalogTranslationRef } from './translation'; +export * from './translation'; diff --git a/plugins/scaffolder-react/src/next/components/TemplateCard/CardHeader.test.tsx b/plugins/scaffolder-react/src/next/components/TemplateCard/CardHeader.test.tsx index 5aa138340e..90157c3226 100644 --- a/plugins/scaffolder-react/src/next/components/TemplateCard/CardHeader.test.tsx +++ b/plugins/scaffolder-react/src/next/components/TemplateCard/CardHeader.test.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ import React from 'react'; -import { fireEvent, render } from '@testing-library/react'; +import { fireEvent } from '@testing-library/react'; import { CardHeader } from './CardHeader'; import { ThemeProvider } from '@material-ui/core/styles'; import { lightTheme } from '@backstage/theme'; @@ -30,7 +30,7 @@ import { stringifyEntityRef } from '@backstage/catalog-model'; import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common'; describe('CardHeader', () => { - it('should select the correct theme from the theme provider from the header', () => { + it('should select the correct theme from the theme provider from the header', async () => { // Can't really test what we want here. // But we can check that we call the getPage theme with the right type of template at least. const mockTheme = { @@ -38,7 +38,7 @@ describe('CardHeader', () => { getPageTheme: jest.fn(lightTheme.getPageTheme), }; - render( + await renderInTestApp( Date: Tue, 5 Mar 2024 17:27:16 +0800 Subject: [PATCH 038/416] chore: update changelog Signed-off-by: mario ma --- .changeset/friendly-oranges-greet.md | 1 - 1 file changed, 1 deletion(-) diff --git a/.changeset/friendly-oranges-greet.md b/.changeset/friendly-oranges-greet.md index 4fbabf76f5..d327c40640 100644 --- a/.changeset/friendly-oranges-greet.md +++ b/.changeset/friendly-oranges-greet.md @@ -1,5 +1,4 @@ --- -'@backstage/plugin-scaffolder-react': patch '@backstage/plugin-catalog-react': patch '@backstage/plugin-catalog': patch --- From 951e2daf16df181a6e9f70fa861e068e2d6a0338 Mon Sep 17 00:00:00 2001 From: mario ma Date: Thu, 28 Mar 2024 21:39:24 +0800 Subject: [PATCH 039/416] fix: unit test Signed-off-by: mario ma --- .../EntityNamespacePicker/EntityNamespacePicker.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/catalog-react/src/components/EntityNamespacePicker/EntityNamespacePicker.test.tsx b/plugins/catalog-react/src/components/EntityNamespacePicker/EntityNamespacePicker.test.tsx index aa9c794f3b..05fa1dc07f 100644 --- a/plugins/catalog-react/src/components/EntityNamespacePicker/EntityNamespacePicker.test.tsx +++ b/plugins/catalog-react/src/components/EntityNamespacePicker/EntityNamespacePicker.test.tsx @@ -241,7 +241,7 @@ describe('', () => { ); }); it('renders initially selected namespaces', async () => { - render( + renderInTestApp( Date: Tue, 9 Apr 2024 21:10:24 +0800 Subject: [PATCH 040/416] fix: ci pipeline prettier:check error Signed-off-by: mario ma --- .../src/components/EntitySearchBar/EntitySearchBar.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/catalog-react/src/components/EntitySearchBar/EntitySearchBar.test.tsx b/plugins/catalog-react/src/components/EntitySearchBar/EntitySearchBar.test.tsx index 89a486bfa3..736c0678f8 100644 --- a/plugins/catalog-react/src/components/EntitySearchBar/EntitySearchBar.test.tsx +++ b/plugins/catalog-react/src/components/EntitySearchBar/EntitySearchBar.test.tsx @@ -53,4 +53,4 @@ describe('EntitySearchBar', () => { text: undefined, }); }); -}); \ No newline at end of file +}); From 430c8fbcfc79a5e121dfec06a095758a98268824 Mon Sep 17 00:00:00 2001 From: mario ma Date: Tue, 9 Apr 2024 21:54:53 +0800 Subject: [PATCH 041/416] fix: update api report Signed-off-by: mario ma --- plugins/catalog/api-report-alpha.md | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/catalog/api-report-alpha.md b/plugins/catalog/api-report-alpha.md index 642eeb3225..14d62d53bf 100644 --- a/plugins/catalog/api-report-alpha.md +++ b/plugins/catalog/api-report-alpha.md @@ -29,6 +29,7 @@ export const catalogTranslationRef: TranslationRef< readonly 'aboutCard.title': 'About'; readonly 'aboutCard.refreshButtonTitle': 'Schedule entity refresh'; readonly 'aboutCard.editButtonTitle': 'Edit Metadata'; + readonly 'aboutCard.createSimilarButtonTitle': 'Create something similar'; readonly 'aboutCard.refreshScheduledMessage': 'Refresh scheduled'; readonly 'aboutCard.launchTemplate': 'Launch Template'; readonly 'aboutCard.viewTechdocs': 'View TechDocs'; From 24208fce4e26cb708ce94bdedf23a5d45124287e Mon Sep 17 00:00:00 2001 From: mario ma Date: Tue, 9 Apr 2024 22:29:10 +0800 Subject: [PATCH 042/416] fix: unit test Signed-off-by: mario ma --- .../EntitySearchBar/EntitySearchBar.test.tsx | 2 +- .../CatalogTable/PaginatedCatalogTable.test.tsx | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/catalog-react/src/components/EntitySearchBar/EntitySearchBar.test.tsx b/plugins/catalog-react/src/components/EntitySearchBar/EntitySearchBar.test.tsx index 736c0678f8..cbfeffa009 100644 --- a/plugins/catalog-react/src/components/EntitySearchBar/EntitySearchBar.test.tsx +++ b/plugins/catalog-react/src/components/EntitySearchBar/EntitySearchBar.test.tsx @@ -25,7 +25,7 @@ describe('EntitySearchBar', () => { it('should display search value and execute set callback', async () => { const updateFilters = jest.fn(); - renderInTestApp( + await renderInTestApp( { ); }; - it('should display all the items', () => { - render( + it('should display all the items', async () => { + await renderInTestApp( wrapInContext(), ); @@ -74,7 +74,7 @@ describe('PaginatedCatalogTable', () => { }); it('should display and invoke the next button', async () => { - const { rerender } = render( + const { rerender } = await renderInTestApp( wrapInContext( { }); it('should display and invoke the prev button', async () => { - const { rerender } = render( + const { rerender } = await renderInTestApp( wrapInContext( Date: Tue, 18 Jun 2024 16:27:59 +0800 Subject: [PATCH 043/416] fix: rebase conficts Signed-off-by: mario ma --- plugins/catalog/api-report-alpha.md | 2 -- plugins/scaffolder/api-report.md | 26 +++++++++++++------------- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/plugins/catalog/api-report-alpha.md b/plugins/catalog/api-report-alpha.md index 14d62d53bf..102e2a7aa3 100644 --- a/plugins/catalog/api-report-alpha.md +++ b/plugins/catalog/api-report-alpha.md @@ -17,8 +17,6 @@ import { TranslationRef } from '@backstage/core-plugin-api/alpha'; export const catalogTranslationRef: TranslationRef< 'catalog', { - readonly 'indexPage.title': '{{orgName}} Catalog'; - readonly 'indexPage.createButtonTitle': 'Create'; readonly 'deleteEntity.description': 'This entity is not referenced by any location and is therefore not receiving updates. Click here to delete.'; readonly 'deleteEntity.cancelButtonTitle': 'Cancel'; readonly 'deleteEntity.deleteButtonTitle': 'Delete'; diff --git a/plugins/scaffolder/api-report.md b/plugins/scaffolder/api-report.md index 5c766af890..7f16d4c787 100644 --- a/plugins/scaffolder/api-report.md +++ b/plugins/scaffolder/api-report.md @@ -81,8 +81,6 @@ export const EntityPickerFieldExtension: FieldExtensionComponent_2< { defaultKind?: string | undefined; defaultNamespace?: string | false | undefined; - allowedKinds?: string[] | undefined; - allowArbitraryValues?: boolean | undefined; catalogFilter?: | Record< string, @@ -101,6 +99,8 @@ export const EntityPickerFieldExtension: FieldExtensionComponent_2< } >[] | undefined; + allowedKinds?: string[] | undefined; + allowArbitraryValues?: boolean | undefined; } >; @@ -110,8 +110,6 @@ export const EntityPickerFieldSchema: FieldSchema< { defaultKind?: string | undefined; defaultNamespace?: string | false | undefined; - allowedKinds?: string[] | undefined; - allowArbitraryValues?: boolean | undefined; catalogFilter?: | Record< string, @@ -130,6 +128,8 @@ export const EntityPickerFieldSchema: FieldSchema< } >[] | undefined; + allowedKinds?: string[] | undefined; + allowArbitraryValues?: boolean | undefined; } >; @@ -216,7 +216,6 @@ export const MultiEntityPickerFieldExtension: FieldExtensionComponent_2< { defaultKind?: string | undefined; defaultNamespace?: string | false | undefined; - allowArbitraryValues?: boolean | undefined; catalogFilter?: | Record< string, @@ -235,6 +234,7 @@ export const MultiEntityPickerFieldExtension: FieldExtensionComponent_2< } >[] | undefined; + allowArbitraryValues?: boolean | undefined; } >; @@ -269,8 +269,6 @@ export const OwnedEntityPickerFieldExtension: FieldExtensionComponent_2< { defaultKind?: string | undefined; defaultNamespace?: string | false | undefined; - allowedKinds?: string[] | undefined; - allowArbitraryValues?: boolean | undefined; catalogFilter?: | Record< string, @@ -289,6 +287,8 @@ export const OwnedEntityPickerFieldExtension: FieldExtensionComponent_2< } >[] | undefined; + allowedKinds?: string[] | undefined; + allowArbitraryValues?: boolean | undefined; } >; @@ -298,8 +298,6 @@ export const OwnedEntityPickerFieldSchema: FieldSchema< { defaultKind?: string | undefined; defaultNamespace?: string | false | undefined; - allowedKinds?: string[] | undefined; - allowArbitraryValues?: boolean | undefined; catalogFilter?: | Record< string, @@ -318,6 +316,8 @@ export const OwnedEntityPickerFieldSchema: FieldSchema< } >[] | undefined; + allowedKinds?: string[] | undefined; + allowArbitraryValues?: boolean | undefined; } >; @@ -330,8 +330,6 @@ export const OwnerPickerFieldExtension: FieldExtensionComponent_2< string, { defaultNamespace?: string | false | undefined; - allowedKinds?: string[] | undefined; - allowArbitraryValues?: boolean | undefined; catalogFilter?: | Record< string, @@ -350,6 +348,8 @@ export const OwnerPickerFieldExtension: FieldExtensionComponent_2< } >[] | undefined; + allowedKinds?: string[] | undefined; + allowArbitraryValues?: boolean | undefined; } >; @@ -358,8 +358,6 @@ export const OwnerPickerFieldSchema: FieldSchema< string, { defaultNamespace?: string | false | undefined; - allowedKinds?: string[] | undefined; - allowArbitraryValues?: boolean | undefined; catalogFilter?: | Record< string, @@ -378,6 +376,8 @@ export const OwnerPickerFieldSchema: FieldSchema< } >[] | undefined; + allowedKinds?: string[] | undefined; + allowArbitraryValues?: boolean | undefined; } >; From d42b410050645dcac54a3bbefa6f20e219b7a807 Mon Sep 17 00:00:00 2001 From: blam Date: Tue, 18 Jun 2024 11:53:20 +0200 Subject: [PATCH 044/416] chore: initial pass at implementation from mob with simple test Signed-off-by: blam --- .../src/wiring/createExtensionKind.test.tsx | 44 +++++ .../src/wiring/createExtensionKind.ts | 164 ++++++++++++++++++ 2 files changed, 208 insertions(+) create mode 100644 packages/frontend-plugin-api/src/wiring/createExtensionKind.test.tsx create mode 100644 packages/frontend-plugin-api/src/wiring/createExtensionKind.ts diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionKind.test.tsx b/packages/frontend-plugin-api/src/wiring/createExtensionKind.test.tsx new file mode 100644 index 0000000000..d841ea2c62 --- /dev/null +++ b/packages/frontend-plugin-api/src/wiring/createExtensionKind.test.tsx @@ -0,0 +1,44 @@ +/* + * Copyright 2024 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 { coreExtensionData } from './coreExtensionData'; +import { createExtensionKind } from './createExtensionKind'; + +describe('createExtensionKind', () => { + it('should allow creation of extension kinds', () => { + const TestExtension = createExtensionKind({ + kind: 'test-extension', + attachTo: { id: 'test', input: 'default' }, + output: { + element: coreExtensionData.reactElement, + }, + factory(_, props: { text: string }) { + return { + element:

    {props.text}

    , + }; + }, + }); + + const extension = TestExtension.new({ + name: 'my-extension', + props: { + text: 'Hello, world!', + }, + }); + + expect(extension).toBeDefined(); + }); +}); diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionKind.ts b/packages/frontend-plugin-api/src/wiring/createExtensionKind.ts new file mode 100644 index 0000000000..31a8e5da64 --- /dev/null +++ b/packages/frontend-plugin-api/src/wiring/createExtensionKind.ts @@ -0,0 +1,164 @@ +import { AppNode } from '../apis'; +import { PortableSchema } from '../schema'; +import { Expand } from '../types'; +import { + AnyExtensionDataMap, + AnyExtensionInputMap, + ExtensionDataValues, + ResolvedExtensionInputs, + createExtension, +} from './createExtension'; + +/* + * Copyright 2024 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. + */ +interface ExtensionKindOptions< + TProps, + TInputs extends AnyExtensionInputMap, + TOutput extends AnyExtensionDataMap, + TConfig, +> { + kind: string; + namespace?: string; + name?: string; + attachTo: { id: string; input: string }; + disabled?: boolean; + inputs?: TInputs; + output: TOutput; + configSchema?: PortableSchema; + factory( + options: { + node: AppNode; + config: TConfig; + inputs: Expand>; + }, + props: TProps, + ): Expand>; +} + +class ExtensionKind< + TProps, + TInputs extends AnyExtensionInputMap, + TOutput extends AnyExtensionDataMap, + TConfig, +> { + static create< + TProps, + TInputs extends AnyExtensionInputMap, + TOutput extends AnyExtensionDataMap, + TConfig, + >( + options: ExtensionKindOptions, + ): ExtensionKind { + return new ExtensionKind(options); + } + + private constructor( + private readonly options: ExtensionKindOptions< + TProps, + TInputs, + TOutput, + TConfig + >, + ) {} + + public new(options: { + namespace?: string; + name?: string; + attachTo?: { id: string; input: string }; + disabled?: boolean; + inputs?: TInputs; + output?: TOutput; + configSchema?: PortableSchema; + props: TProps; + factory?( + options: { + node: AppNode; + config: TConfig; + inputs: Expand>; + orignalFactory( + options?: { + node?: AppNode; + config?: TConfig; + inputs?: Expand>; + }, + props?: TProps, + ): Expand>; + }, + props: TProps, + ): Expand>; + }) { + return createExtension({ + kind: this.options.kind, + namespace: options.namespace ?? this.options.namespace, + name: options.name ?? this.options.name, + attachTo: options.attachTo ?? this.options.attachTo, + disabled: options.disabled ?? this.options.disabled, + inputs: options.inputs ?? this.options.inputs, + output: options.output ?? this.options.output, + configSchema: options.configSchema ?? this.options.configSchema, // TODO: some config merging or smth + factory: ({ node, config, inputs }) => { + if (options.factory) { + return options.factory( + { + node, + config, + inputs, + orignalFactory: ( + innerOptions?: { + node?: AppNode; + config?: TConfig; + inputs?: Expand>; + }, + innerProps?: TProps, + ) => + this.options.factory( + { + node: innerOptions?.node ?? node, + config: innerOptions?.config ?? config, + inputs: innerOptions?.inputs ?? inputs, + }, + innerProps ?? options.props, + ), + }, + options.props, + ); + } + + return this.options.factory( + { + node, + config, + inputs, + }, + options.props, + ); + }, + }); + } +} + +/** + * A simpler replacement for wrapping up `createExtension` inside a kind or type. This allows for a cleaner API for creating + * types and instances of those types. + */ +export function createExtensionKind< + TProps, + TInputs extends AnyExtensionInputMap, + TOutput extends AnyExtensionDataMap, + TConfig, +>(options: ExtensionKindOptions) { + return ExtensionKind.create(options); +} From d6c9f12ab3bc54f077e1d2baac8396c61c1c9cbf Mon Sep 17 00:00:00 2001 From: blam Date: Tue, 18 Jun 2024 13:27:31 +0200 Subject: [PATCH 045/416] chore: add some simple tests Signed-off-by: blam --- .../src/wiring/createExtensionKind.test.tsx | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionKind.test.tsx b/packages/frontend-plugin-api/src/wiring/createExtensionKind.test.tsx index d841ea2c62..ea9459f3f6 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtensionKind.test.tsx +++ b/packages/frontend-plugin-api/src/wiring/createExtensionKind.test.tsx @@ -16,6 +16,7 @@ import React from 'react'; import { coreExtensionData } from './coreExtensionData'; import { createExtensionKind } from './createExtensionKind'; +import { createExtensionTester } from '@backstage/frontend-test-utils'; describe('createExtensionKind', () => { it('should allow creation of extension kinds', () => { @@ -40,5 +41,40 @@ describe('createExtensionKind', () => { }); expect(extension).toBeDefined(); + + const { container } = createExtensionTester(extension).render(); + expect(container.querySelector('h1')).toHaveTextContent('Hello, world!'); + }); + + it('should allow overriding of the default factory', () => { + const TestExtension = createExtensionKind({ + kind: 'test-extension', + attachTo: { id: 'test', input: 'default' }, + output: { + element: coreExtensionData.reactElement, + }, + factory(_, props: { text: string }) { + return { + element:

    {props.text}

    , + }; + }, + }); + + const extension = TestExtension.new({ + name: 'my-extension', + props: { + text: 'Hello, world!', + }, + factory(_, props: { text: string }) { + return { + element:

    {props.text}

    , + }; + }, + }); + + expect(extension).toBeDefined(); + + const { container } = createExtensionTester(extension).render(); + expect(container.querySelector('h2')).toHaveTextContent('Hello, world!'); }); }); From ad4591af6615ac1e6281e424ea3b7ec90e9ca4f9 Mon Sep 17 00:00:00 2001 From: blam Date: Tue, 18 Jun 2024 13:29:57 +0200 Subject: [PATCH 046/416] chore: test creted extension Signed-off-by: blam --- .../src/wiring/createExtensionKind.test.tsx | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionKind.test.tsx b/packages/frontend-plugin-api/src/wiring/createExtensionKind.test.tsx index ea9459f3f6..2d5b218082 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtensionKind.test.tsx +++ b/packages/frontend-plugin-api/src/wiring/createExtensionKind.test.tsx @@ -40,7 +40,31 @@ describe('createExtensionKind', () => { }, }); - expect(extension).toBeDefined(); + expect(extension).toEqual({ + $$type: '@backstage/ExtensionDefinition', + attachTo: { + id: 'test', + input: 'default', + }, + configSchema: undefined, + disabled: false, + inputs: {}, + kind: 'test-extension', + name: 'my-extension', + namespace: undefined, + output: { + element: { + $$type: '@backstage/ExtensionDataRef', + config: {}, + id: 'core.reactElement', + optional: expect.any(Function), + toString: expect.any(Function), + }, + }, + factory: expect.any(Function), + toString: expect.any(Function), + version: 'v1', + }); const { container } = createExtensionTester(extension).render(); expect(container.querySelector('h1')).toHaveTextContent('Hello, world!'); From 582dfb5359009e74913b0466976a6ee77a29a822 Mon Sep 17 00:00:00 2001 From: mario ma Date: Tue, 18 Jun 2024 19:54:41 +0800 Subject: [PATCH 047/416] fix: EntityNamespacePicker test Signed-off-by: mario ma --- .../EntityNamespacePicker.test.tsx | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/plugins/catalog-react/src/components/EntityNamespacePicker/EntityNamespacePicker.test.tsx b/plugins/catalog-react/src/components/EntityNamespacePicker/EntityNamespacePicker.test.tsx index 05fa1dc07f..0fd336da42 100644 --- a/plugins/catalog-react/src/components/EntityNamespacePicker/EntityNamespacePicker.test.tsx +++ b/plugins/catalog-react/src/components/EntityNamespacePicker/EntityNamespacePicker.test.tsx @@ -215,7 +215,7 @@ describe('', () => { }), ); }); - it('namespace picker is invisible if there are only 1 available option', async () => { + it('namespace picker is visible if there are only 1 available option', async () => { const defaultNamespaces = ['default', 'default', 'default']; const mockCatalogApiRefDefaultNamespace = { getEntityFacets: async () => ({ @@ -236,6 +236,27 @@ describe('', () => {
    , ); + await waitFor(() => + expect(screen.queryByText('Namespace')).toBeInTheDocument(), + ); + }); + it('namespace picker is invisible if there is zero available option', async () => { + const mockCatalogApiRefDefaultNamespace = { + getEntityFacets: async () => ({ + facets: { + 'metadata.namespace': [], + }, + }), + } as unknown as CatalogApi; + await renderInTestApp( + + + + + , + ); await waitFor(() => expect(screen.queryByText('Namespace')).not.toBeInTheDocument(), ); From 71172a4caf3044b5379bd956c64d3535e1bc6528 Mon Sep 17 00:00:00 2001 From: blam Date: Tue, 18 Jun 2024 14:13:34 +0200 Subject: [PATCH 048/416] chore: added api-reports Signed-off-by: blam --- packages/frontend-plugin-api/api-report.md | 95 +++++++++++++++++++ .../src/wiring/createExtensionKind.ts | 13 ++- .../frontend-plugin-api/src/wiring/index.ts | 5 + 3 files changed, 111 insertions(+), 2 deletions(-) diff --git a/packages/frontend-plugin-api/api-report.md b/packages/frontend-plugin-api/api-report.md index 3e19573d95..b4c761ec05 100644 --- a/packages/frontend-plugin-api/api-report.md +++ b/packages/frontend-plugin-api/api-report.md @@ -522,6 +522,16 @@ export function createExtensionInput< } >; +// @public +export function createExtensionKind< + TProps, + TInputs extends AnyExtensionInputMap, + TOutput extends AnyExtensionDataMap, + TConfig, +>( + options: ExtensionKindOptions, +): ExtensionKind; + // @public (undocumented) export interface CreateExtensionOptions< TOutput extends AnyExtensionDataMap, @@ -913,6 +923,91 @@ export interface ExtensionInput< extensionData: TExtensionData; } +// @public (undocumented) +export class ExtensionKind< + TProps, + TInputs extends AnyExtensionInputMap, + TOutput extends AnyExtensionDataMap, + TConfig, +> { + // (undocumented) + static create< + TProps, + TInputs extends AnyExtensionInputMap, + TOutput extends AnyExtensionDataMap, + TConfig, + >( + options: ExtensionKindOptions, + ): ExtensionKind; + // (undocumented) + new(options: { + namespace?: string; + name?: string; + attachTo?: { + id: string; + input: string; + }; + disabled?: boolean; + inputs?: TInputs; + output?: TOutput; + configSchema?: PortableSchema; + props: TProps; + factory?( + options: { + node: AppNode; + config: TConfig; + inputs: Expand>; + orignalFactory( + options?: { + node?: AppNode; + config?: TConfig; + inputs?: Expand>; + }, + props?: TProps, + ): Expand>; + }, + props: TProps, + ): Expand>; + }): ExtensionDefinition; +} + +// @public (undocumented) +export interface ExtensionKindOptions< + TProps, + TInputs extends AnyExtensionInputMap, + TOutput extends AnyExtensionDataMap, + TConfig, +> { + // (undocumented) + attachTo: { + id: string; + input: string; + }; + // (undocumented) + configSchema?: PortableSchema; + // (undocumented) + disabled?: boolean; + // (undocumented) + factory( + options: { + node: AppNode; + config: TConfig; + inputs: Expand>; + }, + props: TProps, + ): Expand>; + // (undocumented) + inputs?: TInputs; + // (undocumented) + kind: string; + // (undocumented) + name?: string; + // (undocumented) + namespace?: string; + // (undocumented) + output: TOutput; +} + // @public (undocumented) export interface ExtensionOverrides { // (undocumented) diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionKind.ts b/packages/frontend-plugin-api/src/wiring/createExtensionKind.ts index 31a8e5da64..2067d18c04 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtensionKind.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtensionKind.ts @@ -24,7 +24,11 @@ import { * See the License for the specific language governing permissions and * limitations under the License. */ -interface ExtensionKindOptions< + +/** + * @public + */ +export interface ExtensionKindOptions< TProps, TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, @@ -48,7 +52,10 @@ interface ExtensionKindOptions< ): Expand>; } -class ExtensionKind< +/** + * @public + */ +export class ExtensionKind< TProps, TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, @@ -153,6 +160,8 @@ class ExtensionKind< /** * A simpler replacement for wrapping up `createExtension` inside a kind or type. This allows for a cleaner API for creating * types and instances of those types. + * + * @public */ export function createExtensionKind< TProps, diff --git a/packages/frontend-plugin-api/src/wiring/index.ts b/packages/frontend-plugin-api/src/wiring/index.ts index 61f821c7ce..e8c9afbaae 100644 --- a/packages/frontend-plugin-api/src/wiring/index.ts +++ b/packages/frontend-plugin-api/src/wiring/index.ts @@ -48,3 +48,8 @@ export { type FeatureFlagConfig, type FrontendFeature, } from './types'; +export { + type ExtensionKindOptions, + ExtensionKind, + createExtensionKind, +} from './createExtensionKind'; From 4e53ad666d3c39d53ad4b81d7b6869a23dc1d5fa Mon Sep 17 00:00:00 2001 From: blam Date: Tue, 18 Jun 2024 14:15:39 +0200 Subject: [PATCH 049/416] chore: add changeset Signed-off-by: blam --- .changeset/dry-squids-tap.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 .changeset/dry-squids-tap.md diff --git a/.changeset/dry-squids-tap.md b/.changeset/dry-squids-tap.md new file mode 100644 index 0000000000..a9eb7efb3b --- /dev/null +++ b/.changeset/dry-squids-tap.md @@ -0,0 +1,26 @@ +--- +'@backstage/frontend-plugin-api': patch +--- + +Introduce a new way to create extension types and kinds, with `createExtensionKind`. + +This allows the creation of extension with the following pattern: + +```tsx +// create the extension kind +const TestExtension = createExtensionKind({ + kind: 'test-extension', + attachTo: { id: 'test', input: 'default' }, + output: { + element: coreExtensionData.reactElement, + }, + factory(_, props: { text: string }) { + return { + element:

    {props.text}

    , + }; + }, +}); + +// create an instance of the extension kind with props +const testExtension = TestExtension.create({ text: 'Hello World' }); +``` From dfaa28db0711ffe942da9fc5ddb6e3a7a45d0ecb Mon Sep 17 00:00:00 2001 From: Adam Letizia Date: Tue, 18 Jun 2024 09:23:41 -0500 Subject: [PATCH 050/416] fix(scaffolder-backend-module-github): adds requireLastPushApproval input Signed-off-by: Adam Letizia --- .changeset/ten-nails-hear.md | 5 + .../api-report.md | 2 + .../src/actions/gitHelpers.ts | 3 + .../src/actions/github.test.ts | 651 ++++-------------- .../src/actions/github.ts | 4 + .../src/actions/githubRepoPush.test.ts | 102 ++- .../src/actions/githubRepoPush.ts | 4 + .../src/actions/helpers.ts | 2 + .../src/actions/inputProperties.ts | 6 + 9 files changed, 277 insertions(+), 502 deletions(-) create mode 100644 .changeset/ten-nails-hear.md diff --git a/.changeset/ten-nails-hear.md b/.changeset/ten-nails-hear.md new file mode 100644 index 0000000000..363b028372 --- /dev/null +++ b/.changeset/ten-nails-hear.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend-module-github': patch +--- + +Adds requireLastPushApproval input property to configure Branch Protection Settings diff --git a/plugins/scaffolder-backend-module-github/api-report.md b/plugins/scaffolder-backend-module-github/api-report.md index beabdfaaf6..78b1daf65d 100644 --- a/plugins/scaffolder-backend-module-github/api-report.md +++ b/plugins/scaffolder-backend-module-github/api-report.md @@ -256,6 +256,7 @@ export function createGithubRepoPushAction(options: { sourcePath?: string | undefined; token?: string | undefined; requiredCommitSigning?: boolean | undefined; + requireLastPushApproval?: boolean | undefined; }, JsonObject >; @@ -328,6 +329,7 @@ export function createPublishGithubAction(options: { requiredStatusCheckContexts?: string[] | undefined; requireBranchesToBeUpToDate?: boolean | undefined; requiredConversationResolution?: boolean | undefined; + requireLastPushApproval?: boolean | undefined; repoVisibility?: 'internal' | 'private' | 'public' | undefined; collaborators?: | ( diff --git a/plugins/scaffolder-backend-module-github/src/actions/gitHelpers.ts b/plugins/scaffolder-backend-module-github/src/actions/gitHelpers.ts index ea92201eec..9989a80724 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/gitHelpers.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/gitHelpers.ts @@ -38,6 +38,7 @@ type BranchProtectionOptions = { }; requireBranchesToBeUpToDate?: boolean; requiredConversationResolution?: boolean; + requireLastPushApproval: boolean; defaultBranch?: string; enforceAdmins?: boolean; dismissStaleReviews?: boolean; @@ -56,6 +57,7 @@ export const enableBranchProtectionOnDefaultRepoBranch = async ({ requiredStatusCheckContexts = [], requireBranchesToBeUpToDate = true, requiredConversationResolution = false, + requireLastPushApproval = false, defaultBranch = 'master', enforceAdmins = true, dismissStaleReviews = false, @@ -88,6 +90,7 @@ export const enableBranchProtectionOnDefaultRepoBranch = async ({ require_code_owner_reviews: requireCodeOwnerReviews, bypass_pull_request_allowances: bypassPullRequestAllowances, dismiss_stale_reviews: dismissStaleReviews, + require_last_push_approval: requireLastPushApproval, }, required_conversation_resolution: requiredConversationResolution, }); diff --git a/plugins/scaffolder-backend-module-github/src/actions/github.test.ts b/plugins/scaffolder-backend-module-github/src/actions/github.test.ts index 9eda9a2eb0..31ec7ecc90 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/github.test.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/github.test.ts @@ -1010,174 +1010,6 @@ describe('publish:github', () => { ); }); - it('should call enableBranchProtectionOnDefaultRepoBranch with the correct values of requireCodeOwnerReviews', async () => { - mockOctokit.rest.users.getByUsername.mockResolvedValue({ - data: { type: 'User' }, - }); - - mockOctokit.rest.repos.createForAuthenticatedUser.mockResolvedValue({ - data: { - name: 'repo', - }, - }); - - await action.handler(mockContext); - - expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ - owner: 'owner', - client: mockOctokit, - repoName: 'repo', - logger: mockContext.logger, - defaultBranch: 'master', - requireCodeOwnerReviews: false, - bypassPullRequestAllowances: undefined, - requiredApprovingReviewCount: 1, - restrictions: undefined, - requiredStatusCheckContexts: [], - requireBranchesToBeUpToDate: true, - requiredConversationResolution: false, - enforceAdmins: true, - dismissStaleReviews: false, - requiredCommitSigning: false, - }); - - await action.handler({ - ...mockContext, - input: { - ...mockContext.input, - requireCodeOwnerReviews: true, - }, - }); - - expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ - owner: 'owner', - client: mockOctokit, - repoName: 'repo', - logger: mockContext.logger, - defaultBranch: 'master', - requireCodeOwnerReviews: true, - bypassPullRequestAllowances: undefined, - requiredApprovingReviewCount: 1, - restrictions: undefined, - requiredStatusCheckContexts: [], - requireBranchesToBeUpToDate: true, - requiredConversationResolution: false, - enforceAdmins: true, - dismissStaleReviews: false, - requiredCommitSigning: false, - }); - - await action.handler({ - ...mockContext, - input: { - ...mockContext.input, - requireCodeOwnerReviews: false, - }, - }); - - expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ - owner: 'owner', - client: mockOctokit, - repoName: 'repo', - logger: mockContext.logger, - defaultBranch: 'master', - requireCodeOwnerReviews: false, - bypassPullRequestAllowances: undefined, - requiredApprovingReviewCount: 1, - restrictions: undefined, - requiredStatusCheckContexts: [], - requireBranchesToBeUpToDate: true, - requiredConversationResolution: false, - enforceAdmins: true, - dismissStaleReviews: false, - requiredCommitSigning: false, - }); - }); - - it('should call enableBranchProtectionOnDefaultRepoBranch with the correct values of enforceAdmins', async () => { - mockOctokit.rest.users.getByUsername.mockResolvedValue({ - data: { type: 'User' }, - }); - - mockOctokit.rest.repos.createForAuthenticatedUser.mockResolvedValue({ - data: { - name: 'repo', - }, - }); - - await action.handler(mockContext); - - expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ - owner: 'owner', - client: mockOctokit, - repoName: 'repo', - logger: mockContext.logger, - defaultBranch: 'master', - requireCodeOwnerReviews: false, - bypassPullRequestAllowances: undefined, - requiredApprovingReviewCount: 1, - restrictions: undefined, - requiredStatusCheckContexts: [], - requireBranchesToBeUpToDate: true, - requiredConversationResolution: false, - enforceAdmins: true, - dismissStaleReviews: false, - requiredCommitSigning: false, - }); - - await action.handler({ - ...mockContext, - input: { - ...mockContext.input, - protectEnforceAdmins: false, - }, - }); - - expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ - owner: 'owner', - client: mockOctokit, - repoName: 'repo', - logger: mockContext.logger, - defaultBranch: 'master', - requireCodeOwnerReviews: false, - bypassPullRequestAllowances: undefined, - requiredApprovingReviewCount: 1, - restrictions: undefined, - requiredStatusCheckContexts: [], - requireBranchesToBeUpToDate: true, - requiredConversationResolution: false, - enforceAdmins: false, - dismissStaleReviews: false, - requiredCommitSigning: false, - }); - - await action.handler({ - ...mockContext, - input: { - ...mockContext.input, - protectEnforceAdmins: true, - }, - }); - - expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ - owner: 'owner', - client: mockOctokit, - repoName: 'repo', - logger: mockContext.logger, - defaultBranch: 'master', - requireCodeOwnerReviews: false, - bypassPullRequestAllowances: undefined, - requiredApprovingReviewCount: 1, - restrictions: undefined, - requiredStatusCheckContexts: [], - requireBranchesToBeUpToDate: true, - requiredConversationResolution: false, - enforceAdmins: true, - dismissStaleReviews: false, - requiredCommitSigning: false, - }); - }); - it('should call enableBranchProtectionOnDefaultRepoBranch with the correct values of requiredStatusCheckContexts and requireBranchesToBeUpToDate', async () => { mockOctokit.rest.users.getByUsername.mockResolvedValue({ data: { type: 'User' }, @@ -1204,6 +1036,7 @@ describe('publish:github', () => { requiredStatusCheckContexts: [], requireBranchesToBeUpToDate: true, requiredConversationResolution: false, + requireLastPushApproval: false, enforceAdmins: true, dismissStaleReviews: false, requiredCommitSigning: false, @@ -1232,6 +1065,7 @@ describe('publish:github', () => { requiredStatusCheckContexts: [], requireBranchesToBeUpToDate: true, requiredConversationResolution: false, + requireLastPushApproval: false, enforceAdmins: true, dismissStaleReviews: false, requiredCommitSigning: false, @@ -1259,6 +1093,7 @@ describe('publish:github', () => { requiredStatusCheckContexts: ['statusCheck'], requireBranchesToBeUpToDate: false, requiredConversationResolution: false, + requireLastPushApproval: false, enforceAdmins: true, dismissStaleReviews: false, requiredCommitSigning: false, @@ -1285,6 +1120,7 @@ describe('publish:github', () => { requiredStatusCheckContexts: [], requireBranchesToBeUpToDate: true, requiredConversationResolution: false, + requireLastPushApproval: false, enforceAdmins: true, dismissStaleReviews: false, requiredCommitSigning: false, @@ -1346,255 +1182,6 @@ describe('publish:github', () => { }); }); - it('should call enableBranchProtectionOnDefaultRepoBranch with the correct values of dismissStaleReviews', async () => { - mockOctokit.rest.users.getByUsername.mockResolvedValue({ - data: { type: 'User' }, - }); - - mockOctokit.rest.repos.createForAuthenticatedUser.mockResolvedValue({ - data: { - name: 'repo', - }, - }); - - await action.handler(mockContext); - - expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ - owner: 'owner', - client: mockOctokit, - repoName: 'repo', - logger: mockContext.logger, - defaultBranch: 'master', - requireCodeOwnerReviews: false, - bypassPullRequestAllowances: undefined, - requiredApprovingReviewCount: 1, - restrictions: undefined, - requiredStatusCheckContexts: [], - requireBranchesToBeUpToDate: true, - requiredConversationResolution: false, - enforceAdmins: true, - dismissStaleReviews: false, - requiredCommitSigning: false, - }); - - await action.handler({ - ...mockContext, - input: { - ...mockContext.input, - dismissStaleReviews: true, - }, - }); - - expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ - owner: 'owner', - client: mockOctokit, - repoName: 'repo', - logger: mockContext.logger, - defaultBranch: 'master', - requireCodeOwnerReviews: false, - bypassPullRequestAllowances: undefined, - requiredApprovingReviewCount: 1, - restrictions: undefined, - requiredStatusCheckContexts: [], - requireBranchesToBeUpToDate: true, - requiredConversationResolution: false, - enforceAdmins: true, - dismissStaleReviews: true, - requiredCommitSigning: false, - }); - - await action.handler({ - ...mockContext, - input: { - ...mockContext.input, - dismissStaleReviews: false, - }, - }); - - expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ - owner: 'owner', - client: mockOctokit, - repoName: 'repo', - logger: mockContext.logger, - defaultBranch: 'master', - requireCodeOwnerReviews: false, - bypassPullRequestAllowances: undefined, - requiredApprovingReviewCount: 1, - restrictions: undefined, - requiredStatusCheckContexts: [], - requireBranchesToBeUpToDate: true, - requiredConversationResolution: false, - enforceAdmins: true, - dismissStaleReviews: false, - requiredCommitSigning: false, - }); - }); - it('should call enableBranchProtectionOnDefaultRepoBranch with the correct values of requiredConversationResolution', async () => { - mockOctokit.rest.users.getByUsername.mockResolvedValue({ - data: { type: 'User' }, - }); - - mockOctokit.rest.repos.createForAuthenticatedUser.mockResolvedValue({ - data: { - name: 'repo', - }, - }); - - await action.handler(mockContext); - - expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ - owner: 'owner', - client: mockOctokit, - repoName: 'repo', - logger: mockContext.logger, - defaultBranch: 'master', - requireCodeOwnerReviews: false, - bypassPullRequestAllowances: undefined, - requiredApprovingReviewCount: 1, - restrictions: undefined, - requiredStatusCheckContexts: [], - requireBranchesToBeUpToDate: true, - requiredConversationResolution: false, - enforceAdmins: true, - dismissStaleReviews: false, - requiredCommitSigning: false, - }); - - await action.handler({ - ...mockContext, - input: { - ...mockContext.input, - requiredConversationResolution: true, - }, - }); - - expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ - owner: 'owner', - client: mockOctokit, - repoName: 'repo', - logger: mockContext.logger, - defaultBranch: 'master', - requireCodeOwnerReviews: false, - bypassPullRequestAllowances: undefined, - requiredApprovingReviewCount: 1, - restrictions: undefined, - requiredStatusCheckContexts: [], - requireBranchesToBeUpToDate: true, - requiredConversationResolution: true, - enforceAdmins: true, - dismissStaleReviews: false, - requiredCommitSigning: false, - }); - - await action.handler({ - ...mockContext, - input: { - ...mockContext.input, - requiredConversationResolution: false, - }, - }); - - expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ - owner: 'owner', - client: mockOctokit, - repoName: 'repo', - logger: mockContext.logger, - defaultBranch: 'master', - requireCodeOwnerReviews: false, - bypassPullRequestAllowances: undefined, - requiredApprovingReviewCount: 1, - restrictions: undefined, - requiredStatusCheckContexts: [], - requireBranchesToBeUpToDate: true, - requiredConversationResolution: false, - enforceAdmins: true, - dismissStaleReviews: false, - requiredCommitSigning: false, - }); - }); - it('should call enableBranchProtectionOnDefaultRepoBranch with the correct values of requiredApprovingReviewCount', async () => { - mockOctokit.rest.users.getByUsername.mockResolvedValue({ - data: { type: 'User' }, - }); - - mockOctokit.rest.repos.createForAuthenticatedUser.mockResolvedValue({ - data: { - name: 'repo', - }, - }); - - await action.handler(mockContext); - - expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ - owner: 'owner', - client: mockOctokit, - repoName: 'repo', - logger: mockContext.logger, - defaultBranch: 'master', - requireCodeOwnerReviews: false, - bypassPullRequestAllowances: undefined, - requiredApprovingReviewCount: 1, - restrictions: undefined, - requiredStatusCheckContexts: [], - requireBranchesToBeUpToDate: true, - requiredConversationResolution: false, - enforceAdmins: true, - dismissStaleReviews: false, - requiredCommitSigning: false, - }); - - await action.handler({ - ...mockContext, - input: { - ...mockContext.input, - requiredApprovingReviewCount: 2, - }, - }); - - expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ - owner: 'owner', - client: mockOctokit, - repoName: 'repo', - logger: mockContext.logger, - defaultBranch: 'master', - requireCodeOwnerReviews: false, - bypassPullRequestAllowances: undefined, - requiredApprovingReviewCount: 2, - restrictions: undefined, - requiredStatusCheckContexts: [], - requireBranchesToBeUpToDate: true, - requiredConversationResolution: false, - enforceAdmins: true, - dismissStaleReviews: false, - requiredCommitSigning: false, - }); - - await action.handler({ - ...mockContext, - input: { - ...mockContext.input, - requiredApprovingReviewCount: 0, - }, - }); - - expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ - owner: 'owner', - client: mockOctokit, - repoName: 'repo', - logger: mockContext.logger, - defaultBranch: 'master', - requireCodeOwnerReviews: false, - bypassPullRequestAllowances: undefined, - requiredApprovingReviewCount: 0, - restrictions: undefined, - requiredStatusCheckContexts: [], - requireBranchesToBeUpToDate: true, - requiredConversationResolution: false, - enforceAdmins: true, - dismissStaleReviews: false, - requiredCommitSigning: false, - }); - }); it('should call enableBranchProtectionOnDefaultRepoBranch with the correct values of restrictions', async () => { mockOctokit.rest.users.getByUsername.mockResolvedValue({ data: { type: 'User' }, @@ -1621,6 +1208,7 @@ describe('publish:github', () => { requiredStatusCheckContexts: [], requireBranchesToBeUpToDate: true, requiredConversationResolution: false, + requireLastPushApproval: false, enforceAdmins: true, dismissStaleReviews: false, requiredCommitSigning: false, @@ -1653,6 +1241,7 @@ describe('publish:github', () => { requiredStatusCheckContexts: [], requireBranchesToBeUpToDate: true, requiredConversationResolution: false, + requireLastPushApproval: false, enforceAdmins: true, dismissStaleReviews: false, requiredCommitSigning: false, @@ -1685,6 +1274,7 @@ describe('publish:github', () => { requiredStatusCheckContexts: [], requireBranchesToBeUpToDate: true, requiredConversationResolution: false, + requireLastPushApproval: false, enforceAdmins: true, dismissStaleReviews: false, requiredCommitSigning: false, @@ -1719,6 +1309,7 @@ describe('publish:github', () => { requiredStatusCheckContexts: [], requireBranchesToBeUpToDate: true, requiredConversationResolution: false, + requireLastPushApproval: false, enforceAdmins: true, dismissStaleReviews: false, requiredCommitSigning: false, @@ -1753,6 +1344,7 @@ describe('publish:github', () => { requiredStatusCheckContexts: [], requireBranchesToBeUpToDate: true, requiredConversationResolution: false, + requireLastPushApproval: false, enforceAdmins: true, dismissStaleReviews: false, requiredCommitSigning: false, @@ -1787,94 +1379,12 @@ describe('publish:github', () => { requiredStatusCheckContexts: [], requireBranchesToBeUpToDate: true, requiredConversationResolution: false, + requireLastPushApproval: false, enforceAdmins: true, dismissStaleReviews: false, requiredCommitSigning: false, }); }); - it('should call enableBranchProtectionOnDefaultRepoBranch with the correct values of requiredCommitSigning', async () => { - mockOctokit.rest.users.getByUsername.mockResolvedValue({ - data: { type: 'User' }, - }); - - mockOctokit.rest.repos.createForAuthenticatedUser.mockResolvedValue({ - data: { - name: 'repo', - }, - }); - - await action.handler(mockContext); - - expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ - owner: 'owner', - client: mockOctokit, - repoName: 'repo', - logger: mockContext.logger, - defaultBranch: 'master', - requireCodeOwnerReviews: false, - bypassPullRequestAllowances: undefined, - requiredApprovingReviewCount: 1, - restrictions: undefined, - requiredStatusCheckContexts: [], - requireBranchesToBeUpToDate: true, - requiredConversationResolution: false, - enforceAdmins: true, - dismissStaleReviews: false, - requiredCommitSigning: false, - }); - - await action.handler({ - ...mockContext, - input: { - ...mockContext.input, - requiredCommitSigning: false, - }, - }); - - expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ - owner: 'owner', - client: mockOctokit, - repoName: 'repo', - logger: mockContext.logger, - defaultBranch: 'master', - requireCodeOwnerReviews: false, - bypassPullRequestAllowances: undefined, - requiredApprovingReviewCount: 1, - restrictions: undefined, - requiredStatusCheckContexts: [], - requireBranchesToBeUpToDate: true, - requiredConversationResolution: false, - enforceAdmins: true, - dismissStaleReviews: false, - requiredCommitSigning: false, - }); - - await action.handler({ - ...mockContext, - input: { - ...mockContext.input, - requiredCommitSigning: true, - }, - }); - - expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ - owner: 'owner', - client: mockOctokit, - repoName: 'repo', - logger: mockContext.logger, - defaultBranch: 'master', - requireCodeOwnerReviews: false, - bypassPullRequestAllowances: undefined, - requiredApprovingReviewCount: 1, - restrictions: undefined, - requiredStatusCheckContexts: [], - requireBranchesToBeUpToDate: true, - requiredConversationResolution: false, - enforceAdmins: true, - dismissStaleReviews: false, - requiredCommitSigning: true, - }); - }); it('should call enableBranchProtectionOnDefaultRepoBranch with the correct values of bypassPullRequestAllowances', async () => { mockOctokit.rest.users.getByUsername.mockResolvedValue({ data: { type: 'User' }, @@ -1901,6 +1411,7 @@ describe('publish:github', () => { requiredStatusCheckContexts: [], requireBranchesToBeUpToDate: true, requiredConversationResolution: false, + requireLastPushApproval: false, enforceAdmins: true, dismissStaleReviews: false, requiredCommitSigning: false, @@ -1931,6 +1442,7 @@ describe('publish:github', () => { requiredStatusCheckContexts: [], requireBranchesToBeUpToDate: true, requiredConversationResolution: false, + requireLastPushApproval: false, enforceAdmins: true, dismissStaleReviews: false, requiredCommitSigning: false, @@ -1961,6 +1473,7 @@ describe('publish:github', () => { requiredStatusCheckContexts: [], requireBranchesToBeUpToDate: true, requiredConversationResolution: false, + requireLastPushApproval: false, enforceAdmins: true, dismissStaleReviews: false, requiredCommitSigning: false, @@ -1991,6 +1504,7 @@ describe('publish:github', () => { requiredStatusCheckContexts: [], requireBranchesToBeUpToDate: true, requiredConversationResolution: false, + requireLastPushApproval: false, enforceAdmins: true, dismissStaleReviews: false, requiredCommitSigning: false, @@ -2025,6 +1539,7 @@ describe('publish:github', () => { requiredStatusCheckContexts: [], requireBranchesToBeUpToDate: true, requiredConversationResolution: false, + requireLastPushApproval: false, enforceAdmins: true, dismissStaleReviews: false, requiredCommitSigning: false, @@ -2059,9 +1574,145 @@ describe('publish:github', () => { requiredStatusCheckContexts: [], requireBranchesToBeUpToDate: true, requiredConversationResolution: false, + requireLastPushApproval: false, enforceAdmins: true, dismissStaleReviews: false, requiredCommitSigning: false, }); }); + + it.each([ + { + inputProperty: 'dismissStaleReviews', + defaultValue: false, + overrideValue: true, + }, + { + inputProperty: 'requiredConversationResolution', + defaultValue: false, + overrideValue: true, + }, + { + inputProperty: 'requireLastPushApproval', + defaultValue: false, + overrideValue: true, + }, + { + inputProperty: 'requiredApprovingReviewCount', + defaultValue: 1, + overrideValue: 2, + }, + { + inputProperty: 'requiredCommitSigning', + defaultValue: false, + overrideValue: true, + }, + { + inputProperty: 'protectEnforceAdmins', + defaultValue: true, + overrideValue: false, + octokitParameter: 'enforceAdmins', + }, + { + inputProperty: 'requireCodeOwnerReviews', + defaultValue: false, + overrideValue: true, + }, + ])( + 'should call enableBranchProtectionOnDefaultRepoBranch with the correct values of $inputProperty', + async ({ + inputProperty, + defaultValue, + overrideValue, + octokitParameter, + }) => { + mockOctokit.rest.users.getByUsername.mockResolvedValue({ + data: { type: 'User' }, + }); + + mockOctokit.rest.repos.createForAuthenticatedUser.mockResolvedValue({ + data: { + name: 'repo', + }, + }); + + await action.handler(mockContext); + + expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ + owner: 'owner', + client: mockOctokit, + repoName: 'repo', + logger: mockContext.logger, + defaultBranch: 'master', + requireCodeOwnerReviews: false, + bypassPullRequestAllowances: undefined, + requiredApprovingReviewCount: 1, + restrictions: undefined, + requiredStatusCheckContexts: [], + requireBranchesToBeUpToDate: true, + requiredConversationResolution: false, + requireLastPushApproval: false, + enforceAdmins: true, + dismissStaleReviews: false, + requiredCommitSigning: false, + [octokitParameter || inputProperty]: defaultValue, + }); + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + [inputProperty]: overrideValue, + }, + }); + + expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ + owner: 'owner', + client: mockOctokit, + repoName: 'repo', + logger: mockContext.logger, + defaultBranch: 'master', + requireCodeOwnerReviews: false, + bypassPullRequestAllowances: undefined, + requiredApprovingReviewCount: 1, + restrictions: undefined, + requiredStatusCheckContexts: [], + requireBranchesToBeUpToDate: true, + requiredConversationResolution: false, + requireLastPushApproval: false, + enforceAdmins: true, + dismissStaleReviews: false, + requiredCommitSigning: false, + [octokitParameter || inputProperty]: overrideValue, + }); + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + [inputProperty]: defaultValue, + }, + }); + + expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ + owner: 'owner', + client: mockOctokit, + repoName: 'repo', + logger: mockContext.logger, + defaultBranch: 'master', + requireCodeOwnerReviews: false, + bypassPullRequestAllowances: undefined, + requiredApprovingReviewCount: 1, + restrictions: undefined, + requiredStatusCheckContexts: [], + requireBranchesToBeUpToDate: true, + requiredConversationResolution: false, + requireLastPushApproval: false, + enforceAdmins: true, + dismissStaleReviews: false, + requiredCommitSigning: false, + [octokitParameter || inputProperty]: defaultValue, + }); + }, + ); }); diff --git a/plugins/scaffolder-backend-module-github/src/actions/github.ts b/plugins/scaffolder-backend-module-github/src/actions/github.ts index f32b65bc9a..c8b22de7e7 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/github.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/github.ts @@ -86,6 +86,7 @@ export function createPublishGithubAction(options: { requiredStatusCheckContexts?: string[]; requireBranchesToBeUpToDate?: boolean; requiredConversationResolution?: boolean; + requireLastPushApproval?: boolean; repoVisibility?: 'private' | 'internal' | 'public'; collaborators?: Array< | { @@ -137,6 +138,7 @@ export function createPublishGithubAction(options: { requireBranchesToBeUpToDate: inputProps.requireBranchesToBeUpToDate, requiredConversationResolution: inputProps.requiredConversationResolution, + requireLastPushApproval: inputProps.requireLastPushApproval, repoVisibility: inputProps.repoVisibility, defaultBranch: inputProps.defaultBranch, protectDefaultBranch: inputProps.protectDefaultBranch, @@ -187,6 +189,7 @@ export function createPublishGithubAction(options: { requiredStatusCheckContexts = [], requireBranchesToBeUpToDate = true, requiredConversationResolution = false, + requireLastPushApproval = false, repoVisibility = 'private', defaultBranch = 'master', protectDefaultBranch = true, @@ -274,6 +277,7 @@ export function createPublishGithubAction(options: { requiredStatusCheckContexts, requireBranchesToBeUpToDate, requiredConversationResolution, + requireLastPushApproval, config, ctx.logger, gitCommitMessage, diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubRepoPush.test.ts b/plugins/scaffolder-backend-module-github/src/actions/githubRepoPush.test.ts index 4d16a25774..257220134f 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubRepoPush.test.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubRepoPush.test.ts @@ -325,6 +325,7 @@ describe('github:repo:push', () => { requiredStatusCheckContexts: [], requireBranchesToBeUpToDate: true, requiredConversationResolution: false, + requireLastPushApproval: false, enforceAdmins: true, dismissStaleReviews: false, bypassPullRequestAllowances: undefined, @@ -351,6 +352,7 @@ describe('github:repo:push', () => { requiredStatusCheckContexts: [], requireBranchesToBeUpToDate: true, requiredConversationResolution: false, + requireLastPushApproval: false, enforceAdmins: true, dismissStaleReviews: false, bypassPullRequestAllowances: undefined, @@ -377,6 +379,7 @@ describe('github:repo:push', () => { requiredStatusCheckContexts: [], requireBranchesToBeUpToDate: true, requiredConversationResolution: false, + requireLastPushApproval: false, enforceAdmins: true, dismissStaleReviews: false, bypassPullRequestAllowances: undefined, @@ -406,6 +409,7 @@ describe('github:repo:push', () => { requiredStatusCheckContexts: [], requireBranchesToBeUpToDate: true, requiredConversationResolution: false, + requireLastPushApproval: false, enforceAdmins: true, dismissStaleReviews: false, bypassPullRequestAllowances: undefined, @@ -432,6 +436,7 @@ describe('github:repo:push', () => { requiredStatusCheckContexts: [], requireBranchesToBeUpToDate: true, requiredConversationResolution: false, + requireLastPushApproval: false, enforceAdmins: true, dismissStaleReviews: false, bypassPullRequestAllowances: undefined, @@ -458,6 +463,7 @@ describe('github:repo:push', () => { requiredStatusCheckContexts: [], requireBranchesToBeUpToDate: true, requiredConversationResolution: false, + requireLastPushApproval: false, enforceAdmins: false, dismissStaleReviews: false, bypassPullRequestAllowances: undefined, @@ -487,6 +493,7 @@ describe('github:repo:push', () => { requiredStatusCheckContexts: [], requireBranchesToBeUpToDate: true, requiredConversationResolution: false, + requireLastPushApproval: false, enforceAdmins: true, dismissStaleReviews: false, bypassPullRequestAllowances: undefined, @@ -501,7 +508,6 @@ describe('github:repo:push', () => { ...mockContext.input, requiredStatusCheckContexts: ['statusCheck'], requireBranchesToBeUpToDate: true, - requiredConversationResolution: false, }, }); @@ -515,6 +521,7 @@ describe('github:repo:push', () => { requiredStatusCheckContexts: ['statusCheck'], requireBranchesToBeUpToDate: true, requiredConversationResolution: false, + requireLastPushApproval: false, enforceAdmins: true, dismissStaleReviews: false, bypassPullRequestAllowances: undefined, @@ -542,6 +549,7 @@ describe('github:repo:push', () => { requiredStatusCheckContexts: ['statusCheck'], requireBranchesToBeUpToDate: false, requiredConversationResolution: false, + requireLastPushApproval: false, enforceAdmins: true, dismissStaleReviews: false, bypassPullRequestAllowances: undefined, @@ -556,7 +564,6 @@ describe('github:repo:push', () => { ...mockContext.input, requiredStatusCheckContexts: [], requireBranchesToBeUpToDate: true, - requiredConversationResolution: false, }, }); @@ -570,6 +577,7 @@ describe('github:repo:push', () => { requiredStatusCheckContexts: [], requireBranchesToBeUpToDate: true, requiredConversationResolution: false, + requireLastPushApproval: false, enforceAdmins: true, dismissStaleReviews: false, bypassPullRequestAllowances: undefined, @@ -618,6 +626,7 @@ describe('github:repo:push', () => { requiredStatusCheckContexts: [], requireBranchesToBeUpToDate: true, requiredConversationResolution: false, + requireLastPushApproval: false, enforceAdmins: true, dismissStaleReviews: false, bypassPullRequestAllowances: undefined, @@ -644,6 +653,7 @@ describe('github:repo:push', () => { requiredStatusCheckContexts: [], requireBranchesToBeUpToDate: true, requiredConversationResolution: false, + requireLastPushApproval: false, enforceAdmins: true, dismissStaleReviews: true, bypassPullRequestAllowances: undefined, @@ -670,6 +680,7 @@ describe('github:repo:push', () => { requiredStatusCheckContexts: [], requireBranchesToBeUpToDate: true, requiredConversationResolution: false, + requireLastPushApproval: false, enforceAdmins: true, dismissStaleReviews: false, bypassPullRequestAllowances: undefined, @@ -699,6 +710,7 @@ describe('github:repo:push', () => { requiredStatusCheckContexts: [], requireBranchesToBeUpToDate: true, requiredConversationResolution: false, + requireLastPushApproval: false, enforceAdmins: true, dismissStaleReviews: false, bypassPullRequestAllowances: undefined, @@ -725,6 +737,7 @@ describe('github:repo:push', () => { requiredStatusCheckContexts: [], requireBranchesToBeUpToDate: true, requiredConversationResolution: true, + requireLastPushApproval: false, enforceAdmins: true, dismissStaleReviews: false, bypassPullRequestAllowances: undefined, @@ -751,6 +764,91 @@ describe('github:repo:push', () => { requiredStatusCheckContexts: [], requireBranchesToBeUpToDate: true, requiredConversationResolution: false, + requireLastPushApproval: false, + enforceAdmins: true, + dismissStaleReviews: false, + bypassPullRequestAllowances: undefined, + requiredApprovingReviewCount: 1, + requiredCommitSigning: false, + restrictions: undefined, + }); + }); + + it('should call enableBranchProtectionOnDefaultRepoBranch with the correct values of requireLastPushApproval', async () => { + mockOctokit.rest.repos.get.mockResolvedValue({ + data: { + clone_url: 'https://github.com/clone/url.git', + html_url: 'https://github.com/html/url', + }, + }); + + await action.handler(mockContext); + + expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ + owner: 'owner', + client: mockOctokit, + repoName: 'repository', + logger: mockContext.logger, + defaultBranch: 'master', + requireCodeOwnerReviews: false, + requiredStatusCheckContexts: [], + requireBranchesToBeUpToDate: true, + requiredConversationResolution: false, + requireLastPushApproval: false, + enforceAdmins: true, + dismissStaleReviews: false, + bypassPullRequestAllowances: undefined, + requiredApprovingReviewCount: 1, + requiredCommitSigning: false, + restrictions: undefined, + }); + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + requireLastPushApproval: true, + }, + }); + + expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ + owner: 'owner', + client: mockOctokit, + repoName: 'repository', + logger: mockContext.logger, + defaultBranch: 'master', + requireCodeOwnerReviews: false, + requiredStatusCheckContexts: [], + requireBranchesToBeUpToDate: true, + requiredConversationResolution: false, + requireLastPushApproval: true, + enforceAdmins: true, + dismissStaleReviews: false, + bypassPullRequestAllowances: undefined, + requiredApprovingReviewCount: 1, + requiredCommitSigning: false, + restrictions: undefined, + }); + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + requireLastPushApproval: false, + }, + }); + + expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ + owner: 'owner', + client: mockOctokit, + repoName: 'repository', + logger: mockContext.logger, + defaultBranch: 'master', + requireCodeOwnerReviews: false, + requiredStatusCheckContexts: [], + requireBranchesToBeUpToDate: true, + requiredConversationResolution: false, + requireLastPushApproval: false, enforceAdmins: true, dismissStaleReviews: false, bypassPullRequestAllowances: undefined, diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubRepoPush.ts b/plugins/scaffolder-backend-module-github/src/actions/githubRepoPush.ts index 5b9db78f48..a4fa7673c6 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubRepoPush.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubRepoPush.ts @@ -75,6 +75,7 @@ export function createGithubRepoPushAction(options: { sourcePath?: string; token?: string; requiredCommitSigning?: boolean; + requireLastPushApproval?: boolean; }>({ id: 'github:repo:push', description: @@ -95,6 +96,7 @@ export function createGithubRepoPushAction(options: { requireBranchesToBeUpToDate: inputProps.requireBranchesToBeUpToDate, requiredConversationResolution: inputProps.requiredConversationResolution, + requireLastPushApproval: inputProps.requireLastPushApproval, defaultBranch: inputProps.defaultBranch, protectDefaultBranch: inputProps.protectDefaultBranch, protectEnforceAdmins: inputProps.protectEnforceAdmins, @@ -132,6 +134,7 @@ export function createGithubRepoPushAction(options: { requiredStatusCheckContexts = [], requireBranchesToBeUpToDate = true, requiredConversationResolution = false, + requireLastPushApproval = false, token: providedToken, requiredCommitSigning = false, } = ctx.input; @@ -174,6 +177,7 @@ export function createGithubRepoPushAction(options: { requiredStatusCheckContexts, requireBranchesToBeUpToDate, requiredConversationResolution, + requireLastPushApproval, config, ctx.logger, gitCommitMessage, diff --git a/plugins/scaffolder-backend-module-github/src/actions/helpers.ts b/plugins/scaffolder-backend-module-github/src/actions/helpers.ts index dd2f4a9f76..eec6f73f92 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/helpers.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/helpers.ts @@ -360,6 +360,7 @@ export async function initRepoPushAndProtect( requiredStatusCheckContexts: string[], requireBranchesToBeUpToDate: boolean, requiredConversationResolution: boolean, + requireLastPushApproval: boolean, config: Config, logger: any, gitCommitMessage?: string, @@ -408,6 +409,7 @@ export async function initRepoPushAndProtect( requiredStatusCheckContexts, requireBranchesToBeUpToDate, requiredConversationResolution, + requireLastPushApproval, enforceAdmins: protectEnforceAdmins, dismissStaleReviews: dismissStaleReviews, requiredCommitSigning: requiredCommitSigning, diff --git a/plugins/scaffolder-backend-module-github/src/actions/inputProperties.ts b/plugins/scaffolder-backend-module-github/src/actions/inputProperties.ts index 585526fe94..f6fc592b72 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/inputProperties.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/inputProperties.ts @@ -64,6 +64,11 @@ const requiredConversationResolution = { 'Requires all conversations on code to be resolved before a pull request can be merged into this branch', type: 'boolean', }; +const requireLastPushApproval = { + title: 'Require last push approval', + type: 'boolean', + description: `Whether the most recent push to a PR must be approved by someone other than the person who pushed it. The default value is 'false'`, +}; const repoVisibility = { title: 'Repository Visibility', type: 'string', @@ -326,6 +331,7 @@ export { dismissStaleReviews }; export { requiredStatusCheckContexts }; export { requireBranchesToBeUpToDate }; export { requiredConversationResolution }; +export { requireLastPushApproval }; export { hasProjects }; export { hasIssues }; export { hasWiki }; From 3008b637979478fa4c7e68f8cc2caa2fbc7044e5 Mon Sep 17 00:00:00 2001 From: Adam Letizia Date: Tue, 18 Jun 2024 10:04:33 -0500 Subject: [PATCH 051/416] chore(test): extract test case scenarios for branch protection settings Signed-off-by: Adam Letizia --- .../src/actions/githubRepoPush.test.ts | 540 ++++-------------- 1 file changed, 126 insertions(+), 414 deletions(-) diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubRepoPush.test.ts b/plugins/scaffolder-backend-module-github/src/actions/githubRepoPush.test.ts index 257220134f..d0ee4bfa12 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubRepoPush.test.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubRepoPush.test.ts @@ -305,174 +305,6 @@ describe('github:repo:push', () => { ); }); - it('should call enableBranchProtectionOnDefaultRepoBranch with the correct values of requireCodeOwnerReviews', async () => { - mockOctokit.rest.repos.get.mockResolvedValue({ - data: { - clone_url: 'https://github.com/clone/url.git', - html_url: 'https://github.com/html/url', - }, - }); - - await action.handler(mockContext); - - expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ - owner: 'owner', - client: mockOctokit, - repoName: 'repository', - logger: mockContext.logger, - defaultBranch: 'master', - requireCodeOwnerReviews: false, - requiredStatusCheckContexts: [], - requireBranchesToBeUpToDate: true, - requiredConversationResolution: false, - requireLastPushApproval: false, - enforceAdmins: true, - dismissStaleReviews: false, - bypassPullRequestAllowances: undefined, - requiredApprovingReviewCount: 1, - requiredCommitSigning: false, - restrictions: undefined, - }); - - await action.handler({ - ...mockContext, - input: { - ...mockContext.input, - requireCodeOwnerReviews: true, - }, - }); - - expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ - owner: 'owner', - client: mockOctokit, - repoName: 'repository', - logger: mockContext.logger, - defaultBranch: 'master', - requireCodeOwnerReviews: true, - requiredStatusCheckContexts: [], - requireBranchesToBeUpToDate: true, - requiredConversationResolution: false, - requireLastPushApproval: false, - enforceAdmins: true, - dismissStaleReviews: false, - bypassPullRequestAllowances: undefined, - requiredApprovingReviewCount: 1, - requiredCommitSigning: false, - restrictions: undefined, - }); - - await action.handler({ - ...mockContext, - input: { - ...mockContext.input, - requireCodeOwnerReviews: false, - }, - }); - - expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ - owner: 'owner', - client: mockOctokit, - repoName: 'repository', - logger: mockContext.logger, - defaultBranch: 'master', - requireCodeOwnerReviews: false, - requiredStatusCheckContexts: [], - requireBranchesToBeUpToDate: true, - requiredConversationResolution: false, - requireLastPushApproval: false, - enforceAdmins: true, - dismissStaleReviews: false, - bypassPullRequestAllowances: undefined, - requiredApprovingReviewCount: 1, - requiredCommitSigning: false, - restrictions: undefined, - }); - }); - - it('should call enableBranchProtectionOnDefaultRepoBranch with the correct values of enforceAdmins', async () => { - mockOctokit.rest.repos.get.mockResolvedValue({ - data: { - clone_url: 'https://github.com/clone/url.git', - html_url: 'https://github.com/html/url', - }, - }); - - await action.handler(mockContext); - - expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ - owner: 'owner', - client: mockOctokit, - repoName: 'repository', - logger: mockContext.logger, - defaultBranch: 'master', - requireCodeOwnerReviews: false, - requiredStatusCheckContexts: [], - requireBranchesToBeUpToDate: true, - requiredConversationResolution: false, - requireLastPushApproval: false, - enforceAdmins: true, - dismissStaleReviews: false, - bypassPullRequestAllowances: undefined, - requiredApprovingReviewCount: 1, - requiredCommitSigning: false, - restrictions: undefined, - }); - - await action.handler({ - ...mockContext, - input: { - ...mockContext.input, - protectEnforceAdmins: true, - }, - }); - - expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ - owner: 'owner', - client: mockOctokit, - repoName: 'repository', - logger: mockContext.logger, - defaultBranch: 'master', - requireCodeOwnerReviews: false, - requiredStatusCheckContexts: [], - requireBranchesToBeUpToDate: true, - requiredConversationResolution: false, - requireLastPushApproval: false, - enforceAdmins: true, - dismissStaleReviews: false, - bypassPullRequestAllowances: undefined, - requiredApprovingReviewCount: 1, - requiredCommitSigning: false, - restrictions: undefined, - }); - - await action.handler({ - ...mockContext, - input: { - ...mockContext.input, - protectEnforceAdmins: false, - }, - }); - - expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ - owner: 'owner', - client: mockOctokit, - repoName: 'repository', - logger: mockContext.logger, - defaultBranch: 'master', - requireCodeOwnerReviews: false, - requiredStatusCheckContexts: [], - requireBranchesToBeUpToDate: true, - requiredConversationResolution: false, - requireLastPushApproval: false, - enforceAdmins: false, - dismissStaleReviews: false, - bypassPullRequestAllowances: undefined, - requiredApprovingReviewCount: 1, - requiredCommitSigning: false, - restrictions: undefined, - }); - }); - it('should call enableBranchProtectionOnDefaultRepoBranch with the correct values of requiredStatusCheckContexts and requireBranchesToBeUpToDate', async () => { mockOctokit.rest.repos.get.mockResolvedValue({ data: { @@ -606,255 +438,135 @@ describe('github:repo:push', () => { expect(enableBranchProtectionOnDefaultRepoBranch).not.toHaveBeenCalled(); }); - it('should call enableBranchProtectionOnDefaultRepoBranch with the correct values of dismissStaleReviews', async () => { - mockOctokit.rest.repos.get.mockResolvedValue({ - data: { - clone_url: 'https://github.com/clone/url.git', - html_url: 'https://github.com/html/url', - }, - }); + it.each([ + { + inputProperty: 'dismissStaleReviews', + defaultValue: false, + overrideValue: true, + }, + { + inputProperty: 'requiredConversationResolution', + defaultValue: false, + overrideValue: true, + }, + { + inputProperty: 'requireLastPushApproval', + defaultValue: false, + overrideValue: true, + }, + { + inputProperty: 'requiredApprovingReviewCount', + defaultValue: 1, + overrideValue: 2, + }, + { + inputProperty: 'requiredCommitSigning', + defaultValue: false, + overrideValue: true, + }, + { + inputProperty: 'protectEnforceAdmins', + defaultValue: true, + overrideValue: false, + octokitParameter: 'enforceAdmins', + }, + { + inputProperty: 'requireCodeOwnerReviews', + defaultValue: false, + overrideValue: true, + }, + ])( + 'should call enableBranchProtectionOnDefaultRepoBranch with the correct values of $inputProperty', + async ({ + inputProperty, + defaultValue, + overrideValue, + octokitParameter, + }) => { + mockOctokit.rest.repos.get.mockResolvedValue({ + data: { + clone_url: 'https://github.com/clone/url.git', + html_url: 'https://github.com/html/url', + }, + }); - await action.handler(mockContext); + await action.handler(mockContext); - expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ - owner: 'owner', - client: mockOctokit, - repoName: 'repository', - logger: mockContext.logger, - defaultBranch: 'master', - requireCodeOwnerReviews: false, - requiredStatusCheckContexts: [], - requireBranchesToBeUpToDate: true, - requiredConversationResolution: false, - requireLastPushApproval: false, - enforceAdmins: true, - dismissStaleReviews: false, - bypassPullRequestAllowances: undefined, - requiredApprovingReviewCount: 1, - requiredCommitSigning: false, - restrictions: undefined, - }); - - await action.handler({ - ...mockContext, - input: { - ...mockContext.input, - dismissStaleReviews: true, - }, - }); - - expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ - owner: 'owner', - client: mockOctokit, - repoName: 'repository', - logger: mockContext.logger, - defaultBranch: 'master', - requireCodeOwnerReviews: false, - requiredStatusCheckContexts: [], - requireBranchesToBeUpToDate: true, - requiredConversationResolution: false, - requireLastPushApproval: false, - enforceAdmins: true, - dismissStaleReviews: true, - bypassPullRequestAllowances: undefined, - requiredApprovingReviewCount: 1, - requiredCommitSigning: false, - restrictions: undefined, - }); - - await action.handler({ - ...mockContext, - input: { - ...mockContext.input, - dismissStaleReviews: false, - }, - }); - - expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ - owner: 'owner', - client: mockOctokit, - repoName: 'repository', - logger: mockContext.logger, - defaultBranch: 'master', - requireCodeOwnerReviews: false, - requiredStatusCheckContexts: [], - requireBranchesToBeUpToDate: true, - requiredConversationResolution: false, - requireLastPushApproval: false, - enforceAdmins: true, - dismissStaleReviews: false, - bypassPullRequestAllowances: undefined, - requiredApprovingReviewCount: 1, - requiredCommitSigning: false, - restrictions: undefined, - }); - }); - - it('should call enableBranchProtectionOnDefaultRepoBranch with the correct values of requiredConversationResolution', async () => { - mockOctokit.rest.repos.get.mockResolvedValue({ - data: { - clone_url: 'https://github.com/clone/url.git', - html_url: 'https://github.com/html/url', - }, - }); - - await action.handler(mockContext); - - expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ - owner: 'owner', - client: mockOctokit, - repoName: 'repository', - logger: mockContext.logger, - defaultBranch: 'master', - requireCodeOwnerReviews: false, - requiredStatusCheckContexts: [], - requireBranchesToBeUpToDate: true, - requiredConversationResolution: false, - requireLastPushApproval: false, - enforceAdmins: true, - dismissStaleReviews: false, - bypassPullRequestAllowances: undefined, - requiredApprovingReviewCount: 1, - requiredCommitSigning: false, - restrictions: undefined, - }); - - await action.handler({ - ...mockContext, - input: { - ...mockContext.input, - requiredConversationResolution: true, - }, - }); - - expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ - owner: 'owner', - client: mockOctokit, - repoName: 'repository', - logger: mockContext.logger, - defaultBranch: 'master', - requireCodeOwnerReviews: false, - requiredStatusCheckContexts: [], - requireBranchesToBeUpToDate: true, - requiredConversationResolution: true, - requireLastPushApproval: false, - enforceAdmins: true, - dismissStaleReviews: false, - bypassPullRequestAllowances: undefined, - requiredApprovingReviewCount: 1, - requiredCommitSigning: false, - restrictions: undefined, - }); - - await action.handler({ - ...mockContext, - input: { - ...mockContext.input, + expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ + owner: 'owner', + client: mockOctokit, + repoName: 'repository', + logger: mockContext.logger, + defaultBranch: 'master', + requireCodeOwnerReviews: false, + requiredStatusCheckContexts: [], + requireBranchesToBeUpToDate: true, requiredConversationResolution: false, - }, - }); - - expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ - owner: 'owner', - client: mockOctokit, - repoName: 'repository', - logger: mockContext.logger, - defaultBranch: 'master', - requireCodeOwnerReviews: false, - requiredStatusCheckContexts: [], - requireBranchesToBeUpToDate: true, - requiredConversationResolution: false, - requireLastPushApproval: false, - enforceAdmins: true, - dismissStaleReviews: false, - bypassPullRequestAllowances: undefined, - requiredApprovingReviewCount: 1, - requiredCommitSigning: false, - restrictions: undefined, - }); - }); - - it('should call enableBranchProtectionOnDefaultRepoBranch with the correct values of requireLastPushApproval', async () => { - mockOctokit.rest.repos.get.mockResolvedValue({ - data: { - clone_url: 'https://github.com/clone/url.git', - html_url: 'https://github.com/html/url', - }, - }); - - await action.handler(mockContext); - - expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ - owner: 'owner', - client: mockOctokit, - repoName: 'repository', - logger: mockContext.logger, - defaultBranch: 'master', - requireCodeOwnerReviews: false, - requiredStatusCheckContexts: [], - requireBranchesToBeUpToDate: true, - requiredConversationResolution: false, - requireLastPushApproval: false, - enforceAdmins: true, - dismissStaleReviews: false, - bypassPullRequestAllowances: undefined, - requiredApprovingReviewCount: 1, - requiredCommitSigning: false, - restrictions: undefined, - }); - - await action.handler({ - ...mockContext, - input: { - ...mockContext.input, - requireLastPushApproval: true, - }, - }); - - expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ - owner: 'owner', - client: mockOctokit, - repoName: 'repository', - logger: mockContext.logger, - defaultBranch: 'master', - requireCodeOwnerReviews: false, - requiredStatusCheckContexts: [], - requireBranchesToBeUpToDate: true, - requiredConversationResolution: false, - requireLastPushApproval: true, - enforceAdmins: true, - dismissStaleReviews: false, - bypassPullRequestAllowances: undefined, - requiredApprovingReviewCount: 1, - requiredCommitSigning: false, - restrictions: undefined, - }); - - await action.handler({ - ...mockContext, - input: { - ...mockContext.input, requireLastPushApproval: false, - }, - }); + enforceAdmins: true, + dismissStaleReviews: false, + bypassPullRequestAllowances: undefined, + requiredApprovingReviewCount: 1, + requiredCommitSigning: false, + restrictions: undefined, + [octokitParameter || inputProperty]: defaultValue, + }); - expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ - owner: 'owner', - client: mockOctokit, - repoName: 'repository', - logger: mockContext.logger, - defaultBranch: 'master', - requireCodeOwnerReviews: false, - requiredStatusCheckContexts: [], - requireBranchesToBeUpToDate: true, - requiredConversationResolution: false, - requireLastPushApproval: false, - enforceAdmins: true, - dismissStaleReviews: false, - bypassPullRequestAllowances: undefined, - requiredApprovingReviewCount: 1, - requiredCommitSigning: false, - restrictions: undefined, - }); - }); + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + [inputProperty]: overrideValue, + }, + }); + + expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ + owner: 'owner', + client: mockOctokit, + repoName: 'repository', + logger: mockContext.logger, + defaultBranch: 'master', + requireCodeOwnerReviews: false, + requiredStatusCheckContexts: [], + requireBranchesToBeUpToDate: true, + requiredConversationResolution: false, + requireLastPushApproval: false, + enforceAdmins: true, + dismissStaleReviews: false, + bypassPullRequestAllowances: undefined, + requiredApprovingReviewCount: 1, + requiredCommitSigning: false, + restrictions: undefined, + [octokitParameter || inputProperty]: overrideValue, + }); + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + [inputProperty]: defaultValue, + }, + }); + + expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ + owner: 'owner', + client: mockOctokit, + repoName: 'repository', + logger: mockContext.logger, + defaultBranch: 'master', + requireCodeOwnerReviews: false, + requiredStatusCheckContexts: [], + requireBranchesToBeUpToDate: true, + requiredConversationResolution: false, + requireLastPushApproval: false, + enforceAdmins: true, + dismissStaleReviews: false, + bypassPullRequestAllowances: undefined, + requiredApprovingReviewCount: 1, + requiredCommitSigning: false, + restrictions: undefined, + [octokitParameter || inputProperty]: defaultValue, + }); + }, + ); }); From 6caac4ef072448c81b29c2765ceeca4f64bdbb37 Mon Sep 17 00:00:00 2001 From: Adam Letizia Date: Tue, 18 Jun 2024 10:22:59 -0500 Subject: [PATCH 052/416] chore(changeset): update changeset description for each action Signed-off-by: Adam Letizia --- .changeset/ten-nails-hear.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.changeset/ten-nails-hear.md b/.changeset/ten-nails-hear.md index 363b028372..8d3c4d59c3 100644 --- a/.changeset/ten-nails-hear.md +++ b/.changeset/ten-nails-hear.md @@ -2,4 +2,6 @@ '@backstage/plugin-scaffolder-backend-module-github': patch --- -Adds requireLastPushApproval input property to configure Branch Protection Settings +Adds `requireLastPushApproval` input property to configure Branch Protection Settings in `github:publish` action + +Adds `requireLastPushApproval` input property to configure Branch Protection Settings in `github:repo:push` action From 3bf0697eb80eb0a78c654c896587e03e678e510e Mon Sep 17 00:00:00 2001 From: Marek Libra Date: Thu, 20 Jun 2024 10:23:18 +0200 Subject: [PATCH 053/416] Hide NotificationsPage toolbar for empty list Signed-off-by: Marek Libra --- .changeset/metal-suits-drum.md | 5 +++ .../NotificationsTable/NotificationsTable.tsx | 41 ++++++++++--------- 2 files changed, 26 insertions(+), 20 deletions(-) create mode 100644 .changeset/metal-suits-drum.md diff --git a/.changeset/metal-suits-drum.md b/.changeset/metal-suits-drum.md new file mode 100644 index 0000000000..4cc7e18ced --- /dev/null +++ b/.changeset/metal-suits-drum.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-notifications': patch +--- + +The toolbar on the Notifications page is hidden when there are no listed notifications. diff --git a/plugins/notifications/src/components/NotificationsTable/NotificationsTable.tsx b/plugins/notifications/src/components/NotificationsTable/NotificationsTable.tsx index 72a27975f6..d7c4c40781 100644 --- a/plugins/notifications/src/components/NotificationsTable/NotificationsTable.tsx +++ b/plugins/notifications/src/components/NotificationsTable/NotificationsTable.tsx @@ -173,12 +173,14 @@ export const NotificationsTable = ({ } }, [notifications, selectedNotifications]); - const compactColumns = React.useMemo( - (): TableColumn[] => [ + const compactColumns = React.useMemo((): TableColumn[] => { + const showToolbar = notifications.length > 0; + + return [ { /* selection column */ width: '1rem', - title: ( + title: showToolbar ? ( - ), + ) : undefined, render: (notification: Notification) => ( - ), + ) : undefined, render: (notification: Notification) => ( ), }, - ], - [ - markAsReadOnLinkOpen, - selectedNotifications, - notifications, - isUnread, - onSwitchReadStatus, - onSwitchSavedStatus, - onMarkAllRead, - onNotificationsSelectChange, - classes.severityItem, - classes.description, - ], - ); + ]; + }, [ + markAsReadOnLinkOpen, + selectedNotifications, + notifications, + isUnread, + onSwitchReadStatus, + onSwitchSavedStatus, + onMarkAllRead, + onNotificationsSelectChange, + classes.severityItem, + classes.description, + ]); return ( From 9a86dc124f64668ff0a2c7f9dcdbe50a1604f1c4 Mon Sep 17 00:00:00 2001 From: Caio Augusto Date: Thu, 20 Jun 2024 10:07:56 -0300 Subject: [PATCH 054/416] fix(docs): update extension for jsx code snippets file Signed-off-by: Caio Augusto --- docs/frontend-system/architecture/07-routes.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/frontend-system/architecture/07-routes.md b/docs/frontend-system/architecture/07-routes.md index 99cfbae937..9c6617a06f 100644 --- a/docs/frontend-system/architecture/07-routes.md +++ b/docs/frontend-system/architecture/07-routes.md @@ -359,7 +359,7 @@ export const detailsSubRouteRef = createSubRouteRef({ Using subroutes in a page extension is as simple as this: -```tsx title="plugins/catalog/src/components/IndexPage.ts" +```tsx title="plugins/catalog/src/components/IndexPage.tsx" import React from 'react'; import { Routes, Route, useLocation } from 'react-router-dom'; import { useRouteRef } from '@backstage/frontend-plugin-api'; @@ -402,7 +402,7 @@ export const IndexPage = () => { This is how you can get the parameters of a sub route URL: -```tsx title="plugins/catalog/src/components/DetailsPage.ts" +```tsx title="plugins/catalog/src/components/DetailsPage.tsx" import React from 'react'; import { useParams } from 'react-router-dom'; @@ -426,7 +426,7 @@ export const DetailsPage = () => { Finally, see how a plugin can provide subroutes: -```tsx title="plugins/catalog/src/plugin.ts" +```tsx title="plugins/catalog/src/plugin.tsx" import React from 'react'; import { createPlugin, From 8839381d6a0980df52604bc6fd8cca5a44931afc Mon Sep 17 00:00:00 2001 From: Stephen Glass Date: Fri, 21 Jun 2024 00:41:13 -0400 Subject: [PATCH 055/416] Add scaffolder option to display object items in separate rows Signed-off-by: Stephen Glass --- .changeset/late-games-protect.md | 5 + .../ReviewState/ReviewState.test.tsx | 173 ++++++++++++++++++ .../components/ReviewState/ReviewState.tsx | 63 ++++++- 3 files changed, 232 insertions(+), 9 deletions(-) create mode 100644 .changeset/late-games-protect.md diff --git a/.changeset/late-games-protect.md b/.changeset/late-games-protect.md new file mode 100644 index 0000000000..584780f836 --- /dev/null +++ b/.changeset/late-games-protect.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-react': minor +--- + +Add scaffolder option to display object items in separate rows on review page 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 e9277b2230..dfa1c9c097 100644 --- a/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.test.tsx +++ b/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.test.tsx @@ -202,4 +202,177 @@ describe('ReviewState', () => { expect(queryByRole('row', { name: 'Name type4' })).toBeInTheDocument(); }); + + it('should display exploded object in separate rows', async () => { + const formState = { + name: { + foo: 'type3', + bar: 'type4', + }, + }; + + const schemas: ParsedTemplateSchema[] = [ + { + mergedSchema: { + type: 'object', + properties: { + name: { + type: 'object', + 'ui:backstage': { + review: { + explode: true, + }, + }, + properties: { + foo: { + type: 'string', + default: 'type1', + }, + bar: { + type: 'string', + default: 'type2', + }, + }, + }, + }, + }, + schema: {}, + title: 'test', + uiSchema: {}, + description: 'asd', + }, + ]; + + const { queryByRole } = render( + , + ); + + expect(queryByRole('row', { name: 'Foo type3' })).toBeInTheDocument(); + expect(queryByRole('row', { name: 'Bar type4' })).toBeInTheDocument(); + }); + + it('should display exploded nested objects', async () => { + const formState = { + name: { + foo: 'type3', + bar: 'type4', + example: { + test: 'type6', + }, + }, + }; + + const schemas: ParsedTemplateSchema[] = [ + { + mergedSchema: { + type: 'object', + properties: { + name: { + type: 'object', + 'ui:backstage': { + review: { + explode: true, + }, + }, + properties: { + foo: { + type: 'string', + default: 'type1', + }, + bar: { + type: 'string', + default: 'type2', + }, + example: { + type: 'object', + 'ui:backstage': { + review: { + explode: true, + }, + }, + properties: { + test: { + type: 'string', + }, + }, + }, + }, + }, + }, + }, + schema: {}, + title: 'test', + uiSchema: {}, + description: 'asd', + }, + ]; + + const { queryByRole } = render( + , + ); + + expect(queryByRole('row', { name: 'Foo type3' })).toBeInTheDocument(); + expect(queryByRole('row', { name: 'Bar type4' })).toBeInTheDocument(); + expect(queryByRole('row', { name: 'Test type6' })).toBeInTheDocument(); + }); + + it('should display partially exploded nested objects', async () => { + const formState = { + name: { + foo: 'type3', + bar: 'type4', + example: { + test: 'type6', + }, + }, + }; + + const schemas: ParsedTemplateSchema[] = [ + { + mergedSchema: { + type: 'object', + properties: { + name: { + type: 'object', + 'ui:backstage': { + review: { + explode: true, + }, + }, + properties: { + foo: { + type: 'string', + default: 'type1', + }, + bar: { + type: 'string', + default: 'type2', + }, + example: { + type: 'object', + properties: { + test: { + type: 'string', + }, + }, + }, + }, + }, + }, + }, + schema: {}, + title: 'test', + uiSchema: {}, + description: 'asd', + }, + ]; + + const { queryByRole } = render( + , + ); + + expect(queryByRole('row', { name: 'Foo type3' })).toBeInTheDocument(); + expect(queryByRole('row', { name: 'Bar type4' })).toBeInTheDocument(); + expect(queryByRole('row', { name: 'Test type6' })).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 e3c7bc303e..ac7ac989e3 100644 --- a/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.tsx +++ b/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.tsx @@ -15,7 +15,7 @@ */ import React from 'react'; import { StructuredMetadataTable } from '@backstage/core-components'; -import { JsonObject } from '@backstage/types'; +import { JsonObject, JsonValue } from '@backstage/types'; import { Draft07 as JSONSchema } from 'json-schema-library'; import { ParsedTemplateSchema } from '../../hooks/useTemplateSchema'; @@ -28,6 +28,39 @@ export type ReviewStateProps = { formState: JsonObject; }; +function flattenObject( + obj: JsonObject, + prefix: string, + schema: JSONSchema, + formState: JsonObject, +): [string, JsonValue | undefined][] { + return Object.entries(obj).flatMap(([key, value]) => { + const prefixedKey = prefix ? `${prefix}/${key}` : key; + + const definitionInSchema = schema.getSchema({ + pointer: `#/${prefixedKey}`, + data: formState, + }); + + if (definitionInSchema) { + const backstageReviewOptions = definitionInSchema['ui:backstage']?.review; + + // Recurse into nested objects + if ( + backstageReviewOptions && + backstageReviewOptions.explode && + typeof value === 'object' && + value !== null && + !Array.isArray(value) + ) { + return flattenObject(value, prefixedKey, schema, formState); + } + } + + return [[key, value]]; + }); +} + /** * The component used by the {@link Stepper} to render the review step. * @alpha @@ -35,7 +68,7 @@ export type ReviewStateProps = { export const ReviewState = (props: ReviewStateProps) => { const reviewData = Object.fromEntries( Object.entries(props.formState) - .map(([key, value]) => { + .flatMap(([key, value]) => { for (const step of props.schemas) { const parsedSchema = new JSONSchema(step.mergedSchema); const definitionInSchema = parsedSchema.getSchema({ @@ -49,30 +82,42 @@ export const ReviewState = (props: ReviewStateProps) => { if (backstageReviewOptions) { if (backstageReviewOptions.mask) { - return [key, backstageReviewOptions.mask]; + return [[key, backstageReviewOptions.mask]]; } if (backstageReviewOptions.show === false) { return []; } + if ( + backstageReviewOptions.explode && + typeof value === 'object' && + value !== null && + !Array.isArray(value) + ) { + return flattenObject(value, key, parsedSchema, props.formState); + } } if (definitionInSchema['ui:widget'] === 'password') { - return [key, '******']; + return [[key, '******']]; } if (definitionInSchema.enum && definitionInSchema.enumNames) { return [ - key, - definitionInSchema.enumNames[ - definitionInSchema.enum.indexOf(value) - ] || value, + [ + key, + definitionInSchema.enumNames[ + definitionInSchema.enum.indexOf(value) + ] || value, + ], ]; } } } - return [key, value]; + + return [[key, value]]; }) .filter(prop => prop.length > 0), ); + return ; }; From 6f8e1176d858545ade3340a656bd098f25113c10 Mon Sep 17 00:00:00 2001 From: Tavi Nolan Date: Fri, 21 Jun 2024 12:30:17 +0100 Subject: [PATCH 056/416] Updating documents Signed-off-by: Tavi Nolan --- docs/features/software-catalog/configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/features/software-catalog/configuration.md b/docs/features/software-catalog/configuration.md index 61366a91f7..d0206172e5 100644 --- a/docs/features/software-catalog/configuration.md +++ b/docs/features/software-catalog/configuration.md @@ -47,7 +47,7 @@ action is logged for further investigation. ### Local File (`type: file`) Configurations In addition to url locations, you can use the `file` location type to bring in content from the local file system. You should only use this for local development, test setups, and example data, not for production data. -You are also not able to use placeholders in them like `$text`. You can however reference other files relative to the current file. See the full [catalog example data set here](https://github.com/backstage/backstage/tree/master/packages/catalog-model/examples) for an extensive example. +You are also not able to use placeholders in them like `$text`. `$json` or `$yaml`. You can however reference other files relative to the current file. See the full [catalog example data set here](https://github.com/backstage/backstage/blob/master/packages/create-app/templates/default-app/app-config.yaml.hbs) for an extensive example. Here is an example pulling in the `all.yaml` file from the examples folder. Note the use of `../../` to go up two levels from the current execution path of the backend. This is typically `packages/backend/`. From 1ba64786fa522e00f4c65868b8ae0d9e6d4db43f Mon Sep 17 00:00:00 2001 From: Tavi Nolan Date: Fri, 21 Jun 2024 13:04:30 +0100 Subject: [PATCH 057/416] Minor updates to testing documentation Signed-off-by: Tavi Nolan --- docs/plugins/testing.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/docs/plugins/testing.md b/docs/plugins/testing.md index a97b3d8166..7292ac9754 100644 --- a/docs/plugins/testing.md +++ b/docs/plugins/testing.md @@ -24,7 +24,7 @@ Running an individual test (e.g. `MyComponent.test.tsx`): To run both `MyComponent.test.tsx` and `MyControl.test.tsx` suite of tests: - yarn test MyCo + yarn test MyComponent MyControl :::note Note @@ -52,10 +52,6 @@ We use the light-weight [react-testing-library](https://github.com/kentcdodds/react-testing-library) to render React components. -## Testing Utilities - -TODO. - ## Writing Unit Tests The following principles are good guides for determining if you are writing high From d7773d174b3b4fab95db812d6a65cb7bff064139 Mon Sep 17 00:00:00 2001 From: Patrick Jungermann Date: Fri, 21 Jun 2024 22:30:44 +0200 Subject: [PATCH 058/416] refactor(catalog,github): reduce code duplication Signed-off-by: Patrick Jungermann --- .../providers/GithubEntityProvider.test.ts | 810 +++++------------- 1 file changed, 200 insertions(+), 610 deletions(-) diff --git a/plugins/catalog-backend-module-github/src/providers/GithubEntityProvider.test.ts b/plugins/catalog-backend-module-github/src/providers/GithubEntityProvider.test.ts index 42e49c2f72..4ee90d5395 100644 --- a/plugins/catalog-backend-module-github/src/providers/GithubEntityProvider.test.ts +++ b/plugins/catalog-backend-module-github/src/providers/GithubEntityProvider.test.ts @@ -19,12 +19,17 @@ import { TaskInvocationDefinition, TaskRunner, } from '@backstage/backend-tasks'; -import { ConfigReader } from '@backstage/config'; -import { EntityProviderConnection } from '@backstage/plugin-catalog-node'; +import { Config, ConfigReader } from '@backstage/config'; +import { + DeferredEntity, + EntityProviderConnection, + locationSpecToMetadataName, +} from '@backstage/plugin-catalog-node'; import { GithubEntityProvider } from './GithubEntityProvider'; import * as helpers from '../lib/github'; import { EventParams } from '@backstage/plugin-events-node'; import { mockServices } from '@backstage/backend-test-utils'; +import { Commit, PushEvent } from '@octokit/webhooks-types'; jest.mock('../lib/github', () => { return { @@ -47,62 +52,147 @@ class PersistingTaskRunner implements TaskRunner { const logger = mockServices.logger.mock(); describe('GithubEntityProvider', () => { - afterEach(() => jest.clearAllMocks()); + const createSingleProviderConfig = (options?: { + providerConfig?: object; + unwrapped?: boolean; + }): Config => { + const providerConfig = { + organization: 'test-org', + ...options?.providerConfig, + }; - it('no provider config', () => { + return new ConfigReader({ + catalog: { + providers: { + github: options?.unwrapped + ? providerConfig + : { myProvider: providerConfig }, + }, + }, + }); + }; + + const createProviders = (config: Config) => { const schedule = new PersistingTaskRunner(); - const config = new ConfigReader({}); - const providers = GithubEntityProvider.fromConfig(config, { + return GithubEntityProvider.fromConfig(config, { logger, schedule, }); + }; + + const createPushEvent = (options?: { + catalogFile?: { action?: 'added' | 'removed' | 'modified'; path?: string }; + org?: string; + ref?: string; + }): EventParams => { + const organization = options?.org ?? 'test-org'; + const repo = { + default_branch: 'main', + master_branch: 'main', + name: 'test-repo', + organization, + topics: [], + url: `https://github.com/${organization}/test-repo`, + } as Partial; + + const catalogCommit = { + added: [] as string[], + modified: [] as string[], + removed: [] as string[], + }; + catalogCommit[options?.catalogFile?.action ?? 'modified'] = [ + options?.catalogFile?.path ?? 'catalog-info.yaml', + ]; + + const event = { + ref: options?.ref ?? 'refs/heads/main', + repository: repo as PushEvent['repository'], + created: true, + deleted: false, + forced: false, + commits: [ + { + added: ['new-file.yaml'], + removed: [], + modified: [], + }, + catalogCommit, + ] as Partial[], + } as PushEvent; + + return { + topic: 'github.push', + metadata: { + 'x-github-event': 'push', + }, + eventPayload: event, + }; + }; + + const createExpectedEntitiesForUrl = (url: string): DeferredEntity[] => { + return [ + { + entity: { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Location', + metadata: { + annotations: { + 'backstage.io/managed-by-location': `url:${url}`, + 'backstage.io/managed-by-origin-location': `url:${url}`, + }, + name: locationSpecToMetadataName({ type: 'url', target: url }), + }, + spec: { + presence: 'optional', + target: url, + type: 'url', + }, + }, + locationKey: 'github-provider:myProvider', + }, + ]; + }; + + const createExpectedEntitiesForEvent = ( + event: EventParams, + options?: { branch?: string; catalogFilePath?: string }, + ): DeferredEntity[] => { + const url = `${event.eventPayload.repository.url}/blob/${ + options?.branch ?? 'main' + }/${options?.catalogFilePath ?? 'catalog-info.yaml'}`; + return createExpectedEntitiesForUrl(url); + }; + + afterEach(() => jest.clearAllMocks()); + + it('no provider config', () => { + const config = new ConfigReader({}); + const providers = createProviders(config); expect(providers).toHaveLength(0); }); it('single simple provider config', () => { - const schedule = new PersistingTaskRunner(); - const config = new ConfigReader({ - catalog: { - providers: { - github: { - organization: 'test-org', - }, - }, - }, - }); - const providers = GithubEntityProvider.fromConfig(config, { - logger, - schedule, - }); + const config = createSingleProviderConfig({ unwrapped: true }); + const providers = createProviders(config); expect(providers).toHaveLength(1); expect(providers[0].getProviderName()).toEqual('github-provider:default'); }); it('throws when the integration config does not exist', () => { - const schedule = new PersistingTaskRunner(); - const config = new ConfigReader({ - catalog: { - providers: { - github: { - organization: 'test-org', - host: 'ghe.internal.com', - }, - }, + const config = createSingleProviderConfig({ + providerConfig: { + host: 'ghe.internal.com', }, }); - expect(() => - GithubEntityProvider.fromConfig(config, { - logger, - schedule, - }), - ).toThrow(/There is no GitHub config that matches host ghe.internal.com/); + expect(() => createProviders(config)).toThrow( + /There is no GitHub config that matches host ghe.internal.com/, + ); }); it('multiple provider configs', () => { - const schedule = new PersistingTaskRunner(); const config = new ConfigReader({ catalog: { providers: { @@ -117,10 +207,7 @@ describe('GithubEntityProvider', () => { }, }, }); - const providers = GithubEntityProvider.fromConfig(config, { - logger, - schedule, - }); + const providers = createProviders(config); expect(providers).toHaveLength(2); expect(providers[0].getProviderName()).toEqual( @@ -132,19 +219,12 @@ describe('GithubEntityProvider', () => { }); it('apply full update on scheduled execution with basic filters', async () => { - const config = new ConfigReader({ - catalog: { - providers: { - github: { - myProvider: { - organization: 'test-org', - catalogPath: 'custom/path/catalog-custom.yaml', - filters: { - branch: 'main', - repository: 'test-.*', - }, - }, - }, + const config = createSingleProviderConfig({ + providerConfig: { + catalogPath: 'custom/path/catalog-custom.yaml', + filters: { + branch: 'main', + repository: 'test-.*', }, }, }); @@ -194,27 +274,7 @@ describe('GithubEntityProvider', () => { await (taskDef.fn as () => Promise)(); const url = `https://github.com/test-org/test-repo/blob/main/custom/path/catalog-custom.yaml`; - const expectedEntities = [ - { - entity: { - apiVersion: 'backstage.io/v1alpha1', - kind: 'Location', - metadata: { - annotations: { - 'backstage.io/managed-by-location': `url:${url}`, - 'backstage.io/managed-by-origin-location': `url:${url}`, - }, - name: 'generated-5e4b9498097f15434e88c477cfba6c079aa8ca7f', - }, - spec: { - presence: 'optional', - target: `${url}`, - type: 'url', - }, - }, - locationKey: 'github-provider:myProvider', - }, - ]; + const expectedEntities = createExpectedEntitiesForUrl(url); expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(1); expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({ @@ -379,27 +439,7 @@ describe('GithubEntityProvider', () => { await (taskDef.fn as () => Promise)(); const url = `https://github.com/test-org/test-repo/blob/main/custom/path/catalog-custom.yaml`; - const expectedEntities = [ - { - entity: { - apiVersion: 'backstage.io/v1alpha1', - kind: 'Location', - metadata: { - annotations: { - 'backstage.io/managed-by-location': `url:${url}`, - 'backstage.io/managed-by-origin-location': `url:${url}`, - }, - name: 'generated-5e4b9498097f15434e88c477cfba6c079aa8ca7f', - }, - spec: { - presence: 'optional', - target: `${url}`, - type: 'url', - }, - }, - locationKey: 'github-provider:myProvider', - }, - ]; + const expectedEntities = createExpectedEntitiesForUrl(url); expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(1); expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({ @@ -487,27 +527,7 @@ describe('GithubEntityProvider', () => { await (taskDef.fn as () => Promise)(); const url = `https://github.com/test-org/another-repo/blob/main/catalog-custom.yaml`; - const expectedEntities = [ - { - entity: { - apiVersion: 'backstage.io/v1alpha1', - kind: 'Location', - metadata: { - annotations: { - 'backstage.io/managed-by-location': `url:${url}`, - 'backstage.io/managed-by-origin-location': `url:${url}`, - }, - name: 'generated-934f500db2ba2e8ea3524567926f45a73bb0b532', - }, - spec: { - presence: 'optional', - target: `${url}`, - type: 'url', - }, - }, - locationKey: 'github-provider:myProvider', - }, - ]; + const expectedEntities = createExpectedEntitiesForUrl(url); expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(1); expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({ @@ -636,27 +656,7 @@ describe('GithubEntityProvider', () => { await (taskDef.fn as () => Promise)(); const url = `https://github.com/test-org/test-repo/blob/main/custom/path/catalog-custom.yaml`; - const expectedEntities = [ - { - entity: { - apiVersion: 'backstage.io/v1alpha1', - kind: 'Location', - metadata: { - annotations: { - 'backstage.io/managed-by-location': `url:${url}`, - 'backstage.io/managed-by-origin-location': `url:${url}`, - }, - name: 'generated-5e4b9498097f15434e88c477cfba6c079aa8ca7f', - }, - spec: { - presence: 'optional', - target: `${url}`, - type: 'url', - }, - }, - locationKey: 'github-provider:myProvider', - }, - ]; + const expectedEntities = createExpectedEntitiesForUrl(url); expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(1); expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({ @@ -666,15 +666,7 @@ describe('GithubEntityProvider', () => { }); it('fail without schedule and scheduler', () => { - const config = new ConfigReader({ - catalog: { - providers: { - github: { - organization: 'test-org', - }, - }, - }, - }); + const config = createSingleProviderConfig(); expect(() => GithubEntityProvider.fromConfig(config, { @@ -687,15 +679,7 @@ describe('GithubEntityProvider', () => { const scheduler = { createScheduledTaskRunner: (_: any) => jest.fn(), } as unknown as PluginTaskScheduler; - const config = new ConfigReader({ - catalog: { - providers: { - github: { - organization: 'test-org', - }, - }, - }, - }); + const config = createSingleProviderConfig(); expect(() => GithubEntityProvider.fromConfig(config, { @@ -703,7 +687,7 @@ describe('GithubEntityProvider', () => { scheduler, }), ).toThrow( - 'No schedule provided neither via code nor config for github-provider:default', + 'No schedule provided neither via code nor config for github-provider:myProvider', ); }); @@ -712,18 +696,14 @@ describe('GithubEntityProvider', () => { const scheduler = { createScheduledTaskRunner: (_: any) => schedule, } as unknown as PluginTaskScheduler; - const config = new ConfigReader({ - catalog: { - providers: { - github: { - organization: 'test-org', - schedule: { - frequency: 'P1M', - timeout: 'PT3M', - }, - }, + const config = createSingleProviderConfig({ + providerConfig: { + schedule: { + frequency: 'P1M', + timeout: 'PT3M', }, }, + unwrapped: true, }); const providers = GithubEntityProvider.fromConfig(config, { logger, @@ -735,22 +715,12 @@ describe('GithubEntityProvider', () => { }); it('apply delta update on added files from push event with glob catalog path', async () => { - const schedule = new PersistingTaskRunner(); - const config = new ConfigReader({ - catalog: { - providers: { - github: { - organization: 'test-org', - catalogPath: '**/catalog-info.yaml', - }, - }, + const config = createSingleProviderConfig({ + providerConfig: { + catalogPath: '**/catalog-info.yaml', }, }); - - const provider = GithubEntityProvider.fromConfig(config, { - logger, - schedule, - })[0]; + const provider = createProviders(config)[0]; const entityProviderConnection: EntityProviderConnection = { applyMutation: jest.fn(), @@ -758,62 +728,15 @@ describe('GithubEntityProvider', () => { }; await provider.connect(entityProviderConnection); - const event: EventParams = { - topic: 'github.push', - metadata: { - 'x-github-event': 'push', + const event = createPushEvent({ + catalogFile: { + action: 'added', + path: 'folder1/folder2/folder3/catalog-info.yaml', }, - eventPayload: { - ref: 'refs/heads/main', - repository: { - name: 'teste-1', - url: 'https://github.com/test-org/test-repo', - default_branch: 'main', - stargazers: 0, - master_branch: 'main', - organization: 'test-org', - topics: [], - }, - created: true, - deleted: false, - forced: false, - commits: [ - { - added: ['new-file.yaml'], - removed: [], - modified: [], - }, - { - added: ['folder1/folder2/folder3/catalog-info.yaml'], - removed: [], - modified: [], - }, - ], - }, - }; - const url = - 'https://github.com/test-org/test-repo/blob/main/folder1/folder2/folder3/catalog-info.yaml'; - const expectedEntities = [ - { - entity: { - apiVersion: 'backstage.io/v1alpha1', - kind: 'Location', - metadata: { - annotations: { - 'backstage.io/managed-by-location': `url:${url}`, - 'backstage.io/managed-by-origin-location': `url:${url}`, - }, - name: 'generated-c499bfb5e3f159d2bfefe26cac86a8a0b95b47f0', - }, - spec: { - presence: 'optional', - target: `${url}`, - type: 'url', - }, - }, - locationKey: 'github-provider:default', - }, - ]; + }); + const expectedEntities = createExpectedEntitiesForEvent(event, { + catalogFilePath: 'folder1/folder2/folder3/catalog-info.yaml', + }); await provider.onEvent(event); @@ -826,21 +749,8 @@ describe('GithubEntityProvider', () => { }); it('apply delta update on added files from push event', async () => { - const schedule = new PersistingTaskRunner(); - const config = new ConfigReader({ - catalog: { - providers: { - github: { - organization: 'test-org', - }, - }, - }, - }); - - const provider = GithubEntityProvider.fromConfig(config, { - logger, - schedule, - })[0]; + const config = createSingleProviderConfig(); + const provider = createProviders(config)[0]; const entityProviderConnection: EntityProviderConnection = { applyMutation: jest.fn(), @@ -848,62 +758,12 @@ describe('GithubEntityProvider', () => { }; await provider.connect(entityProviderConnection); - const event: EventParams = { - topic: 'github.push', - metadata: { - 'x-github-event': 'push', + const event = createPushEvent({ + catalogFile: { + action: 'added', }, - eventPayload: { - ref: 'refs/heads/main', - repository: { - name: 'teste-1', - url: 'https://github.com/test-org/test-repo', - default_branch: 'main', - stargazers: 0, - master_branch: 'main', - organization: 'test-org', - topics: [], - }, - created: true, - deleted: false, - forced: false, - commits: [ - { - added: ['new-file.yaml'], - removed: [], - modified: [], - }, - { - added: ['catalog-info.yaml'], - removed: [], - modified: [], - }, - ], - }, - }; - const url = - 'https://github.com/test-org/test-repo/blob/main/catalog-info.yaml'; - const expectedEntities = [ - { - entity: { - apiVersion: 'backstage.io/v1alpha1', - kind: 'Location', - metadata: { - annotations: { - 'backstage.io/managed-by-location': `url:${url}`, - 'backstage.io/managed-by-origin-location': `url:${url}`, - }, - name: 'generated-8688630f57e421bc85f12b9828ed7dad6aff3bb3', - }, - spec: { - presence: 'optional', - target: `${url}`, - type: 'url', - }, - }, - locationKey: 'github-provider:default', - }, - ]; + }); + const expectedEntities = createExpectedEntitiesForEvent(event); await provider.onEvent(event); @@ -916,21 +776,8 @@ describe('GithubEntityProvider', () => { }); it('apply delta update on removed files from push event', async () => { - const schedule = new PersistingTaskRunner(); - const config = new ConfigReader({ - catalog: { - providers: { - github: { - organization: 'test-org', - }, - }, - }, - }); - - const provider = GithubEntityProvider.fromConfig(config, { - logger, - schedule, - })[0]; + const config = createSingleProviderConfig(); + const provider = createProviders(config)[0]; const entityProviderConnection: EntityProviderConnection = { applyMutation: jest.fn(), @@ -938,62 +785,12 @@ describe('GithubEntityProvider', () => { }; await provider.connect(entityProviderConnection); - const event: EventParams = { - topic: 'github.push', - metadata: { - 'x-github-event': 'push', + const event = createPushEvent({ + catalogFile: { + action: 'removed', }, - eventPayload: { - ref: 'refs/heads/main', - repository: { - name: 'teste-1', - url: 'https://github.com/test-org/test-repo', - default_branch: 'main', - stargazers: 0, - master_branch: 'main', - organization: 'test-org', - topics: [], - }, - created: true, - deleted: false, - forced: false, - commits: [ - { - added: ['new-file.yaml'], - removed: [], - modified: [], - }, - { - added: [], - removed: ['catalog-info.yaml'], - modified: [], - }, - ], - }, - }; - const url = - 'https://github.com/test-org/test-repo/blob/main/catalog-info.yaml'; - const expectedEntities = [ - { - entity: { - apiVersion: 'backstage.io/v1alpha1', - kind: 'Location', - metadata: { - annotations: { - 'backstage.io/managed-by-location': `url:${url}`, - 'backstage.io/managed-by-origin-location': `url:${url}`, - }, - name: 'generated-8688630f57e421bc85f12b9828ed7dad6aff3bb3', - }, - spec: { - presence: 'optional', - target: `${url}`, - type: 'url', - }, - }, - locationKey: 'github-provider:default', - }, - ]; + }); + const expectedEntities = createExpectedEntitiesForEvent(event); await provider.onEvent(event); @@ -1006,21 +803,8 @@ describe('GithubEntityProvider', () => { }); it('apply refresh call on modified files from push event', async () => { - const schedule = new PersistingTaskRunner(); - const config = new ConfigReader({ - catalog: { - providers: { - github: { - organization: 'test-org', - }, - }, - }, - }); - - const provider = GithubEntityProvider.fromConfig(config, { - logger, - schedule, - })[0]; + const config = createSingleProviderConfig(); + const provider = createProviders(config)[0]; const entityProviderConnection: EntityProviderConnection = { applyMutation: jest.fn(), @@ -1028,39 +812,7 @@ describe('GithubEntityProvider', () => { }; await provider.connect(entityProviderConnection); - const event: EventParams = { - topic: 'github.push', - metadata: { - 'x-github-event': 'push', - }, - eventPayload: { - ref: 'refs/heads/main', - repository: { - name: 'teste-1', - url: 'https://github.com/test-org/test-repo', - default_branch: 'main', - stargazers: 0, - master_branch: 'main', - organization: 'test-org', - topics: [], - }, - created: true, - deleted: false, - forced: false, - commits: [ - { - added: ['new-file.yaml'], - removed: [], - modified: [], - }, - { - added: [], - removed: [], - modified: ['catalog-info.yaml'], - }, - ], - }, - }; + const event = createPushEvent(); await provider.onEvent(event); @@ -1075,7 +827,6 @@ describe('GithubEntityProvider', () => { }); it('apply refresh call on modified files from push event when catalogPath contains a glob pattern', async () => { - const schedule = new PersistingTaskRunner(); const config = new ConfigReader({ catalog: { providers: { @@ -1086,11 +837,7 @@ describe('GithubEntityProvider', () => { }, }, }); - - const provider = GithubEntityProvider.fromConfig(config, { - logger, - schedule, - })[0]; + const provider = createProviders(config)[0]; const entityProviderConnection: EntityProviderConnection = { applyMutation: jest.fn(), @@ -1098,39 +845,7 @@ describe('GithubEntityProvider', () => { }; await provider.connect(entityProviderConnection); - const event: EventParams = { - topic: 'github.push', - metadata: { - 'x-github-event': 'push', - }, - eventPayload: { - ref: 'refs/heads/main', - repository: { - name: 'teste-1', - url: 'https://github.com/test-org/test-repo', - default_branch: 'main', - stargazers: 0, - master_branch: 'main', - organization: 'test-org', - topics: [], - }, - created: true, - deleted: false, - forced: false, - commits: [ - { - added: ['new-file.yaml'], - removed: [], - modified: [], - }, - { - added: [], - removed: [], - modified: ['catalog-info.yaml'], - }, - ], - }, - }; + const event = createPushEvent(); await provider.onEvent(event); @@ -1146,25 +861,15 @@ describe('GithubEntityProvider', () => { }); it('should process repository when match filters from push event', async () => { - const schedule = new PersistingTaskRunner(); - const config = new ConfigReader({ - catalog: { - providers: { - github: { - organization: 'test-org', - filters: { - branch: 'my-special-branch', - repository: 'test-repo', - }, - }, + const config = createSingleProviderConfig({ + providerConfig: { + filters: { + branch: 'my-special-branch', + repository: 'test-repo', }, }, }); - - const provider = GithubEntityProvider.fromConfig(config, { - logger, - schedule, - })[0]; + const provider = createProviders(config)[0]; const entityProviderConnection: EntityProviderConnection = { applyMutation: jest.fn(), @@ -1172,39 +877,7 @@ describe('GithubEntityProvider', () => { }; await provider.connect(entityProviderConnection); - const event: EventParams = { - topic: 'github.push', - metadata: { - 'x-github-event': 'push', - }, - eventPayload: { - ref: 'refs/heads/my-special-branch', - repository: { - name: 'test-repo', - url: 'https://github.com/test-org/test-repo', - default_branch: 'main', - stargazers: 0, - master_branch: 'main', - organization: 'test-org', - topics: [], - }, - created: true, - deleted: false, - forced: false, - commits: [ - { - added: ['new-file.yaml'], - removed: [], - modified: [], - }, - { - added: [], - removed: [], - modified: ['catalog-info.yaml'], - }, - ], - }, - }; + const event = createPushEvent({ ref: 'refs/heads/my-special-branch' }); await provider.onEvent(event); @@ -1219,24 +892,14 @@ describe('GithubEntityProvider', () => { }); it("should skip process when didn't match filters from push event", async () => { - const schedule = new PersistingTaskRunner(); - const config = new ConfigReader({ - catalog: { - providers: { - github: { - organization: 'test-org', - filters: { - repository: 'only-special-repository', - }, - }, + const config = createSingleProviderConfig({ + providerConfig: { + filters: { + repository: 'only-special-repository', }, }, }); - - const provider = GithubEntityProvider.fromConfig(config, { - logger, - schedule, - })[0]; + const provider = createProviders(config)[0]; const entityProviderConnection: EntityProviderConnection = { applyMutation: jest.fn(), @@ -1244,39 +907,7 @@ describe('GithubEntityProvider', () => { }; await provider.connect(entityProviderConnection); - const event: EventParams = { - topic: 'github.push', - metadata: { - 'x-github-event': 'push', - }, - eventPayload: { - ref: 'refs/heads/main', - repository: { - name: 'teste-1', - url: 'https://github.com/test-org/test-repo', - default_branch: 'main', - stargazers: 0, - master_branch: 'main', - organization: 'test-org', - topics: [], - }, - created: true, - deleted: false, - forced: false, - commits: [ - { - added: ['new-file.yaml'], - removed: [], - modified: [], - }, - { - added: [], - removed: [], - modified: ['catalog-info.yaml'], - }, - ], - }, - }; + const event = createPushEvent(); await provider.onEvent(event); @@ -1285,25 +916,15 @@ describe('GithubEntityProvider', () => { }); it("should skip process when didn't match org from push event", async () => { - const schedule = new PersistingTaskRunner(); - const config = new ConfigReader({ - catalog: { - providers: { - github: { - organization: 'test-org', - filters: { - branch: 'my-special-branch', - repository: 'test-repo', - }, - }, + const config = createSingleProviderConfig({ + providerConfig: { + filters: { + branch: 'my-special-branch', + repository: 'test-repo', }, }, }); - - const provider = GithubEntityProvider.fromConfig(config, { - logger, - schedule, - })[0]; + const provider = createProviders(config)[0]; const entityProviderConnection: EntityProviderConnection = { applyMutation: jest.fn(), @@ -1311,41 +932,10 @@ describe('GithubEntityProvider', () => { }; await provider.connect(entityProviderConnection); - const event: EventParams = { - topic: 'github.push', - metadata: { - 'x-github-event': 'push', - }, - eventPayload: { - ref: 'refs/heads/my-special-branch', - repository: { - name: 'test-repo', - url: 'https://github.com/test-org/test-repo', - default_branch: 'main', - stargazers: 0, - master_branch: 'main', - organization: 'other-org', - topics: [], - }, - created: true, - deleted: false, - forced: false, - commits: [ - { - added: ['new-file.yaml'], - removed: [], - modified: [], - }, - { - added: [], - removed: [], - modified: ['catalog-info.yaml'], - }, - ], - }, - }; - - await provider.onEvent(event); + const event = createPushEvent({ + ref: 'refs/heads/my-special-branch', + org: 'other-org', + }); await provider.onEvent(event); From 89145d7efc44264c35d9327edd51d322db18abce Mon Sep 17 00:00:00 2001 From: Patrick Jungermann Date: Sat, 22 Jun 2024 01:13:42 +0200 Subject: [PATCH 059/416] refactor(catalog,github): group event-related tests Signed-off-by: Patrick Jungermann --- .../providers/GithubEntityProvider.test.ts | 561 +++++++++--------- 1 file changed, 284 insertions(+), 277 deletions(-) diff --git a/plugins/catalog-backend-module-github/src/providers/GithubEntityProvider.test.ts b/plugins/catalog-backend-module-github/src/providers/GithubEntityProvider.test.ts index 4ee90d5395..a28d216053 100644 --- a/plugins/catalog-backend-module-github/src/providers/GithubEntityProvider.test.ts +++ b/plugins/catalog-backend-module-github/src/providers/GithubEntityProvider.test.ts @@ -80,55 +80,6 @@ describe('GithubEntityProvider', () => { }); }; - const createPushEvent = (options?: { - catalogFile?: { action?: 'added' | 'removed' | 'modified'; path?: string }; - org?: string; - ref?: string; - }): EventParams => { - const organization = options?.org ?? 'test-org'; - const repo = { - default_branch: 'main', - master_branch: 'main', - name: 'test-repo', - organization, - topics: [], - url: `https://github.com/${organization}/test-repo`, - } as Partial; - - const catalogCommit = { - added: [] as string[], - modified: [] as string[], - removed: [] as string[], - }; - catalogCommit[options?.catalogFile?.action ?? 'modified'] = [ - options?.catalogFile?.path ?? 'catalog-info.yaml', - ]; - - const event = { - ref: options?.ref ?? 'refs/heads/main', - repository: repo as PushEvent['repository'], - created: true, - deleted: false, - forced: false, - commits: [ - { - added: ['new-file.yaml'], - removed: [], - modified: [], - }, - catalogCommit, - ] as Partial[], - } as PushEvent; - - return { - topic: 'github.push', - metadata: { - 'x-github-event': 'push', - }, - eventPayload: event, - }; - }; - const createExpectedEntitiesForUrl = (url: string): DeferredEntity[] => { return [ { @@ -153,16 +104,6 @@ describe('GithubEntityProvider', () => { ]; }; - const createExpectedEntitiesForEvent = ( - event: EventParams, - options?: { branch?: string; catalogFilePath?: string }, - ): DeferredEntity[] => { - const url = `${event.eventPayload.repository.url}/blob/${ - options?.branch ?? 'main' - }/${options?.catalogFilePath ?? 'catalog-info.yaml'}`; - return createExpectedEntitiesForUrl(url); - }; - afterEach(() => jest.clearAllMocks()); it('no provider config', () => { @@ -714,232 +655,298 @@ describe('GithubEntityProvider', () => { expect(providers[0].getProviderName()).toEqual('github-provider:default'); }); - it('apply delta update on added files from push event with glob catalog path', async () => { - const config = createSingleProviderConfig({ - providerConfig: { - catalogPath: '**/catalog-info.yaml', - }, - }); - const provider = createProviders(config)[0]; - - const entityProviderConnection: EntityProviderConnection = { - applyMutation: jest.fn(), - refresh: jest.fn(), + describe('on event', () => { + const createExpectedEntitiesForEvent = ( + event: EventParams, + options?: { branch?: string; catalogFilePath?: string }, + ): DeferredEntity[] => { + const url = `${event.eventPayload.repository.url}/blob/${ + options?.branch ?? 'main' + }/${options?.catalogFilePath ?? 'catalog-info.yaml'}`; + return createExpectedEntitiesForUrl(url); }; - await provider.connect(entityProviderConnection); - const event = createPushEvent({ - catalogFile: { - action: 'added', - path: 'folder1/folder2/folder3/catalog-info.yaml', - }, - }); - const expectedEntities = createExpectedEntitiesForEvent(event, { - catalogFilePath: 'folder1/folder2/folder3/catalog-info.yaml', - }); + describe('on push event', () => { + const createPushEvent = (options?: { + catalogFile?: { + action?: 'added' | 'removed' | 'modified'; + path?: string; + }; + org?: string; + ref?: string; + }): EventParams => { + const organization = options?.org ?? 'test-org'; + const repo = { + default_branch: 'main', + master_branch: 'main', + name: 'test-repo', + organization, + topics: [], + url: `https://github.com/${organization}/test-repo`, + } as Partial; - await provider.onEvent(event); + const catalogCommit = { + added: [] as string[], + modified: [] as string[], + removed: [] as string[], + }; + catalogCommit[options?.catalogFile?.action ?? 'modified'] = [ + options?.catalogFile?.path ?? 'catalog-info.yaml', + ]; - expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(1); - expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({ - type: 'delta', - added: expectedEntities, - removed: [], - }); - }); + const event = { + ref: options?.ref ?? 'refs/heads/main', + repository: repo as PushEvent['repository'], + created: true, + deleted: false, + forced: false, + commits: [ + { + added: ['new-file.yaml'], + removed: [], + modified: [], + }, + catalogCommit, + ] as Partial[], + } as PushEvent; - it('apply delta update on added files from push event', async () => { - const config = createSingleProviderConfig(); - const provider = createProviders(config)[0]; + return { + topic: 'github.push', + metadata: { + 'x-github-event': 'push', + }, + eventPayload: event, + }; + }; - const entityProviderConnection: EntityProviderConnection = { - applyMutation: jest.fn(), - refresh: jest.fn(), - }; - await provider.connect(entityProviderConnection); - - const event = createPushEvent({ - catalogFile: { - action: 'added', - }, - }); - const expectedEntities = createExpectedEntitiesForEvent(event); - - await provider.onEvent(event); - - expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(1); - expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({ - type: 'delta', - added: expectedEntities, - removed: [], - }); - }); - - it('apply delta update on removed files from push event', async () => { - const config = createSingleProviderConfig(); - const provider = createProviders(config)[0]; - - const entityProviderConnection: EntityProviderConnection = { - applyMutation: jest.fn(), - refresh: jest.fn(), - }; - await provider.connect(entityProviderConnection); - - const event = createPushEvent({ - catalogFile: { - action: 'removed', - }, - }); - const expectedEntities = createExpectedEntitiesForEvent(event); - - await provider.onEvent(event); - - expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(1); - expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({ - type: 'delta', - added: [], - removed: expectedEntities, - }); - }); - - it('apply refresh call on modified files from push event', async () => { - const config = createSingleProviderConfig(); - const provider = createProviders(config)[0]; - - const entityProviderConnection: EntityProviderConnection = { - applyMutation: jest.fn(), - refresh: jest.fn(), - }; - await provider.connect(entityProviderConnection); - - const event = createPushEvent(); - - await provider.onEvent(event); - - expect(entityProviderConnection.refresh).toHaveBeenCalledTimes(1); - expect(entityProviderConnection.refresh).toHaveBeenCalledWith({ - keys: [ - 'url:https://github.com/test-org/test-repo/tree/main/catalog-info.yaml', - 'url:https://github.com/test-org/test-repo/blob/main/catalog-info.yaml', - ], - }); - expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(0); - }); - - it('apply refresh call on modified files from push event when catalogPath contains a glob pattern', async () => { - const config = new ConfigReader({ - catalog: { - providers: { - github: { - organization: 'test-org', + it('apply delta update on added files with glob catalog path', async () => { + const config = createSingleProviderConfig({ + providerConfig: { catalogPath: '**/catalog-info.yaml', }, - }, - }, + }); + const provider = createProviders(config)[0]; + + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + await provider.connect(entityProviderConnection); + + const event = createPushEvent({ + catalogFile: { + action: 'added', + path: 'folder1/folder2/folder3/catalog-info.yaml', + }, + }); + const expectedEntities = createExpectedEntitiesForEvent(event, { + catalogFilePath: 'folder1/folder2/folder3/catalog-info.yaml', + }); + + await provider.onEvent(event); + + expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(1); + expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({ + type: 'delta', + added: expectedEntities, + removed: [], + }); + }); + + it('apply delta update on added files', async () => { + const config = createSingleProviderConfig(); + const provider = createProviders(config)[0]; + + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + await provider.connect(entityProviderConnection); + + const event = createPushEvent({ + catalogFile: { + action: 'added', + }, + }); + const expectedEntities = createExpectedEntitiesForEvent(event); + + await provider.onEvent(event); + + expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(1); + expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({ + type: 'delta', + added: expectedEntities, + removed: [], + }); + }); + + it('apply delta update on removed files', async () => { + const config = createSingleProviderConfig(); + const provider = createProviders(config)[0]; + + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + await provider.connect(entityProviderConnection); + + const event = createPushEvent({ + catalogFile: { + action: 'removed', + }, + }); + const expectedEntities = createExpectedEntitiesForEvent(event); + + await provider.onEvent(event); + + expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(1); + expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({ + type: 'delta', + added: [], + removed: expectedEntities, + }); + }); + + it('apply refresh call on modified files', async () => { + const config = createSingleProviderConfig(); + const provider = createProviders(config)[0]; + + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + await provider.connect(entityProviderConnection); + + const event = createPushEvent(); + + await provider.onEvent(event); + + expect(entityProviderConnection.refresh).toHaveBeenCalledTimes(1); + expect(entityProviderConnection.refresh).toHaveBeenCalledWith({ + keys: [ + 'url:https://github.com/test-org/test-repo/tree/main/catalog-info.yaml', + 'url:https://github.com/test-org/test-repo/blob/main/catalog-info.yaml', + ], + }); + expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(0); + }); + + it('apply refresh call on modified files with glob catalog path', async () => { + const config = new ConfigReader({ + catalog: { + providers: { + github: { + organization: 'test-org', + catalogPath: '**/catalog-info.yaml', + }, + }, + }, + }); + const provider = createProviders(config)[0]; + + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + await provider.connect(entityProviderConnection); + + const event = createPushEvent(); + + await provider.onEvent(event); + + expect(entityProviderConnection.refresh).toHaveBeenCalledTimes(1); + expect(entityProviderConnection.refresh).toHaveBeenCalledWith({ + keys: [ + 'url:https://github.com/test-org/test-repo/tree/main/catalog-info.yaml', + 'url:https://github.com/test-org/test-repo/blob/main/catalog-info.yaml', + 'url:https://github.com/test-org/test-repo/tree/main/**/catalog-info.yaml', + ], + }); + expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(0); + }); + + it('should process repository when match filters', async () => { + const config = createSingleProviderConfig({ + providerConfig: { + filters: { + branch: 'my-special-branch', + repository: 'test-repo', + }, + }, + }); + const provider = createProviders(config)[0]; + + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + await provider.connect(entityProviderConnection); + + const event = createPushEvent({ ref: 'refs/heads/my-special-branch' }); + + await provider.onEvent(event); + + expect(entityProviderConnection.refresh).toHaveBeenCalledTimes(1); + expect(entityProviderConnection.refresh).toHaveBeenCalledWith({ + keys: [ + 'url:https://github.com/test-org/test-repo/tree/my-special-branch/catalog-info.yaml', + 'url:https://github.com/test-org/test-repo/blob/my-special-branch/catalog-info.yaml', + ], + }); + expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(0); + }); + + it("should skip process when didn't match filters", async () => { + const config = createSingleProviderConfig({ + providerConfig: { + filters: { + repository: 'only-special-repository', + }, + }, + }); + const provider = createProviders(config)[0]; + + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + await provider.connect(entityProviderConnection); + + const event = createPushEvent(); + + await provider.onEvent(event); + + expect(entityProviderConnection.refresh).toHaveBeenCalledTimes(0); + expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(0); + }); + + it("should skip process when didn't match org", async () => { + const config = createSingleProviderConfig({ + providerConfig: { + filters: { + branch: 'my-special-branch', + repository: 'test-repo', + }, + }, + }); + const provider = createProviders(config)[0]; + + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + await provider.connect(entityProviderConnection); + + const event = createPushEvent({ + ref: 'refs/heads/my-special-branch', + org: 'other-org', + }); + + await provider.onEvent(event); + + expect(entityProviderConnection.refresh).toHaveBeenCalledTimes(0); + expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(0); + }); }); - const provider = createProviders(config)[0]; - - const entityProviderConnection: EntityProviderConnection = { - applyMutation: jest.fn(), - refresh: jest.fn(), - }; - await provider.connect(entityProviderConnection); - - const event = createPushEvent(); - - await provider.onEvent(event); - - expect(entityProviderConnection.refresh).toHaveBeenCalledTimes(1); - expect(entityProviderConnection.refresh).toHaveBeenCalledWith({ - keys: [ - 'url:https://github.com/test-org/test-repo/tree/main/catalog-info.yaml', - 'url:https://github.com/test-org/test-repo/blob/main/catalog-info.yaml', - 'url:https://github.com/test-org/test-repo/tree/main/**/catalog-info.yaml', - ], - }); - expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(0); - }); - - it('should process repository when match filters from push event', async () => { - const config = createSingleProviderConfig({ - providerConfig: { - filters: { - branch: 'my-special-branch', - repository: 'test-repo', - }, - }, - }); - const provider = createProviders(config)[0]; - - const entityProviderConnection: EntityProviderConnection = { - applyMutation: jest.fn(), - refresh: jest.fn(), - }; - await provider.connect(entityProviderConnection); - - const event = createPushEvent({ ref: 'refs/heads/my-special-branch' }); - - await provider.onEvent(event); - - expect(entityProviderConnection.refresh).toHaveBeenCalledTimes(1); - expect(entityProviderConnection.refresh).toHaveBeenCalledWith({ - keys: [ - 'url:https://github.com/test-org/test-repo/tree/my-special-branch/catalog-info.yaml', - 'url:https://github.com/test-org/test-repo/blob/my-special-branch/catalog-info.yaml', - ], - }); - expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(0); - }); - - it("should skip process when didn't match filters from push event", async () => { - const config = createSingleProviderConfig({ - providerConfig: { - filters: { - repository: 'only-special-repository', - }, - }, - }); - const provider = createProviders(config)[0]; - - const entityProviderConnection: EntityProviderConnection = { - applyMutation: jest.fn(), - refresh: jest.fn(), - }; - await provider.connect(entityProviderConnection); - - const event = createPushEvent(); - - await provider.onEvent(event); - - expect(entityProviderConnection.refresh).toHaveBeenCalledTimes(0); - expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(0); - }); - - it("should skip process when didn't match org from push event", async () => { - const config = createSingleProviderConfig({ - providerConfig: { - filters: { - branch: 'my-special-branch', - repository: 'test-repo', - }, - }, - }); - const provider = createProviders(config)[0]; - - const entityProviderConnection: EntityProviderConnection = { - applyMutation: jest.fn(), - refresh: jest.fn(), - }; - await provider.connect(entityProviderConnection); - - const event = createPushEvent({ - ref: 'refs/heads/my-special-branch', - org: 'other-org', - }); - - await provider.onEvent(event); - - expect(entityProviderConnection.refresh).toHaveBeenCalledTimes(0); - expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(0); }); }); From e10c75aebfdc030ea3dac888ac165d93cd75d032 Mon Sep 17 00:00:00 2001 From: "Stephen A. Wilson" Date: Sat, 22 Jun 2024 15:52:58 -0400 Subject: [PATCH 060/416] Remove duplicated docs Signed-off-by: Stephen A. Wilson --- .../catalog-info.yaml | 12 -- .../docs/code/code-sample.md | 31 ----- .../docs/extensions.md | 112 ------------------ .../docs/images/backstage-logo-cncf.svg | 1 - .../docs/index.md | 55 --------- .../docs/sub-page.md | 12 -- .../mkdocs.yml | 12 -- .../documented-component/catalog-info.yaml | 2 +- 8 files changed, 1 insertion(+), 236 deletions(-) delete mode 100644 plugins/techdocs-backend/examples/documented-component-with-title/catalog-info.yaml delete mode 100644 plugins/techdocs-backend/examples/documented-component-with-title/docs/code/code-sample.md delete mode 100644 plugins/techdocs-backend/examples/documented-component-with-title/docs/extensions.md delete mode 100644 plugins/techdocs-backend/examples/documented-component-with-title/docs/images/backstage-logo-cncf.svg delete mode 100644 plugins/techdocs-backend/examples/documented-component-with-title/docs/index.md delete mode 100644 plugins/techdocs-backend/examples/documented-component-with-title/docs/sub-page.md delete mode 100644 plugins/techdocs-backend/examples/documented-component-with-title/mkdocs.yml diff --git a/plugins/techdocs-backend/examples/documented-component-with-title/catalog-info.yaml b/plugins/techdocs-backend/examples/documented-component-with-title/catalog-info.yaml deleted file mode 100644 index 1a1d65ba39..0000000000 --- a/plugins/techdocs-backend/examples/documented-component-with-title/catalog-info.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: backstage.io/v1alpha1 -kind: Component -metadata: - name: documented-with-title - title: Fizzbuzz Docs - description: A TechDocs with a title different than it's name - annotations: - backstage.io/techdocs-ref: dir:. -spec: - type: service - lifecycle: experimental - owner: user:guest diff --git a/plugins/techdocs-backend/examples/documented-component-with-title/docs/code/code-sample.md b/plugins/techdocs-backend/examples/documented-component-with-title/docs/code/code-sample.md deleted file mode 100644 index f41ab1d506..0000000000 --- a/plugins/techdocs-backend/examples/documented-component-with-title/docs/code/code-sample.md +++ /dev/null @@ -1,31 +0,0 @@ -# Sample Code - -This page provides some sample code which may be used in your example component. - -This code uses TypeScript, and the Markdown code fence to wrap the code. - -```typescript -const serviceEntityPage = ( - - - - - - - - - - - - -); -``` - -Here is an example of Python code: - -```python -def getUsersInGroup(targetGroup, secure=False): - - if __debug__: - print('targetGroup=[' + targetGroup + ']') -``` diff --git a/plugins/techdocs-backend/examples/documented-component-with-title/docs/extensions.md b/plugins/techdocs-backend/examples/documented-component-with-title/docs/extensions.md deleted file mode 100644 index eb9abca74a..0000000000 --- a/plugins/techdocs-backend/examples/documented-component-with-title/docs/extensions.md +++ /dev/null @@ -1,112 +0,0 @@ -# Plugins & Extensions - -Just by including the TechDocs Core Plugin to your MkDocs site included with Backstage, -you gain the immediate use of a variety of popular plugins and extensions to MkDocs. - -For more information and full details of the available features, see the -[`mkdocs-techdocs-core` repository](https://github.com/backstage/mkdocs-techdocs-core#mkdocs-plugins-and-extensions). - -This page provides a demonstration of some of the available features. - -## Admonitions - -Admonitions are call outs that help catch a users attention. - -To define an admonition simply put the following Markdown into your content: - -``` -!!! warn - Defining admonitions can be addicting. -``` - -And they end up looking like this: - - -!!! warn - Defining admonitions can be addicting. - - -!!! note - You can learn a lot about TechDocs by just visiting the Backstage web site at - https://backstage.io/docs. - - -!!! info - TechDocs is the core feature that supports documentation as code in Backstage. - - -!!! tip - Don't forget to spell check your documentation. - -## PlantUML - -You can create dynamic UML diagrams on the fly by just specifying flow via text, -using [PlantUML](https://pypi.org/project/plantuml-markdown/). - -```plantuml format="svg" classes="uml myDiagram" alt="Backstage sample PlantUML" title="Backstage sample PlantUML" width="500px" height="250px" -User -> SCMProvider: stores -TechDocs -> SCMProvider: prepares -TechDocs -> TechDocs: generates -TechDocs -> CloudStorage: publishes -CloudStorage -> Backstage: displays -``` - -## Pymdownx Extensions - -Pymdownx (Python Markdown extensions) are a variety of smaller additions. - -### Details - - -??? note "What is the answer to life, the universe, and everything? (click me for the answer)" - The answer is 42. - - -??? note "What is 4 plus 4?" - The answer is 8. - - -???+ note "How do I get support?" - You can get support by opening an issue in this repository. This detail is open by default - so it's more easily visible without requiring the user to click to open it. - -### Task Lists - -Automatic rendering of Markdown task lists. - -- [x] Phase 1 -- [x] Phase 2 -- [ ] Phase 3 - -### Emojis - -Very nice job on documentation! :thumbsup: - -I've read a lot of documentation, but I love :heart: this document. - -Weather: :sunny: :umbrella: :cloud: :snowflake: - -Animals: :tiger: :horse: :turtle: :wolf: :frog: - -### Attributes - -[A Download Link](./images/backstage-logo-cncf.svg){: download } - -![A Scaled Image](./images/backstage-logo-cncf.svg){: style="width: 100px" } - -### MDX truly sane lists - -- `attributes` - -- `customer` - - `first_name` - - `test` - - `family_name` - - `email` -- `person` - - `first_name` - - `family_name` - - `birth_date` -- `subscription_id` - -- `request` diff --git a/plugins/techdocs-backend/examples/documented-component-with-title/docs/images/backstage-logo-cncf.svg b/plugins/techdocs-backend/examples/documented-component-with-title/docs/images/backstage-logo-cncf.svg deleted file mode 100644 index b5ff591d1b..0000000000 --- a/plugins/techdocs-backend/examples/documented-component-with-title/docs/images/backstage-logo-cncf.svg +++ /dev/null @@ -1 +0,0 @@ -05 Logo_Black \ No newline at end of file diff --git a/plugins/techdocs-backend/examples/documented-component-with-title/docs/index.md b/plugins/techdocs-backend/examples/documented-component-with-title/docs/index.md deleted file mode 100644 index 6295a69406..0000000000 --- a/plugins/techdocs-backend/examples/documented-component-with-title/docs/index.md +++ /dev/null @@ -1,55 +0,0 @@ -# Welcome! - -This is a basic example of documentation. It is intended as a showcase of some of the -features that TechDocs provides out of the box. - -You can see also: - -- [A sub page](sub-page.md) -- [Inline code examples](code/code-sample.md) -- [Plugin & Extension examples](extensions.md) - Diagrams, emojis, visual formatting. - -## Basic Markdown - -Headings: - -# h1 - -## h2 - -### h3 - -#### h4 - -##### h5 - -###### h6 - -Here is a bulleted list: - -- Item one -- Item two -- Item Three - -Check out the [Markdown Guide](https://www.markdownguide.org/) to learn more about how to -simply create documentation. - -You can also learn more about how to configure and setup this documentation in Backstage, -[read up on the TechDocs Overview](https://backstage.io/docs/features/techdocs/). - -## Image Example - -This documentation is powered by Backstage's TechDocs feature: - -![Backstage Logo](images/backstage-logo-cncf.svg) - -## Table Example - -While this documentation isn't comprehensive, in the future it should cover the following -topics outlined in this example table: - -| Topic | Description | -| ------- | ------------------------------------------------------------ | -| Topic 1 | An introductory topic to help you learn about the component. | -| Topic 2 | A more detailed topic that explains more information. | -| Topic 3 | A final topic that provides conclusions and lessons learned. | diff --git a/plugins/techdocs-backend/examples/documented-component-with-title/docs/sub-page.md b/plugins/techdocs-backend/examples/documented-component-with-title/docs/sub-page.md deleted file mode 100644 index 987f5e8a95..0000000000 --- a/plugins/techdocs-backend/examples/documented-component-with-title/docs/sub-page.md +++ /dev/null @@ -1,12 +0,0 @@ -# Another page in our documentation - -This sub-page can be used to elaborate on a specific part of the component. - -## Details - -It is linked off the main page, and due to its inclusion in the `mkdocs.yml` file, -becomes part of the auto-generated site navigation. - -## MkDocs - -Visit https://www.mkdocs.org for more information about the MkDocs tool. diff --git a/plugins/techdocs-backend/examples/documented-component-with-title/mkdocs.yml b/plugins/techdocs-backend/examples/documented-component-with-title/mkdocs.yml deleted file mode 100644 index 1a159a4d12..0000000000 --- a/plugins/techdocs-backend/examples/documented-component-with-title/mkdocs.yml +++ /dev/null @@ -1,12 +0,0 @@ -site_name: 'Example Documentation' -repo_url: https://github.com/backstage/backstage -edit_uri: edit/master/plugins/techdocs-backend/examples/documented-component/docs - -nav: - - Home: index.md - - Subpage: sub-page.md - - 'Code Sample': code/code-sample.md - - Extensions: extensions.md - -plugins: - - techdocs-core diff --git a/plugins/techdocs-backend/examples/documented-component/catalog-info.yaml b/plugins/techdocs-backend/examples/documented-component/catalog-info.yaml index e6d14025e1..6b30213a60 100644 --- a/plugins/techdocs-backend/examples/documented-component/catalog-info.yaml +++ b/plugins/techdocs-backend/examples/documented-component/catalog-info.yaml @@ -2,7 +2,7 @@ apiVersion: backstage.io/v1alpha1 kind: Component metadata: name: documented-component - title: Documented Component + title: Example Docs description: A Service with TechDocs documentation annotations: backstage.io/techdocs-ref: dir:. From f229d94b8abd8a79f651266705740e7b8ec8cd17 Mon Sep 17 00:00:00 2001 From: Tavi Nolan Date: Mon, 24 Jun 2024 13:29:53 +0100 Subject: [PATCH 061/416] changing period to comma Signed-off-by: Tavi Nolan --- docs/features/software-catalog/configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/features/software-catalog/configuration.md b/docs/features/software-catalog/configuration.md index d0206172e5..9524886a49 100644 --- a/docs/features/software-catalog/configuration.md +++ b/docs/features/software-catalog/configuration.md @@ -47,7 +47,7 @@ action is logged for further investigation. ### Local File (`type: file`) Configurations In addition to url locations, you can use the `file` location type to bring in content from the local file system. You should only use this for local development, test setups, and example data, not for production data. -You are also not able to use placeholders in them like `$text`. `$json` or `$yaml`. You can however reference other files relative to the current file. See the full [catalog example data set here](https://github.com/backstage/backstage/blob/master/packages/create-app/templates/default-app/app-config.yaml.hbs) for an extensive example. +You are also not able to use placeholders in them like `$text`, `$json` or `$yaml`. You can however reference other files relative to the current file. See the full [catalog example data set here](https://github.com/backstage/backstage/blob/master/packages/create-app/templates/default-app/app-config.yaml.hbs) for an extensive example. Here is an example pulling in the `all.yaml` file from the examples folder. Note the use of `../../` to go up two levels from the current execution path of the backend. This is typically `packages/backend/`. From d1488caaa309df834095bde5a48bf9f99ad797af Mon Sep 17 00:00:00 2001 From: Stephen Date: Mon, 24 Jun 2024 08:52:29 -0400 Subject: [PATCH 062/416] Revert change to app-config.yaml Signed-off-by: Stephen --- app-config.yaml | 3 --- 1 file changed, 3 deletions(-) diff --git a/app-config.yaml b/app-config.yaml index 69145cd896..cb70170541 100644 --- a/app-config.yaml +++ b/app-config.yaml @@ -297,9 +297,6 @@ catalog: # Example component for TechDocs - type: file target: ../../plugins/techdocs-backend/examples/documented-component/catalog-info.yaml - # Example component for TechDocs with a title - - type: file - target: ../../plugins/techdocs-backend/examples/documented-component-with-title/catalog-info.yaml # Example component for ADRs - type: file target: ../../plugins/adr/examples/component/catalog-info.yaml From 589860ec27f7fbe2cb96e5266737850a6c2c5ead Mon Sep 17 00:00:00 2001 From: Alper Altay Date: Mon, 24 Jun 2024 15:26:53 +0200 Subject: [PATCH 063/416] feat: add plugin to backend index.ts Signed-off-by: Alper Altay --- .../lib/new/factories/backendPlugin.test.ts | 88 ++++++++++++++++++- .../src/lib/new/factories/backendPlugin.ts | 34 +++++++ 2 files changed, 119 insertions(+), 3 deletions(-) diff --git a/packages/cli/src/lib/new/factories/backendPlugin.test.ts b/packages/cli/src/lib/new/factories/backendPlugin.test.ts index c5930592a3..c6196d8690 100644 --- a/packages/cli/src/lib/new/factories/backendPlugin.test.ts +++ b/packages/cli/src/lib/new/factories/backendPlugin.test.ts @@ -26,13 +26,19 @@ import { import { backendPlugin } from './backendPlugin'; import { createMockDirectory } from '@backstage/backend-test-utils'; +const backendIndexTsContent = ` +import { createBackend } from '@backstage/backend-defaults'; + +const backend = createBackend(); + +backend.start(); +`; + describe('backendPlugin factory', () => { const mockDir = createMockDirectory(); beforeEach(() => { - mockPaths({ - targetRoot: mockDir.path, - }); + mockPaths({ targetRoot: mockDir.path }); }); afterEach(() => { @@ -44,6 +50,9 @@ describe('backendPlugin factory', () => { packages: { backend: { 'package.json': JSON.stringify({}), + src: { + 'index.ts': backendIndexTsContent, + }, }, }, plugins: {}, @@ -89,6 +98,7 @@ describe('backendPlugin factory', () => { 'Installing:', `moving plugins${sep}test-backend`, 'backend adding dependency', + 'backend adding import and plugin', ]); await expect( @@ -99,6 +109,78 @@ describe('backendPlugin factory', () => { }, }); + await expect( + fs.readFile(mockDir.resolve('packages/backend/src/index.ts'), 'utf8'), + ).resolves.toBe(` +import { createBackend } from '@backstage/backend-defaults'; + +const backend = createBackend(); + +backend.add(import("backstage-plugin-test-backend")); +backend.start(); +`); + + expect(Task.forCommand).toHaveBeenCalledTimes(2); + expect(Task.forCommand).toHaveBeenCalledWith('yarn install', { + cwd: mockDir.resolve('plugins/test-backend'), + optional: true, + }); + expect(Task.forCommand).toHaveBeenCalledWith('yarn lint --fix', { + cwd: mockDir.resolve('plugins/test-backend'), + optional: true, + }); + }); + + it('should create a backend plugin with more options and codeowners', async () => { + mockDir.setContent({ + CODEOWNERS: '', + packages: { + backend: { + 'package.json': JSON.stringify({}), + src: { + 'index.ts': backendIndexTsContent, + }, + }, + }, + plugins: {}, + }); + + const options = await FactoryRegistry.populateOptions(backendPlugin, { + id: 'test', + owner: '@test-user', + }); + + const [, mockStream] = createMockOutputStream(); + jest.spyOn(process, 'stderr', 'get').mockReturnValue(mockStream); + jest.spyOn(Task, 'forCommand').mockResolvedValue(); + + await backendPlugin.create(options, { + scope: 'internal', + private: true, + isMonoRepo: true, + defaultVersion: '1.0.0', + markAsModified: () => {}, + createTemporaryDirectory: () => fs.mkdtemp('test'), + }); + + await expect( + fs.readJson(mockDir.resolve('packages/backend/package.json')), + ).resolves.toEqual({ + dependencies: { + '@internal/backstage-plugin-test-backend': '^1.0.0', + }, + }); + + await expect( + fs.readFile(mockDir.resolve('packages/backend/src/index.ts'), 'utf8'), + ).resolves.toBe(` +import { createBackend } from '@backstage/backend-defaults'; + +const backend = createBackend(); + +backend.add(import("@internal/backstage-plugin-test-backend")); +backend.start();`); + expect(Task.forCommand).toHaveBeenCalledTimes(2); expect(Task.forCommand).toHaveBeenCalledWith('yarn install', { cwd: mockDir.resolve('plugins/test-backend'), diff --git a/packages/cli/src/lib/new/factories/backendPlugin.ts b/packages/cli/src/lib/new/factories/backendPlugin.ts index 09ea98fbe7..06bc6bd366 100644 --- a/packages/cli/src/lib/new/factories/backendPlugin.ts +++ b/packages/cli/src/lib/new/factories/backendPlugin.ts @@ -78,6 +78,40 @@ export const backendPlugin = createFactory({ }, ); }); + + await Task.forItem('backend', 'adding import and plugin', async () => { + const backendFilePath = paths.resolveTargetRoot( + 'packages/backend/src/index.ts', + ); + if (!(await fs.pathExists(backendFilePath))) { + return; + } + const content = await fs.readFile(backendFilePath, 'utf8'); + const revLines = content.split('\n').reverse(); + + const lastImportIndex = revLines.findIndex(line => + line.match(/ from ("|').*("|')/), + ); + const lastBackendAddIndex = revLines.findIndex(line => + line.match(/backend.add/), + ); + + const backendAddLine = `backend.add(import("${name}"));`; + + if (lastImportIndex !== -1 && lastBackendAddIndex !== -1) { + if (!content.includes(backendAddLine)) { + const [indentation] = + revLines[lastBackendAddIndex + 1].match(/^\s*/) ?? []; + revLines.splice( + lastBackendAddIndex + 1, + 0, + indentation + backendAddLine, + ); + } + const newContent = revLines.reverse().join('\n'); + await fs.writeFile(backendFilePath, newContent, 'utf8'); + } + }); } if (options.owner) { From 4baac0c5a54cdc9ee1bfe1a16fd75743d38855e9 Mon Sep 17 00:00:00 2001 From: Alper Altay Date: Mon, 24 Jun 2024 15:30:13 +0200 Subject: [PATCH 064/416] feat: changeset Signed-off-by: Alper Altay --- .changeset/silent-lobsters-tease.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/silent-lobsters-tease.md diff --git a/.changeset/silent-lobsters-tease.md b/.changeset/silent-lobsters-tease.md new file mode 100644 index 0000000000..e116818b7c --- /dev/null +++ b/.changeset/silent-lobsters-tease.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +The backendPlugin factory now includes a step for automatically adding the new backend plugin to the `index.ts` file of the backend. From e09456b71141085d2f00971bf9d12cecc0bd9a33 Mon Sep 17 00:00:00 2001 From: Alper Altay Date: Mon, 24 Jun 2024 15:32:05 +0200 Subject: [PATCH 065/416] chore: remove "import" Signed-off-by: Alper Altay --- packages/cli/src/lib/new/factories/backendPlugin.test.ts | 2 +- packages/cli/src/lib/new/factories/backendPlugin.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/cli/src/lib/new/factories/backendPlugin.test.ts b/packages/cli/src/lib/new/factories/backendPlugin.test.ts index c6196d8690..98d0fcba21 100644 --- a/packages/cli/src/lib/new/factories/backendPlugin.test.ts +++ b/packages/cli/src/lib/new/factories/backendPlugin.test.ts @@ -98,7 +98,7 @@ describe('backendPlugin factory', () => { 'Installing:', `moving plugins${sep}test-backend`, 'backend adding dependency', - 'backend adding import and plugin', + 'backend adding plugin', ]); await expect( diff --git a/packages/cli/src/lib/new/factories/backendPlugin.ts b/packages/cli/src/lib/new/factories/backendPlugin.ts index 06bc6bd366..39d6af39a2 100644 --- a/packages/cli/src/lib/new/factories/backendPlugin.ts +++ b/packages/cli/src/lib/new/factories/backendPlugin.ts @@ -79,7 +79,7 @@ export const backendPlugin = createFactory({ ); }); - await Task.forItem('backend', 'adding import and plugin', async () => { + await Task.forItem('backend', 'adding plugin', async () => { const backendFilePath = paths.resolveTargetRoot( 'packages/backend/src/index.ts', ); From f6581944cc17da9780c01d36c2c3166212bc67bd Mon Sep 17 00:00:00 2001 From: Alper Altay Date: Mon, 24 Jun 2024 17:23:28 +0200 Subject: [PATCH 066/416] feat: adjust the test Signed-off-by: Alper Altay --- .../lib/new/factories/backendPlugin.test.ts | 29 ++++++++++--------- .../src/lib/new/factories/backendPlugin.ts | 27 ++++++----------- 2 files changed, 24 insertions(+), 32 deletions(-) diff --git a/packages/cli/src/lib/new/factories/backendPlugin.test.ts b/packages/cli/src/lib/new/factories/backendPlugin.test.ts index 98d0fcba21..425e0c5bd5 100644 --- a/packages/cli/src/lib/new/factories/backendPlugin.test.ts +++ b/packages/cli/src/lib/new/factories/backendPlugin.test.ts @@ -27,10 +27,10 @@ import { backendPlugin } from './backendPlugin'; import { createMockDirectory } from '@backstage/backend-test-utils'; const backendIndexTsContent = ` -import { createBackend } from '@backstage/backend-defaults'; - -const backend = createBackend(); - +import { createBackend } from '@backstage/backend-defaults'; + +const backend = createBackend(); + backend.start(); `; @@ -112,11 +112,11 @@ describe('backendPlugin factory', () => { await expect( fs.readFile(mockDir.resolve('packages/backend/src/index.ts'), 'utf8'), ).resolves.toBe(` -import { createBackend } from '@backstage/backend-defaults'; +import { createBackend } from '@backstage/backend-defaults'; -const backend = createBackend(); - -backend.add(import("backstage-plugin-test-backend")); +const backend = createBackend(); + +backend.add(import('backstage-plugin-test-backend')); backend.start(); `); @@ -174,12 +174,13 @@ backend.start(); await expect( fs.readFile(mockDir.resolve('packages/backend/src/index.ts'), 'utf8'), ).resolves.toBe(` -import { createBackend } from '@backstage/backend-defaults'; - -const backend = createBackend(); - -backend.add(import("@internal/backstage-plugin-test-backend")); -backend.start();`); +import { createBackend } from '@backstage/backend-defaults'; + +const backend = createBackend(); + +backend.add(import('@internal/backstage-plugin-test-backend')); +backend.start(); +`); expect(Task.forCommand).toHaveBeenCalledTimes(2); expect(Task.forCommand).toHaveBeenCalledWith('yarn install', { diff --git a/packages/cli/src/lib/new/factories/backendPlugin.ts b/packages/cli/src/lib/new/factories/backendPlugin.ts index 39d6af39a2..5848a72047 100644 --- a/packages/cli/src/lib/new/factories/backendPlugin.ts +++ b/packages/cli/src/lib/new/factories/backendPlugin.ts @@ -86,29 +86,20 @@ export const backendPlugin = createFactory({ if (!(await fs.pathExists(backendFilePath))) { return; } + const content = await fs.readFile(backendFilePath, 'utf8'); - const revLines = content.split('\n').reverse(); + const lines = content.split('\n'); + const backendAddLine = `backend.add(import('${name}'));`; - const lastImportIndex = revLines.findIndex(line => - line.match(/ from ("|').*("|')/), - ); - const lastBackendAddIndex = revLines.findIndex(line => - line.match(/backend.add/), + const backendStartIndex = lines.findIndex(line => + line.match(/backend.start/), ); - const backendAddLine = `backend.add(import("${name}"));`; + if (backendStartIndex !== -1) { + const [indentation] = lines[backendStartIndex].match(/^\s*/) ?? []; + lines.splice(backendStartIndex, 0, indentation + backendAddLine); - if (lastImportIndex !== -1 && lastBackendAddIndex !== -1) { - if (!content.includes(backendAddLine)) { - const [indentation] = - revLines[lastBackendAddIndex + 1].match(/^\s*/) ?? []; - revLines.splice( - lastBackendAddIndex + 1, - 0, - indentation + backendAddLine, - ); - } - const newContent = revLines.reverse().join('\n'); + const newContent = lines.join('\n'); await fs.writeFile(backendFilePath, newContent, 'utf8'); } }); From 23fc071b000e960a82f2e5904434c45952b97d8c Mon Sep 17 00:00:00 2001 From: Alper Altay Date: Mon, 24 Jun 2024 17:31:34 +0200 Subject: [PATCH 067/416] feat: auto add modules to index.ts Signed-off-by: Alper Altay --- .../lib/new/factories/backendModule.test.ts | 23 +++++++++++++++++ .../src/lib/new/factories/backendModule.ts | 25 +++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/packages/cli/src/lib/new/factories/backendModule.test.ts b/packages/cli/src/lib/new/factories/backendModule.test.ts index 78ef5f96bb..2d6a4c9c83 100644 --- a/packages/cli/src/lib/new/factories/backendModule.test.ts +++ b/packages/cli/src/lib/new/factories/backendModule.test.ts @@ -26,6 +26,14 @@ import { import { backendModule } from './backendModule'; import { createMockDirectory } from '@backstage/backend-test-utils'; +const backendIndexTsContent = ` +import { createBackend } from '@backstage/backend-defaults'; + +const backend = createBackend(); + +backend.start(); +`; + describe('backendModule factory', () => { const mockDir = createMockDirectory(); @@ -44,6 +52,9 @@ describe('backendModule factory', () => { packages: { backend: { 'package.json': JSON.stringify({}), + src: { + 'index.ts': backendIndexTsContent, + }, }, }, plugins: {}, @@ -86,8 +97,20 @@ describe('backendModule factory', () => { 'Installing:', `moving plugins${sep}test-backend-module-tester-two`, 'backend adding dependency', + 'backend adding module', ]); + await expect( + fs.readFile(mockDir.resolve('packages/backend/src/index.ts'), 'utf8'), + ).resolves.toBe(` +import { createBackend } from '@backstage/backend-defaults'; + +const backend = createBackend(); + +backend.add(import('backstage-plugin-test-backend-module-tester-two')); +backend.start(); +`); + await expect( fs.readJson(mockDir.resolve('packages/backend/package.json')), ).resolves.toEqual({ diff --git a/packages/cli/src/lib/new/factories/backendModule.ts b/packages/cli/src/lib/new/factories/backendModule.ts index 698146a229..e0c56b34ae 100644 --- a/packages/cli/src/lib/new/factories/backendModule.ts +++ b/packages/cli/src/lib/new/factories/backendModule.ts @@ -91,6 +91,31 @@ export const backendModule = createFactory({ }); } + await Task.forItem('backend', 'adding module', async () => { + const backendFilePath = paths.resolveTargetRoot( + 'packages/backend/src/index.ts', + ); + if (!(await fs.pathExists(backendFilePath))) { + return; + } + + const content = await fs.readFile(backendFilePath, 'utf8'); + const lines = content.split('\n'); + const backendAddLine = `backend.add(import('${name}'));`; + + const backendStartIndex = lines.findIndex(line => + line.match(/backend.start/), + ); + + if (backendStartIndex !== -1) { + const [indentation] = lines[backendStartIndex].match(/^\s*/) ?? []; + lines.splice(backendStartIndex, 0, indentation + backendAddLine); + + const newContent = lines.join('\n'); + await fs.writeFile(backendFilePath, newContent, 'utf8'); + } + }); + if (options.owner) { await addCodeownersEntry(`/plugins/${dirName}`, options.owner); } From 983d616d678e34e836be0cfbe0d7a92cab4eff4a Mon Sep 17 00:00:00 2001 From: Alper Altay Date: Mon, 24 Jun 2024 17:32:39 +0200 Subject: [PATCH 068/416] feat: changeset Signed-off-by: Alper Altay --- .changeset/silent-lobsters-tease.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/silent-lobsters-tease.md b/.changeset/silent-lobsters-tease.md index e116818b7c..61a965236c 100644 --- a/.changeset/silent-lobsters-tease.md +++ b/.changeset/silent-lobsters-tease.md @@ -2,4 +2,4 @@ '@backstage/cli': patch --- -The backendPlugin factory now includes a step for automatically adding the new backend plugin to the `index.ts` file of the backend. +The backendPlugin and backendModule factory now includes a step for automatically adding the new backend plugin/module to the `index.ts` file of the backend. From 812afee13103aa1789b5a10c107950e9f49d4b02 Mon Sep 17 00:00:00 2001 From: Alper Altay Date: Mon, 24 Jun 2024 17:35:14 +0200 Subject: [PATCH 069/416] feat: simplify test Signed-off-by: Alper Altay --- .../lib/new/factories/backendPlugin.test.ts | 66 +------------------ 1 file changed, 3 insertions(+), 63 deletions(-) diff --git a/packages/cli/src/lib/new/factories/backendPlugin.test.ts b/packages/cli/src/lib/new/factories/backendPlugin.test.ts index 425e0c5bd5..f6eeb8cf33 100644 --- a/packages/cli/src/lib/new/factories/backendPlugin.test.ts +++ b/packages/cli/src/lib/new/factories/backendPlugin.test.ts @@ -38,7 +38,9 @@ describe('backendPlugin factory', () => { const mockDir = createMockDirectory(); beforeEach(() => { - mockPaths({ targetRoot: mockDir.path }); + mockPaths({ + targetRoot: mockDir.path, + }); }); afterEach(() => { @@ -118,68 +120,6 @@ const backend = createBackend(); backend.add(import('backstage-plugin-test-backend')); backend.start(); -`); - - expect(Task.forCommand).toHaveBeenCalledTimes(2); - expect(Task.forCommand).toHaveBeenCalledWith('yarn install', { - cwd: mockDir.resolve('plugins/test-backend'), - optional: true, - }); - expect(Task.forCommand).toHaveBeenCalledWith('yarn lint --fix', { - cwd: mockDir.resolve('plugins/test-backend'), - optional: true, - }); - }); - - it('should create a backend plugin with more options and codeowners', async () => { - mockDir.setContent({ - CODEOWNERS: '', - packages: { - backend: { - 'package.json': JSON.stringify({}), - src: { - 'index.ts': backendIndexTsContent, - }, - }, - }, - plugins: {}, - }); - - const options = await FactoryRegistry.populateOptions(backendPlugin, { - id: 'test', - owner: '@test-user', - }); - - const [, mockStream] = createMockOutputStream(); - jest.spyOn(process, 'stderr', 'get').mockReturnValue(mockStream); - jest.spyOn(Task, 'forCommand').mockResolvedValue(); - - await backendPlugin.create(options, { - scope: 'internal', - private: true, - isMonoRepo: true, - defaultVersion: '1.0.0', - markAsModified: () => {}, - createTemporaryDirectory: () => fs.mkdtemp('test'), - }); - - await expect( - fs.readJson(mockDir.resolve('packages/backend/package.json')), - ).resolves.toEqual({ - dependencies: { - '@internal/backstage-plugin-test-backend': '^1.0.0', - }, - }); - - await expect( - fs.readFile(mockDir.resolve('packages/backend/src/index.ts'), 'utf8'), - ).resolves.toBe(` -import { createBackend } from '@backstage/backend-defaults'; - -const backend = createBackend(); - -backend.add(import('@internal/backstage-plugin-test-backend')); -backend.start(); `); expect(Task.forCommand).toHaveBeenCalledTimes(2); From 42227da4acd71ec360c0eb96bbd9aa077d2e83e4 Mon Sep 17 00:00:00 2001 From: Alper Altay Date: Mon, 24 Jun 2024 17:55:48 +0200 Subject: [PATCH 070/416] chore: spelling Signed-off-by: Alper Altay --- .changeset/silent-lobsters-tease.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/silent-lobsters-tease.md b/.changeset/silent-lobsters-tease.md index 61a965236c..2dea26d8ff 100644 --- a/.changeset/silent-lobsters-tease.md +++ b/.changeset/silent-lobsters-tease.md @@ -2,4 +2,4 @@ '@backstage/cli': patch --- -The backendPlugin and backendModule factory now includes a step for automatically adding the new backend plugin/module to the `index.ts` file of the backend. +The `backendPlugin` and `backendModule` factory now includes a step for automatically adding the new backend plugin/module to the `index.ts` file of the backend. From d99fd81a7465dc68b41c9ff102e15c5c126f05ac Mon Sep 17 00:00:00 2001 From: Tavi Nolan Date: Mon, 24 Jun 2024 18:41:08 +0100 Subject: [PATCH 071/416] Adding note detailing functionality re local files and nesting Signed-off-by: Tavi Nolan --- docs/features/software-templates/input-examples.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/features/software-templates/input-examples.md b/docs/features/software-templates/input-examples.md index 32d37ae17c..5769c9976e 100644 --- a/docs/features/software-templates/input-examples.md +++ b/docs/features/software-templates/input-examples.md @@ -241,7 +241,11 @@ spec: ## Use placeholders to reference remote files -#### Note: testing of this functionality is not yet supported using _create/edit_ +:::note + +Testing of this functionality is not yet supported using _create/edit_. In addition, this functionality only works for remote files and not local files. You also cannot nest files. + +::: ### template.yaml From 8fadb84aa406b9a0d75f2bdb68c4d396b9b864c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Edstr=C3=B6m?= Date: Mon, 24 Jun 2024 22:03:10 +0200 Subject: [PATCH 072/416] Modified Select component to take in a testid parameter that sets the data-testid of the material ui Select component, ensuring backwards compatibility with default value corresponding to previously hardcoded parameter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Simon Edström --- packages/core-components/src/components/Select/Select.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/core-components/src/components/Select/Select.tsx b/packages/core-components/src/components/Select/Select.tsx index 924b49f640..5a758e6ca6 100644 --- a/packages/core-components/src/components/Select/Select.tsx +++ b/packages/core-components/src/components/Select/Select.tsx @@ -32,6 +32,7 @@ import React, { useEffect, useState } from 'react'; import ClosedDropdown from './static/ClosedDropdown'; import OpenedDropdown from './static/OpenedDropdown'; +import { string } from 'zod'; /** @public */ export type SelectInputBaseClassKey = 'root' | 'input'; @@ -136,6 +137,7 @@ export type SelectProps = { native?: boolean; disabled?: boolean; margin?: 'dense' | 'none'; + testid?: string; }; /** @public */ @@ -151,6 +153,7 @@ export function SelectComponent(props: SelectProps) { native = false, disabled = false, margin, + testid = 'select', } = props; const classes = useStyles(); const [value, setValue] = useState( @@ -203,7 +206,7 @@ export function SelectComponent(props: SelectProps) { value={value} native={native} disabled={disabled} - data-testid="select" + data-testid={testid} displayEmpty multiple={multiple} margin={margin} From 99d672dee67e9434c21b6544ef1319ed853ac57a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Edstr=C3=B6m?= Date: Mon, 24 Jun 2024 22:19:19 +0200 Subject: [PATCH 073/416] Added changeset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Simon Edström --- .changeset/new-sheep-arrive.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/new-sheep-arrive.md diff --git a/.changeset/new-sheep-arrive.md b/.changeset/new-sheep-arrive.md new file mode 100644 index 0000000000..9ae0af93aa --- /dev/null +++ b/.changeset/new-sheep-arrive.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-components': patch +--- + +Modified the Select component to take in a testid parameter that sets the data-testid of the material ui Select sub-component, ensuring backwards compatibility with default value corresponding to previously hardcoded data-testid of "select". From 73e43d29339a2a331716e921731a582b9f81e7cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Edstr=C3=B6m?= Date: Mon, 24 Jun 2024 22:26:33 +0200 Subject: [PATCH 074/416] Removed accidental import MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Simon Edström --- packages/core-components/src/components/Select/Select.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/core-components/src/components/Select/Select.tsx b/packages/core-components/src/components/Select/Select.tsx index 5a758e6ca6..9c0d4e4dfe 100644 --- a/packages/core-components/src/components/Select/Select.tsx +++ b/packages/core-components/src/components/Select/Select.tsx @@ -32,7 +32,6 @@ import React, { useEffect, useState } from 'react'; import ClosedDropdown from './static/ClosedDropdown'; import OpenedDropdown from './static/OpenedDropdown'; -import { string } from 'zod'; /** @public */ export type SelectInputBaseClassKey = 'root' | 'input'; From dde03ea950b01e65ac922c03738c2dd59b6711c0 Mon Sep 17 00:00:00 2001 From: Jente Sondervorst Date: Mon, 24 Jun 2024 23:39:04 +0200 Subject: [PATCH 075/416] Update api-report.md Signed-off-by: Jente Sondervorst --- plugins/catalog-backend-module-ldap/api-report.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/catalog-backend-module-ldap/api-report.md b/plugins/catalog-backend-module-ldap/api-report.md index 308b2d6da3..2ee3c1ec79 100644 --- a/plugins/catalog-backend-module-ldap/api-report.md +++ b/plugins/catalog-backend-module-ldap/api-report.md @@ -86,7 +86,7 @@ export const LDAP_UUID_ANNOTATION = 'backstage.io/ldap-uuid'; // @public export class LdapClient { - constructor(client: Client, logger: L oggerService); + constructor(client: Client, logger: LoggerService); // (undocumented) static create( logger: LoggerService, From 9112efc364d24f134881e9c09db1323fdfcc4165 Mon Sep 17 00:00:00 2001 From: Patrick Jungermann Date: Sat, 22 Jun 2024 03:02:42 +0200 Subject: [PATCH 076/416] feat(catalog,github): support `repository` events The provider adds a subscription to the topic `github.repository`. Hereby, it supports events of type `repository` with actions - `archived` - `deleted` - `edited` - `renamed` - `transferred` - `unarchived` Actions skipped as they don't require entity changes: - `created` - `privatized` - `publicized` If the config option `validateLocationsExist` is enabled, an API request is necessary and will be executed. This affects the actions `renamed`, `transferred`, and `unarchive` of event type `repository`. Catalog entities related to the `GithubEntityProvider` instance will be adjusted according to action and its meaning for them. Closes: #21906 Signed-off-by: Patrick Jungermann --- .changeset/poor-cheetahs-raise.md | 30 + docs/integrations/github/discovery.md | 15 +- .../src/lib/github.ts | 56 ++ .../providers/GithubEntityProvider.test.ts | 547 +++++++++++++++++- .../src/providers/GithubEntityProvider.ts | 386 ++++++++++-- 5 files changed, 971 insertions(+), 63 deletions(-) create mode 100644 .changeset/poor-cheetahs-raise.md diff --git a/.changeset/poor-cheetahs-raise.md b/.changeset/poor-cheetahs-raise.md new file mode 100644 index 0000000000..0ee2162a22 --- /dev/null +++ b/.changeset/poor-cheetahs-raise.md @@ -0,0 +1,30 @@ +--- +'@backstage/plugin-catalog-backend-module-github': patch +--- + +Adds support for `repository` events. + +The provider adds a subscription to the topic `github.repository`. + +Hereby, it supports events of type `repository` with actions + +- `archived` +- `deleted` +- `edited` +- `renamed` +- `transferred` +- `unarchived` + +Actions skipped as they don't require entity changes: + +- `created` +- `privatized` +- `publicized` + +If the config option `validateLocationsExist` is enabled, an API request +is necessary and will be executed. +This affects the actions `renamed`, `transferred`, and `unarchive` +of event type `repository`. + +Catalog entities related to the `GithubEntityProvider` instance will be adjusted +according to action and its meaning for them. diff --git a/docs/integrations/github/discovery.md b/docs/integrations/github/discovery.md index 5c3a33416b..d8374932b8 100644 --- a/docs/integrations/github/discovery.md +++ b/docs/integrations/github/discovery.md @@ -40,8 +40,9 @@ backend.add(import('@backstage/plugin-catalog-backend-module-github/alpha')); ## Events Support The catalog module for GitHub comes with events support enabled. -This will make it subscribe to its relevant topics (`github.push`) -and expects these events to be published via the `EventsService`. +This will make it subscribe to its relevant topics (`github.push`, +`github.repository`) and expects these events to be published +via the `EventsService`. Additionally, you should install the [event router by `events-backend-module-github`](https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-github/README.md) @@ -55,7 +56,15 @@ You can decide between the following options (extensible): - [via HTTP endpoint](https://github.com/backstage/backstage/tree/master/plugins/events-backend/README.md) - [via an AWS SQS queue](https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-aws-sqs/README.md) -You can check the official docs to [configure your webhook](https://docs.github.com/en/developers/webhooks-and-events/webhooks/creating-webhooks) and to [secure your request](https://docs.github.com/en/developers/webhooks-and-events/webhooks/securing-your-webhooks). The webhook will need to be configured to forward `push` events. +You can check the official docs to [configure your webhook](https://docs.github.com/en/developers/webhooks-and-events/webhooks/creating-webhooks) and to [secure your request](https://docs.github.com/en/developers/webhooks-and-events/webhooks/securing-your-webhooks). + +The webhook(s) will need to be configured to react to `push` and +`repository` events. + +Certain actions like `transferred` by the `repository` event type +will not be supported when you use repository webhooks. +Please check the GitHubs documentation for these event types and +its actions. ## Configuration diff --git a/plugins/catalog-backend-module-github/src/lib/github.ts b/plugins/catalog-backend-module-github/src/lib/github.ts index eff52ea98d..cba65e522e 100644 --- a/plugins/catalog-backend-module-github/src/lib/github.ts +++ b/plugins/catalog-backend-module-github/src/lib/github.ts @@ -38,6 +38,7 @@ export type QueryResponse = { type RepositoryOwnerResponse = { repositories?: Connection; + repository?: RepositoryResponse; }; export type OrganizationResponse = { @@ -509,6 +510,61 @@ export async function getOrganizationRepositories( return { repositories }; } +export async function getOrganizationRepository( + client: typeof graphql, + org: string, + repoName: string, + catalogPath: string, +): Promise { + let relativeCatalogPathRef: string; + // We must strip the leading slash or the query for objects does not work + if (catalogPath.startsWith('/')) { + relativeCatalogPathRef = catalogPath.substring(1); + } else { + relativeCatalogPathRef = catalogPath; + } + const catalogPathRef = `HEAD:${relativeCatalogPathRef}`; + const query = ` + query repository($org: String!, $repoName: String!, $catalogPathRef: String!) { + repositoryOwner(login: $org) { + repository(name: $repoName) { + name + catalogInfoFile: object(expression: $catalogPathRef) { + __typename + ... on Blob { + id + text + } + } + url + isArchived + isFork + visibility + repositoryTopics(first: 100) { + nodes { + ... on RepositoryTopic { + topic { + name + } + } + } + } + defaultBranchRef { + name + } + } + } + }`; + + const response: QueryResponse = await client(query, { + org, + repoName, + catalogPathRef, + }); + + return response.repositoryOwner?.repository || null; +} + /** * Gets all the users out of a Github organization. * diff --git a/plugins/catalog-backend-module-github/src/providers/GithubEntityProvider.test.ts b/plugins/catalog-backend-module-github/src/providers/GithubEntityProvider.test.ts index a28d216053..002b2bbfd1 100644 --- a/plugins/catalog-backend-module-github/src/providers/GithubEntityProvider.test.ts +++ b/plugins/catalog-backend-module-github/src/providers/GithubEntityProvider.test.ts @@ -29,7 +29,12 @@ import { GithubEntityProvider } from './GithubEntityProvider'; import * as helpers from '../lib/github'; import { EventParams } from '@backstage/plugin-events-node'; import { mockServices } from '@backstage/backend-test-utils'; -import { Commit, PushEvent } from '@octokit/webhooks-types'; +import { + Commit, + PushEvent, + RepositoryEvent, + RepositoryRenamedEvent, +} from '@octokit/webhooks-types'; jest.mock('../lib/github', () => { return { @@ -657,7 +662,7 @@ describe('GithubEntityProvider', () => { describe('on event', () => { const createExpectedEntitiesForEvent = ( - event: EventParams, + event: EventParams, options?: { branch?: string; catalogFilePath?: string }, ): DeferredEntity[] => { const url = `${event.eventPayload.repository.url}/blob/${ @@ -948,5 +953,543 @@ describe('GithubEntityProvider', () => { expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(0); }); }); + + describe('on repository event', () => { + const createRepoEvent = ( + action: RepositoryEvent['action'], + ): EventParams => { + const repo = { + name: 'test-repo', + url: 'https://github.com/test-org/test-repo', + default_branch: 'main', + master_branch: 'main', + organization: 'test-org', + topics: [], + archived: action === 'archived', + private: action !== 'publicized', + } as Partial; + + const event = { + action, + repository: repo as RepositoryEvent['repository'], + } as RepositoryEvent; + + if (action === 'renamed') { + (event as RepositoryRenamedEvent).changes = { + repository: { + name: { + from: `old-${event.repository.name}`, + }, + }, + }; + } + + return { + topic: 'github.repository', + metadata: { + 'x-github-event': 'repository', + }, + eventPayload: event, + }; + }; + + describe('on repository archived event', () => { + it('skip on non-matching org', async () => { + const config = createSingleProviderConfig({ + providerConfig: { + organization: 'other-org', + }, + }); + const provider = createProviders(config)[0]; + + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + await provider.connect(entityProviderConnection); + + const event = createRepoEvent('archived'); + + await provider.onEvent(event); + + expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes( + 0, + ); + }); + + it('apply delta update removing entities', async () => { + const config = createSingleProviderConfig(); + const provider = createProviders(config)[0]; + + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + await provider.connect(entityProviderConnection); + + const event = createRepoEvent('archived'); + const expectedEntities = createExpectedEntitiesForEvent(event); + + await provider.onEvent(event); + + expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes( + 1, + ); + expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({ + type: 'delta', + added: [], + removed: expectedEntities, + }); + }); + }); + + describe('on repository created event', () => { + it('skip', async () => { + const config = createSingleProviderConfig(); + const provider = createProviders(config)[0]; + + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + await provider.connect(entityProviderConnection); + + const event = createRepoEvent('created'); + + await provider.onEvent(event); + + expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes( + 0, + ); + }); + }); + + describe('on repository deleted event', () => { + it('skip on non-matching org', async () => { + const config = createSingleProviderConfig({ + providerConfig: { + organization: 'other-org', + }, + }); + const provider = createProviders(config)[0]; + + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + await provider.connect(entityProviderConnection); + + const event = createRepoEvent('deleted'); + + await provider.onEvent(event); + + expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes( + 0, + ); + }); + + it('apply delta update removing entities', async () => { + const config = createSingleProviderConfig(); + const provider = createProviders(config)[0]; + + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + await provider.connect(entityProviderConnection); + + const event = createRepoEvent('deleted'); + const expectedEntities = createExpectedEntitiesForEvent(event); + + await provider.onEvent(event); + + expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes( + 1, + ); + expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({ + type: 'delta', + added: [], + removed: expectedEntities, + }); + }); + }); + + describe('on repository edited event', () => { + it('skip on non-matching org', async () => { + const config = createSingleProviderConfig({ + providerConfig: { + organization: 'other-org', + }, + }); + const provider = createProviders(config)[0]; + + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + await provider.connect(entityProviderConnection); + + const event = createRepoEvent('edited'); + + await provider.onEvent(event); + + expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes( + 0, + ); + }); + + it('apply delta update removing entities with non-matching filters', async () => { + const config = createSingleProviderConfig({ + providerConfig: { + filters: { + topic: { + include: ['backstage-include'], + }, + }, + }, + }); + const provider = createProviders(config)[0]; + + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + await provider.connect(entityProviderConnection); + + const event = createRepoEvent('edited'); + const expectedEntities = createExpectedEntitiesForEvent(event); + + await provider.onEvent(event); + + expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes( + 1, + ); + expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({ + type: 'delta', + added: [], + removed: expectedEntities, + }); + }); + + it('apply no delta update with matching filters', async () => { + const config = createSingleProviderConfig({ + providerConfig: { + filters: { + topic: { + include: ['backstage-include'], + }, + }, + }, + }); + const provider = createProviders(config)[0]; + + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + await provider.connect(entityProviderConnection); + + const event = createRepoEvent('edited'); + event.eventPayload.repository.topics = ['backstage-include']; + + await provider.onEvent(event); + + expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes( + 0, + ); + }); + }); + + describe('on repository privatized event', () => { + it('skip', async () => { + const config = createSingleProviderConfig(); + const provider = createProviders(config)[0]; + + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + await provider.connect(entityProviderConnection); + + const event = createRepoEvent('privatized'); + + await provider.onEvent(event); + + expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes( + 0, + ); + }); + }); + + describe('on repository publicized event', () => { + it('skip', async () => { + const config = createSingleProviderConfig(); + const provider = createProviders(config)[0]; + + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + await provider.connect(entityProviderConnection); + + const event = createRepoEvent('publicized'); + + await provider.onEvent(event); + + expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes( + 0, + ); + }); + }); + + describe('on repository renamed event', () => { + it('skip on non-matching org', async () => { + const config = createSingleProviderConfig({ + providerConfig: { + organization: 'other-org', + }, + }); + const provider = createProviders(config)[0]; + + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + await provider.connect(entityProviderConnection); + + const event = createRepoEvent('renamed'); + + await provider.onEvent(event); + + expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes( + 0, + ); + }); + + it('apply delta update removing entities with non-matching filters', async () => { + const config = createSingleProviderConfig({ + providerConfig: { + filters: { + repository: 'other-.*', + }, + }, + }); + const provider = createProviders(config)[0]; + + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + await provider.connect(entityProviderConnection); + + const event = createRepoEvent( + 'renamed', + ) as EventParams; + const urlOldRepo = `https://github.com/${event.eventPayload.repository.organization}/${event.eventPayload.changes.repository.name.from}/blob/main/catalog-info.yaml`; + const expectedEntitiesRemoved = + createExpectedEntitiesForUrl(urlOldRepo); + + await provider.onEvent(event); + + expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes( + 1, + ); + expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({ + type: 'delta', + added: [], + removed: expectedEntitiesRemoved, + }); + }); + + it('apply delta update removing and adding entities with matching filters', async () => { + const config = createSingleProviderConfig(); + const provider = createProviders(config)[0]; + + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + await provider.connect(entityProviderConnection); + + const event = createRepoEvent( + 'renamed', + ) as EventParams; + const urlOldRepo = `https://github.com/${event.eventPayload.repository.organization}/${event.eventPayload.changes.repository.name.from}/blob/main/catalog-info.yaml`; + const expectedEntitiesRemoved = + createExpectedEntitiesForUrl(urlOldRepo); + const expectedEntitiesAdded = createExpectedEntitiesForEvent(event); + + await provider.onEvent(event); + + expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes( + 2, + ); + expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({ + type: 'delta', + added: [], + removed: expectedEntitiesRemoved, + }); + expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({ + type: 'delta', + added: expectedEntitiesAdded, + removed: [], + }); + }); + }); + + describe('on repository transferred event', () => { + it('skip on non-matching org', async () => { + const config = createSingleProviderConfig({ + providerConfig: { + organization: 'other-org', + }, + }); + const provider = createProviders(config)[0]; + + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + await provider.connect(entityProviderConnection); + + const event = createRepoEvent('transferred'); + + await provider.onEvent(event); + + expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes( + 0, + ); + }); + + it('apply no delta update with non-matching filters', async () => { + const config = createSingleProviderConfig({ + providerConfig: { + filters: { + topic: { + include: ['backstage-include'], + }, + }, + }, + }); + const provider = createProviders(config)[0]; + + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + await provider.connect(entityProviderConnection); + + const event = createRepoEvent('transferred'); + + await provider.onEvent(event); + + expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes( + 0, + ); + }); + + it('apply delta update adding entities with matching filters', async () => { + const config = createSingleProviderConfig(); + const provider = createProviders(config)[0]; + + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + await provider.connect(entityProviderConnection); + + const event = createRepoEvent('transferred'); + const expectedEntitiesAdded = createExpectedEntitiesForEvent(event); + + await provider.onEvent(event); + + expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes( + 1, + ); + expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({ + type: 'delta', + added: expectedEntitiesAdded, + removed: [], + }); + }); + }); + + describe('on repository unarchived event', () => { + it('skip on non-matching org', async () => { + const config = createSingleProviderConfig({ + providerConfig: { + organization: 'other-org', + }, + }); + const provider = createProviders(config)[0]; + + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + await provider.connect(entityProviderConnection); + + const event = createRepoEvent('unarchived'); + + await provider.onEvent(event); + + expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes( + 0, + ); + }); + + it('apply no delta update with non-matching filters', async () => { + const config = createSingleProviderConfig({ + providerConfig: { + filters: { + topic: { + include: ['backstage-include'], + }, + }, + }, + }); + const provider = createProviders(config)[0]; + + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + await provider.connect(entityProviderConnection); + + const event = createRepoEvent('unarchived'); + + await provider.onEvent(event); + + expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes( + 0, + ); + }); + + it('apply delta update adding entities with matching filters', async () => { + const config = createSingleProviderConfig(); + const provider = createProviders(config)[0]; + + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + await provider.connect(entityProviderConnection); + + const event = createRepoEvent('unarchived'); + const expectedEntitiesAdded = createExpectedEntitiesForEvent(event); + + await provider.onEvent(event); + + expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes( + 1, + ); + expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({ + type: 'delta', + added: expectedEntitiesAdded, + removed: [], + }); + }); + }); + }); }); }); diff --git a/plugins/catalog-backend-module-github/src/providers/GithubEntityProvider.ts b/plugins/catalog-backend-module-github/src/providers/GithubEntityProvider.ts index 978d9593c1..daade9660a 100644 --- a/plugins/catalog-backend-module-github/src/providers/GithubEntityProvider.ts +++ b/plugins/catalog-backend-module-github/src/providers/GithubEntityProvider.ts @@ -38,7 +38,11 @@ import { GithubEntityProviderConfig, readProviderConfigs, } from './GithubEntityProviderConfig'; -import { getOrganizationRepositories } from '../lib/github'; +import { + getOrganizationRepositories, + getOrganizationRepository, + RepositoryResponse, +} from '../lib/github'; import { satisfiesForkFilter, satisfiesTopicFilter, @@ -50,11 +54,21 @@ import { EventsService, EventSubscriber, } from '@backstage/plugin-events-node'; -import { Commit, PushEvent } from '@octokit/webhooks-types'; +import { + Commit, + PushEvent, + RepositoryArchivedEvent, + RepositoryDeletedEvent, + RepositoryEditedEvent, + RepositoryEvent, + RepositoryRenamedEvent, + RepositoryTransferredEvent, + RepositoryUnarchivedEvent, +} from '@octokit/webhooks-types'; import { Minimatch } from 'minimatch'; import { LoggerService } from '@backstage/backend-plugin-api'; -const TOPIC_REPO_PUSH = 'github.push'; +const EVENT_TOPICS = ['github.push', 'github.repository']; type Repository = { name: string; @@ -157,7 +171,7 @@ export class GithubEntityProvider implements EntityProvider, EventSubscriber { this.connection = connection; await this.events?.subscribe({ id: this.getProviderName(), - topics: [TOPIC_REPO_PUSH], + topics: EVENT_TOPICS, onEvent: params => this.onEvent(params), }); return await this.scheduleFn(); @@ -194,15 +208,7 @@ export class GithubEntityProvider implements EntityProvider, EventSubscriber { const targets = await this.findCatalogFiles(); const matchingTargets = this.matchesFilters(targets); - const entities = matchingTargets - .map(repository => this.createLocationUrl(repository)) - .map(GithubEntityProvider.toLocationSpec) - .map(location => { - return { - locationKey: this.getProviderName(), - entity: locationSpecToLocationEntity({ location }), - }; - }); + const entities = this.toDeferredEntitiesFromRepos(matchingTargets); await this.connection.applyMutation({ type: 'full', @@ -214,38 +220,32 @@ export class GithubEntityProvider implements EntityProvider, EventSubscriber { ); } - // go to the server and get all of the repositories - private async findCatalogFiles(): Promise { + private async createGraphqlClient() { const organization = this.config.organization; const host = this.integration.host; - const catalogPath = this.config.catalogPath; const orgUrl = `https://${host}/${organization}`; const { headers } = await this.githubCredentialsProvider.getCredentials({ url: orgUrl, }); - const client = graphql.defaults({ + return graphql.defaults({ baseUrl: this.integration.apiBaseUrl, headers, }); + } + + // go to the server and get all repositories + private async findCatalogFiles(): Promise { + const organization = this.config.organization; + const catalogPath = this.config.catalogPath; + const client = await this.createGraphqlClient(); const { repositories: repositoriesFromGithub } = await getOrganizationRepositories(client, organization, catalogPath); - const repositories = repositoriesFromGithub.map(r => { - return { - url: r.url, - name: r.name, - defaultBranchRef: r.defaultBranchRef?.name, - repositoryTopics: r.repositoryTopics.nodes.map(t => t.topic.name), - isArchived: r.isArchived, - isFork: r.isFork, - isCatalogInfoFilePresent: - r.catalogInfoFile?.__typename === 'Blob' && - r.catalogInfoFile.text !== '', - visibility: r.visibility, - }; - }); + const repositories = repositoriesFromGithub.map( + this.createRepoFromGithubResponse, + ); if (this.config.validateLocationsExist) { return repositories.filter( @@ -256,13 +256,13 @@ export class GithubEntityProvider implements EntityProvider, EventSubscriber { return repositories; } - private matchesFilters(repositories: Repository[]) { + private matchesFilters(repositories: Repository[]): Repository[] { const repositoryFilter = this.config.filters?.repository; const topicFilters = this.config.filters?.topic; const allowForks = this.config.filters?.allowForks ?? true; const visibilities = this.config.filters?.visibility ?? []; - const matchingRepositories = repositories.filter(r => { + return repositories.filter(r => { const repoTopics: string[] = r.repositoryTopics; return ( !r.isArchived && @@ -273,7 +273,6 @@ export class GithubEntityProvider implements EntityProvider, EventSubscriber { r.defaultBranchRef ); }); - return matchingRepositories; } private createLocationUrl(repository: Repository): string { @@ -296,23 +295,34 @@ export class GithubEntityProvider implements EntityProvider, EventSubscriber { /** {@inheritdoc @backstage/plugin-events-node#EventSubscriber.onEvent} */ async onEvent(params: EventParams): Promise { this.logger.debug(`Received event from ${params.topic}`); - if (params.topic !== TOPIC_REPO_PUSH) { - return; - } + if (EVENT_TOPICS.some(topic => topic === params.topic)) { + if (!this.connection) { + throw new Error('Not initialized'); + } - await this.onRepoPush(params.eventPayload as PushEvent); + switch (params.topic) { + case 'github.push': + await this.onPush(params.eventPayload as PushEvent); + return; + + case 'github.repository': + await this.onRepoChange(params.eventPayload as RepositoryEvent); + return; + + default: // should never be reached + this.logger.warn( + `Missing implementation for event of topic ${params.topic}`, + ); + } + } } /** {@inheritdoc @backstage/plugin-events-node#EventSubscriber.supportsEventTopics} */ supportsEventTopics(): string[] { - return [TOPIC_REPO_PUSH]; + return EVENT_TOPICS; } - private async onRepoPush(event: PushEvent) { - if (!this.connection) { - throw new Error('Not initialized'); - } - + private async onPush(event: PushEvent) { if (this.config.organization !== event.repository.organization) { this.logger.debug( `skipping push event from organization ${event.repository.organization}`, @@ -332,18 +342,7 @@ export class GithubEntityProvider implements EntityProvider, EventSubscriber { return; } - const repository: Repository = { - url: event.repository.url, - name: event.repository.name, - defaultBranchRef: event.repository.default_branch, - repositoryTopics: event.repository.topics, - isArchived: event.repository.archived, - isFork: event.repository.fork, - // we can consider this file present because - // only the catalog file will be recovered from the commits - isCatalogInfoFilePresent: true, - visibility: event.repository.visibility, - }; + const repository = this.createRepoFromEvent(event); const matchingTargets = this.matchesFilters([repository]); if (matchingTargets.length === 0) { @@ -378,7 +377,7 @@ export class GithubEntityProvider implements EntityProvider, EventSubscriber { ? this.config.catalogPath.substring(1) : this.config.catalogPath; - await this.connection.refresh({ + await this.connection!.refresh({ keys: [ ...new Set([ ...modified.map( @@ -396,7 +395,7 @@ export class GithubEntityProvider implements EntityProvider, EventSubscriber { } if (added.length > 0 || removed.length > 0) { - await this.connection.applyMutation({ + await this.connection!.applyMutation({ type: 'delta', added: added, removed: removed, @@ -408,6 +407,263 @@ export class GithubEntityProvider implements EntityProvider, EventSubscriber { ); } + private async onRepoChange(event: RepositoryEvent) { + if (this.config.organization !== event.repository.organization) { + this.logger.debug( + `skipping repository event from organization ${event.repository.organization}`, + ); + return; + } + + const action = event.action; + switch (action) { + case 'archived': + await this.onRepoArchived(event as RepositoryArchivedEvent); + return; + + // A repository was created. + case 'created': + // skip these events + return; + + case 'deleted': + await this.onRepoDeleted(event as RepositoryDeletedEvent); + return; + + case 'edited': + await this.onRepoEdited(event as RepositoryEditedEvent); + return; + + // The visibility of a repository was changed to `private`. + case 'privatized': + // skip these events + return; + + // The visibility of a repository was changed to `public`. + case 'publicized': + // skip these events + return; + + case 'renamed': + await this.onRepoRenamed(event as RepositoryRenamedEvent); + return; + + case 'transferred': + await this.onRepoTransferred(event as RepositoryTransferredEvent); + return; + + case 'unarchived': + await this.onRepoUnarchived(event as RepositoryUnarchivedEvent); + return; + + default: // should never be reached + this.logger.warn( + `Missing implementation for event of topic repository with action ${action}`, + ); + } + } + + /** + * A repository was archived. + * + * Removes all entities associated with the repository. + * + * @param event - The repository archived event. + * @private + */ + private async onRepoArchived(event: RepositoryArchivedEvent) { + const repository = this.createRepoFromEvent(event); + await this.removeEntitiesForRepo(repository); + this.logger.debug( + `Removed entities for archived repository ${repository.name}`, + ); + } + + /** + * A repository was deleted. + * + * Removes all entities associated with the repository. + * + * @param event - The repository deleted event. + * @private + */ + private async onRepoDeleted(event: RepositoryDeletedEvent) { + const repository = this.createRepoFromEvent(event); + await this.removeEntitiesForRepo(repository); + this.logger.debug( + `Removed entities for deleted repository ${repository.name}`, + ); + } + + /** + * The topics, default branch, description, or homepage of a repository was changed. + * + * We are interested in potential topic changes as these can be used as part of the filters. + * + * Removes all entities associated with the repository if the repository no longer matches the filters. + * + * @param event - The repository edited event. + * @private + */ + private async onRepoEdited(event: RepositoryEditedEvent) { + const repository = this.createRepoFromEvent(event); + + const matchingTargets = this.matchesFilters([repository]); + if (matchingTargets.length === 0) { + await this.removeEntitiesForRepo(repository); + } + // else: repository is (still) matching the filters, so we don't need to do anything + } + + /** + * The name of a repository was changed. + * + * Removes all entities associated with the repository's old name. + * Creates new entities for the repository's new name if it still matches the filters. + * + * @param event - The repository renamed event. + * @private + */ + private async onRepoRenamed(event: RepositoryRenamedEvent) { + const repository = this.createRepoFromEvent(event); + const oldRepoName = event.changes.repository.name.from; + const urlParts = event.repository.url.split('/'); + urlParts[urlParts.length - 1] = oldRepoName; + const oldRepoUrl = urlParts.join('/'); + const oldRepository: Repository = { + ...repository, + name: oldRepoName, + url: oldRepoUrl, + }; + await this.removeEntitiesForRepo(oldRepository); + + const matchingTargets = this.matchesFilters([repository]); + if (matchingTargets.length === 0) { + this.logger.debug( + `skipping repository transferred event for repository ${repository.name} because it didn't match provider filters`, + ); + return; + } + + await this.addEntitiesForRepo(repository); + } + + /** + * Ownership of the repository was transferred to a user or organization account. + * This event is only sent to the account where the ownership is transferred. + * To receive the `repository.transferred` event, the new owner account must have the GitHub App installed, + * and the App must be subscribed to "Repository" events. + * + * Creates new entities for the repository if it matches the filters. + * + * @param event - The repository unarchived event. + * @private + */ + private async onRepoTransferred(event: RepositoryTransferredEvent) { + const repository = this.createRepoFromEvent(event); + + const matchingTargets = this.matchesFilters([repository]); + if (matchingTargets.length === 0) { + this.logger.debug( + `skipping repository transferred event for repository ${repository.name} because it didn't match provider filters`, + ); + return; + } + + await this.addEntitiesForRepo(repository); + } + + /** + * A previously archived repository was unarchived. + * + * Creates new entities for the repository if it matches the filters. + * + * @param event - The repository unarchived event. + * @private + */ + private async onRepoUnarchived(event: RepositoryUnarchivedEvent) { + const repository = this.createRepoFromEvent(event); + + const matchingTargets = this.matchesFilters([repository]); + if (matchingTargets.length === 0) { + this.logger.debug( + `skipping repository transferred event for repository ${repository.name} because it didn't match provider filters`, + ); + return; + } + + await this.addEntitiesForRepo(repository); + } + + private async removeEntitiesForRepo(repository: Repository) { + const removed = this.toDeferredEntitiesFromRepos([repository]); + await this.connection!.applyMutation({ + type: 'delta', + added: [], + removed: removed, + }); + } + + private async addEntitiesForRepo(repository: Repository) { + if (this.config.validateLocationsExist) { + const organization = this.config.organization; + const catalogPath = this.config.catalogPath; + const client = await this.createGraphqlClient(); + + const repositoryFromGithub = await getOrganizationRepository( + client, + organization, + repository.name, + catalogPath, + ).then(r => (r ? this.createRepoFromGithubResponse(r) : null)); + + if (!repositoryFromGithub?.isCatalogInfoFilePresent) { + return; + } + } + + const added = this.toDeferredEntitiesFromRepos([repository]); + await this.connection!.applyMutation({ + type: 'delta', + added: added, + removed: [], + }); + } + + private createRepoFromEvent(event: RepositoryEvent | PushEvent): Repository { + return { + url: event.repository.url, + name: event.repository.name, + defaultBranchRef: event.repository.default_branch, + repositoryTopics: event.repository.topics, + isArchived: event.repository.archived, + isFork: event.repository.fork, + // we can consider this file present because + // only the catalog file will be recovered from the commits + isCatalogInfoFilePresent: true, + visibility: event.repository.visibility, + }; + } + + private createRepoFromGithubResponse( + repositoryResponse: RepositoryResponse, + ): Repository { + return { + url: repositoryResponse.url, + name: repositoryResponse.name, + defaultBranchRef: repositoryResponse.defaultBranchRef?.name, + repositoryTopics: repositoryResponse.repositoryTopics.nodes.map( + t => t.topic.name, + ), + isArchived: repositoryResponse.isArchived, + isFork: repositoryResponse.isFork, + isCatalogInfoFilePresent: + repositoryResponse.catalogInfoFile?.__typename === 'Blob' && + repositoryResponse.catalogInfoFile.text !== '', + visibility: repositoryResponse.visibility, + }; + } + private collectDeferredEntitiesFromCommit( repositoryUrl: string, branch: string, @@ -454,6 +710,20 @@ export class GithubEntityProvider implements EntityProvider, EventSubscriber { }; }); } + + private toDeferredEntitiesFromRepos( + repositories: Repository[], + ): DeferredEntity[] { + return repositories + .map(repository => this.createLocationUrl(repository)) + .map(GithubEntityProvider.toLocationSpec) + .map(location => { + return { + locationKey: this.getProviderName(), + entity: locationSpecToLocationEntity({ location }), + }; + }); + } } /* From 70df2be217b7c26e23d5d7221d39182c145ee8de Mon Sep 17 00:00:00 2001 From: Jente Sondervorst Date: Tue, 25 Jun 2024 08:24:29 +0200 Subject: [PATCH 077/416] adapt test Closes: #25256 Signed-off-by: Jente Sondervorst --- .../src/ldap/config.test.ts | 64 ++++++++++--------- 1 file changed, 34 insertions(+), 30 deletions(-) diff --git a/plugins/catalog-backend-module-ldap/src/ldap/config.test.ts b/plugins/catalog-backend-module-ldap/src/ldap/config.test.ts index 9c9165580a..598bcc8839 100644 --- a/plugins/catalog-backend-module-ldap/src/ldap/config.test.ts +++ b/plugins/catalog-backend-module-ldap/src/ldap/config.test.ts @@ -115,38 +115,42 @@ describe('readLdapConfig', () => { frequency: { minutes: 3 }, timeout: { minutes: 1 }, }, - users: { - dn: 'udn', - options: { - scope: 'one', - attributes: ['*', '+'], + users: [ + { + dn: 'udn', + options: { + scope: 'one', + attributes: ['*', '+'], + }, + set: undefined, + map: { + rdn: 'uid', + name: 'uid', + displayName: 'cn', + email: 'mail', + memberOf: 'memberOf', + }, }, - set: undefined, - map: { - rdn: 'uid', - name: 'uid', - displayName: 'cn', - email: 'mail', - memberOf: 'memberOf', + ], + groups: [ + { + dn: 'gdn', + options: { + scope: 'one', + attributes: ['*', '+'], + }, + set: undefined, + map: { + rdn: 'cn', + name: 'cn', + description: 'description', + type: 'groupType', + displayName: 'cn', + memberOf: 'memberOf', + members: 'member', + }, }, - }, - groups: { - dn: 'gdn', - options: { - scope: 'one', - attributes: ['*', '+'], - }, - set: undefined, - map: { - rdn: 'cn', - name: 'cn', - description: 'description', - type: 'groupType', - displayName: 'cn', - memberOf: 'memberOf', - members: 'member', - }, - }, + ], }, ]; expect(actual).toEqual(expected); From 5132d28818568a0c45132f9f49b49cba138a6b08 Mon Sep 17 00:00:00 2001 From: Beth Griggs Date: Fri, 21 Jun 2024 18:35:30 +0100 Subject: [PATCH 078/416] fix(plugin-org): implement batching in useGetEntities to handle large headers The useGetEntities hook can result in requests to /api/catalog/entities where the headers exceed the default maximum Node.js header size of 16KB. This commit implements batching in the useGetEntities hook to handle cases where this is likely to occur. Refs: https://github.com/backstage/backstage/issues/22139 Signed-off-by: Beth Griggs --- .changeset/fast-pens-smell.md | 5 + .../OwnershipCard/useGetEntities.test.ts | 104 ++++++++++++++++++ .../Cards/OwnershipCard/useGetEntities.ts | 50 +++++---- 3 files changed, 140 insertions(+), 19 deletions(-) create mode 100644 .changeset/fast-pens-smell.md diff --git a/.changeset/fast-pens-smell.md b/.changeset/fast-pens-smell.md new file mode 100644 index 0000000000..6d909a397c --- /dev/null +++ b/.changeset/fast-pens-smell.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-org': patch +--- + +The `useGetEntities` hook could result in requests to `/api/catalog/entities` where the headers exceed the default maximum Node.js header size of 16KB. The hook logic has been adjusted to batch the requests. diff --git a/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.test.ts b/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.test.ts index eac5a171ba..2c223c3f4f 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.test.ts +++ b/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.test.ts @@ -231,6 +231,110 @@ describe('useGetEntities', () => { ); }); }); + + describe('useGetEntities with 500+ relations', () => { + const manyGroups = Array.from({ length: 555 }, (_, i) => + createGroupEntityFromName(`group${i + 1}`), + ); + + const givenUserWithManyGroups = { + kind: 'User', + metadata: { + name: givenUser, + }, + spec: { + memberOf: manyGroups.map( + group => `group:default/${group.metadata.name}`, + ), + }, + } as Partial as Entity; + + beforeEach(() => { + getEntityRelationsMock.mockImplementation(entity => + entity?.kind === 'User' + ? manyGroups.map(group => createGroupRefFromName(group.metadata.name)) + : [], + ); + (catalogApiMock.getEntities as jest.Mock).mockClear(); + }); + + it('should handle 500+ relations without exceeding URL length limits', async () => { + const { result } = renderHook( + ({ entity }) => useGetEntities(entity, 'aggregated'), + { + initialProps: { entity: givenUserWithManyGroups }, + }, + ); + + await waitFor(() => expect(result.current.loading).toBe(false)); + + const callArgs = (catalogApiMock.getEntities as jest.Mock).mock + .calls[0][0]; + + expect( + callArgs.filter[0]['relations.ownedBy'].length, + ).toBeLessThanOrEqual(100); + + const owners = callArgs.filter[0]['relations.ownedBy']; + + expect(Array.isArray(owners)).toBeTruthy(); + expect(owners.length).toBeLessThanOrEqual(100); + }); + }); + + describe('useGetEntities exceeding default 16384 bytes header size', () => { + const largeNumberOfGroups = Array.from({ length: 600 }, (_, i) => + createGroupEntityFromName(`very-long-group-name-${i + 1}`), + ); + + const givenUserWithLargeNumberOfGroups = { + kind: 'User', + metadata: { + name: givenUser, + }, + spec: { + memberOf: largeNumberOfGroups.map( + group => `group:default/${group.metadata.name}`, + ), + }, + } as Partial as Entity; + + beforeEach(() => { + getEntityRelationsMock.mockImplementation(entity => + entity?.kind === 'User' + ? largeNumberOfGroups.map(group => + createGroupRefFromName(group.metadata.name), + ) + : [], + ); + (catalogApiMock.getEntities as jest.Mock).mockClear(); + }); + + it('should batch the request to avoid exceeding header size limits', async () => { + const { result } = renderHook( + ({ entity }) => useGetEntities(entity, 'aggregated'), + { + initialProps: { entity: givenUserWithLargeNumberOfGroups }, + }, + ); + + await waitFor(() => expect(result.current.loading).toBe(false)); + const callArgs = (catalogApiMock.getEntities as jest.Mock).mock + .calls[0][0]; + + const url = new URL( + `http://localhost/api/catalog/entities?${new URLSearchParams( + callArgs as any, + )}`, + ); + const headerSize = url.href.length; + expect(headerSize).toBeLessThanOrEqual(16384); + + const owners = callArgs.filter[0]['relations.ownedBy']; + expect(Array.isArray(owners)).toBeTruthy(); + expect(owners.length).toBeLessThanOrEqual(100); + }); + }); }); function createGroupEntityFromName(name: string): Entity { diff --git a/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.ts b/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.ts index 5a708bcfee..d919e1d7c5 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.ts +++ b/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.ts @@ -143,26 +143,38 @@ const getOwners = async ( return [stringifyEntityRef(entity)]; }; -const getOwnedEntitiesByOwners = ( +const batchGetOwnedEntitiesByOwners = async ( owners: string[], kinds: string[], catalogApi: CatalogApi, -) => - catalogApi.getEntities({ - filter: [ - { - kind: kinds, - 'relations.ownedBy': owners, - }, - ], - fields: [ - 'kind', - 'metadata.name', - 'metadata.namespace', - 'spec.type', - 'relations', - ], - }); + batchSize: number = 100, +) => { + const batches = []; + + for (let i = 0; i < owners.length; i += batchSize) { + const batch = owners.slice(i, i + batchSize); + batches.push( + catalogApi.getEntities({ + filter: [ + { + kind: kinds, + 'relations.ownedBy': batch, + }, + ], + fields: [ + 'kind', + 'metadata.name', + 'metadata.namespace', + 'spec.type', + 'relations', + ], + }), + ); + } + + const results = await Promise.all(batches); + return results.flatMap(result => result.items); +}; export function useGetEntities( entity: Entity, @@ -191,13 +203,13 @@ export function useGetEntities( } = useAsync(async () => { const owners = await getOwners(entity, relations, catalogApi); - const ownedEntitiesList = await getOwnedEntitiesByOwners( + const ownedEntitiesList = await batchGetOwnedEntitiesByOwners( owners, kinds, catalogApi, ); - const counts = ownedEntitiesList.items.reduce( + const counts = ownedEntitiesList.reduce( (acc: EntityTypeProps[], ownedEntity) => { const match = acc.find( x => x.kind === ownedEntity.kind && x.type === ownedEntity.spec?.type, From a936761afefd680e87b8f04b3e96764ffdd0bb4a Mon Sep 17 00:00:00 2001 From: Alper Altay <43654387+alper98@users.noreply.github.com> Date: Tue, 25 Jun 2024 12:26:51 +0200 Subject: [PATCH 079/416] Update packages/cli/src/lib/new/factories/backendPlugin.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Fredrik Adelöw Signed-off-by: Alper Altay <43654387+alper98@users.noreply.github.com> --- packages/cli/src/lib/new/factories/backendPlugin.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli/src/lib/new/factories/backendPlugin.ts b/packages/cli/src/lib/new/factories/backendPlugin.ts index 5848a72047..e1bfac5eb8 100644 --- a/packages/cli/src/lib/new/factories/backendPlugin.ts +++ b/packages/cli/src/lib/new/factories/backendPlugin.ts @@ -97,7 +97,7 @@ export const backendPlugin = createFactory({ if (backendStartIndex !== -1) { const [indentation] = lines[backendStartIndex].match(/^\s*/) ?? []; - lines.splice(backendStartIndex, 0, indentation + backendAddLine); + lines.splice(backendStartIndex, 0, `${indentation}${backendAddLine}`); const newContent = lines.join('\n'); await fs.writeFile(backendFilePath, newContent, 'utf8'); From 1e88954016fb4e27cdd32b86b2918077cac2d20c Mon Sep 17 00:00:00 2001 From: Alper Altay <43654387+alper98@users.noreply.github.com> Date: Tue, 25 Jun 2024 12:27:10 +0200 Subject: [PATCH 080/416] Update packages/cli/src/lib/new/factories/backendPlugin.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Fredrik Adelöw Signed-off-by: Alper Altay <43654387+alper98@users.noreply.github.com> --- packages/cli/src/lib/new/factories/backendPlugin.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli/src/lib/new/factories/backendPlugin.ts b/packages/cli/src/lib/new/factories/backendPlugin.ts index e1bfac5eb8..c5cd043132 100644 --- a/packages/cli/src/lib/new/factories/backendPlugin.ts +++ b/packages/cli/src/lib/new/factories/backendPlugin.ts @@ -96,7 +96,7 @@ export const backendPlugin = createFactory({ ); if (backendStartIndex !== -1) { - const [indentation] = lines[backendStartIndex].match(/^\s*/) ?? []; + const [indentation] = lines[backendStartIndex].match(/^\s*/)!; lines.splice(backendStartIndex, 0, `${indentation}${backendAddLine}`); const newContent = lines.join('\n'); From e053c105f4a27fa29b76aea11a2a209c38664f49 Mon Sep 17 00:00:00 2001 From: Alper Altay Date: Tue, 25 Jun 2024 12:38:10 +0200 Subject: [PATCH 081/416] chore: breaking out into function Signed-off-by: Alper Altay --- .../src/lib/new/factories/backendModule.ts | 28 +++------------- .../src/lib/new/factories/backendPlugin.ts | 28 +++------------- packages/cli/src/lib/tasks.ts | 32 +++++++++++++++++++ 3 files changed, 40 insertions(+), 48 deletions(-) diff --git a/packages/cli/src/lib/new/factories/backendModule.ts b/packages/cli/src/lib/new/factories/backendModule.ts index e0c56b34ae..8cfa7f1e00 100644 --- a/packages/cli/src/lib/new/factories/backendModule.ts +++ b/packages/cli/src/lib/new/factories/backendModule.ts @@ -20,7 +20,7 @@ import camelCase from 'lodash/camelCase'; import { paths } from '../../paths'; import { addCodeownersEntry, getCodeownersFilePath } from '../../codeowners'; import { CreateContext, createFactory } from '../types'; -import { addPackageDependency, Task } from '../../tasks'; +import { addPackageDependency, addToBackend, Task } from '../../tasks'; import { moduleIdIdPrompt, ownerPrompt, @@ -91,29 +91,9 @@ export const backendModule = createFactory({ }); } - await Task.forItem('backend', 'adding module', async () => { - const backendFilePath = paths.resolveTargetRoot( - 'packages/backend/src/index.ts', - ); - if (!(await fs.pathExists(backendFilePath))) { - return; - } - - const content = await fs.readFile(backendFilePath, 'utf8'); - const lines = content.split('\n'); - const backendAddLine = `backend.add(import('${name}'));`; - - const backendStartIndex = lines.findIndex(line => - line.match(/backend.start/), - ); - - if (backendStartIndex !== -1) { - const [indentation] = lines[backendStartIndex].match(/^\s*/) ?? []; - lines.splice(backendStartIndex, 0, indentation + backendAddLine); - - const newContent = lines.join('\n'); - await fs.writeFile(backendFilePath, newContent, 'utf8'); - } + await addToBackend(name, { + defaultVersion: ctx.defaultVersion, + type: 'module', }); if (options.owner) { diff --git a/packages/cli/src/lib/new/factories/backendPlugin.ts b/packages/cli/src/lib/new/factories/backendPlugin.ts index c5cd043132..d7bf33b033 100644 --- a/packages/cli/src/lib/new/factories/backendPlugin.ts +++ b/packages/cli/src/lib/new/factories/backendPlugin.ts @@ -20,7 +20,7 @@ import camelCase from 'lodash/camelCase'; import { paths } from '../../paths'; import { addCodeownersEntry, getCodeownersFilePath } from '../../codeowners'; import { CreateContext, createFactory } from '../types'; -import { addPackageDependency, Task } from '../../tasks'; +import { addPackageDependency, addToBackend, Task } from '../../tasks'; import { ownerPrompt, pluginIdPrompt } from './common/prompts'; import { executePluginPackageTemplate } from './common/tasks'; import { resolvePackageName } from './common/util'; @@ -79,29 +79,9 @@ export const backendPlugin = createFactory({ ); }); - await Task.forItem('backend', 'adding plugin', async () => { - const backendFilePath = paths.resolveTargetRoot( - 'packages/backend/src/index.ts', - ); - if (!(await fs.pathExists(backendFilePath))) { - return; - } - - const content = await fs.readFile(backendFilePath, 'utf8'); - const lines = content.split('\n'); - const backendAddLine = `backend.add(import('${name}'));`; - - const backendStartIndex = lines.findIndex(line => - line.match(/backend.start/), - ); - - if (backendStartIndex !== -1) { - const [indentation] = lines[backendStartIndex].match(/^\s*/)!; - lines.splice(backendStartIndex, 0, `${indentation}${backendAddLine}`); - - const newContent = lines.join('\n'); - await fs.writeFile(backendFilePath, newContent, 'utf8'); - } + await addToBackend(name, { + defaultVersion: ctx.defaultVersion, + type: 'plugin', }); } diff --git a/packages/cli/src/lib/tasks.ts b/packages/cli/src/lib/tasks.ts index 851f962c62..84362d7856 100644 --- a/packages/cli/src/lib/tasks.ts +++ b/packages/cli/src/lib/tasks.ts @@ -196,3 +196,35 @@ export async function addPackageDependency( throw new Error(`Failed to add package dependencies, ${error}`); } } + +export async function addToBackend( + name: string, + ctx: { defaultVersion: string; type: 'plugin' | 'module' }, +) { + if (await fs.pathExists(paths.resolveTargetRoot('packages/backend'))) { + await Task.forItem('backend', `adding ${ctx.type}`, async () => { + const backendFilePath = paths.resolveTargetRoot( + 'packages/backend/src/index.ts', + ); + if (!(await fs.pathExists(backendFilePath))) { + return; + } + + const content = await fs.readFile(backendFilePath, 'utf8'); + const lines = content.split('\n'); + const backendAddLine = `backend.add(import('${name}'));`; + + const backendStartIndex = lines.findIndex(line => + line.match(/backend.start/), + ); + + if (backendStartIndex !== -1) { + const [indentation] = lines[backendStartIndex].match(/^\s*/)!; + lines.splice(backendStartIndex, 0, `${indentation}${backendAddLine}`); + + const newContent = lines.join('\n'); + await fs.writeFile(backendFilePath, newContent, 'utf8'); + } + }); + } +} From f812183f6cf19f1f4a2a1f204304d84e7f539e90 Mon Sep 17 00:00:00 2001 From: Alper Altay Date: Tue, 25 Jun 2024 12:41:53 +0200 Subject: [PATCH 082/416] chore: remove defaultversion Signed-off-by: Alper Altay --- packages/cli/src/lib/new/factories/backendModule.ts | 5 +---- packages/cli/src/lib/new/factories/backendPlugin.ts | 5 +---- packages/cli/src/lib/tasks.ts | 8 +++----- 3 files changed, 5 insertions(+), 13 deletions(-) diff --git a/packages/cli/src/lib/new/factories/backendModule.ts b/packages/cli/src/lib/new/factories/backendModule.ts index 8cfa7f1e00..2ace64e165 100644 --- a/packages/cli/src/lib/new/factories/backendModule.ts +++ b/packages/cli/src/lib/new/factories/backendModule.ts @@ -91,10 +91,7 @@ export const backendModule = createFactory({ }); } - await addToBackend(name, { - defaultVersion: ctx.defaultVersion, - type: 'module', - }); + await addToBackend(name, 'module'); if (options.owner) { await addCodeownersEntry(`/plugins/${dirName}`, options.owner); diff --git a/packages/cli/src/lib/new/factories/backendPlugin.ts b/packages/cli/src/lib/new/factories/backendPlugin.ts index d7bf33b033..8671ef9952 100644 --- a/packages/cli/src/lib/new/factories/backendPlugin.ts +++ b/packages/cli/src/lib/new/factories/backendPlugin.ts @@ -79,10 +79,7 @@ export const backendPlugin = createFactory({ ); }); - await addToBackend(name, { - defaultVersion: ctx.defaultVersion, - type: 'plugin', - }); + await addToBackend(name, 'plugin'); } if (options.owner) { diff --git a/packages/cli/src/lib/tasks.ts b/packages/cli/src/lib/tasks.ts index 84362d7856..11cf53bf4f 100644 --- a/packages/cli/src/lib/tasks.ts +++ b/packages/cli/src/lib/tasks.ts @@ -23,6 +23,7 @@ import { basename, dirname } from 'path'; import recursive from 'recursive-readdir'; import { exec as execCb } from 'child_process'; import { assertError } from '@backstage/errors'; +import { paths } from './paths'; const exec = promisify(execCb); @@ -197,12 +198,9 @@ export async function addPackageDependency( } } -export async function addToBackend( - name: string, - ctx: { defaultVersion: string; type: 'plugin' | 'module' }, -) { +export async function addToBackend(name: string, type: 'plugin' | 'module') { if (await fs.pathExists(paths.resolveTargetRoot('packages/backend'))) { - await Task.forItem('backend', `adding ${ctx.type}`, async () => { + await Task.forItem('backend', `adding ${type}`, async () => { const backendFilePath = paths.resolveTargetRoot( 'packages/backend/src/index.ts', ); From 9572fe40dff9adcc953a1e4a3573d45c3919f308 Mon Sep 17 00:00:00 2001 From: Alper Altay Date: Tue, 25 Jun 2024 12:45:58 +0200 Subject: [PATCH 083/416] chore: options instead of positional args Signed-off-by: Alper Altay --- packages/cli/src/lib/new/factories/backendModule.ts | 4 +++- packages/cli/src/lib/new/factories/backendPlugin.ts | 4 +++- packages/cli/src/lib/tasks.ts | 9 +++++++-- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/packages/cli/src/lib/new/factories/backendModule.ts b/packages/cli/src/lib/new/factories/backendModule.ts index 2ace64e165..67860b812e 100644 --- a/packages/cli/src/lib/new/factories/backendModule.ts +++ b/packages/cli/src/lib/new/factories/backendModule.ts @@ -91,7 +91,9 @@ export const backendModule = createFactory({ }); } - await addToBackend(name, 'module'); + await addToBackend(name, { + type: 'module', + }); if (options.owner) { await addCodeownersEntry(`/plugins/${dirName}`, options.owner); diff --git a/packages/cli/src/lib/new/factories/backendPlugin.ts b/packages/cli/src/lib/new/factories/backendPlugin.ts index 8671ef9952..fc77896461 100644 --- a/packages/cli/src/lib/new/factories/backendPlugin.ts +++ b/packages/cli/src/lib/new/factories/backendPlugin.ts @@ -79,7 +79,9 @@ export const backendPlugin = createFactory({ ); }); - await addToBackend(name, 'plugin'); + await addToBackend(name, { + type: 'plugin', + }); } if (options.owner) { diff --git a/packages/cli/src/lib/tasks.ts b/packages/cli/src/lib/tasks.ts index 11cf53bf4f..ffff2892fb 100644 --- a/packages/cli/src/lib/tasks.ts +++ b/packages/cli/src/lib/tasks.ts @@ -198,9 +198,14 @@ export async function addPackageDependency( } } -export async function addToBackend(name: string, type: 'plugin' | 'module') { +export async function addToBackend( + name: string, + options: { + type: 'plugin' | 'module'; + }, +) { if (await fs.pathExists(paths.resolveTargetRoot('packages/backend'))) { - await Task.forItem('backend', `adding ${type}`, async () => { + await Task.forItem('backend', `adding ${options.type}`, async () => { const backendFilePath = paths.resolveTargetRoot( 'packages/backend/src/index.ts', ); From c4275d2d14b39750b47a44df48ee52d4d4744d3f Mon Sep 17 00:00:00 2001 From: Debabrata Panigrahi <50622005+Debanitrkl@users.noreply.github.com> Date: Tue, 25 Jun 2024 12:25:28 +0000 Subject: [PATCH 084/416] Signed-off-by: Debabrata Panigrahi <50622005+Debanitrkl@users.noreply.github.com> Fixed the incorrect plugin naming --- microsite/data/plugins/harness-chaos.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/microsite/data/plugins/harness-chaos.yaml b/microsite/data/plugins/harness-chaos.yaml index ade6f9e566..e089b3d86b 100644 --- a/microsite/data/plugins/harness-chaos.yaml +++ b/microsite/data/plugins/harness-chaos.yaml @@ -1,4 +1,4 @@ -title: Harness Service Reliability Management +title: Harness Chaos Engineering author: harness.io authorUrl: https://github.com/harness/backstage-plugins category: Chaos Engineering From e8c2fbb9ed28818cec130faab8b10a299d9f0ef1 Mon Sep 17 00:00:00 2001 From: Marek Libra Date: Wed, 26 Jun 2024 10:59:30 +0200 Subject: [PATCH 085/416] Set 001-notifications BEP to "implementable" Signed-off-by: Marek Libra --- beps/0001-notifications-system/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/beps/0001-notifications-system/README.md b/beps/0001-notifications-system/README.md index 80751179dd..541e75e555 100644 --- a/beps/0001-notifications-system/README.md +++ b/beps/0001-notifications-system/README.md @@ -1,6 +1,6 @@ --- title: Backstage Notifications System -status: provisional +status: implementable authors: - '@Rugvip' - '@drodil' From 546700b0c1acd565c089c6b8a9a89228d3f97909 Mon Sep 17 00:00:00 2001 From: blam Date: Wed, 26 Jun 2024 14:15:45 +0200 Subject: [PATCH 086/416] chore: some PR feedback suggestions Signed-off-by: blam --- .changeset/dry-squids-tap.md | 9 +- packages/frontend-plugin-api/api-report.md | 36 +++---- .../src/wiring/createExtension.ts | 4 +- .../src/wiring/createExtensionKind.test.tsx | 17 ++-- .../src/wiring/createExtensionKind.ts | 93 ++++++++++--------- .../frontend-plugin-api/src/wiring/index.ts | 2 +- 6 files changed, 84 insertions(+), 77 deletions(-) diff --git a/.changeset/dry-squids-tap.md b/.changeset/dry-squids-tap.md index a9eb7efb3b..5193e1f204 100644 --- a/.changeset/dry-squids-tap.md +++ b/.changeset/dry-squids-tap.md @@ -8,7 +8,7 @@ This allows the creation of extension with the following pattern: ```tsx // create the extension kind -const TestExtension = createExtensionKind({ +const TestExtensionKind = createExtensionKind({ kind: 'test-extension', attachTo: { id: 'test', input: 'default' }, output: { @@ -22,5 +22,10 @@ const TestExtension = createExtensionKind({ }); // create an instance of the extension kind with props -const testExtension = TestExtension.create({ text: 'Hello World' }); +const testExtension = TestExtensionKind.new({ + name: 'foo', + options: { + text: 'Hello World', + }, +}); ``` diff --git a/packages/frontend-plugin-api/api-report.md b/packages/frontend-plugin-api/api-report.md index b4c761ec05..48718f5375 100644 --- a/packages/frontend-plugin-api/api-report.md +++ b/packages/frontend-plugin-api/api-report.md @@ -524,13 +524,13 @@ export function createExtensionInput< // @public export function createExtensionKind< - TProps, + TOptions, TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, TConfig, >( - options: ExtensionKindOptions, -): ExtensionKind; + options: ExtensionKindOptions, +): ExtensionKind; // @public (undocumented) export interface CreateExtensionOptions< @@ -548,7 +548,7 @@ export interface CreateExtensionOptions< // (undocumented) disabled?: boolean; // (undocumented) - factory(options: { + factory(context: { node: AppNode; config: TConfig; inputs: Expand>; @@ -923,24 +923,24 @@ export interface ExtensionInput< extensionData: TExtensionData; } -// @public (undocumented) +// @public export class ExtensionKind< - TProps, + TOptions, TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, TConfig, > { // (undocumented) static create< - TProps, + TOptions, TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, TConfig, >( - options: ExtensionKindOptions, - ): ExtensionKind; + options: ExtensionKindOptions, + ): ExtensionKind; // (undocumented) - new(options: { + new(args: { namespace?: string; name?: string; attachTo?: { @@ -951,29 +951,29 @@ export class ExtensionKind< inputs?: TInputs; output?: TOutput; configSchema?: PortableSchema; - props: TProps; + options: TOptions; factory?( - options: { + context: { node: AppNode; config: TConfig; inputs: Expand>; orignalFactory( - options?: { + context?: { node?: AppNode; config?: TConfig; inputs?: Expand>; }, - props?: TProps, + options?: TOptions, ): Expand>; }, - props: TProps, + options: TOptions, ): Expand>; }): ExtensionDefinition; } // @public (undocumented) export interface ExtensionKindOptions< - TProps, + TOptions, TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, TConfig, @@ -989,12 +989,12 @@ export interface ExtensionKindOptions< disabled?: boolean; // (undocumented) factory( - options: { + context: { node: AppNode; config: TConfig; inputs: Expand>; }, - props: TProps, + options: TOptions, ): Expand>; // (undocumented) inputs?: TInputs; diff --git a/packages/frontend-plugin-api/src/wiring/createExtension.ts b/packages/frontend-plugin-api/src/wiring/createExtension.ts index be76fbc069..28dc6a4e29 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtension.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtension.ts @@ -91,7 +91,7 @@ export interface CreateExtensionOptions< inputs?: TInputs; output: TOutput; configSchema?: PortableSchema; - factory(options: { + factory(context: { node: AppNode; config: TConfig; inputs: Expand>; @@ -115,7 +115,7 @@ export interface InternalExtensionDefinition readonly version: 'v1'; readonly inputs: AnyExtensionInputMap; readonly output: AnyExtensionDataMap; - factory(options: { + factory(context: { node: AppNode; config: TConfig; inputs: ResolvedExtensionInputs; diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionKind.test.tsx b/packages/frontend-plugin-api/src/wiring/createExtensionKind.test.tsx index 2d5b218082..3bdcd3a7cc 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtensionKind.test.tsx +++ b/packages/frontend-plugin-api/src/wiring/createExtensionKind.test.tsx @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import React from 'react'; import { coreExtensionData } from './coreExtensionData'; import { createExtensionKind } from './createExtensionKind'; @@ -26,16 +27,16 @@ describe('createExtensionKind', () => { output: { element: coreExtensionData.reactElement, }, - factory(_, props: { text: string }) { + factory(_, options: { text: string }) { return { - element:

    {props.text}

    , + element:

    {options.text}

    , }; }, }); const extension = TestExtension.new({ name: 'my-extension', - props: { + options: { text: 'Hello, world!', }, }); @@ -77,21 +78,21 @@ describe('createExtensionKind', () => { output: { element: coreExtensionData.reactElement, }, - factory(_, props: { text: string }) { + factory(_, options: { text: string }) { return { - element:

    {props.text}

    , + element:

    {options.text}

    , }; }, }); const extension = TestExtension.new({ name: 'my-extension', - props: { + options: { text: 'Hello, world!', }, - factory(_, props: { text: string }) { + factory(_, options: { text: string }) { return { - element:

    {props.text}

    , + element:

    {options.text}

    , }; }, }); diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionKind.ts b/packages/frontend-plugin-api/src/wiring/createExtensionKind.ts index 2067d18c04..52bf711822 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtensionKind.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtensionKind.ts @@ -1,14 +1,3 @@ -import { AppNode } from '../apis'; -import { PortableSchema } from '../schema'; -import { Expand } from '../types'; -import { - AnyExtensionDataMap, - AnyExtensionInputMap, - ExtensionDataValues, - ResolvedExtensionInputs, - createExtension, -} from './createExtension'; - /* * Copyright 2024 The Backstage Authors * @@ -25,11 +14,22 @@ import { * limitations under the License. */ +import { AppNode } from '../apis'; +import { PortableSchema } from '../schema'; +import { Expand } from '../types'; +import { + AnyExtensionDataMap, + AnyExtensionInputMap, + ExtensionDataValues, + ResolvedExtensionInputs, + createExtension, +} from './createExtension'; + /** * @public */ -export interface ExtensionKindOptions< - TProps, +export interface CreateExtensionKindOptions< + TOptions, TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, TConfig, @@ -43,45 +43,46 @@ export interface ExtensionKindOptions< output: TOutput; configSchema?: PortableSchema; factory( - options: { + context: { node: AppNode; config: TConfig; inputs: Expand>; }, - props: TProps, + options: TOptions, ): Expand>; } /** + * TODO: should we export an interface instead of a concrete class? * @public */ export class ExtensionKind< - TProps, + TOptions, TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, TConfig, > { static create< - TProps, + TOptions, TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, TConfig, >( - options: ExtensionKindOptions, - ): ExtensionKind { + options: CreateExtensionKindOptions, + ): ExtensionKind { return new ExtensionKind(options); } private constructor( - private readonly options: ExtensionKindOptions< - TProps, + private readonly options: CreateExtensionKindOptions< + TOptions, TInputs, TOutput, TConfig >, ) {} - public new(options: { + public new(args: { namespace?: string; name?: string; attachTo?: { id: string; input: string }; @@ -89,58 +90,58 @@ export class ExtensionKind< inputs?: TInputs; output?: TOutput; configSchema?: PortableSchema; - props: TProps; + options: TOptions; factory?( - options: { + context: { node: AppNode; config: TConfig; inputs: Expand>; orignalFactory( - options?: { + context?: { node?: AppNode; config?: TConfig; inputs?: Expand>; }, - props?: TProps, + options?: TOptions, ): Expand>; }, - props: TProps, + options: TOptions, ): Expand>; }) { return createExtension({ kind: this.options.kind, - namespace: options.namespace ?? this.options.namespace, - name: options.name ?? this.options.name, - attachTo: options.attachTo ?? this.options.attachTo, - disabled: options.disabled ?? this.options.disabled, - inputs: options.inputs ?? this.options.inputs, - output: options.output ?? this.options.output, - configSchema: options.configSchema ?? this.options.configSchema, // TODO: some config merging or smth + namespace: args.namespace ?? this.options.namespace, + name: args.name ?? this.options.name, + attachTo: args.attachTo ?? this.options.attachTo, + disabled: args.disabled ?? this.options.disabled, + inputs: args.inputs ?? this.options.inputs, + output: args.output ?? this.options.output, + configSchema: args.configSchema ?? this.options.configSchema, // TODO: some config merging or smth factory: ({ node, config, inputs }) => { - if (options.factory) { - return options.factory( + if (args.factory) { + return args.factory( { node, config, inputs, orignalFactory: ( - innerOptions?: { + innerContext?: { node?: AppNode; config?: TConfig; inputs?: Expand>; }, - innerProps?: TProps, + innerOptions?: TOptions, ) => this.options.factory( { - node: innerOptions?.node ?? node, - config: innerOptions?.config ?? config, - inputs: innerOptions?.inputs ?? inputs, + node: innerContext?.node ?? node, + config: innerContext?.config ?? config, + inputs: innerContext?.inputs ?? inputs, }, - innerProps ?? options.props, + innerOptions ?? args.options, ), }, - options.props, + args.options, ); } @@ -150,7 +151,7 @@ export class ExtensionKind< config, inputs, }, - options.props, + args.options, ); }, }); @@ -164,10 +165,10 @@ export class ExtensionKind< * @public */ export function createExtensionKind< - TProps, + TOptions, TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, TConfig, ->(options: ExtensionKindOptions) { +>(options: CreateExtensionKindOptions) { return ExtensionKind.create(options); } diff --git a/packages/frontend-plugin-api/src/wiring/index.ts b/packages/frontend-plugin-api/src/wiring/index.ts index e8c9afbaae..8fe9dc3a54 100644 --- a/packages/frontend-plugin-api/src/wiring/index.ts +++ b/packages/frontend-plugin-api/src/wiring/index.ts @@ -49,7 +49,7 @@ export { type FrontendFeature, } from './types'; export { - type ExtensionKindOptions, + type CreateExtensionKindOptions as ExtensionKindOptions, ExtensionKind, createExtensionKind, } from './createExtensionKind'; From 6fa652c88deafbc61ad27b79eea7e9f801c76cd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Wed, 26 Jun 2024 17:12:28 +0200 Subject: [PATCH 087/416] improve default docs sorting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .changeset/eleven-radios-begin.md | 5 +++++ .../src/home/components/Tables/DocsTable.tsx | 14 +++++++------- .../src/home/components/Tables/columns.tsx | 6 ++++++ 3 files changed, 18 insertions(+), 7 deletions(-) create mode 100644 .changeset/eleven-radios-begin.md diff --git a/.changeset/eleven-radios-begin.md b/.changeset/eleven-radios-begin.md new file mode 100644 index 0000000000..3fc2dd7895 --- /dev/null +++ b/.changeset/eleven-radios-begin.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs': patch +--- + +Improve default sorting of docs table diff --git a/plugins/techdocs/src/home/components/Tables/DocsTable.tsx b/plugins/techdocs/src/home/components/Tables/DocsTable.tsx index c0b39878cd..de57c70e6a 100644 --- a/plugins/techdocs/src/home/components/Tables/DocsTable.tsx +++ b/plugins/techdocs/src/home/components/Tables/DocsTable.tsx @@ -51,6 +51,13 @@ export type DocsTableProps = { options?: TableOptions; }; +const defaultColumns: TableColumn[] = [ + columnFactories.createNameColumn(), + columnFactories.createOwnerColumn(), + columnFactories.createKindColumn(), + columnFactories.createTypeColumn(), +]; + /** * Component which renders a table documents * @@ -84,13 +91,6 @@ export const DocsTable = (props: DocsTableProps) => { }; }); - const defaultColumns: TableColumn[] = [ - columnFactories.createNameColumn(), - columnFactories.createOwnerColumn(), - columnFactories.createKindColumn(), - columnFactories.createTypeColumn(), - ]; - const defaultActions: TableProps['actions'] = [ actionFactories.createCopyDocsUrlAction(copyToClipboard), ]; diff --git a/plugins/techdocs/src/home/components/Tables/columns.tsx b/plugins/techdocs/src/home/components/Tables/columns.tsx index bc85bb7a63..8c8346b406 100644 --- a/plugins/techdocs/src/home/components/Tables/columns.tsx +++ b/plugins/techdocs/src/home/components/Tables/columns.tsx @@ -35,6 +35,12 @@ export const columnFactories = { title: 'Document', field: 'entity.metadata.name', highlight: true, + defaultSort: 'asc', + customSort: (row1, row2) => { + const title1 = customTitle(row1.entity).toLocaleLowerCase(); + const title2 = customTitle(row2.entity).toLocaleLowerCase(); + return title1.localeCompare(title2); + }, render: (row: DocsTableRow) => ( Date: Wed, 26 Jun 2024 17:48:55 +0000 Subject: [PATCH 088/416] Add OLX to ADOPTERS.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Márcio Eduardo Gomes Barbosa --- ADOPTERS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/ADOPTERS.md b/ADOPTERS.md index 5fe359bf1e..3ff0c5e1b5 100644 --- a/ADOPTERS.md +++ b/ADOPTERS.md @@ -271,3 +271,4 @@ _You can do this by using the [Adopter form](https://info.backstage.spotify.com/ | [Scania](https://www.scania.com) | [Santosh Rangavajjula](https://linkedin.com/in/rsbth) | We are implementing backstage at Scania to consolidate operational information from Gitlab, Jira, Confluence, Artifactory, Servicenow and other tools into one place. | | [Senora.dev](https://senora.dev) | [Shaked Braimok Yosef](https://github.com/ShakedBraimok) | We are using Backstage as a service catalog for our costumers. | | [Covestro](https://www.covestro.com) | [Julien Gedeon](https://github.com/cvvcv1) | We use Backstage as our Internal developer portal for the Digital R&D department. | +| [Grupo OLX](https://www.olx.com.br/) | [@marciorgb](https://github.com/marciorgb), [@jeffbraga](https://github.com/jeffbraga), [@rogerfernandes](https://github.com/rogerfernandes), [@stockrt](https://github.com/stockrt) | At Grupo OLX, we are using Backstage to reduce friction and enhance developer autonomy by creating Golden Paths, which automate previously manual processes. Additionally, Backstage's catalog integrates various views of our organizational structure and workflows, offering a comprehensive overview of how different components interconnect. | From b9ed1bb50f734678d596d9800d3dda8b8ba6de53 Mon Sep 17 00:00:00 2001 From: Karl Haworth Date: Wed, 5 Jun 2024 11:54:22 -0400 Subject: [PATCH 089/416] bump better-sqlite3 from ^9.0.0 to ^11.0.0 Signed-off-by: Karl Haworth --- .changeset/weak-boats-float.md | 9 +++++++++ packages/backend-common/package.json | 2 +- packages/backend-defaults/package.json | 2 +- packages/backend-legacy/package.json | 2 +- packages/backend-test-utils/package.json | 2 +- plugins/catalog-backend/package.json | 2 +- yarn.lock | 18 +++++++++--------- 7 files changed, 23 insertions(+), 14 deletions(-) create mode 100644 .changeset/weak-boats-float.md diff --git a/.changeset/weak-boats-float.md b/.changeset/weak-boats-float.md new file mode 100644 index 0000000000..c4c41c5922 --- /dev/null +++ b/.changeset/weak-boats-float.md @@ -0,0 +1,9 @@ +--- +'@backstage/plugin-catalog-backend': minor +'@backstage/backend-test-utils': patch +'@backstage/backend-defaults': patch +'@backstage/backend-common': patch +'example-backend-legacy': patch +--- + +bumped better-sqlite3 from ^9.0.0 to ^11.0.0 diff --git a/packages/backend-common/package.json b/packages/backend-common/package.json index 7944477c88..28378f6c41 100644 --- a/packages/backend-common/package.json +++ b/packages/backend-common/package.json @@ -137,7 +137,7 @@ "@types/webpack-env": "^1.15.2", "@types/yauzl": "^2.10.0", "aws-sdk-client-mock": "^4.0.0", - "better-sqlite3": "^9.0.0", + "better-sqlite3": "^11.0.0", "http-errors": "^2.0.0", "msw": "^1.0.0", "mysql2": "^3.0.0", diff --git a/packages/backend-defaults/package.json b/packages/backend-defaults/package.json index 376aa9d36f..824f1893bd 100644 --- a/packages/backend-defaults/package.json +++ b/packages/backend-defaults/package.json @@ -143,7 +143,7 @@ "@types/express": "^4.17.6", "archiver": "^6.0.0", "base64-stream": "^1.0.0", - "better-sqlite3": "^9.0.0", + "better-sqlite3": "^11.0.0", "compression": "^1.7.4", "concat-stream": "^2.0.0", "cookie": "^0.6.0", diff --git a/packages/backend-legacy/package.json b/packages/backend-legacy/package.json index c8b019848f..6b9bb3523a 100644 --- a/packages/backend-legacy/package.json +++ b/packages/backend-legacy/package.json @@ -66,7 +66,7 @@ "@gitbeaker/node": "^35.1.0", "@octokit/rest": "^19.0.3", "azure-devops-node-api": "^12.0.0", - "better-sqlite3": "^9.0.0", + "better-sqlite3": "^11.0.0", "dockerode": "^4.0.0", "example-app": "link:../app", "express": "^4.17.1", diff --git a/packages/backend-test-utils/package.json b/packages/backend-test-utils/package.json index 47f2c9c628..540b4f9ee4 100644 --- a/packages/backend-test-utils/package.json +++ b/packages/backend-test-utils/package.json @@ -56,7 +56,7 @@ "@keyv/memcache": "^1.3.5", "@keyv/redis": "^2.5.3", "@types/keyv": "^4.2.0", - "better-sqlite3": "^9.0.0", + "better-sqlite3": "^11.0.0", "cookie": "^0.6.0", "express": "^4.17.1", "fs-extra": "^11.0.0", diff --git a/plugins/catalog-backend/package.json b/plugins/catalog-backend/package.json index d9bc71ae91..596e51435e 100644 --- a/plugins/catalog-backend/package.json +++ b/plugins/catalog-backend/package.json @@ -110,7 +110,7 @@ "@types/lodash": "^4.14.151", "@types/supertest": "^2.0.8", "@types/uuid": "^9.0.0", - "better-sqlite3": "^9.0.0", + "better-sqlite3": "^11.0.0", "luxon": "^3.0.0", "msw": "^1.0.0", "supertest": "^6.1.3", diff --git a/yarn.lock b/yarn.lock index 912220ac86..fec9c84b79 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3559,7 +3559,7 @@ __metadata: archiver: ^6.0.0 aws-sdk-client-mock: ^4.0.0 base64-stream: ^1.0.0 - better-sqlite3: ^9.0.0 + better-sqlite3: ^11.0.0 compression: ^1.7.4 concat-stream: ^2.0.0 cors: ^2.8.5 @@ -3647,7 +3647,7 @@ __metadata: archiver: ^6.0.0 aws-sdk-client-mock: ^4.0.0 base64-stream: ^1.0.0 - better-sqlite3: ^9.0.0 + better-sqlite3: ^11.0.0 compression: ^1.7.4 concat-stream: ^2.0.0 cookie: ^0.6.0 @@ -3818,7 +3818,7 @@ __metadata: "@keyv/redis": ^2.5.3 "@types/keyv": ^4.2.0 "@types/supertest": ^2.0.8 - better-sqlite3: ^9.0.0 + better-sqlite3: ^11.0.0 cookie: ^0.6.0 express: ^4.17.1 fs-extra: ^11.0.0 @@ -5694,7 +5694,7 @@ __metadata: "@types/lodash": ^4.14.151 "@types/supertest": ^2.0.8 "@types/uuid": ^9.0.0 - better-sqlite3: ^9.0.0 + better-sqlite3: ^11.0.0 codeowners-utils: ^1.0.2 core-js: ^3.6.5 express: ^4.17.1 @@ -21618,14 +21618,14 @@ __metadata: languageName: node linkType: hard -"better-sqlite3@npm:^9.0.0": - version: 9.6.0 - resolution: "better-sqlite3@npm:9.6.0" +"better-sqlite3@npm:^11.0.0": + version: 11.0.0 + resolution: "better-sqlite3@npm:11.0.0" dependencies: bindings: ^1.5.0 node-gyp: latest prebuild-install: ^7.1.1 - checksum: be3a1d2a3f6f9b5141be6607a38c0a51fa5849495b071955e507bc0c2a2fb08430852c1bf03796eec1a53344b25645807db48dcb51c71b0662b74c5a70420bb0 + checksum: 7bf02ea6ba3253f53cb36bd872f86379ebf1a66cb103d39b91c610995c4396dde2b976bdf866f07eb7d67eb6f5433aa5490a6a4f4264244f83a53562f68832dc languageName: node linkType: hard @@ -26624,7 +26624,7 @@ __metadata: "@types/express-serve-static-core": ^4.17.5 "@types/luxon": ^3.0.0 azure-devops-node-api: ^12.0.0 - better-sqlite3: ^9.0.0 + better-sqlite3: ^11.0.0 dockerode: ^4.0.0 example-app: "link:../app" express: ^4.17.1 From f16e1b4d39e2081d373c7adabd1d0683fcafac23 Mon Sep 17 00:00:00 2001 From: Karl Haworth Date: Fri, 7 Jun 2024 10:40:09 -0400 Subject: [PATCH 090/416] remove changeset item per goalie Signed-off-by: Karl Haworth --- .changeset/weak-boats-float.md | 1 - 1 file changed, 1 deletion(-) diff --git a/.changeset/weak-boats-float.md b/.changeset/weak-boats-float.md index c4c41c5922..4fe6fe73a0 100644 --- a/.changeset/weak-boats-float.md +++ b/.changeset/weak-boats-float.md @@ -3,7 +3,6 @@ '@backstage/backend-test-utils': patch '@backstage/backend-defaults': patch '@backstage/backend-common': patch -'example-backend-legacy': patch --- bumped better-sqlite3 from ^9.0.0 to ^11.0.0 From 5f0a3eea33af613ca92a47adac689c78fc2dfaf8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 26 Jun 2024 22:29:47 +0000 Subject: [PATCH 091/416] chore(deps): update dependency nodemon to v3.1.4 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 08218f6ee9..831fdf7e92 100644 --- a/yarn.lock +++ b/yarn.lock @@ -34903,8 +34903,8 @@ __metadata: linkType: hard "nodemon@npm:^3.0.1": - version: 3.1.3 - resolution: "nodemon@npm:3.1.3" + version: 3.1.4 + resolution: "nodemon@npm:3.1.4" dependencies: chokidar: ^3.5.2 debug: ^4 @@ -34918,7 +34918,7 @@ __metadata: undefsafe: ^2.0.5 bin: nodemon: bin/nodemon.js - checksum: ac2fa8865ab292b7ddf66731487acca4b4282b2728361e0de633c0c74cd705d6a0852b52f785c09469d959241d038ba824f50375622e687a2a318be747d9cd9d + checksum: 3f003fc2c7bdaba559108320f188b7cb063220455e5da218ff3bf4f7468ad7059852da6e35a52b8c690cc27f6e36a433a9ad1f1bdb8096ec1ee3d930629cbeca languageName: node linkType: hard From 9ca6af45fc07c5692efcfd170db0682f8538034a Mon Sep 17 00:00:00 2001 From: Kevin L Date: Wed, 26 Jun 2024 18:55:32 -0400 Subject: [PATCH 092/416] Minor fix in the homepage setup and customization documentation Signed-off-by: Kevin L --- docs/getting-started/app-custom-theme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started/app-custom-theme.md b/docs/getting-started/app-custom-theme.md index 3fb0365ad0..4c013440da 100644 --- a/docs/getting-started/app-custom-theme.md +++ b/docs/getting-started/app-custom-theme.md @@ -64,7 +64,7 @@ const app = createApp({ }) ``` -Note that your list of custom themes overrides the default themes. If you still want to use the default themes, they are exported as `themes.light` and `themes.light` from [`@backstage/theme`](https://www.npmjs.com/package/@backstage/theme). +Note that your list of custom themes overrides the default themes. If you still want to use the default themes, they are exported as `themes.light` and `themes.dark` from [`@backstage/theme`](https://www.npmjs.com/package/@backstage/theme). ## Example of a custom theme From e1d58ced052f8f404b9610ebcf212cd33895f6a4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 26 Jun 2024 23:09:32 +0000 Subject: [PATCH 093/416] fix(deps): update dependency @types/express-serve-static-core to v4.19.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 831fdf7e92..ffb1e0c157 100644 --- a/yarn.lock +++ b/yarn.lock @@ -17540,14 +17540,14 @@ __metadata: linkType: hard "@types/express-serve-static-core@npm:*, @types/express-serve-static-core@npm:^4.17.33, @types/express-serve-static-core@npm:^4.17.5": - version: 4.19.3 - resolution: "@types/express-serve-static-core@npm:4.19.3" + version: 4.19.5 + resolution: "@types/express-serve-static-core@npm:4.19.5" dependencies: "@types/node": "*" "@types/qs": "*" "@types/range-parser": "*" "@types/send": "*" - checksum: fff38a7f43baeb6a62380682d39846c9d92047e0dce1737d76ebd944528619abc18addc4f0548bf43dbf4514090a1bd5140ba36695024656f941a87424b8ed7d + checksum: 72076c2f8df55e89136d4343fc874050d56c0f4afd885772a8aa506b98c3f4f3ddc7dcba42295a8b931c61000234fd679aec79ef50db15f376bf37d46234939a languageName: node linkType: hard From a5a73eb6f569a92993a46d1de56919d5d2d3cd5e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 26 Jun 2024 23:48:22 +0000 Subject: [PATCH 094/416] fix(deps): update dependency eslint-plugin-react to v7.34.3 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/yarn.lock b/yarn.lock index ffb1e0c157..e7d5b62b9a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -21003,16 +21003,16 @@ __metadata: languageName: node linkType: hard -"array.prototype.tosorted@npm:^1.1.3": - version: 1.1.3 - resolution: "array.prototype.tosorted@npm:1.1.3" +"array.prototype.tosorted@npm:^1.1.4": + version: 1.1.4 + resolution: "array.prototype.tosorted@npm:1.1.4" dependencies: - call-bind: ^1.0.5 + call-bind: ^1.0.7 define-properties: ^1.2.1 - es-abstract: ^1.22.3 - es-errors: ^1.1.0 + es-abstract: ^1.23.3 + es-errors: ^1.3.0 es-shim-unscopables: ^1.0.2 - checksum: 555e8808086bbde9e634c5dc5a8c0a2f1773075447b43b2fa76ab4f94f4e90f416d2a4f881024e1ce1a2931614caf76cd6b408af901c9d7cd13061d0d268f5af + checksum: e4142d6f556bcbb4f393c02e7dbaea9af8f620c040450c2be137c9cbbd1a17f216b9c688c5f2c08fbb038ab83f55993fa6efdd9a05881d84693c7bcb5422127a languageName: node linkType: hard @@ -25571,7 +25571,7 @@ __metadata: languageName: node linkType: hard -"es-errors@npm:^1.1.0, es-errors@npm:^1.2.1, es-errors@npm:^1.3.0": +"es-errors@npm:^1.2.1, es-errors@npm:^1.3.0": version: 1.3.0 resolution: "es-errors@npm:1.3.0" checksum: ec1414527a0ccacd7f15f4a3bc66e215f04f595ba23ca75cdae0927af099b5ec865f9f4d33e9d7e86f512f252876ac77d4281a7871531a50678132429b1271b5 @@ -26207,14 +26207,14 @@ __metadata: linkType: hard "eslint-plugin-react@npm:^7.28.0": - version: 7.34.2 - resolution: "eslint-plugin-react@npm:7.34.2" + version: 7.34.3 + resolution: "eslint-plugin-react@npm:7.34.3" dependencies: array-includes: ^3.1.8 array.prototype.findlast: ^1.2.5 array.prototype.flatmap: ^1.3.2 array.prototype.toreversed: ^1.1.2 - array.prototype.tosorted: ^1.1.3 + array.prototype.tosorted: ^1.1.4 doctrine: ^2.1.0 es-iterator-helpers: ^1.0.19 estraverse: ^5.3.0 @@ -26230,7 +26230,7 @@ __metadata: string.prototype.matchall: ^4.0.11 peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 - checksum: aed331239f3a64fcd884380534ece4b8716f1eca4899c8636d04306879e6b4e7339e28e427bdd571d372b78b713025e0767e5f5b5486a8d19bff82616ebe8959 + checksum: 1a519b9792ab9392a5157f2543ce98ab1218c62f4a31c4c3ceb5dd3e7997def4aa07ab39f7276af0fe116ef002db29d97216a15b7aa3b200e55b641cf77d6292 languageName: node linkType: hard From e5f7503dbb1455ae6f79226beaa378db2e0f9351 Mon Sep 17 00:00:00 2001 From: Caleb Troughton Date: Wed, 26 Jun 2024 17:11:16 -0700 Subject: [PATCH 095/416] Fix package install instructions for plugin-events-backend Signed-off-by: Caleb Troughton --- docs/features/software-catalog/configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/features/software-catalog/configuration.md b/docs/features/software-catalog/configuration.md index 3bbbfd6716..e02dc355e2 100644 --- a/docs/features/software-catalog/configuration.md +++ b/docs/features/software-catalog/configuration.md @@ -186,7 +186,7 @@ The first step is to add the events backend plugin to your Backstage application ```ts # From your Backstage root directory -yarn --cwd packages/backend add @backstage/plugin-events-node +yarn --cwd packages/backend add @backstage/plugin-events-backend ``` Now you can install the events backend plugin in your backend. From c95fc38d0558f92c31ecaddcbf3bc50c8faa05e3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 27 Jun 2024 00:44:50 +0000 Subject: [PATCH 096/416] fix(deps): update dependency minimatch to v9.0.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 e7d5b62b9a..12305b634c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -33971,11 +33971,11 @@ __metadata: linkType: hard "minimatch@npm:^9.0.0, minimatch@npm:^9.0.1, minimatch@npm:^9.0.3": - version: 9.0.4 - resolution: "minimatch@npm:9.0.4" + version: 9.0.5 + resolution: "minimatch@npm:9.0.5" dependencies: brace-expansion: ^2.0.1 - checksum: cf717f597ec3eed7dabc33153482a2e8d49f4fd3c26e58fd9c71a94c5029a0838728841b93f46bf1263b65a8010e2ee800d0dc9b004ab8ba8b6d1ec07cc115b5 + checksum: 2c035575eda1e50623c731ec6c14f65a85296268f749b9337005210bb2b34e2705f8ef1a358b188f69892286ab99dc42c8fb98a57bde55c8d81b3023c19cea28 languageName: node linkType: hard From 9f72e31617cd4779ca693789b84bd8ee89289320 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 27 Jun 2024 08:01:05 +0000 Subject: [PATCH 097/416] fix(deps): update dependency nodemailer to v6.9.14 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 65f3c565c4..5d92f37a1d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -34896,9 +34896,9 @@ __metadata: linkType: hard "nodemailer@npm:^6.9.13": - version: 6.9.13 - resolution: "nodemailer@npm:6.9.13" - checksum: 1b591ef480be2ff69480127cbff819e6593b1ef263b6f920e1a4e83e40280582daf7a14a809ef92f9828e2a70bdb3ce22b11924e209f2afe4975f9ff37e08e9d + version: 6.9.14 + resolution: "nodemailer@npm:6.9.14" + checksum: 4037a45e24dbca47c0ea9a962d2c316deef7afe6ebf73c7da3a84942a8d501d85aae7f36dc1c5dac58dec7275f7cb1c92fd4f9c7c19f037225019ad2f402a9dc languageName: node linkType: hard From cc81579db2319e76213648a1863aec443d6c86e1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 27 Jun 2024 08:10:28 +0000 Subject: [PATCH 098/416] fix(deps): update rjsf monorepo to v5.18.5 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .changeset/renovate-ced359b.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-ced359b.md diff --git a/.changeset/renovate-ced359b.md b/.changeset/renovate-ced359b.md new file mode 100644 index 0000000000..2c100b6e23 --- /dev/null +++ b/.changeset/renovate-ced359b.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.18.5`. +Updated dependency `@rjsf/core` to `5.18.5`. +Updated dependency `@rjsf/material-ui` to `5.18.5`. +Updated dependency `@rjsf/validator-ajv8` to `5.18.5`. diff --git a/plugins/home-react/package.json b/plugins/home-react/package.json index 819c87e20d..9c7667b4d0 100644 --- a/plugins/home-react/package.json +++ b/plugins/home-react/package.json @@ -46,7 +46,7 @@ "@backstage/core-plugin-api": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@rjsf/utils": "5.18.4", + "@rjsf/utils": "5.18.5", "@types/react": "^16.13.1 || ^17.0.0" }, "devDependencies": { diff --git a/plugins/home/package.json b/plugins/home/package.json index d6fbc13d29..2bc646b417 100644 --- a/plugins/home/package.json +++ b/plugins/home/package.json @@ -70,10 +70,10 @@ "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", - "@rjsf/core": "5.18.4", - "@rjsf/material-ui": "5.18.4", - "@rjsf/utils": "5.18.4", - "@rjsf/validator-ajv8": "5.18.4", + "@rjsf/core": "5.18.5", + "@rjsf/material-ui": "5.18.5", + "@rjsf/utils": "5.18.5", + "@rjsf/validator-ajv8": "5.18.5", "@types/react": "^16.13.1 || ^17.0.0 || ^18.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 6e37ff3e71..d5fe7ca9cb 100644 --- a/plugins/scaffolder-react/package.json +++ b/plugins/scaffolder-react/package.json @@ -72,10 +72,10 @@ "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", "@react-hookz/web": "^24.0.0", - "@rjsf/core": "5.18.4", - "@rjsf/material-ui": "5.18.4", - "@rjsf/utils": "5.18.4", - "@rjsf/validator-ajv8": "5.18.4", + "@rjsf/core": "5.18.5", + "@rjsf/material-ui": "5.18.5", + "@rjsf/utils": "5.18.5", + "@rjsf/validator-ajv8": "5.18.5", "@types/json-schema": "^7.0.9", "@types/react": "^16.13.1 || ^17.0.0 || ^18.0.0", "classnames": "^2.2.6", diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index 4cce0a83ce..33cf7be16f 100644 --- a/plugins/scaffolder/package.json +++ b/plugins/scaffolder/package.json @@ -81,10 +81,10 @@ "@material-ui/lab": "4.0.0-alpha.61", "@microsoft/fetch-event-source": "^2.0.1", "@react-hookz/web": "^24.0.0", - "@rjsf/core": "5.18.4", - "@rjsf/material-ui": "5.18.4", - "@rjsf/utils": "5.18.4", - "@rjsf/validator-ajv8": "5.18.4", + "@rjsf/core": "5.18.5", + "@rjsf/material-ui": "5.18.5", + "@rjsf/utils": "5.18.5", + "@rjsf/validator-ajv8": "5.18.5", "@types/react": "^16.13.1 || ^17.0.0 || ^18.0.0", "@uiw/react-codemirror": "^4.9.3", "classnames": "^2.2.6", diff --git a/yarn.lock b/yarn.lock index 65f3c565c4..89f9c68c95 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6222,7 +6222,7 @@ __metadata: "@backstage/core-plugin-api": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@rjsf/utils": 5.18.4 + "@rjsf/utils": 5.18.5 "@types/react": ^16.13.1 || ^17.0.0 "@types/react-grid-layout": ^1.3.2 peerDependencies: @@ -6253,10 +6253,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.18.4 - "@rjsf/material-ui": 5.18.4 - "@rjsf/utils": 5.18.4 - "@rjsf/validator-ajv8": 5.18.4 + "@rjsf/core": 5.18.5 + "@rjsf/material-ui": 5.18.5 + "@rjsf/utils": 5.18.5 + "@rjsf/validator-ajv8": 5.18.5 "@testing-library/dom": ^10.0.0 "@testing-library/jest-dom": ^6.0.0 "@testing-library/react": ^15.0.0 @@ -7234,10 +7234,10 @@ __metadata: "@material-ui/icons": ^4.9.1 "@material-ui/lab": 4.0.0-alpha.61 "@react-hookz/web": ^24.0.0 - "@rjsf/core": 5.18.4 - "@rjsf/material-ui": 5.18.4 - "@rjsf/utils": 5.18.4 - "@rjsf/validator-ajv8": 5.18.4 + "@rjsf/core": 5.18.5 + "@rjsf/material-ui": 5.18.5 + "@rjsf/utils": 5.18.5 + "@rjsf/validator-ajv8": 5.18.5 "@testing-library/dom": ^10.0.0 "@testing-library/jest-dom": ^6.0.0 "@testing-library/react": ^15.0.0 @@ -7300,10 +7300,10 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@microsoft/fetch-event-source": ^2.0.1 "@react-hookz/web": ^24.0.0 - "@rjsf/core": 5.18.4 - "@rjsf/material-ui": 5.18.4 - "@rjsf/utils": 5.18.4 - "@rjsf/validator-ajv8": 5.18.4 + "@rjsf/core": 5.18.5 + "@rjsf/material-ui": 5.18.5 + "@rjsf/utils": 5.18.5 + "@rjsf/validator-ajv8": 5.18.5 "@testing-library/dom": ^10.0.0 "@testing-library/jest-dom": ^6.0.0 "@testing-library/react": ^15.0.0 @@ -14479,9 +14479,9 @@ __metadata: languageName: node linkType: hard -"@rjsf/core@npm:5.18.4": - version: 5.18.4 - resolution: "@rjsf/core@npm:5.18.4" +"@rjsf/core@npm:5.18.5": + version: 5.18.5 + resolution: "@rjsf/core@npm:5.18.5" dependencies: lodash: ^4.17.21 lodash-es: ^4.17.21 @@ -14491,26 +14491,26 @@ __metadata: peerDependencies: "@rjsf/utils": ^5.18.x react: ^16.14.0 || >=17 - checksum: 8c3f49914be396595ce67dc4c36ac25c5cb6673917ec82c47f79321f5bb78d02741e8dca39287d0435270e7c9ccb06f7d40e396bdf71a3e9eb1371ef16954817 + checksum: 7b986ec075d5b2de503d01172abdb3e3d33d04e5298fbf80842400e682f0aecdabfe4bb8482dde8a6aed90a35f4f5574cb7b24a11d689566c0cc0599485b334a languageName: node linkType: hard -"@rjsf/material-ui@npm:5.18.4": - version: 5.18.4 - resolution: "@rjsf/material-ui@npm:5.18.4" +"@rjsf/material-ui@npm:5.18.5": + version: 5.18.5 + resolution: "@rjsf/material-ui@npm:5.18.5" peerDependencies: "@material-ui/core": ^4.12.3 "@material-ui/icons": ^4.11.2 "@rjsf/core": ^5.18.x "@rjsf/utils": ^5.18.x react: ^16.14.0 || >=17 - checksum: 2bb0eeb0603bd11b034785ac1902cfcf3630cb4d04161728adff86b2629ca4d21bbb42beb9e6acdd4c9a6a4d84cce1ca325413a9bd1fd94eda47f58d62eb3164 + checksum: 61337141bcd7bcb46013d81ae6b618919eff3f55319800511443e524876bf5c84089970e14148716de203d5def341aa15c4d102243f0b694f120f05189a3adb7 languageName: node linkType: hard -"@rjsf/utils@npm:5.18.4": - version: 5.18.4 - resolution: "@rjsf/utils@npm:5.18.4" +"@rjsf/utils@npm:5.18.5": + version: 5.18.5 + resolution: "@rjsf/utils@npm:5.18.5" dependencies: json-schema-merge-allof: ^0.8.1 jsonpointer: ^5.0.1 @@ -14519,13 +14519,13 @@ __metadata: react-is: ^18.2.0 peerDependencies: react: ^16.14.0 || >=17 - checksum: d7cf514527ec50a94751c5ec1f9e5eafd89d0c56441a22ae28a4e667aaa7c60447e1e1ccf8355c5be5b97e9a1163853c116816b13307e3463433d50f6b89bb3e + checksum: 8da3ce82a0ec83e78806461db7226fd20489f6e8c41906ccde9d55c554aec3f50b8b8bac8c35e3cdf12d788c18fdad71c992f0d8b44f6161a1bf9e13598ded99 languageName: node linkType: hard -"@rjsf/validator-ajv8@npm:5.18.4": - version: 5.18.4 - resolution: "@rjsf/validator-ajv8@npm:5.18.4" +"@rjsf/validator-ajv8@npm:5.18.5": + version: 5.18.5 + resolution: "@rjsf/validator-ajv8@npm:5.18.5" dependencies: ajv: ^8.12.0 ajv-formats: ^2.1.1 @@ -14533,7 +14533,7 @@ __metadata: lodash-es: ^4.17.21 peerDependencies: "@rjsf/utils": ^5.18.x - checksum: edf3b24e07babe972e57645d396467c6404ff3f95a79118667f2d62082aa28e4ee7df5fad81e28071cd24b5455fe687a9f9bcf714718d4fd6036912b04c69a84 + checksum: 350d1f8043b7bbd88cf5d7fa28560062f4141e1ef9ef004c2997b63d0281d4a1af04be4b951c2c9c4d1c56d10f0e2fbab665c7176b38e87dd6da6d5303e1c84e languageName: node linkType: hard From e467708ca43384c97b04ce4b850a6f8eb26099e6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 27 Jun 2024 09:21:46 +0000 Subject: [PATCH 099/416] chore(deps): update dependency @playwright/test to v1.45.0 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 5d92f37a1d..66b353a237 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13734,13 +13734,13 @@ __metadata: linkType: hard "@playwright/test@npm:^1.32.3": - version: 1.44.1 - resolution: "@playwright/test@npm:1.44.1" + version: 1.45.0 + resolution: "@playwright/test@npm:1.45.0" dependencies: - playwright: 1.44.1 + playwright: 1.45.0 bin: playwright: cli.js - checksum: 90507b77e388aa984deb92db56f7bb3b305c6be441e1d0087ca046989cfdda068bbc26d75bd29c20ad3dbb2434e69a8ff0d6b30003b88c9234cd3aa6a9f7deb9 + checksum: 55fb72f393b05f6684b5098e0681712f71e1fe25aa6a00bd636133f9ccc26d096d61ee30f569b83368e4bf6a1288d2f8f6fd5364da5d396eab180f89f61b7164 languageName: node linkType: hard @@ -36647,27 +36647,27 @@ __metadata: languageName: node linkType: hard -"playwright-core@npm:1.44.1": - version: 1.44.1 - resolution: "playwright-core@npm:1.44.1" +"playwright-core@npm:1.45.0": + version: 1.45.0 + resolution: "playwright-core@npm:1.45.0" bin: playwright-core: cli.js - checksum: ebc6fa0ff77792fe52648fda06cc4474d4e9746db6dc5750d262b7fe2caf9f9e2327a71f1fb365e862213403a9daf95361c5040a9b0fd462928d7eb4fdc760e1 + checksum: e81a55eeefa997fcb559527127c9cefbbabe81f196de486224e6c2a3a66852dab883379ff28a05b8008fb0ad4992840ad53c2415cee27e2d1778836210d9248e languageName: node linkType: hard -"playwright@npm:1.44.1": - version: 1.44.1 - resolution: "playwright@npm:1.44.1" +"playwright@npm:1.45.0": + version: 1.45.0 + resolution: "playwright@npm:1.45.0" dependencies: fsevents: 2.3.2 - playwright-core: 1.44.1 + playwright-core: 1.45.0 dependenciesMeta: fsevents: optional: true bin: playwright: cli.js - checksum: c2e8ff0a855e4a9e665ae5ffa0ff90423289546157be55e83f78916d17075c5910a7244773739c2a973da884a4ff0b3cf9b6e6b543de112e43b12169a9208e86 + checksum: 2a5f827fdcc90f1ec0ea4d9e4f2021ae894df88d3c0577677a81f72a09d91fb15584346e63ec2f85bfc24f872976ff2a76cee6ca7d7f29a8cc3159ced4f25b50 languageName: node linkType: hard From 2defad94e3237184cdb6d1528a64dd8d8bcac021 Mon Sep 17 00:00:00 2001 From: blam Date: Thu, 27 Jun 2024 11:58:20 +0200 Subject: [PATCH 100/416] chore: disabled and readonly props are optional from rjsf now, let's default them to something sane Signed-off-by: blam --- plugins/scaffolder-react/src/next/components/Form/Form.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/scaffolder-react/src/next/components/Form/Form.tsx b/plugins/scaffolder-react/src/next/components/Form/Form.tsx index 8717c8b55a..05c8a4934f 100644 --- a/plugins/scaffolder-react/src/next/components/Form/Form.tsx +++ b/plugins/scaffolder-react/src/next/components/Form/Form.tsx @@ -44,6 +44,8 @@ export const Form = (props: PropsWithChildren) => { uiSchema={wrapperProps.uiSchema ?? {}} formData={wrapperProps.formData} rawErrors={wrapperProps.rawErrors ?? []} + disabled={wrapperProps.disabled ?? false} + readonly={wrapperProps.readonly ?? false} /> ); }, From f2f01f0350666208f05bf3e3ab45e38aeb33f8af Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 27 Jun 2024 10:08:54 +0000 Subject: [PATCH 101/416] fix(deps): update dependency prom-client to v15.1.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 66b353a237..8e50d73b0d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -37404,12 +37404,12 @@ __metadata: linkType: hard "prom-client@npm:^15.0.0": - version: 15.1.2 - resolution: "prom-client@npm:15.1.2" + version: 15.1.3 + resolution: "prom-client@npm:15.1.3" dependencies: "@opentelemetry/api": ^1.4.0 tdigest: ^0.1.1 - checksum: b9b2f439588a462c0aec840e8aa857bb0a77284174d6587ca042eb13ea6ac36ba13277f45ae6ed3696b3007a1020c5ee2c5ee46b23be033a7bb45207a5365c21 + checksum: 9a57f3c16f39aa9a03da021883a4231c0bb56fc9d02f6ef9c28f913379f275640a5a33b98d9946ebf53c71011a29b580e9d2d6e3806cb1c229a3f59c65993968 languageName: node linkType: hard From 31337accbab3a823b5911496a03084b0a69f1dea Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 27 Jun 2024 10:51:36 +0000 Subject: [PATCH 102/416] chore(deps): update dependency knip to v5.23.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 5322ef697d..2df9262dc5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -32065,8 +32065,8 @@ __metadata: linkType: hard "knip@npm:^5.0.0": - version: 5.22.2 - resolution: "knip@npm:5.22.2" + version: 5.23.1 + resolution: "knip@npm:5.23.1" dependencies: "@ericcornelissen/bash-parser": 0.5.3 "@nodelib/fs.walk": 2.0.0 @@ -32092,7 +32092,7 @@ __metadata: bin: knip: bin/knip.js knip-bun: bin/knip-bun.js - checksum: 995924973618391af39ba6bfb324f1f4dac427879a944eeecbcf48b61ec165f10f18196f27a7d079076f351223ed067bb917bc863e0424153c3fae2dd65582d6 + checksum: d3c39f266907b2c8f241e4d7d7c4b3a4fa1500c57f7e60f86bd3e9cd2684696e4c84b823d2a461b23cdc729a310ad571eec6ac22acacb5a4b17130d19ef5b866 languageName: node linkType: hard From e7098b6d9a8342ee98f46853698083127685566c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 27 Jun 2024 11:12:21 +0000 Subject: [PATCH 103/416] chore(deps): update dependency node-mocks-http to v1.15.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 259687412b..cc6d1c7d42 100644 --- a/yarn.lock +++ b/yarn.lock @@ -34817,8 +34817,8 @@ __metadata: linkType: hard "node-mocks-http@npm:^1.0.0": - version: 1.14.1 - resolution: "node-mocks-http@npm:1.14.1" + version: 1.15.0 + resolution: "node-mocks-http@npm:1.15.0" dependencies: "@types/express": ^4.17.21 "@types/node": ^20.10.6 @@ -34832,7 +34832,7 @@ __metadata: parseurl: ^1.3.3 range-parser: ^1.2.0 type-is: ^1.6.18 - checksum: cc37618fb5f44a6049f8fcfc73373c4b42943e35e4b0f7463939d3f219663fe647e00e6eb9c3b8aedd48e88e10e1542993ac1a7ff8442ee2c3f6b97f23ced0e0 + checksum: 9be3ef4eec1b283800bbae50d7615fb633c7d28a0bedcf13e2ddfaa7ed4aa865d00c1d26e929ee8d617b3734958d8c19345f615760004f1940a8268c9bbacf07 languageName: node linkType: hard From 53ae33ab796504a2b66460dd808e10829df1957b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 27 Jun 2024 11:40:47 +0000 Subject: [PATCH 104/416] fix(deps): update dependency @azure/identity to v4.3.0 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 43 ++++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/yarn.lock b/yarn.lock index 965d939677..a871cf4e0b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1660,6 +1660,15 @@ __metadata: languageName: node linkType: hard +"@azure/abort-controller@npm:^2.0.0": + version: 2.1.2 + resolution: "@azure/abort-controller@npm:2.1.2" + dependencies: + tslib: ^2.6.2 + checksum: 22176c04ea01498311c6bbd336669f6e3faffad1cbb0c9ebc6ee9c1ff2cf958fd17ce73c7354b99d8bda9fcd311325ece7bee248875279174e3fc460e8b1a63d + languageName: node + linkType: hard + "@azure/core-auth@npm:^1.3.0, @azure/core-auth@npm:^1.4.0, @azure/core-auth@npm:^1.5.0": version: 1.5.0 resolution: "@azure/core-auth@npm:1.5.0" @@ -1671,18 +1680,18 @@ __metadata: languageName: node linkType: hard -"@azure/core-client@npm:^1.4.0": - version: 1.7.3 - resolution: "@azure/core-client@npm:1.7.3" +"@azure/core-client@npm:^1.9.2": + version: 1.9.2 + resolution: "@azure/core-client@npm:1.9.2" dependencies: - "@azure/abort-controller": ^1.0.0 + "@azure/abort-controller": ^2.0.0 "@azure/core-auth": ^1.4.0 "@azure/core-rest-pipeline": ^1.9.1 "@azure/core-tracing": ^1.0.0 - "@azure/core-util": ^1.0.0 + "@azure/core-util": ^1.6.1 "@azure/logger": ^1.0.0 - tslib: ^2.2.0 - checksum: 155a188b75b2d5ea783d5fde50479337c41796736f0fced1576466c8251e429195c229f2aff0bf897761f15c19d8fd0deea9a54aab514bd3584e37140e3f0cdc + tslib: ^2.6.2 + checksum: 961b829dfda4f734a763e9480a2ea622a7031ba2da4126d0add6e351a9f73ddc5782bf2b766735d976b61da3857014e0a90223d1f85d1c68468747a7a56851c3 languageName: node linkType: hard @@ -1765,23 +1774,23 @@ __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.3.0": - version: 1.6.1 - resolution: "@azure/core-util@npm:1.6.1" +"@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.9.0 + resolution: "@azure/core-util@npm:1.9.0" dependencies: - "@azure/abort-controller": ^1.0.0 - tslib: ^2.2.0 - checksum: 1f8cd130993f161c98925070af863510cbcc79e0471864e4b16852afc2ee7413c9c7fabe72f20f3e521ee75c3cd7e3085661fdc8d5d0a643a6e1b1b7bf691ddd + "@azure/abort-controller": ^2.0.0 + tslib: ^2.6.2 + checksum: 9246dc5bd246e7b94883ea8130fce04e2f22abd1e94afcff7a3e92a4c2da5e9b382dbf89a606b21d70bc8b01c7c89c84e803ca9da27f78d87f72bdff91ec7380 languageName: node linkType: hard "@azure/identity@npm:^4.0.0": - version: 4.2.1 - resolution: "@azure/identity@npm:4.2.1" + version: 4.3.0 + resolution: "@azure/identity@npm:4.3.0" dependencies: "@azure/abort-controller": ^1.0.0 "@azure/core-auth": ^1.5.0 - "@azure/core-client": ^1.4.0 + "@azure/core-client": ^1.9.2 "@azure/core-rest-pipeline": ^1.1.0 "@azure/core-tracing": ^1.0.0 "@azure/core-util": ^1.3.0 @@ -1793,7 +1802,7 @@ __metadata: open: ^8.0.0 stoppable: ^1.1.0 tslib: ^2.2.0 - checksum: 2dbd7b0fa6b92904b7b8f828374d7316384cc4e00c71cdac3a2f2544b9e02c7287fe7ad58149bb8794c57913d77a927f5a7b5d1367e05abe82b0f2e1b162415c + checksum: 7f4256b39c4e27bf072c33f02dd63bd50dcf54ad578e3e483dcf89283546a6086b1640adfe4c93a537cbe483dd2e3a29f6d7b837e51f333229f7bbbc448966b3 languageName: node linkType: hard From 605df406e2ef874e16cedf39bdd8888267b55be0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 27 Jun 2024 12:30:58 +0000 Subject: [PATCH 105/416] fix(deps): update dependency @azure/storage-blob to v12.23.0 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 108 +++++++++++++++++++++++------------------------------- 1 file changed, 46 insertions(+), 62 deletions(-) diff --git a/yarn.lock b/yarn.lock index 7e09ea2f97..f1efc58328 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1669,7 +1669,7 @@ __metadata: languageName: node linkType: hard -"@azure/core-auth@npm:^1.3.0, @azure/core-auth@npm:^1.4.0, @azure/core-auth@npm:^1.5.0": +"@azure/core-auth@npm:^1.4.0, @azure/core-auth@npm:^1.5.0": version: 1.5.0 resolution: "@azure/core-auth@npm:1.5.0" dependencies: @@ -1680,7 +1680,7 @@ __metadata: languageName: node linkType: hard -"@azure/core-client@npm:^1.9.2": +"@azure/core-client@npm:^1.3.0, @azure/core-client@npm:^1.6.2, @azure/core-client@npm:^1.9.2": version: 1.9.2 resolution: "@azure/core-client@npm:1.9.2" dependencies: @@ -1695,25 +1695,14 @@ __metadata: languageName: node linkType: hard -"@azure/core-http@npm:^3.0.0": - version: 3.0.2 - resolution: "@azure/core-http@npm:3.0.2" +"@azure/core-http-compat@npm:^2.0.0": + version: 2.1.2 + resolution: "@azure/core-http-compat@npm:2.1.2" dependencies: - "@azure/abort-controller": ^1.0.0 - "@azure/core-auth": ^1.3.0 - "@azure/core-tracing": 1.0.0-preview.13 - "@azure/core-util": ^1.1.1 - "@azure/logger": ^1.0.0 - "@types/node-fetch": ^2.5.0 - "@types/tunnel": ^0.0.3 - form-data: ^4.0.0 - node-fetch: ^2.6.7 - process: ^0.11.10 - tslib: ^2.2.0 - tunnel: ^0.0.6 - uuid: ^8.3.0 - xml2js: ^0.5.0 - checksum: 01b5a75e09533476dbb69c672dcd00d48298cf81db5015cd261c510c5be377176db8e3dc4809e6952459bfbe214f52f8a1ed84a116ac31b8a7388b2025098f66 + "@azure/abort-controller": ^2.0.0 + "@azure/core-client": ^1.3.0 + "@azure/core-rest-pipeline": ^1.3.0 + checksum: 387d0187607d95a6876f63d4b689210bce6ad243f48e56413136ba3875a8a9c4e238813307fb0cf0c53298f4b9d0893d04321c9331812bc74cf0f4e3e6872069 languageName: node linkType: hard @@ -1738,30 +1727,19 @@ __metadata: languageName: node linkType: hard -"@azure/core-rest-pipeline@npm:^1.1.0, @azure/core-rest-pipeline@npm:^1.9.1": - version: 1.12.2 - resolution: "@azure/core-rest-pipeline@npm:1.12.2" +"@azure/core-rest-pipeline@npm:^1.1.0, @azure/core-rest-pipeline@npm:^1.10.1, @azure/core-rest-pipeline@npm:^1.3.0, @azure/core-rest-pipeline@npm:^1.9.1": + version: 1.16.1 + resolution: "@azure/core-rest-pipeline@npm:1.16.1" dependencies: - "@azure/abort-controller": ^1.0.0 + "@azure/abort-controller": ^2.0.0 "@azure/core-auth": ^1.4.0 "@azure/core-tracing": ^1.0.1 - "@azure/core-util": ^1.3.0 + "@azure/core-util": ^1.9.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 - checksum: a774ab2e87ff56d7f3ef1844a814bbd76264ea1c33534081d38ce6df1098d803d0b13b15912f9053d0695ca2669b0dd104c8feec8dbf24df80a3608ea784fc9e - languageName: node - linkType: hard - -"@azure/core-tracing@npm:1.0.0-preview.13": - version: 1.0.0-preview.13 - resolution: "@azure/core-tracing@npm:1.0.0-preview.13" - dependencies: - "@opentelemetry/api": ^1.0.1 - tslib: ^2.2.0 - checksum: bc3ea8dce1fc6bb6e4cb2e82ec0c361b3e6f6e18e162f352eb347e6991c6461ebc249f5d1b36402cc0d295e2a6bcbaa68014445d7f4293c0792a698c430f145e + http-proxy-agent: ^7.0.0 + https-proxy-agent: ^7.0.0 + tslib: ^2.6.2 + checksum: ab2c5b715c4ebb9f6554f12d8e804833be29db0f23868adc092f4841aa8c7f140a6821dbcd9fa046bfb31e435085f171a87dab3f97d851cf9a62127d042fa75e languageName: node linkType: hard @@ -1774,7 +1752,7 @@ __metadata: languageName: node linkType: hard -"@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": +"@azure/core-util@npm:^1.1.0, @azure/core-util@npm:^1.2.0, @azure/core-util@npm:^1.3.0, @azure/core-util@npm:^1.6.1, @azure/core-util@npm:^1.9.0": version: 1.9.0 resolution: "@azure/core-util@npm:1.9.0" dependencies: @@ -1784,6 +1762,16 @@ __metadata: languageName: node linkType: hard +"@azure/core-xml@npm:^1.3.2": + version: 1.4.2 + resolution: "@azure/core-xml@npm:1.4.2" + dependencies: + fast-xml-parser: ^4.3.2 + tslib: ^2.6.2 + checksum: f3815db55f0280db6080a3fc5b6187ad45cacf5c3842ea806a5565886edf2ebf2fa9fc1175407cf58d462341962a8396513943543b332b37b313ac3a79dc28fa + languageName: node + linkType: hard + "@azure/identity@npm:^4.0.0": version: 4.3.0 resolution: "@azure/identity@npm:4.3.0" @@ -1850,18 +1838,23 @@ __metadata: linkType: hard "@azure/storage-blob@npm:^12.5.0": - version: 12.17.0 - resolution: "@azure/storage-blob@npm:12.17.0" + version: 12.23.0 + resolution: "@azure/storage-blob@npm:12.23.0" dependencies: "@azure/abort-controller": ^1.0.0 - "@azure/core-http": ^3.0.0 + "@azure/core-auth": ^1.4.0 + "@azure/core-client": ^1.6.2 + "@azure/core-http-compat": ^2.0.0 "@azure/core-lro": ^2.2.0 "@azure/core-paging": ^1.1.1 - "@azure/core-tracing": 1.0.0-preview.13 + "@azure/core-rest-pipeline": ^1.10.1 + "@azure/core-tracing": ^1.0.0 + "@azure/core-util": ^1.6.1 + "@azure/core-xml": ^1.3.2 "@azure/logger": ^1.0.0 events: ^3.0.0 tslib: ^2.2.0 - checksum: 2e5d3f26577f698498bba7ff7b7cfeb942709a713d9c72864b80633bee28e2b369370afc55f18e49ccc02b4dad9d1de3a4602caa99dce1f8d8196c8472a8add1 + checksum: 7f09b4bfae0d73f7cf8f383038edeaf8bc8610960bc24a9b8c140f4084bb3afd62971fb56e2ff5e013168165dcfff7b9a545f6cc837fe2669618184e4b77c107 languageName: node linkType: hard @@ -12490,7 +12483,7 @@ __metadata: languageName: node linkType: hard -"@opentelemetry/api@npm:^1.0.0, @opentelemetry/api@npm:^1.0.1, @opentelemetry/api@npm:^1.3.0, @opentelemetry/api@npm:^1.4.0": +"@opentelemetry/api@npm:^1.0.0, @opentelemetry/api@npm:^1.3.0, @opentelemetry/api@npm:^1.4.0": version: 1.8.0 resolution: "@opentelemetry/api@npm:1.8.0" checksum: 0e32079975f05bee6de2ad8ade097f0afdc63f462c76550150fce2444c73ab92aaf851ac85e638b6e3b269da6640ac7e63f33913a0fd7df9f9beec2e100759df @@ -18152,7 +18145,7 @@ __metadata: languageName: node linkType: hard -"@types/node-fetch@npm:^2.5.0, @types/node-fetch@npm:^2.5.12": +"@types/node-fetch@npm:^2.5.12": version: 2.6.11 resolution: "@types/node-fetch@npm:2.6.11" dependencies: @@ -18873,15 +18866,6 @@ __metadata: languageName: node linkType: hard -"@types/tunnel@npm:^0.0.3": - version: 0.0.3 - resolution: "@types/tunnel@npm:0.0.3" - dependencies: - "@types/node": "*" - checksum: 53e23a1f9fb14a491c00425b2a4fc443817564d77be5e1b95fcbeb6d009551b62ea82ffc3e5ca0c6b9f6b186824ca6ec46e7450c1bcd6674a46d1325f0116e24 - languageName: node - linkType: hard - "@types/unist@npm:*, @types/unist@npm:^2.0.0": version: 2.0.6 resolution: "@types/unist@npm:2.0.6" @@ -27181,14 +27165,14 @@ __metadata: languageName: node linkType: hard -"fast-xml-parser@npm:^4.3.0": - version: 4.3.2 - resolution: "fast-xml-parser@npm:4.3.2" +"fast-xml-parser@npm:^4.3.0, fast-xml-parser@npm:^4.3.2": + version: 4.4.0 + resolution: "fast-xml-parser@npm:4.4.0" dependencies: strnum: ^1.0.5 bin: fxparser: src/cli/cli.js - checksum: d507ce2efa5fd13d0a5ba28bd76dd68f2fc30ad8748357c37b70f360d19417866d79e35a688af067d5bceaaa796033fa985206aef9692f7a421e1326b6e73309 + checksum: ad33a4b5165a0ffcb6e17ae78825bd4619a8298844a8a8408f2ea141a0d2d9439d18865dc5254162f09fe54d510ff18e5d5c0a190869cab21fc745ee66be816b languageName: node linkType: hard @@ -29202,7 +29186,7 @@ __metadata: languageName: node linkType: hard -"https-proxy-agent@npm:7.0.4, https-proxy-agent@npm:^7.0.1, https-proxy-agent@npm:^7.0.2": +"https-proxy-agent@npm:7.0.4, https-proxy-agent@npm:^7.0.0, https-proxy-agent@npm:^7.0.1, https-proxy-agent@npm:^7.0.2": version: 7.0.4 resolution: "https-proxy-agent@npm:7.0.4" dependencies: From bfc2fb356c5c330a29c6e5f6276d143d29d37f3d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 27 Jun 2024 12:31:57 +0000 Subject: [PATCH 106/416] fix(deps): update dependency @codemirror/view to v6.28.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 7e09ea2f97..9a906af154 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8502,13 +8502,13 @@ __metadata: linkType: hard "@codemirror/view@npm:^6.0.0, @codemirror/view@npm:^6.23.0": - version: 6.26.3 - resolution: "@codemirror/view@npm:6.26.3" + version: 6.28.2 + resolution: "@codemirror/view@npm:6.28.2" dependencies: "@codemirror/state": ^6.4.0 style-mod: ^4.1.0 w3c-keyname: ^2.2.4 - checksum: fdee35fb5e0bbba7b6f1a9b43a865880911bbfafd30360da5dda21b35f81ba2d080ff66b6c3d94dbe946b6b7ec98a76208786360b8f030ef10bcb054b816de05 + checksum: d2d36d7bbb1fc094fb421251b96144b67a932f43d12092bd2318ced283db0081e6e78cc99c5cecf9eedd24278d39fe41deaa490fcc03637d85c5cf332af58fec languageName: node linkType: hard From fb3ef145d355581066d4314573d30ad1607c6f31 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 27 Jun 2024 12:32:58 +0000 Subject: [PATCH 107/416] fix(deps): update dependency @google-cloud/container to v5.15.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 7e09ea2f97..a29356da1d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9475,11 +9475,11 @@ __metadata: linkType: hard "@google-cloud/container@npm:^5.0.0": - version: 5.12.0 - resolution: "@google-cloud/container@npm:5.12.0" + version: 5.15.0 + resolution: "@google-cloud/container@npm:5.15.0" dependencies: google-gax: ^4.0.3 - checksum: bf22c6754d67b133f272522b41f9f383e960a3288847d345407a171cce593856527cd3ee3df13bb4b09091bfce03f3404d24559ce2c28733ce71866068fb5277 + checksum: e31332b17816688f0cf831c66ef1ccc24c7600e4ec798fdeed33b66ed934372b1a962e92c665903bae661db5aaf872d79becc7d67b3f9c6a55b403acdfd534ec languageName: node linkType: hard From efb4e480897b9b72c75eeda8cf545210e07b8ae8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 27 Jun 2024 14:18:13 +0000 Subject: [PATCH 108/416] fix(deps): update dependency @jest-mock/express to v2.1.0 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/yarn.lock b/yarn.lock index 7c407dc27e..6f4f365ea1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10225,11 +10225,11 @@ __metadata: linkType: hard "@jest-mock/express@npm:^2.0.1": - version: 2.0.2 - resolution: "@jest-mock/express@npm:2.0.2" + version: 2.1.0 + resolution: "@jest-mock/express@npm:2.1.0" dependencies: - "@types/express": ^4.17.17 - checksum: 558feb47e7e9620a5e53b83c51b3802782ecf7ab32b8d81077b16f641b7e1a6dc6fffa652d2ab48b28ba0f0634fa6387bd21b08f62b92bd730dfca167a4c2795 + "@types/express": ^4.17.21 + checksum: 305b72c214c1e80ed16271aa48e4d6d906346f5221a4e873d1e8ae48c32c2316cb88bed819b195c934c339b9ab41d4b34c4e41ac66feefe980d2cd16bc0b6d20 languageName: node linkType: hard @@ -17562,7 +17562,7 @@ __metadata: languageName: node linkType: hard -"@types/express@npm:*, @types/express@npm:^4.17.14, @types/express@npm:^4.17.17, @types/express@npm:^4.17.21, @types/express@npm:^4.17.6": +"@types/express@npm:*, @types/express@npm:^4.17.14, @types/express@npm:^4.17.21, @types/express@npm:^4.17.6": version: 4.17.21 resolution: "@types/express@npm:4.17.21" dependencies: From 715f8d5dc08e2eb9327ecb4ae2c74b031d84355c Mon Sep 17 00:00:00 2001 From: mario ma Date: Thu, 27 Jun 2024 23:35:22 +0800 Subject: [PATCH 109/416] fix: update by review comments Signed-off-by: mario ma --- plugins/catalog-react/api-report-alpha.md | 14 +++++----- .../EntityLifecyclePicker.tsx | 2 +- .../EntityNamespacePicker.tsx | 2 +- .../EntityOwnerPicker/EntityOwnerPicker.tsx | 2 +- .../EntityProcessingStatusPicker.tsx | 2 +- .../EntitySearchBar/EntitySearchBar.tsx | 2 +- .../EntityTagPicker/EntityTagPicker.tsx | 2 +- .../FavoriteEntity/FavoriteEntity.tsx | 2 +- plugins/catalog-react/src/translation.ts | 26 ++++++++++++++----- 9 files changed, 33 insertions(+), 21 deletions(-) diff --git a/plugins/catalog-react/api-report-alpha.md b/plugins/catalog-react/api-report-alpha.md index ea01122ccc..b82c7ae3e2 100644 --- a/plugins/catalog-react/api-report-alpha.md +++ b/plugins/catalog-react/api-report-alpha.md @@ -33,21 +33,21 @@ export const catalogReactTranslationRef: TranslationRef< readonly 'catalogFilter.buttonTitle': 'Filters'; readonly 'entityKindPicker.title': 'Kind'; readonly 'entityKindPicker.errorMessage': 'Failed to load entity kinds'; - readonly entityLifecyclePickerTitle: 'Lifecycle'; - readonly entityNamespacePickerTitle: 'Namespace'; - readonly entityOwnerPickerTitle: 'Owner'; + readonly 'entityLifecyclePicker.title': 'Lifecycle'; + readonly 'entityNamespacePicker.title': 'Namespace'; + readonly 'entityOwnerPicker.title': 'Owner'; + readonly 'entityProcessingStatusPicker.title': 'Processing Status'; + readonly 'entityTagPicker.title': 'Tags'; readonly 'entityPeekAheadPopover.title': 'Drill into the entity to see all of the tags.'; readonly 'entityPeekAheadPopover.entityCardActionsTitle': 'Show details'; readonly 'entityPeekAheadPopover.emailCardAction.title': 'Email {{email}}'; readonly 'entityPeekAheadPopover.emailCardAction.subTitle': 'mailto {{email}}'; - readonly entityProcessingStatusPickerTitle: 'Processing Status'; - readonly entitySearchBarPlaceholder: 'Search'; - readonly entityTagPickerTitle: 'Tags'; + readonly 'entitySearchBar.placeholder': 'Search'; readonly 'entityTypePicker.title': 'Type'; readonly 'entityTypePicker.errorMessage': 'Failed to load entity types'; readonly 'entityTypePicker.optionAllTitle': 'all'; readonly 'favoriteEntity.addToFavorites': 'Add to favorites'; - readonly 'favoriteEntity.RemoveFromFavorites': 'Remove from favorites'; + readonly 'favoriteEntity.removeFromFavorites': 'Remove from favorites'; readonly 'inspectEntityDialog.title': 'Entity Inspector'; readonly 'inspectEntityDialog.closeButtonTitle': 'Close'; readonly 'inspectEntityDialog.ancestryPage.title': 'Ancestry'; diff --git a/plugins/catalog-react/src/components/EntityLifecyclePicker/EntityLifecyclePicker.tsx b/plugins/catalog-react/src/components/EntityLifecyclePicker/EntityLifecyclePicker.tsx index 3c4e9e5573..2d8a0dea32 100644 --- a/plugins/catalog-react/src/components/EntityLifecyclePicker/EntityLifecyclePicker.tsx +++ b/plugins/catalog-react/src/components/EntityLifecyclePicker/EntityLifecyclePicker.tsx @@ -41,7 +41,7 @@ export const EntityLifecyclePicker = (props: { initialFilter?: string[] }) => { return ( { return ( { return ( - {t('entityOwnerPickerTitle')} + {t('entityOwnerPicker.title')} (
    {popperProps.children as ReactNode}
    diff --git a/plugins/catalog-react/src/components/EntityProcessingStatusPicker/EntityProcessingStatusPicker.tsx b/plugins/catalog-react/src/components/EntityProcessingStatusPicker/EntityProcessingStatusPicker.tsx index 08ce756923..20190a9907 100644 --- a/plugins/catalog-react/src/components/EntityProcessingStatusPicker/EntityProcessingStatusPicker.tsx +++ b/plugins/catalog-react/src/components/EntityProcessingStatusPicker/EntityProcessingStatusPicker.tsx @@ -74,7 +74,7 @@ export const EntityProcessingStatusPicker = () => { return ( - {t('entityProcessingStatusPickerTitle')} + {t('entityProcessingStatusPicker.title')} PopperComponent={popperProps => (
    {popperProps.children as ReactNode}
    diff --git a/plugins/catalog-react/src/components/EntitySearchBar/EntitySearchBar.tsx b/plugins/catalog-react/src/components/EntitySearchBar/EntitySearchBar.tsx index 671d582a57..abde5430bc 100644 --- a/plugins/catalog-react/src/components/EntitySearchBar/EntitySearchBar.tsx +++ b/plugins/catalog-react/src/components/EntitySearchBar/EntitySearchBar.tsx @@ -88,7 +88,7 @@ export const EntitySearchBar = () => { aria-label="search" id="input-with-icon-adornment" className={classes.input} - placeholder={t('entitySearchBarPlaceholder')} + placeholder={t('entitySearchBar.placeholder')} autoComplete="off" onChange={event => setSearch(event.target.value)} value={search} diff --git a/plugins/catalog-react/src/components/EntityTagPicker/EntityTagPicker.tsx b/plugins/catalog-react/src/components/EntityTagPicker/EntityTagPicker.tsx index a18e4f3b4e..2ab3622474 100644 --- a/plugins/catalog-react/src/components/EntityTagPicker/EntityTagPicker.tsx +++ b/plugins/catalog-react/src/components/EntityTagPicker/EntityTagPicker.tsx @@ -41,7 +41,7 @@ export const EntityTagPicker = (props: EntityTagPickerProps) => { return ( { diff --git a/plugins/catalog-react/src/translation.ts b/plugins/catalog-react/src/translation.ts index 685bf1fd00..7f9661380f 100644 --- a/plugins/catalog-react/src/translation.ts +++ b/plugins/catalog-react/src/translation.ts @@ -28,9 +28,21 @@ export const catalogReactTranslationRef = createTranslationRef({ title: 'Kind', errorMessage: 'Failed to load entity kinds', }, - entityLifecyclePickerTitle: 'Lifecycle', - entityNamespacePickerTitle: 'Namespace', - entityOwnerPickerTitle: 'Owner', + entityLifecyclePicker: { + title: 'Lifecycle', + }, + entityNamespacePicker: { + title: 'Namespace', + }, + entityOwnerPicker: { + title: 'Owner', + }, + entityProcessingStatusPicker: { + title: 'Processing Status', + }, + entityTagPicker: { + title: 'Tags', + }, entityPeekAheadPopover: { title: 'Drill into the entity to see all of the tags.', emailCardAction: { @@ -39,9 +51,9 @@ export const catalogReactTranslationRef = createTranslationRef({ }, entityCardActionsTitle: 'Show details', }, - entityProcessingStatusPickerTitle: 'Processing Status', - entitySearchBarPlaceholder: 'Search', - entityTagPickerTitle: 'Tags', + entitySearchBar: { + placeholder: 'Search', + }, entityTypePicker: { title: 'Type', errorMessage: 'Failed to load entity types', @@ -49,7 +61,7 @@ export const catalogReactTranslationRef = createTranslationRef({ }, favoriteEntity: { addToFavorites: 'Add to favorites', - RemoveFromFavorites: 'Remove from favorites', + removeFromFavorites: 'Remove from favorites', }, inspectEntityDialog: { title: 'Entity Inspector', From e36966c3e9d4536c33b79b8d4640dbcb1e30863c Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Thu, 27 Jun 2024 18:50:05 +0200 Subject: [PATCH 110/416] docs: create backstage engineer journey post Signed-off-by: Camila Belo --- .../2024-06-27-backstage-engineer-journey.mdx | 135 +++++++ .../2024-06-27/backstage-engineer-journey.svg | 362 ++++++++++++++++++ 2 files changed, 497 insertions(+) create mode 100644 microsite/blog/2024-06-27-backstage-engineer-journey.mdx create mode 100644 microsite/blog/assets/2024-06-27/backstage-engineer-journey.svg diff --git a/microsite/blog/2024-06-27-backstage-engineer-journey.mdx b/microsite/blog/2024-06-27-backstage-engineer-journey.mdx new file mode 100644 index 0000000000..b9bfc20e4e --- /dev/null +++ b/microsite/blog/2024-06-27-backstage-engineer-journey.mdx @@ -0,0 +1,135 @@ +--- +# prettier-ignore +title: "1,186 days with Backstage: A journey through the eyes of a developer" +author: Camila Loiola, Spotify +authorURL: https://github.com/camilaibs +authorImageURL: https://avatars.githubusercontent.com/u/6290749?v=4 +--- + +**TL;DR** There is no shortage of content that discusses the benefits that Backstage brings to organizations (and if you want to read more on that, you can just click [here](https://engineering.atspotify.com/category/backstage/), [here](https://backstage.io/blog), or [here](https://backstage.spotify.com/discover/blog/)). But I want to share what it did for me, a developer here at Spotify. And not just what it did, but how I’ve used Backstage to help me achieve goals at each stage of my journey at Spotify — from my first day as a brand new employee to today, my 1,186th day as a contributor. + +![Backstage Engineer Journey](assets/2024-06-27/backstage-engineer-journey.svg) + +{/* truncate */} + +## A new joiner with a need to get up to speed + +My first six months after joining Spotify, I was eager and determined to get up to speed so that I’d be able to start contributing as soon as possible. I set goals for myself and developed concrete activities to reach those goals: + +### Goal 1: Learn the internal process to develop, test, secure, and publish applications. + +Understanding a company’s practices and technologies is absolutely essential to getting started, no matter what company you join. + +At Spotify, we use a Backstage plugin called [TechDocs](https://backstage.io/docs/features/techdocs/) to document [Golden Paths](https://engineering.atspotify.com/2020/08/how-we-use-golden-paths-to-solve-fragmentation-in-our-software-ecosystem/) — tutorials that teach us the development process for each role at the company — for web, backend, mobile, data science development, and so on. + +With Backstage, I had an understanding of how to put things into production, even before I had my first task. I used the web Golden Path to guide me on setting up my environment; creating and structuring projects; and building, publishing, and monitoring production applications. + +> **Reflection:**
    _“Is it easy for newly hired engineers to settle in and find information critical to getting started?”_ + +With Backstage, new hires can quickly and easily understand the nuances of their particular positions and be ready to deliver their first task to production. + +### Goal 2: Find and read the documentation and source code of the products my team maintains. + +Having familiarized myself with the ways of working, it was a good time to understand my specific team’s business domain. This meant spending time reading through documentation and source code to find out the value we provide to our customers. In the past, I would spend time with colleagues for knowledge transfer as opposed to learning on my own and consult my colleagues if needed. + +With the [Backstage Software Catalog](https://backstage.io/docs/features/software-catalog/), I could easily browse the components my team owns, find the source repo and documentation. + +> **Reflection:**
    _“Are you able to accomplish this without asking a teammate for help?”_ + +Use Backstage to get to know the products that you will be working on, and use your peers' time to ask contextualized clarifying questions instead. + +### Goal 3: Figure out where my team fits within the company and with other teams. + +It was also crucial for me to build a network from the beginning so that I could explore collaboration opportunities. + +At Spotify, we use a Backstage plugin called Band Manager which displays information about each team and allows employees to see not only their own teams but also those within the same product area and company domain. + +> **Reflection:**
    _“Are you going to need a one-on-one with your manager to ask this question?”_ + +Backstage helped me find the teams close to mine, and I took the opportunity to develop my network and talk to members from those teams to understand our boundaries and gather ideas to contribute. + +It’s pretty likely that you can relate to one or more of these examples, so use Backstage to support your goals from the very beginning! + +Now let’s move on to the middle of the journey, between six months and two years into life at the company. + +## Two years in — from contributor to leader + +After about two years of contributing to my team’s products, I began to look for opportunities to actually lead initiatives and create a new project. One of my objectives was to ensure I was upholding Spotify’s standards and choosing Spotify-approved technologies. + +My goal has changed from being a contributor to being the driver, i.e., from doing what I was told to do to defining what needed to be done. I “started driving initiatives” and “supporting my peers” in order to position myself as a reference in my technical area. + +### Goal 1: Quickly spin up new projects using the most appropriate technology stack. + +At Spotify, we expect engineers to use technologies approved by our [Tech Radar](https://backstage.io/blog/2020/05/14/tech-radar-plugin/#what-is-tech-radar) and follow the best quality standards. + +To do so, we use a plugin called [Scaffolder](https://backstage.io/docs/reference/plugin-scaffolder) (aka Software Templates), which allows engineers to create templates for setting up new projects. Templates automate actions such as creating repositories, allocating resources, registering in the catalog, configuring deployments, and connecting to other internal systems. + +> **Reflection:**
    _“Do you need to create a ticket to get these things done before you even start coding? And is there a lot of time spent looking for boilerplate code to start a new project and connecting it to other internal systems?"_ + +Backstage enabled me to quickly create and publish a new backend that can deploy code to production with just a few clicks, so I could focus on building solutions for the business. I could use Backstage to easily build the right thing. Instead of spending time scaffolding projects, I could spend my time writing code. + +### Goal 2: Create products that have a healthy operational state and are easy to evolve. + +Keeping track of vulnerabilities and letting my team know about technical debts were other parts of my routine. + +With the [Soundcheck plugin](https://backstage.spotify.com/marketplace/spotify/plugin/soundcheck/), developers can easily configure checks to verify component health, such as reliability and other development and operational standards. We also have an internal Vulnerabilities plugin that displays fragilities in our components, so we can continuously prevent security issues. + +> **Reflection:**
    _“Do you know which components owned by your team follows best practices and standards and which ones are lagging behind?”_ + +Backstage helped me gather and better understand our technical debts, enabling me to effectively prioritize during our team’s planning, visualize which entities were compliant to our team’s best practices, and identify which ones needed improvement. + +### Goal 3: Respond effectively to incidents within our components or their dependencies. + +If you’ve been with a company for around two years, you might have had to manage incidents in one way or another — this was certainly the case for me. A typical problem was to determine if the issue is with the service that I own or a downstream dependency. + +Spotify has adopted [PagerDuty](https://backstage.spotify.com/marketplace/pagerduty/plugin/pagerduty/) to manage on-call rotation and to track incident resolutions. We integrated the PagerDuty plugin in Backstage, so we see who is on call and if there is an incident for a particular component. + +> **Reflection:**
    _“When a downstream dependency is failing, do you know who to contact?”_ + +In the event that one of our components starts failing, I check whether any of the systems we rely on is experiencing an incident, and Backstage again makes it easy for me to see the dependencies between systems and the status of those dependencies. + +## Today and beyond! + +With three-plus years of experience at Spotify, I’m taking on more and more responsibility by embracing challenges outside my team’s scope, coordinating cross-team collaboration, attending and facilitating courses for personal development and growth, and mentoring my peers. + +Backstage has allowed me to drive my pursuit of growth in a multitude of ways. + +### Goal 1: Stay in the flow and optimize my time management practices. + +At this point, finding time to focus — with all that I have on my plate — while also making time to learn new concepts is both fundamental and challenging for me. + +Spotify encourages its developers to manage their time in order to stay in the flow and to turn to the tools that help them prioritize effectively and focus on their work. + +> **Reflection:**
    _“How do you surface the most important notifications and avoid non-emergency distractions?”_ + +Backstage has been instrumental in helping me stay in the flow by surfacing the most critical notifications and call to actions related to cost spikes, security vulnerabilities in my homepage. + +### Goal 2: Platformize our solutions and reuse code to boost my productivity. + +Reinventing the wheel is a common problem in software development and Spotify is no different. + +Autonomous teams tend to prioritize speed over reuse and develop the same solutions in different places (1) as it unblocks the delivery for their team and (2) there is no easy way to discover if a particular functionality has been developed in another part of the company and if it can be reused for their requirement. + +> **Reflection:**
    _“Do you find yourself wondering if someone else already did it before starting a task?”_ + +With the [Backstage Search plugin](https://backstage.io/docs/features/search/), I can discover solutions to reuse, find inspiration, and also share what I’ve built for other developers to discover and use. + +### Goal 3: Grow my career and take steps toward the next level. + +I began looking for opportunities to gain new experiences and responsibilities while expanding my knowledge. + +With Spotify’s [Skill Exchange plugin](https://backstage.spotify.com/marketplace/spotify/plugin/skill-exchange/) for Backstage, engineers temporarily embed with a different team, allowing them to partake in work outside their day-to-day. The plugin also helps engineers connect with mentees or mentors that align with their skills profiles. + +> **Reflection:**
    _“Are you able to find opportunities that match your current skill set?”_ + +With Backstage, I've applied for an embed to experience working with another team and eventually make a permanent move to this new team, calling it my new home. + +I am passionate about teaching and eager to share my knowledge to help others. Through Skill Exchange, I found a mentee, a colleague transitioning into engineering, and I am helping them take their first steps. + +## What’s next? + +Backstage is highly customizable, and with its extensive plugin ecosystem, engineers can use it strategically to achieve their goals. + +No matter what point in your journey you are, you can find value with [Backstage](http://backstage.io). It was, after all, made by engineers for engineers. 💚 + +Special thanks to [Stanley Nicholl](https://github.com/stanley-nicholl), [Patrik Oldsberg](https://github.com/Rugvip), [Vincenzo Scamporlino](https://github.com/vinzscam), [Mihai Tabara](https://github.com/MihaiTabara), [Emma Indal](https://github.com/emmaindal), [Raghunandan Balachandran](https://github.com/soapraj) for all of their support. diff --git a/microsite/blog/assets/2024-06-27/backstage-engineer-journey.svg b/microsite/blog/assets/2024-06-27/backstage-engineer-journey.svg new file mode 100644 index 0000000000..1e302206a5 --- /dev/null +++ b/microsite/blog/assets/2024-06-27/backstage-engineer-journey.svg @@ -0,0 +1,362 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From a629fb22914852cd5f2c2e431b372833773c5156 Mon Sep 17 00:00:00 2001 From: 1337 <19777147+the-serious-programmer@users.noreply.github.com> Date: Thu, 27 Jun 2024 17:26:29 +0000 Subject: [PATCH 111/416] Added setAllowedLocationTypes with new CatalogLocationsExtensionPoint Signed-off-by: The serious programmer <19777147+the-serious-programmer@users.noreply.github.com> Signed-off-by: 1337 <19777147+the-serious-programmer@users.noreply.github.com> --- .changeset/hip-hairs-exist.md | 6 +++++ .../src/service/CatalogPlugin.ts | 26 +++++++++++++++++++ plugins/catalog-node/api-report-alpha.md | 8 ++++++ plugins/catalog-node/src/alpha.ts | 2 ++ plugins/catalog-node/src/extensions.ts | 19 ++++++++++++++ 5 files changed, 61 insertions(+) create mode 100644 .changeset/hip-hairs-exist.md diff --git a/.changeset/hip-hairs-exist.md b/.changeset/hip-hairs-exist.md new file mode 100644 index 0000000000..d8cb939dfb --- /dev/null +++ b/.changeset/hip-hairs-exist.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-catalog-backend': patch +'@backstage/plugin-catalog-node': patch +--- + +Added setAllowedLocationTypes while introducing a new extension point called CatalogLocationsExtensionPoint diff --git a/plugins/catalog-backend/src/service/CatalogPlugin.ts b/plugins/catalog-backend/src/service/CatalogPlugin.ts index aebd969701..2f5fd9103d 100644 --- a/plugins/catalog-backend/src/service/CatalogPlugin.ts +++ b/plugins/catalog-backend/src/service/CatalogPlugin.ts @@ -28,6 +28,8 @@ import { catalogPermissionExtensionPoint, CatalogProcessingExtensionPoint, catalogProcessingExtensionPoint, + CatalogLocationsExtensionPoint, + catalogLocationsExtensionPoint, } from '@backstage/plugin-catalog-node/alpha'; import { CatalogProcessor, @@ -41,6 +43,20 @@ import { merge } from 'lodash'; import { Permission } from '@backstage/plugin-permission-common'; import { ForwardedError } from '@backstage/errors'; +class CatalogLocationsExtensionPointImpl + implements CatalogLocationsExtensionPoint +{ + #locationTypes = new Array(); + + setAllowedLocationTypes(locationTypes: Array) { + this.#locationTypes = locationTypes; + } + + get allowedLocationTypes() { + return this.#locationTypes; + } +} + class CatalogProcessingExtensionPointImpl implements CatalogProcessingExtensionPoint { @@ -199,6 +215,12 @@ export const catalogPlugin = createBackendPlugin({ const modelExtensions = new CatalogModelExtensionPointImpl(); env.registerExtensionPoint(catalogModelExtensionPoint, modelExtensions); + const locationTypeExtensions = new CatalogLocationsExtensionPointImpl(); + env.registerExtensionPoint( + catalogLocationsExtensionPoint, + locationTypeExtensions, + ); + env.registerInit({ deps: { logger: coreServices.logger, @@ -271,6 +293,10 @@ export const catalogPlugin = createBackendPlugin({ builder.addPermissionRules(...permissionExtensions.permissionRules); builder.setFieldFormatValidators(modelExtensions.fieldValidators); + builder.setAllowedLocationTypes( + locationTypeExtensions.allowedLocationTypes, + ); + const { processingEngine, router } = await builder.build(); lifecycle.addStartupHook(async () => { diff --git a/plugins/catalog-node/api-report-alpha.md b/plugins/catalog-node/api-report-alpha.md index b61d1b1d27..e14f55c196 100644 --- a/plugins/catalog-node/api-report-alpha.md +++ b/plugins/catalog-node/api-report-alpha.md @@ -34,6 +34,14 @@ export interface CatalogAnalysisExtensionPoint { // @alpha (undocumented) export const catalogAnalysisExtensionPoint: ExtensionPoint; +// @alpha (undocumented) +export interface CatalogLocationsExtensionPoint { + setAllowedLocationTypes(locationTypes: Array): void; +} + +// @alpha (undocumented) +export const catalogLocationsExtensionPoint: ExtensionPoint; + // @alpha (undocumented) export interface CatalogModelExtensionPoint { setEntityDataParser(parser: CatalogProcessorParser): void; diff --git a/plugins/catalog-node/src/alpha.ts b/plugins/catalog-node/src/alpha.ts index 91b5bb99b6..b75ec48a7f 100644 --- a/plugins/catalog-node/src/alpha.ts +++ b/plugins/catalog-node/src/alpha.ts @@ -15,6 +15,8 @@ */ export { catalogServiceRef } from './catalogService'; +export type { CatalogLocationsExtensionPoint } from './extensions'; +export { catalogLocationsExtensionPoint } from './extensions'; export type { CatalogProcessingExtensionPoint } from './extensions'; export { catalogProcessingExtensionPoint } from './extensions'; export type { CatalogAnalysisExtensionPoint } from './extensions'; diff --git a/plugins/catalog-node/src/extensions.ts b/plugins/catalog-node/src/extensions.ts index 7c1fe6c30d..a971e1588d 100644 --- a/plugins/catalog-node/src/extensions.ts +++ b/plugins/catalog-node/src/extensions.ts @@ -31,6 +31,25 @@ import { } from '@backstage/plugin-permission-common'; import { PermissionRule } from '@backstage/plugin-permission-node'; +/** + * @alpha + */ +export interface CatalogLocationsExtensionPoint { + /** + * Allows setting custom location types, such as showcased in: https://backstage.io/docs/features/software-catalog/external-integrations/#creating-a-catalog-data-reader-processor + * @param locationTypes - List of location types to allow, default is "url" and "file" + */ + setAllowedLocationTypes(locationTypes: Array): void; +} + +/** + * @alpha + */ +export const catalogLocationsExtensionPoint = + createExtensionPoint({ + id: 'catalog.locations', + }); + /** * @alpha */ From 8a4c24e036daf76220b27c28f55178b8c1ea8814 Mon Sep 17 00:00:00 2001 From: Alex Lorenzi Date: Wed, 26 Jun 2024 17:21:37 -0400 Subject: [PATCH 112/416] Rollback the changes in #25332 Add MutationObserver in useShadowRootElements to we can trigger update when the elements under the shadow root change Signed-off-by: Alex Lorenzi Signed-off-by: Jackson Chen --- plugins/techdocs-react/src/context.tsx | 9 +------ plugins/techdocs-react/src/hooks.ts | 25 ++++++++++++++++--- .../TechDocsReaderPageContent.tsx | 4 +-- 3 files changed, 24 insertions(+), 14 deletions(-) diff --git a/plugins/techdocs-react/src/context.tsx b/plugins/techdocs-react/src/context.tsx index 2e7cd9586d..43fdada98e 100644 --- a/plugins/techdocs-react/src/context.tsx +++ b/plugins/techdocs-react/src/context.tsx @@ -25,7 +25,6 @@ import React, { } from 'react'; import useAsync, { AsyncState } from 'react-use/esm/useAsync'; import useAsyncRetry from 'react-use/esm/useAsyncRetry'; -import useCounter from 'react-use/esm/useCounter'; import { CompoundEntityRef, @@ -65,8 +64,6 @@ export type TechDocsReaderPageValue = { entityMetadata: AsyncState; shadowRoot?: ShadowRoot; setShadowRoot: Dispatch>; - shadowRootVersion: number; - incShadowRootVersion: () => void; title: string; setTitle: Dispatch>; subtitle: string; @@ -83,8 +80,6 @@ const defaultTechDocsReaderPageValue: TechDocsReaderPageValue = { setTitle: () => {}, setSubtitle: () => {}, setShadowRoot: () => {}, - shadowRootVersion: 0, - incShadowRootVersion: () => {}, metadata: { loading: true }, entityMetadata: { loading: true }, entityRef: { kind: '', name: '', namespace: '' }, @@ -139,7 +134,6 @@ export const TechDocsReaderPageProvider = memo( const [shadowRoot, setShadowRoot] = useState( defaultTechDocsReaderPageValue.shadowRoot, ); - const [shadowRootVersion, { inc: incShadowRootVersion }] = useCounter(0); useEffect(() => { if (shadowRoot && !metadata.value && !metadata.loading) { @@ -159,8 +153,6 @@ export const TechDocsReaderPageProvider = memo( entityMetadata, shadowRoot, setShadowRoot, - shadowRootVersion, - incShadowRootVersion, title, setTitle, subtitle, @@ -198,5 +190,6 @@ export const useTechDocsReaderPage = () => { if (context === undefined) { throw new Error('No context found for version 1.'); } + return context; }; diff --git a/plugins/techdocs-react/src/hooks.ts b/plugins/techdocs-react/src/hooks.ts index 2984a4b588..bbff875f3a 100644 --- a/plugins/techdocs-react/src/hooks.ts +++ b/plugins/techdocs-react/src/hooks.ts @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { useState, useEffect, useMemo } from 'react'; +import { useEffect, useMemo, useState } from 'react'; import debounce from 'lodash/debounce'; import { useTechDocsReaderPage } from './context'; @@ -39,9 +39,28 @@ export const useShadowRootElements = < selectors: string[], ): TReturnedElement[] => { const shadowRoot = useShadowRoot(); - if (!shadowRoot) return []; + const [root, setRootNode] = useState(shadowRoot?.querySelector('html')); + + useEffect(() => { + let observer: MutationObserver; + if (shadowRoot) { + observer = new MutationObserver(() => { + setRootNode(shadowRoot.querySelector('html')); + }); + observer.observe(shadowRoot, { + attributes: true, + characterData: true, + childList: true, + subtree: true, + }); + } + return () => observer?.disconnect(); + }, [shadowRoot]); + + if (!root) return []; + return selectors - .map(selector => shadowRoot?.querySelectorAll(selector)) + .map(selector => root.querySelectorAll(selector)) .filter(nodeList => nodeList.length) .map(nodeList => Array.from(nodeList)) .flat(); diff --git a/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/TechDocsReaderPageContent.tsx b/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/TechDocsReaderPageContent.tsx index 00df73cab3..3692ed22d3 100644 --- a/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/TechDocsReaderPageContent.tsx +++ b/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/TechDocsReaderPageContent.tsx @@ -80,7 +80,6 @@ export const TechDocsReaderPageContent = withTechDocsReaderProvider( entityMetadata: { value: entityMetadata, loading: entityMetadataLoading }, entityRef, setShadowRoot, - incShadowRootVersion, } = useTechDocsReaderPage(); const dom = useTechDocsReaderDom(entityRef); const path = window.location.pathname; @@ -103,12 +102,11 @@ export const TechDocsReaderPageContent = withTechDocsReaderProvider( const handleAppend = useCallback( (newShadowRoot: ShadowRoot) => { setShadowRoot(newShadowRoot); - incShadowRootVersion(); if (onReady instanceof Function) { onReady(); } }, - [setShadowRoot, incShadowRootVersion, onReady], + [setShadowRoot, onReady], ); // No entity metadata = 404. Don't render content at all. From ed67c8a16d53215c3a3176e13f8569c566a5c9f1 Mon Sep 17 00:00:00 2001 From: Alex Lorenzi Date: Wed, 26 Jun 2024 17:31:16 -0400 Subject: [PATCH 113/416] Updated changelog message Signed-off-by: Alex Lorenzi Signed-off-by: Jackson Chen --- .changeset/clever-waves-judge.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.changeset/clever-waves-judge.md b/.changeset/clever-waves-judge.md index 585ad01bbe..100ab66f90 100644 --- a/.changeset/clever-waves-judge.md +++ b/.changeset/clever-waves-judge.md @@ -1,6 +1,5 @@ --- '@backstage/plugin-techdocs-react': patch -'@backstage/plugin-techdocs': patch --- -Fixed a bug with the TechDocsReaderPageProvider not re-rendering when setShadowDom is called, meaning that the useShadowDom hooks were inconsistent. This issue caused the TextSize addon changes not to reapply during navigation. +Resolved the issue where changes in TechDoc add-ons, including the TextSize add-on, were not reapplying during navigation From 3c60a1095a644fb3fa406650eca2e8b843d35833 Mon Sep 17 00:00:00 2001 From: Alex Lorenzi Date: Wed, 26 Jun 2024 17:51:00 -0400 Subject: [PATCH 114/416] Reset API report Signed-off-by: Alex Lorenzi Signed-off-by: Jackson Chen --- plugins/techdocs-react/api-report.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/plugins/techdocs-react/api-report.md b/plugins/techdocs-react/api-report.md index 7d787c4da6..c158bbd81e 100644 --- a/plugins/techdocs-react/api-report.md +++ b/plugins/techdocs-react/api-report.md @@ -116,8 +116,6 @@ export type TechDocsReaderPageValue = { entityMetadata: AsyncState; shadowRoot?: ShadowRoot; setShadowRoot: Dispatch>; - shadowRootVersion: number; - incShadowRootVersion: () => void; title: string; setTitle: Dispatch>; subtitle: string; From 64e7e9409f6bc84fed0241adca226d09ac396561 Mon Sep 17 00:00:00 2001 From: ElaineDeMattosSilvaB Date: Thu, 27 Jun 2024 21:44:08 +0200 Subject: [PATCH 115/416] feat: add oauth token option for fetch action Signed-off-by: ElaineDeMattosSilvaB --- .../urlReader/lib/GitlabUrlReader.ts | 26 +++++++-------- packages/integration/src/gitlab/core.test.ts | 32 ++++++++++++++++++- packages/integration/src/gitlab/core.ts | 17 +++++++--- 3 files changed, 57 insertions(+), 18 deletions(-) diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/GitlabUrlReader.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/GitlabUrlReader.ts index 615eeb20a2..35123da851 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/GitlabUrlReader.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/GitlabUrlReader.ts @@ -23,21 +23,21 @@ import { UrlReaderServiceSearchOptions, UrlReaderServiceSearchResponse, } from '@backstage/backend-plugin-api'; +import { NotFoundError, NotModifiedError } from '@backstage/errors'; import { + GitLabIntegration, + ScmIntegrations, getGitLabFileFetchUrl, getGitLabIntegrationRelativePath, getGitLabRequestOptions, - GitLabIntegration, - ScmIntegrations, } from '@backstage/integration'; -import fetch, { Response } from 'node-fetch'; import parseGitUrl from 'git-url-parse'; -import { Minimatch } from 'minimatch'; -import { Readable } from 'stream'; -import { NotFoundError, NotModifiedError } from '@backstage/errors'; -import { ReadTreeResponseFactory, ReaderFactory } from './types'; import { trimEnd, trimStart } from 'lodash'; +import { Minimatch } from 'minimatch'; +import fetch, { Response } from 'node-fetch'; +import { Readable } from 'stream'; import { ReadUrlResponseFactory } from './ReadUrlResponseFactory'; +import { ReadTreeResponseFactory, ReaderFactory } from './types'; import { parseLastModified } from './util'; /** @@ -71,14 +71,14 @@ export class GitlabUrlReader implements UrlReaderService { url: string, options?: UrlReaderServiceReadUrlOptions, ): Promise { - const { etag, lastModifiedAfter, signal } = options ?? {}; + const { etag, lastModifiedAfter, signal, token } = options ?? {}; const builtUrl = await this.getGitlabFetchUrl(url); let response: Response; try { response = await fetch(builtUrl, { headers: { - ...getGitLabRequestOptions(this.integration.config).headers, + ...getGitLabRequestOptions(this.integration.config, token).headers, ...(etag && { 'If-None-Match': etag }), ...(lastModifiedAfter && { 'If-Modified-Since': lastModifiedAfter.toUTCString(), @@ -120,7 +120,7 @@ export class GitlabUrlReader implements UrlReaderService { url: string, options?: UrlReaderServiceReadTreeOptions, ): Promise { - const { etag, signal } = options ?? {}; + const { etag, signal, token } = options ?? {}; const { ref, full_name, filepath } = parseGitUrl(url); let repoFullName = full_name; @@ -147,7 +147,7 @@ export class GitlabUrlReader implements UrlReaderService { repoFullName, )}`, ).toString(), - getGitLabRequestOptions(this.integration.config), + getGitLabRequestOptions(this.integration.config, token), ); if (!projectGitlabResponse.ok) { const msg = `Failed to read tree from ${url}, ${projectGitlabResponse.status} ${projectGitlabResponse.statusText}`; @@ -175,7 +175,7 @@ export class GitlabUrlReader implements UrlReaderService { )}/repository/commits?${commitsReqParams.toString()}`, ).toString(), { - ...getGitLabRequestOptions(this.integration.config), + ...getGitLabRequestOptions(this.integration.config, token), // TODO(freben): The signal cast is there because pre-3.x versions of // node-fetch have a very slightly deviating AbortSignal type signature. // The difference does not affect us in practice however. The cast can @@ -209,7 +209,7 @@ export class GitlabUrlReader implements UrlReaderService { repoFullName, )}/repository/archive?${archiveReqParams.toString()}`, { - ...getGitLabRequestOptions(this.integration.config), + ...getGitLabRequestOptions(this.integration.config, token), // TODO(freben): The signal cast is there because pre-3.x versions of // node-fetch have a very slightly deviating AbortSignal type signature. // The difference does not affect us in practice however. The cast can diff --git a/packages/integration/src/gitlab/core.test.ts b/packages/integration/src/gitlab/core.test.ts index 98fd9b7c13..fd374ea56f 100644 --- a/packages/integration/src/gitlab/core.test.ts +++ b/packages/integration/src/gitlab/core.test.ts @@ -17,7 +17,7 @@ import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { GitLabIntegrationConfig } from './config'; -import { getGitLabFileFetchUrl } from './core'; +import { getGitLabFileFetchUrl, getGitLabRequestOptions } from './core'; const worker = setupServer(); @@ -186,4 +186,34 @@ describe('gitlab core', () => { }); }); }); + + describe('getGitLabRequestOptions', () => { + it('should return Authorization header when oauthToken is provided', () => { + const oauthToken = 'mock-oauth-token'; + const result = getGitLabRequestOptions( + configSelfHosteWithRelativePath, + oauthToken, + ); + + expect(result).toEqual({ + headers: { + Authorization: `Bearer ${oauthToken}`, + }, + }); + }); + + it('should return private-token header when oauthToken is undefined', () => { + const oauthToken = undefined; + const result = getGitLabRequestOptions( + configSelfHosteWithRelativePath, + oauthToken, + ); + + expect(result).toEqual({ + headers: { + 'PRIVATE-TOKEN': configSelfHosteWithRelativePath.token, + }, + }); + }); + }); }); diff --git a/packages/integration/src/gitlab/core.ts b/packages/integration/src/gitlab/core.ts index 040ca202d6..e940440ea4 100644 --- a/packages/integration/src/gitlab/core.ts +++ b/packages/integration/src/gitlab/core.ts @@ -14,11 +14,11 @@ * limitations under the License. */ +import fetch from 'cross-fetch'; import { getGitLabIntegrationRelativePath, GitLabIntegrationConfig, } from './config'; -import fetch from 'cross-fetch'; /** * Given a URL pointing to a file on a provider, returns a URL that is suitable @@ -51,9 +51,18 @@ export async function getGitLabFileFetchUrl( * @param config - The relevant provider config * @public */ -export function getGitLabRequestOptions(config: GitLabIntegrationConfig): { - headers: Record; -} { +export function getGitLabRequestOptions( + config: GitLabIntegrationConfig, + oauthToken?: string, +): { headers: Record } { + if (oauthToken) { + return { + headers: { + Authorization: `Bearer ${oauthToken}`, + }, + }; + } + const { token = '' } = config; return { headers: { From 2f7a7df46b557ddb747e2952cc657aa9f46be133 Mon Sep 17 00:00:00 2001 From: ElaineDeMattosSilvaB Date: Thu, 27 Jun 2024 22:10:40 +0200 Subject: [PATCH 116/416] feat: add possibility of a user provided glpat Signed-off-by: ElaineDeMattosSilvaB --- packages/integration/src/gitlab/core.test.ts | 22 ++++++++++++++++---- packages/integration/src/gitlab/core.ts | 18 ++++++++-------- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/packages/integration/src/gitlab/core.test.ts b/packages/integration/src/gitlab/core.test.ts index fd374ea56f..c6e7410932 100644 --- a/packages/integration/src/gitlab/core.test.ts +++ b/packages/integration/src/gitlab/core.test.ts @@ -189,15 +189,30 @@ describe('gitlab core', () => { describe('getGitLabRequestOptions', () => { it('should return Authorization header when oauthToken is provided', () => { - const oauthToken = 'mock-oauth-token'; + const token = + 'de6780bc506a0446309bd9362820ba8aed28aa506c71eedbe1c5c4f9dd350e54'; const result = getGitLabRequestOptions( configSelfHosteWithRelativePath, - oauthToken, + token, ); expect(result).toEqual({ headers: { - Authorization: `Bearer ${oauthToken}`, + Authorization: `Bearer ${token}`, + }, + }); + }); + + it('should return private-token header when gl-token is provided', () => { + const token = 'glpat-1234566'; + const result = getGitLabRequestOptions( + configSelfHosteWithRelativePath, + token, + ); + + expect(result).toEqual({ + headers: { + 'PRIVATE-TOKEN': token, }, }); }); @@ -208,7 +223,6 @@ describe('gitlab core', () => { configSelfHosteWithRelativePath, oauthToken, ); - expect(result).toEqual({ headers: { 'PRIVATE-TOKEN': configSelfHosteWithRelativePath.token, diff --git a/packages/integration/src/gitlab/core.ts b/packages/integration/src/gitlab/core.ts index e940440ea4..94f4b65d9f 100644 --- a/packages/integration/src/gitlab/core.ts +++ b/packages/integration/src/gitlab/core.ts @@ -53,21 +53,21 @@ export async function getGitLabFileFetchUrl( */ export function getGitLabRequestOptions( config: GitLabIntegrationConfig, - oauthToken?: string, + token?: string, ): { headers: Record } { - if (oauthToken) { + if (token) { + // If token comes from the user and starts with "gl", it's a private token (see https://docs.gitlab.com/ee/security/token_overview.html#token-prefixes) return { - headers: { - Authorization: `Bearer ${oauthToken}`, - }, + headers: token.startsWith('gl') + ? { 'PRIVATE-TOKEN': token } + : { Authorization: `Bearer ${token}` }, // Otherwise, it's a bearer token }; } - const { token = '' } = config; + // If token not provided, fetch the integration token + const { token: configToken = '' } = config; return { - headers: { - 'PRIVATE-TOKEN': token, - }, + headers: { 'PRIVATE-TOKEN': configToken }, }; } From 78c13290e470387e4e490bece3362fe86f115bc6 Mon Sep 17 00:00:00 2001 From: ElaineDeMattosSilvaB Date: Thu, 27 Jun 2024 22:21:59 +0200 Subject: [PATCH 117/416] chore: add changeset and api-report Signed-off-by: ElaineDeMattosSilvaB --- .changeset/nice-peas-retire.md | 6 ++++++ packages/integration/api-report.md | 5 ++++- 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 .changeset/nice-peas-retire.md diff --git a/.changeset/nice-peas-retire.md b/.changeset/nice-peas-retire.md new file mode 100644 index 0000000000..7b7b13706d --- /dev/null +++ b/.changeset/nice-peas-retire.md @@ -0,0 +1,6 @@ +--- +'@backstage/integration': minor +'@backstage/backend-defaults': patch +--- + +Updated `GitlabUrlReader.readUrl` and `GitlabUrlReader.readTree` to accept a user-provided token, supporting both bearer and private tokens. diff --git a/packages/integration/api-report.md b/packages/integration/api-report.md index 4c8e8accf2..cf4b380ad9 100644 --- a/packages/integration/api-report.md +++ b/packages/integration/api-report.md @@ -508,7 +508,10 @@ export function getGitLabIntegrationRelativePath( ): string; // @public -export function getGitLabRequestOptions(config: GitLabIntegrationConfig): { +export function getGitLabRequestOptions( + config: GitLabIntegrationConfig, + token?: string, +): { headers: Record; }; From 28d3cf8c9db6f72f1d7f14c0c5d34d53a0599d80 Mon Sep 17 00:00:00 2001 From: ElaineDeMattosSilvaB Date: Thu, 27 Jun 2024 22:42:29 +0200 Subject: [PATCH 118/416] fix: change mocked bearer token format Signed-off-by: ElaineDeMattosSilvaB --- packages/integration/src/gitlab/core.test.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/integration/src/gitlab/core.test.ts b/packages/integration/src/gitlab/core.test.ts index c6e7410932..81adc29701 100644 --- a/packages/integration/src/gitlab/core.test.ts +++ b/packages/integration/src/gitlab/core.test.ts @@ -189,8 +189,7 @@ describe('gitlab core', () => { describe('getGitLabRequestOptions', () => { it('should return Authorization header when oauthToken is provided', () => { - const token = - 'de6780bc506a0446309bd9362820ba8aed28aa506c71eedbe1c5c4f9dd350e54'; + const token = '1234567890'; const result = getGitLabRequestOptions( configSelfHosteWithRelativePath, token, From 92583daf57de6cb64b0ed889deba220c66b933c7 Mon Sep 17 00:00:00 2001 From: Chap Ambrose Date: Thu, 27 Jun 2024 16:43:38 -0500 Subject: [PATCH 119/416] Update heroku deploy docs Signed-off-by: Chap Ambrose --- docs/deployment/heroku.md | 99 ++++++++++++++++++++++++++------------- 1 file changed, 66 insertions(+), 33 deletions(-) diff --git a/docs/deployment/heroku.md b/docs/deployment/heroku.md index 1545c34733..a70ff66ca5 100644 --- a/docs/deployment/heroku.md +++ b/docs/deployment/heroku.md @@ -5,40 +5,40 @@ sidebar_label: Heroku description: How to deploy Backstage to Heroku --- -Heroku is a Platform as a Service (PaaS) designed to handle application -deployment in a hands-off way. Heroku supports container deployment of Docker -images, a natural fit for Backstage. +Heroku is a Platform as a Service (PaaS) designed to simplify application deployment. -## Configuring the CLI +## Create App -First, install the -[heroku-cli](https://devcenter.heroku.com/articles/heroku-cli) and login: +Start with an exisiting Backstage app or follow the [getting started guide](https://backstage.io/docs/getting-started/) to create a new one: ```shell -$ heroku login +$ npx @backstage/create-app@latest + Enter a name ``` -If you have not yet created a project through the Heroku interface, you can create it through the CLI. +Install the +[Heroku CLI](https://devcenter.heroku.com/articles/heroku-cli) and create a new Heroku app: ```shell -$ heroku create +$ cd your-app/ +$ heroku apps:create ``` -You _might_ also need to set your Heroku app's stack to `container`: +## Domain -```bash -$ heroku stack:set container -a +Get Heroku app URL: +```shell +$ heroku domains -a +.herokuapp.com ``` -Configuring your `app-config.yaml`: - +Update `baseUrl` and `port` in `app-config.yaml`. The core [app-backend plugin](https://www.npmjs.com/package/@backstage/plugin-app-backend) allows a single Heroku app to serve the frontend and backend: ```yaml app: - # Should be the same as backend.baseUrl when using the `app-backend` plugin - baseUrl: https://.herokuapp.com + baseUrl: https://.herokuapp.com backend: - baseUrl: https://.herokuapp.com + baseUrl: https://.herokuapp.com listen: port: $env: PORT @@ -46,28 +46,61 @@ backend: # https://devcenter.heroku.com/articles/dynos#web-dynos ``` -> Make sure your file is being copied into your container in the `Dockerfile`. +## Build Script -Before building the Docker image, run the [backstage host build commands](https://backstage.io/docs/deployment/docker#host-build). They must be run whenever you are going to publish a new image. +Add a build script in `package.json` to compile frontend during deployment: +```json +"scripts": { + "build": "yarn build:backend --config ../../app-config.yaml" +``` -Heroku runs a container registry on `registry.heroku.com`. To push Backstage -Docker images, log in to the container registry also: +## Start Command + +Create a [Procfile](https://devcenter.heroku.com/articles/procfile) in the app's root: +```shell +$ echo "web: yarn workspace backend start --config ../../app-config.yaml" > Procfile +``` + +## Database + +Provision a [Heroku Postgres](https://elements.heroku.com/addons/heroku-postgresql) database: +```shell +$ heroku addons:create heroku-postgresql -a +``` + +Update `database` in `app-config.yaml`: +```yaml +backend: + database: + client: pg + pluginDivisionMode: schema + ensureExists: false + ensureSchemaExists: true + connection: ${DATABASE_URL} +``` + +Allow postgres self-signed certificates: +```shell +$ heroku config:set PGSSLMODE=no-verify -a +``` + +## Deployment + +Commit changes and push to Heroku to build and deploy: ```shell -$ heroku container:login +$ git add Procfile && git commit -am "configure heroku" +$ git push heroku main ``` -## Push and deploy a Docker image +View the app in the browser: -Now we can push a Backstage [Docker image](docker.md) to Heroku's container -registry and release it to the `web` worker: - -```bash -$ docker image build . -f packages/backend/Dockerfile --tag registry.heroku.com//web - -$ docker push registry.heroku.com//web - -$ heroku container:release web -a +```shell +$ heroku open -a ``` -Now you should have Backstage up and running! 🎉 +View logs: + +```shell +$ heroku heroku -a +``` From 354e68c9537b0794634960101909fe05564b659a Mon Sep 17 00:00:00 2001 From: Stephen Glass Date: Wed, 19 Jun 2024 22:14:49 -0400 Subject: [PATCH 120/416] Improve validation error display text in scaffolder UI Signed-off-by: Stephen Glass --- .changeset/swift-dots-cough.md | 5 + .../errorListTemplate.test.tsx | 99 +++++++++++++++---- .../ErrorListTemplate/errorListTemplate.tsx | 26 ++++- 3 files changed, 109 insertions(+), 21 deletions(-) create mode 100644 .changeset/swift-dots-cough.md diff --git a/.changeset/swift-dots-cough.md b/.changeset/swift-dots-cough.md new file mode 100644 index 0000000000..255ee192a0 --- /dev/null +++ b/.changeset/swift-dots-cough.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-react': minor +--- + +Improve validation error display text in scaffolder diff --git a/plugins/scaffolder-react/src/next/components/Stepper/ErrorListTemplate/errorListTemplate.test.tsx b/plugins/scaffolder-react/src/next/components/Stepper/ErrorListTemplate/errorListTemplate.test.tsx index c5ddf6854f..d632340031 100644 --- a/plugins/scaffolder-react/src/next/components/Stepper/ErrorListTemplate/errorListTemplate.test.tsx +++ b/plugins/scaffolder-react/src/next/components/Stepper/ErrorListTemplate/errorListTemplate.test.tsx @@ -19,25 +19,88 @@ import { renderInTestApp } from '@backstage/test-utils'; import { ErrorListProps } from '@rjsf/utils'; describe('Error List Template', () => { - const errorList = { - errors: [ - { - stack: 'Test error 1', - }, - { - stack: 'Test error 2', - }, - ], - errorSchema: {}, - } as Partial as ErrorListProps; + describe('should render the error messages', () => { + it('no properties', async () => { + const errorList = { + errors: [ + { + stack: 'Test error 1', + }, + { + stack: 'Test error 2', + }, + ], + errorSchema: {}, + } as Partial as ErrorListProps; - it('should render the error messages', async () => { - const { getByText } = await renderInTestApp( - , - ); + const { getByText } = await renderInTestApp( + , + ); - for (const error of errorList.errors) { - expect(getByText(error.stack)).toBeInTheDocument(); - } + for (const error of errorList.errors) { + expect(getByText(error.stack)).toBeInTheDocument(); + } + }); + + it('properties no title', async () => { + const errorList = { + errors: [ + { + property: '.foo', + stack: 'Test error 1', + message: 'Test error 1', + }, + { + property: '.anExampleTitle', + stack: 'Test error 2', + message: 'Test error 2', + }, + ], + errorSchema: {}, + schema: {}, + } as Partial as ErrorListProps; + + const { getByText } = await renderInTestApp( + , + ); + + expect(getByText("'Foo' Test error 1")).toBeInTheDocument(); + expect(getByText("'An Example Title' Test error 2")).toBeInTheDocument(); + }); + + it('properties with title', async () => { + const errorList = { + errors: [ + { + property: '.foo', + stack: 'Test error 1', + message: 'Test error 1', + }, + { + property: '.bar', + stack: 'Test error 2', + message: 'Test error 2', + }, + ], + errorSchema: {}, + schema: { + properties: { + foo: { + title: 'Hello', + }, + bar: { + title: 'Example Title', + }, + }, + }, + } as Partial as ErrorListProps; + + const { getByText } = await renderInTestApp( + , + ); + + expect(getByText("'Hello' Test error 1")).toBeInTheDocument(); + expect(getByText("'Example Title' Test error 2")).toBeInTheDocument(); + }); }); }); diff --git a/plugins/scaffolder-react/src/next/components/Stepper/ErrorListTemplate/errorListTemplate.tsx b/plugins/scaffolder-react/src/next/components/Stepper/ErrorListTemplate/errorListTemplate.tsx index a5310a5806..6b664fc235 100644 --- a/plugins/scaffolder-react/src/next/components/Stepper/ErrorListTemplate/errorListTemplate.tsx +++ b/plugins/scaffolder-react/src/next/components/Stepper/ErrorListTemplate/errorListTemplate.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ import React from 'react'; -import { ErrorListProps } from '@rjsf/utils'; +import { ErrorListProps, RJSFValidationError } from '@rjsf/utils'; import List from '@material-ui/core/List'; import ListItem from '@material-ui/core/ListItem'; import ListItemIcon from '@material-ui/core/ListItemIcon'; @@ -22,6 +22,7 @@ import ListItemText from '@material-ui/core/ListItemText'; import Paper from '@material-ui/core/Paper'; import { Theme, createStyles, makeStyles } from '@material-ui/core/styles'; import ErrorIcon from '@material-ui/icons/Error'; +import startCase from 'lodash/startCase'; const useStyles = makeStyles((_theme: Theme) => createStyles({ @@ -39,9 +40,28 @@ const useStyles = makeStyles((_theme: Theme) => * * @public */ -export const ErrorListTemplate = ({ errors }: ErrorListProps) => { +export const ErrorListTemplate = ({ errors, schema }: ErrorListProps) => { const classes = useStyles(); + function formatErrorMessage(error: RJSFValidationError) { + if (error.property && error.message) { + const propertyName = error.property.startsWith('.') + ? error.property.substring(1) + : error.property; + if (schema.properties && propertyName in schema.properties) { + const property = schema.properties[propertyName]; + + if (typeof property === 'object' && 'title' in property) { + return `'${property.title}' ${error.message}`; + } + } + // fall back to property name + return `'${startCase(propertyName)}' ${error.message}`; + } + // fall back if property does not exist + return error.stack; + } + return ( @@ -52,7 +72,7 @@ export const ErrorListTemplate = ({ errors }: ErrorListProps) => { ))} From df4d3ca4939802045f2a0dd7157fee44077c4ee6 Mon Sep 17 00:00:00 2001 From: Jackson Chen Date: Thu, 27 Jun 2024 15:33:39 -0400 Subject: [PATCH 121/416] Fix tests Signed-off-by: Jackson Chen --- plugins/techdocs-react/src/hooks.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/techdocs-react/src/hooks.ts b/plugins/techdocs-react/src/hooks.ts index bbff875f3a..2d922ab7f4 100644 --- a/plugins/techdocs-react/src/hooks.ts +++ b/plugins/techdocs-react/src/hooks.ts @@ -39,13 +39,13 @@ export const useShadowRootElements = < selectors: string[], ): TReturnedElement[] => { const shadowRoot = useShadowRoot(); - const [root, setRootNode] = useState(shadowRoot?.querySelector('html')); + const [render, rerender] = useState(false); useEffect(() => { let observer: MutationObserver; if (shadowRoot) { observer = new MutationObserver(() => { - setRootNode(shadowRoot.querySelector('html')); + rerender(!render); }); observer.observe(shadowRoot, { attributes: true, @@ -55,12 +55,12 @@ export const useShadowRootElements = < }); } return () => observer?.disconnect(); - }, [shadowRoot]); + }, [shadowRoot, render, rerender]); - if (!root) return []; + if (!shadowRoot) return []; return selectors - .map(selector => root.querySelectorAll(selector)) + .map(selector => shadowRoot.querySelectorAll(selector)) .filter(nodeList => nodeList.length) .map(nodeList => Array.from(nodeList)) .flat(); From 19d495939d23984987ac1097e61faadb3b0fd2aa Mon Sep 17 00:00:00 2001 From: Stephen Glass Date: Thu, 27 Jun 2024 23:20:51 -0400 Subject: [PATCH 122/416] Extract condition check to function Signed-off-by: Stephen Glass --- .../components/ReviewState/ReviewState.tsx | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.tsx b/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.tsx index ac7ac989e3..202e0c0fbf 100644 --- a/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.tsx +++ b/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.tsx @@ -47,11 +47,8 @@ function flattenObject( // Recurse into nested objects if ( - backstageReviewOptions && - backstageReviewOptions.explode && - typeof value === 'object' && - value !== null && - !Array.isArray(value) + backstageReviewOptions?.explode && + isJsonObject(value) ) { return flattenObject(value, prefixedKey, schema, formState); } @@ -61,6 +58,14 @@ function flattenObject( }); } +function isJsonObject(value?: JsonValue): value is JsonObject { + return ( + typeof value === 'object' && + value !== null && + !Array.isArray(value) + ); +} + /** * The component used by the {@link Stepper} to render the review step. * @alpha @@ -89,9 +94,7 @@ export const ReviewState = (props: ReviewStateProps) => { } if ( backstageReviewOptions.explode && - typeof value === 'object' && - value !== null && - !Array.isArray(value) + isJsonObject(value) ) { return flattenObject(value, key, parsedSchema, props.formState); } @@ -106,7 +109,7 @@ export const ReviewState = (props: ReviewStateProps) => { [ key, definitionInSchema.enumNames[ - definitionInSchema.enum.indexOf(value) + definitionInSchema.enum.indexOf(value) ] || value, ], ]; From 7193d02b32b27eed9519875a03456b687e738936 Mon Sep 17 00:00:00 2001 From: Stephen Glass Date: Fri, 28 Jun 2024 01:18:20 -0400 Subject: [PATCH 123/416] Fix formatting Signed-off-by: Stephen Glass --- .../components/ReviewState/ReviewState.tsx | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.tsx b/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.tsx index 202e0c0fbf..22ec54ac26 100644 --- a/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.tsx +++ b/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.tsx @@ -46,10 +46,7 @@ function flattenObject( const backstageReviewOptions = definitionInSchema['ui:backstage']?.review; // Recurse into nested objects - if ( - backstageReviewOptions?.explode && - isJsonObject(value) - ) { + if (backstageReviewOptions?.explode && isJsonObject(value)) { return flattenObject(value, prefixedKey, schema, formState); } } @@ -59,11 +56,7 @@ function flattenObject( } function isJsonObject(value?: JsonValue): value is JsonObject { - return ( - typeof value === 'object' && - value !== null && - !Array.isArray(value) - ); + return typeof value === 'object' && value !== null && !Array.isArray(value); } /** @@ -92,10 +85,7 @@ export const ReviewState = (props: ReviewStateProps) => { if (backstageReviewOptions.show === false) { return []; } - if ( - backstageReviewOptions.explode && - isJsonObject(value) - ) { + if (backstageReviewOptions.explode && isJsonObject(value)) { return flattenObject(value, key, parsedSchema, props.formState); } } @@ -109,7 +99,7 @@ export const ReviewState = (props: ReviewStateProps) => { [ key, definitionInSchema.enumNames[ - definitionInSchema.enum.indexOf(value) + definitionInSchema.enum.indexOf(value) ] || value, ], ]; From c59167016378de2b5206737ab283b43d5b77887a Mon Sep 17 00:00:00 2001 From: Calvin Lee Date: Wed, 26 Jun 2024 16:07:06 -0600 Subject: [PATCH 124/416] fix: enable support for account and org level urls Signed-off-by: Calvin Lee --- .changeset/witty-bears-behave.md | 5 ++ packages/integration/src/harness/core.ts | 71 +++++++++++++++++------- 2 files changed, 55 insertions(+), 21 deletions(-) create mode 100644 .changeset/witty-bears-behave.md diff --git a/.changeset/witty-bears-behave.md b/.changeset/witty-bears-behave.md new file mode 100644 index 0000000000..33b4c0b187 --- /dev/null +++ b/.changeset/witty-bears-behave.md @@ -0,0 +1,5 @@ +--- +'@backstage/integration': patch +--- + +Updated function for getHarnessEditContentsUrl, getHarnessFileContentsUrl, getHarnessArchiveUrl, getHarnessLatestCommitUrl and parseHarnessUrl to handle account and org level urls diff --git a/packages/integration/src/harness/core.ts b/packages/integration/src/harness/core.ts index 81281eaa6e..1887a5c0d8 100644 --- a/packages/integration/src/harness/core.ts +++ b/packages/integration/src/harness/core.ts @@ -34,7 +34,12 @@ export function getHarnessEditContentsUrl( url: string, ) { const parsedUrl = parseHarnessUrl(config, url); - return `${parsedUrl.baseUrl}/ng/account/${parsedUrl.accountId}/module/code/orgs/${parsedUrl.orgName}/projects/${parsedUrl.projectName}/repos/${parsedUrl.repoName}/files/${parsedUrl.branch}/~/${parsedUrl.path}`; + + return `${parsedUrl.baseUrl}/ng/account/${parsedUrl.accountId}/module/code${ + parsedUrl.orgName !== '' ? `/orgs/${parsedUrl.orgName}` : '' + }${ + parsedUrl.projectName !== '' ? `/projects/${parsedUrl.projectName}` : '' + }/repos/${parsedUrl.repoName}/files/${parsedUrl.branch}/~/${parsedUrl.path}`; } /** @@ -44,6 +49,7 @@ export function getHarnessEditContentsUrl( * * Converts * from: https://app.harness.io/ng/account/accountId/module/code/orgs/orgName/projects/projName/repos/repoName/files/refMain/~/all-apis.yaml + * https://qa.harness.io/ng/account/bDCAuAjFSJCLFj_0ug3lCg/module/code/orgs/HiteshTest/repos/impoorter/files/main/~/catalog.yaml * to: https://app.harness.io/gateway/code/api/v1/repos/accountId/orgName/projName/repoName/+/content/all-apis.yaml?routingId=accountId&include_commit=false&ref=refMain * * @param url - A URL pointing to a file @@ -55,7 +61,14 @@ export function getHarnessFileContentsUrl( url: string, ) { const parsedUrl = parseHarnessUrl(config, url); - return `${parsedUrl.baseUrl}/gateway/code/api/v1/repos/${parsedUrl.accountId}/${parsedUrl.orgName}/${parsedUrl.projectName}/${parsedUrl.repoName}/+/raw/${parsedUrl.path}?routingId=${parsedUrl.accountId}&git_ref=refs/heads/${parsedUrl.refString}`; + + return `${parsedUrl.baseUrl}/gateway/code/api/v1/repos/${ + parsedUrl.accountId + }/${parsedUrl.orgName}${ + parsedUrl.projectName !== '' ? `/${parsedUrl.projectName}/` : '/' + }${parsedUrl.repoName}/+/raw/${parsedUrl.path}?routingId=${ + parsedUrl.accountId + }&git_ref=refs/heads/${parsedUrl.refString}`; } /** @@ -77,7 +90,13 @@ export function getHarnessArchiveUrl( url: string, ) { const parsedUrl = parseHarnessUrl(config, url); - return `${parsedUrl.baseUrl}/gateway/code/api/v1/repos/${parsedUrl.accountId}/${parsedUrl.orgName}/${parsedUrl.projectName}/${parsedUrl.repoName}/+/archive/${parsedUrl.branch}.zip?routingId=${parsedUrl.accountId}`; + return `${parsedUrl.baseUrl}/gateway/code/api/v1/repos/${ + parsedUrl.accountId + }/${parsedUrl.orgName}${ + parsedUrl.projectName !== '' ? `/${parsedUrl.projectName}/` : '/' + }${parsedUrl.repoName}/+/archive/${parsedUrl.branch}.zip?routingId=${ + parsedUrl.accountId + }`; } /** @@ -99,7 +118,13 @@ export function getHarnessLatestCommitUrl( url: string, ) { const parsedUrl = parseHarnessUrl(config, url); - return `${parsedUrl.baseUrl}/gateway/code/api/v1/repos/${parsedUrl.accountId}/${parsedUrl.orgName}/${parsedUrl.projectName}/${parsedUrl.repoName}/+/content?routingId=${parsedUrl.accountId}&include_commit=true&git_ref=refs/heads/${parsedUrl.branch}`; + return `${parsedUrl.baseUrl}/gateway/code/api/v1/repos/${ + parsedUrl.accountId + }/${parsedUrl.orgName}${ + parsedUrl.projectName !== '' ? `/${parsedUrl.projectName}/` : '/' + }${parsedUrl.repoName}/+/content?routingId=${ + parsedUrl.accountId + }&include_commit=true&git_ref=refs/heads/${parsedUrl.branch}`; } /** @@ -153,27 +178,30 @@ export function parseHarnessUrl( .split('/') .filter(segment => segment !== ''); const urlParts = pathUrl.pathname.split('/'); - const [ - _ng, - _account, - accountId, - _module, - _moduleName, - _org, - orgName, - _projects, - projectName, - _repos, - repoName, - _files, - _ref, - _branch, - ..._path - ] = pathSegments; + + const accountIdIndex = + pathSegments.findIndex(segment => segment === 'account') + 1; + const accountId = pathSegments[accountIdIndex]; + + const orgNameIndex = pathSegments.findIndex(segment => segment === 'orgs'); + const orgName = orgNameIndex !== -1 ? pathSegments[orgNameIndex + 1] : ''; + + const projectNameIndex = pathSegments.findIndex( + segment => segment === 'projects', + ); + + const projectName = + projectNameIndex !== -1 ? pathSegments[projectNameIndex + 1] : ''; + + const repoNameIndex = + pathSegments.findIndex(segment => segment === 'repos') + 1; + const repoName = pathSegments[repoNameIndex]; + const refAndPath = urlParts.slice( urlParts.findIndex(i => i === 'files' || i === 'edit') + 1, ); const refIndex = refAndPath.findIndex(item => item === '~'); + const refString = refAndPath.slice(0, refIndex).join('/'); const pathWithoutSlash = refIndex !== -1 @@ -182,6 +210,7 @@ export function parseHarnessUrl( .join('/') .replace(/^\//, '') : ''; + return { baseUrl: baseUrl, accountId: accountId, From a840355a10f9ad1b47975b65b30e89a4e7181876 Mon Sep 17 00:00:00 2001 From: Calvin Lee Date: Fri, 28 Jun 2024 11:41:43 -0600 Subject: [PATCH 125/416] fix: update changeset Signed-off-by: Calvin Lee --- .changeset/witty-bears-behave.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/witty-bears-behave.md b/.changeset/witty-bears-behave.md index 33b4c0b187..7514759189 100644 --- a/.changeset/witty-bears-behave.md +++ b/.changeset/witty-bears-behave.md @@ -2,4 +2,4 @@ '@backstage/integration': patch --- -Updated function for getHarnessEditContentsUrl, getHarnessFileContentsUrl, getHarnessArchiveUrl, getHarnessLatestCommitUrl and parseHarnessUrl to handle account and org level urls +Updated functions for getHarnessEditContentsUrl, getHarnessFileContentsUrl, getHarnessArchiveUrl, getHarnessLatestCommitUrl and parseHarnessUrl to handle account and org level urls From 141f36662561d0c7cbc62a27a8aa0deff89603c7 Mon Sep 17 00:00:00 2001 From: Andre Wanlin Date: Fri, 21 Jun 2024 11:29:29 -0500 Subject: [PATCH 126/416] Added action to enable GitHub Pages on a repo Signed-off-by: Andre Wanlin --- .changeset/spotty-crabs-shop.md | 5 + .../api-report.md | 15 ++ .../src/actions/githubPages.examples.test.ts | 90 ++++++++++++ .../src/actions/githubPages.examples.ts | 40 ++++++ .../src/actions/githubPages.test.ts | 93 +++++++++++++ .../src/actions/githubPages.ts | 130 ++++++++++++++++++ .../src/actions/index.ts | 2 +- .../src/module.ts | 5 + 8 files changed, 379 insertions(+), 1 deletion(-) create mode 100644 .changeset/spotty-crabs-shop.md create mode 100644 plugins/scaffolder-backend-module-github/src/actions/githubPages.examples.test.ts create mode 100644 plugins/scaffolder-backend-module-github/src/actions/githubPages.examples.ts create mode 100644 plugins/scaffolder-backend-module-github/src/actions/githubPages.test.ts create mode 100644 plugins/scaffolder-backend-module-github/src/actions/githubPages.ts diff --git a/.changeset/spotty-crabs-shop.md b/.changeset/spotty-crabs-shop.md new file mode 100644 index 0000000000..6bc1bcfe0c --- /dev/null +++ b/.changeset/spotty-crabs-shop.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend-module-github': patch +--- + +Added action to enable GitHub Pages on a repo diff --git a/plugins/scaffolder-backend-module-github/api-report.md b/plugins/scaffolder-backend-module-github/api-report.md index 94b642bdbf..aa4d94dcd6 100644 --- a/plugins/scaffolder-backend-module-github/api-report.md +++ b/plugins/scaffolder-backend-module-github/api-report.md @@ -107,6 +107,21 @@ export function createGithubIssuesLabelAction(options: { JsonObject >; +// @public +export function createGithubPagesAction(options: { + integrations: ScmIntegrationRegistry; + githubCredentialsProvider?: GithubCredentialsProvider; +}): TemplateAction< + { + repoUrl: string; + buildType?: 'legacy' | 'workflow' | undefined; + sourceBranch?: string | undefined; + sourcePath?: '/' | '/docs' | undefined; + token?: string | undefined; + }, + JsonObject +>; + // @public export interface CreateGithubPullRequestActionOptions { clientFactory?: (input: { diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubPages.examples.test.ts b/plugins/scaffolder-backend-module-github/src/actions/githubPages.examples.test.ts new file mode 100644 index 0000000000..7480d8d478 --- /dev/null +++ b/plugins/scaffolder-backend-module-github/src/actions/githubPages.examples.test.ts @@ -0,0 +1,90 @@ +/* + * 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 { TemplateAction } from '@backstage/plugin-scaffolder-node'; +import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test-utils'; +import { ConfigReader } from '@backstage/config'; +import { + DefaultGithubCredentialsProvider, + GithubCredentialsProvider, + ScmIntegrations, +} from '@backstage/integration'; +import { createGithubPagesAction } from './githubPages'; +import { examples } from './githubPages.examples'; +import yaml from 'yaml'; + +const mockOctokit = { + request: jest.fn(), +}; + +jest.mock('octokit', () => ({ + Octokit: class { + constructor() { + return mockOctokit; + } + }, +})); + +describe('github:pages', () => { + const config = new ConfigReader({ + integrations: { + github: [ + { host: 'github.com', token: 'mock-token' }, + { host: 'ghe.github.com' }, + ], + }, + }); + + const integrations = ScmIntegrations.fromConfig(config); + let githubCredentialsProvider: GithubCredentialsProvider; + let action: TemplateAction; + + const input = yaml.parse(examples[0].example).steps[0].input; + const mockContext = createMockActionContext({ + input, + }); + + beforeEach(() => { + githubCredentialsProvider = + DefaultGithubCredentialsProvider.fromIntegrations(integrations); + action = createGithubPagesAction({ + integrations, + githubCredentialsProvider, + }); + }); + + afterEach(jest.resetAllMocks); + + it('should work with example input', async () => { + await action.handler(mockContext); + + expect(mockOctokit.request).toHaveBeenCalledWith( + 'POST /repos/{owner}/{repo}/pages', + { + owner: 'owner', + repo: 'repo', + build_type: 'workflow', + source: { + branch: 'main', + path: '/', + }, + headers: { + 'X-GitHub-Api-Version': '2022-11-28', + }, + }, + ); + }); +}); diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubPages.examples.ts b/plugins/scaffolder-backend-module-github/src/actions/githubPages.examples.ts new file mode 100644 index 0000000000..be4a33e5df --- /dev/null +++ b/plugins/scaffolder-backend-module-github/src/actions/githubPages.examples.ts @@ -0,0 +1,40 @@ +/* + * Copyright 2024 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: 'Enables GitHub Pages for a repository.', + example: yaml.stringify({ + steps: [ + { + action: 'github:pages', + id: 'github-pages', + name: 'Enable GitHub Pages', + input: { + repoUrl: 'github.com?repo=repo&owner=owner', + buildType: 'workflow', + sourceBranch: 'main', + sourcePath: '/', + token: 'gph_YourGitHubToken', + }, + }, + ], + }), + }, +]; diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubPages.test.ts b/plugins/scaffolder-backend-module-github/src/actions/githubPages.test.ts new file mode 100644 index 0000000000..266f4c5a53 --- /dev/null +++ b/plugins/scaffolder-backend-module-github/src/actions/githubPages.test.ts @@ -0,0 +1,93 @@ +/* + * 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 { TemplateAction } from '@backstage/plugin-scaffolder-node'; +import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test-utils'; +import { ConfigReader } from '@backstage/config'; +import { + DefaultGithubCredentialsProvider, + GithubCredentialsProvider, + ScmIntegrations, +} from '@backstage/integration'; +import { createGithubPagesAction } from './githubPages'; + +const mockOctokit = { + request: jest.fn(), +}; + +jest.mock('octokit', () => ({ + Octokit: class { + constructor() { + return mockOctokit; + } + }, +})); + +describe('github:pages', () => { + const config = new ConfigReader({ + integrations: { + github: [ + { host: 'github.com', token: 'mock-token' }, + { host: 'ghe.github.com' }, + ], + }, + }); + + const integrations = ScmIntegrations.fromConfig(config); + let githubCredentialsProvider: GithubCredentialsProvider; + let action: TemplateAction; + + const mockContext = createMockActionContext({ + input: { + repoUrl: 'github.com?repo=repo&owner=owner', + buildType: 'workflow', + sourceBranch: 'main', + sourcePath: '/', + token: 'gph_YourGitHubToken', + }, + }); + + beforeEach(() => { + githubCredentialsProvider = + DefaultGithubCredentialsProvider.fromIntegrations(integrations); + action = createGithubPagesAction({ + integrations, + githubCredentialsProvider, + }); + }); + + afterEach(jest.resetAllMocks); + + it('should work happy path', async () => { + await action.handler(mockContext); + + expect(mockOctokit.request).toHaveBeenCalledWith( + 'POST /repos/{owner}/{repo}/pages', + { + owner: 'owner', + repo: 'repo', + build_type: 'workflow', + source: { + branch: 'main', + path: '/', + }, + headers: { + 'X-GitHub-Api-Version': '2022-11-28', + }, + }, + ); + }); +}); diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubPages.ts b/plugins/scaffolder-backend-module-github/src/actions/githubPages.ts new file mode 100644 index 0000000000..09910319fe --- /dev/null +++ b/plugins/scaffolder-backend-module-github/src/actions/githubPages.ts @@ -0,0 +1,130 @@ +/* + * Copyright 2024 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 { + GithubCredentialsProvider, + ScmIntegrationRegistry, +} from '@backstage/integration'; +import { Octokit } from 'octokit'; +import { + createTemplateAction, + parseRepoUrl, +} from '@backstage/plugin-scaffolder-node'; +import { examples } from './githubPages.examples'; +import { getOctokitOptions } from '@backstage/plugin-scaffolder-backend-module-github'; + +/** + * Creates a new action that enables GitHub Pages for a repository. + * + * @public + */ +export function createGithubPagesAction(options: { + integrations: ScmIntegrationRegistry; + githubCredentialsProvider?: GithubCredentialsProvider; +}) { + const { integrations, githubCredentialsProvider } = options; + + return createTemplateAction<{ + repoUrl: string; + buildType?: 'legacy' | 'workflow'; + sourceBranch?: string; + sourcePath?: '/' | '/docs'; + token?: string; + }>({ + id: 'github:pages', + examples, + description: 'Enables GitHub Pages for a repository.', + schema: { + input: { + type: 'object', + required: ['repoUrl'], + properties: { + repoUrl: { + title: 'Repository Location', + description: `Accepts the format 'github.com?repo=reponame&owner=owner' where 'reponame' is the new repository name and 'owner' is an organization or username`, + type: 'string', + }, + buildType: { + title: 'Build Type', + type: 'string', + description: + 'The GitHub Pages build type - "legacy" or "workflow". Default is "workflow', + }, + sourceBranch: { + title: 'Source Branch', + type: 'string', + description: + 'The the GitHub Pages source branch. Default is "main"', + }, + sourcePath: { + title: 'Source Path', + type: 'string', + description: + 'The the GitHub Pages source path - "/" or "/docs". Default is "/"', + }, + token: { + title: 'Authorization Token', + type: 'string', + description: 'The token to use for authorization to GitHub', + }, + }, + }, + }, + async handler(ctx) { + const { + repoUrl, + buildType = 'workflow', + sourceBranch = 'main', + sourcePath = '/', + token: providedToken, + } = ctx.input; + + const octokitOptions = await getOctokitOptions({ + integrations, + credentialsProvider: githubCredentialsProvider, + token: providedToken, + repoUrl: repoUrl, + }); + const client = new Octokit(octokitOptions); + + const { owner, repo } = parseRepoUrl(repoUrl, integrations); + + if (!owner) { + throw new InputError('Invalid repository owner provided in repoUrl'); + } + + ctx.logger.info( + `Attempting to enable GitHub Pages for ${owner}/${repo} with "${buildType}" build type, on source branch "${sourceBranch}" and source path "${sourcePath}"`, + ); + + await client.request('POST /repos/{owner}/{repo}/pages', { + owner: owner, + repo: repo, + build_type: buildType, + source: { + branch: sourceBranch, + path: sourcePath, + }, + headers: { + 'X-GitHub-Api-Version': '2022-11-28', + }, + }); + + ctx.logger.info('Completed enabling GitHub Pages'); + }, + }); +} diff --git a/plugins/scaffolder-backend-module-github/src/actions/index.ts b/plugins/scaffolder-backend-module-github/src/actions/index.ts index 40a0da5455..e9a11e9377 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/index.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/index.ts @@ -21,12 +21,12 @@ export { createGithubRepoPushAction } from './githubRepoPush'; export { createGithubWebhookAction } from './githubWebhook'; export { createGithubDeployKeyAction } from './githubDeployKey'; export { createGithubEnvironmentAction } from './githubEnvironment'; - export { createPublishGithubPullRequestAction, type CreateGithubPullRequestActionOptions, } from './githubPullRequest'; export { createPublishGithubAction } from './github'; export { createGithubAutolinksAction } from './githubAutolinks'; +export { createGithubPagesAction } from './githubPages'; export { getOctokitOptions } from './helpers'; diff --git a/plugins/scaffolder-backend-module-github/src/module.ts b/plugins/scaffolder-backend-module-github/src/module.ts index 1817a68bfb..a26fdd7d2d 100644 --- a/plugins/scaffolder-backend-module-github/src/module.ts +++ b/plugins/scaffolder-backend-module-github/src/module.ts @@ -29,6 +29,7 @@ import { createGithubWebhookAction, createPublishGithubAction, createPublishGithubPullRequestAction, + createGithubPagesAction, } from './actions'; import { DefaultGithubCredentialsProvider, @@ -91,6 +92,10 @@ export const githubModule = createBackendModule({ githubCredentialsProvider, config, }), + createGithubPagesAction({ + integrations, + githubCredentialsProvider, + }), ); }, }); From 1469ddade4ee796fac4ebee923433594f3c1e72e Mon Sep 17 00:00:00 2001 From: Andre Wanlin Date: Fri, 28 Jun 2024 15:43:55 -0500 Subject: [PATCH 127/416] Rename based on feedback Signed-off-by: Andre Wanlin --- plugins/scaffolder-backend-module-github/api-report.md | 2 +- ....examples.test.ts => githubPagesEnable.examples.test.ts} | 6 +++--- ...ithubPages.examples.ts => githubPagesEnable.examples.ts} | 0 .../{githubPages.test.ts => githubPagesEnable.test.ts} | 4 ++-- .../src/actions/{githubPages.ts => githubPagesEnable.ts} | 6 +++--- .../scaffolder-backend-module-github/src/actions/index.ts | 2 +- plugins/scaffolder-backend-module-github/src/module.ts | 4 ++-- 7 files changed, 12 insertions(+), 12 deletions(-) rename plugins/scaffolder-backend-module-github/src/actions/{githubPages.examples.test.ts => githubPagesEnable.examples.test.ts} (93%) rename plugins/scaffolder-backend-module-github/src/actions/{githubPages.examples.ts => githubPagesEnable.examples.ts} (100%) rename plugins/scaffolder-backend-module-github/src/actions/{githubPages.test.ts => githubPagesEnable.test.ts} (95%) rename plugins/scaffolder-backend-module-github/src/actions/{githubPages.ts => githubPagesEnable.ts} (96%) diff --git a/plugins/scaffolder-backend-module-github/api-report.md b/plugins/scaffolder-backend-module-github/api-report.md index aa4d94dcd6..0572052fd4 100644 --- a/plugins/scaffolder-backend-module-github/api-report.md +++ b/plugins/scaffolder-backend-module-github/api-report.md @@ -108,7 +108,7 @@ export function createGithubIssuesLabelAction(options: { >; // @public -export function createGithubPagesAction(options: { +export function createGithubPagesEnableAction(options: { integrations: ScmIntegrationRegistry; githubCredentialsProvider?: GithubCredentialsProvider; }): TemplateAction< diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubPages.examples.test.ts b/plugins/scaffolder-backend-module-github/src/actions/githubPagesEnable.examples.test.ts similarity index 93% rename from plugins/scaffolder-backend-module-github/src/actions/githubPages.examples.test.ts rename to plugins/scaffolder-backend-module-github/src/actions/githubPagesEnable.examples.test.ts index 7480d8d478..ee7b5caa65 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubPages.examples.test.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubPagesEnable.examples.test.ts @@ -22,8 +22,8 @@ import { GithubCredentialsProvider, ScmIntegrations, } from '@backstage/integration'; -import { createGithubPagesAction } from './githubPages'; -import { examples } from './githubPages.examples'; +import { createGithubPagesEnableAction } from './githubPagesEnable'; +import { examples } from './githubPagesEnable.examples'; import yaml from 'yaml'; const mockOctokit = { @@ -60,7 +60,7 @@ describe('github:pages', () => { beforeEach(() => { githubCredentialsProvider = DefaultGithubCredentialsProvider.fromIntegrations(integrations); - action = createGithubPagesAction({ + action = createGithubPagesEnableAction({ integrations, githubCredentialsProvider, }); diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubPages.examples.ts b/plugins/scaffolder-backend-module-github/src/actions/githubPagesEnable.examples.ts similarity index 100% rename from plugins/scaffolder-backend-module-github/src/actions/githubPages.examples.ts rename to plugins/scaffolder-backend-module-github/src/actions/githubPagesEnable.examples.ts diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubPages.test.ts b/plugins/scaffolder-backend-module-github/src/actions/githubPagesEnable.test.ts similarity index 95% rename from plugins/scaffolder-backend-module-github/src/actions/githubPages.test.ts rename to plugins/scaffolder-backend-module-github/src/actions/githubPagesEnable.test.ts index 266f4c5a53..203014b67b 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubPages.test.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubPagesEnable.test.ts @@ -22,7 +22,7 @@ import { GithubCredentialsProvider, ScmIntegrations, } from '@backstage/integration'; -import { createGithubPagesAction } from './githubPages'; +import { createGithubPagesEnableAction } from './githubPagesEnable'; const mockOctokit = { request: jest.fn(), @@ -63,7 +63,7 @@ describe('github:pages', () => { beforeEach(() => { githubCredentialsProvider = DefaultGithubCredentialsProvider.fromIntegrations(integrations); - action = createGithubPagesAction({ + action = createGithubPagesEnableAction({ integrations, githubCredentialsProvider, }); diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubPages.ts b/plugins/scaffolder-backend-module-github/src/actions/githubPagesEnable.ts similarity index 96% rename from plugins/scaffolder-backend-module-github/src/actions/githubPages.ts rename to plugins/scaffolder-backend-module-github/src/actions/githubPagesEnable.ts index 09910319fe..044005961e 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubPages.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubPagesEnable.ts @@ -24,7 +24,7 @@ import { createTemplateAction, parseRepoUrl, } from '@backstage/plugin-scaffolder-node'; -import { examples } from './githubPages.examples'; +import { examples } from './githubPagesEnable.examples'; import { getOctokitOptions } from '@backstage/plugin-scaffolder-backend-module-github'; /** @@ -32,7 +32,7 @@ import { getOctokitOptions } from '@backstage/plugin-scaffolder-backend-module-g * * @public */ -export function createGithubPagesAction(options: { +export function createGithubPagesEnableAction(options: { integrations: ScmIntegrationRegistry; githubCredentialsProvider?: GithubCredentialsProvider; }) { @@ -45,7 +45,7 @@ export function createGithubPagesAction(options: { sourcePath?: '/' | '/docs'; token?: string; }>({ - id: 'github:pages', + id: 'github:pages:enable', examples, description: 'Enables GitHub Pages for a repository.', schema: { diff --git a/plugins/scaffolder-backend-module-github/src/actions/index.ts b/plugins/scaffolder-backend-module-github/src/actions/index.ts index e9a11e9377..6f37678099 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/index.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/index.ts @@ -27,6 +27,6 @@ export { } from './githubPullRequest'; export { createPublishGithubAction } from './github'; export { createGithubAutolinksAction } from './githubAutolinks'; -export { createGithubPagesAction } from './githubPages'; +export { createGithubPagesEnableAction } from './githubPagesEnable'; export { getOctokitOptions } from './helpers'; diff --git a/plugins/scaffolder-backend-module-github/src/module.ts b/plugins/scaffolder-backend-module-github/src/module.ts index a26fdd7d2d..a5676ab8c9 100644 --- a/plugins/scaffolder-backend-module-github/src/module.ts +++ b/plugins/scaffolder-backend-module-github/src/module.ts @@ -29,7 +29,7 @@ import { createGithubWebhookAction, createPublishGithubAction, createPublishGithubPullRequestAction, - createGithubPagesAction, + createGithubPagesEnableAction, } from './actions'; import { DefaultGithubCredentialsProvider, @@ -92,7 +92,7 @@ export const githubModule = createBackendModule({ githubCredentialsProvider, config, }), - createGithubPagesAction({ + createGithubPagesEnableAction({ integrations, githubCredentialsProvider, }), From 780d994544de0045e8aae211a9ebe85957f3ea26 Mon Sep 17 00:00:00 2001 From: Andre Wanlin Date: Fri, 7 Jun 2024 19:35:15 -0500 Subject: [PATCH 128/416] Added `MyGroupsSidebarItem` to the sidebar in the `create-app` template Signed-off-by: Andre Wanlin --- .changeset/bright-fireants-sit.md | 5 +++++ .../default-app/packages/app/src/components/Root/Root.tsx | 7 +++++++ 2 files changed, 12 insertions(+) create mode 100644 .changeset/bright-fireants-sit.md diff --git a/.changeset/bright-fireants-sit.md b/.changeset/bright-fireants-sit.md new file mode 100644 index 0000000000..320bc69ff9 --- /dev/null +++ b/.changeset/bright-fireants-sit.md @@ -0,0 +1,5 @@ +--- +'@backstage/create-app': patch +--- + +Added `MyGroupsSidebarItem` to the sidebar in the `create-app` template diff --git a/packages/create-app/templates/default-app/packages/app/src/components/Root/Root.tsx b/packages/create-app/templates/default-app/packages/app/src/components/Root/Root.tsx index 71c04122ae..853d175bae 100644 --- a/packages/create-app/templates/default-app/packages/app/src/components/Root/Root.tsx +++ b/packages/create-app/templates/default-app/packages/app/src/components/Root/Root.tsx @@ -25,6 +25,8 @@ import { } from '@backstage/core-components'; import MenuIcon from '@material-ui/icons/Menu'; import SearchIcon from '@material-ui/icons/Search'; +import { MyGroupsSidebarItem } from '@backstage/plugin-org'; +import GroupIcon from '@material-ui/icons/People'; const useSidebarLogoStyles = makeStyles({ root: { @@ -65,6 +67,11 @@ export const Root = ({ children }: PropsWithChildren<{}>) => ( }> {/* Global nav, not org-specific */} + From e5b5e08374ba687016191e2bc61da878c0ccc41c Mon Sep 17 00:00:00 2001 From: Andre Wanlin Date: Mon, 6 May 2024 12:37:50 -0500 Subject: [PATCH 129/416] Added Docs Project Area Signed-off-by: Andre Wanlin --- OWNERS.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/OWNERS.md b/OWNERS.md index 9382b38f4f..4a9fdc4ccc 100644 --- a/OWNERS.md +++ b/OWNERS.md @@ -159,6 +159,18 @@ Scope: The Scaffolder frontend and backend plugins, and related tooling. | ------------------- | ------------ | ------------------------------------- | ---------------- | | Bogdan Nechyporenko | Bol.com | [acierto](https://github.com/acierto) | `bogdan_haarlem` | +### Documentation + +Team: @backstage/documentation-maintainers + +Scope: The Backstage Documentation + +| Name | Organization | GitHub | Discord | +| -------------- | ------------ | ----------------------------------------------------- | ----------------- | +| Andre Wanlin | Spotify | [awanlin](https://github.com/awanlin) | `ahhhndre` | +| Aramis Sennyey | | [aramissennyeydd](https://github.com/aramissennyeydd) | `Aramis#7984` | +| Waldir Montoya | Broadcom | [waldirmontoya25](https://github.com/waldirmontoya25) | `waldirmontoya25` | + ## Sponsors | Name | Organization | GitHub | Email | From a8d0b87f1bb6c91c6db6a5fd6c4939bcb6c450df Mon Sep 17 00:00:00 2001 From: Andre Wanlin Date: Wed, 19 Jun 2024 11:35:56 -0500 Subject: [PATCH 130/416] Updates Signed-off-by: Andre Wanlin --- OWNERS.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/OWNERS.md b/OWNERS.md index 4a9fdc4ccc..16e884e518 100644 --- a/OWNERS.md +++ b/OWNERS.md @@ -165,11 +165,11 @@ Team: @backstage/documentation-maintainers Scope: The Backstage Documentation -| Name | Organization | GitHub | Discord | -| -------------- | ------------ | ----------------------------------------------------- | ----------------- | -| Andre Wanlin | Spotify | [awanlin](https://github.com/awanlin) | `ahhhndre` | -| Aramis Sennyey | | [aramissennyeydd](https://github.com/aramissennyeydd) | `Aramis#7984` | -| Waldir Montoya | Broadcom | [waldirmontoya25](https://github.com/waldirmontoya25) | `waldirmontoya25` | +| Name | Organization | GitHub | Discord | +| --------------- | ------------- | ----------------------------------------------------- | -------------------- | +| Andre Wanlin | Spotify | [awanlin](https://github.com/awanlin) | `ahhhndre` | +| Aramis Sennyey | | [aramissennyeydd](https://github.com/aramissennyeydd) | `Aramis#7984` | +| Peter Macdonald | VodafoneZiggo | [parsifal-m](https://github.com/Parsifal-M) | `Peter "Parsifal-M"` | ## Sponsors From 8def8fec564f38f69fdbd82a567ba52cb0d4dcba Mon Sep 17 00:00:00 2001 From: Andre Wanlin Date: Fri, 28 Jun 2024 15:47:58 -0500 Subject: [PATCH 131/416] Updates Signed-off-by: Andre Wanlin --- OWNERS.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/OWNERS.md b/OWNERS.md index 16e884e518..5012181d21 100644 --- a/OWNERS.md +++ b/OWNERS.md @@ -165,11 +165,11 @@ Team: @backstage/documentation-maintainers Scope: The Backstage Documentation -| Name | Organization | GitHub | Discord | -| --------------- | ------------- | ----------------------------------------------------- | -------------------- | -| Andre Wanlin | Spotify | [awanlin](https://github.com/awanlin) | `ahhhndre` | -| Aramis Sennyey | | [aramissennyeydd](https://github.com/aramissennyeydd) | `Aramis#7984` | -| Peter Macdonald | VodafoneZiggo | [parsifal-m](https://github.com/Parsifal-M) | `Peter "Parsifal-M"` | +| Name | Organization | GitHub | Discord | +| --------------- | ------------- | ----------------------------------------------------- | ------------- | +| Andre Wanlin | Spotify | [awanlin](https://github.com/awanlin) | `ahhhndre` | +| Aramis Sennyey | | [aramissennyeydd](https://github.com/aramissennyeydd) | `Aramis#7984` | +| Peter Macdonald | VodafoneZiggo | [Parsifal-M](https://github.com/Parsifal-M) | `parsifal` | ## Sponsors From 281f44b1e2b3ef4b9bb474a0e935a185773b54c1 Mon Sep 17 00:00:00 2001 From: Jonathan Stevens Date: Fri, 28 Jun 2024 17:51:01 -0600 Subject: [PATCH 132/416] fix(docs): fixing/simplifying new backend system search imports Signed-off-by: Jonathan Stevens --- docs/features/search/how-to-guides.md | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/docs/features/search/how-to-guides.md b/docs/features/search/how-to-guides.md index 6564fd0a44..9ce30da556 100644 --- a/docs/features/search/how-to-guides.md +++ b/docs/features/search/how-to-guides.md @@ -396,21 +396,17 @@ Recently, the Backstage maintainers [announced the new Backend System](https://b In "packages/backend/index.ts", install the search plugin [1], the search engine [2], and the search collators/decorators modules [3]: ```ts -import { searchPlugin } from '@backstage/plugin-search-backend/alpha'; -import { searchModuleElasticsearchEngine } from '@backstage/plugin-search-backend-module-elasticsearch/alpha'; -import { searchModuleCatalogCollator } from '@backstage/plugin-search-backend-module-catalog/alpha'; -import { searchModuleTechDocsCollator } from '@backstage/plugin-search-backend-module-techdocs/alpha'; -import { searchModuleExploreCollator } from '@backstage/plugin-search-backend-module-explore/alpha'; - const backend = createBackend(); // [1] adding the search plugin to the backend -backend.add(searchPlugin()); +backend.add(import('@backstage/plugin-search-backend/alpha')); // [2] (optional) the default search engine is Lunr, if you want to extend the search backend with another search engine. -backend.add(searchModuleElasticsearchEngine()); +backend.add( + import('@backstage/plugin-search-backend-module-elasticsearch/alpha'), +); // [3] extending search with collator modules to start index documents, take in optional schedule parameters. -backend.add(searchModuleCatalogCollator()); -backend.add(searchModuleTechDocsCollator()); -backend.add(searchModuleExploreCollator()); +backend.add(import('@backstage/plugin-search-backend-module-catalog/alpha')); +backend.add(import('@backstage/plugin-search-backend-module-techdocs/alpha')); +backend.add(import('@backstage/plugin-search-backend-module-explore/alpha')); backend.start(); ``` From 84b2516fbb4c00b70b4ab8f42ea509bf466a773a Mon Sep 17 00:00:00 2001 From: aramissennyeydd Date: Sat, 29 Jun 2024 11:18:27 -0400 Subject: [PATCH 133/416] fix(docs): add scheduler to custom provider example Signed-off-by: aramissennyeydd --- .../software-catalog/external-integrations.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/docs/features/software-catalog/external-integrations.md b/docs/features/software-catalog/external-integrations.md index 6eaee2f80d..c77ed51943 100644 --- a/docs/features/software-catalog/external-integrations.md +++ b/docs/features/software-catalog/external-integrations.md @@ -300,9 +300,19 @@ export const catalogModuleFrobsProvider = createBackendModule({ deps: { catalog: catalogProcessingExtensionPoint, reader: coreServices.urlReader, + scheduler: coreServices.scheduler, }, - async init({ catalog, reader }) { - catalog.addEntityProvider(new FrobsProvider('dev', reader)); + async init({ catalog, reader, scheduler }) { + const frobs = new FrobsProvider('dev', reader); + catalog.addEntityProvider(frobs); + await scheduler.scheduleTask({ + id: 'run_frobs_refresh', + fn: async () => { + await frobs.run(); + }, + frequency: { minutes: 30 }, + timeout: { minutes: 10 }, + }); }, }); }, From db2e2d51f612b6cddab9b61ab46527263b8f4aa0 Mon Sep 17 00:00:00 2001 From: Marco Crivellaro Date: Sat, 29 Jun 2024 20:04:46 +0200 Subject: [PATCH 134/416] Config schema to support app.routes.bindings Signed-off-by: Marco Crivellaro --- .changeset/friendly-experts-fail.md | 5 +++++ packages/core-app-api/config.d.ts | 12 ++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 .changeset/friendly-experts-fail.md diff --git a/.changeset/friendly-experts-fail.md b/.changeset/friendly-experts-fail.md new file mode 100644 index 0000000000..df2d2e2b24 --- /dev/null +++ b/.changeset/friendly-experts-fail.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-app-api': patch +--- + +Updated config schema to support app.routes.bindings diff --git a/packages/core-app-api/config.d.ts b/packages/core-app-api/config.d.ts index 22f241fbcf..1a7ccb666f 100644 --- a/packages/core-app-api/config.d.ts +++ b/packages/core-app-api/config.d.ts @@ -65,6 +65,18 @@ export interface Config { }>; }>; }; + + routes?: { + /** + * Maps external route references to regular route references. Both the + * key and the value is expected to be on the form `.`. + * If the value is `false`, the route will be disabled even if it has a + * default mapping. + * + * @deepVisibility frontend + */ + bindings?: { [externalRouteRefId: string]: string | false }; + }; }; /** From 1edd6c27ee943747bd58e0bf35c86944902287e6 Mon Sep 17 00:00:00 2001 From: Tim Klever Date: Sat, 29 Jun 2024 11:29:38 -0700 Subject: [PATCH 135/416] feat: update ConfigSources options to match process.env typings Signed-off-by: Tim Klever --- .changeset/neat-bears-divide.md | 28 +++++++++++++++++++ packages/config-loader/api-report.md | 2 +- .../src/sources/ConfigSources.ts | 2 +- 3 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 .changeset/neat-bears-divide.md diff --git a/.changeset/neat-bears-divide.md b/.changeset/neat-bears-divide.md new file mode 100644 index 0000000000..b40db6c7bd --- /dev/null +++ b/.changeset/neat-bears-divide.md @@ -0,0 +1,28 @@ +--- +'@backstage/config-loader': major +--- + +**BREAKING** The `env` property on the `ConfigSourcesDefaultOptions` interface allows for undefined members. + +This change makes `ConfigSourcesDefaultOptions.env` consistent with other parts of this package and the wider +`node` ecosystem. Specifically, with this update `ConfigSourcesDefaultOptions.env`'s types match: + +#### EnvConfigSource + +- [`EnvConfigSource.constructor`](https://github.com/backstage/backstage/blob/c780320418b7775f18fc0d2cc279ee7db9c7cb25/packages/config-loader/src/sources/EnvConfigSource.ts#L68) +- [`EnvConfigSourceOptions`](https://github.com/backstage/backstage/blob/c780320418b7775f18fc0d2cc279ee7db9c7cb25/packages/config-loader/src/sources/EnvConfigSource.ts#L31) +- [`readEnvConfig`](https://github.com/backstage/backstage/blob/c780320418b7775f18fc0d2cc279ee7db9c7cb25/packages/config-loader/src/sources/EnvConfigSource.ts#L114) + +#### NodeJS process.env + +- [`ProcessEnv`](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/aa121ee3a7a3caa16433b66c1103df5904f612ea/types/node/v18/process.d.ts#L137) + which extends [`Dict`](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/aa121ee3a7a3caa16433b66c1103df5904f612ea/types/node/v18/globals.d.ts#L333-L335) + +While this is a somewhat trivial change, it does loosen typings on a public interface, so by definition it's a breaking +change and a major version bump. + +You may meed to update your backstage instance if you have built an implementation of `ConfigSources` or any other +functionality that relies on `ConfigSourcesDefaultOptions`. This change means you'll have to update that code to account +for the possibility of `undefined` values inside `ConfigSourcesDefaultOptions.env`, although it is very likely already +accounted for as the typings for [`process.env`](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/aa121ee3a7a3caa16433b66c1103df5904f612ea/types/node/v18/process.d.ts#L137) +already include the possibility of [`undefined`](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/aa121ee3a7a3caa16433b66c1103df5904f612ea/types/node/v18/globals.d.ts#L333-L335). diff --git a/packages/config-loader/api-report.md b/packages/config-loader/api-report.md index bc8f217bbb..da836ffd21 100644 --- a/packages/config-loader/api-report.md +++ b/packages/config-loader/api-report.md @@ -87,7 +87,7 @@ export interface ConfigSourcesDefaultOptions extends BaseConfigSourcesOptions { // (undocumented) argv?: string[]; // (undocumented) - env?: Record; + env?: Record; } // @public diff --git a/packages/config-loader/src/sources/ConfigSources.ts b/packages/config-loader/src/sources/ConfigSources.ts index ecff39da2d..15eede736e 100644 --- a/packages/config-loader/src/sources/ConfigSources.ts +++ b/packages/config-loader/src/sources/ConfigSources.ts @@ -102,7 +102,7 @@ export interface ConfigSourcesDefaultForTargetsOptions */ export interface ConfigSourcesDefaultOptions extends BaseConfigSourcesOptions { argv?: string[]; - env?: Record; + env?: Record; } /** From b83fbc00b1c3c262f390236597906be97c7b1a08 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 29 Jun 2024 20:20:56 +0000 Subject: [PATCH 136/416] Update dependency @types/prop-types to v15.7.12 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 8d1c0ecb06..d22cee2a71 100644 --- a/yarn.lock +++ b/yarn.lock @@ -18383,9 +18383,9 @@ __metadata: linkType: hard "@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 + version: 15.7.12 + resolution: "@types/prop-types@npm:15.7.12" + checksum: ac16cc3d0a84431ffa5cfdf89579ad1e2269549f32ce0c769321fdd078f84db4fbe1b461ed5a1a496caf09e637c0e367d600c541435716a55b1d9713f5035dfe languageName: node linkType: hard From d26fc8c19f52044f1d4c64e36b853a442c32b872 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 29 Jun 2024 21:16:49 +0000 Subject: [PATCH 137/416] Update dependency grpc-docs to v1.1.4 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/yarn.lock b/yarn.lock index 20a828a69b..b337884121 100644 --- a/yarn.lock +++ b/yarn.lock @@ -20270,6 +20270,16 @@ __metadata: languageName: node linkType: hard +"GendocuPublicApis@https://git.gendocu.com/gendocu/GendocuPublicApis.git#master": + version: 1.0.0 + resolution: "GendocuPublicApis@https://git.gendocu.com/gendocu/GendocuPublicApis.git#commit=6e8d4c1d2342556a2e8e719f19385b266001ebae" + dependencies: + "@improbable-eng/grpc-web": ^0.14.0 + google-protobuf: ^3.15.8 + checksum: 2c8f28cd89e9a71e5f9df819115a89659d98f22d6e7a6b2f3fc0bc24a4ca954c0112070c00401749dcbcdeeb42ca070d6d8a36b3c205fbf13409fb1110b5966e + languageName: node + linkType: hard + "a-sync-waterfall@npm:^1.0.0": version: 1.0.1 resolution: "a-sync-waterfall@npm:1.0.1" @@ -27962,16 +27972,6 @@ __metadata: languageName: node linkType: hard -"gendocu-public-apis@npm:^1.0.0": - version: 1.0.0 - resolution: "gendocu-public-apis@npm:1.0.0" - dependencies: - "@improbable-eng/grpc-web": ^0.14.0 - google-protobuf: ^3.15.8 - checksum: ee1548d1285f9d2dc7ef04c959e620516322314c8aa2f2bfedd25345a6211abf51cdca4d54cca18de8f31a90f2b86ab171ae41f7c2f39dfdd0ac7163f875f719 - languageName: node - linkType: hard - "generate-function@npm:^2.3.1": version: 2.3.1 resolution: "generate-function@npm:2.3.1" @@ -28392,10 +28392,10 @@ __metadata: languageName: node linkType: hard -"google-protobuf@npm:^3.15.8, google-protobuf@npm:^3.19.1": - version: 3.20.1 - resolution: "google-protobuf@npm:3.20.1" - checksum: a440fbc329bb441b253bc421b01540918f4b66921c47a3bc57d154d2677dc917cb1a29126ff35ddc4d8872d1b5843ef1ece60b6dff506ba64a9f5807962d3f61 +"google-protobuf@npm:^3.15.8, google-protobuf@npm:^3.21.2": + version: 3.21.2 + resolution: "google-protobuf@npm:3.21.2" + checksum: 3caa2e1e2654714cc1a201ac5e5faabcaa48f5fba3d8ff9b64ca66fe19e4e0506b94053f32eddc77bf3a7a47ac1660315c6744185c1e2bb27654fd76fe91b988 languageName: node linkType: hard @@ -28593,13 +28593,13 @@ __metadata: linkType: hard "grpc-docs@npm:^1.0.6, grpc-docs@npm:^1.1.2": - version: 1.1.3 - resolution: "grpc-docs@npm:1.1.3" + version: 1.1.4 + resolution: "grpc-docs@npm:1.1.4" dependencies: "@improbable-eng/grpc-web": ^0.15.0 "@types/minimatch": ^3.0.5 - gendocu-public-apis: ^1.0.0 - google-protobuf: ^3.19.1 + GendocuPublicApis: "https://git.gendocu.com/gendocu/GendocuPublicApis.git#master" + google-protobuf: ^3.21.2 grpc-docs: ^1.0.6 js-yaml: ^4.1.0 minimatch: ^3.0.4 @@ -28612,7 +28612,7 @@ __metadata: styled-components: ^5.3.3 peerDependencies: react: ^16.0.0 - checksum: 1bcd3179ce276e8fd34229acc6d3f1024908b7e6734e36ddcc4852c6db0100b900093355652577ab476c9927167cff92b05e560713995803154d4dbd4459f973 + checksum: 55b088011205fe82ced6af763136bb2494eb059445c5776bf29922439b814fa8983774a68910c47898cef5be82bea60801c2f96305e76170cff1df3f890b8d18 languageName: node linkType: hard From e23579b0bb25b2c29940273d8fd0ed8fccb4e951 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Sat, 29 Jun 2024 23:37:12 +0200 Subject: [PATCH 138/416] Update .changeset/friendly-bulldogs-pay.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .changeset/friendly-bulldogs-pay.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.changeset/friendly-bulldogs-pay.md b/.changeset/friendly-bulldogs-pay.md index 9c7ab8f9cb..d77c739bb0 100644 --- a/.changeset/friendly-bulldogs-pay.md +++ b/.changeset/friendly-bulldogs-pay.md @@ -2,4 +2,6 @@ '@backstage/plugin-catalog-backend-module-ldap': minor --- +**BREAKING**: `readLdapOrg` and the `LdapProviderConfig` type now always accept arrays of user and group configs, not just single items. + Added support for single ldap catalog provider to provide list and undefined user and group bindings next to standard single one. From 85542a9e79543fda5bda36da9495db866654006c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 29 Jun 2024 22:18:21 +0000 Subject: [PATCH 139/416] Update dependency knip to v5.23.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 b337884121..5ec7bb2899 100644 --- a/yarn.lock +++ b/yarn.lock @@ -32067,8 +32067,8 @@ __metadata: linkType: hard "knip@npm:^5.0.0": - version: 5.23.1 - resolution: "knip@npm:5.23.1" + version: 5.23.2 + resolution: "knip@npm:5.23.2" dependencies: "@ericcornelissen/bash-parser": 0.5.3 "@nodelib/fs.walk": 2.0.0 @@ -32094,7 +32094,7 @@ __metadata: bin: knip: bin/knip.js knip-bun: bin/knip-bun.js - checksum: d3c39f266907b2c8f241e4d7d7c4b3a4fa1500c57f7e60f86bd3e9cd2684696e4c84b823d2a461b23cdc729a310ad571eec6ac22acacb5a4b17130d19ef5b866 + checksum: efcfa5bea3848bb6e054cb80a840dbcc718a1c91d8f6c508a686239de5e1fe7775afc05d03fd624f07fb545767b4a08a5c59b7a29a009cbad001cb68a1e92859 languageName: node linkType: hard From 2fb0eb88b7e1105ec9b7a193ab68ce3d66606b77 Mon Sep 17 00:00:00 2001 From: John Redwood Date: Sun, 30 Jun 2024 10:31:15 +1000 Subject: [PATCH 140/416] fix: allow gitlab pipeline triggers to include variables Signed-off-by: John Redwood --- .changeset/three-carpets-smoke.md | 5 ++++ .../api-report.md | 1 + .../actions/gitlabPipelineTrigger.examples.ts | 1 + .../src/actions/gitlabPipelineTrigger.test.ts | 29 +++++++++++++++++++ .../src/actions/gitlabPipelineTrigger.ts | 9 +++++- 5 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 .changeset/three-carpets-smoke.md diff --git a/.changeset/three-carpets-smoke.md b/.changeset/three-carpets-smoke.md new file mode 100644 index 0000000000..e096fe054d --- /dev/null +++ b/.changeset/three-carpets-smoke.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend-module-gitlab': minor +--- + +Fixed trigger pipeline accepting input variables diff --git a/plugins/scaffolder-backend-module-gitlab/api-report.md b/plugins/scaffolder-backend-module-gitlab/api-report.md index 4f9239e9b2..b1f240029e 100644 --- a/plugins/scaffolder-backend-module-gitlab/api-report.md +++ b/plugins/scaffolder-backend-module-gitlab/api-report.md @@ -211,6 +211,7 @@ export const createTriggerGitlabPipelineAction: (options: { projectId: number; tokenDescription: string; token?: string | undefined; + variables?: Record | undefined; }, { pipelineUrl: string; diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabPipelineTrigger.examples.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabPipelineTrigger.examples.ts index 4948db908b..d0840030df 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabPipelineTrigger.examples.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabPipelineTrigger.examples.ts @@ -33,6 +33,7 @@ export const examples: TemplateExample[] = [ 'This is the text that will appear in the pipeline token', token: 'glpt-xxxxxxxxxxxx', branch: 'main', + variables: { var_one: 'one', var_two: 'two' }, }, }, ], diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabPipelineTrigger.test.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabPipelineTrigger.test.ts index a7412032a4..3803198ec8 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabPipelineTrigger.test.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabPipelineTrigger.test.ts @@ -101,6 +101,7 @@ describe('gitlab:pipeline:trigger', () => { 123, 'main', 'glptt-abcdef', + { variables: undefined }, ); expect(mockGitlabClient.PipelineTriggerTokens.remove).toHaveBeenCalledWith( @@ -189,6 +190,7 @@ describe('gitlab:pipeline:trigger', () => { 123, 'main', 'glptt-abcdef', + { variables: undefined }, ); expect(mockGitlabClient.PipelineTriggerTokens.remove).toHaveBeenCalledWith( @@ -196,6 +198,7 @@ describe('gitlab:pipeline:trigger', () => { 42, ); }); + it('should clean up pipeline token on failure', async () => { const mockContext = createMockActionContext({ input: { @@ -232,4 +235,30 @@ describe('gitlab:pipeline:trigger', () => { 42, ); }); + + it('should succeed trigger and pass variables', async () => { + const mockContext = createMockActionContext({ + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: 123, + tokenDescription: 'My cool pipeline token', + branch: 'main', + variables: { var_one: 'val1', var_two: 'val2' }, + }, + workspacePath: 'seen2much', + }); + + await expect( + action.handler({ + ...mockContext, + }), + ).rejects.toThrow('Failed to trigger pipeline'); + + expect(mockGitlabClient.PipelineTriggerTokens.trigger).toHaveBeenCalledWith( + 123, + 'main', + 'glptt-abcdef', + { variables: { var_one: 'val1', var_two: 'val2' } }, + ); + }); }); diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabPipelineTrigger.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabPipelineTrigger.ts index 6937fe44aa..b9f629edfb 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabPipelineTrigger.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabPipelineTrigger.ts @@ -30,6 +30,12 @@ const pipelineInputProperties = z.object({ projectId: z.number().describe('Project Id'), tokenDescription: z.string().describe('Pipeline token description'), branch: z.string().describe('Project branch'), + variables: z + .record(z.string(), z.string()) + .optional() + .describe( + 'A object/record of key-valued strings containing the pipeline variables.', + ), }); const pipelineOutputProperties = z.object({ @@ -57,7 +63,7 @@ export const createTriggerGitlabPipelineAction = (options: { async handler(ctx) { let pipelineTokenResponse: PipelineTriggerTokenSchema | null = null; - const { repoUrl, projectId, tokenDescription, token, branch } = + const { repoUrl, projectId, tokenDescription, token, branch, variables } = commonGitlabConfig.merge(pipelineInputProperties).parse(ctx.input); const { host } = parseRepoUrl(repoUrl, integrations); @@ -84,6 +90,7 @@ export const createTriggerGitlabPipelineAction = (options: { projectId, branch, pipelineTokenResponse.token, + { variables }, )) as ExpandedPipelineSchema; if (!pipelineTriggerResponse.id) { From b141c20b53082ad16af942c2574040d4b83921c6 Mon Sep 17 00:00:00 2001 From: Stephen Glass Date: Sun, 30 Jun 2024 00:53:24 -0400 Subject: [PATCH 141/416] Move review object explode function into utils Signed-off-by: Stephen Glass --- .../components/ReviewState/ReviewState.tsx | 34 +--- .../next/components/ReviewState/util.test.ts | 187 ++++++++++++++++++ .../src/next/components/ReviewState/util.ts | 49 +++++ 3 files changed, 238 insertions(+), 32 deletions(-) create mode 100644 plugins/scaffolder-react/src/next/components/ReviewState/util.test.ts create mode 100644 plugins/scaffolder-react/src/next/components/ReviewState/util.ts diff --git a/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.tsx b/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.tsx index 22ec54ac26..95f5d76212 100644 --- a/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.tsx +++ b/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.tsx @@ -15,9 +15,10 @@ */ import React from 'react'; import { StructuredMetadataTable } from '@backstage/core-components'; -import { JsonObject, JsonValue } from '@backstage/types'; +import { JsonObject } from '@backstage/types'; import { Draft07 as JSONSchema } from 'json-schema-library'; import { ParsedTemplateSchema } from '../../hooks/useTemplateSchema'; +import { flattenObject, isJsonObject } from './util'; /** * The props for the {@link ReviewState} component. @@ -28,37 +29,6 @@ export type ReviewStateProps = { formState: JsonObject; }; -function flattenObject( - obj: JsonObject, - prefix: string, - schema: JSONSchema, - formState: JsonObject, -): [string, JsonValue | undefined][] { - return Object.entries(obj).flatMap(([key, value]) => { - const prefixedKey = prefix ? `${prefix}/${key}` : key; - - const definitionInSchema = schema.getSchema({ - pointer: `#/${prefixedKey}`, - data: formState, - }); - - if (definitionInSchema) { - const backstageReviewOptions = definitionInSchema['ui:backstage']?.review; - - // Recurse into nested objects - if (backstageReviewOptions?.explode && isJsonObject(value)) { - return flattenObject(value, prefixedKey, schema, formState); - } - } - - return [[key, value]]; - }); -} - -function isJsonObject(value?: JsonValue): value is JsonObject { - return typeof value === 'object' && value !== null && !Array.isArray(value); -} - /** * The component used by the {@link Stepper} to render the review step. * @alpha diff --git a/plugins/scaffolder-react/src/next/components/ReviewState/util.test.ts b/plugins/scaffolder-react/src/next/components/ReviewState/util.test.ts new file mode 100644 index 0000000000..c468c1a055 --- /dev/null +++ b/plugins/scaffolder-react/src/next/components/ReviewState/util.test.ts @@ -0,0 +1,187 @@ +/* eslint-disable no-console */ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { flattenObject, isJsonObject } from './util'; +import { Draft07 as JSONSchema } from 'json-schema-library'; +import { ParsedTemplateSchema } from '../../hooks/useTemplateSchema'; + +describe('isJsonObject', () => { + it('should return true for non-null objects', () => { + expect(isJsonObject({})).toBe(true); + expect(isJsonObject({ key: 'value' })).toBe(true); + }); + + it('should return false for null', () => { + expect(isJsonObject(null)).toBe(false); + }); + + it('should return false for arrays', () => { + expect(isJsonObject([])).toBe(false); + expect(isJsonObject([1, 2, 3])).toBe(false); + }); + + it('should return false for non-objects', () => { + expect(isJsonObject('string')).toBe(false); + expect(isJsonObject(123)).toBe(false); + expect(isJsonObject(true)).toBe(false); + expect(isJsonObject(undefined)).toBe(false); + }); +}); + +describe('flattenObject', () => { + it('should handle an empty object', () => { + const schemas: ParsedTemplateSchema[] = [ + { + mergedSchema: { + type: 'object', + properties: { + name: { + type: 'object', + 'ui:backstage': { + review: { + explode: true, + }, + }, + properties: {}, + }, + }, + }, + schema: {}, + title: 'test', + uiSchema: {}, + }, + ]; + + const parsedSchema = new JSONSchema(schemas[0].mergedSchema); + + const result = flattenObject({}, '', parsedSchema, {}); + + expect(result).toEqual([]); + }); + + it('should flatten a simple object', () => { + const formState = { + name: { + foo: 'value1', + bar: 'value2', + }, + }; + + const schemas: ParsedTemplateSchema[] = [ + { + mergedSchema: { + type: 'object', + properties: { + name: { + type: 'object', + 'ui:backstage': { + review: { + explode: true, + }, + }, + properties: { + foo: { + type: 'string', + }, + bar: { + type: 'string', + }, + }, + }, + }, + }, + schema: {}, + title: 'test', + uiSchema: {}, + }, + ]; + + const [key, value] = Object.entries(formState)[0]; + const parsedSchema = new JSONSchema(schemas[0].mergedSchema); + + const result = flattenObject(value, key, parsedSchema, formState); + + expect(result).toEqual([ + ['foo', 'value1'], + ['bar', 'value2'], + ]); + }); + + it('should recurse into a nested object', () => { + const formState = { + name: { + foo: 'value1', + bar: 'value2', + example: { + test: 'value3', + }, + }, + }; + const schemas: ParsedTemplateSchema[] = [ + { + mergedSchema: { + type: 'object', + properties: { + name: { + type: 'object', + 'ui:backstage': { + review: { + explode: true, + }, + }, + properties: { + foo: { + type: 'string', + }, + bar: { + type: 'string', + }, + example: { + type: 'object', + 'ui:backstage': { + review: { + explode: true, + }, + }, + properties: { + test: { + type: 'string', + }, + }, + }, + }, + }, + }, + }, + schema: {}, + title: 'test', + uiSchema: {}, + }, + ]; + + const [key, value] = Object.entries(formState)[0]; + const parsedSchema = new JSONSchema(schemas[0].mergedSchema); + + const result = flattenObject(value, key, parsedSchema, formState); + + expect(result).toEqual([ + ['foo', 'value1'], + ['bar', 'value2'], + ['test', 'value3'], + ]); + }); +}); diff --git a/plugins/scaffolder-react/src/next/components/ReviewState/util.ts b/plugins/scaffolder-react/src/next/components/ReviewState/util.ts new file mode 100644 index 0000000000..0bb6fc08d2 --- /dev/null +++ b/plugins/scaffolder-react/src/next/components/ReviewState/util.ts @@ -0,0 +1,49 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { JsonObject, JsonValue } from '@backstage/types'; +import { Draft07 as JSONSchema } from 'json-schema-library'; + +export function flattenObject( + obj: JsonObject, + prefix: string, + schema: JSONSchema, + formState: JsonObject, +): [string, JsonValue | undefined][] { + return Object.entries(obj).flatMap(([key, value]) => { + const prefixedKey = prefix ? `${prefix}/${key}` : key; + + const definitionInSchema = schema.getSchema({ + pointer: `#/${prefixedKey}`, + data: formState, + }); + + if (definitionInSchema) { + const backstageReviewOptions = definitionInSchema['ui:backstage']?.review; + + // Recurse into nested objects + if (backstageReviewOptions?.explode && isJsonObject(value)) { + return flattenObject(value, prefixedKey, schema, formState); + } + } + + return [[key, value]]; + }); +} + +export function isJsonObject(value?: JsonValue): value is JsonObject { + return typeof value === 'object' && value !== null && !Array.isArray(value); +} From 08b7c3e1802702b456d4b51c69ddfa5d327e1f13 Mon Sep 17 00:00:00 2001 From: Stephen Glass Date: Sun, 30 Jun 2024 01:29:30 -0400 Subject: [PATCH 142/416] Remove debug code Signed-off-by: Stephen Glass --- .../src/next/components/ReviewState/util.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/scaffolder-react/src/next/components/ReviewState/util.test.ts b/plugins/scaffolder-react/src/next/components/ReviewState/util.test.ts index c468c1a055..e2a10587dc 100644 --- a/plugins/scaffolder-react/src/next/components/ReviewState/util.test.ts +++ b/plugins/scaffolder-react/src/next/components/ReviewState/util.test.ts @@ -1,4 +1,3 @@ -/* eslint-disable no-console */ /* * Copyright 2022 The Backstage Authors * From 54429b5cac736d131636fdff4c5b444fe279955a Mon Sep 17 00:00:00 2001 From: Ambarish07 <43902240+Ambarish07@users.noreply.github.com> Date: Mon, 1 Jul 2024 01:20:29 +0530 Subject: [PATCH 143/416] fixed filename and imports for scaffolder-node-test-utils plugin fix: fixed the filename and imports for scaffolder-node-test-utils plugin --------- Signed-off-by: Ambarish07 --- .changeset/yellow-cows-kick.md | 5 +++++ plugins/scaffolder-node-test-utils/src/actions/index.ts | 2 +- .../actions/{mockActionConext.ts => mockActionContext.ts} | 0 3 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 .changeset/yellow-cows-kick.md rename plugins/scaffolder-node-test-utils/src/actions/{mockActionConext.ts => mockActionContext.ts} (100%) diff --git a/.changeset/yellow-cows-kick.md b/.changeset/yellow-cows-kick.md new file mode 100644 index 0000000000..93c7e1cff1 --- /dev/null +++ b/.changeset/yellow-cows-kick.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-node-test-utils': patch +--- + +Filename and imports correction for mockActionContext.ts diff --git a/plugins/scaffolder-node-test-utils/src/actions/index.ts b/plugins/scaffolder-node-test-utils/src/actions/index.ts index 161bae8521..aee195cd34 100644 --- a/plugins/scaffolder-node-test-utils/src/actions/index.ts +++ b/plugins/scaffolder-node-test-utils/src/actions/index.ts @@ -14,4 +14,4 @@ * limitations under the License. */ -export { createMockActionContext } from './mockActionConext'; +export { createMockActionContext } from './mockActionContext'; diff --git a/plugins/scaffolder-node-test-utils/src/actions/mockActionConext.ts b/plugins/scaffolder-node-test-utils/src/actions/mockActionContext.ts similarity index 100% rename from plugins/scaffolder-node-test-utils/src/actions/mockActionConext.ts rename to plugins/scaffolder-node-test-utils/src/actions/mockActionContext.ts From cab824fd984f342163a24c1c3bc1faff82fba5a7 Mon Sep 17 00:00:00 2001 From: Ben Lambert Date: Mon, 1 Jul 2024 12:30:40 +0200 Subject: [PATCH 144/416] Update three-carpets-smoke.md Signed-off-by: Ben Lambert --- .changeset/three-carpets-smoke.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.changeset/three-carpets-smoke.md b/.changeset/three-carpets-smoke.md index e096fe054d..ab6d857f7d 100644 --- a/.changeset/three-carpets-smoke.md +++ b/.changeset/three-carpets-smoke.md @@ -1,5 +1,5 @@ --- -'@backstage/plugin-scaffolder-backend-module-gitlab': minor +'@backstage/plugin-scaffolder-backend-module-gitlab': patch --- -Fixed trigger pipeline accepting input variables +Added support for passing `variables` to `gitlab:pipeline:trigger` From 9a85f1cdaf0fb28e65bdf2958276e528ccad4af5 Mon Sep 17 00:00:00 2001 From: Beth Griggs Date: Mon, 1 Jul 2024 15:41:24 +0100 Subject: [PATCH 145/416] chore: add delay to useGetEntities batches and dedupe Signed-off-by: Beth Griggs --- .../OwnershipCard/useGetEntities.test.ts | 8 +++- .../Cards/OwnershipCard/useGetEntities.ts | 46 ++++++++++--------- 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.test.ts b/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.test.ts index 2c223c3f4f..207b01099e 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.test.ts +++ b/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.test.ts @@ -266,7 +266,9 @@ describe('useGetEntities', () => { }, ); - await waitFor(() => expect(result.current.loading).toBe(false)); + await waitFor(() => expect(result.current.loading).toBe(false), { + timeout: 5000, + }); const callArgs = (catalogApiMock.getEntities as jest.Mock).mock .calls[0][0]; @@ -318,7 +320,9 @@ describe('useGetEntities', () => { }, ); - await waitFor(() => expect(result.current.loading).toBe(false)); + await waitFor(() => expect(result.current.loading).toBe(false), { + timeout: 5000, + }); const callArgs = (catalogApiMock.getEntities as jest.Mock).mock .calls[0][0]; diff --git a/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.ts b/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.ts index d919e1d7c5..27fe3019e2 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.ts +++ b/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.ts @@ -32,7 +32,7 @@ import { useApi } from '@backstage/core-plugin-api'; import useAsync from 'react-use/esm/useAsync'; import qs from 'qs'; import { EntityRelationAggregation } from '../types'; -import { uniq } from 'lodash'; +import { uniq, uniqBy } from 'lodash'; const limiter = limiterFactory(5); @@ -143,37 +143,41 @@ const getOwners = async ( return [stringifyEntityRef(entity)]; }; +const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)); + const batchGetOwnedEntitiesByOwners = async ( owners: string[], kinds: string[], catalogApi: CatalogApi, batchSize: number = 100, + delayMs: number = 100, ) => { - const batches = []; + const results = []; for (let i = 0; i < owners.length; i += batchSize) { const batch = owners.slice(i, i + batchSize); - batches.push( - catalogApi.getEntities({ - filter: [ - { - kind: kinds, - 'relations.ownedBy': batch, - }, - ], - fields: [ - 'kind', - 'metadata.name', - 'metadata.namespace', - 'spec.type', - 'relations', - ], - }), - ); + const response = await catalogApi.getEntities({ + filter: [ + { + kind: kinds, + 'relations.ownedBy': batch, + }, + ], + fields: [ + 'kind', + 'metadata.name', + 'metadata.namespace', + 'spec.type', + 'relations', + ], + }); + + results.push(...response.items); + + if (i + batchSize < owners.length) await delay(delayMs); } - const results = await Promise.all(batches); - return results.flatMap(result => result.items); + return uniqBy(results, stringifyEntityRef); }; export function useGetEntities( From 8944b8b53762bab1acaa9f93fc12ac86444d9e8f Mon Sep 17 00:00:00 2001 From: Coraly Romero-Principe <34314397+cromero-principe@users.noreply.github.com> Date: Mon, 1 Jul 2024 13:29:43 -0500 Subject: [PATCH 146/416] Update README.md Update the plugin import line in the installation instructions for the new backend Signed-off-by: Coraly Romero-Principe <34314397+cromero-principe@users.noreply.github.com> --- plugins/catalog-backend-module-unprocessed/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/catalog-backend-module-unprocessed/README.md b/plugins/catalog-backend-module-unprocessed/README.md index 6b350e5ef8..f01347912d 100644 --- a/plugins/catalog-backend-module-unprocessed/README.md +++ b/plugins/catalog-backend-module-unprocessed/README.md @@ -17,7 +17,7 @@ yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-unproce In `packages/backend/src/index.ts` add the module: ```ts title="packages/backend/src/index.ts" -backend.add(catalogModuleUnprocessedEntities()); +backend.add(import('@backstage/plugin-catalog-backend-module-unprocessed')); ``` ### Legacy Backend From ff1bb4c39ecf55d801b0c33244e292b6f0949ea7 Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Mon, 1 Jul 2024 22:17:07 +0200 Subject: [PATCH 147/416] Added a documentation how to use checkpoints + the fix when to clean the workspace Signed-off-by: bnechyporenko --- .changeset/kind-dancers-boil.md | 5 ++++ .../writing-custom-actions.md | 26 ++++++++++++++++++- .../tasks/NunjucksWorkflowRunner.ts | 13 ++++++---- 3 files changed, 38 insertions(+), 6 deletions(-) create mode 100644 .changeset/kind-dancers-boil.md diff --git a/.changeset/kind-dancers-boil.md b/.changeset/kind-dancers-boil.md new file mode 100644 index 0000000000..8e69e830df --- /dev/null +++ b/.changeset/kind-dancers-boil.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend': patch +--- + +Added a documentation how to use checkpoints + the fix when to clean the workspace diff --git a/docs/features/software-templates/writing-custom-actions.md b/docs/features/software-templates/writing-custom-actions.md index e8b354bd45..41bd7d2026 100644 --- a/docs/features/software-templates/writing-custom-actions.md +++ b/docs/features/software-templates/writing-custom-actions.md @@ -145,6 +145,8 @@ When the action `handler` is called, we provide you a `context` as the only argument. It looks like the following: - `ctx.baseUrl` - a string where the template is located +- `ctx.checkpoint` - _Experimental_ allows to implement idempotency of the actions by not re-running the same function again if it was + executed successfully on the previous run. - `ctx.logger` - a Winston logger for additional logging inside your action - `ctx.logStream` - a stream version of the logger if needed - `ctx.workspacePath` - a string of the working directory of the template run @@ -153,7 +155,7 @@ argument. It looks like the following: - `ctx.output` - a function which you can call to set outputs that match the JSON schema or `zod` in `schema.output` for ex. `ctx.output('downloadUrl', myDownloadUrl)` - `createTemporaryDirectory` a function to call to give you a temporary - directory somewhere on the runner so you can store some files there rather + directory somewhere on the runner, so you can store some files there rather than polluting the `workspacePath` - `ctx.metadata` - an object containing a `name` field, indicating the template name. More metadata fields may be added later. @@ -217,6 +219,28 @@ import { }) ``` +### Using Checkpoints in Custom Actions (Experimental) + +Idempotent action could be achieved via the usage of checkpoints. + +Example: + +```ts +const res = await ctx.checkpoint?.('create.projects', async () => { + const projectStgId = createStagingProjectId(); + const projectProId = createProductionProjectId(); + + return { + projectStgId, + projectProId, + }; +}); +``` + +You have to define the unique key in scope of the scaffolder task for your checkpoint. During the execution task engine +will check if the checkpoint with such key was already executed or not, if yes, and the run was successful, the callback +will be skipped and instead the stored value will be returned. + ### Register Custom Actions with the Legacy Backend System Once you have your Custom Action ready for usage with the scaffolder, you'll diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts index 3b88fd0f10..69f17e9dce 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts @@ -508,11 +508,11 @@ export class NunjucksWorkflowRunner implements WorkflowRunner { const output = this.render(task.spec.output, context, renderTemplate); await taskTrack.markSuccessful(); + await task.cleanWorkspace?.(); return { output }; } finally { if (workspacePath) { - await task.cleanWorkspace?.(); await fs.remove(workspacePath); } } @@ -554,10 +554,13 @@ function scaffoldingTracker() { step: TaskStep, action: TemplateAction, ) { - task.emitLog(`Skipping because ${action.id} does not support dry-run`, { - stepId: step.id, - status: 'skipped', - }); + await task.emitLog( + `Skipping because ${action.id} does not support dry-run`, + { + stepId: step.id, + status: 'skipped', + }, + ); } async function markSuccessful() { From b29b39302ca0df2bb4cd97753f60f52e6470d747 Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Tue, 2 Jul 2024 09:08:29 +0200 Subject: [PATCH 148/416] Excluding the fix from this PR Signed-off-by: bnechyporenko --- .changeset/kind-dancers-boil.md | 2 +- .../src/scaffolder/tasks/NunjucksWorkflowRunner.ts | 13 +++++-------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/.changeset/kind-dancers-boil.md b/.changeset/kind-dancers-boil.md index 8e69e830df..4451cab4f4 100644 --- a/.changeset/kind-dancers-boil.md +++ b/.changeset/kind-dancers-boil.md @@ -2,4 +2,4 @@ '@backstage/plugin-scaffolder-backend': patch --- -Added a documentation how to use checkpoints + the fix when to clean the workspace +Added a documentation how to use checkpoints diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts index 69f17e9dce..3b88fd0f10 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts @@ -508,11 +508,11 @@ export class NunjucksWorkflowRunner implements WorkflowRunner { const output = this.render(task.spec.output, context, renderTemplate); await taskTrack.markSuccessful(); - await task.cleanWorkspace?.(); return { output }; } finally { if (workspacePath) { + await task.cleanWorkspace?.(); await fs.remove(workspacePath); } } @@ -554,13 +554,10 @@ function scaffoldingTracker() { step: TaskStep, action: TemplateAction, ) { - await task.emitLog( - `Skipping because ${action.id} does not support dry-run`, - { - stepId: step.id, - status: 'skipped', - }, - ); + task.emitLog(`Skipping because ${action.id} does not support dry-run`, { + stepId: step.id, + status: 'skipped', + }); } async function markSuccessful() { From 08c63d46ac9ab0987363b5cf314dda81115991f3 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 2 Jul 2024 09:03:14 +0000 Subject: [PATCH 149/416] Version Packages (next) --- .changeset/pre.json | 18 + docs/releases/v1.29.0-next.1-changelog.md | 1952 +++++++++++++++++ package.json | 2 +- packages/app-defaults/CHANGELOG.md | 11 + packages/app-defaults/package.json | 2 +- packages/app-next/CHANGELOG.md | 43 + packages/app-next/package.json | 2 +- packages/app/CHANGELOG.md | 41 + packages/app/package.json | 2 +- packages/backend-app-api/CHANGELOG.md | 17 + packages/backend-app-api/package.json | 2 +- packages/backend-common/CHANGELOG.md | 17 + packages/backend-common/package.json | 2 +- packages/backend-defaults/CHANGELOG.md | 21 + packages/backend-defaults/package.json | 2 +- .../CHANGELOG.md | 26 + .../package.json | 2 +- packages/backend-legacy/CHANGELOG.md | 42 + packages/backend-legacy/package.json | 2 +- packages/backend-openapi-utils/CHANGELOG.md | 8 + packages/backend-openapi-utils/package.json | 2 +- packages/backend-plugin-api/CHANGELOG.md | 12 + packages/backend-plugin-api/package.json | 2 +- packages/backend-tasks/CHANGELOG.md | 11 + packages/backend-tasks/package.json | 2 +- packages/backend-test-utils/CHANGELOG.md | 15 + packages/backend-test-utils/package.json | 2 +- packages/backend/CHANGELOG.md | 37 + packages/backend/package.json | 2 +- packages/cli/CHANGELOG.md | 17 + packages/cli/package.json | 2 +- packages/core-app-api/CHANGELOG.md | 11 + packages/core-app-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/frontend-app-api/CHANGELOG.md | 15 + packages/frontend-app-api/package.json | 2 +- packages/frontend-test-utils/CHANGELOG.md | 10 + packages/frontend-test-utils/package.json | 2 +- packages/repo-tools/CHANGELOG.md | 12 + 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 | 11 + packages/techdocs-cli/package.json | 2 +- packages/test-utils/CHANGELOG.md | 13 + packages/test-utils/package.json | 2 +- plugins/api-docs/CHANGELOG.md | 15 + plugins/api-docs/package.json | 2 +- plugins/app-backend/CHANGELOG.md | 14 + plugins/app-backend/package.json | 2 +- plugins/app-node/CHANGELOG.md | 8 + plugins/app-node/package.json | 2 +- .../CHANGELOG.md | 8 + .../package.json | 2 +- .../CHANGELOG.md | 11 + .../package.json | 2 +- .../CHANGELOG.md | 10 + .../package.json | 2 +- .../CHANGELOG.md | 8 + .../package.json | 2 +- .../CHANGELOG.md | 10 + .../package.json | 2 +- .../CHANGELOG.md | 10 + .../package.json | 2 +- .../CHANGELOG.md | 8 + .../package.json | 2 +- .../CHANGELOG.md | 8 + .../package.json | 2 +- .../CHANGELOG.md | 8 + .../package.json | 2 +- .../CHANGELOG.md | 11 + .../package.json | 2 +- .../CHANGELOG.md | 8 + .../package.json | 2 +- .../CHANGELOG.md | 8 + .../package.json | 2 +- .../CHANGELOG.md | 9 + .../package.json | 2 +- .../CHANGELOG.md | 10 + .../package.json | 2 +- .../CHANGELOG.md | 8 + .../package.json | 2 +- .../CHANGELOG.md | 8 + .../package.json | 2 +- .../CHANGELOG.md | 9 + .../package.json | 2 +- .../CHANGELOG.md | 9 + .../package.json | 2 +- plugins/auth-backend/CHANGELOG.md | 30 + plugins/auth-backend/package.json | 2 +- plugins/auth-node/CHANGELOG.md | 13 + plugins/auth-node/package.json | 2 +- .../catalog-backend-module-aws/CHANGELOG.md | 17 + .../catalog-backend-module-aws/package.json | 2 +- .../catalog-backend-module-azure/CHANGELOG.md | 13 + .../catalog-backend-module-azure/package.json | 2 +- .../CHANGELOG.md | 13 + .../package.json | 2 +- .../CHANGELOG.md | 17 + .../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 | 13 + .../package.json | 2 +- .../CHANGELOG.md | 13 + .../package.json | 2 +- .../CHANGELOG.md | 44 + .../package.json | 2 +- .../CHANGELOG.md | 11 + .../package.json | 2 +- .../CHANGELOG.md | 15 + .../package.json | 2 +- .../CHANGELOG.md | 16 + .../package.json | 2 +- .../catalog-backend-module-ldap/CHANGELOG.md | 20 + .../catalog-backend-module-ldap/package.json | 2 +- .../catalog-backend-module-logs/CHANGELOG.md | 9 + .../catalog-backend-module-logs/package.json | 2 +- .../CHANGELOG.md | 13 + .../package.json | 2 +- .../CHANGELOG.md | 15 + .../package.json | 2 +- .../CHANGELOG.md | 14 + .../package.json | 2 +- .../CHANGELOG.md | 11 + .../package.json | 2 +- .../CHANGELOG.md | 14 + .../package.json | 2 +- plugins/catalog-backend/CHANGELOG.md | 26 + plugins/catalog-backend/package.json | 2 +- plugins/catalog-graph/CHANGELOG.md | 14 + plugins/catalog-graph/package.json | 2 +- plugins/catalog-import/CHANGELOG.md | 18 + plugins/catalog-import/package.json | 2 +- plugins/catalog-node/CHANGELOG.md | 14 + plugins/catalog-node/package.json | 2 +- plugins/catalog-react/CHANGELOG.md | 19 + plugins/catalog-react/package.json | 2 +- plugins/catalog/CHANGELOG.md | 22 + plugins/catalog/package.json | 2 +- plugins/devtools-backend/CHANGELOG.md | 16 + plugins/devtools-backend/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 | 10 + .../example-todo-list-backend/package.json | 2 +- plugins/home-react/CHANGELOG.md | 12 + plugins/home-react/package.json | 2 +- plugins/home/CHANGELOG.md | 21 + plugins/home/package.json | 2 +- plugins/kubernetes-backend/CHANGELOG.md | 20 + plugins/kubernetes-backend/package.json | 2 +- plugins/kubernetes-cluster/CHANGELOG.md | 12 + plugins/kubernetes-cluster/package.json | 2 +- plugins/kubernetes-node/CHANGELOG.md | 10 + plugins/kubernetes-node/package.json | 2 +- plugins/kubernetes/CHANGELOG.md | 12 + plugins/kubernetes/package.json | 2 +- .../CHANGELOG.md | 15 + .../package.json | 2 +- plugins/notifications-backend/CHANGELOG.md | 17 + plugins/notifications-backend/package.json | 2 +- plugins/notifications-node/CHANGELOG.md | 12 + plugins/notifications-node/package.json | 2 +- plugins/notifications/CHANGELOG.md | 14 + plugins/notifications/package.json | 2 +- plugins/org-react/CHANGELOG.md | 11 + plugins/org-react/package.json | 2 +- plugins/org/CHANGELOG.md | 14 + plugins/org/package.json | 2 +- .../CHANGELOG.md | 10 + .../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/proxy-backend/CHANGELOG.md | 10 + plugins/proxy-backend/package.json | 2 +- .../CHANGELOG.md | 11 + .../package.json | 2 +- .../CHANGELOG.md | 12 + .../package.json | 2 +- .../CHANGELOG.md | 11 + .../package.json | 2 +- .../CHANGELOG.md | 13 + .../package.json | 2 +- .../CHANGELOG.md | 12 + .../package.json | 2 +- .../CHANGELOG.md | 13 + .../package.json | 2 +- .../CHANGELOG.md | 11 + .../package.json | 2 +- .../CHANGELOG.md | 11 + .../package.json | 2 +- .../CHANGELOG.md | 11 + .../package.json | 2 +- .../CHANGELOG.md | 17 + .../package.json | 2 +- .../CHANGELOG.md | 13 + .../package.json | 2 +- .../CHANGELOG.md | 11 + .../package.json | 2 +- .../CHANGELOG.md | 13 + .../package.json | 2 +- .../CHANGELOG.md | 10 + .../package.json | 2 +- .../CHANGELOG.md | 10 + .../package.json | 2 +- plugins/scaffolder-backend/CHANGELOG.md | 31 + plugins/scaffolder-backend/package.json | 2 +- .../scaffolder-node-test-utils/CHANGELOG.md | 11 + .../scaffolder-node-test-utils/package.json | 2 +- plugins/scaffolder-node/CHANGELOG.md | 13 + plugins/scaffolder-node/package.json | 2 +- plugins/scaffolder-react/CHANGELOG.md | 24 + plugins/scaffolder-react/package.json | 2 +- plugins/scaffolder/CHANGELOG.md | 25 + plugins/scaffolder/package.json | 2 +- .../CHANGELOG.md | 18 + .../package.json | 2 +- .../CHANGELOG.md | 12 + .../package.json | 2 +- .../CHANGELOG.md | 12 + .../package.json | 2 +- plugins/search-backend-module-pg/CHANGELOG.md | 12 + 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/CHANGELOG.md | 16 + plugins/search/package.json | 2 +- plugins/signals-backend/CHANGELOG.md | 13 + plugins/signals-backend/package.json | 2 +- plugins/signals-node/CHANGELOG.md | 12 + plugins/signals-node/package.json | 2 +- .../techdocs-addons-test-utils/CHANGELOG.md | 15 + .../techdocs-addons-test-utils/package.json | 2 +- plugins/techdocs-backend/CHANGELOG.md | 18 + plugins/techdocs-backend/package.json | 2 +- plugins/techdocs-node/CHANGELOG.md | 16 + plugins/techdocs-node/package.json | 2 +- plugins/techdocs/CHANGELOG.md | 22 + plugins/techdocs/package.json | 2 +- plugins/user-settings-backend/CHANGELOG.md | 14 + plugins/user-settings-backend/package.json | 2 +- plugins/user-settings/CHANGELOG.md | 17 + plugins/user-settings/package.json | 2 +- 275 files changed, 4055 insertions(+), 137 deletions(-) create mode 100644 docs/releases/v1.29.0-next.1-changelog.md diff --git a/.changeset/pre.json b/.changeset/pre.json index df3592a582..ebf0c6bf22 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -189,6 +189,7 @@ "@backstage/plugin-scaffolder-backend-module-gcp": "0.0.1-next.1" }, "changesets": [ + "bright-fireants-sit", "bright-panthers-leave", "calm-jeans-ring", "chilly-roses-trade", @@ -196,11 +197,16 @@ "create-app-1719320674", "curvy-teachers-smell", "eighty-games-wink", + "fair-fans-flow", "fair-pillows-know", "fair-rockets-leave", "famous-dodos-crash", + "fast-pens-smell", "fifty-pumpkins-smell", + "friendly-bulldogs-pay", + "friendly-experts-fail", "friendly-masks-type", + "friendly-oranges-greet", "friendly-stingrays-occur", "funny-laws-tease", "gentle-avocados-obey", @@ -211,22 +217,34 @@ "light-avocados-worry", "little-games-fail", "metal-jokes-add", + "metal-parents-brush", + "metal-suits-drum", "moody-llamas-breathe", + "neat-dingos-tickle", + "poor-cheetahs-raise", "rare-peas-dream", "renovate-7b61228", + "renovate-ced359b", "rich-bears-march", "selfish-turtles-jog", "serious-kings-trade", "short-flowers-cry", "shy-hounds-battle", "silent-experts-move", + "silent-lobsters-tease", "silent-moose-eat", "soft-clocks-bake", "sour-jokes-sneeze", + "spotty-crabs-shop", + "swift-dots-cough", "ten-dancers-drum", + "ten-nails-hear", "ten-pots-walk", "thick-lizards-divide", + "three-carpets-smoke", "tough-lies-mate", + "weak-boats-float", + "yellow-cows-kick", "young-donuts-swim", "young-fishes-lie", "young-houses-unite" diff --git a/docs/releases/v1.29.0-next.1-changelog.md b/docs/releases/v1.29.0-next.1-changelog.md new file mode 100644 index 0000000000..34cd038f22 --- /dev/null +++ b/docs/releases/v1.29.0-next.1-changelog.md @@ -0,0 +1,1952 @@ +# Release v1.29.0-next.1 + +Upgrade Helper: [https://backstage.github.io/upgrade-helper/?to=1.29.0-next.1](https://backstage.github.io/upgrade-helper/?to=1.29.0-next.1) + +## @backstage/plugin-catalog-backend@1.24.0-next.1 + +### Minor Changes + +- b9ed1bb: bumped better-sqlite3 from ^9.0.0 to ^11.0.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-openapi-utils@0.1.15-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.13.0-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.24 + - @backstage/plugin-catalog-node@1.12.4-next.1 + - @backstage/plugin-events-node@0.3.8-next.1 + - @backstage/plugin-permission-common@0.7.14 + - @backstage/plugin-permission-node@0.7.33-next.1 + - @backstage/plugin-search-backend-module-catalog@0.1.28-next.1 + +## @backstage/plugin-catalog-backend-module-ldap@0.7.0-next.1 + +### Minor Changes + +- cb32ca7: **BREAKING**: `readLdapOrg` and the `LdapProviderConfig` type now always accept arrays of user and group configs, not just single items. + + Added support for single ldap catalog provider to provide list and undefined user and group bindings next to standard single one. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.24 + - @backstage/plugin-catalog-node@1.12.4-next.1 + +## @backstage/plugin-scaffolder-react@1.10.0-next.1 + +### Minor Changes + +- 354e68c: Improve validation error display text in scaffolder + +### Patch Changes + +- cc81579: Updated dependency `@rjsf/utils` to `5.18.5`. + Updated dependency `@rjsf/core` to `5.18.5`. + Updated dependency `@rjsf/material-ui` to `5.18.5`. + Updated dependency `@rjsf/validator-ajv8` to `5.18.5`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.2-next.1 + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + - @backstage/plugin-permission-react@0.4.23 + - @backstage/plugin-scaffolder-common@1.5.3 + +## @backstage/app-defaults@1.5.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.13.1-next.1 + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + - @backstage/plugin-permission-react@0.4.23 + +## @backstage/backend-app-api@0.7.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/cli-common@0.1.14 + - @backstage/cli-node@0.2.6 + - @backstage/config@1.2.0 + - @backstage/config-loader@1.8.1 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + - @backstage/plugin-permission-node@0.7.33-next.1 + +## @backstage/backend-common@0.23.3-next.1 + +### Patch Changes + +- b9ed1bb: bumped better-sqlite3 from ^9.0.0 to ^11.0.0 +- Updated dependencies + - @backstage/backend-dev-utils@0.1.4 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/config-loader@1.8.1 + - @backstage/errors@1.2.4 + - @backstage/integration@1.13.0-next.0 + - @backstage/integration-aws-node@0.1.12 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + +## @backstage/backend-defaults@0.3.4-next.1 + +### Patch Changes + +- b9ed1bb: bumped better-sqlite3 from ^9.0.0 to ^11.0.0 +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-app-api@0.7.10-next.1 + - @backstage/backend-dev-utils@0.1.4 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/config-loader@1.8.1 + - @backstage/errors@1.2.4 + - @backstage/integration@1.13.0-next.0 + - @backstage/integration-aws-node@0.1.12 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + - @backstage/plugin-events-node@0.3.8-next.1 + - @backstage/plugin-permission-node@0.7.33-next.1 + +## @backstage/backend-dynamic-feature-service@0.2.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.24.0-next.1 + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-app-api@0.7.10-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/cli-common@0.1.14 + - @backstage/cli-node@0.2.6 + - @backstage/config@1.2.0 + - @backstage/config-loader@1.8.1 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-app-node@0.1.22-next.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + - @backstage/plugin-events-backend@0.3.9-next.1 + - @backstage/plugin-events-node@0.3.8-next.1 + - @backstage/plugin-permission-common@0.7.14 + - @backstage/plugin-permission-node@0.7.33-next.1 + - @backstage/plugin-scaffolder-node@0.4.8-next.1 + - @backstage/plugin-search-backend-node@1.2.27-next.1 + - @backstage/plugin-search-common@1.2.12 + +## @backstage/backend-openapi-utils@0.1.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/errors@1.2.4 + +## @backstage/backend-plugin-api@0.6.22-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + - @backstage/plugin-permission-common@0.7.14 + +## @backstage/backend-tasks@0.5.27-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/backend-test-utils@0.4.4-next.1 + +### Patch Changes + +- b9ed1bb: bumped better-sqlite3 from ^9.0.0 to ^11.0.0 +- Updated dependencies + - @backstage/backend-defaults@0.3.4-next.1 + - @backstage/backend-app-api@0.7.10-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + - @backstage/plugin-events-node@0.3.8-next.1 + +## @backstage/cli@0.26.11-next.1 + +### Patch Changes + +- 4baac0c: The `backendPlugin` and `backendModule` factory now includes a step for automatically adding the new backend plugin/module to the `index.ts` file of the backend. +- Updated dependencies + - @backstage/catalog-model@1.5.0 + - @backstage/cli-common@0.1.14 + - @backstage/cli-node@0.2.6 + - @backstage/config@1.2.0 + - @backstage/config-loader@1.8.1 + - @backstage/errors@1.2.4 + - @backstage/eslint-plugin@0.1.8 + - @backstage/integration@1.13.0-next.0 + - @backstage/release-manifests@0.0.11 + - @backstage/types@1.1.1 + +## @backstage/core-app-api@1.13.1-next.1 + +### Patch Changes + +- db2e2d5: Updated config schema to support app.routes.bindings +- Updated dependencies + - @backstage/core-plugin-api@1.9.3 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + +## @backstage/create-app@0.5.17-next.1 + +### Patch Changes + +- 780d994: Added `MyGroupsSidebarItem` to the sidebar in the `create-app` template +- Updated dependencies + - @backstage/cli-common@0.1.14 + +## @backstage/dev-utils@1.0.35-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.13.1-next.1 + - @backstage/plugin-catalog-react@1.12.2-next.1 + - @backstage/app-defaults@1.5.8-next.1 + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/catalog-model@1.5.0 + - @backstage/integration-react@1.1.29-next.0 + - @backstage/theme@0.5.6 + +## @backstage/frontend-app-api@0.7.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.13.1-next.1 + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/frontend-plugin-api@0.6.7-next.0 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + +## @backstage/frontend-test-utils@0.1.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-app-api@0.7.3-next.1 + - @backstage/test-utils@1.5.8-next.1 + - @backstage/frontend-plugin-api@0.6.7-next.0 + - @backstage/types@1.1.1 + +## @backstage/repo-tools@0.9.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/cli-common@0.1.14 + - @backstage/cli-node@0.2.6 + - @backstage/config-loader@1.8.1 + - @backstage/errors@1.2.4 + +## @techdocs/cli@1.8.16-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs-node@1.12.8-next.1 + - @backstage/backend-defaults@0.3.4-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + +## @backstage/test-utils@1.5.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.13.1-next.1 + - @backstage/core-plugin-api@1.9.3 + - @backstage/config@1.2.0 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.14 + - @backstage/plugin-permission-react@0.4.23 + +## @backstage/plugin-api-docs@0.11.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.2-next.1 + - @backstage/plugin-catalog@1.21.1-next.1 + - @backstage/core-compat-api@0.2.7-next.0 + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/catalog-model@1.5.0 + - @backstage/frontend-plugin-api@0.6.7-next.0 + - @backstage/plugin-catalog-common@1.0.24 + - @backstage/plugin-permission-react@0.4.23 + +## @backstage/plugin-app-backend@0.3.71-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/config-loader@1.8.1 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-app-node@0.1.22-next.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + +## @backstage/plugin-app-node@0.1.22-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config-loader@1.8.1 + +## @backstage/plugin-auth-backend@0.22.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-backend-module-atlassian-provider@0.2.3-next.1 + - @backstage/plugin-auth-backend-module-aws-alb-provider@0.1.14-next.1 + - @backstage/plugin-auth-backend-module-azure-easyauth-provider@0.1.5-next.1 + - @backstage/plugin-auth-backend-module-bitbucket-provider@0.1.5-next.1 + - @backstage/plugin-auth-backend-module-cloudflare-access-provider@0.1.5-next.1 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.17-next.1 + - @backstage/plugin-auth-backend-module-github-provider@0.1.19-next.1 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.1.19-next.1 + - @backstage/plugin-auth-backend-module-google-provider@0.1.19-next.1 + - @backstage/plugin-auth-backend-module-microsoft-provider@0.1.17-next.1 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.2.3-next.1 + - @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.15-next.1 + - @backstage/plugin-auth-backend-module-oidc-provider@0.2.3-next.1 + - @backstage/plugin-auth-backend-module-okta-provider@0.0.15-next.1 + - @backstage/plugin-auth-backend-module-onelogin-provider@0.1.3-next.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + - @backstage/plugin-catalog-node@1.12.4-next.1 + +## @backstage/plugin-auth-backend-module-atlassian-provider@0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + +## @backstage/plugin-auth-backend-module-aws-alb-provider@0.1.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-backend@0.22.9-next.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + +## @backstage/plugin-auth-backend-module-azure-easyauth-provider@0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.17-next.1 + +## @backstage/plugin-auth-backend-module-bitbucket-provider@0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + +## @backstage/plugin-auth-backend-module-cloudflare-access-provider@0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.17-next.1 + +## @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + +## @backstage/plugin-auth-backend-module-github-provider@0.1.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + +## @backstage/plugin-auth-backend-module-gitlab-provider@0.1.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + +## @backstage/plugin-auth-backend-module-google-provider@0.1.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + +## @backstage/plugin-auth-backend-module-guest-provider@0.1.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.17-next.1 + +## @backstage/plugin-auth-backend-module-microsoft-provider@0.1.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + +## @backstage/plugin-auth-backend-module-oauth2-provider@0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + +## @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.17-next.1 + +## @backstage/plugin-auth-backend-module-oidc-provider@0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/plugin-auth-backend@0.22.9-next.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + +## @backstage/plugin-auth-backend-module-okta-provider@0.0.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + +## @backstage/plugin-auth-backend-module-onelogin-provider@0.1.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + +## @backstage/plugin-auth-backend-module-pinniped-provider@0.1.16-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/plugin-auth-node@0.4.17-next.1 + +## @backstage/plugin-auth-backend-module-vmware-cloud-provider@0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-auth-node@0.4.17-next.1 + +## @backstage/plugin-auth-node@0.4.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog@1.21.1-next.1 + +### Patch Changes + +- 06c0956: Support i18n for catalog and catalog-react plugins +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.2-next.1 + - @backstage/core-compat-api@0.2.7-next.0 + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/plugin-search-react@1.7.13-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/frontend-plugin-api@0.6.7-next.0 + - @backstage/integration-react@1.1.29-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.24 + - @backstage/plugin-permission-react@0.4.23 + - @backstage/plugin-scaffolder-common@1.5.3 + - @backstage/plugin-search-common@1.2.12 + +## @backstage/plugin-catalog-backend-module-aws@0.3.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.13.0-next.0 + - @backstage/integration-aws-node@0.1.12 + - @backstage/plugin-catalog-common@1.0.24 + - @backstage/plugin-catalog-node@1.12.4-next.1 + - @backstage/plugin-kubernetes-common@0.8.0 + +## @backstage/plugin-catalog-backend-module-azure@0.1.42-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/config@1.2.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-catalog-common@1.0.24 + - @backstage/plugin-catalog-node@1.12.4-next.1 + +## @backstage/plugin-catalog-backend-module-backstage-openapi@0.2.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-openapi-utils@0.1.15-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-catalog-node@1.12.4-next.1 + +## @backstage/plugin-catalog-backend-module-bitbucket-cloud@0.2.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.21-next.0 + - @backstage/plugin-catalog-common@1.0.24 + - @backstage/plugin-catalog-node@1.12.4-next.1 + - @backstage/plugin-events-node@0.3.8-next.1 + +## @backstage/plugin-catalog-backend-module-bitbucket-server@0.1.36-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-catalog-node@1.12.4-next.1 + +## @backstage/plugin-catalog-backend-module-gcp@0.1.23-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/plugin-catalog-node@1.12.4-next.1 + - @backstage/plugin-kubernetes-common@0.8.0 + +## @backstage/plugin-catalog-backend-module-gerrit@0.1.39-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-catalog-node@1.12.4-next.1 + +## @backstage/plugin-catalog-backend-module-github@0.6.5-next.1 + +### Patch Changes + +- 9112efc: Adds support for `repository` events. + + The provider adds a subscription to the topic `github.repository`. + + Hereby, it supports events of type `repository` with actions + + - `archived` + - `deleted` + - `edited` + - `renamed` + - `transferred` + - `unarchived` + + Actions skipped as they don't require entity changes: + + - `created` + - `privatized` + - `publicized` + + If the config option `validateLocationsExist` is enabled, an API request + is necessary and will be executed. + This affects the actions `renamed`, `transferred`, and `unarchive` + of event type `repository`. + + Catalog entities related to the `GithubEntityProvider` instance will be adjusted + according to action and its meaning for them. + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.24.0-next.1 + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-catalog-common@1.0.24 + - @backstage/plugin-catalog-node@1.12.4-next.1 + - @backstage/plugin-events-node@0.3.8-next.1 + +## @backstage/plugin-catalog-backend-module-github-org@0.1.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend-module-github@0.6.5-next.1 + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/config@1.2.0 + - @backstage/plugin-catalog-node@1.12.4-next.1 + - @backstage/plugin-events-node@0.3.8-next.1 + +## @backstage/plugin-catalog-backend-module-gitlab@0.3.21-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-catalog-common@1.0.24 + - @backstage/plugin-catalog-node@1.12.4-next.1 + - @backstage/plugin-events-node@0.3.8-next.1 + +## @backstage/plugin-catalog-backend-module-gitlab-org@0.0.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/plugin-catalog-backend-module-gitlab@0.3.21-next.1 + - @backstage/plugin-catalog-node@1.12.4-next.1 + - @backstage/plugin-events-node@0.3.8-next.1 + +## @backstage/plugin-catalog-backend-module-incremental-ingestion@0.4.27-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.24.0-next.1 + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-catalog-node@1.12.4-next.1 + - @backstage/plugin-events-node@0.3.8-next.1 + - @backstage/plugin-permission-common@0.7.14 + +## @backstage/plugin-catalog-backend-module-logs@0.0.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.24.0-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/plugin-events-node@0.3.8-next.1 + +## @backstage/plugin-catalog-backend-module-msgraph@0.5.30-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/plugin-catalog-common@1.0.24 + - @backstage/plugin-catalog-node@1.12.4-next.1 + +## @backstage/plugin-catalog-backend-module-openapi@0.1.40-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.24.0-next.1 + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.24 + - @backstage/plugin-catalog-node@1.12.4-next.1 + +## @backstage/plugin-catalog-backend-module-puppetdb@0.1.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-node@1.12.4-next.1 + +## @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.20-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-catalog-common@1.0.24 + - @backstage/plugin-catalog-node@1.12.4-next.1 + - @backstage/plugin-scaffolder-common@1.5.3 + +## @backstage/plugin-catalog-backend-module-unprocessed@0.4.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.17-next.1 + - @backstage/plugin-catalog-node@1.12.4-next.1 + - @backstage/plugin-catalog-unprocessed-entities-common@0.0.2 + - @backstage/plugin-permission-common@0.7.14 + +## @backstage/plugin-catalog-graph@0.4.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.2-next.1 + - @backstage/core-compat-api@0.2.7-next.0 + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/frontend-plugin-api@0.6.7-next.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog-import@0.12.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.2-next.1 + - @backstage/core-compat-api@0.2.7-next.0 + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/frontend-plugin-api@0.6.7-next.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/integration-react@1.1.29-next.0 + - @backstage/plugin-catalog-common@1.0.24 + +## @backstage/plugin-catalog-node@1.12.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.24 + - @backstage/plugin-permission-common@0.7.14 + - @backstage/plugin-permission-node@0.7.33-next.1 + +## @backstage/plugin-catalog-react@1.12.2-next.1 + +### Patch Changes + +- 06c0956: Support i18n for catalog and catalog-react plugins +- Updated dependencies + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/frontend-plugin-api@0.6.7-next.0 + - @backstage/integration-react@1.1.29-next.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + - @backstage/plugin-catalog-common@1.0.24 + - @backstage/plugin-permission-common@0.7.14 + - @backstage/plugin-permission-react@0.4.23 + +## @backstage/plugin-devtools-backend@0.3.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/config-loader@1.8.1 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-devtools-common@0.1.10 + - @backstage/plugin-permission-common@0.7.14 + - @backstage/plugin-permission-node@0.7.33-next.1 + +## @backstage/plugin-events-backend@0.3.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/plugin-events-node@0.3.8-next.1 + +## @backstage/plugin-events-backend-module-aws-sqs@0.3.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + - @backstage/plugin-events-node@0.3.8-next.1 + +## @backstage/plugin-events-backend-module-azure@0.2.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/plugin-events-node@0.3.8-next.1 + +## @backstage/plugin-events-backend-module-bitbucket-cloud@0.2.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/plugin-events-node@0.3.8-next.1 + +## @backstage/plugin-events-backend-module-gerrit@0.2.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/plugin-events-node@0.3.8-next.1 + +## @backstage/plugin-events-backend-module-github@0.2.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/plugin-events-node@0.3.8-next.1 + +## @backstage/plugin-events-backend-module-gitlab@0.2.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/plugin-events-node@0.3.8-next.1 + +## @backstage/plugin-events-backend-test-utils@0.1.32-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.3.8-next.1 + +## @backstage/plugin-events-node@0.3.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + +## @backstage/plugin-home@0.7.7-next.1 + +### Patch Changes + +- cc81579: Updated dependency `@rjsf/utils` to `5.18.5`. + Updated dependency `@rjsf/core` to `5.18.5`. + Updated dependency `@rjsf/material-ui` to `5.18.5`. + Updated dependency `@rjsf/validator-ajv8` to `5.18.5`. +- Updated dependencies + - @backstage/core-app-api@1.13.1-next.1 + - @backstage/plugin-catalog-react@1.12.2-next.1 + - @backstage/plugin-home-react@0.1.15-next.1 + - @backstage/core-compat-api@0.2.7-next.0 + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/frontend-plugin-api@0.6.7-next.0 + - @backstage/theme@0.5.6 + +## @backstage/plugin-home-react@0.1.15-next.1 + +### Patch Changes + +- cc81579: Updated dependency `@rjsf/utils` to `5.18.5`. + Updated dependency `@rjsf/core` to `5.18.5`. + Updated dependency `@rjsf/material-ui` to `5.18.5`. + Updated dependency `@rjsf/validator-ajv8` to `5.18.5`. +- Updated dependencies + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + +## @backstage/plugin-kubernetes@0.11.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.2-next.1 + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/plugin-kubernetes-react@0.4.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-kubernetes-common@0.8.0 + +## @backstage/plugin-kubernetes-backend@0.18.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration-aws-node@0.1.12 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + - @backstage/plugin-catalog-node@1.12.4-next.1 + - @backstage/plugin-kubernetes-common@0.8.0 + - @backstage/plugin-kubernetes-node@0.1.16-next.1 + - @backstage/plugin-permission-common@0.7.14 + - @backstage/plugin-permission-node@0.7.33-next.1 + +## @backstage/plugin-kubernetes-cluster@0.0.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.2-next.1 + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/plugin-kubernetes-react@0.4.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-kubernetes-common@0.8.0 + +## @backstage/plugin-kubernetes-node@0.1.16-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/types@1.1.1 + - @backstage/plugin-kubernetes-common@0.8.0 + +## @backstage/plugin-notifications@0.2.3-next.1 + +### Patch Changes + +- 3bf0697: The toolbar on the Notifications page is hidden when there are no listed notifications. +- Updated dependencies + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/plugin-notifications-common@0.0.4 + - @backstage/plugin-signals-react@0.0.4 + +## @backstage/plugin-notifications-backend@0.3.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.17-next.1 + - @backstage/plugin-events-node@0.3.8-next.1 + - @backstage/plugin-notifications-common@0.0.4 + - @backstage/plugin-notifications-node@0.2.3-next.1 + - @backstage/plugin-signals-node@0.1.8-next.1 + +## @backstage/plugin-notifications-backend-module-email@0.1.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/integration-aws-node@0.1.12 + - @backstage/types@1.1.1 + - @backstage/plugin-notifications-common@0.0.4 + - @backstage/plugin-notifications-node@0.2.3-next.1 + +## @backstage/plugin-notifications-node@0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-notifications-common@0.0.4 + - @backstage/plugin-signals-node@0.1.8-next.1 + +## @backstage/plugin-org@0.6.27-next.1 + +### Patch Changes + +- 5132d28: The `useGetEntities` hook could result in requests to `/api/catalog/entities` where the headers exceed the default maximum Node.js header size of 16KB. The hook logic has been adjusted to batch the requests. +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.2-next.1 + - @backstage/core-compat-api@0.2.7-next.0 + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/catalog-model@1.5.0 + - @backstage/frontend-plugin-api@0.6.7-next.0 + - @backstage/plugin-catalog-common@1.0.24 + +## @backstage/plugin-org-react@0.1.26-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.2-next.1 + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + +## @backstage/plugin-permission-backend@0.5.46-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.17-next.1 + - @backstage/plugin-permission-common@0.7.14 + - @backstage/plugin-permission-node@0.7.33-next.1 + +## @backstage/plugin-permission-backend-module-allow-all-policy@0.1.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + - @backstage/plugin-permission-common@0.7.14 + - @backstage/plugin-permission-node@0.7.33-next.1 + +## @backstage/plugin-permission-node@0.7.33-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.17-next.1 + - @backstage/plugin-permission-common@0.7.14 + +## @backstage/plugin-proxy-backend@0.5.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder@1.22.1-next.1 + +### Patch Changes + +- cc81579: Updated dependency `@rjsf/utils` to `5.18.5`. + Updated dependency `@rjsf/core` to `5.18.5`. + Updated dependency `@rjsf/material-ui` to `5.18.5`. + Updated dependency `@rjsf/validator-ajv8` to `5.18.5`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.2-next.1 + - @backstage/plugin-scaffolder-react@1.10.0-next.1 + - @backstage/core-compat-api@0.2.7-next.0 + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/frontend-plugin-api@0.6.7-next.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/integration-react@1.1.29-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.24 + - @backstage/plugin-permission-react@0.4.23 + - @backstage/plugin-scaffolder-common@1.5.3 + +## @backstage/plugin-scaffolder-backend@1.23.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend-module-github@0.4.0-next.1 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.4.4-next.1 + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.13.0-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + - @backstage/plugin-bitbucket-cloud-common@0.2.21-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.20-next.1 + - @backstage/plugin-catalog-node@1.12.4-next.1 + - @backstage/plugin-permission-common@0.7.14 + - @backstage/plugin-permission-node@0.7.33-next.1 + - @backstage/plugin-scaffolder-backend-module-azure@0.1.14-next.1 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.2.12-next.1 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.1.12-next.1 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.1.12-next.1 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.1.14-next.1 + - @backstage/plugin-scaffolder-backend-module-gitea@0.1.12-next.1 + - @backstage/plugin-scaffolder-common@1.5.3 + - @backstage/plugin-scaffolder-node@0.4.8-next.1 + +## @backstage/plugin-scaffolder-backend-module-azure@0.1.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-scaffolder-node@0.4.8-next.1 + +## @backstage/plugin-scaffolder-backend-module-bitbucket@0.2.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.1.12-next.1 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.1.12-next.1 + - @backstage/plugin-scaffolder-node@0.4.8-next.1 + +## @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.1.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.21-next.0 + - @backstage/plugin-scaffolder-node@0.4.8-next.1 + +## @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.1.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-scaffolder-node@0.4.8-next.1 + +## @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.23-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-scaffolder-node@0.4.8-next.1 + +## @backstage/plugin-scaffolder-backend-module-cookiecutter@0.2.46-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.13.0-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.4.8-next.1 + +## @backstage/plugin-scaffolder-backend-module-gcp@0.1.0-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-scaffolder-node@0.4.8-next.1 + +## @backstage/plugin-scaffolder-backend-module-gerrit@0.1.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-scaffolder-node@0.4.8-next.1 + +## @backstage/plugin-scaffolder-backend-module-gitea@0.1.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-scaffolder-node@0.4.8-next.1 + +## @backstage/plugin-scaffolder-backend-module-github@0.4.0-next.1 + +### Patch Changes + +- 141f366: Added action to enable GitHub Pages on a repo + +- dfaa28d: Adds `requireLastPushApproval` input property to configure Branch Protection Settings in `github:publish` action + + Adds `requireLastPushApproval` input property to configure Branch Protection Settings in `github:repo:push` action + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-scaffolder-node@0.4.8-next.1 + +## @backstage/plugin-scaffolder-backend-module-gitlab@0.4.4-next.1 + +### Patch Changes + +- 2fb0eb8: Added support for passing `variables` to `gitlab:pipeline:trigger` +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-scaffolder-node@0.4.8-next.1 + +## @backstage/plugin-scaffolder-backend-module-notifications@0.0.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/plugin-notifications-common@0.0.4 + - @backstage/plugin-notifications-node@0.2.3-next.1 + - @backstage/plugin-scaffolder-node@0.4.8-next.1 + +## @backstage/plugin-scaffolder-backend-module-rails@0.4.39-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.13.0-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.4.8-next.1 + +## @backstage/plugin-scaffolder-backend-module-sentry@0.1.30-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.8-next.1 + +## @backstage/plugin-scaffolder-backend-module-yeoman@0.3.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node-test-utils@0.1.9-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.4.8-next.1 + +## @backstage/plugin-scaffolder-node@0.4.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.13.0-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-common@1.5.3 + +## @backstage/plugin-scaffolder-node-test-utils@0.1.9-next.1 + +### Patch Changes + +- 54429b5: Filename and imports correction for mockActionContext.ts +- Updated dependencies + - @backstage/backend-test-utils@0.4.4-next.1 + - @backstage/backend-common@0.23.3-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.4.8-next.1 + +## @backstage/plugin-search@1.4.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.2-next.1 + - @backstage/core-compat-api@0.2.7-next.0 + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/plugin-search-react@1.7.13-next.0 + - @backstage/errors@1.2.4 + - @backstage/frontend-plugin-api@0.6.7-next.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + - @backstage/plugin-search-common@1.2.12 + +## @backstage/plugin-search-backend@1.5.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.3.4-next.1 + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-openapi-utils@0.1.15-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.14 + - @backstage/plugin-permission-node@0.7.33-next.1 + - @backstage/plugin-search-backend-node@1.2.27-next.1 + - @backstage/plugin-search-common@1.2.12 + +## @backstage/plugin-search-backend-module-catalog@0.1.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-catalog-common@1.0.24 + - @backstage/plugin-catalog-node@1.12.4-next.1 + - @backstage/plugin-permission-common@0.7.14 + - @backstage/plugin-search-backend-node@1.2.27-next.1 + - @backstage/plugin-search-common@1.2.12 + +## @backstage/plugin-search-backend-module-elasticsearch@1.5.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/integration-aws-node@0.1.12 + - @backstage/plugin-search-backend-node@1.2.27-next.1 + - @backstage/plugin-search-common@1.2.12 + +## @backstage/plugin-search-backend-module-explore@0.1.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/config@1.2.0 + - @backstage/plugin-search-backend-node@1.2.27-next.1 + - @backstage/plugin-search-common@1.2.12 + +## @backstage/plugin-search-backend-module-pg@0.5.32-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-app-api@0.7.10-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/plugin-search-backend-node@1.2.27-next.1 + - @backstage/plugin-search-common@1.2.12 + +## @backstage/plugin-search-backend-module-stack-overflow-collator@0.1.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/config@1.2.0 + - @backstage/plugin-search-backend-node@1.2.27-next.1 + - @backstage/plugin-search-common@1.2.12 + +## @backstage/plugin-search-backend-module-techdocs@0.1.27-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs-node@1.12.8-next.1 + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/plugin-catalog-common@1.0.24 + - @backstage/plugin-catalog-node@1.12.4-next.1 + - @backstage/plugin-permission-common@0.7.14 + - @backstage/plugin-search-backend-node@1.2.27-next.1 + - @backstage/plugin-search-common@1.2.12 + +## @backstage/plugin-search-backend-node@1.2.27-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-permission-common@0.7.14 + - @backstage/plugin-search-common@1.2.12 + +## @backstage/plugin-signals-backend@0.1.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + - @backstage/plugin-events-node@0.3.8-next.1 + - @backstage/plugin-signals-node@0.1.8-next.1 + +## @backstage/plugin-signals-node@0.1.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + - @backstage/plugin-events-node@0.3.8-next.1 + +## @backstage/plugin-techdocs@1.10.7-next.1 + +### Patch Changes + +- 60caa92: Fix double scrollbar bug in reader +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.2-next.1 + - @backstage/core-compat-api@0.2.7-next.0 + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/plugin-search-react@1.7.13-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/frontend-plugin-api@0.6.7-next.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/integration-react@1.1.29-next.0 + - @backstage/theme@0.5.6 + - @backstage/plugin-auth-react@0.1.4-next.0 + - @backstage/plugin-search-common@1.2.12 + - @backstage/plugin-techdocs-react@1.2.6-next.0 + +## @backstage/plugin-techdocs-addons-test-utils@1.0.35-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.13.1-next.1 + - @backstage/plugin-catalog-react@1.12.2-next.1 + - @backstage/plugin-catalog@1.21.1-next.1 + - @backstage/plugin-techdocs@1.10.7-next.1 + - @backstage/core-plugin-api@1.9.3 + - @backstage/test-utils@1.5.8-next.1 + - @backstage/plugin-search-react@1.7.13-next.0 + - @backstage/integration-react@1.1.29-next.0 + - @backstage/plugin-techdocs-react@1.2.6-next.0 + +## @backstage/plugin-techdocs-backend@1.10.9-next.1 + +### Patch Changes + +- 9ecf5fd: Adds extension point for publishers to the techdocs backend +- Updated dependencies + - @backstage/plugin-techdocs-node@1.12.8-next.1 + - @backstage/backend-common@0.23.3-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.27-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-catalog-common@1.0.24 + - @backstage/plugin-permission-common@0.7.14 + +## @backstage/plugin-techdocs-node@1.12.8-next.1 + +### Patch Changes + +- 9ecf5fd: Adds extension point for publishers to the techdocs backend +- 4c4d077: Bumps default version of techdocs docker image to latest +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.13.0-next.0 + - @backstage/integration-aws-node@0.1.12 + - @backstage/plugin-search-common@1.2.12 + +## @backstage/plugin-user-settings@0.8.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.13.1-next.1 + - @backstage/plugin-catalog-react@1.12.2-next.1 + - @backstage/core-compat-api@0.2.7-next.0 + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/frontend-plugin-api@0.6.7-next.0 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/plugin-signals-react@0.0.4 + - @backstage/plugin-user-settings-common@0.0.1 + +## @backstage/plugin-user-settings-backend@0.2.21-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + - @backstage/plugin-signals-node@0.1.8-next.1 + - @backstage/plugin-user-settings-common@0.0.1 + +## example-app@0.2.99-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-org@0.6.27-next.1 + - @backstage/core-app-api@1.13.1-next.1 + - @backstage/plugin-catalog-react@1.12.2-next.1 + - @backstage/plugin-catalog@1.21.1-next.1 + - @backstage/plugin-techdocs@1.10.7-next.1 + - @backstage/plugin-notifications@0.2.3-next.1 + - @backstage/plugin-home@0.7.7-next.1 + - @backstage/plugin-scaffolder-react@1.10.0-next.1 + - @backstage/plugin-scaffolder@1.22.1-next.1 + - @backstage/cli@0.26.11-next.1 + - @backstage/app-defaults@1.5.8-next.1 + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/frontend-app-api@0.7.3-next.1 + - @backstage/plugin-api-docs@0.11.7-next.1 + - @backstage/plugin-catalog-graph@0.4.7-next.1 + - @backstage/plugin-catalog-import@0.12.1-next.1 + - @backstage/plugin-search@1.4.13-next.1 + - @backstage/plugin-search-react@1.7.13-next.0 + - @backstage/plugin-signals@0.0.8-next.0 + - @backstage/plugin-user-settings@0.8.9-next.1 + - @backstage/plugin-kubernetes@0.11.12-next.1 + - @backstage/plugin-kubernetes-cluster@0.0.13-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/integration-react@1.1.29-next.0 + - @backstage/theme@0.5.6 + - @backstage/plugin-auth-react@0.1.4-next.0 + - @backstage/plugin-catalog-common@1.0.24 + - @backstage/plugin-catalog-unprocessed-entities@0.2.6-next.0 + - @backstage/plugin-devtools@0.1.16-next.0 + - @backstage/plugin-permission-react@0.4.23 + - @backstage/plugin-search-common@1.2.12 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.12-next.0 + - @backstage/plugin-techdocs-react@1.2.6-next.0 + +## example-app-next@0.0.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-org@0.6.27-next.1 + - @backstage/core-app-api@1.13.1-next.1 + - @backstage/plugin-catalog-react@1.12.2-next.1 + - @backstage/plugin-catalog@1.21.1-next.1 + - @backstage/plugin-techdocs@1.10.7-next.1 + - @backstage/plugin-notifications@0.2.3-next.1 + - @backstage/plugin-home@0.7.7-next.1 + - @backstage/plugin-scaffolder-react@1.10.0-next.1 + - @backstage/plugin-scaffolder@1.22.1-next.1 + - @backstage/cli@0.26.11-next.1 + - @backstage/app-defaults@1.5.8-next.1 + - @backstage/core-compat-api@0.2.7-next.0 + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/frontend-app-api@0.7.3-next.1 + - @backstage/plugin-api-docs@0.11.7-next.1 + - @backstage/plugin-catalog-graph@0.4.7-next.1 + - @backstage/plugin-catalog-import@0.12.1-next.1 + - @backstage/plugin-search@1.4.13-next.1 + - @backstage/plugin-search-react@1.7.13-next.0 + - @backstage/plugin-signals@0.0.8-next.0 + - @backstage/plugin-user-settings@0.8.9-next.1 + - @backstage/plugin-kubernetes@0.11.12-next.1 + - @backstage/plugin-kubernetes-cluster@0.0.13-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/frontend-plugin-api@0.6.7-next.0 + - @backstage/integration-react@1.1.29-next.0 + - @backstage/theme@0.5.6 + - @backstage/plugin-app-visualizer@0.1.8-next.0 + - @backstage/plugin-auth-react@0.1.4-next.0 + - @backstage/plugin-catalog-common@1.0.24 + - @backstage/plugin-catalog-unprocessed-entities@0.2.6-next.0 + - @backstage/plugin-permission-react@0.4.23 + - @backstage/plugin-search-common@1.2.12 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.12-next.0 + - @backstage/plugin-techdocs-react@1.2.6-next.0 + +## example-backend@0.0.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs-backend@1.10.9-next.1 + - @backstage/plugin-scaffolder-backend-module-github@0.4.0-next.1 + - @backstage/plugin-catalog-backend@1.24.0-next.1 + - @backstage/backend-defaults@0.3.4-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.27-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-app-backend@0.3.71-next.1 + - @backstage/plugin-auth-backend@0.22.9-next.1 + - @backstage/plugin-auth-backend-module-github-provider@0.1.19-next.1 + - @backstage/plugin-auth-backend-module-guest-provider@0.1.8-next.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.2.5-next.1 + - @backstage/plugin-catalog-backend-module-openapi@0.1.40-next.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.20-next.1 + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.9-next.1 + - @backstage/plugin-devtools-backend@0.3.8-next.1 + - @backstage/plugin-kubernetes-backend@0.18.3-next.1 + - @backstage/plugin-notifications-backend@0.3.3-next.1 + - @backstage/plugin-permission-backend@0.5.46-next.1 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.19-next.1 + - @backstage/plugin-permission-common@0.7.14 + - @backstage/plugin-permission-node@0.7.33-next.1 + - @backstage/plugin-proxy-backend@0.5.3-next.1 + - @backstage/plugin-scaffolder-backend@1.23.0-next.1 + - @backstage/plugin-search-backend@1.5.14-next.1 + - @backstage/plugin-search-backend-module-catalog@0.1.28-next.1 + - @backstage/plugin-search-backend-module-explore@0.1.28-next.1 + - @backstage/plugin-search-backend-node@1.2.27-next.1 + - @backstage/plugin-signals-backend@0.1.8-next.1 + +## example-backend-legacy@0.2.100-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs-backend@1.10.9-next.1 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.4.4-next.1 + - @backstage/plugin-catalog-backend@1.24.0-next.1 + - @backstage/backend-common@0.23.3-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.27-next.1 + - example-app@0.2.99-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-app-backend@0.3.71-next.1 + - @backstage/plugin-auth-backend@0.22.9-next.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.20-next.1 + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.9-next.1 + - @backstage/plugin-catalog-node@1.12.4-next.1 + - @backstage/plugin-devtools-backend@0.3.8-next.1 + - @backstage/plugin-events-backend@0.3.9-next.1 + - @backstage/plugin-events-node@0.3.8-next.1 + - @backstage/plugin-kubernetes-backend@0.18.3-next.1 + - @backstage/plugin-permission-backend@0.5.46-next.1 + - @backstage/plugin-permission-common@0.7.14 + - @backstage/plugin-permission-node@0.7.33-next.1 + - @backstage/plugin-proxy-backend@0.5.3-next.1 + - @backstage/plugin-scaffolder-backend@1.23.0-next.1 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.23-next.1 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.39-next.1 + - @backstage/plugin-search-backend@1.5.14-next.1 + - @backstage/plugin-search-backend-module-catalog@0.1.28-next.1 + - @backstage/plugin-search-backend-module-elasticsearch@1.5.3-next.1 + - @backstage/plugin-search-backend-module-explore@0.1.28-next.1 + - @backstage/plugin-search-backend-module-pg@0.5.32-next.1 + - @backstage/plugin-search-backend-node@1.2.27-next.1 + - @backstage/plugin-signals-backend@0.1.8-next.1 + - @backstage/plugin-signals-node@0.1.8-next.1 + +## e2e-test@0.2.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.17-next.1 + - @backstage/cli-common@0.1.14 + - @backstage/errors@1.2.4 + +## techdocs-cli-embedded-app@0.2.98-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.13.1-next.1 + - @backstage/plugin-catalog@1.21.1-next.1 + - @backstage/plugin-techdocs@1.10.7-next.1 + - @backstage/cli@0.26.11-next.1 + - @backstage/app-defaults@1.5.8-next.1 + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/test-utils@1.5.8-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/integration-react@1.1.29-next.0 + - @backstage/theme@0.5.6 + - @backstage/plugin-techdocs-react@1.2.6-next.0 + +## @internal/plugin-todo-list-backend@1.0.29-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.17-next.1 diff --git a/package.json b/package.json index 0946671f12..7de757ff9b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "root", - "version": "1.29.0-next.0", + "version": "1.29.0-next.1", "private": true, "repository": { "type": "git", diff --git a/packages/app-defaults/CHANGELOG.md b/packages/app-defaults/CHANGELOG.md index 40ee32565f..588c59c3e4 100644 --- a/packages/app-defaults/CHANGELOG.md +++ b/packages/app-defaults/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/app-defaults +## 1.5.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.13.1-next.1 + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + - @backstage/plugin-permission-react@0.4.23 + ## 1.5.7-next.0 ### Patch Changes diff --git a/packages/app-defaults/package.json b/packages/app-defaults/package.json index 5dc9e3d617..8bb0a707b5 100644 --- a/packages/app-defaults/package.json +++ b/packages/app-defaults/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/app-defaults", - "version": "1.5.7-next.0", + "version": "1.5.8-next.1", "description": "Provides the default wiring of a Backstage App", "backstage": { "role": "web-library" diff --git a/packages/app-next/CHANGELOG.md b/packages/app-next/CHANGELOG.md index 979284c459..6c3d48601f 100644 --- a/packages/app-next/CHANGELOG.md +++ b/packages/app-next/CHANGELOG.md @@ -1,5 +1,48 @@ # example-app-next +## 0.0.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-org@0.6.27-next.1 + - @backstage/core-app-api@1.13.1-next.1 + - @backstage/plugin-catalog-react@1.12.2-next.1 + - @backstage/plugin-catalog@1.21.1-next.1 + - @backstage/plugin-techdocs@1.10.7-next.1 + - @backstage/plugin-notifications@0.2.3-next.1 + - @backstage/plugin-home@0.7.7-next.1 + - @backstage/plugin-scaffolder-react@1.10.0-next.1 + - @backstage/plugin-scaffolder@1.22.1-next.1 + - @backstage/cli@0.26.11-next.1 + - @backstage/app-defaults@1.5.8-next.1 + - @backstage/core-compat-api@0.2.7-next.0 + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/frontend-app-api@0.7.3-next.1 + - @backstage/plugin-api-docs@0.11.7-next.1 + - @backstage/plugin-catalog-graph@0.4.7-next.1 + - @backstage/plugin-catalog-import@0.12.1-next.1 + - @backstage/plugin-search@1.4.13-next.1 + - @backstage/plugin-search-react@1.7.13-next.0 + - @backstage/plugin-signals@0.0.8-next.0 + - @backstage/plugin-user-settings@0.8.9-next.1 + - @backstage/plugin-kubernetes@0.11.12-next.1 + - @backstage/plugin-kubernetes-cluster@0.0.13-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/frontend-plugin-api@0.6.7-next.0 + - @backstage/integration-react@1.1.29-next.0 + - @backstage/theme@0.5.6 + - @backstage/plugin-app-visualizer@0.1.8-next.0 + - @backstage/plugin-auth-react@0.1.4-next.0 + - @backstage/plugin-catalog-common@1.0.24 + - @backstage/plugin-catalog-unprocessed-entities@0.2.6-next.0 + - @backstage/plugin-permission-react@0.4.23 + - @backstage/plugin-search-common@1.2.12 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.12-next.0 + - @backstage/plugin-techdocs-react@1.2.6-next.0 + ## 0.0.13-next.0 ### Patch Changes diff --git a/packages/app-next/package.json b/packages/app-next/package.json index 73141946ea..a0f0174753 100644 --- a/packages/app-next/package.json +++ b/packages/app-next/package.json @@ -1,6 +1,6 @@ { "name": "example-app-next", - "version": "0.0.13-next.0", + "version": "0.0.13-next.1", "private": true, "repository": { "type": "git", diff --git a/packages/app/CHANGELOG.md b/packages/app/CHANGELOG.md index ca64c31049..3a06dd99fd 100644 --- a/packages/app/CHANGELOG.md +++ b/packages/app/CHANGELOG.md @@ -1,5 +1,46 @@ # example-app +## 0.2.99-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-org@0.6.27-next.1 + - @backstage/core-app-api@1.13.1-next.1 + - @backstage/plugin-catalog-react@1.12.2-next.1 + - @backstage/plugin-catalog@1.21.1-next.1 + - @backstage/plugin-techdocs@1.10.7-next.1 + - @backstage/plugin-notifications@0.2.3-next.1 + - @backstage/plugin-home@0.7.7-next.1 + - @backstage/plugin-scaffolder-react@1.10.0-next.1 + - @backstage/plugin-scaffolder@1.22.1-next.1 + - @backstage/cli@0.26.11-next.1 + - @backstage/app-defaults@1.5.8-next.1 + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/frontend-app-api@0.7.3-next.1 + - @backstage/plugin-api-docs@0.11.7-next.1 + - @backstage/plugin-catalog-graph@0.4.7-next.1 + - @backstage/plugin-catalog-import@0.12.1-next.1 + - @backstage/plugin-search@1.4.13-next.1 + - @backstage/plugin-search-react@1.7.13-next.0 + - @backstage/plugin-signals@0.0.8-next.0 + - @backstage/plugin-user-settings@0.8.9-next.1 + - @backstage/plugin-kubernetes@0.11.12-next.1 + - @backstage/plugin-kubernetes-cluster@0.0.13-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/integration-react@1.1.29-next.0 + - @backstage/theme@0.5.6 + - @backstage/plugin-auth-react@0.1.4-next.0 + - @backstage/plugin-catalog-common@1.0.24 + - @backstage/plugin-catalog-unprocessed-entities@0.2.6-next.0 + - @backstage/plugin-devtools@0.1.16-next.0 + - @backstage/plugin-permission-react@0.4.23 + - @backstage/plugin-search-common@1.2.12 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.12-next.0 + - @backstage/plugin-techdocs-react@1.2.6-next.0 + ## 0.2.99-next.0 ### Patch Changes diff --git a/packages/app/package.json b/packages/app/package.json index 067b2d84eb..a30c8e15d7 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,6 +1,6 @@ { "name": "example-app", - "version": "0.2.99-next.0", + "version": "0.2.99-next.1", "backstage": { "role": "frontend" }, diff --git a/packages/backend-app-api/CHANGELOG.md b/packages/backend-app-api/CHANGELOG.md index c9fe21c89e..4456d8438b 100644 --- a/packages/backend-app-api/CHANGELOG.md +++ b/packages/backend-app-api/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/backend-app-api +## 0.7.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/cli-common@0.1.14 + - @backstage/cli-node@0.2.6 + - @backstage/config@1.2.0 + - @backstage/config-loader@1.8.1 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + - @backstage/plugin-permission-node@0.7.33-next.1 + ## 0.7.9-next.0 ### Patch Changes diff --git a/packages/backend-app-api/package.json b/packages/backend-app-api/package.json index 51bbca14bc..4d3ffd874f 100644 --- a/packages/backend-app-api/package.json +++ b/packages/backend-app-api/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/backend-app-api", - "version": "0.7.9-next.0", + "version": "0.7.10-next.1", "description": "Core API used by Backstage backend apps", "backstage": { "role": "node-library" diff --git a/packages/backend-common/CHANGELOG.md b/packages/backend-common/CHANGELOG.md index d635b77c72..d144d461b8 100644 --- a/packages/backend-common/CHANGELOG.md +++ b/packages/backend-common/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/backend-common +## 0.23.3-next.1 + +### Patch Changes + +- b9ed1bb: bumped better-sqlite3 from ^9.0.0 to ^11.0.0 +- Updated dependencies + - @backstage/backend-dev-utils@0.1.4 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/config-loader@1.8.1 + - @backstage/errors@1.2.4 + - @backstage/integration@1.13.0-next.0 + - @backstage/integration-aws-node@0.1.12 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + ## 0.23.2-next.0 ### Patch Changes diff --git a/packages/backend-common/package.json b/packages/backend-common/package.json index 28378f6c41..f23f0d2ce9 100644 --- a/packages/backend-common/package.json +++ b/packages/backend-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/backend-common", - "version": "0.23.2-next.0", + "version": "0.23.3-next.1", "description": "Common functionality library for Backstage backends", "backstage": { "role": "node-library" diff --git a/packages/backend-defaults/CHANGELOG.md b/packages/backend-defaults/CHANGELOG.md index 7e9788756f..a9b20bfbea 100644 --- a/packages/backend-defaults/CHANGELOG.md +++ b/packages/backend-defaults/CHANGELOG.md @@ -1,5 +1,26 @@ # @backstage/backend-defaults +## 0.3.4-next.1 + +### Patch Changes + +- b9ed1bb: bumped better-sqlite3 from ^9.0.0 to ^11.0.0 +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-app-api@0.7.10-next.1 + - @backstage/backend-dev-utils@0.1.4 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/config-loader@1.8.1 + - @backstage/errors@1.2.4 + - @backstage/integration@1.13.0-next.0 + - @backstage/integration-aws-node@0.1.12 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + - @backstage/plugin-events-node@0.3.8-next.1 + - @backstage/plugin-permission-node@0.7.33-next.1 + ## 0.3.3-next.0 ### Patch Changes diff --git a/packages/backend-defaults/package.json b/packages/backend-defaults/package.json index 824f1893bd..0606d942ff 100644 --- a/packages/backend-defaults/package.json +++ b/packages/backend-defaults/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/backend-defaults", - "version": "0.3.3-next.0", + "version": "0.3.4-next.1", "description": "Backend defaults used by Backstage backend apps", "backstage": { "role": "node-library" diff --git a/packages/backend-dynamic-feature-service/CHANGELOG.md b/packages/backend-dynamic-feature-service/CHANGELOG.md index 4ec9489674..02f47ef7b4 100644 --- a/packages/backend-dynamic-feature-service/CHANGELOG.md +++ b/packages/backend-dynamic-feature-service/CHANGELOG.md @@ -1,5 +1,31 @@ # @backstage/backend-dynamic-feature-service +## 0.2.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.24.0-next.1 + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-app-api@0.7.10-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/cli-common@0.1.14 + - @backstage/cli-node@0.2.6 + - @backstage/config@1.2.0 + - @backstage/config-loader@1.8.1 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-app-node@0.1.22-next.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + - @backstage/plugin-events-backend@0.3.9-next.1 + - @backstage/plugin-events-node@0.3.8-next.1 + - @backstage/plugin-permission-common@0.7.14 + - @backstage/plugin-permission-node@0.7.33-next.1 + - @backstage/plugin-scaffolder-node@0.4.8-next.1 + - @backstage/plugin-search-backend-node@1.2.27-next.1 + - @backstage/plugin-search-common@1.2.12 + ## 0.2.14-next.0 ### Patch Changes diff --git a/packages/backend-dynamic-feature-service/package.json b/packages/backend-dynamic-feature-service/package.json index 60ff4d2d4e..3e3e566879 100644 --- a/packages/backend-dynamic-feature-service/package.json +++ b/packages/backend-dynamic-feature-service/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-dynamic-feature-service", "description": "Backstage dynamic feature service", - "version": "0.2.14-next.0", + "version": "0.2.15-next.1", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/packages/backend-legacy/CHANGELOG.md b/packages/backend-legacy/CHANGELOG.md index 9535ba1211..7734d12d4f 100644 --- a/packages/backend-legacy/CHANGELOG.md +++ b/packages/backend-legacy/CHANGELOG.md @@ -1,5 +1,47 @@ # example-backend-legacy +## 0.2.100-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs-backend@1.10.9-next.1 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.4.4-next.1 + - @backstage/plugin-catalog-backend@1.24.0-next.1 + - @backstage/backend-common@0.23.3-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.27-next.1 + - example-app@0.2.99-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-app-backend@0.3.71-next.1 + - @backstage/plugin-auth-backend@0.22.9-next.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.20-next.1 + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.9-next.1 + - @backstage/plugin-catalog-node@1.12.4-next.1 + - @backstage/plugin-devtools-backend@0.3.8-next.1 + - @backstage/plugin-events-backend@0.3.9-next.1 + - @backstage/plugin-events-node@0.3.8-next.1 + - @backstage/plugin-kubernetes-backend@0.18.3-next.1 + - @backstage/plugin-permission-backend@0.5.46-next.1 + - @backstage/plugin-permission-common@0.7.14 + - @backstage/plugin-permission-node@0.7.33-next.1 + - @backstage/plugin-proxy-backend@0.5.3-next.1 + - @backstage/plugin-scaffolder-backend@1.23.0-next.1 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.23-next.1 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.39-next.1 + - @backstage/plugin-search-backend@1.5.14-next.1 + - @backstage/plugin-search-backend-module-catalog@0.1.28-next.1 + - @backstage/plugin-search-backend-module-elasticsearch@1.5.3-next.1 + - @backstage/plugin-search-backend-module-explore@0.1.28-next.1 + - @backstage/plugin-search-backend-module-pg@0.5.32-next.1 + - @backstage/plugin-search-backend-node@1.2.27-next.1 + - @backstage/plugin-signals-backend@0.1.8-next.1 + - @backstage/plugin-signals-node@0.1.8-next.1 + ## 0.2.100-next.0 ### Patch Changes diff --git a/packages/backend-legacy/package.json b/packages/backend-legacy/package.json index 6b9bb3523a..384ce61973 100644 --- a/packages/backend-legacy/package.json +++ b/packages/backend-legacy/package.json @@ -1,6 +1,6 @@ { "name": "example-backend-legacy", - "version": "0.2.100-next.0", + "version": "0.2.100-next.1", "backstage": { "role": "backend" }, diff --git a/packages/backend-openapi-utils/CHANGELOG.md b/packages/backend-openapi-utils/CHANGELOG.md index 0040eddc57..43a57f7d8c 100644 --- a/packages/backend-openapi-utils/CHANGELOG.md +++ b/packages/backend-openapi-utils/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/backend-openapi-utils +## 0.1.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/errors@1.2.4 + ## 0.1.14-next.0 ### Patch Changes diff --git a/packages/backend-openapi-utils/package.json b/packages/backend-openapi-utils/package.json index 4b2551eb13..f35863c6e3 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.14-next.0", + "version": "0.1.15-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 b36d7a996d..cb341b218e 100644 --- a/packages/backend-plugin-api/CHANGELOG.md +++ b/packages/backend-plugin-api/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/backend-plugin-api +## 0.6.22-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + - @backstage/plugin-permission-common@0.7.14 + ## 0.6.21-next.0 ### Patch Changes diff --git a/packages/backend-plugin-api/package.json b/packages/backend-plugin-api/package.json index dbb59f7991..631141a57f 100644 --- a/packages/backend-plugin-api/package.json +++ b/packages/backend-plugin-api/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/backend-plugin-api", - "version": "0.6.21-next.0", + "version": "0.6.22-next.1", "description": "Core API used by Backstage backend plugins", "backstage": { "role": "node-library" diff --git a/packages/backend-tasks/CHANGELOG.md b/packages/backend-tasks/CHANGELOG.md index 008ae3cb11..590d824635 100644 --- a/packages/backend-tasks/CHANGELOG.md +++ b/packages/backend-tasks/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/backend-tasks +## 0.5.27-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 0.5.26-next.0 ### Patch Changes diff --git a/packages/backend-tasks/package.json b/packages/backend-tasks/package.json index 2033be826c..df10190443 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.26-next.0", + "version": "0.5.27-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 435d1f8abc..9f3d84a906 100644 --- a/packages/backend-test-utils/CHANGELOG.md +++ b/packages/backend-test-utils/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/backend-test-utils +## 0.4.4-next.1 + +### Patch Changes + +- b9ed1bb: bumped better-sqlite3 from ^9.0.0 to ^11.0.0 +- Updated dependencies + - @backstage/backend-defaults@0.3.4-next.1 + - @backstage/backend-app-api@0.7.10-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + - @backstage/plugin-events-node@0.3.8-next.1 + ## 0.4.3-next.0 ### Patch Changes diff --git a/packages/backend-test-utils/package.json b/packages/backend-test-utils/package.json index 540b4f9ee4..e975dc01d9 100644 --- a/packages/backend-test-utils/package.json +++ b/packages/backend-test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/backend-test-utils", - "version": "0.4.3-next.0", + "version": "0.4.4-next.1", "description": "Test helpers library for Backstage backends", "backstage": { "role": "node-library" diff --git a/packages/backend/CHANGELOG.md b/packages/backend/CHANGELOG.md index 6e4257b62d..0c91daa13d 100644 --- a/packages/backend/CHANGELOG.md +++ b/packages/backend/CHANGELOG.md @@ -1,5 +1,42 @@ # example-backend +## 0.0.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs-backend@1.10.9-next.1 + - @backstage/plugin-scaffolder-backend-module-github@0.4.0-next.1 + - @backstage/plugin-catalog-backend@1.24.0-next.1 + - @backstage/backend-defaults@0.3.4-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.27-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-app-backend@0.3.71-next.1 + - @backstage/plugin-auth-backend@0.22.9-next.1 + - @backstage/plugin-auth-backend-module-github-provider@0.1.19-next.1 + - @backstage/plugin-auth-backend-module-guest-provider@0.1.8-next.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.2.5-next.1 + - @backstage/plugin-catalog-backend-module-openapi@0.1.40-next.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.20-next.1 + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.9-next.1 + - @backstage/plugin-devtools-backend@0.3.8-next.1 + - @backstage/plugin-kubernetes-backend@0.18.3-next.1 + - @backstage/plugin-notifications-backend@0.3.3-next.1 + - @backstage/plugin-permission-backend@0.5.46-next.1 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.19-next.1 + - @backstage/plugin-permission-common@0.7.14 + - @backstage/plugin-permission-node@0.7.33-next.1 + - @backstage/plugin-proxy-backend@0.5.3-next.1 + - @backstage/plugin-scaffolder-backend@1.23.0-next.1 + - @backstage/plugin-search-backend@1.5.14-next.1 + - @backstage/plugin-search-backend-module-catalog@0.1.28-next.1 + - @backstage/plugin-search-backend-module-explore@0.1.28-next.1 + - @backstage/plugin-search-backend-node@1.2.27-next.1 + - @backstage/plugin-signals-backend@0.1.8-next.1 + ## 0.0.28-next.0 ### Patch Changes diff --git a/packages/backend/package.json b/packages/backend/package.json index f81701a77d..8e6918bfc5 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -1,6 +1,6 @@ { "name": "example-backend", - "version": "0.0.28-next.0", + "version": "0.0.28-next.1", "main": "dist/index.cjs.js", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index 0e65266410..a2fae6e3c0 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/cli +## 0.26.11-next.1 + +### Patch Changes + +- 4baac0c: The `backendPlugin` and `backendModule` factory now includes a step for automatically adding the new backend plugin/module to the `index.ts` file of the backend. +- Updated dependencies + - @backstage/catalog-model@1.5.0 + - @backstage/cli-common@0.1.14 + - @backstage/cli-node@0.2.6 + - @backstage/config@1.2.0 + - @backstage/config-loader@1.8.1 + - @backstage/errors@1.2.4 + - @backstage/eslint-plugin@0.1.8 + - @backstage/integration@1.13.0-next.0 + - @backstage/release-manifests@0.0.11 + - @backstage/types@1.1.1 + ## 0.26.10-next.0 ### Patch Changes diff --git a/packages/cli/package.json b/packages/cli/package.json index b458cf162f..393f1217e1 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/cli", - "version": "0.26.10-next.0", + "version": "0.26.11-next.1", "description": "CLI for developing Backstage plugins and apps", "backstage": { "role": "cli" diff --git a/packages/core-app-api/CHANGELOG.md b/packages/core-app-api/CHANGELOG.md index 32edc95e49..d80ed2fdcb 100644 --- a/packages/core-app-api/CHANGELOG.md +++ b/packages/core-app-api/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/core-app-api +## 1.13.1-next.1 + +### Patch Changes + +- db2e2d5: Updated config schema to support app.routes.bindings +- Updated dependencies + - @backstage/core-plugin-api@1.9.3 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + ## 1.13.0-next.0 ### Minor Changes diff --git a/packages/core-app-api/package.json b/packages/core-app-api/package.json index bdd6a1f663..35e32f9726 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.13.0-next.0", + "version": "1.13.1-next.1", "publishConfig": { "access": "public" }, diff --git a/packages/create-app/CHANGELOG.md b/packages/create-app/CHANGELOG.md index d6ccf478a4..3f102c17da 100644 --- a/packages/create-app/CHANGELOG.md +++ b/packages/create-app/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/create-app +## 0.5.17-next.1 + +### Patch Changes + +- 780d994: Added `MyGroupsSidebarItem` to the sidebar in the `create-app` template +- Updated dependencies + - @backstage/cli-common@0.1.14 + ## 0.5.17-next.0 ### Patch Changes diff --git a/packages/create-app/package.json b/packages/create-app/package.json index bcbb1c5899..96be1f941c 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.17-next.0", + "version": "0.5.17-next.1", "publishConfig": { "access": "public" }, diff --git a/packages/dev-utils/CHANGELOG.md b/packages/dev-utils/CHANGELOG.md index d44d840187..62a5c2adc2 100644 --- a/packages/dev-utils/CHANGELOG.md +++ b/packages/dev-utils/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/dev-utils +## 1.0.35-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.13.1-next.1 + - @backstage/plugin-catalog-react@1.12.2-next.1 + - @backstage/app-defaults@1.5.8-next.1 + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/catalog-model@1.5.0 + - @backstage/integration-react@1.1.29-next.0 + - @backstage/theme@0.5.6 + ## 1.0.34-next.0 ### Patch Changes diff --git a/packages/dev-utils/package.json b/packages/dev-utils/package.json index 43f05d62ae..3e05873d6c 100644 --- a/packages/dev-utils/package.json +++ b/packages/dev-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/dev-utils", - "version": "1.0.34-next.0", + "version": "1.0.35-next.1", "description": "Utilities for developing Backstage plugins.", "backstage": { "role": "web-library" diff --git a/packages/e2e-test/CHANGELOG.md b/packages/e2e-test/CHANGELOG.md index 74e22bcb63..a11001a2aa 100644 --- a/packages/e2e-test/CHANGELOG.md +++ b/packages/e2e-test/CHANGELOG.md @@ -1,5 +1,14 @@ # e2e-test +## 0.2.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.17-next.1 + - @backstage/cli-common@0.1.14 + - @backstage/errors@1.2.4 + ## 0.2.18-next.0 ### Patch Changes diff --git a/packages/e2e-test/package.json b/packages/e2e-test/package.json index d63b93a7ba..d1f42a1d8f 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.18-next.0", + "version": "0.2.18-next.1", "private": true, "backstage": { "role": "cli" diff --git a/packages/frontend-app-api/CHANGELOG.md b/packages/frontend-app-api/CHANGELOG.md index 94fffd0397..fc39807e5b 100644 --- a/packages/frontend-app-api/CHANGELOG.md +++ b/packages/frontend-app-api/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/frontend-app-api +## 0.7.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.13.1-next.1 + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/frontend-plugin-api@0.6.7-next.0 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + ## 0.7.2-next.0 ### Patch Changes diff --git a/packages/frontend-app-api/package.json b/packages/frontend-app-api/package.json index f4290b70cc..a6c2583fbc 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.7.2-next.0", + "version": "0.7.3-next.1", "backstage": { "role": "web-library" }, diff --git a/packages/frontend-test-utils/CHANGELOG.md b/packages/frontend-test-utils/CHANGELOG.md index 04c896d246..5ece8edb86 100644 --- a/packages/frontend-test-utils/CHANGELOG.md +++ b/packages/frontend-test-utils/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/frontend-test-utils +## 0.1.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-app-api@0.7.3-next.1 + - @backstage/test-utils@1.5.8-next.1 + - @backstage/frontend-plugin-api@0.6.7-next.0 + - @backstage/types@1.1.1 + ## 0.1.9-next.0 ### Patch Changes diff --git a/packages/frontend-test-utils/package.json b/packages/frontend-test-utils/package.json index c7d28e99e3..9856a09367 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.9-next.0", + "version": "0.1.10-next.1", "backstage": { "role": "web-library" }, diff --git a/packages/repo-tools/CHANGELOG.md b/packages/repo-tools/CHANGELOG.md index 204437551d..daa0684e41 100644 --- a/packages/repo-tools/CHANGELOG.md +++ b/packages/repo-tools/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/repo-tools +## 0.9.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/cli-common@0.1.14 + - @backstage/cli-node@0.2.6 + - @backstage/config-loader@1.8.1 + - @backstage/errors@1.2.4 + ## 0.9.3-next.0 ### Patch Changes diff --git a/packages/repo-tools/package.json b/packages/repo-tools/package.json index 4eca696aea..cd1658b417 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.9.3-next.0", + "version": "0.9.4-next.1", "publishConfig": { "access": "public" }, diff --git a/packages/techdocs-cli-embedded-app/CHANGELOG.md b/packages/techdocs-cli-embedded-app/CHANGELOG.md index 99af9b8ad0..343ecf5ccb 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.98-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.13.1-next.1 + - @backstage/plugin-catalog@1.21.1-next.1 + - @backstage/plugin-techdocs@1.10.7-next.1 + - @backstage/cli@0.26.11-next.1 + - @backstage/app-defaults@1.5.8-next.1 + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/test-utils@1.5.8-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/integration-react@1.1.29-next.0 + - @backstage/theme@0.5.6 + - @backstage/plugin-techdocs-react@1.2.6-next.0 + ## 0.2.98-next.0 ### Patch Changes diff --git a/packages/techdocs-cli-embedded-app/package.json b/packages/techdocs-cli-embedded-app/package.json index ef762bc3e2..3b234c8f4c 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.98-next.0", + "version": "0.2.98-next.1", "private": true, "backstage": { "role": "frontend" diff --git a/packages/techdocs-cli/CHANGELOG.md b/packages/techdocs-cli/CHANGELOG.md index 9fa6485f0d..0097d35ef6 100644 --- a/packages/techdocs-cli/CHANGELOG.md +++ b/packages/techdocs-cli/CHANGELOG.md @@ -1,5 +1,16 @@ # @techdocs/cli +## 1.8.16-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs-node@1.12.8-next.1 + - @backstage/backend-defaults@0.3.4-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + ## 1.8.15-next.0 ### Patch Changes diff --git a/packages/techdocs-cli/package.json b/packages/techdocs-cli/package.json index e1f00726af..d947af0ee8 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.15-next.0", + "version": "1.8.16-next.1", "publishConfig": { "access": "public" }, diff --git a/packages/test-utils/CHANGELOG.md b/packages/test-utils/CHANGELOG.md index c19d0cd4af..6a038fd0d8 100644 --- a/packages/test-utils/CHANGELOG.md +++ b/packages/test-utils/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/test-utils +## 1.5.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.13.1-next.1 + - @backstage/core-plugin-api@1.9.3 + - @backstage/config@1.2.0 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.14 + - @backstage/plugin-permission-react@0.4.23 + ## 1.5.7-next.0 ### Patch Changes diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index a1e642dd89..9cf0c7a6a7 100644 --- a/packages/test-utils/package.json +++ b/packages/test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/test-utils", - "version": "1.5.7-next.0", + "version": "1.5.8-next.1", "description": "Utilities to test Backstage plugins and apps.", "backstage": { "role": "web-library" diff --git a/plugins/api-docs/CHANGELOG.md b/plugins/api-docs/CHANGELOG.md index 80aaf0dbc7..f41b4534f1 100644 --- a/plugins/api-docs/CHANGELOG.md +++ b/plugins/api-docs/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-api-docs +## 0.11.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.2-next.1 + - @backstage/plugin-catalog@1.21.1-next.1 + - @backstage/core-compat-api@0.2.7-next.0 + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/catalog-model@1.5.0 + - @backstage/frontend-plugin-api@0.6.7-next.0 + - @backstage/plugin-catalog-common@1.0.24 + - @backstage/plugin-permission-react@0.4.23 + ## 0.11.7-next.0 ### Patch Changes diff --git a/plugins/api-docs/package.json b/plugins/api-docs/package.json index 5a64e41e19..84e2891bcc 100644 --- a/plugins/api-docs/package.json +++ b/plugins/api-docs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-api-docs", - "version": "0.11.7-next.0", + "version": "0.11.7-next.1", "description": "A Backstage plugin that helps represent API entities in the frontend", "backstage": { "role": "frontend-plugin", diff --git a/plugins/app-backend/CHANGELOG.md b/plugins/app-backend/CHANGELOG.md index a898805ef2..b472d51f0f 100644 --- a/plugins/app-backend/CHANGELOG.md +++ b/plugins/app-backend/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-app-backend +## 0.3.71-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/config-loader@1.8.1 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-app-node@0.1.22-next.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + ## 0.3.70-next.0 ### Patch Changes diff --git a/plugins/app-backend/package.json b/plugins/app-backend/package.json index 50c7d98d55..0d44e3dc61 100644 --- a/plugins/app-backend/package.json +++ b/plugins/app-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-app-backend", - "version": "0.3.70-next.0", + "version": "0.3.71-next.1", "description": "A Backstage backend plugin that serves the Backstage frontend app", "backstage": { "role": "backend-plugin", diff --git a/plugins/app-node/CHANGELOG.md b/plugins/app-node/CHANGELOG.md index 71d34825c0..e5ff0eb99f 100644 --- a/plugins/app-node/CHANGELOG.md +++ b/plugins/app-node/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-app-node +## 0.1.22-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config-loader@1.8.1 + ## 0.1.21-next.0 ### Patch Changes diff --git a/plugins/app-node/package.json b/plugins/app-node/package.json index e7d639d620..11ddf46cf8 100644 --- a/plugins/app-node/package.json +++ b/plugins/app-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-app-node", - "version": "0.1.21-next.0", + "version": "0.1.22-next.1", "description": "Node.js library for the app plugin", "backstage": { "role": "node-library", diff --git a/plugins/auth-backend-module-atlassian-provider/CHANGELOG.md b/plugins/auth-backend-module-atlassian-provider/CHANGELOG.md index aadbd252ed..0449bc6933 100644 --- a/plugins/auth-backend-module-atlassian-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-atlassian-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-auth-backend-module-atlassian-provider +## 0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + ## 0.2.2-next.0 ### Patch Changes diff --git a/plugins/auth-backend-module-atlassian-provider/package.json b/plugins/auth-backend-module-atlassian-provider/package.json index 9ceec32602..d938144603 100644 --- a/plugins/auth-backend-module-atlassian-provider/package.json +++ b/plugins/auth-backend-module-atlassian-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-atlassian-provider", - "version": "0.2.2-next.0", + "version": "0.2.3-next.1", "description": "The atlassian-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-aws-alb-provider/CHANGELOG.md b/plugins/auth-backend-module-aws-alb-provider/CHANGELOG.md index 747f13b972..f1ae8a4981 100644 --- a/plugins/auth-backend-module-aws-alb-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-aws-alb-provider/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-auth-backend-module-aws-alb-provider +## 0.1.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-backend@0.22.9-next.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + ## 0.1.13-next.0 ### Patch Changes diff --git a/plugins/auth-backend-module-aws-alb-provider/package.json b/plugins/auth-backend-module-aws-alb-provider/package.json index 500914eb64..6ee5c274c1 100644 --- a/plugins/auth-backend-module-aws-alb-provider/package.json +++ b/plugins/auth-backend-module-aws-alb-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-aws-alb-provider", - "version": "0.1.13-next.0", + "version": "0.1.14-next.1", "description": "The aws-alb provider module for the Backstage auth backend.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-azure-easyauth-provider/CHANGELOG.md b/plugins/auth-backend-module-azure-easyauth-provider/CHANGELOG.md index 7067eb6b14..5e78ec6abb 100644 --- a/plugins/auth-backend-module-azure-easyauth-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-azure-easyauth-provider/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-auth-backend-module-azure-easyauth-provider +## 0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.17-next.1 + ## 0.1.4-next.0 ### Patch Changes diff --git a/plugins/auth-backend-module-azure-easyauth-provider/package.json b/plugins/auth-backend-module-azure-easyauth-provider/package.json index b505a45804..287059eb8f 100644 --- a/plugins/auth-backend-module-azure-easyauth-provider/package.json +++ b/plugins/auth-backend-module-azure-easyauth-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-azure-easyauth-provider", - "version": "0.1.4-next.0", + "version": "0.1.5-next.1", "description": "The azure-easyauth-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-bitbucket-provider/CHANGELOG.md b/plugins/auth-backend-module-bitbucket-provider/CHANGELOG.md index f337ee2c87..33b434f86e 100644 --- a/plugins/auth-backend-module-bitbucket-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-bitbucket-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-auth-backend-module-bitbucket-provider +## 0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + ## 0.1.4-next.0 ### Patch Changes diff --git a/plugins/auth-backend-module-bitbucket-provider/package.json b/plugins/auth-backend-module-bitbucket-provider/package.json index 70a5265b87..95189d2cea 100644 --- a/plugins/auth-backend-module-bitbucket-provider/package.json +++ b/plugins/auth-backend-module-bitbucket-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-bitbucket-provider", - "version": "0.1.4-next.0", + "version": "0.1.5-next.1", "description": "The bitbucket-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-cloudflare-access-provider/CHANGELOG.md b/plugins/auth-backend-module-cloudflare-access-provider/CHANGELOG.md index e94bb32963..9754e9a73a 100644 --- a/plugins/auth-backend-module-cloudflare-access-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-cloudflare-access-provider/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-auth-backend-module-cloudflare-access-provider +## 0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.17-next.1 + ## 0.1.4-next.0 ### Patch Changes diff --git a/plugins/auth-backend-module-cloudflare-access-provider/package.json b/plugins/auth-backend-module-cloudflare-access-provider/package.json index 076c94b37c..b0cd52d022 100644 --- a/plugins/auth-backend-module-cloudflare-access-provider/package.json +++ b/plugins/auth-backend-module-cloudflare-access-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-cloudflare-access-provider", - "version": "0.1.4-next.0", + "version": "0.1.5-next.1", "description": "The cloudflare-access-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-gcp-iap-provider/CHANGELOG.md b/plugins/auth-backend-module-gcp-iap-provider/CHANGELOG.md index c593dbacf8..8fe2c331a4 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.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + ## 0.2.16-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 bd97b9094d..8e00b9e935 100644 --- a/plugins/auth-backend-module-gcp-iap-provider/package.json +++ b/plugins/auth-backend-module-gcp-iap-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-gcp-iap-provider", - "version": "0.2.16-next.0", + "version": "0.2.17-next.1", "description": "A GCP IAP auth provider module for the Backstage auth backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-github-provider/CHANGELOG.md b/plugins/auth-backend-module-github-provider/CHANGELOG.md index 8461d67843..f73e6adf3c 100644 --- a/plugins/auth-backend-module-github-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-github-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-auth-backend-module-github-provider +## 0.1.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + ## 0.1.18-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 8a813883ce..138aaa4e02 100644 --- a/plugins/auth-backend-module-github-provider/package.json +++ b/plugins/auth-backend-module-github-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-github-provider", - "version": "0.1.18-next.0", + "version": "0.1.19-next.1", "description": "The github-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-gitlab-provider/CHANGELOG.md b/plugins/auth-backend-module-gitlab-provider/CHANGELOG.md index 5d84c75f92..a8d5844847 100644 --- a/plugins/auth-backend-module-gitlab-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-gitlab-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-auth-backend-module-gitlab-provider +## 0.1.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + ## 0.1.18-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 4dd9548f98..97e680237c 100644 --- a/plugins/auth-backend-module-gitlab-provider/package.json +++ b/plugins/auth-backend-module-gitlab-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-gitlab-provider", - "version": "0.1.18-next.0", + "version": "0.1.19-next.1", "description": "The gitlab-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-google-provider/CHANGELOG.md b/plugins/auth-backend-module-google-provider/CHANGELOG.md index 0cef76c81c..e7eeb2779c 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.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + ## 0.1.18-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 fdf8eb6728..55b2616502 100644 --- a/plugins/auth-backend-module-google-provider/package.json +++ b/plugins/auth-backend-module-google-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-google-provider", - "version": "0.1.18-next.0", + "version": "0.1.19-next.1", "description": "A Google auth provider module for the Backstage auth backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-guest-provider/CHANGELOG.md b/plugins/auth-backend-module-guest-provider/CHANGELOG.md index 5d9a1ac2c8..fd046e8dca 100644 --- a/plugins/auth-backend-module-guest-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-guest-provider/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-auth-backend-module-guest-provider +## 0.1.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.17-next.1 + ## 0.1.7-next.0 ### Patch Changes diff --git a/plugins/auth-backend-module-guest-provider/package.json b/plugins/auth-backend-module-guest-provider/package.json index 7f569c1f74..78fbd098f6 100644 --- a/plugins/auth-backend-module-guest-provider/package.json +++ b/plugins/auth-backend-module-guest-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-guest-provider", - "version": "0.1.7-next.0", + "version": "0.1.8-next.1", "description": "The guest-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-microsoft-provider/CHANGELOG.md b/plugins/auth-backend-module-microsoft-provider/CHANGELOG.md index 48ea704e10..668047c816 100644 --- a/plugins/auth-backend-module-microsoft-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-microsoft-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-auth-backend-module-microsoft-provider +## 0.1.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + ## 0.1.16-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 abdb555bb1..76d3236f8b 100644 --- a/plugins/auth-backend-module-microsoft-provider/package.json +++ b/plugins/auth-backend-module-microsoft-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-microsoft-provider", - "version": "0.1.16-next.0", + "version": "0.1.17-next.1", "description": "The microsoft-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md b/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md index b0d7371bbe..9872a64385 100644 --- a/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-auth-backend-module-oauth2-provider +## 0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + ## 0.2.2-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 b3f7d2ddfe..71934913fe 100644 --- a/plugins/auth-backend-module-oauth2-provider/package.json +++ b/plugins/auth-backend-module-oauth2-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-oauth2-provider", - "version": "0.2.2-next.0", + "version": "0.2.3-next.1", "description": "The oauth2-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-oauth2-proxy-provider/CHANGELOG.md b/plugins/auth-backend-module-oauth2-proxy-provider/CHANGELOG.md index 52480f24f3..895ada0e6e 100644 --- a/plugins/auth-backend-module-oauth2-proxy-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-oauth2-proxy-provider/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-auth-backend-module-oauth2-proxy-provider +## 0.1.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.17-next.1 + ## 0.1.14-next.0 ### Patch Changes diff --git a/plugins/auth-backend-module-oauth2-proxy-provider/package.json b/plugins/auth-backend-module-oauth2-proxy-provider/package.json index 717d4ba09a..4123403eb2 100644 --- a/plugins/auth-backend-module-oauth2-proxy-provider/package.json +++ b/plugins/auth-backend-module-oauth2-proxy-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-oauth2-proxy-provider", - "version": "0.1.14-next.0", + "version": "0.1.15-next.1", "description": "The oauth2-proxy-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-oidc-provider/CHANGELOG.md b/plugins/auth-backend-module-oidc-provider/CHANGELOG.md index a9f175f316..b9f8ffc98d 100644 --- a/plugins/auth-backend-module-oidc-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-oidc-provider/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-auth-backend-module-oidc-provider +## 0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/plugin-auth-backend@0.22.9-next.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + ## 0.2.2-next.0 ### Patch Changes diff --git a/plugins/auth-backend-module-oidc-provider/package.json b/plugins/auth-backend-module-oidc-provider/package.json index 95c5ff49f8..34e6c6f296 100644 --- a/plugins/auth-backend-module-oidc-provider/package.json +++ b/plugins/auth-backend-module-oidc-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-oidc-provider", - "version": "0.2.2-next.0", + "version": "0.2.3-next.1", "description": "The oidc-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-okta-provider/CHANGELOG.md b/plugins/auth-backend-module-okta-provider/CHANGELOG.md index c2fb212b1c..dfb5f638bf 100644 --- a/plugins/auth-backend-module-okta-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-okta-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-auth-backend-module-okta-provider +## 0.0.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + ## 0.0.14-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 16bbb79a44..cf099d40ee 100644 --- a/plugins/auth-backend-module-okta-provider/package.json +++ b/plugins/auth-backend-module-okta-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-okta-provider", - "version": "0.0.14-next.0", + "version": "0.0.15-next.1", "description": "The okta-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-onelogin-provider/CHANGELOG.md b/plugins/auth-backend-module-onelogin-provider/CHANGELOG.md index ed302347c4..8e21a1868e 100644 --- a/plugins/auth-backend-module-onelogin-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-onelogin-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-auth-backend-module-onelogin-provider +## 0.1.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + ## 0.1.2-next.0 ### Patch Changes diff --git a/plugins/auth-backend-module-onelogin-provider/package.json b/plugins/auth-backend-module-onelogin-provider/package.json index 54606d26f3..ac6a38a4f5 100644 --- a/plugins/auth-backend-module-onelogin-provider/package.json +++ b/plugins/auth-backend-module-onelogin-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-onelogin-provider", - "version": "0.1.2-next.0", + "version": "0.1.3-next.1", "description": "The onelogin-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-pinniped-provider/CHANGELOG.md b/plugins/auth-backend-module-pinniped-provider/CHANGELOG.md index 175d786367..4435efc501 100644 --- a/plugins/auth-backend-module-pinniped-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-pinniped-provider/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-auth-backend-module-pinniped-provider +## 0.1.16-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/plugin-auth-node@0.4.17-next.1 + ## 0.1.15-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 0b78dc7dd1..2698a56a2e 100644 --- a/plugins/auth-backend-module-pinniped-provider/package.json +++ b/plugins/auth-backend-module-pinniped-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-pinniped-provider", - "version": "0.1.15-next.0", + "version": "0.1.16-next.1", "description": "The pinniped-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-vmware-cloud-provider/CHANGELOG.md b/plugins/auth-backend-module-vmware-cloud-provider/CHANGELOG.md index c6b724bdd6..edfc30c099 100644 --- a/plugins/auth-backend-module-vmware-cloud-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-vmware-cloud-provider/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-auth-backend-module-vmware-cloud-provider +## 0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-auth-node@0.4.17-next.1 + ## 0.2.2-next.0 ### Patch Changes diff --git a/plugins/auth-backend-module-vmware-cloud-provider/package.json b/plugins/auth-backend-module-vmware-cloud-provider/package.json index 78fbccdd1f..d6b7eaf263 100644 --- a/plugins/auth-backend-module-vmware-cloud-provider/package.json +++ b/plugins/auth-backend-module-vmware-cloud-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-vmware-cloud-provider", - "version": "0.2.2-next.0", + "version": "0.2.3-next.1", "description": "The vmware-cloud-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend/CHANGELOG.md b/plugins/auth-backend/CHANGELOG.md index 98454b2c65..2bb083ed66 100644 --- a/plugins/auth-backend/CHANGELOG.md +++ b/plugins/auth-backend/CHANGELOG.md @@ -1,5 +1,35 @@ # @backstage/plugin-auth-backend +## 0.22.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-backend-module-atlassian-provider@0.2.3-next.1 + - @backstage/plugin-auth-backend-module-aws-alb-provider@0.1.14-next.1 + - @backstage/plugin-auth-backend-module-azure-easyauth-provider@0.1.5-next.1 + - @backstage/plugin-auth-backend-module-bitbucket-provider@0.1.5-next.1 + - @backstage/plugin-auth-backend-module-cloudflare-access-provider@0.1.5-next.1 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.17-next.1 + - @backstage/plugin-auth-backend-module-github-provider@0.1.19-next.1 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.1.19-next.1 + - @backstage/plugin-auth-backend-module-google-provider@0.1.19-next.1 + - @backstage/plugin-auth-backend-module-microsoft-provider@0.1.17-next.1 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.2.3-next.1 + - @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.15-next.1 + - @backstage/plugin-auth-backend-module-oidc-provider@0.2.3-next.1 + - @backstage/plugin-auth-backend-module-okta-provider@0.0.15-next.1 + - @backstage/plugin-auth-backend-module-onelogin-provider@0.1.3-next.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + - @backstage/plugin-catalog-node@1.12.4-next.1 + ## 0.22.8-next.0 ### Patch Changes diff --git a/plugins/auth-backend/package.json b/plugins/auth-backend/package.json index e14d4de6b0..cd31a18064 100644 --- a/plugins/auth-backend/package.json +++ b/plugins/auth-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend", - "version": "0.22.8-next.0", + "version": "0.22.9-next.1", "description": "A Backstage backend plugin that handles authentication", "backstage": { "role": "backend-plugin", diff --git a/plugins/auth-node/CHANGELOG.md b/plugins/auth-node/CHANGELOG.md index 5c775a6bc3..e931a1c26a 100644 --- a/plugins/auth-node/CHANGELOG.md +++ b/plugins/auth-node/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-auth-node +## 0.4.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 0.4.16-next.0 ### Patch Changes diff --git a/plugins/auth-node/package.json b/plugins/auth-node/package.json index c9b956def6..ab84eb7fe6 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.16-next.0", + "version": "0.4.17-next.1", "backstage": { "role": "node-library", "pluginId": "auth", diff --git a/plugins/catalog-backend-module-aws/CHANGELOG.md b/plugins/catalog-backend-module-aws/CHANGELOG.md index bd5663758a..15f944de19 100644 --- a/plugins/catalog-backend-module-aws/CHANGELOG.md +++ b/plugins/catalog-backend-module-aws/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-catalog-backend-module-aws +## 0.3.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.13.0-next.0 + - @backstage/integration-aws-node@0.1.12 + - @backstage/plugin-catalog-common@1.0.24 + - @backstage/plugin-catalog-node@1.12.4-next.1 + - @backstage/plugin-kubernetes-common@0.8.0 + ## 0.3.16-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-aws/package.json b/plugins/catalog-backend-module-aws/package.json index 3b75c3cfcd..7081b09d2b 100644 --- a/plugins/catalog-backend-module-aws/package.json +++ b/plugins/catalog-backend-module-aws/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-aws", - "version": "0.3.16-next.0", + "version": "0.3.17-next.1", "description": "A Backstage catalog backend module that helps integrate towards AWS", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-azure/CHANGELOG.md b/plugins/catalog-backend-module-azure/CHANGELOG.md index 598636a239..1f672302ac 100644 --- a/plugins/catalog-backend-module-azure/CHANGELOG.md +++ b/plugins/catalog-backend-module-azure/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-catalog-backend-module-azure +## 0.1.42-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/config@1.2.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-catalog-common@1.0.24 + - @backstage/plugin-catalog-node@1.12.4-next.1 + ## 0.1.41-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-azure/package.json b/plugins/catalog-backend-module-azure/package.json index bf0b69f177..1159aff6db 100644 --- a/plugins/catalog-backend-module-azure/package.json +++ b/plugins/catalog-backend-module-azure/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-azure", - "version": "0.1.41-next.0", + "version": "0.1.42-next.1", "description": "A Backstage catalog backend module that helps integrate towards Azure", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-backstage-openapi/CHANGELOG.md b/plugins/catalog-backend-module-backstage-openapi/CHANGELOG.md index fa23d67c67..125778b4b6 100644 --- a/plugins/catalog-backend-module-backstage-openapi/CHANGELOG.md +++ b/plugins/catalog-backend-module-backstage-openapi/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-catalog-backend-module-backstage-openapi +## 0.2.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-openapi-utils@0.1.15-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-catalog-node@1.12.4-next.1 + ## 0.2.4-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 4d06de5ddb..fad1dc47c9 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.2.4-next.0", + "version": "0.2.5-next.1", "backstage": { "role": "backend-plugin-module", "pluginId": "catalog", diff --git a/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md b/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md index 2a977a4f7b..4ad56f2aa3 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.2.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.21-next.0 + - @backstage/plugin-catalog-common@1.0.24 + - @backstage/plugin-catalog-node@1.12.4-next.1 + - @backstage/plugin-events-node@0.3.8-next.1 + ## 0.2.8-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 d0261ad01f..e691c2a3c3 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/package.json +++ b/plugins/catalog-backend-module-bitbucket-cloud/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-bitbucket-cloud", - "version": "0.2.8-next.0", + "version": "0.2.9-next.1", "description": "A Backstage catalog backend module that helps integrate towards Bitbucket Cloud", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md b/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md index f395e731ec..a5901702ff 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.36-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-catalog-node@1.12.4-next.1 + ## 0.1.35-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 4d2e0a1e78..4e47fcbdcc 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.35-next.0", + "version": "0.1.36-next.1", "backstage": { "role": "backend-plugin-module", "pluginId": "catalog", diff --git a/plugins/catalog-backend-module-gcp/CHANGELOG.md b/plugins/catalog-backend-module-gcp/CHANGELOG.md index 5948b92338..b76bc9d7a9 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.23-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/plugin-catalog-node@1.12.4-next.1 + - @backstage/plugin-kubernetes-common@0.8.0 + ## 0.1.22-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-gcp/package.json b/plugins/catalog-backend-module-gcp/package.json index 5cfcca3ba9..0888a9eb03 100644 --- a/plugins/catalog-backend-module-gcp/package.json +++ b/plugins/catalog-backend-module-gcp/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-gcp", - "version": "0.1.22-next.0", + "version": "0.1.23-next.1", "description": "A Backstage catalog backend module that helps integrate towards GCP", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-gerrit/CHANGELOG.md b/plugins/catalog-backend-module-gerrit/CHANGELOG.md index 5cab7509bc..6492e65ffa 100644 --- a/plugins/catalog-backend-module-gerrit/CHANGELOG.md +++ b/plugins/catalog-backend-module-gerrit/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-catalog-backend-module-gerrit +## 0.1.39-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-catalog-node@1.12.4-next.1 + ## 0.1.38-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-gerrit/package.json b/plugins/catalog-backend-module-gerrit/package.json index 7bac2566da..b99347e6f5 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.38-next.0", + "version": "0.1.39-next.1", "backstage": { "role": "backend-plugin-module", "pluginId": "catalog", diff --git a/plugins/catalog-backend-module-github-org/CHANGELOG.md b/plugins/catalog-backend-module-github-org/CHANGELOG.md index 950185b415..0236b1d30c 100644 --- a/plugins/catalog-backend-module-github-org/CHANGELOG.md +++ b/plugins/catalog-backend-module-github-org/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-catalog-backend-module-github-org +## 0.1.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend-module-github@0.6.5-next.1 + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/config@1.2.0 + - @backstage/plugin-catalog-node@1.12.4-next.1 + - @backstage/plugin-events-node@0.3.8-next.1 + ## 0.1.16-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 31daeea5ee..abd92889a0 100644 --- a/plugins/catalog-backend-module-github-org/package.json +++ b/plugins/catalog-backend-module-github-org/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-github-org", - "version": "0.1.16-next.0", + "version": "0.1.17-next.1", "description": "The github-org backend module for the catalog plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-github/CHANGELOG.md b/plugins/catalog-backend-module-github/CHANGELOG.md index d9dc710268..02975d2b68 100644 --- a/plugins/catalog-backend-module-github/CHANGELOG.md +++ b/plugins/catalog-backend-module-github/CHANGELOG.md @@ -1,5 +1,49 @@ # @backstage/plugin-catalog-backend-module-github +## 0.6.5-next.1 + +### Patch Changes + +- 9112efc: Adds support for `repository` events. + + The provider adds a subscription to the topic `github.repository`. + + Hereby, it supports events of type `repository` with actions + + - `archived` + - `deleted` + - `edited` + - `renamed` + - `transferred` + - `unarchived` + + Actions skipped as they don't require entity changes: + + - `created` + - `privatized` + - `publicized` + + If the config option `validateLocationsExist` is enabled, an API request + is necessary and will be executed. + This affects the actions `renamed`, `transferred`, and `unarchive` + of event type `repository`. + + Catalog entities related to the `GithubEntityProvider` instance will be adjusted + according to action and its meaning for them. + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.24.0-next.1 + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-catalog-common@1.0.24 + - @backstage/plugin-catalog-node@1.12.4-next.1 + - @backstage/plugin-events-node@0.3.8-next.1 + ## 0.6.4-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-github/package.json b/plugins/catalog-backend-module-github/package.json index 3528786e6d..c8b78c5e92 100644 --- a/plugins/catalog-backend-module-github/package.json +++ b/plugins/catalog-backend-module-github/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-github", - "version": "0.6.4-next.0", + "version": "0.6.5-next.1", "description": "A Backstage catalog backend module that helps integrate towards GitHub", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-gitlab-org/CHANGELOG.md b/plugins/catalog-backend-module-gitlab-org/CHANGELOG.md index 3ce5fef0b4..d86cb76c24 100644 --- a/plugins/catalog-backend-module-gitlab-org/CHANGELOG.md +++ b/plugins/catalog-backend-module-gitlab-org/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-catalog-backend-module-gitlab-org +## 0.0.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/plugin-catalog-backend-module-gitlab@0.3.21-next.1 + - @backstage/plugin-catalog-node@1.12.4-next.1 + - @backstage/plugin-events-node@0.3.8-next.1 + ## 0.0.4-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-gitlab-org/package.json b/plugins/catalog-backend-module-gitlab-org/package.json index 0861d4ec92..a08a42d1f3 100644 --- a/plugins/catalog-backend-module-gitlab-org/package.json +++ b/plugins/catalog-backend-module-gitlab-org/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-gitlab-org", - "version": "0.0.4-next.0", + "version": "0.0.5-next.1", "description": "The gitlab-org backend module for the catalog plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-gitlab/CHANGELOG.md b/plugins/catalog-backend-module-gitlab/CHANGELOG.md index 6fd86bb15d..8d6eb4bfef 100644 --- a/plugins/catalog-backend-module-gitlab/CHANGELOG.md +++ b/plugins/catalog-backend-module-gitlab/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-catalog-backend-module-gitlab +## 0.3.21-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-catalog-common@1.0.24 + - @backstage/plugin-catalog-node@1.12.4-next.1 + - @backstage/plugin-events-node@0.3.8-next.1 + ## 0.3.20-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-gitlab/package.json b/plugins/catalog-backend-module-gitlab/package.json index 51538cc178..0780ccdd6a 100644 --- a/plugins/catalog-backend-module-gitlab/package.json +++ b/plugins/catalog-backend-module-gitlab/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-gitlab", - "version": "0.3.20-next.0", + "version": "0.3.21-next.1", "description": "A Backstage catalog backend module that helps integrate towards GitLab", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md b/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md index 04da7cc46e..9cd19e259e 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md +++ b/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-catalog-backend-module-incremental-ingestion +## 0.4.27-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.24.0-next.1 + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-catalog-node@1.12.4-next.1 + - @backstage/plugin-events-node@0.3.8-next.1 + - @backstage/plugin-permission-common@0.7.14 + ## 0.4.26-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 2941fcd3f4..c9cf1f5a82 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/package.json +++ b/plugins/catalog-backend-module-incremental-ingestion/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-incremental-ingestion", - "version": "0.4.26-next.0", + "version": "0.4.27-next.1", "description": "An entity provider for streaming large asset sources into the catalog", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-ldap/CHANGELOG.md b/plugins/catalog-backend-module-ldap/CHANGELOG.md index b975322d0d..6842b99282 100644 --- a/plugins/catalog-backend-module-ldap/CHANGELOG.md +++ b/plugins/catalog-backend-module-ldap/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-catalog-backend-module-ldap +## 0.7.0-next.1 + +### Minor Changes + +- cb32ca7: **BREAKING**: `readLdapOrg` and the `LdapProviderConfig` type now always accept arrays of user and group configs, not just single items. + + Added support for single ldap catalog provider to provide list and undefined user and group bindings next to standard single one. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.24 + - @backstage/plugin-catalog-node@1.12.4-next.1 + ## 0.6.2-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-ldap/package.json b/plugins/catalog-backend-module-ldap/package.json index f719673682..411f168fd8 100644 --- a/plugins/catalog-backend-module-ldap/package.json +++ b/plugins/catalog-backend-module-ldap/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-ldap", - "version": "0.6.2-next.0", + "version": "0.7.0-next.1", "description": "A Backstage catalog backend module that helps integrate towards LDAP", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-logs/CHANGELOG.md b/plugins/catalog-backend-module-logs/CHANGELOG.md index 7e5ae51a99..c609fc369d 100644 --- a/plugins/catalog-backend-module-logs/CHANGELOG.md +++ b/plugins/catalog-backend-module-logs/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-catalog-backend-module-logs +## 0.0.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.24.0-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/plugin-events-node@0.3.8-next.1 + ## 0.0.1-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-logs/package.json b/plugins/catalog-backend-module-logs/package.json index e0d2e46c78..fe3f09c29c 100644 --- a/plugins/catalog-backend-module-logs/package.json +++ b/plugins/catalog-backend-module-logs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-logs", - "version": "0.0.1-next.0", + "version": "0.0.1-next.1", "description": "A module that subscribes to catalog releated events and logs them.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-msgraph/CHANGELOG.md b/plugins/catalog-backend-module-msgraph/CHANGELOG.md index 0f74e4591b..eb3591241f 100644 --- a/plugins/catalog-backend-module-msgraph/CHANGELOG.md +++ b/plugins/catalog-backend-module-msgraph/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-catalog-backend-module-msgraph +## 0.5.30-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/plugin-catalog-common@1.0.24 + - @backstage/plugin-catalog-node@1.12.4-next.1 + ## 0.5.29-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-msgraph/package.json b/plugins/catalog-backend-module-msgraph/package.json index 7ba2b7e1e6..b04cd8788c 100644 --- a/plugins/catalog-backend-module-msgraph/package.json +++ b/plugins/catalog-backend-module-msgraph/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-msgraph", - "version": "0.5.29-next.0", + "version": "0.5.30-next.1", "description": "A Backstage catalog backend module that helps integrate towards Microsoft Graph", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-openapi/CHANGELOG.md b/plugins/catalog-backend-module-openapi/CHANGELOG.md index 8003dc39ac..bf35045dcc 100644 --- a/plugins/catalog-backend-module-openapi/CHANGELOG.md +++ b/plugins/catalog-backend-module-openapi/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-catalog-backend-module-openapi +## 0.1.40-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.24.0-next.1 + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.24 + - @backstage/plugin-catalog-node@1.12.4-next.1 + ## 0.1.39-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-openapi/package.json b/plugins/catalog-backend-module-openapi/package.json index 7016701fc0..b37cb09b15 100644 --- a/plugins/catalog-backend-module-openapi/package.json +++ b/plugins/catalog-backend-module-openapi/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-openapi", - "version": "0.1.39-next.0", + "version": "0.1.40-next.1", "description": "A Backstage catalog backend module that helps with OpenAPI specifications", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-puppetdb/CHANGELOG.md b/plugins/catalog-backend-module-puppetdb/CHANGELOG.md index 4e5b25479a..ead44a56aa 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.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-node@1.12.4-next.1 + ## 0.1.27-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-puppetdb/package.json b/plugins/catalog-backend-module-puppetdb/package.json index 1759eebb14..114daa45e8 100644 --- a/plugins/catalog-backend-module-puppetdb/package.json +++ b/plugins/catalog-backend-module-puppetdb/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-puppetdb", - "version": "0.1.27-next.0", + "version": "0.1.28-next.1", "description": "A Backstage catalog backend module that helps integrate towards PuppetDB", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md b/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md index df4e93de73..758d59c7c0 100644 --- a/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md +++ b/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-catalog-backend-module-scaffolder-entity-model +## 0.1.20-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-catalog-common@1.0.24 + - @backstage/plugin-catalog-node@1.12.4-next.1 + - @backstage/plugin-scaffolder-common@1.5.3 + ## 0.1.19-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 a2891d2d4d..58bcdc6fb5 100644 --- a/plugins/catalog-backend-module-scaffolder-entity-model/package.json +++ b/plugins/catalog-backend-module-scaffolder-entity-model/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-scaffolder-entity-model", - "version": "0.1.19-next.0", + "version": "0.1.20-next.1", "description": "Adds support for the scaffolder specific entity model (e.g. the Template kind) to the catalog backend plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-unprocessed/CHANGELOG.md b/plugins/catalog-backend-module-unprocessed/CHANGELOG.md index 6940a04db9..afac0ebeed 100644 --- a/plugins/catalog-backend-module-unprocessed/CHANGELOG.md +++ b/plugins/catalog-backend-module-unprocessed/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-catalog-backend-module-unprocessed +## 0.4.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.17-next.1 + - @backstage/plugin-catalog-node@1.12.4-next.1 + - @backstage/plugin-catalog-unprocessed-entities-common@0.0.2 + - @backstage/plugin-permission-common@0.7.14 + ## 0.4.8-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-unprocessed/package.json b/plugins/catalog-backend-module-unprocessed/package.json index 582be2ffe8..c49a3d700d 100644 --- a/plugins/catalog-backend-module-unprocessed/package.json +++ b/plugins/catalog-backend-module-unprocessed/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-unprocessed", - "version": "0.4.8-next.0", + "version": "0.4.9-next.1", "description": "Backstage Catalog module to view unprocessed entities", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend/CHANGELOG.md b/plugins/catalog-backend/CHANGELOG.md index 16442df3c1..65ed28cb6d 100644 --- a/plugins/catalog-backend/CHANGELOG.md +++ b/plugins/catalog-backend/CHANGELOG.md @@ -1,5 +1,31 @@ # @backstage/plugin-catalog-backend +## 1.24.0-next.1 + +### Minor Changes + +- b9ed1bb: bumped better-sqlite3 from ^9.0.0 to ^11.0.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-openapi-utils@0.1.15-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.13.0-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.24 + - @backstage/plugin-catalog-node@1.12.4-next.1 + - @backstage/plugin-events-node@0.3.8-next.1 + - @backstage/plugin-permission-common@0.7.14 + - @backstage/plugin-permission-node@0.7.33-next.1 + - @backstage/plugin-search-backend-module-catalog@0.1.28-next.1 + ## 1.23.2-next.0 ### Patch Changes diff --git a/plugins/catalog-backend/package.json b/plugins/catalog-backend/package.json index 596e51435e..e554f0a334 100644 --- a/plugins/catalog-backend/package.json +++ b/plugins/catalog-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend", - "version": "1.23.2-next.0", + "version": "1.24.0-next.1", "description": "The Backstage backend plugin that provides the Backstage catalog", "backstage": { "role": "backend-plugin", diff --git a/plugins/catalog-graph/CHANGELOG.md b/plugins/catalog-graph/CHANGELOG.md index c632769632..fd2b0477e0 100644 --- a/plugins/catalog-graph/CHANGELOG.md +++ b/plugins/catalog-graph/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-catalog-graph +## 0.4.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.2-next.1 + - @backstage/core-compat-api@0.2.7-next.0 + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/frontend-plugin-api@0.6.7-next.0 + - @backstage/types@1.1.1 + ## 0.4.7-next.0 ### Patch Changes diff --git a/plugins/catalog-graph/package.json b/plugins/catalog-graph/package.json index 82f3e5d171..22e30e3406 100644 --- a/plugins/catalog-graph/package.json +++ b/plugins/catalog-graph/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-graph", - "version": "0.4.7-next.0", + "version": "0.4.7-next.1", "backstage": { "role": "frontend-plugin", "pluginId": "catalog-graph", diff --git a/plugins/catalog-import/CHANGELOG.md b/plugins/catalog-import/CHANGELOG.md index bbb56b6f08..bebc0c5240 100644 --- a/plugins/catalog-import/CHANGELOG.md +++ b/plugins/catalog-import/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-catalog-import +## 0.12.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.2-next.1 + - @backstage/core-compat-api@0.2.7-next.0 + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/frontend-plugin-api@0.6.7-next.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/integration-react@1.1.29-next.0 + - @backstage/plugin-catalog-common@1.0.24 + ## 0.12.1-next.0 ### Patch Changes diff --git a/plugins/catalog-import/package.json b/plugins/catalog-import/package.json index 1082f08113..704fdae2e6 100644 --- a/plugins/catalog-import/package.json +++ b/plugins/catalog-import/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-import", - "version": "0.12.1-next.0", + "version": "0.12.1-next.1", "description": "A Backstage plugin the helps you import entities into your catalog", "backstage": { "role": "frontend-plugin", diff --git a/plugins/catalog-node/CHANGELOG.md b/plugins/catalog-node/CHANGELOG.md index f23bfa9917..54f39e9e51 100644 --- a/plugins/catalog-node/CHANGELOG.md +++ b/plugins/catalog-node/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-catalog-node +## 1.12.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.24 + - @backstage/plugin-permission-common@0.7.14 + - @backstage/plugin-permission-node@0.7.33-next.1 + ## 1.12.3-next.0 ### Patch Changes diff --git a/plugins/catalog-node/package.json b/plugins/catalog-node/package.json index 293b915eea..575a1c65f5 100644 --- a/plugins/catalog-node/package.json +++ b/plugins/catalog-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-node", - "version": "1.12.3-next.0", + "version": "1.12.4-next.1", "description": "The plugin-catalog-node module for @backstage/plugin-catalog-backend", "backstage": { "role": "node-library", diff --git a/plugins/catalog-react/CHANGELOG.md b/plugins/catalog-react/CHANGELOG.md index 892bfe306d..68febf6b12 100644 --- a/plugins/catalog-react/CHANGELOG.md +++ b/plugins/catalog-react/CHANGELOG.md @@ -1,5 +1,24 @@ # @backstage/plugin-catalog-react +## 1.12.2-next.1 + +### Patch Changes + +- 06c0956: Support i18n for catalog and catalog-react plugins +- Updated dependencies + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/frontend-plugin-api@0.6.7-next.0 + - @backstage/integration-react@1.1.29-next.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + - @backstage/plugin-catalog-common@1.0.24 + - @backstage/plugin-permission-common@0.7.14 + - @backstage/plugin-permission-react@0.4.23 + ## 1.12.2-next.0 ### Patch Changes diff --git a/plugins/catalog-react/package.json b/plugins/catalog-react/package.json index 8267047b2d..99eb8af013 100644 --- a/plugins/catalog-react/package.json +++ b/plugins/catalog-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-react", - "version": "1.12.2-next.0", + "version": "1.12.2-next.1", "description": "A frontend library that helps other Backstage plugins interact with the catalog", "backstage": { "role": "web-library", diff --git a/plugins/catalog/CHANGELOG.md b/plugins/catalog/CHANGELOG.md index 9c6031799c..d003afccf1 100644 --- a/plugins/catalog/CHANGELOG.md +++ b/plugins/catalog/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-catalog +## 1.21.1-next.1 + +### Patch Changes + +- 06c0956: Support i18n for catalog and catalog-react plugins +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.2-next.1 + - @backstage/core-compat-api@0.2.7-next.0 + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/plugin-search-react@1.7.13-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/frontend-plugin-api@0.6.7-next.0 + - @backstage/integration-react@1.1.29-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.24 + - @backstage/plugin-permission-react@0.4.23 + - @backstage/plugin-scaffolder-common@1.5.3 + - @backstage/plugin-search-common@1.2.12 + ## 1.21.1-next.0 ### Patch Changes diff --git a/plugins/catalog/package.json b/plugins/catalog/package.json index 7cafc9cf92..5cf63e86ab 100644 --- a/plugins/catalog/package.json +++ b/plugins/catalog/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog", - "version": "1.21.1-next.0", + "version": "1.21.1-next.1", "description": "The Backstage plugin for browsing the Backstage catalog", "backstage": { "role": "frontend-plugin", diff --git a/plugins/devtools-backend/CHANGELOG.md b/plugins/devtools-backend/CHANGELOG.md index 94c827d2f3..cc0dc806c8 100644 --- a/plugins/devtools-backend/CHANGELOG.md +++ b/plugins/devtools-backend/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-devtools-backend +## 0.3.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/config-loader@1.8.1 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-devtools-common@0.1.10 + - @backstage/plugin-permission-common@0.7.14 + - @backstage/plugin-permission-node@0.7.33-next.1 + ## 0.3.7-next.0 ### Patch Changes diff --git a/plugins/devtools-backend/package.json b/plugins/devtools-backend/package.json index f15e205bca..bd3b61f22d 100644 --- a/plugins/devtools-backend/package.json +++ b/plugins/devtools-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-devtools-backend", - "version": "0.3.7-next.0", + "version": "0.3.8-next.1", "backstage": { "role": "backend-plugin", "pluginId": "devtools", diff --git a/plugins/events-backend-module-aws-sqs/CHANGELOG.md b/plugins/events-backend-module-aws-sqs/CHANGELOG.md index 677cdddcfc..399ed2689d 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.3.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + - @backstage/plugin-events-node@0.3.8-next.1 + ## 0.3.7-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 9cba8e76e3..b2c09d3b8a 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.3.7-next.0", + "version": "0.3.8-next.1", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-module-azure/CHANGELOG.md b/plugins/events-backend-module-azure/CHANGELOG.md index cea3fab2b6..5e5ccffc2a 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.2.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/plugin-events-node@0.3.8-next.1 + ## 0.2.7-next.0 ### Patch Changes diff --git a/plugins/events-backend-module-azure/package.json b/plugins/events-backend-module-azure/package.json index 74573116d7..8bb6ac4f6b 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.2.7-next.0", + "version": "0.2.8-next.1", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-module-bitbucket-cloud/CHANGELOG.md b/plugins/events-backend-module-bitbucket-cloud/CHANGELOG.md index eac1919f41..1a339c3807 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.2.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/plugin-events-node@0.3.8-next.1 + ## 0.2.7-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 471ecb4ae2..7efffdd361 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.2.7-next.0", + "version": "0.2.8-next.1", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-module-gerrit/CHANGELOG.md b/plugins/events-backend-module-gerrit/CHANGELOG.md index cb5ac5662f..78963fbbaf 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.2.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/plugin-events-node@0.3.8-next.1 + ## 0.2.7-next.0 ### Patch Changes diff --git a/plugins/events-backend-module-gerrit/package.json b/plugins/events-backend-module-gerrit/package.json index dbff36987a..f1bea2868c 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.2.7-next.0", + "version": "0.2.8-next.1", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-module-github/CHANGELOG.md b/plugins/events-backend-module-github/CHANGELOG.md index e2511f76ba..a095cf4ab3 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.2.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/plugin-events-node@0.3.8-next.1 + ## 0.2.7-next.0 ### Patch Changes diff --git a/plugins/events-backend-module-github/package.json b/plugins/events-backend-module-github/package.json index 126da9f29c..3b37f29022 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.2.7-next.0", + "version": "0.2.8-next.1", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-module-gitlab/CHANGELOG.md b/plugins/events-backend-module-gitlab/CHANGELOG.md index 89d2f47c10..dc8470bd7a 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.2.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/plugin-events-node@0.3.8-next.1 + ## 0.2.7-next.0 ### Patch Changes diff --git a/plugins/events-backend-module-gitlab/package.json b/plugins/events-backend-module-gitlab/package.json index 45a9637a24..21c95448b1 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.2.7-next.0", + "version": "0.2.8-next.1", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-test-utils/CHANGELOG.md b/plugins/events-backend-test-utils/CHANGELOG.md index e0f42a6f24..967ffc80da 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.32-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.3.8-next.1 + ## 0.1.31-next.0 ### Patch Changes diff --git a/plugins/events-backend-test-utils/package.json b/plugins/events-backend-test-utils/package.json index 931cb89248..120c7f5fa6 100644 --- a/plugins/events-backend-test-utils/package.json +++ b/plugins/events-backend-test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-test-utils", - "version": "0.1.31-next.0", + "version": "0.1.32-next.1", "description": "The plugin-events-backend-test-utils for @backstage/plugin-events-node", "backstage": { "role": "node-library", diff --git a/plugins/events-backend/CHANGELOG.md b/plugins/events-backend/CHANGELOG.md index a0e1f91a23..a4b4b550bb 100644 --- a/plugins/events-backend/CHANGELOG.md +++ b/plugins/events-backend/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-events-backend +## 0.3.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/plugin-events-node@0.3.8-next.1 + ## 0.3.8-next.0 ### Patch Changes diff --git a/plugins/events-backend/package.json b/plugins/events-backend/package.json index b176044bf9..82066d5a91 100644 --- a/plugins/events-backend/package.json +++ b/plugins/events-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend", - "version": "0.3.8-next.0", + "version": "0.3.9-next.1", "backstage": { "role": "backend-plugin", "pluginId": "events", diff --git a/plugins/events-node/CHANGELOG.md b/plugins/events-node/CHANGELOG.md index 1c5025b788..022d50fdd1 100644 --- a/plugins/events-node/CHANGELOG.md +++ b/plugins/events-node/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-events-node +## 0.3.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + ## 0.3.7-next.0 ### Patch Changes diff --git a/plugins/events-node/package.json b/plugins/events-node/package.json index 58790c4e02..f89617dd14 100644 --- a/plugins/events-node/package.json +++ b/plugins/events-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-node", - "version": "0.3.7-next.0", + "version": "0.3.8-next.1", "description": "The plugin-events-node module for @backstage/plugin-events-backend", "backstage": { "role": "node-library", diff --git a/plugins/example-todo-list-backend/CHANGELOG.md b/plugins/example-todo-list-backend/CHANGELOG.md index f42ba59723..d1553258ed 100644 --- a/plugins/example-todo-list-backend/CHANGELOG.md +++ b/plugins/example-todo-list-backend/CHANGELOG.md @@ -1,5 +1,15 @@ # @internal/plugin-todo-list-backend +## 1.0.29-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.17-next.1 + ## 1.0.29-next.0 ### Patch Changes diff --git a/plugins/example-todo-list-backend/package.json b/plugins/example-todo-list-backend/package.json index ec37ce2843..3d46a9f5f7 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.29-next.0", + "version": "1.0.29-next.1", "backstage": { "role": "backend-plugin", "pluginId": "todo-list", diff --git a/plugins/home-react/CHANGELOG.md b/plugins/home-react/CHANGELOG.md index 62f3d98623..8353571dd8 100644 --- a/plugins/home-react/CHANGELOG.md +++ b/plugins/home-react/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-home-react +## 0.1.15-next.1 + +### Patch Changes + +- cc81579: Updated dependency `@rjsf/utils` to `5.18.5`. + Updated dependency `@rjsf/core` to `5.18.5`. + Updated dependency `@rjsf/material-ui` to `5.18.5`. + Updated dependency `@rjsf/validator-ajv8` to `5.18.5`. +- Updated dependencies + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + ## 0.1.15-next.0 ### Patch Changes diff --git a/plugins/home-react/package.json b/plugins/home-react/package.json index 9c7667b4d0..b5dcaae83e 100644 --- a/plugins/home-react/package.json +++ b/plugins/home-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-home-react", - "version": "0.1.15-next.0", + "version": "0.1.15-next.1", "description": "A Backstage plugin that contains react components helps you build a home page", "backstage": { "role": "web-library", diff --git a/plugins/home/CHANGELOG.md b/plugins/home/CHANGELOG.md index b6ff8061f2..b475b7f764 100644 --- a/plugins/home/CHANGELOG.md +++ b/plugins/home/CHANGELOG.md @@ -1,5 +1,26 @@ # @backstage/plugin-home +## 0.7.7-next.1 + +### Patch Changes + +- cc81579: Updated dependency `@rjsf/utils` to `5.18.5`. + Updated dependency `@rjsf/core` to `5.18.5`. + Updated dependency `@rjsf/material-ui` to `5.18.5`. + Updated dependency `@rjsf/validator-ajv8` to `5.18.5`. +- Updated dependencies + - @backstage/core-app-api@1.13.1-next.1 + - @backstage/plugin-catalog-react@1.12.2-next.1 + - @backstage/plugin-home-react@0.1.15-next.1 + - @backstage/core-compat-api@0.2.7-next.0 + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/frontend-plugin-api@0.6.7-next.0 + - @backstage/theme@0.5.6 + ## 0.7.6-next.0 ### Patch Changes diff --git a/plugins/home/package.json b/plugins/home/package.json index 2bc646b417..928417145b 100644 --- a/plugins/home/package.json +++ b/plugins/home/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-home", - "version": "0.7.6-next.0", + "version": "0.7.7-next.1", "description": "A Backstage plugin that helps you build a home page", "backstage": { "role": "frontend-plugin", diff --git a/plugins/kubernetes-backend/CHANGELOG.md b/plugins/kubernetes-backend/CHANGELOG.md index ea2049d73c..7b8d3fb534 100644 --- a/plugins/kubernetes-backend/CHANGELOG.md +++ b/plugins/kubernetes-backend/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-kubernetes-backend +## 0.18.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration-aws-node@0.1.12 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + - @backstage/plugin-catalog-node@1.12.4-next.1 + - @backstage/plugin-kubernetes-common@0.8.0 + - @backstage/plugin-kubernetes-node@0.1.16-next.1 + - @backstage/plugin-permission-common@0.7.14 + - @backstage/plugin-permission-node@0.7.33-next.1 + ## 0.18.2-next.0 ### Patch Changes diff --git a/plugins/kubernetes-backend/package.json b/plugins/kubernetes-backend/package.json index d0de031d9d..c9d8733319 100644 --- a/plugins/kubernetes-backend/package.json +++ b/plugins/kubernetes-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes-backend", - "version": "0.18.2-next.0", + "version": "0.18.3-next.1", "description": "A Backstage backend plugin that integrates towards Kubernetes", "backstage": { "role": "backend-plugin", diff --git a/plugins/kubernetes-cluster/CHANGELOG.md b/plugins/kubernetes-cluster/CHANGELOG.md index cef2c059d1..0d8596888a 100644 --- a/plugins/kubernetes-cluster/CHANGELOG.md +++ b/plugins/kubernetes-cluster/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-kubernetes-cluster +## 0.0.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.2-next.1 + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/plugin-kubernetes-react@0.4.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-kubernetes-common@0.8.0 + ## 0.0.13-next.0 ### Patch Changes diff --git a/plugins/kubernetes-cluster/package.json b/plugins/kubernetes-cluster/package.json index ce1fa2bc63..40a6d33dd2 100644 --- a/plugins/kubernetes-cluster/package.json +++ b/plugins/kubernetes-cluster/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes-cluster", - "version": "0.0.13-next.0", + "version": "0.0.13-next.1", "description": "A Backstage plugin that shows details of Kubernetes clusters", "backstage": { "role": "frontend-plugin", diff --git a/plugins/kubernetes-node/CHANGELOG.md b/plugins/kubernetes-node/CHANGELOG.md index 6f6306cda6..4a6514a2d0 100644 --- a/plugins/kubernetes-node/CHANGELOG.md +++ b/plugins/kubernetes-node/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-kubernetes-node +## 0.1.16-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/types@1.1.1 + - @backstage/plugin-kubernetes-common@0.8.0 + ## 0.1.15-next.0 ### Patch Changes diff --git a/plugins/kubernetes-node/package.json b/plugins/kubernetes-node/package.json index 2b4d061ba7..461bf1bbbe 100644 --- a/plugins/kubernetes-node/package.json +++ b/plugins/kubernetes-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes-node", - "version": "0.1.15-next.0", + "version": "0.1.16-next.1", "description": "Node.js library for the kubernetes plugin", "backstage": { "role": "node-library", diff --git a/plugins/kubernetes/CHANGELOG.md b/plugins/kubernetes/CHANGELOG.md index 5c8c4d6d4b..2d92f6b026 100644 --- a/plugins/kubernetes/CHANGELOG.md +++ b/plugins/kubernetes/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-kubernetes +## 0.11.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.2-next.1 + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/plugin-kubernetes-react@0.4.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-kubernetes-common@0.8.0 + ## 0.11.12-next.0 ### Patch Changes diff --git a/plugins/kubernetes/package.json b/plugins/kubernetes/package.json index 998bae3626..eef4da08bc 100644 --- a/plugins/kubernetes/package.json +++ b/plugins/kubernetes/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes", - "version": "0.11.12-next.0", + "version": "0.11.12-next.1", "description": "A Backstage plugin that integrates towards Kubernetes", "backstage": { "role": "frontend-plugin", diff --git a/plugins/notifications-backend-module-email/CHANGELOG.md b/plugins/notifications-backend-module-email/CHANGELOG.md index 60725d15ee..c536369352 100644 --- a/plugins/notifications-backend-module-email/CHANGELOG.md +++ b/plugins/notifications-backend-module-email/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-notifications-backend-module-email +## 0.1.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/integration-aws-node@0.1.12 + - @backstage/types@1.1.1 + - @backstage/plugin-notifications-common@0.0.4 + - @backstage/plugin-notifications-node@0.2.3-next.1 + ## 0.1.2-next.0 ### Patch Changes diff --git a/plugins/notifications-backend-module-email/package.json b/plugins/notifications-backend-module-email/package.json index 76bf5432e2..c47a65d4f4 100644 --- a/plugins/notifications-backend-module-email/package.json +++ b/plugins/notifications-backend-module-email/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-notifications-backend-module-email", - "version": "0.1.2-next.0", + "version": "0.1.3-next.1", "description": "The email backend module for the notifications plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/notifications-backend/CHANGELOG.md b/plugins/notifications-backend/CHANGELOG.md index c42aa95a2e..a4be935628 100644 --- a/plugins/notifications-backend/CHANGELOG.md +++ b/plugins/notifications-backend/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-notifications-backend +## 0.3.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.17-next.1 + - @backstage/plugin-events-node@0.3.8-next.1 + - @backstage/plugin-notifications-common@0.0.4 + - @backstage/plugin-notifications-node@0.2.3-next.1 + - @backstage/plugin-signals-node@0.1.8-next.1 + ## 0.3.2-next.0 ### Patch Changes diff --git a/plugins/notifications-backend/package.json b/plugins/notifications-backend/package.json index 63b3b263b1..bfa1f2f0bd 100644 --- a/plugins/notifications-backend/package.json +++ b/plugins/notifications-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-notifications-backend", - "version": "0.3.2-next.0", + "version": "0.3.3-next.1", "backstage": { "role": "backend-plugin", "pluginId": "notifications", diff --git a/plugins/notifications-node/CHANGELOG.md b/plugins/notifications-node/CHANGELOG.md index 041d0c355f..69e594b513 100644 --- a/plugins/notifications-node/CHANGELOG.md +++ b/plugins/notifications-node/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-notifications-node +## 0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-notifications-common@0.0.4 + - @backstage/plugin-signals-node@0.1.8-next.1 + ## 0.2.2-next.0 ### Patch Changes diff --git a/plugins/notifications-node/package.json b/plugins/notifications-node/package.json index e79b457965..f18ce420f7 100644 --- a/plugins/notifications-node/package.json +++ b/plugins/notifications-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-notifications-node", - "version": "0.2.2-next.0", + "version": "0.2.3-next.1", "description": "Node.js library for the notifications plugin", "backstage": { "role": "node-library", diff --git a/plugins/notifications/CHANGELOG.md b/plugins/notifications/CHANGELOG.md index ebcacf97f6..9f532b3698 100644 --- a/plugins/notifications/CHANGELOG.md +++ b/plugins/notifications/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-notifications +## 0.2.3-next.1 + +### Patch Changes + +- 3bf0697: The toolbar on the Notifications page is hidden when there are no listed notifications. +- Updated dependencies + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/plugin-notifications-common@0.0.4 + - @backstage/plugin-signals-react@0.0.4 + ## 0.2.3-next.0 ### Patch Changes diff --git a/plugins/notifications/package.json b/plugins/notifications/package.json index bc868c56a1..2e2c67e891 100644 --- a/plugins/notifications/package.json +++ b/plugins/notifications/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-notifications", - "version": "0.2.3-next.0", + "version": "0.2.3-next.1", "backstage": { "role": "frontend-plugin", "pluginId": "notifications", diff --git a/plugins/org-react/CHANGELOG.md b/plugins/org-react/CHANGELOG.md index 8c2ea470da..1ce749fede 100644 --- a/plugins/org-react/CHANGELOG.md +++ b/plugins/org-react/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-org-react +## 0.1.26-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.2-next.1 + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + ## 0.1.26-next.0 ### Patch Changes diff --git a/plugins/org-react/package.json b/plugins/org-react/package.json index 7bde5d9e9a..327e27662f 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.26-next.0", + "version": "0.1.26-next.1", "backstage": { "role": "web-library", "pluginId": "org", diff --git a/plugins/org/CHANGELOG.md b/plugins/org/CHANGELOG.md index fe82d2c948..5ca788557f 100644 --- a/plugins/org/CHANGELOG.md +++ b/plugins/org/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-org +## 0.6.27-next.1 + +### Patch Changes + +- 5132d28: The `useGetEntities` hook could result in requests to `/api/catalog/entities` where the headers exceed the default maximum Node.js header size of 16KB. The hook logic has been adjusted to batch the requests. +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.2-next.1 + - @backstage/core-compat-api@0.2.7-next.0 + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/catalog-model@1.5.0 + - @backstage/frontend-plugin-api@0.6.7-next.0 + - @backstage/plugin-catalog-common@1.0.24 + ## 0.6.27-next.0 ### Patch Changes diff --git a/plugins/org/package.json b/plugins/org/package.json index 5b749ac215..5c62ffa99f 100644 --- a/plugins/org/package.json +++ b/plugins/org/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-org", - "version": "0.6.27-next.0", + "version": "0.6.27-next.1", "description": "A Backstage plugin that helps you create entity pages for your organization", "backstage": { "role": "frontend-plugin", diff --git a/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md b/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md index 9192850893..616c6acda2 100644 --- a/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md +++ b/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-permission-backend-module-allow-all-policy +## 0.1.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + - @backstage/plugin-permission-common@0.7.14 + - @backstage/plugin-permission-node@0.7.33-next.1 + ## 0.1.18-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 62a3f6d101..60e11825f4 100644 --- a/plugins/permission-backend-module-policy-allow-all/package.json +++ b/plugins/permission-backend-module-policy-allow-all/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-permission-backend-module-allow-all-policy", - "version": "0.1.18-next.0", + "version": "0.1.19-next.1", "description": "Allow all policy backend module for the permission plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/permission-backend/CHANGELOG.md b/plugins/permission-backend/CHANGELOG.md index d7190f15ee..39ae10e557 100644 --- a/plugins/permission-backend/CHANGELOG.md +++ b/plugins/permission-backend/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-permission-backend +## 0.5.46-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.17-next.1 + - @backstage/plugin-permission-common@0.7.14 + - @backstage/plugin-permission-node@0.7.33-next.1 + ## 0.5.45-next.0 ### Patch Changes diff --git a/plugins/permission-backend/package.json b/plugins/permission-backend/package.json index 24b62d1358..43a57407e1 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.45-next.0", + "version": "0.5.46-next.1", "backstage": { "role": "backend-plugin", "pluginId": "permission", diff --git a/plugins/permission-node/CHANGELOG.md b/plugins/permission-node/CHANGELOG.md index 7255dbe266..a63abb1d95 100644 --- a/plugins/permission-node/CHANGELOG.md +++ b/plugins/permission-node/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-permission-node +## 0.7.33-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.17-next.1 + - @backstage/plugin-permission-common@0.7.14 + ## 0.7.32-next.0 ### Patch Changes diff --git a/plugins/permission-node/package.json b/plugins/permission-node/package.json index 695e28f30b..db3c067088 100644 --- a/plugins/permission-node/package.json +++ b/plugins/permission-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-permission-node", - "version": "0.7.32-next.0", + "version": "0.7.33-next.1", "description": "Common permission and authorization utilities for backend plugins", "backstage": { "role": "node-library", diff --git a/plugins/proxy-backend/CHANGELOG.md b/plugins/proxy-backend/CHANGELOG.md index d57f4936fb..a6c1ef02d2 100644 --- a/plugins/proxy-backend/CHANGELOG.md +++ b/plugins/proxy-backend/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-proxy-backend +## 0.5.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + ## 0.5.2-next.0 ### Patch Changes diff --git a/plugins/proxy-backend/package.json b/plugins/proxy-backend/package.json index 18ad338131..23acc935f3 100644 --- a/plugins/proxy-backend/package.json +++ b/plugins/proxy-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-proxy-backend", - "version": "0.5.2-next.0", + "version": "0.5.3-next.1", "description": "A Backstage backend plugin that helps you set up proxy endpoints in the backend", "backstage": { "role": "backend-plugin", diff --git a/plugins/scaffolder-backend-module-azure/CHANGELOG.md b/plugins/scaffolder-backend-module-azure/CHANGELOG.md index 99ff7bd723..c634d8c8ca 100644 --- a/plugins/scaffolder-backend-module-azure/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-azure/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-scaffolder-backend-module-azure +## 0.1.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-scaffolder-node@0.4.8-next.1 + ## 0.1.13-next.0 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-azure/package.json b/plugins/scaffolder-backend-module-azure/package.json index 672689ef73..c0e00e8ffe 100644 --- a/plugins/scaffolder-backend-module-azure/package.json +++ b/plugins/scaffolder-backend-module-azure/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-azure", - "version": "0.1.13-next.0", + "version": "0.1.14-next.1", "description": "The azure module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/CHANGELOG.md b/plugins/scaffolder-backend-module-bitbucket-cloud/CHANGELOG.md index f4453bab7a..4e1e2b9531 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-scaffolder-backend-module-bitbucket-cloud +## 0.1.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.21-next.0 + - @backstage/plugin-scaffolder-node@0.4.8-next.1 + ## 0.1.11-next.0 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/package.json b/plugins/scaffolder-backend-module-bitbucket-cloud/package.json index d4432ee3d5..5ce826ff1a 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/package.json +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-bitbucket-cloud", - "version": "0.1.11-next.0", + "version": "0.1.12-next.1", "description": "The Bitbucket Cloud module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-bitbucket-server/CHANGELOG.md b/plugins/scaffolder-backend-module-bitbucket-server/CHANGELOG.md index f614b16994..3443242e91 100644 --- a/plugins/scaffolder-backend-module-bitbucket-server/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-bitbucket-server/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-scaffolder-backend-module-bitbucket-server +## 0.1.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-scaffolder-node@0.4.8-next.1 + ## 0.1.11-next.0 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-bitbucket-server/package.json b/plugins/scaffolder-backend-module-bitbucket-server/package.json index 16ce106570..b396faa5e5 100644 --- a/plugins/scaffolder-backend-module-bitbucket-server/package.json +++ b/plugins/scaffolder-backend-module-bitbucket-server/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-bitbucket-server", - "version": "0.1.11-next.0", + "version": "0.1.12-next.1", "description": "The Bitbucket Server module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-bitbucket/CHANGELOG.md b/plugins/scaffolder-backend-module-bitbucket/CHANGELOG.md index dc3a0f1597..35f5382652 100644 --- a/plugins/scaffolder-backend-module-bitbucket/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-bitbucket/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-scaffolder-backend-module-bitbucket +## 0.2.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.1.12-next.1 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.1.12-next.1 + - @backstage/plugin-scaffolder-node@0.4.8-next.1 + ## 0.2.11-next.0 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-bitbucket/package.json b/plugins/scaffolder-backend-module-bitbucket/package.json index 35b23e39d9..bca6e94878 100644 --- a/plugins/scaffolder-backend-module-bitbucket/package.json +++ b/plugins/scaffolder-backend-module-bitbucket/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-bitbucket", - "version": "0.2.11-next.0", + "version": "0.2.12-next.1", "description": "The bitbucket module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md b/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md index d24746f67a..b3c7bfbe36 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.23-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-scaffolder-node@0.4.8-next.1 + ## 0.2.22-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 34e49f740f..f607696136 100644 --- a/plugins/scaffolder-backend-module-confluence-to-markdown/package.json +++ b/plugins/scaffolder-backend-module-confluence-to-markdown/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-confluence-to-markdown", - "version": "0.2.22-next.0", + "version": "0.2.23-next.1", "description": "The confluence-to-markdown module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md b/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md index dfa740b4a6..5854e9ff47 100644 --- a/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-scaffolder-backend-module-cookiecutter +## 0.2.46-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.13.0-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.4.8-next.1 + ## 0.2.45-next.0 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-cookiecutter/package.json b/plugins/scaffolder-backend-module-cookiecutter/package.json index ea0a7fad77..43a7e348a4 100644 --- a/plugins/scaffolder-backend-module-cookiecutter/package.json +++ b/plugins/scaffolder-backend-module-cookiecutter/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-cookiecutter", - "version": "0.2.45-next.0", + "version": "0.2.46-next.1", "description": "A module for the scaffolder backend that lets you template projects using cookiecutter", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-gcp/CHANGELOG.md b/plugins/scaffolder-backend-module-gcp/CHANGELOG.md index 5afcde9965..e32c2ef08f 100644 --- a/plugins/scaffolder-backend-module-gcp/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-gcp/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-scaffolder-backend-module-gcp +## 0.1.0-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-scaffolder-node@0.4.8-next.1 + ## 0.1.0-next.2 ### Minor Changes diff --git a/plugins/scaffolder-backend-module-gcp/package.json b/plugins/scaffolder-backend-module-gcp/package.json index 2f8f130d39..c441acb21a 100644 --- a/plugins/scaffolder-backend-module-gcp/package.json +++ b/plugins/scaffolder-backend-module-gcp/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-gcp", - "version": "0.1.0-next.2", + "version": "0.1.0-next.3", "description": "The GCP Bucket module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-gerrit/CHANGELOG.md b/plugins/scaffolder-backend-module-gerrit/CHANGELOG.md index cc4d9612a1..dd26e1d5a8 100644 --- a/plugins/scaffolder-backend-module-gerrit/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-gerrit/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-scaffolder-backend-module-gerrit +## 0.1.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-scaffolder-node@0.4.8-next.1 + ## 0.1.13-next.0 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-gerrit/package.json b/plugins/scaffolder-backend-module-gerrit/package.json index 06c5d063d4..31a30c3f7e 100644 --- a/plugins/scaffolder-backend-module-gerrit/package.json +++ b/plugins/scaffolder-backend-module-gerrit/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-gerrit", - "version": "0.1.13-next.0", + "version": "0.1.14-next.1", "description": "The gerrit module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-gitea/CHANGELOG.md b/plugins/scaffolder-backend-module-gitea/CHANGELOG.md index 5f26aa6a2d..f3ceb7ce8c 100644 --- a/plugins/scaffolder-backend-module-gitea/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-gitea/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-scaffolder-backend-module-gitea +## 0.1.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-scaffolder-node@0.4.8-next.1 + ## 0.1.11-next.0 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-gitea/package.json b/plugins/scaffolder-backend-module-gitea/package.json index f6563795cd..3cacbc66db 100644 --- a/plugins/scaffolder-backend-module-gitea/package.json +++ b/plugins/scaffolder-backend-module-gitea/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-gitea", - "version": "0.1.11-next.0", + "version": "0.1.12-next.1", "description": "The gitea module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-github/CHANGELOG.md b/plugins/scaffolder-backend-module-github/CHANGELOG.md index e3cd0904aa..2d3c6ff0f2 100644 --- a/plugins/scaffolder-backend-module-github/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-github/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-scaffolder-backend-module-github +## 0.4.0-next.1 + +### Patch Changes + +- 141f366: Added action to enable GitHub Pages on a repo +- dfaa28d: Adds `requireLastPushApproval` input property to configure Branch Protection Settings in `github:publish` action + + Adds `requireLastPushApproval` input property to configure Branch Protection Settings in `github:repo:push` action + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-scaffolder-node@0.4.8-next.1 + ## 0.4.0-next.0 ### Minor Changes diff --git a/plugins/scaffolder-backend-module-github/package.json b/plugins/scaffolder-backend-module-github/package.json index 1fd404c6f9..500ec86f9f 100644 --- a/plugins/scaffolder-backend-module-github/package.json +++ b/plugins/scaffolder-backend-module-github/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-github", - "version": "0.4.0-next.0", + "version": "0.4.0-next.1", "description": "The github module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md b/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md index c64aa0ca32..0c8f0529a6 100644 --- a/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-scaffolder-backend-module-gitlab +## 0.4.4-next.1 + +### Patch Changes + +- 2fb0eb8: Added support for passing `variables` to `gitlab:pipeline:trigger` +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-scaffolder-node@0.4.8-next.1 + ## 0.4.3-next.0 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-gitlab/package.json b/plugins/scaffolder-backend-module-gitlab/package.json index 7444bde77d..499cfd6872 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.4.3-next.0", + "version": "0.4.4-next.1", "backstage": { "role": "backend-plugin-module", "pluginId": "scaffolder", diff --git a/plugins/scaffolder-backend-module-notifications/CHANGELOG.md b/plugins/scaffolder-backend-module-notifications/CHANGELOG.md index 948770e600..6371124957 100644 --- a/plugins/scaffolder-backend-module-notifications/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-notifications/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-scaffolder-backend-module-notifications +## 0.0.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/plugin-notifications-common@0.0.4 + - @backstage/plugin-notifications-node@0.2.3-next.1 + - @backstage/plugin-scaffolder-node@0.4.8-next.1 + ## 0.0.4-next.0 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-notifications/package.json b/plugins/scaffolder-backend-module-notifications/package.json index bb8b7807e8..7c983c36ce 100644 --- a/plugins/scaffolder-backend-module-notifications/package.json +++ b/plugins/scaffolder-backend-module-notifications/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-notifications", - "version": "0.0.4-next.0", + "version": "0.0.5-next.1", "description": "The notifications backend module for the scaffolder plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-rails/CHANGELOG.md b/plugins/scaffolder-backend-module-rails/CHANGELOG.md index afaebde648..0db7584509 100644 --- a/plugins/scaffolder-backend-module-rails/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-rails/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-scaffolder-backend-module-rails +## 0.4.39-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.13.0-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.4.8-next.1 + ## 0.4.38-next.0 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-rails/package.json b/plugins/scaffolder-backend-module-rails/package.json index a736106df1..c15815d2fa 100644 --- a/plugins/scaffolder-backend-module-rails/package.json +++ b/plugins/scaffolder-backend-module-rails/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-rails", - "version": "0.4.38-next.0", + "version": "0.4.39-next.1", "description": "A module for the scaffolder backend that lets you template projects using Rails", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-sentry/CHANGELOG.md b/plugins/scaffolder-backend-module-sentry/CHANGELOG.md index fa7712e500..29e8c17b04 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.30-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.8-next.1 + ## 0.1.29-next.0 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-sentry/package.json b/plugins/scaffolder-backend-module-sentry/package.json index 7943de9b5c..c0866f979d 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.29-next.0", + "version": "0.1.30-next.1", "backstage": { "role": "backend-plugin-module", "pluginId": "scaffolder", diff --git a/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md b/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md index c3c2322b9a..4e99b51284 100644 --- a/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-scaffolder-backend-module-yeoman +## 0.3.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node-test-utils@0.1.9-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.4.8-next.1 + ## 0.3.5-next.0 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-yeoman/package.json b/plugins/scaffolder-backend-module-yeoman/package.json index 70133616ef..76158fdc01 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.3.5-next.0", + "version": "0.3.6-next.1", "backstage": { "role": "backend-plugin-module", "pluginId": "scaffolder", diff --git a/plugins/scaffolder-backend/CHANGELOG.md b/plugins/scaffolder-backend/CHANGELOG.md index 5737dc0165..97cd859856 100644 --- a/plugins/scaffolder-backend/CHANGELOG.md +++ b/plugins/scaffolder-backend/CHANGELOG.md @@ -1,5 +1,36 @@ # @backstage/plugin-scaffolder-backend +## 1.23.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend-module-github@0.4.0-next.1 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.4.4-next.1 + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.13.0-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + - @backstage/plugin-bitbucket-cloud-common@0.2.21-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.20-next.1 + - @backstage/plugin-catalog-node@1.12.4-next.1 + - @backstage/plugin-permission-common@0.7.14 + - @backstage/plugin-permission-node@0.7.33-next.1 + - @backstage/plugin-scaffolder-backend-module-azure@0.1.14-next.1 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.2.12-next.1 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.1.12-next.1 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.1.12-next.1 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.1.14-next.1 + - @backstage/plugin-scaffolder-backend-module-gitea@0.1.12-next.1 + - @backstage/plugin-scaffolder-common@1.5.3 + - @backstage/plugin-scaffolder-node@0.4.8-next.1 + ## 1.23.0-next.0 ### Minor Changes diff --git a/plugins/scaffolder-backend/package.json b/plugins/scaffolder-backend/package.json index c9c19d9983..71857e245b 100644 --- a/plugins/scaffolder-backend/package.json +++ b/plugins/scaffolder-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend", - "version": "1.23.0-next.0", + "version": "1.23.0-next.1", "description": "The Backstage backend plugin that helps you create new things", "backstage": { "role": "backend-plugin", diff --git a/plugins/scaffolder-node-test-utils/CHANGELOG.md b/plugins/scaffolder-node-test-utils/CHANGELOG.md index 1136cce04b..9104fbcb26 100644 --- a/plugins/scaffolder-node-test-utils/CHANGELOG.md +++ b/plugins/scaffolder-node-test-utils/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-scaffolder-node-test-utils +## 0.1.9-next.1 + +### Patch Changes + +- 54429b5: Filename and imports correction for mockActionContext.ts +- Updated dependencies + - @backstage/backend-test-utils@0.4.4-next.1 + - @backstage/backend-common@0.23.3-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.4.8-next.1 + ## 0.1.8-next.0 ### Patch Changes diff --git a/plugins/scaffolder-node-test-utils/package.json b/plugins/scaffolder-node-test-utils/package.json index 87f895efc3..d361d0ae1d 100644 --- a/plugins/scaffolder-node-test-utils/package.json +++ b/plugins/scaffolder-node-test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-node-test-utils", - "version": "0.1.8-next.0", + "version": "0.1.9-next.1", "backstage": { "role": "node-library", "pluginId": "scaffolder", diff --git a/plugins/scaffolder-node/CHANGELOG.md b/plugins/scaffolder-node/CHANGELOG.md index f0deb319ff..f67c8c8cda 100644 --- a/plugins/scaffolder-node/CHANGELOG.md +++ b/plugins/scaffolder-node/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-scaffolder-node +## 0.4.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.13.0-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-common@1.5.3 + ## 0.4.7-next.0 ### Patch Changes diff --git a/plugins/scaffolder-node/package.json b/plugins/scaffolder-node/package.json index 2568809647..079eebfb00 100644 --- a/plugins/scaffolder-node/package.json +++ b/plugins/scaffolder-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-node", - "version": "0.4.7-next.0", + "version": "0.4.8-next.1", "description": "The plugin-scaffolder-node module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "node-library", diff --git a/plugins/scaffolder-react/CHANGELOG.md b/plugins/scaffolder-react/CHANGELOG.md index baa34dbc5b..6cbdb781f3 100644 --- a/plugins/scaffolder-react/CHANGELOG.md +++ b/plugins/scaffolder-react/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-scaffolder-react +## 1.10.0-next.1 + +### Minor Changes + +- 354e68c: Improve validation error display text in scaffolder + +### Patch Changes + +- cc81579: Updated dependency `@rjsf/utils` to `5.18.5`. + Updated dependency `@rjsf/core` to `5.18.5`. + Updated dependency `@rjsf/material-ui` to `5.18.5`. + Updated dependency `@rjsf/validator-ajv8` to `5.18.5`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.2-next.1 + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + - @backstage/plugin-permission-react@0.4.23 + - @backstage/plugin-scaffolder-common@1.5.3 + ## 1.10.0-next.0 ### Minor Changes diff --git a/plugins/scaffolder-react/package.json b/plugins/scaffolder-react/package.json index d5fe7ca9cb..6bdc263b3d 100644 --- a/plugins/scaffolder-react/package.json +++ b/plugins/scaffolder-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-react", - "version": "1.10.0-next.0", + "version": "1.10.0-next.1", "description": "A frontend library that helps other Backstage plugins interact with the Scaffolder", "backstage": { "role": "web-library", diff --git a/plugins/scaffolder/CHANGELOG.md b/plugins/scaffolder/CHANGELOG.md index 55d7271807..566411b9bd 100644 --- a/plugins/scaffolder/CHANGELOG.md +++ b/plugins/scaffolder/CHANGELOG.md @@ -1,5 +1,30 @@ # @backstage/plugin-scaffolder +## 1.22.1-next.1 + +### Patch Changes + +- cc81579: Updated dependency `@rjsf/utils` to `5.18.5`. + Updated dependency `@rjsf/core` to `5.18.5`. + Updated dependency `@rjsf/material-ui` to `5.18.5`. + Updated dependency `@rjsf/validator-ajv8` to `5.18.5`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.2-next.1 + - @backstage/plugin-scaffolder-react@1.10.0-next.1 + - @backstage/core-compat-api@0.2.7-next.0 + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/frontend-plugin-api@0.6.7-next.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/integration-react@1.1.29-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.24 + - @backstage/plugin-permission-react@0.4.23 + - @backstage/plugin-scaffolder-common@1.5.3 + ## 1.22.0-next.0 ### Minor Changes diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index 33cf7be16f..0db796359a 100644 --- a/plugins/scaffolder/package.json +++ b/plugins/scaffolder/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder", - "version": "1.22.0-next.0", + "version": "1.22.1-next.1", "description": "The Backstage plugin that helps you create new things", "backstage": { "role": "frontend-plugin", diff --git a/plugins/search-backend-module-catalog/CHANGELOG.md b/plugins/search-backend-module-catalog/CHANGELOG.md index e2d6440c94..d064814ecb 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.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-catalog-common@1.0.24 + - @backstage/plugin-catalog-node@1.12.4-next.1 + - @backstage/plugin-permission-common@0.7.14 + - @backstage/plugin-search-backend-node@1.2.27-next.1 + - @backstage/plugin-search-common@1.2.12 + ## 0.1.27-next.0 ### Patch Changes diff --git a/plugins/search-backend-module-catalog/package.json b/plugins/search-backend-module-catalog/package.json index d46e220029..0f45f3ce43 100644 --- a/plugins/search-backend-module-catalog/package.json +++ b/plugins/search-backend-module-catalog/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-backend-module-catalog", - "version": "0.1.27-next.0", + "version": "0.1.28-next.1", "description": "A module for the search backend that exports catalog modules", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/search-backend-module-elasticsearch/CHANGELOG.md b/plugins/search-backend-module-elasticsearch/CHANGELOG.md index 16cf473283..f0628d0254 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.5.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/integration-aws-node@0.1.12 + - @backstage/plugin-search-backend-node@1.2.27-next.1 + - @backstage/plugin-search-common@1.2.12 + ## 1.5.2-next.0 ### Patch Changes diff --git a/plugins/search-backend-module-elasticsearch/package.json b/plugins/search-backend-module-elasticsearch/package.json index 57414ec6e5..9cb61ee97b 100644 --- a/plugins/search-backend-module-elasticsearch/package.json +++ b/plugins/search-backend-module-elasticsearch/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-backend-module-elasticsearch", - "version": "1.5.2-next.0", + "version": "1.5.3-next.1", "description": "A module for the search backend that implements search using ElasticSearch", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/search-backend-module-explore/CHANGELOG.md b/plugins/search-backend-module-explore/CHANGELOG.md index 4b75d163f9..888be119be 100644 --- a/plugins/search-backend-module-explore/CHANGELOG.md +++ b/plugins/search-backend-module-explore/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-search-backend-module-explore +## 0.1.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/config@1.2.0 + - @backstage/plugin-search-backend-node@1.2.27-next.1 + - @backstage/plugin-search-common@1.2.12 + ## 0.1.27-next.0 ### Patch Changes diff --git a/plugins/search-backend-module-explore/package.json b/plugins/search-backend-module-explore/package.json index 13cba189e5..f37c4d55d3 100644 --- a/plugins/search-backend-module-explore/package.json +++ b/plugins/search-backend-module-explore/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-backend-module-explore", - "version": "0.1.27-next.0", + "version": "0.1.28-next.1", "description": "A module for the search backend that exports explore modules", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/search-backend-module-pg/CHANGELOG.md b/plugins/search-backend-module-pg/CHANGELOG.md index 376d266f8f..3fe18213bb 100644 --- a/plugins/search-backend-module-pg/CHANGELOG.md +++ b/plugins/search-backend-module-pg/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-search-backend-module-pg +## 0.5.32-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-app-api@0.7.10-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/plugin-search-backend-node@1.2.27-next.1 + - @backstage/plugin-search-common@1.2.12 + ## 0.5.31-next.0 ### Patch Changes diff --git a/plugins/search-backend-module-pg/package.json b/plugins/search-backend-module-pg/package.json index 3319d85dbb..ec6782535f 100644 --- a/plugins/search-backend-module-pg/package.json +++ b/plugins/search-backend-module-pg/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-backend-module-pg", - "version": "0.5.31-next.0", + "version": "0.5.32-next.1", "description": "A module for the search backend that implements search using PostgreSQL", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/search-backend-module-stack-overflow-collator/CHANGELOG.md b/plugins/search-backend-module-stack-overflow-collator/CHANGELOG.md index 91652d5543..96214102b7 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.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/config@1.2.0 + - @backstage/plugin-search-backend-node@1.2.27-next.1 + - @backstage/plugin-search-common@1.2.12 + ## 0.1.14-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 60b658a34a..dd09d75b11 100644 --- a/plugins/search-backend-module-stack-overflow-collator/package.json +++ b/plugins/search-backend-module-stack-overflow-collator/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-backend-module-stack-overflow-collator", - "version": "0.1.14-next.0", + "version": "0.1.15-next.1", "description": "A module for the search backend that exports stack overflow modules", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/search-backend-module-techdocs/CHANGELOG.md b/plugins/search-backend-module-techdocs/CHANGELOG.md index 4e7e3c4baa..706d178601 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.27-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs-node@1.12.8-next.1 + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/plugin-catalog-common@1.0.24 + - @backstage/plugin-catalog-node@1.12.4-next.1 + - @backstage/plugin-permission-common@0.7.14 + - @backstage/plugin-search-backend-node@1.2.27-next.1 + - @backstage/plugin-search-common@1.2.12 + ## 0.1.26-next.0 ### Patch Changes diff --git a/plugins/search-backend-module-techdocs/package.json b/plugins/search-backend-module-techdocs/package.json index 1650012d93..b26065cc60 100644 --- a/plugins/search-backend-module-techdocs/package.json +++ b/plugins/search-backend-module-techdocs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-backend-module-techdocs", - "version": "0.1.26-next.0", + "version": "0.1.27-next.1", "description": "A module for the search backend that exports techdocs modules", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/search-backend-node/CHANGELOG.md b/plugins/search-backend-node/CHANGELOG.md index 5209cb8753..26cd8e91eb 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.27-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/backend-tasks@0.5.27-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-permission-common@0.7.14 + - @backstage/plugin-search-common@1.2.12 + ## 1.2.26-next.0 ### Patch Changes diff --git a/plugins/search-backend-node/package.json b/plugins/search-backend-node/package.json index ef655ac566..e8cc89d117 100644 --- a/plugins/search-backend-node/package.json +++ b/plugins/search-backend-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-backend-node", - "version": "1.2.26-next.0", + "version": "1.2.27-next.1", "description": "A library for Backstage backend plugins that want to interact with the search backend plugin", "backstage": { "role": "node-library", diff --git a/plugins/search-backend/CHANGELOG.md b/plugins/search-backend/CHANGELOG.md index ea4142e583..2de90e3960 100644 --- a/plugins/search-backend/CHANGELOG.md +++ b/plugins/search-backend/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-search-backend +## 1.5.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.3.4-next.1 + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-openapi-utils@0.1.15-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.14 + - @backstage/plugin-permission-node@0.7.33-next.1 + - @backstage/plugin-search-backend-node@1.2.27-next.1 + - @backstage/plugin-search-common@1.2.12 + ## 1.5.13-next.0 ### Patch Changes diff --git a/plugins/search-backend/package.json b/plugins/search-backend/package.json index c1d536d4d4..8d266c63a8 100644 --- a/plugins/search-backend/package.json +++ b/plugins/search-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-backend", - "version": "1.5.13-next.0", + "version": "1.5.14-next.1", "description": "The Backstage backend plugin that provides your backstage app with search", "backstage": { "role": "backend-plugin", diff --git a/plugins/search/CHANGELOG.md b/plugins/search/CHANGELOG.md index effe205170..dac2074373 100644 --- a/plugins/search/CHANGELOG.md +++ b/plugins/search/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-search +## 1.4.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.2-next.1 + - @backstage/core-compat-api@0.2.7-next.0 + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/plugin-search-react@1.7.13-next.0 + - @backstage/errors@1.2.4 + - @backstage/frontend-plugin-api@0.6.7-next.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + - @backstage/plugin-search-common@1.2.12 + ## 1.4.13-next.0 ### Patch Changes diff --git a/plugins/search/package.json b/plugins/search/package.json index f25bff3e26..3b08790026 100644 --- a/plugins/search/package.json +++ b/plugins/search/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search", - "version": "1.4.13-next.0", + "version": "1.4.13-next.1", "description": "The Backstage plugin that provides your backstage app with search", "backstage": { "role": "frontend-plugin", diff --git a/plugins/signals-backend/CHANGELOG.md b/plugins/signals-backend/CHANGELOG.md index 1e9c57e1da..aaf4a0c15f 100644 --- a/plugins/signals-backend/CHANGELOG.md +++ b/plugins/signals-backend/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-signals-backend +## 0.1.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + - @backstage/plugin-events-node@0.3.8-next.1 + - @backstage/plugin-signals-node@0.1.8-next.1 + ## 0.1.7-next.0 ### Patch Changes diff --git a/plugins/signals-backend/package.json b/plugins/signals-backend/package.json index 9501878d87..0bded11c2e 100644 --- a/plugins/signals-backend/package.json +++ b/plugins/signals-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-signals-backend", - "version": "0.1.7-next.0", + "version": "0.1.8-next.1", "backstage": { "role": "backend-plugin", "pluginId": "signals", diff --git a/plugins/signals-node/CHANGELOG.md b/plugins/signals-node/CHANGELOG.md index 28db4b57fa..cbcdea7a98 100644 --- a/plugins/signals-node/CHANGELOG.md +++ b/plugins/signals-node/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-signals-node +## 0.1.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + - @backstage/plugin-events-node@0.3.8-next.1 + ## 0.1.7-next.0 ### Patch Changes diff --git a/plugins/signals-node/package.json b/plugins/signals-node/package.json index 8185c27d6b..033dcb8246 100644 --- a/plugins/signals-node/package.json +++ b/plugins/signals-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-signals-node", - "version": "0.1.7-next.0", + "version": "0.1.8-next.1", "description": "Node.js library for the signals plugin", "backstage": { "role": "node-library", diff --git a/plugins/techdocs-addons-test-utils/CHANGELOG.md b/plugins/techdocs-addons-test-utils/CHANGELOG.md index 93552868b9..0695f7e1f4 100644 --- a/plugins/techdocs-addons-test-utils/CHANGELOG.md +++ b/plugins/techdocs-addons-test-utils/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-techdocs-addons-test-utils +## 1.0.35-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.13.1-next.1 + - @backstage/plugin-catalog-react@1.12.2-next.1 + - @backstage/plugin-catalog@1.21.1-next.1 + - @backstage/plugin-techdocs@1.10.7-next.1 + - @backstage/core-plugin-api@1.9.3 + - @backstage/test-utils@1.5.8-next.1 + - @backstage/plugin-search-react@1.7.13-next.0 + - @backstage/integration-react@1.1.29-next.0 + - @backstage/plugin-techdocs-react@1.2.6-next.0 + ## 1.0.34-next.0 ### Patch Changes diff --git a/plugins/techdocs-addons-test-utils/package.json b/plugins/techdocs-addons-test-utils/package.json index a18bfea16f..fd1c806414 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.34-next.0", + "version": "1.0.35-next.1", "backstage": { "role": "web-library", "pluginId": "techdocs-addons", diff --git a/plugins/techdocs-backend/CHANGELOG.md b/plugins/techdocs-backend/CHANGELOG.md index 286ea77341..d50062c744 100644 --- a/plugins/techdocs-backend/CHANGELOG.md +++ b/plugins/techdocs-backend/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-techdocs-backend +## 1.10.9-next.1 + +### Patch Changes + +- 9ecf5fd: Adds extension point for publishers to the techdocs backend +- Updated dependencies + - @backstage/plugin-techdocs-node@1.12.8-next.1 + - @backstage/backend-common@0.23.3-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.27-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.13.0-next.0 + - @backstage/plugin-catalog-common@1.0.24 + - @backstage/plugin-permission-common@0.7.14 + ## 1.10.8-next.0 ### Patch Changes diff --git a/plugins/techdocs-backend/package.json b/plugins/techdocs-backend/package.json index 01891b83d4..1533cdc3fe 100644 --- a/plugins/techdocs-backend/package.json +++ b/plugins/techdocs-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs-backend", - "version": "1.10.8-next.0", + "version": "1.10.9-next.1", "description": "The Backstage backend plugin that renders technical documentation for your components", "backstage": { "role": "backend-plugin", diff --git a/plugins/techdocs-node/CHANGELOG.md b/plugins/techdocs-node/CHANGELOG.md index 0093f6a1eb..99240bd9d4 100644 --- a/plugins/techdocs-node/CHANGELOG.md +++ b/plugins/techdocs-node/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-techdocs-node +## 1.12.8-next.1 + +### Patch Changes + +- 9ecf5fd: Adds extension point for publishers to the techdocs backend +- 4c4d077: Bumps default version of techdocs docker image to latest +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration@1.13.0-next.0 + - @backstage/integration-aws-node@0.1.12 + - @backstage/plugin-search-common@1.2.12 + ## 1.12.7-next.0 ### Patch Changes diff --git a/plugins/techdocs-node/package.json b/plugins/techdocs-node/package.json index ae11fcb1df..70d10aeed4 100644 --- a/plugins/techdocs-node/package.json +++ b/plugins/techdocs-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs-node", - "version": "1.12.7-next.0", + "version": "1.12.8-next.1", "description": "Common node.js functionalities for TechDocs, to be shared between techdocs-backend plugin and techdocs-cli", "backstage": { "role": "node-library", diff --git a/plugins/techdocs/CHANGELOG.md b/plugins/techdocs/CHANGELOG.md index fd35205da8..a14559de1e 100644 --- a/plugins/techdocs/CHANGELOG.md +++ b/plugins/techdocs/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-techdocs +## 1.10.7-next.1 + +### Patch Changes + +- 60caa92: Fix double scrollbar bug in reader +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.2-next.1 + - @backstage/core-compat-api@0.2.7-next.0 + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/plugin-search-react@1.7.13-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/frontend-plugin-api@0.6.7-next.0 + - @backstage/integration@1.13.0-next.0 + - @backstage/integration-react@1.1.29-next.0 + - @backstage/theme@0.5.6 + - @backstage/plugin-auth-react@0.1.4-next.0 + - @backstage/plugin-search-common@1.2.12 + - @backstage/plugin-techdocs-react@1.2.6-next.0 + ## 1.10.7-next.0 ### Patch Changes diff --git a/plugins/techdocs/package.json b/plugins/techdocs/package.json index 8212246aab..2a404551be 100644 --- a/plugins/techdocs/package.json +++ b/plugins/techdocs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs", - "version": "1.10.7-next.0", + "version": "1.10.7-next.1", "description": "The Backstage plugin that renders technical documentation for your components", "backstage": { "role": "frontend-plugin", diff --git a/plugins/user-settings-backend/CHANGELOG.md b/plugins/user-settings-backend/CHANGELOG.md index cbd2ab7536..c830df43e5 100644 --- a/plugins/user-settings-backend/CHANGELOG.md +++ b/plugins/user-settings-backend/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-user-settings-backend +## 0.2.21-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3-next.1 + - @backstage/backend-plugin-api@0.6.22-next.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.17-next.1 + - @backstage/plugin-signals-node@0.1.8-next.1 + - @backstage/plugin-user-settings-common@0.0.1 + ## 0.2.20-next.0 ### Patch Changes diff --git a/plugins/user-settings-backend/package.json b/plugins/user-settings-backend/package.json index d8dc0770a5..e975b38c08 100644 --- a/plugins/user-settings-backend/package.json +++ b/plugins/user-settings-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-user-settings-backend", - "version": "0.2.20-next.0", + "version": "0.2.21-next.1", "description": "The Backstage backend plugin to manage user settings", "backstage": { "role": "backend-plugin", diff --git a/plugins/user-settings/CHANGELOG.md b/plugins/user-settings/CHANGELOG.md index 20ef229a2d..5b86011ba8 100644 --- a/plugins/user-settings/CHANGELOG.md +++ b/plugins/user-settings/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-user-settings +## 0.8.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.13.1-next.1 + - @backstage/plugin-catalog-react@1.12.2-next.1 + - @backstage/core-compat-api@0.2.7-next.0 + - @backstage/core-components@0.14.9-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/frontend-plugin-api@0.6.7-next.0 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/plugin-signals-react@0.0.4 + - @backstage/plugin-user-settings-common@0.0.1 + ## 0.8.8-next.0 ### Patch Changes diff --git a/plugins/user-settings/package.json b/plugins/user-settings/package.json index 3257de8072..a549c7cdd2 100644 --- a/plugins/user-settings/package.json +++ b/plugins/user-settings/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-user-settings", - "version": "0.8.8-next.0", + "version": "0.8.9-next.1", "description": "A Backstage plugin that provides a settings page", "backstage": { "role": "frontend-plugin", From 3b118003a93d9f4954b45386e52c05870195a5c9 Mon Sep 17 00:00:00 2001 From: aramissennyeydd Date: Tue, 2 Jul 2024 09:23:33 -0400 Subject: [PATCH 150/416] update to use taskRunner and show how to use config Signed-off-by: aramissennyeydd --- .../software-catalog/external-integrations.md | 106 ++++++++++++++---- 1 file changed, 85 insertions(+), 21 deletions(-) diff --git a/docs/features/software-catalog/external-integrations.md b/docs/features/software-catalog/external-integrations.md index c77ed51943..c269030f29 100644 --- a/docs/features/software-catalog/external-integrations.md +++ b/docs/features/software-catalog/external-integrations.md @@ -84,6 +84,7 @@ import { EntityProvider, EntityProviderConnection, } from '@backstage/plugin-catalog-node'; +import { SchedulerServiceTaskRunner } from '@backstage/backend-plugin-api'; /** * Provides entities from fictional frobs service. @@ -92,11 +93,17 @@ export class FrobsProvider implements EntityProvider { private readonly env: string; private readonly reader: UrlReader; private connection?: EntityProviderConnection; + private taskRunner: SchedulerServiceTaskRunner; /** [1] */ - constructor(env: string, reader: UrlReader) { + constructor( + env: string, + reader: UrlReader, + taskRunner: SchedulerServiceTaskRunner, + ) { this.env = env; this.reader = reader; + this.taskRunner = taskRunner; } /** [2] */ @@ -107,6 +114,12 @@ export class FrobsProvider implements EntityProvider { /** [3] */ async connect(connection: EntityProviderConnection): Promise { this.connection = connection; + this.taskRunner.run({ + id: this.getProviderName(), + fn: async () => { + await this.run(); + }, + }); } /** [4] */ @@ -248,24 +261,17 @@ export default async function createPlugin( ): Promise { const builder = CatalogBuilder.create(env); /* highlight-add-start */ - const frobs = new FrobsProvider('production', env.reader); + const taskRunner = env.scheduler.createScheduledTaskRunner({ + frequency: { minutes: 30 }, + timeout: { minutes: 10 }, + }); + const frobs = new FrobsProvider('production', env.reader, taskRunner); builder.addEntityProvider(frobs); /* highlight-add-end */ const { processingEngine, router } = await builder.build(); await processingEngine.start(); - /* highlight-add-start */ - await env.scheduler.scheduleTask({ - id: 'run_frobs_refresh', - fn: async () => { - await frobs.run(); - }, - frequency: { minutes: 30 }, - timeout: { minutes: 10 }, - }); - /* highlight-add-end */ - // .. } ``` @@ -300,19 +306,17 @@ export const catalogModuleFrobsProvider = createBackendModule({ deps: { catalog: catalogProcessingExtensionPoint, reader: coreServices.urlReader, + /* highlight-add-start */ scheduler: coreServices.scheduler, + /* highlight-add-end */ }, - async init({ catalog, reader, scheduler }) { - const frobs = new FrobsProvider('dev', reader); - catalog.addEntityProvider(frobs); - await scheduler.scheduleTask({ - id: 'run_frobs_refresh', - fn: async () => { - await frobs.run(); - }, + async init({ catalog, reader, scheduler, config }) { + const taskRunner = scheduler.createScheduledTaskRunner({ frequency: { minutes: 30 }, timeout: { minutes: 10 }, }); + const frobs = new FrobsProvider('dev', reader, taskRunner); + catalog.addEntityProvider(frobs); }, }); }, @@ -328,6 +332,66 @@ backend.add(catalogModuleFrobsProvider); backend.start(); ``` +#### Follow-up: Config Defined Schedule + +If you want to go a step further and increase the configurability of your new `FrobsProvider`, you can define the schedule that the task runs at in `app-config.yaml` instead of requiring code changes to adjust. + +```yaml +catalog: + providers: + frobs-provider: + schedule: + initialDelay: { seconds: 30 } + frequency: { hours: 1 } + timeout: { minutes: 50 } +``` + +This approach will also allow you to customize the schedule per environment + +#### New Backend + +```ts +import { + SchedulerServiceTaskScheduleDefinition, + /* highlight-add-start */ + readSchedulerServiceTaskScheduleDefinitionFromConfig, + /* highlight-add-end */ +} from '@backstage/backend-plugin-api'; + +export const catalogModuleFrobsProvider = createBackendModule({ + pluginId: 'catalog', + moduleId: 'frobs-provider', + register(env) { + env.registerInit({ + deps: { + // ... other deps + /* highlight-add-start */ + rootConfig: coreServices.rootConfig, + /* highlight-add-end */ + }, + async init({ catalog, reader, scheduler, rootConfig }) { + /* highlight-add-start */ + const config = rootConfig.getConfig('catalog.providers.frobs-provider'); // Generally, catalog config goes under catalog.providers.pluginId + // Add a default schedule if you don't define one in config. + const schedule = config.has('schedule') + ? readSchedulerServiceTaskScheduleDefinitionFromConfig( + config.getConfig('schedule'), + ) + : { + frequency: { minutes: 30 }, + timeout: { minutes: 10 }, + }; + const taskRunner: SchedulerServiceTaskRunner = + scheduler.createScheduledTaskRunner(schedule); + /* highlight-add-end */ + + // rest of your code + }, + }); + }, +}); +``` + ### Example User Entity Provider If you have a 3rd party entity provider such as an internal HR system that you wish to use you are not limited to using our entity providers, (or simply wish to add to existing entity providers with your own data). From fc221e0e57a52d52398140a5d7e4e93eb089e154 Mon Sep 17 00:00:00 2001 From: Aramis Sennyey <159921952+aramissennyeydd@users.noreply.github.com> Date: Tue, 2 Jul 2024 09:24:29 -0400 Subject: [PATCH 151/416] Update docs/features/software-catalog/external-integrations.md Signed-off-by: Aramis Sennyey <159921952+aramissennyeydd@users.noreply.github.com> --- docs/features/software-catalog/external-integrations.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/features/software-catalog/external-integrations.md b/docs/features/software-catalog/external-integrations.md index c269030f29..c9fed03e23 100644 --- a/docs/features/software-catalog/external-integrations.md +++ b/docs/features/software-catalog/external-integrations.md @@ -310,7 +310,7 @@ export const catalogModuleFrobsProvider = createBackendModule({ scheduler: coreServices.scheduler, /* highlight-add-end */ }, - async init({ catalog, reader, scheduler, config }) { + async init({ catalog, reader, scheduler }) { const taskRunner = scheduler.createScheduledTaskRunner({ frequency: { minutes: 30 }, timeout: { minutes: 10 }, From 82d14dd868f6701673f56e80a8a88dcda21945c4 Mon Sep 17 00:00:00 2001 From: aramissennyeydd Date: Tue, 2 Jul 2024 09:29:01 -0400 Subject: [PATCH 152/416] show how to do it for the old backend as well Signed-off-by: aramissennyeydd --- .../software-catalog/external-integrations.md | 36 +++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/docs/features/software-catalog/external-integrations.md b/docs/features/software-catalog/external-integrations.md index c9fed03e23..56423c9392 100644 --- a/docs/features/software-catalog/external-integrations.md +++ b/docs/features/software-catalog/external-integrations.md @@ -336,7 +336,7 @@ backend.start(); If you want to go a step further and increase the configurability of your new `FrobsProvider`, you can define the schedule that the task runs at in `app-config.yaml` instead of requiring code changes to adjust. -```yaml +```yaml title="app-config.yaml" catalog: providers: frobs-provider: @@ -350,7 +350,7 @@ This approach will also allow you to customize the schedule per environment #### New Backend -```ts +```ts title="packages/backend/src/index.ts" import { SchedulerServiceTaskScheduleDefinition, /* highlight-add-start */ @@ -392,6 +392,38 @@ export const catalogModuleFrobsProvider = createBackendModule({ }); ``` +#### Old Backend + +```ts title="packages/backend/src/plugins/catalog.ts" +/* highlight-add-next-line */ +import { FrobsProvider } from '../path/to/class'; +import { + /* highlight-add-start */ + readSchedulerServiceTaskScheduleDefinitionFromConfig, + /* highlight-add-end */ +} from '@backstage/backend-plugin-api'; + +export default async function createPlugin( + env: PluginEnvironment, +): Promise { + /* highlight-add-start */ + const config = env.config.getConfig('catalog.providers.frobs-provider'); // Generally, catalog config goes under catalog.providers.pluginId + // Add a default schedule if you don't define one in config. + const schedule = config.has('schedule') + ? readSchedulerServiceTaskScheduleDefinitionFromConfig( + config.getConfig('schedule'), + ) + : { + frequency: { minutes: 30 }, + timeout: { minutes: 10 }, + }; + const taskRunner = env.scheduler.createScheduledTaskRunner(schedule); + /* highlight-add-end */ + + // .. +} +``` + ### Example User Entity Provider If you have a 3rd party entity provider such as an internal HR system that you wish to use you are not limited to using our entity providers, (or simply wish to add to existing entity providers with your own data). From a36e90ef56069029fcdee38fd990aea6aaab12c9 Mon Sep 17 00:00:00 2001 From: Debabrata Panigrahi <50622005+Debanitrkl@users.noreply.github.com> Date: Tue, 2 Jul 2024 13:39:12 +0000 Subject: [PATCH 153/416] Signed-off-by: Debabrata Panigrahi <50622005+Debanitrkl@users.noreply.github.com> Added the harness iacm plugin info to microsite --- microsite/data/plugins/harness-iacm.yaml | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 microsite/data/plugins/harness-iacm.yaml diff --git a/microsite/data/plugins/harness-iacm.yaml b/microsite/data/plugins/harness-iacm.yaml new file mode 100644 index 0000000000..4463bab371 --- /dev/null +++ b/microsite/data/plugins/harness-iacm.yaml @@ -0,0 +1,13 @@ +--- +title: Harness Infrastructure as Code Management +author: harness.io +authorUrl: https://github.com/harness/backstage-plugins +category: Infrastructure +description: This plugin provides an overview of all the resources provisioned through information on active workspaces in your account +documentation: https://github.com/harness/backstage-plugins/tree/main/plugins/harness-iacm#harness-iacm-plugin +iconUrl: https://static.harness.io/ng-static/images/favicon.png +npmPackageName: '@harnessio/backstage-plugin-harness-iacm' +tags: + - infrastrucure-as-code + - resource-management +addedDate: '2024-07-03' From e3cb6abeec2e4a9861890cea9f9f29450b6134aa Mon Sep 17 00:00:00 2001 From: Ilias Van Peer <1038427+zwilias@users.noreply.github.com> Date: Tue, 2 Jul 2024 16:47:10 +0200 Subject: [PATCH 154/416] Add namespace label to argo rollouts in kubernetes (#25467) * Create fixture for rollouts Since rollouts have customized support, having a fixture for them can help in maintaining their rendering. Signed-off-by: ilias * Show namespace on Argo Rollout drawers Signed-off-by: ilias * Add changeset Signed-off-by: ilias * Check namespace shows up on rollouts Signed-off-by: ilias --------- Signed-off-by: ilias --- .changeset/sharp-rice-tickle.md | 5 + .../ArgoRollouts/Rollout.test.tsx | 4 + .../ArgoRollouts/RolloutDrawer.tsx | 7 + plugins/kubernetes/dev/index.tsx | 14 + .../src/__fixtures__/1-rollouts.json | 2908 +++++++++++++++++ 5 files changed, 2938 insertions(+) create mode 100644 .changeset/sharp-rice-tickle.md create mode 100644 plugins/kubernetes/src/__fixtures__/1-rollouts.json diff --git a/.changeset/sharp-rice-tickle.md b/.changeset/sharp-rice-tickle.md new file mode 100644 index 0000000000..6104e11e75 --- /dev/null +++ b/.changeset/sharp-rice-tickle.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-kubernetes-react': patch +--- + +Add a namespace label to RolloutDrawer diff --git a/plugins/kubernetes-react/src/components/CustomResources/ArgoRollouts/Rollout.test.tsx b/plugins/kubernetes-react/src/components/CustomResources/ArgoRollouts/Rollout.test.tsx index 00063afa99..a4748cdae7 100644 --- a/plugins/kubernetes-react/src/components/CustomResources/ArgoRollouts/Rollout.test.tsx +++ b/plugins/kubernetes-react/src/components/CustomResources/ArgoRollouts/Rollout.test.tsx @@ -35,6 +35,7 @@ describe('Rollout', () => { expect(screen.getByText('dice-roller')).toBeInTheDocument(); expect(screen.getByText('Rollout')).toBeInTheDocument(); + expect(screen.getByText('namespace: default')).toBeInTheDocument(); expect(screen.getByText('2 pods')).toBeInTheDocument(); expect(screen.getByText('No pods with errors')).toBeInTheDocument(); expect(screen.queryByText('Paused')).toBeNull(); @@ -52,6 +53,7 @@ describe('Rollout', () => { expect(screen.getByText('dice-roller')).toBeInTheDocument(); expect(screen.getByText('Rollout')).toBeInTheDocument(); + expect(screen.getByText('namespace: default')).toBeInTheDocument(); expect(screen.getByText('2 pods')).toBeInTheDocument(); expect(screen.getByText('1 pod with errors')).toBeInTheDocument(); expect(screen.queryByText('Paused')).toBeNull(); @@ -71,6 +73,7 @@ describe('Rollout', () => { expect(screen.getByText('dice-roller')).toBeInTheDocument(); expect(screen.getByText('Rollout')).toBeInTheDocument(); + expect(screen.getByText('namespace: default')).toBeInTheDocument(); expect(screen.getByText('2 pods')).toBeInTheDocument(); expect(screen.getByText('No pods with errors')).toBeInTheDocument(); expect(screen.getByText('Paused (45 minutes ago)')).toBeInTheDocument(); @@ -90,6 +93,7 @@ describe('Rollout', () => { expect(screen.getByText('dice-roller')).toBeInTheDocument(); expect(screen.getByText('Rollout')).toBeInTheDocument(); + expect(screen.getByText('namespace: default')).toBeInTheDocument(); expect(screen.getByText('2 pods')).toBeInTheDocument(); expect(screen.getByText('No pods with errors')).toBeInTheDocument(); expect(screen.queryByText('Paused')).toBeNull(); diff --git a/plugins/kubernetes-react/src/components/CustomResources/ArgoRollouts/RolloutDrawer.tsx b/plugins/kubernetes-react/src/components/CustomResources/ArgoRollouts/RolloutDrawer.tsx index 304c8bdf78..65d4840bf0 100644 --- a/plugins/kubernetes-react/src/components/CustomResources/ArgoRollouts/RolloutDrawer.tsx +++ b/plugins/kubernetes-react/src/components/CustomResources/ArgoRollouts/RolloutDrawer.tsx @@ -18,6 +18,7 @@ import React from 'react'; import { KubernetesStructuredMetadataTableDrawer } from '../../KubernetesDrawer'; import Typography from '@material-ui/core/Typography'; import Grid from '@material-ui/core/Grid'; +import Chip from '@material-ui/core/Chip'; export const RolloutDrawer = ({ rollout, @@ -26,6 +27,7 @@ export const RolloutDrawer = ({ rollout: any; expanded?: boolean; }) => { + const namespace = rollout.metadata?.namespace; return ( + {namespace && ( + + + + )} ); diff --git a/plugins/kubernetes/dev/index.tsx b/plugins/kubernetes/dev/index.tsx index fbc666ae13..2de5a17f25 100644 --- a/plugins/kubernetes/dev/index.tsx +++ b/plugins/kubernetes/dev/index.tsx @@ -33,6 +33,7 @@ import fixture1 from '../src/__fixtures__/1-deployments.json'; import fixture2 from '../src/__fixtures__/2-deployments.json'; import fixture3 from '../src/__fixtures__/1-cronjobs.json'; import fixture4 from '../src/__fixtures__/2-cronjobs.json'; +import fixture5 from '../src/__fixtures__/1-rollouts.json'; import { TestApiProvider } from '@backstage/test-utils'; const mockEntity: Entity = { @@ -186,5 +187,18 @@ createDevApp()
    ), }) + .addPage({ + path: '/fixture-5', + title: 'Fixture 5', + element: ( + + + + + + ), + }) .registerPlugin(kubernetesPlugin) .render(); diff --git a/plugins/kubernetes/src/__fixtures__/1-rollouts.json b/plugins/kubernetes/src/__fixtures__/1-rollouts.json new file mode 100644 index 0000000000..66929b9129 --- /dev/null +++ b/plugins/kubernetes/src/__fixtures__/1-rollouts.json @@ -0,0 +1,2908 @@ +{ + "pods": [ + { + "metadata": { + "creationTimestamp": "2020-09-25T09:58:50.000Z", + "generateName": "dice-roller-6c8646bfd-", + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"5126c354-4310-4e23-a9e4-c9b87cb69792\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:58:50.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.11\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-25T09:58:55.000Z" + } + ], + "name": "dice-roller-6c8646bfd-2m5hv", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + } + ], + "resourceVersion": "593216", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-6c8646bfd-2m5hv", + "uid": "aadb71c0-36fa-43e3-b38a-162f134d4359" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "status": "True", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "status": "True", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://aa4489297c34c48bb33c18474a8d2b33854a82ed42155680b259f635f556ce70", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-25T09:58:53.000Z" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.11", + "podIPs": [ + { + "ip": "172.17.0.11" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-25T09:58:50.000Z" + } + }, + { + "metadata": { + "creationTimestamp": "2020-09-25T09:58:50.000Z", + "generateName": "dice-roller-6c8646bfd-", + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"5126c354-4310-4e23-a9e4-c9b87cb69792\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:58:50.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.7\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-25T09:58:55.000Z" + } + ], + "name": "dice-roller-6c8646bfd-4v6s8", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + } + ], + "resourceVersion": "593221", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-6c8646bfd-4v6s8", + "uid": "32e56490-6f20-4757-991f-a0c7fb407358" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "status": "True", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "status": "True", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://d91cc76c41249b8d3dfcf538d180b471b2a7966aae0d17a818307c8a9b4af897", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-25T09:58:53.000Z" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.7", + "podIPs": [ + { + "ip": "172.17.0.7" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-25T09:58:50.000Z" + } + }, + { + "metadata": { + "creationTimestamp": "2020-09-24T11:39:26.000Z", + "generateName": "dice-roller-6c8646bfd-", + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"5126c354-4310-4e23-a9e4-c9b87cb69792\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-24T11:39:26.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.6\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-24T11:39:27.000Z" + } + ], + "name": "dice-roller-6c8646bfd-b9zt5", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + } + ], + "resourceVersion": "503886", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-6c8646bfd-b9zt5", + "uid": "8b6601b6-469e-4e89-8fd0-abb2f1a567e4" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-24T11:39:26.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-24T11:39:27.000Z", + "status": "True", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-24T11:39:27.000Z", + "status": "True", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-24T11:39:26.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://c50e0d0fa96f09a2ed5df7dd5a7f7de88e6b7c7addb8f002f299d6afc52d82ce", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-24T11:39:27.000Z" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.6", + "podIPs": [ + { + "ip": "172.17.0.6" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-24T11:39:26.000Z" + } + }, + { + "metadata": { + "creationTimestamp": "2020-09-25T09:58:50.000Z", + "generateName": "dice-roller-6c8646bfd-", + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"5126c354-4310-4e23-a9e4-c9b87cb69792\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:58:50.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.13\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-25T09:58:55.000Z" + } + ], + "name": "dice-roller-6c8646bfd-cfxqc", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + } + ], + "resourceVersion": "593211", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-6c8646bfd-cfxqc", + "uid": "e87e1776-0ca7-41fb-aeea-e1f648387545" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:51.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "status": "True", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "status": "True", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://c1641d986aae424429b7c2c1117baeb17d3794f73206bd57292cdf8264f929b2", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-25T09:58:53.000Z" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.13", + "podIPs": [ + { + "ip": "172.17.0.13" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-25T09:58:51.000Z" + } + }, + { + "metadata": { + "creationTimestamp": "2020-09-25T09:58:50.000Z", + "generateName": "dice-roller-6c8646bfd-", + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"5126c354-4310-4e23-a9e4-c9b87cb69792\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:58:50.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.15\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-25T09:58:54.000Z" + } + ], + "name": "dice-roller-6c8646bfd-dtv5z", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + } + ], + "resourceVersion": "593190", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-6c8646bfd-dtv5z", + "uid": "1638a41b-e47e-4c17-a1f7-7b447df248b6" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:51.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:53.000Z", + "status": "True", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:53.000Z", + "status": "True", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://e62c32db58dbfe0a74b2d2cba0e0a97b7f222693c68e930037ac8738c4758ca3", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-25T09:58:53.000Z" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.15", + "podIPs": [ + { + "ip": "172.17.0.15" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-25T09:58:51.000Z" + } + }, + { + "metadata": { + "creationTimestamp": "2020-09-25T09:58:50.000Z", + "generateName": "dice-roller-6c8646bfd-", + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"5126c354-4310-4e23-a9e4-c9b87cb69792\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:58:50.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.12\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-25T09:58:53.000Z" + } + ], + "name": "dice-roller-6c8646bfd-hhts2", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + } + ], + "resourceVersion": "593186", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-6c8646bfd-hhts2", + "uid": "ea0b147a-c56a-46e6-9445-7a0b1b0ed3c0" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:53.000Z", + "status": "True", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:53.000Z", + "status": "True", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://bcdbc153630f90556d57ff0d62f04d847ca63a5f0a7e5d9230683623d33d4b8d", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-25T09:58:53.000Z" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.12", + "podIPs": [ + { + "ip": "172.17.0.12" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-25T09:58:50.000Z" + } + }, + { + "metadata": { + "creationTimestamp": "2020-09-25T09:58:50.000Z", + "generateName": "dice-roller-6c8646bfd-", + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"5126c354-4310-4e23-a9e4-c9b87cb69792\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:58:50.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.14\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-25T09:58:55.000Z" + } + ], + "name": "dice-roller-6c8646bfd-j68lm", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + } + ], + "resourceVersion": "593226", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-6c8646bfd-j68lm", + "uid": "b230ff1d-7a13-479b-9c7b-77c26bd79f62" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "status": "True", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "status": "True", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://30fa8a3429f86ab8e9a4cec472b79d74266609082703f48950f4aae021e9d6a2", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-25T09:58:53.000Z" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.14", + "podIPs": [ + { + "ip": "172.17.0.14" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-25T09:58:50.000Z" + } + }, + { + "metadata": { + "creationTimestamp": "2020-09-25T09:58:50.000Z", + "generateName": "dice-roller-6c8646bfd-", + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"5126c354-4310-4e23-a9e4-c9b87cb69792\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:58:50.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.9\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-25T09:58:53.000Z" + } + ], + "name": "dice-roller-6c8646bfd-m6f9w", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + } + ], + "resourceVersion": "593181", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-6c8646bfd-m6f9w", + "uid": "9b0079f6-ff29-4619-bf6e-71cc10199ac5" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:53.000Z", + "status": "True", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:53.000Z", + "status": "True", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://f78767ee90eedffe46ff64bfe76d7f69426800dd89f3df012daf0baf3a9c5bdd", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-25T09:58:53.000Z" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.9", + "podIPs": [ + { + "ip": "172.17.0.9" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-25T09:58:50.000Z" + } + }, + { + "metadata": { + "creationTimestamp": "2020-09-24T11:39:27.000Z", + "generateName": "dice-roller-6c8646bfd-", + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"5126c354-4310-4e23-a9e4-c9b87cb69792\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-24T11:39:27.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.4\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-24T11:39:28.000Z" + } + ], + "name": "dice-roller-6c8646bfd-nv9pk", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + } + ], + "resourceVersion": "503918", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-6c8646bfd-nv9pk", + "uid": "acf7f77f-78c6-4d4b-bc73-637211770ffc" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-24T11:39:27.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-24T11:39:28.000Z", + "status": "True", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-24T11:39:28.000Z", + "status": "True", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-24T11:39:27.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://63dec9b32942c4b09ae43d09d6978261f674a3ee623823b8f1d20da8044c12ac", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-24T11:39:28.000Z" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.4", + "podIPs": [ + { + "ip": "172.17.0.4" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-24T11:39:27.000Z" + } + }, + { + "metadata": { + "creationTimestamp": "2020-09-25T09:58:50.000Z", + "generateName": "dice-roller-6c8646bfd-", + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"5126c354-4310-4e23-a9e4-c9b87cb69792\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:58:50.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.10\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-25T09:58:55.000Z" + } + ], + "name": "dice-roller-6c8646bfd-pjhfj", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + } + ], + "resourceVersion": "593205", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-6c8646bfd-pjhfj", + "uid": "78775c3a-7af2-4ebe-a676-bc2e5dfa2bcc" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "status": "True", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "status": "True", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://cbb83dda250db74285dcbe0b81bd0896acf402bac9710af090311f7360f824aa", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-25T09:58:53.000Z" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.10", + "podIPs": [ + { + "ip": "172.17.0.10" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-25T09:58:50.000Z" + } + } + ], + "replicaSets": [ + { + "metadata": { + "annotations": { + "deployment.kubernetes.io/desired-replicas": "10", + "deployment.kubernetes.io/max-replicas": "13", + "deployment.kubernetes.io/revision": "2" + }, + "creationTimestamp": "2020-09-24T11:39:26.000Z", + "generation": 3, + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "apps/v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:annotations": { + ".": {}, + "f:deployment.kubernetes.io/desired-replicas": {}, + "f:deployment.kubernetes.io/max-replicas": {}, + "f:deployment.kubernetes.io/revision": {} + }, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"7551e949-42d1-4061-83c5-9da107186e47\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:replicas": {}, + "f:selector": { + "f:matchLabels": { + ".": {}, + "f:app": {}, + "f:pod-template-hash": {} + } + }, + "f:template": { + "f:metadata": { + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + } + }, + "f:status": { + "f:availableReplicas": {}, + "f:fullyLabeledReplicas": {}, + "f:observedGeneration": {}, + "f:readyReplicas": {}, + "f:replicas": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:58:55.000Z" + } + ], + "name": "dice-roller-6c8646bfd", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "Deployment", + "name": "dice-roller", + "uid": "7551e949-42d1-4061-83c5-9da107186e47" + } + ], + "resourceVersion": "593228", + "selfLink": "/apis/apps/v1/namespaces/default/replicasets/dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + }, + "spec": { + "replicas": 10, + "selector": { + "matchLabels": { + "app": "dice-roller", + "pod-template-hash": "6c8646bfd" + } + }, + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + } + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File" + } + ], + "dnsPolicy": "ClusterFirst", + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "terminationGracePeriodSeconds": 30 + } + } + }, + "status": { + "availableReplicas": 10, + "fullyLabeledReplicas": 10, + "observedGeneration": 3, + "readyReplicas": 10, + "replicas": 10 + } + } + ], + "customResources": [ + { + "apiVersion": "argoproj.io/v1alpha1", + "kind": "Rollout", + "metadata": { + "annotations": { + "deployment.kubernetes.io/revision": "2", + "kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"apps/v1\",\"kind\":\"Deployment\",\"metadata\":{\"annotations\":{},\"labels\":{\"backstage.io/kubernetes-id\":\"dice-roller\"},\"name\":\"dice-roller\",\"namespace\":\"default\"},\"spec\":{\"replicas\":10,\"selector\":{\"matchLabels\":{\"app\":\"dice-roller\"}},\"template\":{\"metadata\":{\"labels\":{\"app\":\"dice-roller\",\"backstage.io/kubernetes-id\":\"dice-roller\"}},\"spec\":{\"containers\":[{\"image\":\"nginx:1.14.2\",\"name\":\"nginx\",\"ports\":[{\"containerPort\":80}]}]}}}}\n" + }, + "creationTimestamp": "2020-09-23T12:00:55.000Z", + "generation": 3, + "labels": { + "backstage.io/kubernetes-id": "dice-roller" + }, + "managedFields": [ + { + "apiVersion": "apps/v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:annotations": { + ".": {}, + "f:kubectl.kubernetes.io/last-applied-configuration": {} + }, + "f:labels": { + ".": {}, + "f:backstage.io/kubernetes-id": {} + } + }, + "f:spec": { + "f:progressDeadlineSeconds": {}, + "f:replicas": {}, + "f:revisionHistoryLimit": {}, + "f:selector": { + "f:matchLabels": { + ".": {}, + "f:app": {} + } + }, + "f:strategy": { + "f:rollingUpdate": { + ".": {}, + "f:maxSurge": {}, + "f:maxUnavailable": {} + }, + "f:type": {} + }, + "f:template": { + "f:metadata": { + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {} + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + } + } + }, + "manager": "kubectl", + "operation": "Update", + "time": "2020-09-25T09:58:50.000Z" + }, + { + "apiVersion": "apps/v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:annotations": { + "f:deployment.kubernetes.io/revision": {} + } + }, + "f:status": { + "f:availableReplicas": {}, + "f:conditions": { + ".": {}, + "k:{\"type\":\"Available\"}": { + ".": {}, + "f:lastTransitionTime": {}, + "f:lastUpdateTime": {}, + "f:message": {}, + "f:reason": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Progressing\"}": { + ".": {}, + "f:lastTransitionTime": {}, + "f:lastUpdateTime": {}, + "f:message": {}, + "f:reason": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:observedGeneration": {}, + "f:readyReplicas": {}, + "f:replicas": {}, + "f:updatedReplicas": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:58:55.000Z" + } + ], + "name": "dice-roller", + "namespace": "default", + "resourceVersion": "593230", + "selfLink": "/apis/apps/v1/namespaces/default/deployments/dice-roller", + "uid": "7551e949-42d1-4061-83c5-9da107186e47" + }, + "spec": { + "progressDeadlineSeconds": 600, + "replicas": 10, + "revisionHistoryLimit": 10, + "selector": { + "matchLabels": { + "app": "dice-roller" + } + }, + "strategy": { + "rollingUpdate": { + "maxSurge": "25%", + "maxUnavailable": "25%" + }, + "type": "RollingUpdate" + }, + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller" + } + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File" + } + ], + "dnsPolicy": "ClusterFirst", + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "terminationGracePeriodSeconds": 30 + } + } + }, + "status": { + "availableReplicas": 10, + "conditions": [ + { + "lastTransitionTime": "2020-09-23T12:00:55.000Z", + "lastUpdateTime": "2020-09-24T11:39:28.000Z", + "message": "ReplicaSet \"dice-roller-6c8646bfd\" has successfully progressed.", + "reason": "NewReplicaSetAvailable", + "status": "True", + "type": "Progressing" + }, + { + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "lastUpdateTime": "2020-09-25T09:58:55.000Z", + "message": "Deployment has minimum availability.", + "reason": "MinimumReplicasAvailable", + "status": "True", + "type": "Available" + } + ], + "observedGeneration": 3, + "readyReplicas": 10, + "replicas": 10, + "updatedReplicas": 10 + } + } + ], + "horizontalPodAutoscalers": [ + { + "apiVersion": "autoscaling/v2", + "kind": "HorizontalPodAutoscaler", + "metadata": { + "annotations": {}, + "creationTimestamp": "2024-02-13T20:13:52Z", + "labels": { + "backstage.io/kubernetes-id": "dice-roller" + }, + "name": "dice-roller", + "namespace": "default", + "resourceVersion": "6717s736", + "uid": "a34c90e1-8e8f-407f-b4c5-b4543bd56c1b" + }, + "spec": { + "maxReplicas": 2, + "metrics": [ + { + "resource": { + "name": "cpu", + "target": { + "averageUtilization": 50, + "type": "Utilization" + } + }, + "type": "Resource" + } + ], + "minReplicas": 1, + "scaleTargetRef": { + "apiVersion": "apps/v1", + "kind": "Deployment", + "name": "dice-roller" + } + }, + "status": { + "conditions": [ + { + "lastTransitionTime": "2024-05-17T19:50:35Z", + "message": "recent recommendations were higher than current one, applying the highest recent recommendation", + "reason": "ScaleDownStabilized", + "status": "True", + "type": "AbleToScale" + }, + { + "lastTransitionTime": "2024-05-16T06:21:01Z", + "message": "the HPA was able to successfully calculate a replica count from cpu resource utilization (percentage of request)", + "reason": "ValidMetricFound", + "status": "True", + "type": "ScalingActive" + }, + { + "lastTransitionTime": "2024-05-16T06:21:01Z", + "message": "the desired replica count is more than the maximum replica count", + "reason": "TooManyReplicas", + "status": "True", + "type": "ScalingLimited" + } + ], + "currentMetrics": [ + { + "resource": { + "current": { + "averageUtilization": 100, + "averageValue": "50m", + "value": "100m" + }, + "name": "cpu" + }, + "type": "Resource" + } + ], + "currentReplicas": 2, + "desiredReplicas": 2, + "lastScaleTime": "2024-02-13T20:14:23Z" + } + } + ] +} From 9182cb074f2933291ef72443b43c5d386db1093d Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Tue, 2 Jul 2024 19:19:56 +0200 Subject: [PATCH 155/416] Feedback Signed-off-by: bnechyporenko --- docs/features/software-templates/writing-custom-actions.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/features/software-templates/writing-custom-actions.md b/docs/features/software-templates/writing-custom-actions.md index 41bd7d2026..3b5843e795 100644 --- a/docs/features/software-templates/writing-custom-actions.md +++ b/docs/features/software-templates/writing-custom-actions.md @@ -146,7 +146,7 @@ argument. It looks like the following: - `ctx.baseUrl` - a string where the template is located - `ctx.checkpoint` - _Experimental_ allows to implement idempotency of the actions by not re-running the same function again if it was - executed successfully on the previous run. + executed successfully on the previous run. More information [here](https://github.com/backstage/backstage/tree/master/beps/0004-scaffolder-task-idempotency#checkpoints) - `ctx.logger` - a Winston logger for additional logging inside your action - `ctx.logStream` - a stream version of the logger if needed - `ctx.workspacePath` - a string of the working directory of the template run @@ -225,7 +225,7 @@ Idempotent action could be achieved via the usage of checkpoints. Example: -```ts +```ts title="plugins/my-company-scaffolder-actions-plugin/src/vendor/my-custom-action.ts" const res = await ctx.checkpoint?.('create.projects', async () => { const projectStgId = createStagingProjectId(); const projectProId = createProductionProjectId(); From 920d0f9c96c0e92275f5566a6a9e495b03aa1f12 Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Tue, 2 Jul 2024 19:20:54 +0200 Subject: [PATCH 156/416] Feedback Signed-off-by: bnechyporenko --- docs/features/software-templates/writing-custom-actions.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/features/software-templates/writing-custom-actions.md b/docs/features/software-templates/writing-custom-actions.md index 3b5843e795..6c1ea573db 100644 --- a/docs/features/software-templates/writing-custom-actions.md +++ b/docs/features/software-templates/writing-custom-actions.md @@ -145,8 +145,10 @@ When the action `handler` is called, we provide you a `context` as the only argument. It looks like the following: - `ctx.baseUrl` - a string where the template is located -- `ctx.checkpoint` - _Experimental_ allows to implement idempotency of the actions by not re-running the same function again if it was - executed successfully on the previous run. More information [here](https://github.com/backstage/backstage/tree/master/beps/0004-scaffolder-task-idempotency#checkpoints) +- `ctx.checkpoint` - _Experimental_ allows to + implement [idempotency of the actions](https://github.com/backstage/backstage/tree/master/beps/0004-scaffolder-task-idempotency) + by not re-running the same function again if it was + executed successfully on the previous run. - `ctx.logger` - a Winston logger for additional logging inside your action - `ctx.logStream` - a stream version of the logger if needed - `ctx.workspacePath` - a string of the working directory of the template run From 44ecd6d5eebb51613deb6e921234b097452a52c9 Mon Sep 17 00:00:00 2001 From: aramissennyeydd Date: Tue, 2 Jul 2024 18:47:10 -0400 Subject: [PATCH 157/416] docs: add a link to config definition Signed-off-by: aramissennyeydd --- docs/features/software-catalog/external-integrations.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/features/software-catalog/external-integrations.md b/docs/features/software-catalog/external-integrations.md index 56423c9392..98fae5a95e 100644 --- a/docs/features/software-catalog/external-integrations.md +++ b/docs/features/software-catalog/external-integrations.md @@ -346,7 +346,7 @@ catalog: timeout: { minutes: 50 } ``` -This approach will also allow you to customize the schedule per environment +This approach will also allow you to customize the schedule per environment. You can also [add a schema to your config](../../conf/defining.md). #### New Backend From 72143aa7d65a743ec521536a64b1b1164c254136 Mon Sep 17 00:00:00 2001 From: Tavi Nolan Date: Wed, 3 Jul 2024 11:03:11 +0100 Subject: [PATCH 158/416] Changing to original link Signed-off-by: Tavi Nolan --- docs/features/software-catalog/configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/features/software-catalog/configuration.md b/docs/features/software-catalog/configuration.md index 9524886a49..3c875d90c4 100644 --- a/docs/features/software-catalog/configuration.md +++ b/docs/features/software-catalog/configuration.md @@ -47,7 +47,7 @@ action is logged for further investigation. ### Local File (`type: file`) Configurations In addition to url locations, you can use the `file` location type to bring in content from the local file system. You should only use this for local development, test setups, and example data, not for production data. -You are also not able to use placeholders in them like `$text`, `$json` or `$yaml`. You can however reference other files relative to the current file. See the full [catalog example data set here](https://github.com/backstage/backstage/blob/master/packages/create-app/templates/default-app/app-config.yaml.hbs) for an extensive example. +You are also not able to use placeholders in them like `$text`, `$json` or `$yaml`. You can however reference other files relative to the current file. See the full [catalog example data set here](https://github.com/backstage/backstage/tree/master/packages/catalog-model/examples) for an extensive example. Here is an example pulling in the `all.yaml` file from the examples folder. Note the use of `../../` to go up two levels from the current execution path of the backend. This is typically `packages/backend/`. From 25ff80427472fb11658a992bdad4cfa69a0f515e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Edstr=C3=B6m?= Date: Wed, 3 Jul 2024 12:20:45 +0200 Subject: [PATCH 159/416] Modified propname to be data-test and added unit test for custom data-testid MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Simon Edström --- .../core-components/src/components/Select/Select.test.tsx | 8 ++++++++ packages/core-components/src/components/Select/Select.tsx | 6 +++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/core-components/src/components/Select/Select.test.tsx b/packages/core-components/src/components/Select/Select.test.tsx index 71159150e4..3c05c6bcaf 100644 --- a/packages/core-components/src/components/Select/Select.test.tsx +++ b/packages/core-components/src/components/Select/Select.test.tsx @@ -66,4 +66,12 @@ describe(', + ); + const input = getByTestId('custom-select'); + expect(input.textContent).toBe('All results'); + }); }); diff --git a/packages/core-components/src/components/Select/Select.tsx b/packages/core-components/src/components/Select/Select.tsx index 9c0d4e4dfe..b78693213f 100644 --- a/packages/core-components/src/components/Select/Select.tsx +++ b/packages/core-components/src/components/Select/Select.tsx @@ -136,7 +136,7 @@ export type SelectProps = { native?: boolean; disabled?: boolean; margin?: 'dense' | 'none'; - testid?: string; + 'data-testid'?: string; }; /** @public */ @@ -152,7 +152,7 @@ export function SelectComponent(props: SelectProps) { native = false, disabled = false, margin, - testid = 'select', + 'data-testid': dataTestId = 'select', } = props; const classes = useStyles(); const [value, setValue] = useState( @@ -205,7 +205,7 @@ export function SelectComponent(props: SelectProps) { value={value} native={native} disabled={disabled} - data-testid={testid} + data-testid={dataTestId} displayEmpty multiple={multiple} margin={margin} From f0426dc9f5e50faf40d24b076506fbf47e9032fd Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Wed, 3 Jul 2024 14:04:11 +0200 Subject: [PATCH 160/416] Update .changeset/new-sheep-arrive.md Signed-off-by: Camila Belo --- .changeset/new-sheep-arrive.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/new-sheep-arrive.md b/.changeset/new-sheep-arrive.md index 9ae0af93aa..00e759a187 100644 --- a/.changeset/new-sheep-arrive.md +++ b/.changeset/new-sheep-arrive.md @@ -2,4 +2,4 @@ '@backstage/core-components': patch --- -Modified the Select component to take in a testid parameter that sets the data-testid of the material ui Select sub-component, ensuring backwards compatibility with default value corresponding to previously hardcoded data-testid of "select". +Modified the `Select` component to take in a `data-testid` parameter ensuring backwards compatibility with default value corresponding to previously hardcoded `data-testid` of "select". From ece2dae403e80c3d01a326cb6fe3da8eb8f84d2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Edstr=C3=B6m?= Date: Wed, 3 Jul 2024 14:25:21 +0200 Subject: [PATCH 161/416] Fixed RepoUrlPickerHost having incorrect testid in test, data-testid was specified (but did nothing) and the test expected the hardcoded 'select' testid MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Simon Edström --- .../fields/RepoUrlPicker/RepoUrlPickerHost.test.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPickerHost.test.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPickerHost.test.tsx index 0c7ca75990..a070e0c6e4 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPickerHost.test.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPickerHost.test.tsx @@ -64,7 +64,7 @@ describe('RepoUrlPickerHostField', () => { , ); - fireEvent.mouseDown(getByTestId('select')); + fireEvent.mouseDown(getByTestId('host-select')); expect(getByText('gitlab.com')).toBeInTheDocument(); const listbox = within(getByRole('combobox')); @@ -93,7 +93,7 @@ describe('RepoUrlPickerHostField', () => { , ); - fireEvent.mouseDown(getByTestId('select')); + fireEvent.mouseDown(getByTestId('host-select')); expect(getByText('gitlab.com')).toBeInTheDocument(); const listbox = within(getByRole('combobox')); From fad1b903a8e166492837c003916adb1f59be788e Mon Sep 17 00:00:00 2001 From: ElaineDeMattosSilvaB Date: Wed, 3 Jul 2024 19:47:37 +0200 Subject: [PATCH 162/416] feat: allow the oauth token to be used in the gitlab:projectVariableAction:create action Signed-off-by: ElaineDeMattosSilvaB --- .changeset/grumpy-owls-suffer.md | 5 ++ ...tlabProjectVariableCreate.examples.test.ts | 61 ++++++++++--------- .../actions/gitlabProjectVariableCreate.ts | 27 ++++---- 3 files changed, 49 insertions(+), 44 deletions(-) create mode 100644 .changeset/grumpy-owls-suffer.md diff --git a/.changeset/grumpy-owls-suffer.md b/.changeset/grumpy-owls-suffer.md new file mode 100644 index 0000000000..977055eb33 --- /dev/null +++ b/.changeset/grumpy-owls-suffer.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend-module-gitlab': patch +--- + +Allow the `createGitlabProjectVariableAction` to use oauth tokens diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectVariableCreate.examples.test.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectVariableCreate.examples.test.ts index 1eeb01ca91..99b26682d8 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectVariableCreate.examples.test.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectVariableCreate.examples.test.ts @@ -26,7 +26,7 @@ const mockGitlabClient = { create: jest.fn(), }, }; -jest.mock('@gitbeaker/node', () => ({ +jest.mock('@gitbeaker/rest', () => ({ Gitlab: class { constructor() { return mockGitlabClient; @@ -41,7 +41,7 @@ describe('gitlab:projectVariableAction: create examples', () => { { host: 'gitlab.com', token: 'tokenlols', - apiBaseUrl: 'https://api.gitlab.com', + apiBaseUrl: 'https://api.gitlab.com/api/v4', }, { host: 'hosted.gitlab.com', @@ -79,17 +79,18 @@ describe('gitlab:projectVariableAction: create examples', () => { expect(mockGitlabClient.ProjectVariables.create).toHaveBeenCalledWith( '123', + 'MY_VARIABLE', + 'my_value', { - key: 'MY_VARIABLE', - value: 'my_value', - variable_type: 'env_var', - environment_scope: '*', + variableType: 'env_var', // Correctly using variableType + environmentScope: '*', masked: false, protected: false, raw: false, }, ); }); + it(`Should ${examples[1].description}`, async () => { mockGitlabClient.ProjectVariables.create.mockResolvedValue({ token: 'TOKEN', @@ -102,14 +103,14 @@ describe('gitlab:projectVariableAction: create examples', () => { expect(mockGitlabClient.ProjectVariables.create).toHaveBeenCalledWith( '123', + 'MY_VARIABLE', + 'my-file-content', { - key: 'MY_VARIABLE', - value: 'my-file-content', + variableType: 'file', // Correctly using variableType protected: false, masked: false, raw: false, - environment_scope: '*', - variable_type: 'file', + environmentScope: '*', }, ); }); @@ -126,13 +127,13 @@ describe('gitlab:projectVariableAction: create examples', () => { expect(mockGitlabClient.ProjectVariables.create).toHaveBeenCalledWith( '456', + 'MY_VARIABLE', + 'my_value', { - key: 'MY_VARIABLE', - value: 'my_value', masked: false, raw: false, - environment_scope: '*', - variable_type: 'env_var', + environmentScope: '*', + variableType: 'env_var', // Correctly using variableType protected: true, }, ); @@ -150,13 +151,13 @@ describe('gitlab:projectVariableAction: create examples', () => { expect(mockGitlabClient.ProjectVariables.create).toHaveBeenCalledWith( '789', + 'DB_PASSWORD', + 'password123', { - key: 'DB_PASSWORD', - value: 'password123', protected: false, raw: false, - environment_scope: '*', - variable_type: 'env_var', + environmentScope: '*', + variableType: 'env_var', // Correctly using variableType masked: true, }, ); @@ -174,12 +175,12 @@ describe('gitlab:projectVariableAction: create examples', () => { expect(mockGitlabClient.ProjectVariables.create).toHaveBeenCalledWith( '123', + 'MY_VARIABLE', + 'my_value', { - key: 'MY_VARIABLE', - value: 'my_value', protected: false, - environment_scope: '*', - variable_type: 'env_var', + environmentScope: '*', + variableType: 'env_var', // Correctly using variableType masked: false, raw: true, }, @@ -198,14 +199,14 @@ describe('gitlab:projectVariableAction: create examples', () => { expect(mockGitlabClient.ProjectVariables.create).toHaveBeenCalledWith( '123', + 'MY_VARIABLE', + 'my_value', { - key: 'MY_VARIABLE', - value: 'my_value', protected: false, - variable_type: 'env_var', + variableType: 'env_var', // Correctly using variableType masked: false, raw: false, - environment_scope: 'production', + environmentScope: 'production', }, ); }); @@ -222,14 +223,14 @@ describe('gitlab:projectVariableAction: create examples', () => { expect(mockGitlabClient.ProjectVariables.create).toHaveBeenCalledWith( '123', + 'MY_VARIABLE', + 'my_value', { - key: 'MY_VARIABLE', - value: 'my_value', protected: false, - variable_type: 'env_var', + variableType: 'env_var', // Correctly using variableType masked: false, raw: false, - environment_scope: '*', + environmentScope: '*', }, ); }); diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectVariableCreate.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectVariableCreate.ts index a07ec747fa..3a9eeec0a1 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectVariableCreate.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectVariableCreate.ts @@ -16,10 +16,10 @@ import { ScmIntegrationRegistry } from '@backstage/integration'; import { createTemplateAction } from '@backstage/plugin-scaffolder-node'; -import { Gitlab } from '@gitbeaker/node'; +import { VariableType } from '@gitbeaker/rest'; import { z } from 'zod'; import commonGitlabConfig from '../commonGitlabConfig'; -import { getToken } from '../util'; +import { getClient, parseRepoUrl } from '../util'; import { examples } from './gitlabProjectVariableCreate.examples'; /** @@ -72,6 +72,7 @@ export const createGitlabProjectVariableAction = (options: { }, async handler(ctx) { const { + repoUrl, projectId, key, value, @@ -80,21 +81,19 @@ export const createGitlabProjectVariableAction = (options: { masked = false, raw = false, environmentScope = '*', + token, } = ctx.input; - const { token, integrationConfig } = getToken(ctx.input, integrations); - const api = new Gitlab({ - host: integrationConfig.config.baseUrl, - token: token, - }); - await api.ProjectVariables.create(projectId, { - key: key, - value: value, - variable_type: variableType, + const { host } = parseRepoUrl(repoUrl, integrations); + + const api = getClient({ host, integrations, token }); + + await api.ProjectVariables.create(projectId, key, value, { + variableType: variableType as VariableType, protected: variableProtected, - masked: masked, - raw: raw, - environment_scope: environmentScope, + masked, + raw, + environmentScope, }); }, }); From 1ba55321bfea5911cec426452868f8d7e50edb2c Mon Sep 17 00:00:00 2001 From: "Stephen A. Wilson" Date: Wed, 3 Jul 2024 20:17:30 -0400 Subject: [PATCH 163/416] Fix linting errors Signed-off-by: Stephen A. Wilson --- plugins/techdocs/src/home/components/Tables/DocsTable.tsx | 2 +- plugins/techdocs/src/home/components/Tables/columns.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/techdocs/src/home/components/Tables/DocsTable.tsx b/plugins/techdocs/src/home/components/Tables/DocsTable.tsx index e2904374a0..b1537affdb 100644 --- a/plugins/techdocs/src/home/components/Tables/DocsTable.tsx +++ b/plugins/techdocs/src/home/components/Tables/DocsTable.tsx @@ -58,7 +58,7 @@ const defaultColumns: TableColumn[] = [ columnFactories.createKindColumn(), columnFactories.createTypeColumn(), ]; - + /** * Component which renders a table documents * diff --git a/plugins/techdocs/src/home/components/Tables/columns.tsx b/plugins/techdocs/src/home/components/Tables/columns.tsx index 08c190c26b..ef22f6d288 100644 --- a/plugins/techdocs/src/home/components/Tables/columns.tsx +++ b/plugins/techdocs/src/home/components/Tables/columns.tsx @@ -31,12 +31,12 @@ function customTitle(entity: Entity): string { */ export const columnFactories = { createTitleColumn(options?: { hidden?: boolean }): TableColumn { - const nameCol = columnFactories.createNameColumn() + const nameCol = columnFactories.createNameColumn(); return { ...nameCol, field: 'entity.metadata.title', hidden: options?.hidden, - } + }; }, createNameColumn(): TableColumn { return { From 3c2659e721086903d5bdad60778775950cbadee8 Mon Sep 17 00:00:00 2001 From: Emma Indal Date: Thu, 4 Jul 2024 10:40:23 +0200 Subject: [PATCH 164/416] add fetch api to deps Signed-off-by: Emma Indal --- plugins/search/src/alpha.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/search/src/alpha.tsx b/plugins/search/src/alpha.tsx index 5c85d097d4..c202d58712 100644 --- a/plugins/search/src/alpha.tsx +++ b/plugins/search/src/alpha.tsx @@ -33,7 +33,7 @@ import { useApi, DiscoveryApi, discoveryApiRef, - identityApiRef, + fetchApiRef, FetchApi, } from '@backstage/core-plugin-api'; @@ -79,7 +79,7 @@ import { export const searchApi = createApiExtension({ factory: { api: searchApiRef, - deps: { discoveryApi: discoveryApiRef, identityApi: identityApiRef }, + deps: { discoveryApi: discoveryApiRef, fetchApi: fetchApiRef }, factory: ({ fetchApi, discoveryApi, From 1117aba4bfc7ce64b85d6aaeef9f2639dac70492 Mon Sep 17 00:00:00 2001 From: Emma Indal Date: Thu, 4 Jul 2024 10:51:47 +0200 Subject: [PATCH 165/416] add changeset Signed-off-by: Emma Indal --- .changeset/thick-moose-decide.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/thick-moose-decide.md diff --git a/.changeset/thick-moose-decide.md b/.changeset/thick-moose-decide.md new file mode 100644 index 0000000000..194932979d --- /dev/null +++ b/.changeset/thick-moose-decide.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-search': patch +--- + +Update deps in search api extension to include fetch api From 5351b8c6bd0b26d5da70dcb9587e72bae818c9c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Thu, 4 Jul 2024 11:53:18 +0200 Subject: [PATCH 166/416] Update publishing.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- docs/publishing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/publishing.md b/docs/publishing.md index d7a4f65008..50d78ebf09 100644 --- a/docs/publishing.md +++ b/docs/publishing.md @@ -75,7 +75,7 @@ Given one or more PRs towards master that we want to create a patch release for, ./scripts/patch-release-for-pr.js ... ``` -Wait until the script has finished executing, at the end of the output you will find a link of the format `https://github.com/backstage/backstage/compare/patch/...`. Open this link in your browser to create a PR for the patch release. Finish the sentence "This release fixes an issue where..." and create the PR. +Wait until the script has finished executing, at the end of the output you will find a link of the format `https://github.com/backstage/backstage/pull/new/patch-release-pr-...`. Open this link in your browser to create a PR for the patch release. Finish the sentence "This release fixes an issue where..." and create the PR. Once the PR has been approved and merged, the patch release will be automatically created. The patch release is complete when a notification has been posted to Discord in the `#announcements` channel. Keep an eye on "Deploy Packages" workflow and re-trigger if it fails. It is safe to re-trigger any part of this workflow, including the release step. From 031f07d470782a116b7de613173c426ec33703be Mon Sep 17 00:00:00 2001 From: Adem Simsek Date: Thu, 4 Jul 2024 16:50:26 +0200 Subject: [PATCH 167/416] docs: Use correct Application Link Setup for Bitbucket Server Signed-off-by: Adem Simsek --- docs/auth/bitbucketServer/provider.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/auth/bitbucketServer/provider.md b/docs/auth/bitbucketServer/provider.md index 96c7db263e..eef934ca60 100644 --- a/docs/auth/bitbucketServer/provider.md +++ b/docs/auth/bitbucketServer/provider.md @@ -10,8 +10,8 @@ users using Bitbucket Server. This does **NOT** work with Bitbucket Cloud. ## Create an Application Link in Bitbucket Server -To add Bitbucket Server authentication, you must create an outgoing application link. Follow the steps described in -the [Bitbucket Server documentation](https://confluence.atlassian.com/bitbucketserver/configure-an-outgoing-link-1108483656.html) +To add Bitbucket Server authentication, you must create an incoming application link. Follow the steps described in +the [Bitbucket Server documentation](https://confluence.atlassian.com/bitbucketserver/configure-an-incoming-link-1108483657.html) to create one. ## Configuration From e90a2cdc0578b32edc532185ab2babaa7623260b Mon Sep 17 00:00:00 2001 From: Andre Wanlin Date: Fri, 5 Jul 2024 10:22:05 -0500 Subject: [PATCH 168/416] Added the Catalog logs module to the `create-app` template Signed-off-by: Andre Wanlin --- .changeset/fair-spoons-work.md | 5 +++++ packages/create-app/src/lib/versions.ts | 3 +++ .../templates/default-app/packages/backend/package.json.hbs | 1 + .../templates/default-app/packages/backend/src/index.ts | 3 +++ 4 files changed, 12 insertions(+) create mode 100644 .changeset/fair-spoons-work.md diff --git a/.changeset/fair-spoons-work.md b/.changeset/fair-spoons-work.md new file mode 100644 index 0000000000..e4b94625db --- /dev/null +++ b/.changeset/fair-spoons-work.md @@ -0,0 +1,5 @@ +--- +'@backstage/create-app': patch +--- + +Added the Catalog logs module to the `create-app` template diff --git a/packages/create-app/src/lib/versions.ts b/packages/create-app/src/lib/versions.ts index febc68102c..25fd7b7c3c 100644 --- a/packages/create-app/src/lib/versions.ts +++ b/packages/create-app/src/lib/versions.ts @@ -58,6 +58,7 @@ import { version as pluginCatalog } from '../../../../plugins/catalog/package.js import { version as pluginCatalogCommon } from '../../../../plugins/catalog-common/package.json'; import { version as pluginCatalogReact } from '../../../../plugins/catalog-react/package.json'; import { version as pluginCatalogBackend } from '../../../../plugins/catalog-backend/package.json'; +import { version as pluginCatalogBackendModuleLogs } from '../../../../plugins/catalog-backend-module-logs/package.json'; 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'; @@ -111,6 +112,8 @@ export const packageVersions = { '@backstage/plugin-catalog-common': pluginCatalogCommon, '@backstage/plugin-catalog-react': pluginCatalogReact, '@backstage/plugin-catalog-backend': pluginCatalogBackend, + '@backstage/plugin-catalog-backend-module-logs': + pluginCatalogBackendModuleLogs, '@backstage/plugin-catalog-backend-module-scaffolder-entity-model': pluginCatalogBackendModuleScaffolderEntityModel, '@backstage/plugin-catalog-graph': pluginCatalogGraph, diff --git a/packages/create-app/templates/default-app/packages/backend/package.json.hbs b/packages/create-app/templates/default-app/packages/backend/package.json.hbs index 8d95ee60a5..e26c788496 100644 --- a/packages/create-app/templates/default-app/packages/backend/package.json.hbs +++ b/packages/create-app/templates/default-app/packages/backend/package.json.hbs @@ -26,6 +26,7 @@ "@backstage/plugin-auth-backend-module-guest-provider": "^{{version '@backstage/plugin-auth-backend-module-guest-provider'}}", "@backstage/plugin-auth-node": "^{{version '@backstage/plugin-auth-node'}}", "@backstage/plugin-catalog-backend": "^{{version '@backstage/plugin-catalog-backend'}}", + "@backstage/plugin-catalog-backend-module-logs": "^{{version '@backstage/plugin-catalog-backend-module-logs'}}", "@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "^{{version '@backstage/plugin-catalog-backend-module-scaffolder-entity-model'}}", "@backstage/plugin-permission-backend": "^{{version '@backstage/plugin-permission-backend'}}", "@backstage/plugin-permission-backend-module-allow-all-policy": "^{{version '@backstage/plugin-permission-backend-module-allow-all-policy'}}", diff --git a/packages/create-app/templates/default-app/packages/backend/src/index.ts b/packages/create-app/templates/default-app/packages/backend/src/index.ts index 1c442a8d95..239269288e 100644 --- a/packages/create-app/templates/default-app/packages/backend/src/index.ts +++ b/packages/create-app/templates/default-app/packages/backend/src/index.ts @@ -27,6 +27,9 @@ backend.add( import('@backstage/plugin-catalog-backend-module-scaffolder-entity-model'), ); +// See https://backstage.io/docs/features/software-catalog/configuration#subscribing-to-catalog-errors +backend.add(import('@backstage/plugin-catalog-backend-module-logs')); + // permission plugin backend.add(import('@backstage/plugin-permission-backend/alpha')); backend.add( From 0976bbd15238533f72038a66d0ec2696adb2daf2 Mon Sep 17 00:00:00 2001 From: Andre Wanlin Date: Fri, 5 Jul 2024 12:07:22 -0500 Subject: [PATCH 169/416] Added backend install steps for various auth providers Signed-off-by: Andre Wanlin --- docs/auth/atlassian/provider.md | 17 +++ docs/auth/aws-alb/provider.md | 67 +++++----- docs/auth/bitbucket/provider.md | 77 ++++++------ docs/auth/cloudflare/access.md | 174 -------------------------- docs/auth/cloudflare/provider.md | 82 ++++++++++++ docs/auth/github/provider.md | 33 +++-- docs/auth/gitlab/provider.md | 17 +++ docs/auth/google/gcp-iap-auth.md | 95 ++------------ docs/auth/google/provider.md | 21 +++- docs/auth/identity-resolver.md | 2 + docs/auth/microsoft/azure-easyauth.md | 137 +++++++++----------- docs/auth/microsoft/provider.md | 41 ++++-- docs/auth/oauth2-proxy/provider.md | 38 +++--- docs/auth/okta/provider.md | 17 +++ docs/auth/onelogin/provider.md | 39 ++++++ docs/auth/vmware-cloud/provider.md | 133 +++++--------------- 16 files changed, 439 insertions(+), 551 deletions(-) delete mode 100644 docs/auth/cloudflare/access.md create mode 100644 docs/auth/cloudflare/provider.md diff --git a/docs/auth/atlassian/provider.md b/docs/auth/atlassian/provider.md index c8db009805..44f6d097b9 100644 --- a/docs/auth/atlassian/provider.md +++ b/docs/auth/atlassian/provider.md @@ -79,6 +79,23 @@ The resolvers will be tried in order, but will only be skipped if they throw a ` If these resolvers do not fit your needs you can build a custom resolver, this is covered in the [Building Custom Resolvers](../identity-resolver.md#building-custom-resolvers) section of the Sign-in Identities and Resolvers documentation. +## Backend Installation + +To add the provider to the backend we will first need to install the package by running this command: + +```bash title="from your Backstage root directory" +yarn --cwd packages/backend add @backstage/plugin-auth-backend-module-atlassian-provider +``` + +Then we will need to this line: + +```ts title="in packages/backend/src/index.ts" +backend.add(import('@backstage/plugin-auth-backend')); +/* highlight-add-start */ +backend.add(import('@backstage/plugin-auth-backend-module-atlassian-provider')); +/* highlight-add-end */ +``` + ## Adding the provider to the Backstage frontend To add the provider to the frontend, add the `atlassianAuthApi` reference and diff --git a/docs/auth/aws-alb/provider.md b/docs/auth/aws-alb/provider.md index dc878e8971..8f21b7dbf0 100644 --- a/docs/auth/aws-alb/provider.md +++ b/docs/auth/aws-alb/provider.md @@ -8,37 +8,6 @@ description: Adding AWS ALB as an authentication provider in Backstage Backstage can de deployed behind [AWS Application Load Balancer](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/introduction.html) and get the user seamlessly authenticated. -## Installation - -### Backend - -:::note -These instructions are written for the [new backend system](../../backend-system/index.md). -::: - -Add the `@backstage/plugin-auth-backend-module-aws-alb-provider` to your backend installation. - -```sh -# From your Backstage root directory -yarn --cwd packages/backend add @backstage/plugin-auth-backend-module-aws-alb-provider -``` - -Then, add it to your backend's source, - -```ts title="packages/backend/src/index.ts" -const backend = createBackend(); - -backend.add(import('@backstage/plugin-auth-backend')); -// highlight-add-next-line -backend.add(import('@backstage/plugin-auth-backend-module-aws-alb-provider')); - -await backend.start(); -``` - -### Frontend - -See [Sign-In with Proxy Providers](../index.md#sign-in-with-proxy-providers) for pointers on how to set up the sign-in page, and to also make it work smoothly for local development. - ## Configuration The provider configuration can be added to your `app-config.yaml` under the root @@ -57,4 +26,40 @@ auth: - resolver: emailLocalPartMatchingUserEntityName ``` +### Resolvers + +This provider includes several resolvers out of the box that you can use: + +- `emailMatchingUserEntityProfileEmail`: Matches the email address from the auth provider with the User entity that has a matching `spec.profile.email`. If no match is found it will throw a `NotFoundError`. +- `emailLocalPartMatchingUserEntityName`: Matches the [local part](https://en.wikipedia.org/wiki/Email_address#Local-part) of the email address from the auth provider with the User entity that has a matching `name`. If no match is found it will throw a `NotFoundError`. + +:::note Note + +The resolvers will be tried in order, but will only be skipped if they throw a `NotFoundError`. + +::: + +If these resolvers do not fit your needs you can build a custom resolver, this is covered in the [Building Custom Resolvers](../identity-resolver.md#building-custom-resolvers) section of the Sign-in Identities and Resolvers documentation. + +## Backend Installation + +To add the provider to the backend we will first need to install the package by running this command: + +```bash title="from your Backstage root directory" +yarn --cwd packages/backend add @backstage/plugin-auth-backend-module-aws-alb-provider +``` + +Then we will need to add this line: + +```ts title="in packages/backend/src/index.ts" +backend.add(import('@backstage/plugin-auth-backend')); +/* highlight-add-start */ +backend.add(import('@backstage/plugin-auth-backend-module-aws-alb-provider')); +/* highlight-add-end */ +``` + +## Adding the provider to the Backstage frontend + +See [Sign-In with Proxy Providers](../index.md#sign-in-with-proxy-providers) for pointers on how to set up the sign-in page, and to also make it work smoothly for local development. You'll use `awsalb` as the provider name. + If you [provide a custom sign in resolver](https://backstage.io/docs/auth/identity-resolver#building-custom-resolvers), you can skip the `signIn` block entirely. diff --git a/docs/auth/bitbucket/provider.md b/docs/auth/bitbucket/provider.md index b03201893c..163647c790 100644 --- a/docs/auth/bitbucket/provider.md +++ b/docs/auth/bitbucket/provider.md @@ -37,6 +37,13 @@ auth: development: clientId: ${AUTH_BITBUCKET_CLIENT_ID} clientSecret: ${AUTH_BITBUCKET_CLIENT_SECRET} + signIn: + resolvers: + # typically you would pick one of these + - resolver: emailMatchingUserEntityProfileEmail + - resolver: emailLocalPartMatchingUserEntityName + - resolver: userIdMatchingUserEntityAnnotation + - resolver: usernameMatchingUserEntityAnnotation ``` The Bitbucket provider is a structure with two configuration keys: @@ -45,44 +52,42 @@ The Bitbucket provider is a structure with two configuration keys: `b59241722e3c3b4816e2` - `clientSecret`: The Secret tied to the generated Key. +### Resolvers + +This provider includes several resolvers out of the box that you can use: + +- `emailMatchingUserEntityProfileEmail`: Matches the email address from the auth provider with the User entity that has a matching `spec.profile.email`. If no match is found it will throw a `NotFoundError`. +- `emailLocalPartMatchingUserEntityName`: Matches the [local part](https://en.wikipedia.org/wiki/Email_address#Local-part) of the email address from the auth provider with the User entity that has a matching `name`. If no match is found it will throw a `NotFoundError`. +- `userIdMatchingUserEntityAnnotation`: Matches the `userId` from the auth provider with the User entity that has a matching `bitbucket.org/user-id` annotation. If no match is found it will throw a `NotFoundError`. +- `usernameMatchingUserEntityAnnotation`: Matches the `username` from the auth provider with the User entity that has a matching `bitbucket.org/username` annotation. If no match is found it will throw a `NotFoundError`. + +:::note Note + +The resolvers will be tried in order, but will only be skipped if they throw a `NotFoundError`. + +::: + +If these resolvers do not fit your needs you can build a custom resolver, this is covered in the [Building Custom Resolvers](../identity-resolver.md#building-custom-resolvers) section of the Sign-in Identities and Resolvers documentation. + +## Backend Installation + +To add the provider to the backend we will first need to install the package by running this command: + +```bash title="from your Backstage root directory" +yarn --cwd packages/backend add @backstage/plugin-auth-backend-module-bitbucket-provider +``` + +Then we will need to add this line: + +```ts title="in packages/backend/src/index.ts" +backend.add(import('@backstage/plugin-auth-backend')); +/* highlight-add-start */ +backend.add(import('@backstage/plugin-auth-backend-module-bitbucket-provider')); +/* highlight-add-end */ +``` + ## Adding the provider to the Backstage frontend To add the provider to the frontend, add the `bitbucketAuthApi` reference and `SignInPage` component as shown in [Adding the provider to the sign-in page](../index.md#adding-the-provider-to-the-sign-in-page). - -## Using Bitbucket for sign-in - -In order to use the Bitbucket provider for sign-in, you must configure it with a -`signIn.resolver`. See the -[Sign-In Resolver documentation](../identity-resolver.md) for more details on -how this is done. Note that for the Bitbucket provider, you'll want to use -`bitbucket` as the provider ID, and `providers.bitbucket.create` for the provider -factory. - -The `@backstage/plugin-auth-backend` plugin also comes with two built-in -resolvers that can be used if desired. The first one is the -`bitbucketUsernameSignInResolver`, which identifies users by matching their -Bitbucket username to `bitbucket.org/username` annotations of `User` entities in -the catalog. Note that you must populate your catalog with matching entities or -users will not be able to sign in. - -The second resolver is the `bitbucketUserIdSignInResolver`, which works the -same way, but uses the Bitbucket user ID instead, and matches on the -`bitbucket.org/user-id` annotation. - -The following is an example of how to use one of the built-in resolvers: - -```ts -import { providers } from '@backstage/plugin-auth-backend'; - -// ... - providerFactories: { - bitbucket: providers.bitbucket.create({ - signIn: { - resolver: - providers.bitbucket.resolvers.usernameMatchingUserEntityAnnotation(), - }, - }), - }, -``` diff --git a/docs/auth/cloudflare/access.md b/docs/auth/cloudflare/access.md deleted file mode 100644 index 52d9fdfc21..0000000000 --- a/docs/auth/cloudflare/access.md +++ /dev/null @@ -1,174 +0,0 @@ ---- -id: provider -title: Cloudflare Access Provider -sidebar_label: Cloudflare Access -description: Adding Cloudflare Access as an authentication provider in Backstage ---- - -Similar to GCP IAP Proxy Provider or AWS ALB provider, developers can offload authentication -support to Cloudflare Access. - -This tutorial shows how to use authentication on Cloudflare Access sitting in -front of Backstage. - -It is assumed a Cloudflare tunnel is already serving traffic in front of a -Backstage instance configured to serve the frontend app from the backend and is -already gated using Cloudflare Access. - -## Configuration - -Let's start by adding the following `auth` configuration in your -`app-config.yaml` or `app-config.production.yaml` or similar: - -```yaml -auth: - providers: - cfaccess: - # You can find the team name in the Cloudflare Zero Trust dashboard. - teamName: - # This service tokens section is optional -- you only need it if you have - # some Cloudflare Service Tokens that you want to be able to log in to your - # Backstage instance. - serviceTokens: - - token: '1uh2fh19efvfh129f1f919u21f2f19jf2.access' - subject: 'bot-user@your-company.com' - # This picks what sign in resolver(s) you want to use. - signIn: - resolvers: - - resolver: emailMatchingUserEntityProfileEmail -``` - -This config section must be in place for the provider to load at all. - -The `signIn` section picks what sign-in resolver(s) to use for sign-in attempts. -It is responsible for matching the upstream provider's sign-in result to a -corresponding Backstage identity, or to throw an error if the attempt should be -rejected for any reason. The `emailMatchingUserEntityProfileEmail` is a common -choice: it tries to match the email of the signed-in user to a `User` kind -entity in the catalog whose profile email matches that. - -If the builtin sign in resolvers do not match your needs, you can skip the -`signIn` section and instead [provide a custom resolver](#advanced-custom-sign-in-resolver). - -## Backend Changes - -We need to add the provider package as a dependency to our backend: - -```bash title="from your Backstage root directory" -yarn --cwd packages/backend add @backstage/plugin-auth-backend-module-cloudflare-access-provider -``` - -And to tell the backend to load it: - -```ts title="in packages/backend/src/index.ts" -backend.add(import('@backstage/plugin-auth-backend')); -/* highlight-add-start */ -backend.add( - import('@backstage/plugin-auth-backend-module-cloudflare-access-provider'), -); -/* highlight-add-end */ -``` - -Now the backend is ready to serve auth requests on the -`/api/auth/cfaccess/refresh` endpoint. All that's left is to update the frontend -sign-in mechanism to poll that endpoint through Cloudflare Access, on the user's -behalf. - -## Frontend Changes - -It is recommended to use the `ProxiedSignInPage` for this provider, which is -installed in your app like this: - -```tsx title="in packages/app/src/App.tsx" -/* highlight-add-next-line */ -import { ProxiedSignInPage } from '@backstage/core-components'; - -const app = createApp({ - /* highlight-add-start */ - components: { - SignInPage: props => , - }, - /* highlight-add-end */ - // ... -}); -``` - -See [Sign-In with Proxy Providers](../index.md#sign-in-with-proxy-providers) for -pointers on how to set up the sign-in page to also work smoothly for local -development. - -## Advanced: Custom Sign-in Resolver - -If none of the built-in sign in resolvers fit your needs, you need to provide a -customized version of the module. Now you should _not_ -`backend.add(import(...))`, instead you will do the following. - -```ts title="in packages/backend/plugin/auth.ts" -/* highlight-add-start */ -import { createCloudflareAccessAuthenticator } from '@backstage/plugin-auth-backend-module-cloudflare-access-provider'; -import { - coreServices, - createBackendModule, -} from '@backstage/backend-plugin-api'; -import { - authProvidersExtensionPoint, - createProxyAuthProviderFactory, -} from '@backstage/plugin-auth-node'; - -const customAuth = createBackendModule({ - // This ID must be exactly "auth" because that's the plugin it targets - pluginId: 'auth', - // This ID must be unique, but can be anything - moduleId: 'custom-auth-provider', - register(reg) { - reg.registerInit({ - deps: { - providers: authProvidersExtensionPoint, - cache: coreServices.cache, - }, - async init({ providers, cache }) { - providers.registerProvider({ - // This ID must match the actual provider config, e.g. addressing - // auth.providers.github means that this must be "github". - providerId: 'cfaccess', - // Use createProxyAuthProviderFactory instead if it's one of the proxy - // based providers rather than an OAuth based one - factory: createProxyAuthProviderFactory({ - authenticator: createCloudflareAccessAuthenticator({ cache }), - async signInResolver(info, ctx) { - // This is where the body of the sign-in resolver goes! - const { profile } = info; - if (!profile.email) { - throw new Error( - 'Login failed, user profile does not contain an email', - ); - } - return ctx.signInWithCatalogUser({ - filter: { - 'spec.profile.email': profile.email, - }, - }); - }, - }), - }); - }, - }); - }, -}); -/* highlight-add-end */ - -backend.add(import('@backstage/plugin-auth-backend')); -/* highlight-remove-start */ -backend.add( - import('@backstage/plugin-auth-backend-module-cloudflare-access-provider'), -); -/* highlight-remove-end */ -/* highlight-add-next-line */ -backend.add(customAuth); -``` - -The body of the sign-in resolver is up to you to write! The example code above -is just a copy of what `emailMatchingUserEntityProfileEmail` does. The `info` -parameter contains all of the results of the sign-in attempt so far. The `ctx` -context [has several useful functions](https://backstage.io/docs/reference/plugin-auth-node.authresolvercontext/) -for issuing tokens in various ways. diff --git a/docs/auth/cloudflare/provider.md b/docs/auth/cloudflare/provider.md new file mode 100644 index 0000000000..516ea9d647 --- /dev/null +++ b/docs/auth/cloudflare/provider.md @@ -0,0 +1,82 @@ +--- +id: provider +title: Cloudflare Access Provider +sidebar_label: Cloudflare Access +description: Adding Cloudflare Access as an authentication provider in Backstage +--- + +Similar to GCP IAP Proxy Provider or AWS ALB provider, developers can offload authentication +support to Cloudflare Access. + +This tutorial shows how to use authentication on Cloudflare Access sitting in +front of Backstage. + +It is assumed a Cloudflare tunnel is already serving traffic in front of a +Backstage instance configured to serve the frontend app from the backend and is +already gated using Cloudflare Access. + +## Configuration + +Let's start by adding the following `auth` configuration in your +`app-config.yaml` or `app-config.production.yaml` or similar: + +```yaml +auth: + providers: + cfaccess: + # You can find the team name in the Cloudflare Zero Trust dashboard. + teamName: + # This service tokens section is optional -- you only need it if you have + # some Cloudflare Service Tokens that you want to be able to log in to your + # Backstage instance. + serviceTokens: + - token: '1uh2fh19efvfh129f1f919u21f2f19jf2.access' + subject: 'bot-user@your-company.com' + # This picks what sign in resolver(s) you want to use. + signIn: + resolvers: + - resolver: emailMatchingUserEntityProfileEmail + - resolver: emailLocalPartMatchingUserEntityName +``` + +This config section must be in place for the provider to load at all. + +### Resolvers + +This provider includes several resolvers out of the box that you can use: + +- `emailMatchingUserEntityProfileEmail`: Matches the email address from the auth provider with the User entity that has a matching `spec.profile.email`. If no match is found it will throw a `NotFoundError`. +- `emailLocalPartMatchingUserEntityName`: Matches the [local part](https://en.wikipedia.org/wiki/Email_address#Local-part) of the email address from the auth provider with the User entity that has a matching `name`. If no match is found it will throw a `NotFoundError`. + +:::note Note + +The resolvers will be tried in order, but will only be skipped if they throw a `NotFoundError`. + +::: + +If these resolvers do not fit your needs you can build a custom resolver, this is covered in the [Building Custom Resolvers](../identity-resolver.md#building-custom-resolvers) section of the Sign-in Identities and Resolvers documentation. + +## Backend Installation + +To add the provider to the backend we will first need to install the package by running this command: + +```bash title="from your Backstage root directory" +yarn --cwd packages/backend add @backstage/plugin-auth-backend-module-cloudflare-access-provider +``` + +Then we will need to add this line: + +```ts title="in packages/backend/src/index.ts" +backend.add(import('@backstage/plugin-auth-backend')); +/* highlight-add-start */ +backend.add( + import('@backstage/plugin-auth-backend-module-cloudflare-access-provider'), +); +/* highlight-add-end */ +``` + +## Adding the provider to the Backstage frontend + +See [Sign-In with Proxy Providers](../index.md#sign-in-with-proxy-providers) for pointers on how to set up the sign-in page, and to also make it work smoothly for local development. You'll use `cfaccess` as the provider name. + +If you [provide a custom sign in resolver](https://backstage.io/docs/auth/identity-resolver#building-custom-resolvers), you can skip the `signIn` block entirely. diff --git a/docs/auth/github/provider.md b/docs/auth/github/provider.md index 1873730bd6..801320299b 100644 --- a/docs/auth/github/provider.md +++ b/docs/auth/github/provider.md @@ -26,6 +26,14 @@ Settings for local development: - Homepage URL: `http://localhost:3000` - Authorization callback URL: `http://localhost:7007/api/auth/github/handler/frame` +### Difference between GitHub Apps and GitHub OAuth Apps + +GitHub Apps handle OAuth scope at the app installation level, meaning that the +`scope` parameter for the call to `getAccessToken` in the frontend has no +effect. When calling `getAccessToken` in open source plugins, one should still +include the appropriate scope, but also document in the plugin README what +scopes are required for GitHub Apps. + ## Configuration The provider configuration can then be added to your `app-config.yaml` under the @@ -79,16 +87,25 @@ The resolvers will be tried in order, but will only be skipped if they throw a ` If these resolvers do not fit your needs you can build a custom resolver, this is covered in the [Building Custom Resolvers](../identity-resolver.md#building-custom-resolvers) section of the Sign-in Identities and Resolvers documentation. +## Backend Installation + +To add the provider to the backend we will first need to install the package by running this command: + +```bash title="from your Backstage root directory" +yarn --cwd packages/backend add @backstage/plugin-auth-backend-module-github-provider +``` + +Then we will need to add this line: + +```ts title="in packages/backend/src/index.ts" +backend.add(import('@backstage/plugin-auth-backend')); +/* highlight-add-start */ +backend.add(import('@backstage/plugin-auth-backend-module-github-provider')); +/* highlight-add-end */ +``` + ## Adding the provider to the Backstage frontend To add the provider to the frontend, add the `githubAuthApi` reference and `SignInPage` component as shown in [Adding the provider to the sign-in page](../index.md#adding-the-provider-to-the-sign-in-page). - -## Difference between GitHub Apps and GitHub OAuth Apps - -GitHub Apps handle OAuth scope at the app installation level, meaning that the -`scope` parameter for the call to `getAccessToken` in the frontend has no -effect. When calling `getAccessToken` in open source plugins, one should still -include the appropriate scope, but also document in the plugin README what -scopes are required for GitHub Apps. diff --git a/docs/auth/gitlab/provider.md b/docs/auth/gitlab/provider.md index f5613582fd..e70953e11d 100644 --- a/docs/auth/gitlab/provider.md +++ b/docs/auth/gitlab/provider.md @@ -78,6 +78,23 @@ The resolvers will be tried in order, but will only be skipped if they throw a ` If these resolvers do not fit your needs you can build a custom resolver, this is covered in the [Building Custom Resolvers](../identity-resolver.md#building-custom-resolvers) section of the Sign-in Identities and Resolvers documentation. +## Backend Installation + +To add the provider to the backend we will first need to install the package by running this command: + +```bash title="from your Backstage root directory" +yarn --cwd packages/backend add @backstage/plugin-auth-backend-module-gitlab-provider +``` + +Then we will need to add this line: + +```ts title="in packages/backend/src/index.ts" +backend.add(import('@backstage/plugin-auth-backend')); +/* highlight-add-start */ +backend.add(import('@backstage/plugin-auth-backend-module-gitlab-provider')); +/* highlight-add-end */ +``` + ## Adding the provider to the Backstage frontend To add the provider to the frontend, add the `gitlabAuthApi` reference and diff --git a/docs/auth/google/gcp-iap-auth.md b/docs/auth/google/gcp-iap-auth.md index 7e6178154c..6479ac7268 100644 --- a/docs/auth/google/gcp-iap-auth.md +++ b/docs/auth/google/gcp-iap-auth.md @@ -58,102 +58,25 @@ The resolvers will be tried in order, but will only be skipped if they throw a ` If these resolvers do not fit your needs you can build a custom resolver, this is covered in the [Building Custom Resolvers](../identity-resolver.md#building-custom-resolvers) section of the Sign-in Identities and Resolvers documentation. -## Backend Changes +## Backend Installation -There is a module for this provider that you will need to add to your backend. +To add the provider to the backend we will first need to install the package by running this command: -First you'll want to run this command to add the module: - -```sh - yarn --cwd packages/backend add @backstage/plugin-auth-backend-module-gcp-iap-provider +```bash title="from your Backstage root directory" +yarn --cwd packages/backend add @backstage/plugin-auth-backend-module-gcp-iap-provider ``` -Then you will need to add this to your backend: - -```ts title="packages/backend/src/index.ts" -const backend = createBackend(); +Then we will need to add this line: +```ts title="in packages/backend/src/index.ts" backend.add(import('@backstage/plugin-auth-backend')); /* highlight-add-start */ backend.add(import('@backstage/plugin-auth-backend-module-gcp-iap-provider')); /* highlight-add-end */ ``` -### Legacy Backend Changes +## Adding the provider to the Backstage frontend -If you are still using the legacy backend you will need to make the changes outlined here. +See [Sign-In with Proxy Providers](../index.md#sign-in-with-proxy-providers) for pointers on how to set up the sign-in page, and to also make it work smoothly for local development. You'll use `gcp-iap` as the provider name. -This provider is not enabled by default in the auth backend code, because besides the config section above, it also needs to be given one or more callbacks in actual code as well as described below. - -Add a `providerFactories` entry to the router in -`packages/backend/src/plugins/auth.ts`. - -```ts title="packages/backend/src/plugins/auth.ts" -import { providers } from '@backstage/plugin-auth-backend'; -import { stringifyEntityRef } from '@backstage/catalog-model'; - -export default async function createPlugin( - env: PluginEnvironment, -): Promise { - return await createRouter({ - logger: env.logger, - config: env.config, - database: env.database, - discovery: env.discovery, - providerFactories: { - 'gcp-iap': providers.gcpIap.create({ - // Replace the auth handler if you want to customize the returned user - // profile info (can be left out; the default implementation is shown - // below which only returns the email). You may want to amend this code - // with something that loads additional user profile data out of e.g. - // GSuite or LDAP or similar. - async authHandler({ iapToken }) { - return { profile: { email: iapToken.email } }; - }, - signIn: { - // You need to supply an identity resolver, that takes the profile - // and the IAP token and produces the Backstage token with the - // relevant user info. - async resolver({ profile, result: { iapToken } }, ctx) { - // Somehow compute the Backstage token claims. Just some sample code - // shown here, but you may want to query your LDAP server, or - // GSuite or similar, based on the IAP token sub/email claims - const id = iapToken.email.split('@')[0]; - const sub = stringifyEntityRef({ kind: 'User', name: id }); - const ent = [ - sub, - stringifyEntityRef({ kind: 'Group', name: 'team-name' }), - ]; - return ctx.issueToken({ claims: { sub, ent } }); - }, - }, - }), - }, - }); -} -``` - -Now the backend is ready to serve auth requests on the -`/api/auth/gcp-iap/refresh` endpoint. All that's left is to update the frontend -sign-in mechanism to poll that endpoint through the IAP, on the user's behalf. - -## Frontend Changes - -It is recommended to use the `ProxiedSignInPage` for this provider, which is -installed in `packages/app/src/App.tsx` like this: - -```tsx title="packages/app/src/App.tsx" -/* highlight-add-next-line */ -import { ProxiedSignInPage } from '@backstage/core-components'; - -const app = createApp({ - /* highlight-add-start */ - components: { - SignInPage: props => , - }, - /* highlight-add-end */ - // .. -}); -``` - -See the [Sign-In with Proxy Providers](../index.md#sign-in-with-proxy-providers) section for more information. +If you [provide a custom sign in resolver](https://backstage.io/docs/auth/identity-resolver#building-custom-resolvers), you can skip the `signIn` block entirely. diff --git a/docs/auth/google/provider.md b/docs/auth/google/provider.md index f7802d43f7..e2efacfed2 100644 --- a/docs/auth/google/provider.md +++ b/docs/auth/google/provider.md @@ -24,9 +24,9 @@ To support Google authentication, you must create OAuth credentials: - Add yourself as a test user, if using External user type 6. Set **Application Type** to `Web Application` with these settings: - `Name`: Backstage (or your custom app name) - - `Authorized JavaScript origins`: http://localhost:3000 + - `Authorized JavaScript origins`: - `Authorized Redirect URIs`: - http://localhost:7007/api/auth/google/handler/frame + 7. Click Create ## Configuration @@ -72,6 +72,23 @@ The resolvers will be tried in order, but will only be skipped if they throw a ` If these resolvers do not fit your needs you can build a custom resolver, this is covered in the [Building Custom Resolvers](../identity-resolver.md#building-custom-resolvers) section of the Sign-in Identities and Resolvers documentation. +## Backend Installation + +To add the provider to the backend we will first need to install the package by running this command: + +```bash title="from your Backstage root directory" +yarn --cwd packages/backend add @backstage/plugin-auth-backend-module-google-provider +``` + +Then we will need to add this line: + +```ts title="in packages/backend/src/index.ts" +backend.add(import('@backstage/plugin-auth-backend')); +/* highlight-add-start */ +backend.add(import('@backstage/plugin-auth-backend-module-google-provider')); +/* highlight-add-end */ +``` + ## Adding the provider to the Backstage frontend To add the provider to the frontend, add the `googleAuthApi` reference and diff --git a/docs/auth/identity-resolver.md b/docs/auth/identity-resolver.md index 4140276df8..5efb592270 100644 --- a/docs/auth/identity-resolver.md +++ b/docs/auth/identity-resolver.md @@ -124,6 +124,8 @@ The list of available resolvers is different for each provider, since they often depend on the information model returned from the upstream provider service. Consult the documentation of the respective provider to find the list. +In the example above `emailMatchingUserEntityProfileEmail` and `emailLocalPartMatchingUserEntityName` are common to all auth providers and `usernameMatchingUserEntityName` is specific to GitHub. + ### Building Custom Resolvers If the builtins don't work for you, you can also provide a completely custom diff --git a/docs/auth/microsoft/azure-easyauth.md b/docs/auth/microsoft/azure-easyauth.md index 5fec3354d7..e8d6f2f105 100644 --- a/docs/auth/microsoft/azure-easyauth.md +++ b/docs/auth/microsoft/azure-easyauth.md @@ -7,87 +7,6 @@ description: Adding Azure's EasyAuth Proxy as an authentication provider in Back The Backstage `core-plugin-api` package comes with a Microsoft authentication provider that can authenticate users using Microsoft Entra ID (formerly Azure Active Directory) for PaaS service hosted in Azure that support Easy Auth, such as Azure App Services. -## Backend Changes - -Add the following into your `app-config.yaml` under the root `auth` configuration: - -```yaml title="app-config.yaml" -auth: - providers: - azureEasyAuth: - signIn: - resolvers: - - resolver: idMatchingUserEntityAnnotation - - resolver: emailMatchingUserEntityProfileEmail - - resolver: emailLocalPartMatchingUserEntityName -``` - -The `idMatchingUserEntityAnnotation` is -[a builtin sign-in resolver](../identity-resolver.md#using-builtin-resolvers) from `azureEasyAuth` provider. -It tries to find a user entity with [a `graph.microsoft.com/user-id` annotation](../../features/software-catalog/well-known-annotations.md#graphmicrosoftcomtenant-id-graphmicrosoftcomgroup-id-graphmicrosoftcomuser-id) -which matches the object ID of the user attempting to sign in. -If you want to provide your own sign-in resolver, -see [Building Custom Resolvers](../identity-resolver.md#building-custom-resolvers). - -Add the `@backstage/plugin-auth-backend-module-azure-easyauth-provider` to your backend installation. - -```sh -# From your Backstage root directory -yarn --cwd packages/backend add @backstage/plugin-auth-backend-module-azure-easyauth-provider -``` - -Then, add it to your backend's source, - -```ts title="packages/backend/src/index.ts" -const backend = createBackend(); - -backend.add(import('@backstage/plugin-auth-backend')); -// highlight-add-next-line -backend.add( - import('@backstage/plugin-auth-backend-module-azure-easyauth-provider'), -); - -await backend.start(); -``` - -Now the backend is ready to serve auth requests on the -`/api/auth/azureEasyAuth/refresh` endpoint. All that's left is to update the frontend -sign-in mechanism to poll that endpoint through the Easy Auth proxy, on the user's behalf. - -## Frontend Changes - -To use this component, you'll need to configure the app's `SignInPage`. -It is recommended to use the `ProxiedSignInPage` for this provider when running in Azure, However for local development (or any other scenario running outside of Azure), you'll want to set up something different. -For the closest experience to Easy Auth, you could set up the `microsoft` provider locally, but that will requires setting up App Registrations & secrets which may be locked down by your organisation, in which case it may be easier to use guest login locally. -See [Sign-In with Proxy Providers](../index.md#sign-in-with-proxy-providers) for more details. - -```tsx title="packages/app/src/App.tsx" -/* highlight-add-next-line */ -import { ProxiedSignInPage } from '@backstage/core-components'; - -const app = createApp({ - /* highlight-add-start */ - components: { - SignInPage: props => { - const configApi = useApi(configApiRef); - if (configApi.getString('auth.environment') !== 'development') { - return ; - } - return ( - - ); - }, - }, - /* highlight-add-end */ - // .. -}); -``` - ## Azure Configuration How to configure azure depends on the Azure service you're using to host Backstage. @@ -136,3 +55,59 @@ resource webApp 'Microsoft.Web/sites@2022-03-01' existing = { } } ``` + +## Configuration + +Add the following into your `app-config.yaml` under the root `auth` configuration: + +```yaml title="app-config.yaml" +auth: + providers: + azureEasyAuth: + signIn: + resolvers: + - resolver: emailMatchingUserEntityProfileEmail + - resolver: emailLocalPartMatchingUserEntityName + - resolver: idMatchingUserEntityAnnotation +``` + +### Resolvers + +This provider includes several resolvers out of the box that you can use: + +- `emailMatchingUserEntityProfileEmail`: Matches the email address from the auth provider with the User entity that has a matching `spec.profile.email`. If no match is found it will throw a `NotFoundError`. +- `emailLocalPartMatchingUserEntityName`: Matches the [local part](https://en.wikipedia.org/wiki/Email_address#Local-part) of the email address from the auth provider with the User entity that has a matching `name`. If no match is found it will throw a `NotFoundError`. +- `idMatchingUserEntityAnnotation`: Matches the user Id from the auth provider with the User entity that has a matching `graph.microsoft.com/user-id` annotation. If no match is found it will throw a `NotFoundError`. + +:::note Note + +The resolvers will be tried in order, but will only be skipped if they throw a `NotFoundError`. + +::: + +If these resolvers do not fit your needs you can build a custom resolver, this is covered in the [Building Custom Resolvers](../identity-resolver.md#building-custom-resolvers) section of the Sign-in Identities and Resolvers documentation. + +## Backend Installation + +To add the provider to the backend we will first need to install the package by running this command: + +```bash title="from your Backstage root directory" +yarn --cwd packages/backend add @backstage/plugin-auth-backend-module-azure-easyauth-provider +``` + +Then we will need to this line: + +```ts title="in packages/backend/src/index.ts" +backend.add(import('@backstage/plugin-auth-backend')); +/* highlight-add-start */ +backend.add( + import('@backstage/plugin-auth-backend-module-azure-easyauth-provider'), +); +/* highlight-add-end */ +``` + +## Adding the provider to the Backstage frontend + +See [Sign-In with Proxy Providers](../index.md#sign-in-with-proxy-providers) for pointers on how to set up the sign-in page, and to also make it work smoothly for local development. You'll use `azureEasyAuth` as the provider name. + +If you [provide a custom sign in resolver](https://backstage.io/docs/auth/identity-resolver#building-custom-resolvers), you can skip the `signIn` block entirely. diff --git a/docs/auth/microsoft/provider.md b/docs/auth/microsoft/provider.md index b96f175183..aeec71213f 100644 --- a/docs/auth/microsoft/provider.md +++ b/docs/auth/microsoft/provider.md @@ -40,6 +40,18 @@ If you're using an existing app registration, and backstage already has a client If not, go to the **Certificates & Secrets** page, then the **Client secrets** tab and create a new client secret. Make a note of this value as you'll need it in the next section. +## Outbound Network Access + +If your environment has restrictions on outgoing access (e.g. through +firewall rules), make sure your Backstage backend has access to the following +hosts: + +- `login.microsoftonline.com`, to get and exchange authorization codes and access + tokens +- `graph.microsoft.com`, to fetch user profile information (as seen + in [this source code](https://github.com/seanfisher/passport-microsoft/blob/0456aa9bce05579c18e77f51330176eb26373658/lib/strategy.js#L93-L95)). + If this host is unreachable, users may see an `Authentication failed, failed to fetch user profile` error when they attempt to log in. + ## Configuration The provider configuration can then be added to your `app-config.yaml` under the @@ -92,20 +104,25 @@ The resolvers will be tried in order, but will only be skipped if they throw a ` If these resolvers do not fit your needs you can build a custom resolver, this is covered in the [Building Custom Resolvers](../identity-resolver.md#building-custom-resolvers) section of the Sign-in Identities and Resolvers documentation. +## Backend Installation + +To add the provider to the backend we will first need to install the package by running this command: + +```bash title="from your Backstage root directory" +yarn --cwd packages/backend add @backstage/plugin-auth-backend-module-microsoft-provider +``` + +Then we will need to this line: + +```ts title="in packages/backend/src/index.ts" +backend.add(import('@backstage/plugin-auth-backend')); +/* highlight-add-start */ +backend.add(import('@backstage/plugin-auth-backend-module-microsoft-provider')); +/* highlight-add-end */ +``` + ## Adding the provider to the Backstage frontend To add the provider to the frontend, add the `microsoftAuthApiRef` reference and `SignInPage` component as shown in [Adding the provider to the sign-in page](../index.md#adding-the-provider-to-the-sign-in-page). - -## Outbound Network Access - -If your environment has restrictions on outgoing access (e.g. through -firewall rules), make sure your Backstage backend has access to the following -hosts: - -- `login.microsoftonline.com`, to get and exchange authorization codes and access - tokens -- `graph.microsoft.com`, to fetch user profile information (as seen - in [this source code](https://github.com/seanfisher/passport-microsoft/blob/0456aa9bce05579c18e77f51330176eb26373658/lib/strategy.js#L93-L95)). - If this host is unreachable, users may see an `Authentication failed, failed to fetch user profile` error when they attempt to log in. diff --git a/docs/auth/oauth2-proxy/provider.md b/docs/auth/oauth2-proxy/provider.md index dca074cc7d..0901685b2f 100644 --- a/docs/auth/oauth2-proxy/provider.md +++ b/docs/auth/oauth2-proxy/provider.md @@ -47,25 +47,27 @@ The resolvers will be tried in order, but will only be skipped if they throw a ` If these resolvers do not fit your needs you can build a custom resolver, this is covered in the [Building Custom Resolvers](../identity-resolver.md#building-custom-resolvers) section of the Sign-in Identities and Resolvers documentation. -## Adding the provider to the Backstage frontend +## Backend Installation -It is recommended to use the `ProxiedSignInPage` for this provider, which is -installed in `packages/app/src/App.tsx` like this: +To add the provider to the backend we will first need to install the package by running this command: -```tsx title="packages/app/src/App.tsx" -/* highlight-add-next-line */ -import { ProxiedSignInPage } from '@backstage/core-components'; - -const app = createApp({ - /* highlight-add-start */ - components: { - SignInPage: props => ( - - ), - }, - /* highlight-add-end */ - // .. -}); +```bash title="from your Backstage root directory" +yarn --cwd packages/backend add @backstage/plugin-auth-backend-module-oauth2-proxy-provider ``` -See [Sign-In with Proxy Providers](../index.md#sign-in-with-proxy-providers) for pointers on how to set up the sign-in page to also work smoothly for local development. +Then we will need to this line: + +```ts title="in packages/backend/src/index.ts" +backend.add(import('@backstage/plugin-auth-backend')); +/* highlight-add-start */ +backend.add( + import('@backstage/plugin-auth-backend-module-oauth2-proxy-provider'), +); +/* highlight-add-end */ +``` + +## Adding the provider to the Backstage frontend + +See [Sign-In with Proxy Providers](../index.md#sign-in-with-proxy-providers) for pointers on how to set up the sign-in page, and to also make it work smoothly for local development. You'll use `oauth2Proxy` as the provider name. + +If you [provide a custom sign in resolver](https://backstage.io/docs/auth/identity-resolver#building-custom-resolvers), you can skip the `signIn` block entirely. diff --git a/docs/auth/okta/provider.md b/docs/auth/okta/provider.md index 6fe7a8b992..77dace2289 100644 --- a/docs/auth/okta/provider.md +++ b/docs/auth/okta/provider.md @@ -83,6 +83,23 @@ The resolvers will be tried in order, but will only be skipped if they throw a ` If these resolvers do not fit your needs you can build a custom resolver, this is covered in the [Building Custom Resolvers](../identity-resolver.md#building-custom-resolvers) section of the Sign-in Identities and Resolvers documentation. +## Backend Installation + +To add the provider to the backend we will first need to install the package by running this command: + +```bash title="from your Backstage root directory" +yarn --cwd packages/backend add @backstage/plugin-auth-backend-module-okta-provider +``` + +Then we will need to add this line: + +```ts title="in packages/backend/src/index.ts" +backend.add(import('@backstage/plugin-auth-backend')); +/* highlight-add-start */ +backend.add(import('@backstage/plugin-auth-backend-module-okta-provider')); +/* highlight-add-end */ +``` + ## Adding the provider to the Backstage frontend To add the provider to the frontend, add the `oktaAuthApi` reference and diff --git a/docs/auth/onelogin/provider.md b/docs/auth/onelogin/provider.md index c3572367d2..9330a20332 100644 --- a/docs/auth/onelogin/provider.md +++ b/docs/auth/onelogin/provider.md @@ -38,6 +38,12 @@ auth: clientId: ${AUTH_ONELOGIN_CLIENT_ID} clientSecret: ${AUTH_ONELOGIN_CLIENT_SECRET} issuer: https://.onelogin.com/oidc/2 + signIn: + resolvers: + # typically you would pick one of these + - resolver: emailMatchingUserEntityProfileEmail + - resolver: emailLocalPartMatchingUserEntityName + - resolver: usernameMatchingUserEntityName ``` The OneLogin provider is a structure with three configuration keys; **these are @@ -47,6 +53,39 @@ found on the SSO tab** for the OneLogin Application: - `clientSecret`: The client secret - `issuer`: The issuer URL +### Resolvers + +This provider includes several resolvers out of the box that you can use: + +- `emailMatchingUserEntityProfileEmail`: Matches the email address from the auth provider with the User entity that has a matching `spec.profile.email`. If no match is found it will throw a `NotFoundError`. +- `emailLocalPartMatchingUserEntityName`: Matches the [local part](https://en.wikipedia.org/wiki/Email_address#Local-part) of the email address from the auth provider with the User entity that has a matching `name`. If no match is found it will throw a `NotFoundError`. +- `usernameMatchingUserEntityName`: Matches the username from the auth provider with the User entity that has a matching `name`. If no match is found it will throw a `NotFoundError`. + +:::note Note + +The resolvers will be tried in order, but will only be skipped if they throw a `NotFoundError`. + +::: + +If these resolvers do not fit your needs you can build a custom resolver, this is covered in the [Building Custom Resolvers](../identity-resolver.md#building-custom-resolvers) section of the Sign-in Identities and Resolvers documentation. + +## Backend Installation + +To add the provider to the backend we will first need to install the package by running this command: + +```bash title="from your Backstage root directory" +yarn --cwd packages/backend add @backstage/plugin-auth-backend-module-onelogin-provider +``` + +Then we will need to add this line: + +```ts title="in packages/backend/src/index.ts" +backend.add(import('@backstage/plugin-auth-backend')); +/* highlight-add-start */ +backend.add(import('@backstage/plugin-auth-backend-module-onelogin-provider')); +/* highlight-add-end */ +``` + ## Adding the provider to the Backstage frontend To add the provider to the frontend, add the `oneloginAuthApi` reference and diff --git a/docs/auth/vmware-cloud/provider.md b/docs/auth/vmware-cloud/provider.md index dd7c32f700..d79c84534a 100644 --- a/docs/auth/vmware-cloud/provider.md +++ b/docs/auth/vmware-cloud/provider.md @@ -33,108 +33,6 @@ Cloud Console and within a Backstage app required to enable this capability. 1. Take note of the `App ID` in the resulting modal; this is the client ID to be used by Backstage. -## Install the provider in the backend - -### New backend system - -Apps using the [new backend system](../../backend-system/index.md), -can enable the VMware Cloud provider with a small modification like: - -```ts title="packages/backend/src/index.ts" -import { createBackend } from '@backstage/backend-defaults'; - -const backend = createBackend(); -backend.add(import('@backstage/plugin-auth-backend')); -/* highlight-add-start */ -backend.add( - import('@backstage/plugin-auth-backend-module-vmware-cloud-provider'), -); -/* highlight-add-end */ -backend.start(); -``` - -### Old backend system - -This provider was added after the migration of the auth-backend plugin to the -new backend system, so no default provider factory was added. Because of this, -the installation procedure for old-style backends is slightly more involved: - -```ts title="packages/backend/src/plugins/auth.ts" -import { - DEFAULT_NAMESPACE, - stringifyEntityRef, -} from '@backstage/catalog-model'; -import { - createRouter, - providers, - defaultAuthProviderFactories, -} from '@backstage/plugin-auth-backend'; -import { Router } from 'express'; -import { PluginEnvironment } from '../types'; -/* highlight-add-start */ -import { - commonSignInResolvers, - createOAuthProviderFactory, -} from '@backstage/plugin-auth-node'; -import { - vmwareCloudAuthenticator, -} from '@backstage/plugin-auth-backend-module-vmware-cloud-provider'; -/* highlight-add-end */ - -export default async function createPlugin( - env: PluginEnvironment, -): Promise { - return await createRouter({ - logger: env.logger, - config: env.config, - database: env.database, - discovery: env.discovery, - tokenManager: env.tokenManager, - providerFactories: { - ...defaultAuthProviderFactories, - /* highlight-add-start */ - vmwareCloudServices: createOAuthProviderFactory({ - authenticator: vmwareCloudAuthenticator, - signInResolver: - commonSignInResolvers.emailLocalPartMatchingUserEntityName(), - }), - /* highlight-add-end */ -``` - -In the above, `commonSignInResolvers.emailLocalPartMatchingUserEntityName()` -can be replaced with a more suitable resolver for the app in question. - -## Add to Sign-in Page - -See the [Sign-In Configuration](../index.md#sign-in-configuration) docs for -general guidance, but as an example: - -```tsx title="packages/app/src/App.tsx" -/* highlight-add-start */ -import { vmwareCloudAuthApiRef } from '@backstage/core-plugin-api'; -import { SignInPage } from '@backstage/core-components'; -/* highlight-add-end */ - -const app = createApp({ - /* highlight-add-start */ - components: { - SignInPage: props => ( - - ), - }, - /* highlight-add-end */ - // .. -}); -``` - ## Configuration Add the following to your `app-config.yaml` under the root `auth` configuration: @@ -161,13 +59,17 @@ Where `APP_ID` refers to the ID retrieved when creating the OAuth App, and `ORG_ID` is the [long ID of the Organization](https://docs.vmware.com/en/VMware-Cloud-services/services/Using-VMware-Cloud-Services/GUID-CF9E9318-B811-48CF-8499-9419997DC1F8.html#view-the-organization-id-1) in VMware Cloud for which you wish to enable sign-in. -Note that VMware Cloud requires OAuth Apps to use +:::note Note + +VMware Cloud requires OAuth Apps to use [PKCE](https://oauth.net/2/pkce/) when performing authorization code flows; the library used by this provider requires the use of Express session middleware to do this. Therefore the value `your session secret` under `auth.session.secret` should be replaced with a long, complex and unique string which will act as a key for signing session cookies set by Backstage. +::: + ### Resolvers This provider includes several resolvers out of the box that you can use: @@ -183,3 +85,28 @@ The resolvers will be tried in order, but will only be skipped if they throw a ` ::: If these resolvers do not fit your needs you can build a custom resolver, this is covered in the [Building Custom Resolvers](../identity-resolver.md#building-custom-resolvers) section of the Sign-in Identities and Resolvers documentation. + +## Backend Installation + +To add the provider to the backend we will first need to install the package by running this command: + +```bash title="from your Backstage root directory" +yarn --cwd packages/backend add @backstage/plugin-auth-backend-module-vmware-cloud-provider +``` + +Then we will need to this line: + +```ts title="in packages/backend/src/index.ts" +backend.add(import('@backstage/plugin-auth-backend')); +/* highlight-add-start */ +backend.add( + import('@backstage/plugin-auth-backend-module-vmware-cloud-provider'), +); +/* highlight-add-end */ +``` + +## Adding the provider to the Backstage frontend + +To add the provider to the frontend, add the `vmwareCloudAuthApiRef` reference and +`SignInPage` component as shown in +[Adding the provider to the sign-in page](../index.md#adding-the-provider-to-the-sign-in-page). From 3e71b19711948fc4fb2de70423ef6c90b11da3aa Mon Sep 17 00:00:00 2001 From: Andre Wanlin Date: Fri, 5 Jul 2024 12:14:38 -0500 Subject: [PATCH 170/416] Fixed tests Signed-off-by: Andre Wanlin --- packages/create-app/src/lib/tasks.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/create-app/src/lib/tasks.test.ts b/packages/create-app/src/lib/tasks.test.ts index 38a09f7ac6..1f507b95ed 100644 --- a/packages/create-app/src/lib/tasks.test.ts +++ b/packages/create-app/src/lib/tasks.test.ts @@ -62,6 +62,7 @@ jest.mock('./versions', () => ({ '@backstage/plugin-auth-backend-module-github-provider': '1.0.0', '@backstage/plugin-auth-backend-module-guest-provider': '1.0.0', '@backstage/plugin-catalog-backend': '1.0.0', + '@backstage/plugin-catalog-backend-module-logs': '1.0.0', '@backstage/plugin-catalog-backend-module-scaffolder-entity-model': '1.0.0', '@backstage/plugin-permission-common': '1.0.0', '@backstage/plugin-permission-node': '1.0.0', From b4e401fd9ed99f379c6a2a5a3277cad3cab1d568 Mon Sep 17 00:00:00 2001 From: Andre Wanlin Date: Fri, 5 Jul 2024 13:32:46 -0500 Subject: [PATCH 171/416] Fixed links and MkDocs config Signed-off-by: Andre Wanlin --- docs/auth/atlassian/provider.md | 2 +- docs/auth/auth0/provider.md | 2 +- docs/auth/bitbucket/provider.md | 2 +- docs/auth/bitbucketServer/provider.md | 2 +- docs/auth/github/provider.md | 2 +- docs/auth/gitlab/provider.md | 2 +- docs/auth/google/provider.md | 2 +- docs/auth/microsoft/provider.md | 2 +- docs/auth/okta/provider.md | 2 +- docs/auth/onelogin/provider.md | 2 +- docs/auth/vmware-cloud/provider.md | 2 +- mkdocs.yml | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/auth/atlassian/provider.md b/docs/auth/atlassian/provider.md index 44f6d097b9..96271f04a0 100644 --- a/docs/auth/atlassian/provider.md +++ b/docs/auth/atlassian/provider.md @@ -100,4 +100,4 @@ backend.add(import('@backstage/plugin-auth-backend-module-atlassian-provider')); To add the provider to the frontend, add the `atlassianAuthApi` reference and `SignInPage` component as shown in -[Adding the provider to the sign-in page](../index.md#adding-the-provider-to-the-sign-in-page). +[Adding the provider to the sign-in page](../index.md#sign-in-configuration). diff --git a/docs/auth/auth0/provider.md b/docs/auth/auth0/provider.md index dcd02d226f..ae44114906 100644 --- a/docs/auth/auth0/provider.md +++ b/docs/auth/auth0/provider.md @@ -64,4 +64,4 @@ Auth0 requires a session, so you need to give the session a secret key. To add the provider to the frontend, add the `auth0AuthApi` reference and `SignInPage` component as shown in -[Adding the provider to the sign-in page](../index.md#adding-the-provider-to-the-sign-in-page). +[Adding the provider to the sign-in page](../index.md#sign-in-configuration). diff --git a/docs/auth/bitbucket/provider.md b/docs/auth/bitbucket/provider.md index 163647c790..1ca35437ba 100644 --- a/docs/auth/bitbucket/provider.md +++ b/docs/auth/bitbucket/provider.md @@ -90,4 +90,4 @@ backend.add(import('@backstage/plugin-auth-backend-module-bitbucket-provider')); To add the provider to the frontend, add the `bitbucketAuthApi` reference and `SignInPage` component as shown in -[Adding the provider to the sign-in page](../index.md#adding-the-provider-to-the-sign-in-page). +[Adding the provider to the sign-in page](../index.md#sign-in-configuration). diff --git a/docs/auth/bitbucketServer/provider.md b/docs/auth/bitbucketServer/provider.md index eef934ca60..82aebc20b2 100644 --- a/docs/auth/bitbucketServer/provider.md +++ b/docs/auth/bitbucketServer/provider.md @@ -37,7 +37,7 @@ The Bitbucket Server provider is a structure with two configuration keys: ## Adding the provider to the Backstage frontend To add the provider to the frontend, add the `bitbucketServerAuthApi` reference and `SignInPage` component as shown -in [Adding the provider to the sign-in page](../index.md#adding-the-provider-to-the-sign-in-page). +in [Adding the provider to the sign-in page](../index.md#sign-in-configuration). ## Using Bitbucket Server for sign-in diff --git a/docs/auth/github/provider.md b/docs/auth/github/provider.md index 801320299b..76b63c6617 100644 --- a/docs/auth/github/provider.md +++ b/docs/auth/github/provider.md @@ -108,4 +108,4 @@ backend.add(import('@backstage/plugin-auth-backend-module-github-provider')); To add the provider to the frontend, add the `githubAuthApi` reference and `SignInPage` component as shown in -[Adding the provider to the sign-in page](../index.md#adding-the-provider-to-the-sign-in-page). +[Adding the provider to the sign-in page](../index.md#sign-in-configuration). diff --git a/docs/auth/gitlab/provider.md b/docs/auth/gitlab/provider.md index e70953e11d..73546411bf 100644 --- a/docs/auth/gitlab/provider.md +++ b/docs/auth/gitlab/provider.md @@ -99,4 +99,4 @@ backend.add(import('@backstage/plugin-auth-backend-module-gitlab-provider')); To add the provider to the frontend, add the `gitlabAuthApi` reference and `SignInPage` component as shown in -[Adding the provider to the sign-in page](../index.md#adding-the-provider-to-the-sign-in-page). +[Adding the provider to the sign-in page](../index.md#sign-in-configuration). diff --git a/docs/auth/google/provider.md b/docs/auth/google/provider.md index e2efacfed2..b19d21d63f 100644 --- a/docs/auth/google/provider.md +++ b/docs/auth/google/provider.md @@ -93,4 +93,4 @@ backend.add(import('@backstage/plugin-auth-backend-module-google-provider')); To add the provider to the frontend, add the `googleAuthApi` reference and `SignInPage` component as shown in -[Adding the provider to the sign-in page](../index.md#adding-the-provider-to-the-sign-in-page). +[Adding the provider to the sign-in page](../index.md#sign-in-configuration). diff --git a/docs/auth/microsoft/provider.md b/docs/auth/microsoft/provider.md index aeec71213f..f799eeb627 100644 --- a/docs/auth/microsoft/provider.md +++ b/docs/auth/microsoft/provider.md @@ -125,4 +125,4 @@ backend.add(import('@backstage/plugin-auth-backend-module-microsoft-provider')); To add the provider to the frontend, add the `microsoftAuthApiRef` reference and `SignInPage` component as shown in -[Adding the provider to the sign-in page](../index.md#adding-the-provider-to-the-sign-in-page). +[Adding the provider to the sign-in page](../index.md#sign-in-configuration). diff --git a/docs/auth/okta/provider.md b/docs/auth/okta/provider.md index 77dace2289..83352aaa0d 100644 --- a/docs/auth/okta/provider.md +++ b/docs/auth/okta/provider.md @@ -104,4 +104,4 @@ backend.add(import('@backstage/plugin-auth-backend-module-okta-provider')); To add the provider to the frontend, add the `oktaAuthApi` reference and `SignInPage` component as shown in -[Adding the provider to the sign-in page](../index.md#adding-the-provider-to-the-sign-in-page). +[Adding the provider to the sign-in page](../index.md#sign-in-configuration). diff --git a/docs/auth/onelogin/provider.md b/docs/auth/onelogin/provider.md index 9330a20332..002445a9d1 100644 --- a/docs/auth/onelogin/provider.md +++ b/docs/auth/onelogin/provider.md @@ -90,4 +90,4 @@ backend.add(import('@backstage/plugin-auth-backend-module-onelogin-provider')); To add the provider to the frontend, add the `oneloginAuthApi` reference and `SignInPage` component as shown in -[Adding the provider to the sign-in page](../index.md#adding-the-provider-to-the-sign-in-page). +[Adding the provider to the sign-in page](../index.md#sign-in-configuration). diff --git a/docs/auth/vmware-cloud/provider.md b/docs/auth/vmware-cloud/provider.md index d79c84534a..ac2cf3ee92 100644 --- a/docs/auth/vmware-cloud/provider.md +++ b/docs/auth/vmware-cloud/provider.md @@ -109,4 +109,4 @@ backend.add( To add the provider to the frontend, add the `vmwareCloudAuthApiRef` reference and `SignInPage` component as shown in -[Adding the provider to the sign-in page](../index.md#adding-the-provider-to-the-sign-in-page). +[Adding the provider to the sign-in page](../index.md#sign-in-configuration). diff --git a/mkdocs.yml b/mkdocs.yml index b9f6d41d46..f163005377 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -158,7 +158,7 @@ nav: - Azure EasyAuth: 'auth/microsoft/azure-easyauth.md' - Bitbucket: 'auth/bitbucket/provider.md' - Bitbucket Server: 'auth/bitbucketServer/provider.md' - - Cloudflare Access: 'auth/cloudflare/access.md' + - Cloudflare Access: 'auth/cloudflare/provider.md' - GitHub: 'auth/github/provider.md' - GitLab: 'auth/gitlab/provider.md' - Google: 'auth/google/provider.md' From 401e892bafc3927acd87213b69712144dbef1603 Mon Sep 17 00:00:00 2001 From: Andre Wanlin Date: Fri, 5 Jul 2024 13:49:45 -0500 Subject: [PATCH 172/416] Fixed more links Signed-off-by: Andre Wanlin --- docs/auth/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/auth/index.md b/docs/auth/index.md index f925e52917..4a0e56a36e 100644 --- a/docs/auth/index.md +++ b/docs/auth/index.md @@ -31,7 +31,7 @@ Backstage comes with many common authentication providers in the core library: - [Azure Easy Auth](microsoft/azure-easyauth.md) - [Bitbucket](bitbucket/provider.md) - [Bitbucket Server](bitbucketServer/provider.md) -- [Cloudflare Access](cloudflare/access.md) +- [Cloudflare Access](cloudflare/provider.md) - [GitHub](github/provider.md) - [GitLab](gitlab/provider.md) - [Google](google/provider.md) @@ -158,7 +158,7 @@ Some auth providers are so-called "proxy" providers, meaning they're meant to be behind an authentication proxy. Examples of these are [Amazon Application Load Balancer](https://github.com/backstage/backstage/blob/master/contrib/docs/tutorials/aws-alb-aad-oidc-auth.md), [Azure EasyAuth](./microsoft/azure-easyauth.md), -[Cloudflare Access](./cloudflare/access.md), +[Cloudflare Access](./cloudflare/provider.md), [Google Identity-Aware Proxy](./google/gcp-iap-auth.md) and [OAuth2 Proxy](./oauth2-proxy/provider.md). From a835d6f644d10fb7b7334e7749e7824f34bb8e46 Mon Sep 17 00:00:00 2001 From: Adam Harvey <33203301+adamdmharvey@users.noreply.github.com> Date: Fri, 5 Jul 2024 22:40:33 -0400 Subject: [PATCH 173/416] chore(docs): Fix broken Note admonition Signed-off-by: Adam Harvey <33203301+adamdmharvey@users.noreply.github.com> --- docs/integrations/github/github-apps.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/integrations/github/github-apps.md b/docs/integrations/github/github-apps.md index b5e252be74..298eba26e3 100644 --- a/docs/integrations/github/github-apps.md +++ b/docs/integrations/github/github-apps.md @@ -109,8 +109,8 @@ integrations: webhookSecret: ${AUTH_ORG_WEBHOOK_SECRET} ``` -:::Note -Note that in both examples above `apps` is an array which means you can add multiple GitHub Apps using `$include` or environment variables as long as they are each for a different GitHub Org as mentioned under the [Caveats](#caveats) section +:::note +Note that in both examples above `apps` is an array which means you can add multiple GitHub Apps using `$include` or environment variables as long as they are each for a different GitHub Org as mentioned under the [Caveats](#caveats) section. ::: ## Limiting the GitHub App installations From 583715dbbe375fe54d9feb8fee3153e5876ecd33 Mon Sep 17 00:00:00 2001 From: Adam Harvey <33203301+adamdmharvey@users.noreply.github.com> Date: Fri, 5 Jul 2024 23:33:03 -0400 Subject: [PATCH 174/416] chore: Fix comment typo Signed-off-by: Adam Harvey <33203301+adamdmharvey@users.noreply.github.com> --- packages/repo-tools/src/commands/api-reports/api-extractor.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 6a523af6a9..c3054dffe9 100644 --- a/packages/repo-tools/src/commands/api-reports/api-extractor.ts +++ b/packages/repo-tools/src/commands/api-reports/api-extractor.ts @@ -145,7 +145,7 @@ ApiReportGenerator.generateReviewFileContent = if (!localName) { // Sometimes the symbol name is suffixed with a number to disambiguate, // e.g. "Props_14" instead of "Props" if there are multiple Props interfaces - // so we tyry to strip that suffix and look up the symbol again. + // so we try to strip that suffix and look up the symbol again. const [, trimmedSymbolName] = symbolName.match(/(.*)_\d+/) || []; localName = (sourceFile as any).identifiers?.get(trimmedSymbolName); } @@ -1101,6 +1101,7 @@ export async function buildDocs({ switch (hierarchyItem.kind) { case ApiItemKind.Model: case ApiItemKind.EntryPoint: + case ApiItemKind.None: // We don't show the model as part of the breadcrumb because it is the root-level container. // We don't show the entry point because today API Extractor doesn't support multiple entry points; // this may change in the future. From c3837fb3fca523d296b9024c5dd8c80a5f207e1f Mon Sep 17 00:00:00 2001 From: Adam Harvey <33203301+adamdmharvey@users.noreply.github.com> Date: Fri, 5 Jul 2024 23:34:33 -0400 Subject: [PATCH 175/416] chore: Fix invalid API docs cross-reference Signed-off-by: Adam Harvey <33203301+adamdmharvey@users.noreply.github.com> --- plugins/permission-node/src/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/permission-node/src/types.ts b/plugins/permission-node/src/types.ts index 36e30714f6..0a7e06ed91 100644 --- a/plugins/permission-node/src/types.ts +++ b/plugins/permission-node/src/types.ts @@ -23,7 +23,7 @@ import { NoInfer } from './integration/util'; /** * A conditional rule that can be provided in an - * {@link @backstage/permission-common#AuthorizeDecision} response to an authorization request. + * {@link @backstage/plugin-permission-common#AuthorizeDecision} response to an authorization request. * * @remarks * From 09086e8d0ae82ca18f1e2a476bff60278af872f6 Mon Sep 17 00:00:00 2001 From: Adam Harvey <33203301+adamdmharvey@users.noreply.github.com> Date: Fri, 5 Jul 2024 23:34:53 -0400 Subject: [PATCH 176/416] chore: Add packageDocumentation for API Docs Index Signed-off-by: Adam Harvey <33203301+adamdmharvey@users.noreply.github.com> --- plugins/permission-react/api-report.md | 2 -- plugins/permission-react/src/index.ts | 5 +++++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/plugins/permission-react/api-report.md b/plugins/permission-react/api-report.md index 3c1961c92c..4c51d16b80 100644 --- a/plugins/permission-react/api-report.md +++ b/plugins/permission-react/api-report.md @@ -100,6 +100,4 @@ export function usePermission( resourceRef: string | undefined; }, ): AsyncPermissionResult; - -// (No @packageDocumentation comment for this package) ``` diff --git a/plugins/permission-react/src/index.ts b/plugins/permission-react/src/index.ts index 57352c5cdd..de6958b3e5 100644 --- a/plugins/permission-react/src/index.ts +++ b/plugins/permission-react/src/index.ts @@ -14,6 +14,11 @@ * limitations under the License. */ +/** + * Components and hooks to help implement permissions in Backstage frontend plugins. + * + * @packageDocumentation + */ export * from './components'; export * from './hooks'; export * from './apis'; From 28b2cfb08cf1bc88107ef61d344b687febfd2bed Mon Sep 17 00:00:00 2001 From: Adam Harvey <33203301+adamdmharvey@users.noreply.github.com> Date: Fri, 5 Jul 2024 23:37:30 -0400 Subject: [PATCH 177/416] chore: Add changesets Signed-off-by: Adam Harvey <33203301+adamdmharvey@users.noreply.github.com> --- .changeset/famous-clocks-visit.md | 5 +++++ .changeset/tender-turkeys-begin.md | 5 +++++ 2 files changed, 10 insertions(+) create mode 100644 .changeset/famous-clocks-visit.md create mode 100644 .changeset/tender-turkeys-begin.md diff --git a/.changeset/famous-clocks-visit.md b/.changeset/famous-clocks-visit.md new file mode 100644 index 0000000000..66c2048872 --- /dev/null +++ b/.changeset/famous-clocks-visit.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-permission-node': patch +--- + +Fix invalid cross-reference in API Reference docs diff --git a/.changeset/tender-turkeys-begin.md b/.changeset/tender-turkeys-begin.md new file mode 100644 index 0000000000..26e376cecf --- /dev/null +++ b/.changeset/tender-turkeys-begin.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-permission-react': patch +--- + +Improve API Reference documentation From 518616d4c9f13eeaef816a9dfa8ce9b95a07e773 Mon Sep 17 00:00:00 2001 From: Adam Harvey <33203301+adamdmharvey@users.noreply.github.com> Date: Sat, 6 Jul 2024 00:14:44 -0400 Subject: [PATCH 178/416] chore: Remove testing Signed-off-by: Adam Harvey <33203301+adamdmharvey@users.noreply.github.com> --- packages/repo-tools/src/commands/api-reports/api-extractor.ts | 1 - 1 file changed, 1 deletion(-) 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 c3054dffe9..122f04cc7e 100644 --- a/packages/repo-tools/src/commands/api-reports/api-extractor.ts +++ b/packages/repo-tools/src/commands/api-reports/api-extractor.ts @@ -1101,7 +1101,6 @@ export async function buildDocs({ switch (hierarchyItem.kind) { case ApiItemKind.Model: case ApiItemKind.EntryPoint: - case ApiItemKind.None: // We don't show the model as part of the breadcrumb because it is the root-level container. // We don't show the entry point because today API Extractor doesn't support multiple entry points; // this may change in the future. From ad8f60b1f74761558f65b777f593db6ba2d88c47 Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Mon, 8 Jul 2024 10:59:17 +0200 Subject: [PATCH 179/416] chore: add DPG Media as an adopter Signed-off-by: Benjamin Janssens --- ADOPTERS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/ADOPTERS.md b/ADOPTERS.md index 3ff0c5e1b5..c1b1686ccc 100644 --- a/ADOPTERS.md +++ b/ADOPTERS.md @@ -272,3 +272,4 @@ _You can do this by using the [Adopter form](https://info.backstage.spotify.com/ | [Senora.dev](https://senora.dev) | [Shaked Braimok Yosef](https://github.com/ShakedBraimok) | We are using Backstage as a service catalog for our costumers. | | [Covestro](https://www.covestro.com) | [Julien Gedeon](https://github.com/cvvcv1) | We use Backstage as our Internal developer portal for the Digital R&D department. | | [Grupo OLX](https://www.olx.com.br/) | [@marciorgb](https://github.com/marciorgb), [@jeffbraga](https://github.com/jeffbraga), [@rogerfernandes](https://github.com/rogerfernandes), [@stockrt](https://github.com/stockrt) | At Grupo OLX, we are using Backstage to reduce friction and enhance developer autonomy by creating Golden Paths, which automate previously manual processes. Additionally, Backstage's catalog integrates various views of our organizational structure and workflows, offering a comprehensive overview of how different components interconnect. | +| [DPG Media](https://www.dpgmediagroup.com) | [@benjidotsh](https://github.com/benjidotsh), [@lvstb](https://github.com/lvstb), [@ssliman](https://github.com/ssliman), [@edewel-beep](https://github.com/edewel-beep) | Access to infrastructure, documentation and internal tooling | From bc2700cbf962e3f3a4554d664a193943224b3f27 Mon Sep 17 00:00:00 2001 From: Chap Ambrose Date: Mon, 8 Jul 2024 08:26:47 -0500 Subject: [PATCH 180/416] recommend updating config in app-config.production.yaml Co-authored-by: Andre Wanlin <67169551+awanlin@users.noreply.github.com> Signed-off-by: Chap Ambrose --- docs/deployment/heroku.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/deployment/heroku.md b/docs/deployment/heroku.md index a70ff66ca5..23dff683f8 100644 --- a/docs/deployment/heroku.md +++ b/docs/deployment/heroku.md @@ -32,7 +32,7 @@ $ heroku domains -a .herokuapp.com ``` -Update `baseUrl` and `port` in `app-config.yaml`. The core [app-backend plugin](https://www.npmjs.com/package/@backstage/plugin-app-backend) allows a single Heroku app to serve the frontend and backend: +The core [app-backend plugin](https://www.npmjs.com/package/@backstage/plugin-app-backend) allows a single Heroku app to serve the frontend and backend. To make this work you need to update the `baseUrl` and `port` in `app-config.production.yaml`: ```yaml app: baseUrl: https://.herokuapp.com From fb6a5d5f6ba90edb6152c20d4c111b93a9182d16 Mon Sep 17 00:00:00 2001 From: Chap Ambrose Date: Mon, 8 Jul 2024 08:27:20 -0500 Subject: [PATCH 181/416] Typo in docs Co-authored-by: Andre Wanlin <67169551+awanlin@users.noreply.github.com> Signed-off-by: Chap Ambrose --- docs/deployment/heroku.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/deployment/heroku.md b/docs/deployment/heroku.md index 23dff683f8..5e6eb59a82 100644 --- a/docs/deployment/heroku.md +++ b/docs/deployment/heroku.md @@ -9,7 +9,7 @@ Heroku is a Platform as a Service (PaaS) designed to simplify application deploy ## Create App -Start with an exisiting Backstage app or follow the [getting started guide](https://backstage.io/docs/getting-started/) to create a new one: +Starting with an existing Backstage app or follow the [getting started guide](https://backstage.io/docs/getting-started/) to create a new one: ```shell $ npx @backstage/create-app@latest From 6b56a1921925517006e8cbdecffccc3f74814916 Mon Sep 17 00:00:00 2001 From: Chap Ambrose Date: Mon, 8 Jul 2024 08:27:45 -0500 Subject: [PATCH 182/416] add app-config.production to build script Co-authored-by: Andre Wanlin <67169551+awanlin@users.noreply.github.com> Signed-off-by: Chap Ambrose --- docs/deployment/heroku.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/deployment/heroku.md b/docs/deployment/heroku.md index 5e6eb59a82..c5042c732c 100644 --- a/docs/deployment/heroku.md +++ b/docs/deployment/heroku.md @@ -51,7 +51,7 @@ backend: Add a build script in `package.json` to compile frontend during deployment: ```json "scripts": { - "build": "yarn build:backend --config ../../app-config.yaml" + "build": "yarn build:backend --config ../../app-config.yaml --config app-config.production.yaml" ``` ## Start Command From 32b73f957c7ee8379e190f66640a4a9ec7ced9ab Mon Sep 17 00:00:00 2001 From: Chap Ambrose Date: Mon, 8 Jul 2024 08:32:26 -0500 Subject: [PATCH 183/416] remove command to create new backstage app Signed-off-by: Chap Ambrose --- docs/deployment/heroku.md | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/docs/deployment/heroku.md b/docs/deployment/heroku.md index c5042c732c..9629dbb212 100644 --- a/docs/deployment/heroku.md +++ b/docs/deployment/heroku.md @@ -9,12 +9,7 @@ Heroku is a Platform as a Service (PaaS) designed to simplify application deploy ## Create App -Starting with an existing Backstage app or follow the [getting started guide](https://backstage.io/docs/getting-started/) to create a new one: - -```shell -$ npx @backstage/create-app@latest - Enter a name -``` +Starting with an existing Backstage app or follow the [getting started guide](https://backstage.io/docs/getting-started/) to create a new one. Install the [Heroku CLI](https://devcenter.heroku.com/articles/heroku-cli) and create a new Heroku app: From e80a94f5c31aad63840c36bf592a072310d787c2 Mon Sep 17 00:00:00 2001 From: Chap Ambrose Date: Mon, 8 Jul 2024 09:50:17 -0500 Subject: [PATCH 184/416] add docker instructions to heroku.md Signed-off-by: Chap Ambrose --- docs/deployment/heroku.md | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/docs/deployment/heroku.md b/docs/deployment/heroku.md index 9629dbb212..8f173578c5 100644 --- a/docs/deployment/heroku.md +++ b/docs/deployment/heroku.md @@ -46,14 +46,14 @@ backend: Add a build script in `package.json` to compile frontend during deployment: ```json "scripts": { - "build": "yarn build:backend --config ../../app-config.yaml --config app-config.production.yaml" + "build": "yarn build:backend --config ../../app-config.yaml --config ../../app-config.production.yaml" ``` ## Start Command Create a [Procfile](https://devcenter.heroku.com/articles/procfile) in the app's root: ```shell -$ echo "web: yarn workspace backend start --config ../../app-config.yaml" > Procfile +$ echo "web: yarn workspace backend start --config ../../app-config.yaml --config ../../app-config.production.yaml" > Procfile ``` ## Database @@ -63,7 +63,7 @@ Provision a [Heroku Postgres](https://elements.heroku.com/addons/heroku-postgres $ heroku addons:create heroku-postgresql -a ``` -Update `database` in `app-config.yaml`: +Update `database` in `app-config.production.yaml`: ```yaml backend: database: @@ -99,3 +99,33 @@ View logs: ```shell $ heroku heroku -a ``` + +## Docker + +As an alternative to git deploys, Heroku also [supports container images](https://devcenter.heroku.com/articles/container-registry-and-runtime). + +Login to Heroku's container registry: + +```shell +$ heroku container:login +``` + +Configure the Heroku app to run a container image: + +```shell +$ heroku stack:set container -a +``` + +Locally run the [host build command](https://backstage.io/docs/deployment/docker/#host-build): +```shell +$ yarn build:backend --config ../../app-config.yaml --config ../../app-config.production.yaml +``` + +Build, push, and release the container image: +```shell +$ docker image build . -f packages/backend/Dockerfile --tag registry.heroku.com//web + +$ docker push registry.heroku.com//web + +$ heroku container:release web -a +``` From 9ddbd8c729bf96a36d6642459e3a326e7f8bb6d5 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 8 Jul 2024 17:09:53 +0200 Subject: [PATCH 185/416] search: add missing createApiFactory Signed-off-by: Patrik Oldsberg --- plugins/search/src/alpha.tsx | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/plugins/search/src/alpha.tsx b/plugins/search/src/alpha.tsx index c202d58712..838fb95046 100644 --- a/plugins/search/src/alpha.tsx +++ b/plugins/search/src/alpha.tsx @@ -31,10 +31,9 @@ import { } from '@backstage/core-components'; import { useApi, - DiscoveryApi, discoveryApiRef, fetchApiRef, - FetchApi, + createApiFactory, } from '@backstage/core-plugin-api'; import { @@ -77,17 +76,12 @@ import { /** @alpha */ export const searchApi = createApiExtension({ - factory: { + factory: createApiFactory({ api: searchApiRef, deps: { discoveryApi: discoveryApiRef, fetchApi: fetchApiRef }, - factory: ({ - fetchApi, - discoveryApi, - }: { - fetchApi: FetchApi; - discoveryApi: DiscoveryApi; - }) => new SearchClient({ discoveryApi, fetchApi }), - }, + factory: ({ discoveryApi, fetchApi }) => + new SearchClient({ discoveryApi, fetchApi }), + }), }); const useSearchPageStyles = makeStyles((theme: Theme) => ({ From dc41795dd508275e8d95a89b81861dd1ea636500 Mon Sep 17 00:00:00 2001 From: Chap Ambrose Date: Mon, 8 Jul 2024 11:15:28 -0500 Subject: [PATCH 186/416] prettier fixes Signed-off-by: Chap Ambrose --- docs/deployment/heroku.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/deployment/heroku.md b/docs/deployment/heroku.md index 8f173578c5..74732bb431 100644 --- a/docs/deployment/heroku.md +++ b/docs/deployment/heroku.md @@ -22,12 +22,14 @@ $ heroku apps:create ## Domain Get Heroku app URL: + ```shell $ heroku domains -a .herokuapp.com ``` The core [app-backend plugin](https://www.npmjs.com/package/@backstage/plugin-app-backend) allows a single Heroku app to serve the frontend and backend. To make this work you need to update the `baseUrl` and `port` in `app-config.production.yaml`: + ```yaml app: baseUrl: https://.herokuapp.com @@ -44,6 +46,7 @@ backend: ## Build Script Add a build script in `package.json` to compile frontend during deployment: + ```json "scripts": { "build": "yarn build:backend --config ../../app-config.yaml --config ../../app-config.production.yaml" @@ -52,6 +55,7 @@ Add a build script in `package.json` to compile frontend during deployment: ## Start Command Create a [Procfile](https://devcenter.heroku.com/articles/procfile) in the app's root: + ```shell $ echo "web: yarn workspace backend start --config ../../app-config.yaml --config ../../app-config.production.yaml" > Procfile ``` @@ -59,11 +63,13 @@ $ echo "web: yarn workspace backend start --config ../../app-config.yaml --confi ## Database Provision a [Heroku Postgres](https://elements.heroku.com/addons/heroku-postgresql) database: + ```shell $ heroku addons:create heroku-postgresql -a ``` Update `database` in `app-config.production.yaml`: + ```yaml backend: database: @@ -75,6 +81,7 @@ backend: ``` Allow postgres self-signed certificates: + ```shell $ heroku config:set PGSSLMODE=no-verify -a ``` @@ -117,11 +124,13 @@ $ heroku stack:set container -a ``` Locally run the [host build command](https://backstage.io/docs/deployment/docker/#host-build): + ```shell $ yarn build:backend --config ../../app-config.yaml --config ../../app-config.production.yaml ``` Build, push, and release the container image: + ```shell $ docker image build . -f packages/backend/Dockerfile --tag registry.heroku.com//web From 0b6d31a56b530d92a6881174b91ed7036e4ea169 Mon Sep 17 00:00:00 2001 From: David Weber Date: Mon, 8 Jul 2024 18:55:40 +0200 Subject: [PATCH 187/416] docs: add Baloise as adaptor Signed-off-by: David Weber Signed-off-by: David Weber --- ADOPTERS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/ADOPTERS.md b/ADOPTERS.md index c1b1686ccc..870b4c93d4 100644 --- a/ADOPTERS.md +++ b/ADOPTERS.md @@ -273,3 +273,4 @@ _You can do this by using the [Adopter form](https://info.backstage.spotify.com/ | [Covestro](https://www.covestro.com) | [Julien Gedeon](https://github.com/cvvcv1) | We use Backstage as our Internal developer portal for the Digital R&D department. | | [Grupo OLX](https://www.olx.com.br/) | [@marciorgb](https://github.com/marciorgb), [@jeffbraga](https://github.com/jeffbraga), [@rogerfernandes](https://github.com/rogerfernandes), [@stockrt](https://github.com/stockrt) | At Grupo OLX, we are using Backstage to reduce friction and enhance developer autonomy by creating Golden Paths, which automate previously manual processes. Additionally, Backstage's catalog integrates various views of our organizational structure and workflows, offering a comprehensive overview of how different components interconnect. | | [DPG Media](https://www.dpgmediagroup.com) | [@benjidotsh](https://github.com/benjidotsh), [@lvstb](https://github.com/lvstb), [@ssliman](https://github.com/ssliman), [@edewel-beep](https://github.com/edewel-beep) | Access to infrastructure, documentation and internal tooling | +| [Baloise](https://www.baloise.ch) | [@dweber019](https://github.com/dweber019), [@mikevader](https://github.com/mikevader) | We are using Backstage as internal developer protal for use cases like software catalog, documentation, infrastructure. | From b9832aee3d57c40de8e77e35275eff5acfe8d1de Mon Sep 17 00:00:00 2001 From: Olivier Liechti Date: Tue, 9 Jul 2024 09:55:58 +0200 Subject: [PATCH 188/416] Fix issues described in #25551 Signed-off-by: Olivier Liechti --- .changeset/chilly-rabbits-sneeze.md | 5 +++ .../src/authenticator.test.ts | 40 +++++++++++++++++ .../src/authenticator.ts | 44 +++++++++++++++---- .../src/types.d.ts | 3 +- 4 files changed, 83 insertions(+), 9 deletions(-) create mode 100644 .changeset/chilly-rabbits-sneeze.md create mode 100644 plugins/auth-backend-module-atlassian-provider/src/authenticator.test.ts diff --git a/.changeset/chilly-rabbits-sneeze.md b/.changeset/chilly-rabbits-sneeze.md new file mode 100644 index 0000000000..cbce80ebbc --- /dev/null +++ b/.changeset/chilly-rabbits-sneeze.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-auth-backend-module-atlassian-provider': patch +--- + +Fix several issues with the Atlassian auth provider (type definition, profile url, profile transformation, scopes) diff --git a/plugins/auth-backend-module-atlassian-provider/src/authenticator.test.ts b/plugins/auth-backend-module-atlassian-provider/src/authenticator.test.ts new file mode 100644 index 0000000000..b8e9e1ad75 --- /dev/null +++ b/plugins/auth-backend-module-atlassian-provider/src/authenticator.test.ts @@ -0,0 +1,40 @@ +/* + * Copyright 2024 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 Strategy from 'passport-atlassian-oauth2'; + +describe('Strategy', () => { + it('should be an instance of', () => { + try { + console.log(Strategy); + const strategy = new Strategy( + { + authorizationURL: 'https://auth.atlassian.com/authorize', + tokenURL: 'https://auth.atlassian.com/oauth/token', + clientID: 'my-client-id', + clientSecret: 'my-client-secret', + scope: ['offline_access', 'read:jira-work', 'read:jira-user'], + }, + () => {}, + ); + console.log(strategy.name); + expect(strategy).toBeInstanceOf(Strategy); + + expect((strategy as any).name).toBe('atlassian'); + } catch (e) { + console.error(e); + } + }); +}); diff --git a/plugins/auth-backend-module-atlassian-provider/src/authenticator.ts b/plugins/auth-backend-module-atlassian-provider/src/authenticator.ts index 0ced9cf831..ab2cd3f94a 100644 --- a/plugins/auth-backend-module-atlassian-provider/src/authenticator.ts +++ b/plugins/auth-backend-module-atlassian-provider/src/authenticator.ts @@ -20,14 +20,35 @@ import { PassportOAuthDoneCallback, PassportProfile, } from '@backstage/plugin-auth-node'; -import { Strategy as AtlassianStrategy } from 'passport-atlassian-oauth2'; +import AtlassianStrategy from 'passport-atlassian-oauth2'; + +export type AtlassianPassportProfile = { + id: string; + displayName: string; + email: string; + photo: string; + provider: string; + _json: any; +}; /** @public */ -export const atlassianAuthenticator = createOAuthAuthenticator({ - defaultProfileTransform: - PassportOAuthAuthenticatorHelper.defaultProfileTransform, +export const atlassianAuthenticator = createOAuthAuthenticator< + any, + AtlassianPassportProfile +>({ + defaultProfileTransform: async (input, context) => { + // const result = await PassportOAuthAuthenticatorHelper.defaultProfileTransform(input, context); + + return { + profile: { + displayName: input.fullProfile.displayName, + email: input.fullProfile.email, + picture: input.fullProfile.photo, + }, + }; + }, scopes: { - required: ['offline_access', 'read:jira-work', 'read:jira-user'], + required: ['offline_access', 'read:me', 'read:jira-work', 'read:jira-user'], }, initialize({ callbackUrl, config }) { const clientId = config.getString('clientId'); @@ -49,18 +70,25 @@ export const atlassianAuthenticator = createOAuthAuthenticator({ baseURL: baseUrl, authorizationURL: `${baseUrl}/authorize`, tokenURL: `${baseUrl}/oauth/token`, - profileURL: `${baseUrl}/api/v4/user`, + // profileURL: `${baseUrl}/api/v4/user`, + profileURL: 'https://api.atlassian.com/me', + scope: config.getOptionalString('additionalScopes')?.split(' ') || [], }, ( accessToken: string, refreshToken: string, params: any, - fullProfile: PassportProfile, + fullProfile: PassportProfile & { email: string; photo: string }, done: PassportOAuthDoneCallback, ) => { + const fullProfileWithEmails = { + ...fullProfile, + // avatarUrl: fullProfile.photo, + // emails: [{ value: fullProfile.email }], + }; done( undefined, - { fullProfile, params, accessToken }, + { fullProfile: fullProfileWithEmails, params, accessToken }, { refreshToken }, ); }, diff --git a/plugins/auth-backend-module-atlassian-provider/src/types.d.ts b/plugins/auth-backend-module-atlassian-provider/src/types.d.ts index 5fd47bf885..aa945f3705 100644 --- a/plugins/auth-backend-module-atlassian-provider/src/types.d.ts +++ b/plugins/auth-backend-module-atlassian-provider/src/types.d.ts @@ -18,8 +18,9 @@ declare module 'passport-atlassian-oauth2' { import { Request } from 'express'; import { StrategyCreated } from 'passport'; - export class Strategy { + export default class Strategy { constructor(options: any, verify: any); + name?: string; authenticate(this: StrategyCreated, req: Request, options?: any): any; } } From be5f08f3a8474cb428ddaf0f6b2fe6b61b27fdaa Mon Sep 17 00:00:00 2001 From: Olivier Liechti Date: Tue, 9 Jul 2024 10:20:17 +0200 Subject: [PATCH 189/416] Cleaning up details Signed-off-by: Olivier Liechti --- .../src/authenticator.test.ts | 3 --- .../src/authenticator.ts | 8 +------- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/plugins/auth-backend-module-atlassian-provider/src/authenticator.test.ts b/plugins/auth-backend-module-atlassian-provider/src/authenticator.test.ts index b8e9e1ad75..cb723ecece 100644 --- a/plugins/auth-backend-module-atlassian-provider/src/authenticator.test.ts +++ b/plugins/auth-backend-module-atlassian-provider/src/authenticator.test.ts @@ -29,9 +29,6 @@ describe('Strategy', () => { }, () => {}, ); - console.log(strategy.name); - expect(strategy).toBeInstanceOf(Strategy); - expect((strategy as any).name).toBe('atlassian'); } catch (e) { console.error(e); diff --git a/plugins/auth-backend-module-atlassian-provider/src/authenticator.ts b/plugins/auth-backend-module-atlassian-provider/src/authenticator.ts index ab2cd3f94a..ff020f131d 100644 --- a/plugins/auth-backend-module-atlassian-provider/src/authenticator.ts +++ b/plugins/auth-backend-module-atlassian-provider/src/authenticator.ts @@ -70,7 +70,6 @@ export const atlassianAuthenticator = createOAuthAuthenticator< baseURL: baseUrl, authorizationURL: `${baseUrl}/authorize`, tokenURL: `${baseUrl}/oauth/token`, - // profileURL: `${baseUrl}/api/v4/user`, profileURL: 'https://api.atlassian.com/me', scope: config.getOptionalString('additionalScopes')?.split(' ') || [], }, @@ -81,14 +80,9 @@ export const atlassianAuthenticator = createOAuthAuthenticator< fullProfile: PassportProfile & { email: string; photo: string }, done: PassportOAuthDoneCallback, ) => { - const fullProfileWithEmails = { - ...fullProfile, - // avatarUrl: fullProfile.photo, - // emails: [{ value: fullProfile.email }], - }; done( undefined, - { fullProfile: fullProfileWithEmails, params, accessToken }, + { fullProfile, params, accessToken }, { refreshToken }, ); }, From f7cf3a2a875f833c63dbab687b77b28eeb991f67 Mon Sep 17 00:00:00 2001 From: Olivier Liechti Date: Tue, 9 Jul 2024 10:30:26 +0200 Subject: [PATCH 190/416] Cleaning up details Signed-off-by: Olivier Liechti --- .../auth-backend-module-atlassian-provider/src/authenticator.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/auth-backend-module-atlassian-provider/src/authenticator.ts b/plugins/auth-backend-module-atlassian-provider/src/authenticator.ts index ff020f131d..1e7b631493 100644 --- a/plugins/auth-backend-module-atlassian-provider/src/authenticator.ts +++ b/plugins/auth-backend-module-atlassian-provider/src/authenticator.ts @@ -77,7 +77,7 @@ export const atlassianAuthenticator = createOAuthAuthenticator< accessToken: string, refreshToken: string, params: any, - fullProfile: PassportProfile & { email: string; photo: string }, + fullProfile: AtlassianPassportProfile, done: PassportOAuthDoneCallback, ) => { done( From 3cdea7aa1e38893c239d71b2ac073457ffe059ff Mon Sep 17 00:00:00 2001 From: Olivier Liechti Date: Tue, 9 Jul 2024 12:12:58 +0200 Subject: [PATCH 191/416] Fix typescript typing issues Signed-off-by: Olivier Liechti --- .../src/authenticator.ts | 32 +++++++++++-------- .../src/module.ts | 7 ++-- 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/plugins/auth-backend-module-atlassian-provider/src/authenticator.ts b/plugins/auth-backend-module-atlassian-provider/src/authenticator.ts index 1e7b631493..8a1b952d15 100644 --- a/plugins/auth-backend-module-atlassian-provider/src/authenticator.ts +++ b/plugins/auth-backend-module-atlassian-provider/src/authenticator.ts @@ -16,9 +16,10 @@ import { createOAuthAuthenticator, + OAuthAuthenticatorResult, PassportOAuthAuthenticatorHelper, PassportOAuthDoneCallback, - PassportProfile, + ProfileInfo, } from '@backstage/plugin-auth-node'; import AtlassianStrategy from 'passport-atlassian-oauth2'; @@ -32,19 +33,20 @@ export type AtlassianPassportProfile = { }; /** @public */ -export const atlassianAuthenticator = createOAuthAuthenticator< - any, - AtlassianPassportProfile ->({ - defaultProfileTransform: async (input, context) => { - // const result = await PassportOAuthAuthenticatorHelper.defaultProfileTransform(input, context); +export const atlassianAuthenticator = createOAuthAuthenticator({ + defaultProfileTransform: async ( + input: OAuthAuthenticatorResult, + ) => { + const atlassianProfile = input.fullProfile as AtlassianPassportProfile; + + const profile: ProfileInfo = { + displayName: atlassianProfile.displayName, + email: atlassianProfile.email, + picture: atlassianProfile.photo, + }; return { - profile: { - displayName: input.fullProfile.displayName, - email: input.fullProfile.email, - picture: input.fullProfile.photo, - }, + profile, }; }, scopes: { @@ -98,10 +100,12 @@ export const atlassianAuthenticator = createOAuthAuthenticator< }, async authenticate(input, helper) { - return helper.authenticate(input); + const result = await helper.authenticate(input); + return result as OAuthAuthenticatorResult; }, async refresh(input, helper) { - return helper.refresh(input); + const result = await helper.refresh(input); + return result as OAuthAuthenticatorResult; }, }); diff --git a/plugins/auth-backend-module-atlassian-provider/src/module.ts b/plugins/auth-backend-module-atlassian-provider/src/module.ts index 9acb665ede..2080da3065 100644 --- a/plugins/auth-backend-module-atlassian-provider/src/module.ts +++ b/plugins/auth-backend-module-atlassian-provider/src/module.ts @@ -19,7 +19,10 @@ import { commonSignInResolvers, createOAuthProviderFactory, } from '@backstage/plugin-auth-node'; -import { atlassianAuthenticator } from './authenticator'; +import { + AtlassianPassportProfile, + atlassianAuthenticator, +} from './authenticator'; import { atlassianSignInResolvers } from './resolvers'; /** @public */ @@ -34,7 +37,7 @@ export const authModuleAtlassianProvider = createBackendModule({ async init({ providers }) { providers.registerProvider({ providerId: 'atlassian', - factory: createOAuthProviderFactory({ + factory: createOAuthProviderFactory({ authenticator: atlassianAuthenticator, signInResolverFactories: { ...atlassianSignInResolvers, From a6acc4c2ea28965e0d695972b0eecb9f78be4373 Mon Sep 17 00:00:00 2001 From: Lorenzo Davis <118796878+lorrrrrrrenzo@users.noreply.github.com> Date: Tue, 9 Jul 2024 15:24:35 +0400 Subject: [PATCH 192/416] Export `defaultEksClusterEntityTransformer` from `catalog-backend-module-aws` Signed-off-by: Lorenzo Davis <118796878+lorrrrrrrenzo@users.noreply.github.com> --- plugins/catalog-backend-module-aws/src/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/catalog-backend-module-aws/src/index.ts b/plugins/catalog-backend-module-aws/src/index.ts index 72ddc6386a..de8f9fd7b2 100644 --- a/plugins/catalog-backend-module-aws/src/index.ts +++ b/plugins/catalog-backend-module-aws/src/index.ts @@ -24,3 +24,4 @@ export * from './processors'; export * from './providers'; export * from './types'; export * from './constants'; +export { defaultEksClusterEntityTransformer } from './lib'; From 4afa050758b60b81ad978b6a293dbb94fcc05c4e Mon Sep 17 00:00:00 2001 From: Lorenzo Davis <118796878+lorrrrrrrenzo@users.noreply.github.com> Date: Tue, 9 Jul 2024 15:31:17 +0400 Subject: [PATCH 193/416] Add changeset Signed-off-by: Lorenzo Davis <118796878+lorrrrrrrenzo@users.noreply.github.com> --- .changeset/mighty-keys-bow.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/mighty-keys-bow.md diff --git a/.changeset/mighty-keys-bow.md b/.changeset/mighty-keys-bow.md new file mode 100644 index 0000000000..5f1bb408c9 --- /dev/null +++ b/.changeset/mighty-keys-bow.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend-module-aws': patch +--- + +Export `defaultEksClusterEntityTransformer` to allow library consumers to layer additional changes on top of the default transformer. From baaf9977730807c67602324c02941000eb759fd6 Mon Sep 17 00:00:00 2001 From: Lorenzo Davis <118796878+lorrrrrrrenzo@users.noreply.github.com> Date: Tue, 9 Jul 2024 16:17:40 +0400 Subject: [PATCH 194/416] Update API Report in light of the change Signed-off-by: Lorenzo Davis <118796878+lorrrrrrrenzo@users.noreply.github.com> --- plugins/catalog-backend-module-aws/api-report.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/catalog-backend-module-aws/api-report.md b/plugins/catalog-backend-module-aws/api-report.md index 5098ab5c32..428a39d934 100644 --- a/plugins/catalog-backend-module-aws/api-report.md +++ b/plugins/catalog-backend-module-aws/api-report.md @@ -106,6 +106,9 @@ export class AwsS3EntityProvider implements EntityProvider { refresh(logger: LoggerService): Promise; } +// @public +export const defaultEksClusterEntityTransformer: EksClusterEntityTransformer; + // @public export type EksClusterEntityTransformer = ( cluster: Cluster, From 9d9a391cfb92796faf192a0f60fdba01bb7ce5f0 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 9 Jul 2024 14:21:33 +0200 Subject: [PATCH 195/416] beps/0009: move to implemented Signed-off-by: Patrik Oldsberg --- beps/0009-plugin-metadata/README.md | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/beps/0009-plugin-metadata/README.md b/beps/0009-plugin-metadata/README.md index c0ae487daa..59101f121c 100644 --- a/beps/0009-plugin-metadata/README.md +++ b/beps/0009-plugin-metadata/README.md @@ -1,6 +1,6 @@ --- title: Plugin Metadata -status: implementable +status: implemented authors: - '@Rugvip' owners: @@ -10,16 +10,8 @@ project-areas: creation-date: yyyy-mm-dd --- - - # BEP: Plugin Metadata - - [**Discussion Issue**](https://github.com/backstage/backstage/issues/25076) - [Summary](#summary) From e583b476870481d92c16e951ad0ab357cb8ad093 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 9 Jul 2024 12:58:58 +0000 Subject: [PATCH 196/416] Version Packages (next) --- .changeset/pre.json | 6 + docs/releases/v1.29.0-next.2-changelog.md | 446 ++++++++++++++++++ package.json | 2 +- packages/app-defaults/CHANGELOG.md | 7 + 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 | 35 ++ packages/app-next/package.json | 2 +- packages/app/CHANGELOG.md | 33 ++ packages/app/package.json | 2 +- packages/backend-legacy/CHANGELOG.md | 8 + packages/backend-legacy/package.json | 2 +- packages/backend/CHANGELOG.md | 7 + packages/backend/package.json | 2 +- packages/core-compat-api/CHANGELOG.md | 7 + packages/core-compat-api/package.json | 2 +- packages/core-components/CHANGELOG.md | 6 + packages/core-components/package.json | 2 +- packages/create-app/CHANGELOG.md | 6 + packages/create-app/package.json | 2 +- packages/dev-utils/CHANGELOG.md | 10 + packages/dev-utils/package.json | 2 +- packages/e2e-test/CHANGELOG.md | 7 + packages/e2e-test/package.json | 2 +- packages/frontend-app-api/CHANGELOG.md | 8 + packages/frontend-app-api/package.json | 2 +- packages/frontend-plugin-api/CHANGELOG.md | 7 + packages/frontend-plugin-api/package.json | 2 +- packages/frontend-test-utils/CHANGELOG.md | 8 + packages/frontend-test-utils/package.json | 2 +- .../techdocs-cli-embedded-app/CHANGELOG.md | 13 + .../techdocs-cli-embedded-app/package.json | 2 +- plugins/api-docs/CHANGELOG.md | 11 + plugins/api-docs/package.json | 2 +- plugins/app-visualizer/CHANGELOG.md | 8 + plugins/app-visualizer/package.json | 2 +- plugins/auth-react/CHANGELOG.md | 7 + plugins/auth-react/package.json | 2 +- plugins/catalog-graph/CHANGELOG.md | 10 + plugins/catalog-graph/package.json | 2 +- plugins/catalog-import/CHANGELOG.md | 11 + plugins/catalog-import/package.json | 2 +- plugins/catalog-react/CHANGELOG.md | 9 + plugins/catalog-react/package.json | 2 +- .../catalog-unprocessed-entities/CHANGELOG.md | 7 + .../catalog-unprocessed-entities/package.json | 2 +- plugins/catalog/CHANGELOG.md | 12 + plugins/catalog/package.json | 2 +- plugins/config-schema/CHANGELOG.md | 7 + plugins/config-schema/package.json | 2 +- plugins/devtools/CHANGELOG.md | 9 + plugins/devtools/package.json | 2 +- plugins/example-todo-list/CHANGELOG.md | 7 + plugins/example-todo-list/package.json | 2 +- plugins/home-react/CHANGELOG.md | 7 + plugins/home-react/package.json | 2 +- plugins/home/CHANGELOG.md | 11 + plugins/home/package.json | 2 +- plugins/kubernetes-cluster/CHANGELOG.md | 9 + plugins/kubernetes-cluster/package.json | 2 +- plugins/kubernetes-react/CHANGELOG.md | 8 + plugins/kubernetes-react/package.json | 2 +- plugins/kubernetes/CHANGELOG.md | 9 + plugins/kubernetes/package.json | 2 +- plugins/notifications/CHANGELOG.md | 7 + plugins/notifications/package.json | 2 +- plugins/org-react/CHANGELOG.md | 8 + plugins/org-react/package.json | 2 +- plugins/org/CHANGELOG.md | 10 + plugins/org/package.json | 2 +- plugins/scaffolder-backend/CHANGELOG.md | 6 + plugins/scaffolder-backend/package.json | 2 +- plugins/scaffolder-react/CHANGELOG.md | 8 + plugins/scaffolder-react/package.json | 2 +- plugins/scaffolder/CHANGELOG.md | 12 + plugins/scaffolder/package.json | 2 +- plugins/search-react/CHANGELOG.md | 8 + plugins/search-react/package.json | 2 +- plugins/search/CHANGELOG.md | 12 + plugins/search/package.json | 2 +- plugins/signals/CHANGELOG.md | 7 + plugins/signals/package.json | 2 +- .../techdocs-addons-test-utils/CHANGELOG.md | 12 + .../techdocs-addons-test-utils/package.json | 2 +- .../CHANGELOG.md | 9 + .../package.json | 2 +- plugins/techdocs-react/CHANGELOG.md | 7 + plugins/techdocs-react/package.json | 2 +- plugins/techdocs/CHANGELOG.md | 15 + plugins/techdocs/package.json | 2 +- plugins/user-settings/CHANGELOG.md | 10 + plugins/user-settings/package.json | 2 +- 93 files changed, 941 insertions(+), 46 deletions(-) create mode 100644 docs/releases/v1.29.0-next.2-changelog.md diff --git a/.changeset/pre.json b/.changeset/pre.json index ebf0c6bf22..acd37c2559 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -197,9 +197,11 @@ "create-app-1719320674", "curvy-teachers-smell", "eighty-games-wink", + "eleven-radios-begin", "fair-fans-flow", "fair-pillows-know", "fair-rockets-leave", + "fair-spoons-work", "famous-dodos-crash", "fast-pens-smell", "fifty-pumpkins-smell", @@ -214,6 +216,7 @@ "heavy-moose-pull", "honest-pears-run", "khaki-rivers-obey", + "kind-dancers-boil", "light-avocados-worry", "little-games-fail", "metal-jokes-add", @@ -221,6 +224,7 @@ "metal-suits-drum", "moody-llamas-breathe", "neat-dingos-tickle", + "new-sheep-arrive", "poor-cheetahs-raise", "rare-peas-dream", "renovate-7b61228", @@ -228,6 +232,7 @@ "rich-bears-march", "selfish-turtles-jog", "serious-kings-trade", + "sharp-rice-tickle", "short-flowers-cry", "shy-hounds-battle", "silent-experts-move", @@ -241,6 +246,7 @@ "ten-nails-hear", "ten-pots-walk", "thick-lizards-divide", + "thick-moose-decide", "three-carpets-smoke", "tough-lies-mate", "weak-boats-float", diff --git a/docs/releases/v1.29.0-next.2-changelog.md b/docs/releases/v1.29.0-next.2-changelog.md new file mode 100644 index 0000000000..f6269407cf --- /dev/null +++ b/docs/releases/v1.29.0-next.2-changelog.md @@ -0,0 +1,446 @@ +# Release v1.29.0-next.2 + +Upgrade Helper: [https://backstage.github.io/upgrade-helper/?to=1.29.0-next.2](https://backstage.github.io/upgrade-helper/?to=1.29.0-next.2) + +## @backstage/app-defaults@1.5.8-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + +## @backstage/core-compat-api@0.2.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.7-next.1 + +## @backstage/core-components@0.14.9-next.1 + +### Patch Changes + +- 99d672d: Modified the `Select` component to take in a `data-testid` parameter ensuring backwards compatibility with default value corresponding to previously hardcoded `data-testid` of "select". + +## @backstage/create-app@0.5.17-next.2 + +### Patch Changes + +- e90a2cd: Added the Catalog logs module to the `create-app` template + +## @backstage/dev-utils@1.0.35-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + - @backstage/app-defaults@1.5.8-next.2 + - @backstage/integration-react@1.1.29-next.0 + - @backstage/plugin-catalog-react@1.12.2-next.2 + +## @backstage/frontend-app-api@0.7.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + - @backstage/frontend-plugin-api@0.6.7-next.1 + +## @backstage/frontend-plugin-api@0.6.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + +## @backstage/frontend-test-utils@0.1.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-app-api@0.7.3-next.2 + - @backstage/frontend-plugin-api@0.6.7-next.1 + +## @backstage/plugin-api-docs@0.11.7-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + - @backstage/frontend-plugin-api@0.6.7-next.1 + - @backstage/plugin-catalog@1.21.1-next.2 + - @backstage/plugin-catalog-react@1.12.2-next.2 + - @backstage/core-compat-api@0.2.7-next.1 + +## @backstage/plugin-app-visualizer@0.1.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + - @backstage/frontend-plugin-api@0.6.7-next.1 + +## @backstage/plugin-auth-react@0.1.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + +## @backstage/plugin-catalog@1.21.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + - @backstage/frontend-plugin-api@0.6.7-next.1 + - @backstage/integration-react@1.1.29-next.0 + - @backstage/plugin-catalog-react@1.12.2-next.2 + - @backstage/plugin-search-react@1.7.13-next.1 + - @backstage/core-compat-api@0.2.7-next.1 + +## @backstage/plugin-catalog-graph@0.4.7-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + - @backstage/frontend-plugin-api@0.6.7-next.1 + - @backstage/plugin-catalog-react@1.12.2-next.2 + - @backstage/core-compat-api@0.2.7-next.1 + +## @backstage/plugin-catalog-import@0.12.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + - @backstage/frontend-plugin-api@0.6.7-next.1 + - @backstage/integration-react@1.1.29-next.0 + - @backstage/plugin-catalog-react@1.12.2-next.2 + - @backstage/core-compat-api@0.2.7-next.1 + +## @backstage/plugin-catalog-react@1.12.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + - @backstage/frontend-plugin-api@0.6.7-next.1 + - @backstage/integration-react@1.1.29-next.0 + +## @backstage/plugin-catalog-unprocessed-entities@0.2.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + +## @backstage/plugin-config-schema@0.1.57-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + +## @backstage/plugin-devtools@0.1.16-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + - @backstage/frontend-plugin-api@0.6.7-next.1 + - @backstage/core-compat-api@0.2.7-next.1 + +## @backstage/plugin-home@0.7.7-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + - @backstage/frontend-plugin-api@0.6.7-next.1 + - @backstage/plugin-catalog-react@1.12.2-next.2 + - @backstage/plugin-home-react@0.1.15-next.2 + - @backstage/core-compat-api@0.2.7-next.1 + +## @backstage/plugin-home-react@0.1.15-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + +## @backstage/plugin-kubernetes@0.11.12-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + - @backstage/plugin-kubernetes-react@0.4.1-next.1 + - @backstage/plugin-catalog-react@1.12.2-next.2 + +## @backstage/plugin-kubernetes-cluster@0.0.13-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + - @backstage/plugin-kubernetes-react@0.4.1-next.1 + - @backstage/plugin-catalog-react@1.12.2-next.2 + +## @backstage/plugin-kubernetes-react@0.4.1-next.1 + +### Patch Changes + +- e3cb6ab: Add a namespace label to RolloutDrawer +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + +## @backstage/plugin-notifications@0.2.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + +## @backstage/plugin-org@0.6.27-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + - @backstage/frontend-plugin-api@0.6.7-next.1 + - @backstage/plugin-catalog-react@1.12.2-next.2 + - @backstage/core-compat-api@0.2.7-next.1 + +## @backstage/plugin-org-react@0.1.26-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + - @backstage/plugin-catalog-react@1.12.2-next.2 + +## @backstage/plugin-scaffolder@1.22.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + - @backstage/frontend-plugin-api@0.6.7-next.1 + - @backstage/integration-react@1.1.29-next.0 + - @backstage/plugin-catalog-react@1.12.2-next.2 + - @backstage/plugin-scaffolder-react@1.10.0-next.2 + - @backstage/core-compat-api@0.2.7-next.1 + +## @backstage/plugin-scaffolder-backend@1.23.0-next.2 + +### Patch Changes + +- ff1bb4c: Added a documentation how to use checkpoints + +## @backstage/plugin-scaffolder-react@1.10.0-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + - @backstage/plugin-catalog-react@1.12.2-next.2 + +## @backstage/plugin-search@1.4.14-next.2 + +### Patch Changes + +- 1117aba: Update deps in search api extension to include fetch api +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + - @backstage/frontend-plugin-api@0.6.7-next.1 + - @backstage/plugin-catalog-react@1.12.2-next.2 + - @backstage/plugin-search-react@1.7.13-next.1 + - @backstage/core-compat-api@0.2.7-next.1 + +## @backstage/plugin-search-react@1.7.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + - @backstage/frontend-plugin-api@0.6.7-next.1 + +## @backstage/plugin-signals@0.0.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + +## @backstage/plugin-techdocs@1.10.7-next.2 + +### Patch Changes + +- 6fa652c: Improve default sorting of docs table +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + - @backstage/frontend-plugin-api@0.6.7-next.1 + - @backstage/integration-react@1.1.29-next.0 + - @backstage/plugin-auth-react@0.1.4-next.1 + - @backstage/plugin-catalog-react@1.12.2-next.2 + - @backstage/plugin-search-react@1.7.13-next.1 + - @backstage/plugin-techdocs-react@1.2.6-next.1 + - @backstage/core-compat-api@0.2.7-next.1 + +## @backstage/plugin-techdocs-addons-test-utils@1.0.35-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs@1.10.7-next.2 + - @backstage/integration-react@1.1.29-next.0 + - @backstage/plugin-catalog@1.21.1-next.2 + - @backstage/plugin-catalog-react@1.12.2-next.2 + - @backstage/plugin-search-react@1.7.13-next.1 + - @backstage/plugin-techdocs-react@1.2.6-next.1 + +## @backstage/plugin-techdocs-module-addons-contrib@1.1.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + - @backstage/integration-react@1.1.29-next.0 + - @backstage/plugin-techdocs-react@1.2.6-next.1 + +## @backstage/plugin-techdocs-react@1.2.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + +## @backstage/plugin-user-settings@0.8.9-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + - @backstage/frontend-plugin-api@0.6.7-next.1 + - @backstage/plugin-catalog-react@1.12.2-next.2 + - @backstage/core-compat-api@0.2.7-next.1 + +## example-app@0.2.99-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs@1.10.7-next.2 + - @backstage/core-components@0.14.9-next.1 + - @backstage/plugin-search@1.4.14-next.2 + - @backstage/app-defaults@1.5.8-next.2 + - @backstage/cli@0.26.11-next.1 + - @backstage/frontend-app-api@0.7.3-next.2 + - @backstage/integration-react@1.1.29-next.0 + - @backstage/plugin-api-docs@0.11.7-next.2 + - @backstage/plugin-auth-react@0.1.4-next.1 + - @backstage/plugin-catalog@1.21.1-next.2 + - @backstage/plugin-catalog-graph@0.4.7-next.2 + - @backstage/plugin-catalog-import@0.12.1-next.2 + - @backstage/plugin-catalog-react@1.12.2-next.2 + - @backstage/plugin-catalog-unprocessed-entities@0.2.6-next.1 + - @backstage/plugin-devtools@0.1.16-next.1 + - @backstage/plugin-home@0.7.7-next.2 + - @backstage/plugin-kubernetes@0.11.12-next.2 + - @backstage/plugin-kubernetes-cluster@0.0.13-next.2 + - @backstage/plugin-notifications@0.2.3-next.2 + - @backstage/plugin-org@0.6.27-next.2 + - @backstage/plugin-scaffolder@1.22.1-next.2 + - @backstage/plugin-scaffolder-react@1.10.0-next.2 + - @backstage/plugin-search-react@1.7.13-next.1 + - @backstage/plugin-signals@0.0.8-next.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.12-next.1 + - @backstage/plugin-techdocs-react@1.2.6-next.1 + - @backstage/plugin-user-settings@0.8.9-next.2 + +## example-app-next@0.0.13-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs@1.10.7-next.2 + - @backstage/core-components@0.14.9-next.1 + - @backstage/plugin-search@1.4.14-next.2 + - @backstage/app-defaults@1.5.8-next.2 + - @backstage/cli@0.26.11-next.1 + - @backstage/frontend-app-api@0.7.3-next.2 + - @backstage/frontend-plugin-api@0.6.7-next.1 + - @backstage/integration-react@1.1.29-next.0 + - @backstage/plugin-api-docs@0.11.7-next.2 + - @backstage/plugin-app-visualizer@0.1.8-next.1 + - @backstage/plugin-auth-react@0.1.4-next.1 + - @backstage/plugin-catalog@1.21.1-next.2 + - @backstage/plugin-catalog-graph@0.4.7-next.2 + - @backstage/plugin-catalog-import@0.12.1-next.2 + - @backstage/plugin-catalog-react@1.12.2-next.2 + - @backstage/plugin-catalog-unprocessed-entities@0.2.6-next.1 + - @backstage/plugin-home@0.7.7-next.2 + - @backstage/plugin-kubernetes@0.11.12-next.2 + - @backstage/plugin-kubernetes-cluster@0.0.13-next.2 + - @backstage/plugin-notifications@0.2.3-next.2 + - @backstage/plugin-org@0.6.27-next.2 + - @backstage/plugin-scaffolder@1.22.1-next.2 + - @backstage/plugin-scaffolder-react@1.10.0-next.2 + - @backstage/plugin-search-react@1.7.13-next.1 + - @backstage/plugin-signals@0.0.8-next.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.12-next.1 + - @backstage/plugin-techdocs-react@1.2.6-next.1 + - @backstage/plugin-user-settings@0.8.9-next.2 + - @backstage/core-compat-api@0.2.7-next.1 + +## app-next-example-plugin@0.0.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + - @backstage/frontend-plugin-api@0.6.7-next.1 + +## example-backend@0.0.28-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.23.0-next.2 + +## example-backend-legacy@0.2.100-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.23.0-next.2 + - example-app@0.2.99-next.2 + +## e2e-test@0.2.18-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.17-next.2 + +## techdocs-cli-embedded-app@0.2.98-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs@1.10.7-next.2 + - @backstage/core-components@0.14.9-next.1 + - @backstage/app-defaults@1.5.8-next.2 + - @backstage/cli@0.26.11-next.1 + - @backstage/integration-react@1.1.29-next.0 + - @backstage/plugin-catalog@1.21.1-next.2 + - @backstage/plugin-techdocs-react@1.2.6-next.1 + +## @internal/plugin-todo-list@1.0.29-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 diff --git a/package.json b/package.json index 7de757ff9b..d3d042c2f5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "root", - "version": "1.29.0-next.1", + "version": "1.29.0-next.2", "private": true, "repository": { "type": "git", diff --git a/packages/app-defaults/CHANGELOG.md b/packages/app-defaults/CHANGELOG.md index 588c59c3e4..21fe959edb 100644 --- a/packages/app-defaults/CHANGELOG.md +++ b/packages/app-defaults/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/app-defaults +## 1.5.8-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + ## 1.5.8-next.1 ### Patch Changes diff --git a/packages/app-defaults/package.json b/packages/app-defaults/package.json index 8bb0a707b5..4393164fcd 100644 --- a/packages/app-defaults/package.json +++ b/packages/app-defaults/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/app-defaults", - "version": "1.5.8-next.1", + "version": "1.5.8-next.2", "description": "Provides the default wiring of a Backstage App", "backstage": { "role": "web-library" diff --git a/packages/app-next-example-plugin/CHANGELOG.md b/packages/app-next-example-plugin/CHANGELOG.md index e6788c8566..5456da237c 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.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + - @backstage/frontend-plugin-api@0.6.7-next.1 + ## 0.0.13-next.0 ### Patch Changes diff --git a/packages/app-next-example-plugin/package.json b/packages/app-next-example-plugin/package.json index 9d2e76c418..c3faec66d6 100644 --- a/packages/app-next-example-plugin/package.json +++ b/packages/app-next-example-plugin/package.json @@ -1,6 +1,6 @@ { "name": "app-next-example-plugin", - "version": "0.0.13-next.0", + "version": "0.0.13-next.1", "description": "Backstage internal example plugin", "backstage": { "role": "frontend-plugin", diff --git a/packages/app-next/CHANGELOG.md b/packages/app-next/CHANGELOG.md index 6c3d48601f..22d53e4c78 100644 --- a/packages/app-next/CHANGELOG.md +++ b/packages/app-next/CHANGELOG.md @@ -1,5 +1,40 @@ # example-app-next +## 0.0.13-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs@1.10.7-next.2 + - @backstage/core-components@0.14.9-next.1 + - @backstage/plugin-search@1.4.14-next.2 + - @backstage/app-defaults@1.5.8-next.2 + - @backstage/cli@0.26.11-next.1 + - @backstage/frontend-app-api@0.7.3-next.2 + - @backstage/frontend-plugin-api@0.6.7-next.1 + - @backstage/integration-react@1.1.29-next.0 + - @backstage/plugin-api-docs@0.11.7-next.2 + - @backstage/plugin-app-visualizer@0.1.8-next.1 + - @backstage/plugin-auth-react@0.1.4-next.1 + - @backstage/plugin-catalog@1.21.1-next.2 + - @backstage/plugin-catalog-graph@0.4.7-next.2 + - @backstage/plugin-catalog-import@0.12.1-next.2 + - @backstage/plugin-catalog-react@1.12.2-next.2 + - @backstage/plugin-catalog-unprocessed-entities@0.2.6-next.1 + - @backstage/plugin-home@0.7.7-next.2 + - @backstage/plugin-kubernetes@0.11.12-next.2 + - @backstage/plugin-kubernetes-cluster@0.0.13-next.2 + - @backstage/plugin-notifications@0.2.3-next.2 + - @backstage/plugin-org@0.6.27-next.2 + - @backstage/plugin-scaffolder@1.22.1-next.2 + - @backstage/plugin-scaffolder-react@1.10.0-next.2 + - @backstage/plugin-search-react@1.7.13-next.1 + - @backstage/plugin-signals@0.0.8-next.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.12-next.1 + - @backstage/plugin-techdocs-react@1.2.6-next.1 + - @backstage/plugin-user-settings@0.8.9-next.2 + - @backstage/core-compat-api@0.2.7-next.1 + ## 0.0.13-next.1 ### Patch Changes diff --git a/packages/app-next/package.json b/packages/app-next/package.json index a0f0174753..c38eacfcd5 100644 --- a/packages/app-next/package.json +++ b/packages/app-next/package.json @@ -1,6 +1,6 @@ { "name": "example-app-next", - "version": "0.0.13-next.1", + "version": "0.0.13-next.2", "private": true, "repository": { "type": "git", diff --git a/packages/app/CHANGELOG.md b/packages/app/CHANGELOG.md index 3a06dd99fd..4977cc1d6d 100644 --- a/packages/app/CHANGELOG.md +++ b/packages/app/CHANGELOG.md @@ -1,5 +1,38 @@ # example-app +## 0.2.99-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs@1.10.7-next.2 + - @backstage/core-components@0.14.9-next.1 + - @backstage/plugin-search@1.4.14-next.2 + - @backstage/app-defaults@1.5.8-next.2 + - @backstage/cli@0.26.11-next.1 + - @backstage/frontend-app-api@0.7.3-next.2 + - @backstage/integration-react@1.1.29-next.0 + - @backstage/plugin-api-docs@0.11.7-next.2 + - @backstage/plugin-auth-react@0.1.4-next.1 + - @backstage/plugin-catalog@1.21.1-next.2 + - @backstage/plugin-catalog-graph@0.4.7-next.2 + - @backstage/plugin-catalog-import@0.12.1-next.2 + - @backstage/plugin-catalog-react@1.12.2-next.2 + - @backstage/plugin-catalog-unprocessed-entities@0.2.6-next.1 + - @backstage/plugin-devtools@0.1.16-next.1 + - @backstage/plugin-home@0.7.7-next.2 + - @backstage/plugin-kubernetes@0.11.12-next.2 + - @backstage/plugin-kubernetes-cluster@0.0.13-next.2 + - @backstage/plugin-notifications@0.2.3-next.2 + - @backstage/plugin-org@0.6.27-next.2 + - @backstage/plugin-scaffolder@1.22.1-next.2 + - @backstage/plugin-scaffolder-react@1.10.0-next.2 + - @backstage/plugin-search-react@1.7.13-next.1 + - @backstage/plugin-signals@0.0.8-next.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.12-next.1 + - @backstage/plugin-techdocs-react@1.2.6-next.1 + - @backstage/plugin-user-settings@0.8.9-next.2 + ## 0.2.99-next.1 ### Patch Changes diff --git a/packages/app/package.json b/packages/app/package.json index a30c8e15d7..f15dbac9db 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,6 +1,6 @@ { "name": "example-app", - "version": "0.2.99-next.1", + "version": "0.2.99-next.2", "backstage": { "role": "frontend" }, diff --git a/packages/backend-legacy/CHANGELOG.md b/packages/backend-legacy/CHANGELOG.md index 7734d12d4f..35ed7a6c93 100644 --- a/packages/backend-legacy/CHANGELOG.md +++ b/packages/backend-legacy/CHANGELOG.md @@ -1,5 +1,13 @@ # example-backend-legacy +## 0.2.100-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.23.0-next.2 + - example-app@0.2.99-next.2 + ## 0.2.100-next.1 ### Patch Changes diff --git a/packages/backend-legacy/package.json b/packages/backend-legacy/package.json index 384ce61973..a537361746 100644 --- a/packages/backend-legacy/package.json +++ b/packages/backend-legacy/package.json @@ -1,6 +1,6 @@ { "name": "example-backend-legacy", - "version": "0.2.100-next.1", + "version": "0.2.100-next.2", "backstage": { "role": "backend" }, diff --git a/packages/backend/CHANGELOG.md b/packages/backend/CHANGELOG.md index 0c91daa13d..4ceb786f2a 100644 --- a/packages/backend/CHANGELOG.md +++ b/packages/backend/CHANGELOG.md @@ -1,5 +1,12 @@ # example-backend +## 0.0.28-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.23.0-next.2 + ## 0.0.28-next.1 ### Patch Changes diff --git a/packages/backend/package.json b/packages/backend/package.json index 8e6918bfc5..459db3c317 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -1,6 +1,6 @@ { "name": "example-backend", - "version": "0.0.28-next.1", + "version": "0.0.28-next.2", "main": "dist/index.cjs.js", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/packages/core-compat-api/CHANGELOG.md b/packages/core-compat-api/CHANGELOG.md index 8bcedca9c4..3ad2bd654e 100644 --- a/packages/core-compat-api/CHANGELOG.md +++ b/packages/core-compat-api/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/core-compat-api +## 0.2.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.7-next.1 + ## 0.2.7-next.0 ### Patch Changes diff --git a/packages/core-compat-api/package.json b/packages/core-compat-api/package.json index 954cd6deb3..0f164a6187 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.2.7-next.0", + "version": "0.2.7-next.1", "backstage": { "role": "web-library" }, diff --git a/packages/core-components/CHANGELOG.md b/packages/core-components/CHANGELOG.md index f42b6396ce..163406bbca 100644 --- a/packages/core-components/CHANGELOG.md +++ b/packages/core-components/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/core-components +## 0.14.9-next.1 + +### Patch Changes + +- 99d672d: Modified the `Select` component to take in a `data-testid` parameter ensuring backwards compatibility with default value corresponding to previously hardcoded `data-testid` of "select". + ## 0.14.9-next.0 ### Patch Changes diff --git a/packages/core-components/package.json b/packages/core-components/package.json index 72f733e1a9..21c4a19dbf 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.14.9-next.0", + "version": "0.14.9-next.1", "publishConfig": { "access": "public" }, diff --git a/packages/create-app/CHANGELOG.md b/packages/create-app/CHANGELOG.md index 3f102c17da..708a9b33f8 100644 --- a/packages/create-app/CHANGELOG.md +++ b/packages/create-app/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/create-app +## 0.5.17-next.2 + +### Patch Changes + +- e90a2cd: Added the Catalog logs module to the `create-app` template + ## 0.5.17-next.1 ### Patch Changes diff --git a/packages/create-app/package.json b/packages/create-app/package.json index 96be1f941c..c1ca92f87b 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.17-next.1", + "version": "0.5.17-next.2", "publishConfig": { "access": "public" }, diff --git a/packages/dev-utils/CHANGELOG.md b/packages/dev-utils/CHANGELOG.md index 62a5c2adc2..ee9f56dec7 100644 --- a/packages/dev-utils/CHANGELOG.md +++ b/packages/dev-utils/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/dev-utils +## 1.0.35-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + - @backstage/app-defaults@1.5.8-next.2 + - @backstage/integration-react@1.1.29-next.0 + - @backstage/plugin-catalog-react@1.12.2-next.2 + ## 1.0.35-next.1 ### Patch Changes diff --git a/packages/dev-utils/package.json b/packages/dev-utils/package.json index 3e05873d6c..50220c36e1 100644 --- a/packages/dev-utils/package.json +++ b/packages/dev-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/dev-utils", - "version": "1.0.35-next.1", + "version": "1.0.35-next.2", "description": "Utilities for developing Backstage plugins.", "backstage": { "role": "web-library" diff --git a/packages/e2e-test/CHANGELOG.md b/packages/e2e-test/CHANGELOG.md index a11001a2aa..5144d9fd86 100644 --- a/packages/e2e-test/CHANGELOG.md +++ b/packages/e2e-test/CHANGELOG.md @@ -1,5 +1,12 @@ # e2e-test +## 0.2.18-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.17-next.2 + ## 0.2.18-next.1 ### Patch Changes diff --git a/packages/e2e-test/package.json b/packages/e2e-test/package.json index d1f42a1d8f..1d65314e83 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.18-next.1", + "version": "0.2.18-next.2", "private": true, "backstage": { "role": "cli" diff --git a/packages/frontend-app-api/CHANGELOG.md b/packages/frontend-app-api/CHANGELOG.md index fc39807e5b..dde282a831 100644 --- a/packages/frontend-app-api/CHANGELOG.md +++ b/packages/frontend-app-api/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/frontend-app-api +## 0.7.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + - @backstage/frontend-plugin-api@0.6.7-next.1 + ## 0.7.3-next.1 ### Patch Changes diff --git a/packages/frontend-app-api/package.json b/packages/frontend-app-api/package.json index a6c2583fbc..68c2fd8fab 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.7.3-next.1", + "version": "0.7.3-next.2", "backstage": { "role": "web-library" }, diff --git a/packages/frontend-plugin-api/CHANGELOG.md b/packages/frontend-plugin-api/CHANGELOG.md index 15e3c06bd6..dda46968a4 100644 --- a/packages/frontend-plugin-api/CHANGELOG.md +++ b/packages/frontend-plugin-api/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/frontend-plugin-api +## 0.6.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + ## 0.6.7-next.0 ### Patch Changes diff --git a/packages/frontend-plugin-api/package.json b/packages/frontend-plugin-api/package.json index be603e2611..b62fe36059 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.6.7-next.0", + "version": "0.6.7-next.1", "backstage": { "role": "web-library" }, diff --git a/packages/frontend-test-utils/CHANGELOG.md b/packages/frontend-test-utils/CHANGELOG.md index 5ece8edb86..34d9b28143 100644 --- a/packages/frontend-test-utils/CHANGELOG.md +++ b/packages/frontend-test-utils/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/frontend-test-utils +## 0.1.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-app-api@0.7.3-next.2 + - @backstage/frontend-plugin-api@0.6.7-next.1 + ## 0.1.10-next.1 ### Patch Changes diff --git a/packages/frontend-test-utils/package.json b/packages/frontend-test-utils/package.json index 9856a09367..2a366fa152 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.10-next.1", + "version": "0.1.10-next.2", "backstage": { "role": "web-library" }, diff --git a/packages/techdocs-cli-embedded-app/CHANGELOG.md b/packages/techdocs-cli-embedded-app/CHANGELOG.md index 343ecf5ccb..123e82edf7 100644 --- a/packages/techdocs-cli-embedded-app/CHANGELOG.md +++ b/packages/techdocs-cli-embedded-app/CHANGELOG.md @@ -1,5 +1,18 @@ # techdocs-cli-embedded-app +## 0.2.98-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs@1.10.7-next.2 + - @backstage/core-components@0.14.9-next.1 + - @backstage/app-defaults@1.5.8-next.2 + - @backstage/cli@0.26.11-next.1 + - @backstage/integration-react@1.1.29-next.0 + - @backstage/plugin-catalog@1.21.1-next.2 + - @backstage/plugin-techdocs-react@1.2.6-next.1 + ## 0.2.98-next.1 ### Patch Changes diff --git a/packages/techdocs-cli-embedded-app/package.json b/packages/techdocs-cli-embedded-app/package.json index 3b234c8f4c..979d18620f 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.98-next.1", + "version": "0.2.98-next.2", "private": true, "backstage": { "role": "frontend" diff --git a/plugins/api-docs/CHANGELOG.md b/plugins/api-docs/CHANGELOG.md index f41b4534f1..58d69f516d 100644 --- a/plugins/api-docs/CHANGELOG.md +++ b/plugins/api-docs/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-api-docs +## 0.11.7-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + - @backstage/frontend-plugin-api@0.6.7-next.1 + - @backstage/plugin-catalog@1.21.1-next.2 + - @backstage/plugin-catalog-react@1.12.2-next.2 + - @backstage/core-compat-api@0.2.7-next.1 + ## 0.11.7-next.1 ### Patch Changes diff --git a/plugins/api-docs/package.json b/plugins/api-docs/package.json index 84e2891bcc..5a6d97b7ce 100644 --- a/plugins/api-docs/package.json +++ b/plugins/api-docs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-api-docs", - "version": "0.11.7-next.1", + "version": "0.11.7-next.2", "description": "A Backstage plugin that helps represent API entities in the frontend", "backstage": { "role": "frontend-plugin", diff --git a/plugins/app-visualizer/CHANGELOG.md b/plugins/app-visualizer/CHANGELOG.md index d4a23d79f2..cdb8bab69e 100644 --- a/plugins/app-visualizer/CHANGELOG.md +++ b/plugins/app-visualizer/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-app-visualizer +## 0.1.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + - @backstage/frontend-plugin-api@0.6.7-next.1 + ## 0.1.8-next.0 ### Patch Changes diff --git a/plugins/app-visualizer/package.json b/plugins/app-visualizer/package.json index 31c7dfd87e..95df128040 100644 --- a/plugins/app-visualizer/package.json +++ b/plugins/app-visualizer/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-app-visualizer", - "version": "0.1.8-next.0", + "version": "0.1.8-next.1", "description": "Visualizes the Backstage app structure", "backstage": { "role": "frontend-plugin", diff --git a/plugins/auth-react/CHANGELOG.md b/plugins/auth-react/CHANGELOG.md index 668f751352..84bfadc98c 100644 --- a/plugins/auth-react/CHANGELOG.md +++ b/plugins/auth-react/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-auth-react +## 0.1.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + ## 0.1.4-next.0 ### Patch Changes diff --git a/plugins/auth-react/package.json b/plugins/auth-react/package.json index 114ecd1d55..8af97a0b04 100644 --- a/plugins/auth-react/package.json +++ b/plugins/auth-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-react", - "version": "0.1.4-next.0", + "version": "0.1.4-next.1", "description": "Web library for the auth plugin", "backstage": { "role": "web-library", diff --git a/plugins/catalog-graph/CHANGELOG.md b/plugins/catalog-graph/CHANGELOG.md index fd2b0477e0..f397955e1c 100644 --- a/plugins/catalog-graph/CHANGELOG.md +++ b/plugins/catalog-graph/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-catalog-graph +## 0.4.7-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + - @backstage/frontend-plugin-api@0.6.7-next.1 + - @backstage/plugin-catalog-react@1.12.2-next.2 + - @backstage/core-compat-api@0.2.7-next.1 + ## 0.4.7-next.1 ### Patch Changes diff --git a/plugins/catalog-graph/package.json b/plugins/catalog-graph/package.json index 22e30e3406..eb27725d45 100644 --- a/plugins/catalog-graph/package.json +++ b/plugins/catalog-graph/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-graph", - "version": "0.4.7-next.1", + "version": "0.4.7-next.2", "backstage": { "role": "frontend-plugin", "pluginId": "catalog-graph", diff --git a/plugins/catalog-import/CHANGELOG.md b/plugins/catalog-import/CHANGELOG.md index bebc0c5240..455f094a86 100644 --- a/plugins/catalog-import/CHANGELOG.md +++ b/plugins/catalog-import/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-catalog-import +## 0.12.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + - @backstage/frontend-plugin-api@0.6.7-next.1 + - @backstage/integration-react@1.1.29-next.0 + - @backstage/plugin-catalog-react@1.12.2-next.2 + - @backstage/core-compat-api@0.2.7-next.1 + ## 0.12.1-next.1 ### Patch Changes diff --git a/plugins/catalog-import/package.json b/plugins/catalog-import/package.json index 704fdae2e6..f41d239792 100644 --- a/plugins/catalog-import/package.json +++ b/plugins/catalog-import/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-import", - "version": "0.12.1-next.1", + "version": "0.12.1-next.2", "description": "A Backstage plugin the helps you import entities into your catalog", "backstage": { "role": "frontend-plugin", diff --git a/plugins/catalog-react/CHANGELOG.md b/plugins/catalog-react/CHANGELOG.md index 68febf6b12..b29a49e47d 100644 --- a/plugins/catalog-react/CHANGELOG.md +++ b/plugins/catalog-react/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-catalog-react +## 1.12.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + - @backstage/frontend-plugin-api@0.6.7-next.1 + - @backstage/integration-react@1.1.29-next.0 + ## 1.12.2-next.1 ### Patch Changes diff --git a/plugins/catalog-react/package.json b/plugins/catalog-react/package.json index 99eb8af013..f522a4f111 100644 --- a/plugins/catalog-react/package.json +++ b/plugins/catalog-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-react", - "version": "1.12.2-next.1", + "version": "1.12.2-next.2", "description": "A frontend library that helps other Backstage plugins interact with the catalog", "backstage": { "role": "web-library", diff --git a/plugins/catalog-unprocessed-entities/CHANGELOG.md b/plugins/catalog-unprocessed-entities/CHANGELOG.md index ab22634257..fefeffe9d2 100644 --- a/plugins/catalog-unprocessed-entities/CHANGELOG.md +++ b/plugins/catalog-unprocessed-entities/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-catalog-unprocessed-entities +## 0.2.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + ## 0.2.6-next.0 ### Patch Changes diff --git a/plugins/catalog-unprocessed-entities/package.json b/plugins/catalog-unprocessed-entities/package.json index f32ff293df..142b850bd3 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.2.6-next.0", + "version": "0.2.6-next.1", "backstage": { "role": "frontend-plugin", "pluginId": "catalog-unprocessed-entities", diff --git a/plugins/catalog/CHANGELOG.md b/plugins/catalog/CHANGELOG.md index d003afccf1..08a70d4956 100644 --- a/plugins/catalog/CHANGELOG.md +++ b/plugins/catalog/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-catalog +## 1.21.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + - @backstage/frontend-plugin-api@0.6.7-next.1 + - @backstage/integration-react@1.1.29-next.0 + - @backstage/plugin-catalog-react@1.12.2-next.2 + - @backstage/plugin-search-react@1.7.13-next.1 + - @backstage/core-compat-api@0.2.7-next.1 + ## 1.21.1-next.1 ### Patch Changes diff --git a/plugins/catalog/package.json b/plugins/catalog/package.json index 5cf63e86ab..0d101af3df 100644 --- a/plugins/catalog/package.json +++ b/plugins/catalog/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog", - "version": "1.21.1-next.1", + "version": "1.21.1-next.2", "description": "The Backstage plugin for browsing the Backstage catalog", "backstage": { "role": "frontend-plugin", diff --git a/plugins/config-schema/CHANGELOG.md b/plugins/config-schema/CHANGELOG.md index 76472b69b4..8458a50aa3 100644 --- a/plugins/config-schema/CHANGELOG.md +++ b/plugins/config-schema/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-config-schema +## 0.1.57-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + ## 0.1.57-next.0 ### Patch Changes diff --git a/plugins/config-schema/package.json b/plugins/config-schema/package.json index 38db6a21d5..9a1971d80b 100644 --- a/plugins/config-schema/package.json +++ b/plugins/config-schema/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-config-schema", - "version": "0.1.57-next.0", + "version": "0.1.57-next.1", "description": "A Backstage plugin that lets you browse the configuration schema of your app", "backstage": { "role": "frontend-plugin", diff --git a/plugins/devtools/CHANGELOG.md b/plugins/devtools/CHANGELOG.md index 977e9cd73f..5bc6220aa3 100644 --- a/plugins/devtools/CHANGELOG.md +++ b/plugins/devtools/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-devtools +## 0.1.16-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + - @backstage/frontend-plugin-api@0.6.7-next.1 + - @backstage/core-compat-api@0.2.7-next.1 + ## 0.1.16-next.0 ### Patch Changes diff --git a/plugins/devtools/package.json b/plugins/devtools/package.json index 2749bbeef2..90d724692c 100644 --- a/plugins/devtools/package.json +++ b/plugins/devtools/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-devtools", - "version": "0.1.16-next.0", + "version": "0.1.16-next.1", "backstage": { "role": "frontend-plugin", "pluginId": "devtools", diff --git a/plugins/example-todo-list/CHANGELOG.md b/plugins/example-todo-list/CHANGELOG.md index 2f392e6c33..f61f8b8d0a 100644 --- a/plugins/example-todo-list/CHANGELOG.md +++ b/plugins/example-todo-list/CHANGELOG.md @@ -1,5 +1,12 @@ # @internal/plugin-todo-list +## 1.0.29-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + ## 1.0.29-next.0 ### Patch Changes diff --git a/plugins/example-todo-list/package.json b/plugins/example-todo-list/package.json index c0ef80b3de..d008b73538 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.29-next.0", + "version": "1.0.29-next.1", "backstage": { "role": "frontend-plugin", "pluginId": "todo-list", diff --git a/plugins/home-react/CHANGELOG.md b/plugins/home-react/CHANGELOG.md index 8353571dd8..1f1c9a0e2e 100644 --- a/plugins/home-react/CHANGELOG.md +++ b/plugins/home-react/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-home-react +## 0.1.15-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + ## 0.1.15-next.1 ### Patch Changes diff --git a/plugins/home-react/package.json b/plugins/home-react/package.json index b5dcaae83e..ec05852818 100644 --- a/plugins/home-react/package.json +++ b/plugins/home-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-home-react", - "version": "0.1.15-next.1", + "version": "0.1.15-next.2", "description": "A Backstage plugin that contains react components helps you build a home page", "backstage": { "role": "web-library", diff --git a/plugins/home/CHANGELOG.md b/plugins/home/CHANGELOG.md index b475b7f764..e65b3dec1c 100644 --- a/plugins/home/CHANGELOG.md +++ b/plugins/home/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-home +## 0.7.7-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + - @backstage/frontend-plugin-api@0.6.7-next.1 + - @backstage/plugin-catalog-react@1.12.2-next.2 + - @backstage/plugin-home-react@0.1.15-next.2 + - @backstage/core-compat-api@0.2.7-next.1 + ## 0.7.7-next.1 ### Patch Changes diff --git a/plugins/home/package.json b/plugins/home/package.json index 928417145b..01dd27a295 100644 --- a/plugins/home/package.json +++ b/plugins/home/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-home", - "version": "0.7.7-next.1", + "version": "0.7.7-next.2", "description": "A Backstage plugin that helps you build a home page", "backstage": { "role": "frontend-plugin", diff --git a/plugins/kubernetes-cluster/CHANGELOG.md b/plugins/kubernetes-cluster/CHANGELOG.md index 0d8596888a..8932454b3c 100644 --- a/plugins/kubernetes-cluster/CHANGELOG.md +++ b/plugins/kubernetes-cluster/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-kubernetes-cluster +## 0.0.13-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + - @backstage/plugin-kubernetes-react@0.4.1-next.1 + - @backstage/plugin-catalog-react@1.12.2-next.2 + ## 0.0.13-next.1 ### Patch Changes diff --git a/plugins/kubernetes-cluster/package.json b/plugins/kubernetes-cluster/package.json index 40a6d33dd2..3c6e6c8f1b 100644 --- a/plugins/kubernetes-cluster/package.json +++ b/plugins/kubernetes-cluster/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes-cluster", - "version": "0.0.13-next.1", + "version": "0.0.13-next.2", "description": "A Backstage plugin that shows details of Kubernetes clusters", "backstage": { "role": "frontend-plugin", diff --git a/plugins/kubernetes-react/CHANGELOG.md b/plugins/kubernetes-react/CHANGELOG.md index 81b5c62fad..3755d259a8 100644 --- a/plugins/kubernetes-react/CHANGELOG.md +++ b/plugins/kubernetes-react/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-kubernetes-react +## 0.4.1-next.1 + +### Patch Changes + +- e3cb6ab: Add a namespace label to RolloutDrawer +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + ## 0.4.1-next.0 ### Patch Changes diff --git a/plugins/kubernetes-react/package.json b/plugins/kubernetes-react/package.json index 0cc34da7db..fc6f382d3d 100644 --- a/plugins/kubernetes-react/package.json +++ b/plugins/kubernetes-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes-react", - "version": "0.4.1-next.0", + "version": "0.4.1-next.1", "description": "Web library for the kubernetes-react plugin", "backstage": { "role": "web-library", diff --git a/plugins/kubernetes/CHANGELOG.md b/plugins/kubernetes/CHANGELOG.md index 2d92f6b026..a6d07dc706 100644 --- a/plugins/kubernetes/CHANGELOG.md +++ b/plugins/kubernetes/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-kubernetes +## 0.11.12-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + - @backstage/plugin-kubernetes-react@0.4.1-next.1 + - @backstage/plugin-catalog-react@1.12.2-next.2 + ## 0.11.12-next.1 ### Patch Changes diff --git a/plugins/kubernetes/package.json b/plugins/kubernetes/package.json index eef4da08bc..d0ee97a882 100644 --- a/plugins/kubernetes/package.json +++ b/plugins/kubernetes/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes", - "version": "0.11.12-next.1", + "version": "0.11.12-next.2", "description": "A Backstage plugin that integrates towards Kubernetes", "backstage": { "role": "frontend-plugin", diff --git a/plugins/notifications/CHANGELOG.md b/plugins/notifications/CHANGELOG.md index 9f532b3698..97e6c50b44 100644 --- a/plugins/notifications/CHANGELOG.md +++ b/plugins/notifications/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-notifications +## 0.2.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + ## 0.2.3-next.1 ### Patch Changes diff --git a/plugins/notifications/package.json b/plugins/notifications/package.json index 2e2c67e891..4ef28f9508 100644 --- a/plugins/notifications/package.json +++ b/plugins/notifications/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-notifications", - "version": "0.2.3-next.1", + "version": "0.2.3-next.2", "backstage": { "role": "frontend-plugin", "pluginId": "notifications", diff --git a/plugins/org-react/CHANGELOG.md b/plugins/org-react/CHANGELOG.md index 1ce749fede..d13578fd32 100644 --- a/plugins/org-react/CHANGELOG.md +++ b/plugins/org-react/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-org-react +## 0.1.26-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + - @backstage/plugin-catalog-react@1.12.2-next.2 + ## 0.1.26-next.1 ### Patch Changes diff --git a/plugins/org-react/package.json b/plugins/org-react/package.json index 327e27662f..e6494eaa28 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.26-next.1", + "version": "0.1.26-next.2", "backstage": { "role": "web-library", "pluginId": "org", diff --git a/plugins/org/CHANGELOG.md b/plugins/org/CHANGELOG.md index 5ca788557f..aa4bd9a93f 100644 --- a/plugins/org/CHANGELOG.md +++ b/plugins/org/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-org +## 0.6.27-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + - @backstage/frontend-plugin-api@0.6.7-next.1 + - @backstage/plugin-catalog-react@1.12.2-next.2 + - @backstage/core-compat-api@0.2.7-next.1 + ## 0.6.27-next.1 ### Patch Changes diff --git a/plugins/org/package.json b/plugins/org/package.json index 5c62ffa99f..c2d43bc5ed 100644 --- a/plugins/org/package.json +++ b/plugins/org/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-org", - "version": "0.6.27-next.1", + "version": "0.6.27-next.2", "description": "A Backstage plugin that helps you create entity pages for your organization", "backstage": { "role": "frontend-plugin", diff --git a/plugins/scaffolder-backend/CHANGELOG.md b/plugins/scaffolder-backend/CHANGELOG.md index 97cd859856..a4df9e72e9 100644 --- a/plugins/scaffolder-backend/CHANGELOG.md +++ b/plugins/scaffolder-backend/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/plugin-scaffolder-backend +## 1.23.0-next.2 + +### Patch Changes + +- ff1bb4c: Added a documentation how to use checkpoints + ## 1.23.0-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend/package.json b/plugins/scaffolder-backend/package.json index 71857e245b..10d827762e 100644 --- a/plugins/scaffolder-backend/package.json +++ b/plugins/scaffolder-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend", - "version": "1.23.0-next.1", + "version": "1.23.0-next.2", "description": "The Backstage backend plugin that helps you create new things", "backstage": { "role": "backend-plugin", diff --git a/plugins/scaffolder-react/CHANGELOG.md b/plugins/scaffolder-react/CHANGELOG.md index 6cbdb781f3..a1ed542bd5 100644 --- a/plugins/scaffolder-react/CHANGELOG.md +++ b/plugins/scaffolder-react/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-scaffolder-react +## 1.10.0-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + - @backstage/plugin-catalog-react@1.12.2-next.2 + ## 1.10.0-next.1 ### Minor Changes diff --git a/plugins/scaffolder-react/package.json b/plugins/scaffolder-react/package.json index 6bdc263b3d..36ee0870fc 100644 --- a/plugins/scaffolder-react/package.json +++ b/plugins/scaffolder-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-react", - "version": "1.10.0-next.1", + "version": "1.10.0-next.2", "description": "A frontend library that helps other Backstage plugins interact with the Scaffolder", "backstage": { "role": "web-library", diff --git a/plugins/scaffolder/CHANGELOG.md b/plugins/scaffolder/CHANGELOG.md index 566411b9bd..3c4cfe54ab 100644 --- a/plugins/scaffolder/CHANGELOG.md +++ b/plugins/scaffolder/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-scaffolder +## 1.22.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + - @backstage/frontend-plugin-api@0.6.7-next.1 + - @backstage/integration-react@1.1.29-next.0 + - @backstage/plugin-catalog-react@1.12.2-next.2 + - @backstage/plugin-scaffolder-react@1.10.0-next.2 + - @backstage/core-compat-api@0.2.7-next.1 + ## 1.22.1-next.1 ### Patch Changes diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index 0db796359a..95dd5bff08 100644 --- a/plugins/scaffolder/package.json +++ b/plugins/scaffolder/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder", - "version": "1.22.1-next.1", + "version": "1.22.1-next.2", "description": "The Backstage plugin that helps you create new things", "backstage": { "role": "frontend-plugin", diff --git a/plugins/search-react/CHANGELOG.md b/plugins/search-react/CHANGELOG.md index 19ace29f0c..494ce07772 100644 --- a/plugins/search-react/CHANGELOG.md +++ b/plugins/search-react/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-search-react +## 1.7.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + - @backstage/frontend-plugin-api@0.6.7-next.1 + ## 1.7.13-next.0 ### Patch Changes diff --git a/plugins/search-react/package.json b/plugins/search-react/package.json index 25bc946bd4..a0701e1f3b 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.13-next.0", + "version": "1.7.13-next.1", "backstage": { "role": "web-library", "pluginId": "search", diff --git a/plugins/search/CHANGELOG.md b/plugins/search/CHANGELOG.md index dac2074373..a6cab671b5 100644 --- a/plugins/search/CHANGELOG.md +++ b/plugins/search/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-search +## 1.4.14-next.2 + +### Patch Changes + +- 1117aba: Update deps in search api extension to include fetch api +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + - @backstage/frontend-plugin-api@0.6.7-next.1 + - @backstage/plugin-catalog-react@1.12.2-next.2 + - @backstage/plugin-search-react@1.7.13-next.1 + - @backstage/core-compat-api@0.2.7-next.1 + ## 1.4.13-next.1 ### Patch Changes diff --git a/plugins/search/package.json b/plugins/search/package.json index 3b08790026..ad8210df4c 100644 --- a/plugins/search/package.json +++ b/plugins/search/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search", - "version": "1.4.13-next.1", + "version": "1.4.14-next.2", "description": "The Backstage plugin that provides your backstage app with search", "backstage": { "role": "frontend-plugin", diff --git a/plugins/signals/CHANGELOG.md b/plugins/signals/CHANGELOG.md index f5992789c5..9ccdff8b97 100644 --- a/plugins/signals/CHANGELOG.md +++ b/plugins/signals/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-signals +## 0.0.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + ## 0.0.8-next.0 ### Patch Changes diff --git a/plugins/signals/package.json b/plugins/signals/package.json index 18345295b5..58b82fab7a 100644 --- a/plugins/signals/package.json +++ b/plugins/signals/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-signals", - "version": "0.0.8-next.0", + "version": "0.0.8-next.1", "backstage": { "role": "frontend-plugin", "pluginId": "signals", diff --git a/plugins/techdocs-addons-test-utils/CHANGELOG.md b/plugins/techdocs-addons-test-utils/CHANGELOG.md index 0695f7e1f4..5b247addab 100644 --- a/plugins/techdocs-addons-test-utils/CHANGELOG.md +++ b/plugins/techdocs-addons-test-utils/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-techdocs-addons-test-utils +## 1.0.35-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs@1.10.7-next.2 + - @backstage/integration-react@1.1.29-next.0 + - @backstage/plugin-catalog@1.21.1-next.2 + - @backstage/plugin-catalog-react@1.12.2-next.2 + - @backstage/plugin-search-react@1.7.13-next.1 + - @backstage/plugin-techdocs-react@1.2.6-next.1 + ## 1.0.35-next.1 ### Patch Changes diff --git a/plugins/techdocs-addons-test-utils/package.json b/plugins/techdocs-addons-test-utils/package.json index fd1c806414..966308ee94 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.35-next.1", + "version": "1.0.35-next.2", "backstage": { "role": "web-library", "pluginId": "techdocs-addons", diff --git a/plugins/techdocs-module-addons-contrib/CHANGELOG.md b/plugins/techdocs-module-addons-contrib/CHANGELOG.md index da76210708..2cc99a8158 100644 --- a/plugins/techdocs-module-addons-contrib/CHANGELOG.md +++ b/plugins/techdocs-module-addons-contrib/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-techdocs-module-addons-contrib +## 1.1.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + - @backstage/integration-react@1.1.29-next.0 + - @backstage/plugin-techdocs-react@1.2.6-next.1 + ## 1.1.12-next.0 ### Patch Changes diff --git a/plugins/techdocs-module-addons-contrib/package.json b/plugins/techdocs-module-addons-contrib/package.json index f0b2301dfb..f68df2a883 100644 --- a/plugins/techdocs-module-addons-contrib/package.json +++ b/plugins/techdocs-module-addons-contrib/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs-module-addons-contrib", - "version": "1.1.12-next.0", + "version": "1.1.12-next.1", "description": "Plugin module for contributed TechDocs Addons", "backstage": { "role": "frontend-plugin-module", diff --git a/plugins/techdocs-react/CHANGELOG.md b/plugins/techdocs-react/CHANGELOG.md index d07ed27eb0..97677352df 100644 --- a/plugins/techdocs-react/CHANGELOG.md +++ b/plugins/techdocs-react/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-techdocs-react +## 1.2.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + ## 1.2.6-next.0 ### Patch Changes diff --git a/plugins/techdocs-react/package.json b/plugins/techdocs-react/package.json index d002db68d1..1686b176ca 100644 --- a/plugins/techdocs-react/package.json +++ b/plugins/techdocs-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs-react", - "version": "1.2.6-next.0", + "version": "1.2.6-next.1", "description": "Shared frontend utilities for TechDocs and Addons", "backstage": { "role": "web-library", diff --git a/plugins/techdocs/CHANGELOG.md b/plugins/techdocs/CHANGELOG.md index a14559de1e..34dc9a310f 100644 --- a/plugins/techdocs/CHANGELOG.md +++ b/plugins/techdocs/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-techdocs +## 1.10.7-next.2 + +### Patch Changes + +- 6fa652c: Improve default sorting of docs table +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + - @backstage/frontend-plugin-api@0.6.7-next.1 + - @backstage/integration-react@1.1.29-next.0 + - @backstage/plugin-auth-react@0.1.4-next.1 + - @backstage/plugin-catalog-react@1.12.2-next.2 + - @backstage/plugin-search-react@1.7.13-next.1 + - @backstage/plugin-techdocs-react@1.2.6-next.1 + - @backstage/core-compat-api@0.2.7-next.1 + ## 1.10.7-next.1 ### Patch Changes diff --git a/plugins/techdocs/package.json b/plugins/techdocs/package.json index 2a404551be..cbf1f828ce 100644 --- a/plugins/techdocs/package.json +++ b/plugins/techdocs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs", - "version": "1.10.7-next.1", + "version": "1.10.7-next.2", "description": "The Backstage plugin that renders technical documentation for your components", "backstage": { "role": "frontend-plugin", diff --git a/plugins/user-settings/CHANGELOG.md b/plugins/user-settings/CHANGELOG.md index 5b86011ba8..8d886aee80 100644 --- a/plugins/user-settings/CHANGELOG.md +++ b/plugins/user-settings/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-user-settings +## 0.8.9-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9-next.1 + - @backstage/frontend-plugin-api@0.6.7-next.1 + - @backstage/plugin-catalog-react@1.12.2-next.2 + - @backstage/core-compat-api@0.2.7-next.1 + ## 0.8.9-next.1 ### Patch Changes diff --git a/plugins/user-settings/package.json b/plugins/user-settings/package.json index a549c7cdd2..34c719d9df 100644 --- a/plugins/user-settings/package.json +++ b/plugins/user-settings/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-user-settings", - "version": "0.8.9-next.1", + "version": "0.8.9-next.2", "description": "A Backstage plugin that provides a settings page", "backstage": { "role": "frontend-plugin", From efda5a301dbe9a4c40e9194559d32cc606734aeb Mon Sep 17 00:00:00 2001 From: Olivier Liechti Date: Tue, 9 Jul 2024 15:08:24 +0200 Subject: [PATCH 197/416] Export Atlassian OAuth Profile type Signed-off-by: Olivier Liechti --- .changeset/nasty-balloons-attack.md | 5 +++++ plugins/auth-backend-module-atlassian-provider/src/index.ts | 3 +-- plugins/auth-backend/src/providers/atlassian/provider.ts | 3 ++- 3 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 .changeset/nasty-balloons-attack.md diff --git a/.changeset/nasty-balloons-attack.md b/.changeset/nasty-balloons-attack.md new file mode 100644 index 0000000000..60229b4a25 --- /dev/null +++ b/.changeset/nasty-balloons-attack.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-auth-backend': patch +--- + +Use new Atlassian Passport profile in type definition diff --git a/plugins/auth-backend-module-atlassian-provider/src/index.ts b/plugins/auth-backend-module-atlassian-provider/src/index.ts index cc71c9b7e3..224037b868 100644 --- a/plugins/auth-backend-module-atlassian-provider/src/index.ts +++ b/plugins/auth-backend-module-atlassian-provider/src/index.ts @@ -13,13 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - /** * The atlassian-provider backend module for the auth plugin. * * @packageDocumentation */ - export { atlassianAuthenticator } from './authenticator'; +export type { AtlassianPassportProfile } from './authenticator'; export { authModuleAtlassianProvider as default } from './module'; export { atlassianSignInResolvers } from './resolvers'; diff --git a/plugins/auth-backend/src/providers/atlassian/provider.ts b/plugins/auth-backend/src/providers/atlassian/provider.ts index 22db26fd85..d30164bd6e 100644 --- a/plugins/auth-backend/src/providers/atlassian/provider.ts +++ b/plugins/auth-backend/src/providers/atlassian/provider.ts @@ -26,6 +26,7 @@ import { import { OAuthResult } from '../../lib/oauth'; import { createAuthProviderIntegration } from '../createAuthProviderIntegration'; import { AuthHandler } from '../types'; +import { AtlassianPassportProfile } from '@backstage/plugin-auth-backend-module-atlassian-provider'; /** * Auth provider integration for Atlassian auth @@ -47,7 +48,7 @@ export const atlassian = createAuthProviderIntegration({ resolver: SignInResolver; }; }) { - return createOAuthProviderFactory({ + return createOAuthProviderFactory({ authenticator: atlassianAuthenticator, profileTransform: adaptLegacyOAuthHandler(options?.authHandler), signInResolver: adaptLegacyOAuthSignInResolver(options?.signIn?.resolver), From 55c1a729ac4cdd84afd9ac4bb081b9b1c2ad7274 Mon Sep 17 00:00:00 2001 From: Olivier Liechti Date: Tue, 9 Jul 2024 16:29:50 +0200 Subject: [PATCH 198/416] Simplify the bug fix, by implementing logic in the PassportHelper Signed-off-by: Olivier Liechti --- .changeset/stale-beds-sneeze.md | 6 +++ .../src/authenticator.ts | 37 +++---------------- .../src/index.ts | 1 - .../src/providers/atlassian/provider.ts | 3 +- .../auth-node/src/passport/PassportHelpers.ts | 7 ++++ plugins/auth-node/src/passport/types.ts | 2 + 6 files changed, 22 insertions(+), 34 deletions(-) create mode 100644 .changeset/stale-beds-sneeze.md diff --git a/.changeset/stale-beds-sneeze.md b/.changeset/stale-beds-sneeze.md new file mode 100644 index 0000000000..e2fc5acdf2 --- /dev/null +++ b/.changeset/stale-beds-sneeze.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-auth-backend-module-atlassian-provider': patch +'@backstage/plugin-auth-node': patch +--- + +Fix issues with Atlassian OAuth provider diff --git a/plugins/auth-backend-module-atlassian-provider/src/authenticator.ts b/plugins/auth-backend-module-atlassian-provider/src/authenticator.ts index 8a1b952d15..23a4a52197 100644 --- a/plugins/auth-backend-module-atlassian-provider/src/authenticator.ts +++ b/plugins/auth-backend-module-atlassian-provider/src/authenticator.ts @@ -16,39 +16,16 @@ import { createOAuthAuthenticator, - OAuthAuthenticatorResult, PassportOAuthAuthenticatorHelper, PassportOAuthDoneCallback, - ProfileInfo, + PassportProfile, } from '@backstage/plugin-auth-node'; import AtlassianStrategy from 'passport-atlassian-oauth2'; -export type AtlassianPassportProfile = { - id: string; - displayName: string; - email: string; - photo: string; - provider: string; - _json: any; -}; - /** @public */ export const atlassianAuthenticator = createOAuthAuthenticator({ - defaultProfileTransform: async ( - input: OAuthAuthenticatorResult, - ) => { - const atlassianProfile = input.fullProfile as AtlassianPassportProfile; - - const profile: ProfileInfo = { - displayName: atlassianProfile.displayName, - email: atlassianProfile.email, - picture: atlassianProfile.photo, - }; - - return { - profile, - }; - }, + defaultProfileTransform: + PassportOAuthAuthenticatorHelper.defaultProfileTransform, scopes: { required: ['offline_access', 'read:me', 'read:jira-work', 'read:jira-user'], }, @@ -79,7 +56,7 @@ export const atlassianAuthenticator = createOAuthAuthenticator({ accessToken: string, refreshToken: string, params: any, - fullProfile: AtlassianPassportProfile, + fullProfile: PassportProfile, done: PassportOAuthDoneCallback, ) => { done( @@ -100,12 +77,10 @@ export const atlassianAuthenticator = createOAuthAuthenticator({ }, async authenticate(input, helper) { - const result = await helper.authenticate(input); - return result as OAuthAuthenticatorResult; + return helper.authenticate(input); }, async refresh(input, helper) { - const result = await helper.refresh(input); - return result as OAuthAuthenticatorResult; + return helper.refresh(input); }, }); diff --git a/plugins/auth-backend-module-atlassian-provider/src/index.ts b/plugins/auth-backend-module-atlassian-provider/src/index.ts index 224037b868..8f090b76d4 100644 --- a/plugins/auth-backend-module-atlassian-provider/src/index.ts +++ b/plugins/auth-backend-module-atlassian-provider/src/index.ts @@ -19,6 +19,5 @@ * @packageDocumentation */ export { atlassianAuthenticator } from './authenticator'; -export type { AtlassianPassportProfile } from './authenticator'; export { authModuleAtlassianProvider as default } from './module'; export { atlassianSignInResolvers } from './resolvers'; diff --git a/plugins/auth-backend/src/providers/atlassian/provider.ts b/plugins/auth-backend/src/providers/atlassian/provider.ts index d30164bd6e..22db26fd85 100644 --- a/plugins/auth-backend/src/providers/atlassian/provider.ts +++ b/plugins/auth-backend/src/providers/atlassian/provider.ts @@ -26,7 +26,6 @@ import { import { OAuthResult } from '../../lib/oauth'; import { createAuthProviderIntegration } from '../createAuthProviderIntegration'; import { AuthHandler } from '../types'; -import { AtlassianPassportProfile } from '@backstage/plugin-auth-backend-module-atlassian-provider'; /** * Auth provider integration for Atlassian auth @@ -48,7 +47,7 @@ export const atlassian = createAuthProviderIntegration({ resolver: SignInResolver; }; }) { - return createOAuthProviderFactory({ + return createOAuthProviderFactory({ authenticator: atlassianAuthenticator, profileTransform: adaptLegacyOAuthHandler(options?.authHandler), signInResolver: adaptLegacyOAuthSignInResolver(options?.signIn?.resolver), diff --git a/plugins/auth-node/src/passport/PassportHelpers.ts b/plugins/auth-node/src/passport/PassportHelpers.ts index d7b554d56a..8531309917 100644 --- a/plugins/auth-node/src/passport/PassportHelpers.ts +++ b/plugins/auth-node/src/passport/PassportHelpers.ts @@ -42,12 +42,19 @@ export class PassportHelpers { email = firstEmail.value; } + // This is the case for Atlassian + if (profile.email) { + email = profile.email; + } + let picture: string | undefined = undefined; if (profile.avatarUrl) { picture = profile.avatarUrl; } else if (profile.photos && profile.photos.length > 0) { const [firstPhoto] = profile.photos; picture = firstPhoto.value; + } else if (profile.photo) { + picture = profile.photo; // This is the case for Atlassian } let displayName: string | undefined = diff --git a/plugins/auth-node/src/passport/types.ts b/plugins/auth-node/src/passport/types.ts index 4a3f41b6b2..d5681fa9e3 100644 --- a/plugins/auth-node/src/passport/types.ts +++ b/plugins/auth-node/src/passport/types.ts @@ -19,6 +19,8 @@ import { Profile } from 'passport'; /** @public */ export type PassportProfile = Profile & { avatarUrl?: string; + email?: string; + photo?: string; }; /** @public */ From 487c100100365db39a89814f9dd127f8c17ec40e Mon Sep 17 00:00:00 2001 From: Olivier Liechti Date: Tue, 9 Jul 2024 16:41:18 +0200 Subject: [PATCH 199/416] Simplify the bug fix, by implementing logic in the PassportHelper Signed-off-by: Olivier Liechti --- .../auth-backend-module-atlassian-provider/src/module.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/plugins/auth-backend-module-atlassian-provider/src/module.ts b/plugins/auth-backend-module-atlassian-provider/src/module.ts index 2080da3065..9acb665ede 100644 --- a/plugins/auth-backend-module-atlassian-provider/src/module.ts +++ b/plugins/auth-backend-module-atlassian-provider/src/module.ts @@ -19,10 +19,7 @@ import { commonSignInResolvers, createOAuthProviderFactory, } from '@backstage/plugin-auth-node'; -import { - AtlassianPassportProfile, - atlassianAuthenticator, -} from './authenticator'; +import { atlassianAuthenticator } from './authenticator'; import { atlassianSignInResolvers } from './resolvers'; /** @public */ @@ -37,7 +34,7 @@ export const authModuleAtlassianProvider = createBackendModule({ async init({ providers }) { providers.registerProvider({ providerId: 'atlassian', - factory: createOAuthProviderFactory({ + factory: createOAuthProviderFactory({ authenticator: atlassianAuthenticator, signInResolverFactories: { ...atlassianSignInResolvers, From e1eda89df32a9d2b6987c87e8351288379332210 Mon Sep 17 00:00:00 2001 From: Olivier Liechti Date: Tue, 9 Jul 2024 18:58:55 +0200 Subject: [PATCH 200/416] Add api-report.md Signed-off-by: Olivier Liechti --- plugins/auth-node/api-report.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/auth-node/api-report.md b/plugins/auth-node/api-report.md index dc1d86308a..a3750819f9 100644 --- a/plugins/auth-node/api-report.md +++ b/plugins/auth-node/api-report.md @@ -552,6 +552,8 @@ export type PassportOAuthResult = { // @public (undocumented) export type PassportProfile = Profile & { avatarUrl?: string; + email?: string; + photo?: string; }; // @public From 9076843ffd67153f71b1ff9df0eb9af68ba96236 Mon Sep 17 00:00:00 2001 From: Olivier Liechti Date: Tue, 9 Jul 2024 19:48:38 +0200 Subject: [PATCH 201/416] Adatp test to the payload returned by the actual Atlassian strategy (vs its parent) Signed-off-by: Olivier Liechti --- .../src/module.test.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/plugins/auth-backend-module-atlassian-provider/src/module.test.ts b/plugins/auth-backend-module-atlassian-provider/src/module.test.ts index 7b92218d56..7e83aed179 100644 --- a/plugins/auth-backend-module-atlassian-provider/src/module.test.ts +++ b/plugins/auth-backend-module-atlassian-provider/src/module.test.ts @@ -64,10 +64,12 @@ describe('authModuleAtlassianProvider', () => { expect(startUrl.pathname).toBe('/authorize'); expect(Object.fromEntries(startUrl.searchParams)).toEqual({ response_type: 'code', + audience: 'api.atlassian.com', client_id: 'my-client-id', + prompt: 'consent', redirect_uri: `http://localhost:${server.port()}/api/auth/atlassian/handler/frame`, state: expect.any(String), - scope: 'offline_access read:jira-work read:jira-user', + scope: 'offline_access read:me read:jira-work read:jira-user', }); expect(decodeOAuthState(startUrl.searchParams.get('state')!)).toEqual({ @@ -92,10 +94,7 @@ describe('authModuleAtlassianProvider', () => { development: { clientId: 'my-client-id', clientSecret: 'my-client-secret', - additionalScopes: [ - 'read:filter:jira', - 'read:jira-work', // already required - ], + additionalScopes: 'read:filter:jira read:jira-work', // 2nd is already required }, }, }, @@ -123,11 +122,14 @@ describe('authModuleAtlassianProvider', () => { expect(startUrl.origin).toBe('https://auth.atlassian.com'); expect(startUrl.pathname).toBe('/authorize'); expect(Object.fromEntries(startUrl.searchParams)).toEqual({ + audience: 'api.atlassian.com', response_type: 'code', client_id: 'my-client-id', + prompt: 'consent', redirect_uri: `http://localhost:${server.port()}/api/auth/atlassian/handler/frame`, state: expect.any(String), - scope: 'offline_access read:jira-work read:jira-user read:filter:jira', + scope: + 'offline_access read:me read:jira-work read:jira-user read:filter:jira', }); expect(decodeOAuthState(startUrl.searchParams.get('state')!)).toEqual({ From aca86a6a007fa8c9c431f92b685f58c591f25c73 Mon Sep 17 00:00:00 2001 From: Olivier Liechti Date: Wed, 10 Jul 2024 08:11:02 +0200 Subject: [PATCH 202/416] Address review comments Signed-off-by: Olivier Liechti --- .changeset/nasty-balloons-attack.md | 5 ----- .changeset/stale-beds-sneeze.md | 3 +-- plugins/auth-node/src/passport/PassportHelpers.ts | 9 ++++----- 3 files changed, 5 insertions(+), 12 deletions(-) delete mode 100644 .changeset/nasty-balloons-attack.md diff --git a/.changeset/nasty-balloons-attack.md b/.changeset/nasty-balloons-attack.md deleted file mode 100644 index 60229b4a25..0000000000 --- a/.changeset/nasty-balloons-attack.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-auth-backend': patch ---- - -Use new Atlassian Passport profile in type definition diff --git a/.changeset/stale-beds-sneeze.md b/.changeset/stale-beds-sneeze.md index e2fc5acdf2..695e09a624 100644 --- a/.changeset/stale-beds-sneeze.md +++ b/.changeset/stale-beds-sneeze.md @@ -1,6 +1,5 @@ --- -'@backstage/plugin-auth-backend-module-atlassian-provider': patch '@backstage/plugin-auth-node': patch --- -Fix issues with Atlassian OAuth provider +Fix issues with Atlassian OAuth provider: retrieve the email and photo that were not in arrays but rather in single props. diff --git a/plugins/auth-node/src/passport/PassportHelpers.ts b/plugins/auth-node/src/passport/PassportHelpers.ts index 8531309917..d1ddee20a7 100644 --- a/plugins/auth-node/src/passport/PassportHelpers.ts +++ b/plugins/auth-node/src/passport/PassportHelpers.ts @@ -40,10 +40,8 @@ export class PassportHelpers { if (profile.emails && profile.emails.length > 0) { const [firstEmail] = profile.emails; email = firstEmail.value; - } - - // This is the case for Atlassian - if (profile.email) { + } else if (profile.email) { + // This is the case for Atlassian email = profile.email; } @@ -54,7 +52,8 @@ export class PassportHelpers { const [firstPhoto] = profile.photos; picture = firstPhoto.value; } else if (profile.photo) { - picture = profile.photo; // This is the case for Atlassian + // This is the case for Atlassian + picture = profile.photo; } let displayName: string | undefined = From c48f2cc68df4065d1d19fbbf09e167fe89492600 Mon Sep 17 00:00:00 2001 From: Olivier Liechti Date: Wed, 10 Jul 2024 10:42:16 +0200 Subject: [PATCH 203/416] Cleanup test Signed-off-by: Olivier Liechti --- .../src/authenticator.test.ts | 27 ++++++++----------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/plugins/auth-backend-module-atlassian-provider/src/authenticator.test.ts b/plugins/auth-backend-module-atlassian-provider/src/authenticator.test.ts index cb723ecece..ab0a4840f9 100644 --- a/plugins/auth-backend-module-atlassian-provider/src/authenticator.test.ts +++ b/plugins/auth-backend-module-atlassian-provider/src/authenticator.test.ts @@ -17,21 +17,16 @@ import Strategy from 'passport-atlassian-oauth2'; describe('Strategy', () => { it('should be an instance of', () => { - try { - console.log(Strategy); - const strategy = new Strategy( - { - authorizationURL: 'https://auth.atlassian.com/authorize', - tokenURL: 'https://auth.atlassian.com/oauth/token', - clientID: 'my-client-id', - clientSecret: 'my-client-secret', - scope: ['offline_access', 'read:jira-work', 'read:jira-user'], - }, - () => {}, - ); - expect((strategy as any).name).toBe('atlassian'); - } catch (e) { - console.error(e); - } + const strategy = new Strategy( + { + authorizationURL: 'https://auth.atlassian.com/authorize', + tokenURL: 'https://auth.atlassian.com/oauth/token', + clientID: 'my-client-id', + clientSecret: 'my-client-secret', + scope: ['offline_access', 'read:jira-work', 'read:jira-user'], + }, + () => {}, + ); + expect((strategy as any).name).toBe('atlassian'); }); }); From 3d9abab684c528f9547814713bf1a93531059417 Mon Sep 17 00:00:00 2001 From: Olivier Liechti Date: Wed, 10 Jul 2024 11:10:56 +0200 Subject: [PATCH 204/416] Pass an empty array to the 'scope' prop required by Atlassian strategy, but which value is not actually used Signed-off-by: Olivier Liechti --- .../auth-backend-module-atlassian-provider/src/authenticator.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/auth-backend-module-atlassian-provider/src/authenticator.ts b/plugins/auth-backend-module-atlassian-provider/src/authenticator.ts index 23a4a52197..d4f46b5a8c 100644 --- a/plugins/auth-backend-module-atlassian-provider/src/authenticator.ts +++ b/plugins/auth-backend-module-atlassian-provider/src/authenticator.ts @@ -50,7 +50,7 @@ export const atlassianAuthenticator = createOAuthAuthenticator({ authorizationURL: `${baseUrl}/authorize`, tokenURL: `${baseUrl}/oauth/token`, profileURL: 'https://api.atlassian.com/me', - scope: config.getOptionalString('additionalScopes')?.split(' ') || [], + scope: [], // the Atlassian strategy requires a scope, but Backstage passes the right set of scopes when calling OAuth2Strategy.prototype.authenticate }, ( accessToken: string, From 1cb84d7085cf9be7b5255d26e2a7c4317e9d8da7 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 10 Jul 2024 11:19:10 +0200 Subject: [PATCH 205/416] backend-defaults: removed the deprecated getPath option from httpRouterServiceFactory Signed-off-by: Patrik Oldsberg --- .changeset/cold-jars-punch.md | 6 ++ packages/backend-app-api/api-report.md | 12 +-- .../httpRouter/httpRouterServiceFactory.ts | 11 +-- .../implementations/httpRouter/index.ts | 1 - .../backend-defaults/api-report-httpRouter.md | 12 +-- .../httpRouterServiceFactory.test.ts | 26 ------ .../httpRouter/httpRouterServiceFactory.ts | 92 +++++++------------ .../src/entrypoints/httpRouter/index.ts | 1 - packages/backend-test-utils/api-report.md | 5 +- 9 files changed, 48 insertions(+), 118 deletions(-) create mode 100644 .changeset/cold-jars-punch.md diff --git a/.changeset/cold-jars-punch.md b/.changeset/cold-jars-punch.md new file mode 100644 index 0000000000..8708e1f670 --- /dev/null +++ b/.changeset/cold-jars-punch.md @@ -0,0 +1,6 @@ +--- +'@backstage/backend-defaults': minor +'@backstage/backend-app-api': minor +--- + +**BREAKING**: Removed the depreacted `getPath` option from `httpRouterServiceFactory`, as well as the `HttpRouterFactoryOptions` type. diff --git a/packages/backend-app-api/api-report.md b/packages/backend-app-api/api-report.md index 7518f8e2cc..c577084a58 100644 --- a/packages/backend-app-api/api-report.md +++ b/packages/backend-app-api/api-report.md @@ -146,15 +146,11 @@ export const httpAuthServiceFactory: () => ServiceFactory< 'plugin' >; -// Warning: (ae-forgotten-export) The symbol "HttpRouterFactoryOptions_2" needs to be exported by the entry point index.d.ts -// -// @public @deprecated (undocumented) -export type HttpRouterFactoryOptions = HttpRouterFactoryOptions_2; - // @public @deprecated -export const httpRouterServiceFactory: ( - options?: HttpRouterFactoryOptions_2 | undefined, -) => ServiceFactory; +export const httpRouterServiceFactory: () => ServiceFactory< + HttpRouterService, + 'plugin' +>; // Warning: (ae-forgotten-export) The symbol "HttpServerCertificateOptions_2" needs to be exported by the entry point index.d.ts // diff --git a/packages/backend-app-api/src/services/implementations/httpRouter/httpRouterServiceFactory.ts b/packages/backend-app-api/src/services/implementations/httpRouter/httpRouterServiceFactory.ts index 9d2b74fb43..0088e53f98 100644 --- a/packages/backend-app-api/src/services/implementations/httpRouter/httpRouterServiceFactory.ts +++ b/packages/backend-app-api/src/services/implementations/httpRouter/httpRouterServiceFactory.ts @@ -15,16 +15,7 @@ */ // eslint-disable-next-line @backstage/no-relative-monorepo-imports -import { - httpRouterServiceFactory as _httpRouterServiceFactory, - type HttpRouterFactoryOptions as _HttpRouterFactoryOptions, -} from '../../../../../backend-defaults/src/entrypoints/httpRouter/httpRouterServiceFactory'; - -/** - * @public - * @deprecated Please import from `@backstage/backend-defaults/httpRouter` instead. - */ -export type HttpRouterFactoryOptions = _HttpRouterFactoryOptions; +import { httpRouterServiceFactory as _httpRouterServiceFactory } from '../../../../../backend-defaults/src/entrypoints/httpRouter/httpRouterServiceFactory'; /** * HTTP route registration for plugins. diff --git a/packages/backend-app-api/src/services/implementations/httpRouter/index.ts b/packages/backend-app-api/src/services/implementations/httpRouter/index.ts index 928a232131..bc12480ae8 100644 --- a/packages/backend-app-api/src/services/implementations/httpRouter/index.ts +++ b/packages/backend-app-api/src/services/implementations/httpRouter/index.ts @@ -15,6 +15,5 @@ */ export { httpRouterServiceFactory } from './httpRouterServiceFactory'; -export type { HttpRouterFactoryOptions } from './httpRouterServiceFactory'; export { createLifecycleMiddleware } from './createLifecycleMiddleware'; export type { LifecycleMiddlewareOptions } from './createLifecycleMiddleware'; diff --git a/packages/backend-defaults/api-report-httpRouter.md b/packages/backend-defaults/api-report-httpRouter.md index a7ca2c8dd3..f191a5a847 100644 --- a/packages/backend-defaults/api-report-httpRouter.md +++ b/packages/backend-defaults/api-report-httpRouter.md @@ -14,15 +14,11 @@ export function createLifecycleMiddleware( options: LifecycleMiddlewareOptions, ): RequestHandler; -// @public (undocumented) -export interface HttpRouterFactoryOptions { - getPath?(pluginId: string): string; -} - // @public -export const httpRouterServiceFactory: ( - options?: HttpRouterFactoryOptions | undefined, -) => ServiceFactory; +export const httpRouterServiceFactory: () => ServiceFactory< + HttpRouterService, + 'plugin' +>; // @public export interface LifecycleMiddlewareOptions { diff --git a/packages/backend-defaults/src/entrypoints/httpRouter/httpRouterServiceFactory.test.ts b/packages/backend-defaults/src/entrypoints/httpRouter/httpRouterServiceFactory.test.ts index 58c074f985..17665a176a 100644 --- a/packages/backend-defaults/src/entrypoints/httpRouter/httpRouterServiceFactory.test.ts +++ b/packages/backend-defaults/src/entrypoints/httpRouter/httpRouterServiceFactory.test.ts @@ -52,32 +52,6 @@ describe('httpRouterFactory', () => { ); }); - it('should use custom path generator', async () => { - const rootHttpRouter = mockServices.rootHttpRouter.mock(); - const tester = ServiceFactoryTester.from( - httpRouterServiceFactory({ - getPath: id => `/some/${id}/path`, - }), - { dependencies: [rootHttpRouter.factory] }, - ); - - const router1 = await tester.get('test1'); - router1.use(() => {}); - expect(rootHttpRouter.use).toHaveBeenCalledTimes(1); - expect(rootHttpRouter.use).toHaveBeenCalledWith( - '/some/test1/path', - expect.any(Function), - ); - - const router2 = await tester.get('test2'); - router2.use(() => {}); - expect(rootHttpRouter.use).toHaveBeenCalledTimes(2); - expect(rootHttpRouter.use).toHaveBeenCalledWith( - '/some/test2/path', - expect.any(Function), - ); - }); - describe('auth services', () => { const pluginSubject = createBackendPlugin({ pluginId: 'test', diff --git a/packages/backend-defaults/src/entrypoints/httpRouter/httpRouterServiceFactory.ts b/packages/backend-defaults/src/entrypoints/httpRouter/httpRouterServiceFactory.ts index 4a0dec49e6..fb2646580b 100644 --- a/packages/backend-defaults/src/entrypoints/httpRouter/httpRouterServiceFactory.ts +++ b/packages/backend-defaults/src/entrypoints/httpRouter/httpRouterServiceFactory.ts @@ -26,16 +26,6 @@ import { createCredentialsBarrier } from './createCredentialsBarrier'; import { createAuthIntegrationRouter } from './createAuthIntegrationRouter'; import { createCookieAuthRefreshMiddleware } from './createCookieAuthRefreshMiddleware'; -/** - * @public - */ -export interface HttpRouterFactoryOptions { - /** - * A callback used to generate the path for each plugin, defaults to `/api/{pluginId}`. - */ - getPath?(pluginId: string): string; -} - /** * HTTP route registration for plugins. * @@ -45,57 +35,39 @@ export interface HttpRouterFactoryOptions { * * @public */ -export const httpRouterServiceFactory = createServiceFactory( - (options?: HttpRouterFactoryOptions) => ({ - service: coreServices.httpRouter, - initialization: 'always', - deps: { - plugin: coreServices.pluginMetadata, - config: coreServices.rootConfig, - logger: coreServices.logger, - lifecycle: coreServices.lifecycle, - rootHttpRouter: coreServices.rootHttpRouter, - auth: coreServices.auth, - httpAuth: coreServices.httpAuth, - }, - async factory({ - auth, +export const httpRouterServiceFactory = createServiceFactory({ + service: coreServices.httpRouter, + initialization: 'always', + deps: { + plugin: coreServices.pluginMetadata, + config: coreServices.rootConfig, + lifecycle: coreServices.lifecycle, + rootHttpRouter: coreServices.rootHttpRouter, + auth: coreServices.auth, + httpAuth: coreServices.httpAuth, + }, + async factory({ auth, httpAuth, config, plugin, rootHttpRouter, lifecycle }) { + const router = PromiseRouter(); + + rootHttpRouter.use(`/api/${plugin.getId()}`, router); + + const credentialsBarrier = createCredentialsBarrier({ httpAuth, config, - logger, - plugin, - rootHttpRouter, - lifecycle, - }) { - if (options?.getPath) { - logger.warn( - `DEPRECATION WARNING: The 'getPath' option for HttpRouterService is deprecated. The ability to reconfigure the '/api/' path prefix for plugins will be removed in the future.`, - ); - } - const getPath = options?.getPath ?? (id => `/api/${id}`); - const path = getPath(plugin.getId()); + }); - const router = PromiseRouter(); - rootHttpRouter.use(path, router); + router.use(createAuthIntegrationRouter({ auth })); + router.use(createLifecycleMiddleware({ lifecycle })); + router.use(credentialsBarrier.middleware); + router.use(createCookieAuthRefreshMiddleware({ auth, httpAuth })); - const credentialsBarrier = createCredentialsBarrier({ - httpAuth, - config, - }); - - router.use(createAuthIntegrationRouter({ auth })); - router.use(createLifecycleMiddleware({ lifecycle })); - router.use(credentialsBarrier.middleware); - router.use(createCookieAuthRefreshMiddleware({ auth, httpAuth })); - - return { - use(handler: Handler): void { - router.use(handler); - }, - addAuthPolicy(policy: HttpRouterServiceAuthPolicy): void { - credentialsBarrier.addAuthPolicy(policy); - }, - }; - }, - }), -); + return { + use(handler: Handler): void { + router.use(handler); + }, + addAuthPolicy(policy: HttpRouterServiceAuthPolicy): void { + credentialsBarrier.addAuthPolicy(policy); + }, + }; + }, +}); diff --git a/packages/backend-defaults/src/entrypoints/httpRouter/index.ts b/packages/backend-defaults/src/entrypoints/httpRouter/index.ts index 928a232131..bc12480ae8 100644 --- a/packages/backend-defaults/src/entrypoints/httpRouter/index.ts +++ b/packages/backend-defaults/src/entrypoints/httpRouter/index.ts @@ -15,6 +15,5 @@ */ export { httpRouterServiceFactory } from './httpRouterServiceFactory'; -export type { HttpRouterFactoryOptions } from './httpRouterServiceFactory'; export { createLifecycleMiddleware } from './createLifecycleMiddleware'; export type { LifecycleMiddlewareOptions } from './createLifecycleMiddleware'; diff --git a/packages/backend-test-utils/api-report.md b/packages/backend-test-utils/api-report.md index a2fb4b7674..0a44fa5ed3 100644 --- a/packages/backend-test-utils/api-report.md +++ b/packages/backend-test-utils/api-report.md @@ -22,7 +22,6 @@ import { EventsService } from '@backstage/plugin-events-node'; import { ExtendedHttpServer } from '@backstage/backend-app-api'; import { ExtensionPoint } from '@backstage/backend-plugin-api'; import { HttpAuthService } from '@backstage/backend-plugin-api'; -import { HttpRouterFactoryOptions } from '@backstage/backend-defaults/httpRouter'; import { HttpRouterService } from '@backstage/backend-plugin-api'; import { IdentityService } from '@backstage/backend-plugin-api'; import { JsonObject } from '@backstage/types'; @@ -221,9 +220,7 @@ export namespace mockServices { // (undocumented) export namespace httpRouter { const // (undocumented) - factory: ( - options?: HttpRouterFactoryOptions | undefined, - ) => ServiceFactory; + factory: () => ServiceFactory; const // (undocumented) mock: ( partialImpl?: Partial | undefined, From 2f991786a3f9bfb227e7ea6ee97b2f9a8b6dfa28 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Wed, 10 Jul 2024 11:50:52 +0200 Subject: [PATCH 206/416] refactor(test-utils): rename `ServiceFactoryTester.get` to `ServiceFactoryTestest.getSubject` Signed-off-by: Camila Belo --- .changeset/chilly-coats-report.md | 7 +++ .../scheduler/schedulerServiceFactory.test.ts | 2 +- .../tokenManagerServiceFactory.test.ts | 2 +- .../auth/authServiceFactory.test.ts | 24 +++++----- .../httpRouterServiceFactory.test.ts | 4 +- .../scheduler/schedulerServiceFactory.test.ts | 2 +- packages/backend-test-utils/api-report.md | 4 ++ .../next/wiring/ServiceFactoryTester.test.ts | 46 +++++++++---------- .../src/next/wiring/ServiceFactoryTester.ts | 13 +++++- 9 files changed, 63 insertions(+), 41 deletions(-) create mode 100644 .changeset/chilly-coats-report.md diff --git a/.changeset/chilly-coats-report.md b/.changeset/chilly-coats-report.md new file mode 100644 index 0000000000..2fd044b57c --- /dev/null +++ b/.changeset/chilly-coats-report.md @@ -0,0 +1,7 @@ +--- +'@backstage/backend-test-utils': patch +'@backstage/backend-defaults': patch +'@backstage/backend-app-api': patch +--- + +The `ServiceFactoryTest.get` method was deprecated and the `ServiceFactoryTest.getSubject` should be used instead. The `getSubject` method has the same behavior, but has a better method name to indicate that the service instance returned is the subject currently being tested. diff --git a/packages/backend-app-api/src/services/implementations/scheduler/schedulerServiceFactory.test.ts b/packages/backend-app-api/src/services/implementations/scheduler/schedulerServiceFactory.test.ts index 7b889b3a0e..b16509cf96 100644 --- a/packages/backend-app-api/src/services/implementations/scheduler/schedulerServiceFactory.test.ts +++ b/packages/backend-app-api/src/services/implementations/scheduler/schedulerServiceFactory.test.ts @@ -22,7 +22,7 @@ describe('schedulerFactory', () => { it('creates sidecar database features', async () => { const tester = ServiceFactoryTester.from(schedulerServiceFactory()); - const scheduler = await tester.get(); + const scheduler = await tester.getSubject(); await scheduler.scheduleTask({ id: 'task1', timeout: { seconds: 1 }, diff --git a/packages/backend-app-api/src/services/implementations/tokenManager/tokenManagerServiceFactory.test.ts b/packages/backend-app-api/src/services/implementations/tokenManager/tokenManagerServiceFactory.test.ts index f603c6295e..dc52130ec6 100644 --- a/packages/backend-app-api/src/services/implementations/tokenManager/tokenManagerServiceFactory.test.ts +++ b/packages/backend-app-api/src/services/implementations/tokenManager/tokenManagerServiceFactory.test.ts @@ -21,7 +21,7 @@ describe('tokenManagerFactory', () => { it('should create a disabled manager without configuration', async () => { const tokenManager = await ServiceFactoryTester.from( tokenManagerServiceFactory, - ).get(); + ).getSubject(); await expect(tokenManager.authenticate('abc')).rejects.toThrow( 'no legacy keys are configured', diff --git a/packages/backend-defaults/src/entrypoints/auth/authServiceFactory.test.ts b/packages/backend-defaults/src/entrypoints/auth/authServiceFactory.test.ts index 22357d0f49..de89efa351 100644 --- a/packages/backend-defaults/src/entrypoints/auth/authServiceFactory.test.ts +++ b/packages/backend-defaults/src/entrypoints/auth/authServiceFactory.test.ts @@ -86,8 +86,8 @@ describe('authServiceFactory', () => { dependencies: mockDeps, }); - const searchAuth = await tester.get('search'); - const catalogAuth = await tester.get('catalog'); + const searchAuth = await tester.getSubject('search'); + const catalogAuth = await tester.getSubject('catalog'); const { token: searchToken } = await searchAuth.getPluginRequestToken({ onBehalfOf: await searchAuth.getOwnServiceCredentials(), @@ -117,8 +117,8 @@ describe('authServiceFactory', () => { dependencies: mockDeps, }); - const searchAuth = await tester.get('search'); - const catalogAuth = await tester.get('catalog'); + const searchAuth = await tester.getSubject('search'); + const catalogAuth = await tester.getSubject('catalog'); server.use( rest.get( @@ -163,7 +163,7 @@ describe('authServiceFactory', () => { dependencies: mockDeps, }); - const catalogAuth = await tester.get('catalog'); + const catalogAuth = await tester.getSubject('catalog'); await expect( catalogAuth.getPluginRequestToken({ @@ -194,7 +194,7 @@ describe('authServiceFactory', () => { dependencies: mockDeps, }); - const catalogAuth = await tester.get('catalog'); + const catalogAuth = await tester.getSubject('catalog'); const { token } = await catalogAuth.getPluginRequestToken({ onBehalfOf: { @@ -261,7 +261,7 @@ describe('authServiceFactory', () => { dependencies: mockDeps, }); - const catalogAuth = await tester.get('catalog'); + const catalogAuth = await tester.getSubject('catalog'); const fullToken = 'eyJ0eXAiOiJ2bmQuYmFja3N0YWdlLnVzZXIiLCJhbGciOiJFUzI1NiIsImtpZCI6IjhkMDFjM2RiLTU2ZjktNDVmMC04NmRkLTA1YjNjODM1YjNkMyJ9.eyJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjcwMDcvYXBpL2F1dGgiLCJzdWIiOiJ1c2VyOmRldmVsb3BtZW50L2d1ZXN0IiwiZW50IjpbInVzZXI6ZGV2ZWxvcG1lbnQvZ3Vlc3QiLCJncm91cDpkZWZhdWx0L3RlYW0tYSJdLCJhdWQiOiJiYWNrc3RhZ2UiLCJpYXQiOjE3MTIwNzE3MTQsImV4cCI6MTcxMjA3NTMxNCwidWlwIjoiSmwxVEpycG9VUjR1NENjUE9nalJMeHpEMi1FMGZPR3ptSm81UWI2eS1aN19meG5oVVBEdWVWRE1CS0l6WF9pc0lvSDhlZm9EUFA5bG9aQnpPblB5Z2cifQ.1gVMq1ofO8PzRctu72D6c4IMqXuIabT79WdGEhW6vIrBRs_qhuWAa94Wvz_KYKpBTb2nxgzXJ5OeddeoYApMyQ'; @@ -318,9 +318,9 @@ describe('authServiceFactory', () => { dependencies: mockDeps, }); - const searchAuth = await tester.get('search'); - const catalogAuth = await tester.get('catalog'); - const permissionAuth = await tester.get('permission'); + const searchAuth = await tester.getSubject('search'); + const catalogAuth = await tester.getSubject('catalog'); + const permissionAuth = await tester.getSubject('permission'); /* Corresponding private key in case this test needs to be updated in the future: { @@ -431,7 +431,7 @@ describe('authServiceFactory', () => { dependencies: mockDeps, }); - const catalogAuth = await tester.get('catalog'); + const catalogAuth = await tester.getSubject('catalog'); await expect( catalogAuth.authenticate('limited-static-token'), @@ -450,7 +450,7 @@ describe('authServiceFactory', () => { }, }); - const scaffolderAuth = await tester.get('scaffolder'); + const scaffolderAuth = await tester.getSubject('scaffolder'); await expect( scaffolderAuth.authenticate('limited-static-token'), diff --git a/packages/backend-defaults/src/entrypoints/httpRouter/httpRouterServiceFactory.test.ts b/packages/backend-defaults/src/entrypoints/httpRouter/httpRouterServiceFactory.test.ts index 17665a176a..a8b749939b 100644 --- a/packages/backend-defaults/src/entrypoints/httpRouter/httpRouterServiceFactory.test.ts +++ b/packages/backend-defaults/src/entrypoints/httpRouter/httpRouterServiceFactory.test.ts @@ -35,7 +35,7 @@ describe('httpRouterFactory', () => { dependencies: [rootHttpRouter.factory], }); - const router1 = await tester.get('test1'); + const router1 = await tester.getSubject('test1'); router1.use(() => {}); expect(rootHttpRouter.use).toHaveBeenCalledTimes(1); expect(rootHttpRouter.use).toHaveBeenCalledWith( @@ -43,7 +43,7 @@ describe('httpRouterFactory', () => { expect.any(Function), ); - const router2 = await tester.get('test2'); + const router2 = await tester.getSubject('test2'); router2.use(() => {}); expect(rootHttpRouter.use).toHaveBeenCalledTimes(2); expect(rootHttpRouter.use).toHaveBeenCalledWith( diff --git a/packages/backend-defaults/src/entrypoints/scheduler/schedulerServiceFactory.test.ts b/packages/backend-defaults/src/entrypoints/scheduler/schedulerServiceFactory.test.ts index 7b889b3a0e..b16509cf96 100644 --- a/packages/backend-defaults/src/entrypoints/scheduler/schedulerServiceFactory.test.ts +++ b/packages/backend-defaults/src/entrypoints/scheduler/schedulerServiceFactory.test.ts @@ -22,7 +22,7 @@ describe('schedulerFactory', () => { it('creates sidecar database features', async () => { const tester = ServiceFactoryTester.from(schedulerServiceFactory()); - const scheduler = await tester.get(); + const scheduler = await tester.getSubject(); await scheduler.scheduleTask({ id: 'task1', timeout: { seconds: 1 }, diff --git a/packages/backend-test-utils/api-report.md b/packages/backend-test-utils/api-report.md index 0a44fa5ed3..a61d1ccb58 100644 --- a/packages/backend-test-utils/api-report.md +++ b/packages/backend-test-utils/api-report.md @@ -373,6 +373,7 @@ export class ServiceFactoryTester { | (() => ServiceFactory), options?: ServiceFactoryTesterOptions, ): ServiceFactoryTester; + // @deprecated get( ...args: 'root' extends TScope ? [] : [pluginId?: string] ): Promise; @@ -380,6 +381,9 @@ export class ServiceFactoryTester { service: ServiceRef, ...args: 'root' extends TGetScope ? [] : [pluginId?: string] ): Promise; + getSubject( + ...args: 'root' extends TScope ? [] : [pluginId?: string] + ): Promise; } // @public diff --git a/packages/backend-test-utils/src/next/wiring/ServiceFactoryTester.test.ts b/packages/backend-test-utils/src/next/wiring/ServiceFactoryTester.test.ts index 14dd427ecf..5970f6ea52 100644 --- a/packages/backend-test-utils/src/next/wiring/ServiceFactoryTester.test.ts +++ b/packages/backend-test-utils/src/next/wiring/ServiceFactoryTester.test.ts @@ -56,34 +56,34 @@ describe('ServiceFactoryTester', () => { it('should test a root service factory', async () => { const tester = ServiceFactoryTester.from(rootFactory); - await expect(tester.get()).resolves.toBe('root'); + await expect(tester.getSubject()).resolves.toBe('root'); }); it('should test a plugin service factory', async () => { const tester = ServiceFactoryTester.from(pluginFactory); - await expect(tester.get('x')).resolves.toBe('x-plugin'); - await expect(tester.get('y')).resolves.toBe('y-plugin'); - await expect(tester.get('z')).resolves.toBe('z-plugin'); + await expect(tester.getSubject('x')).resolves.toBe('x-plugin'); + await expect(tester.getSubject('y')).resolves.toBe('y-plugin'); + await expect(tester.getSubject('z')).resolves.toBe('z-plugin'); }); it('should test a plugin service factory with root context', async () => { const tester = ServiceFactoryTester.from(sharedPluginFactory); - await expect(tester.get('x')).resolves.toBe('x-1-plugin'); - await expect(tester.get('y')).resolves.toBe('y-2-plugin'); - await expect(tester.get('y')).resolves.toBe('y-2-plugin'); - await expect(tester.get('y')).resolves.toBe('y-2-plugin'); - await expect(tester.get('z')).resolves.toBe('z-3-plugin'); + await expect(tester.getSubject('x')).resolves.toBe('x-1-plugin'); + await expect(tester.getSubject('y')).resolves.toBe('y-2-plugin'); + await expect(tester.getSubject('y')).resolves.toBe('y-2-plugin'); + await expect(tester.getSubject('y')).resolves.toBe('y-2-plugin'); + await expect(tester.getSubject('z')).resolves.toBe('z-3-plugin'); const tester2 = ServiceFactoryTester.from(sharedPluginFactory); - await expect(tester2.get('z')).resolves.toBe('z-1-plugin'); - await expect(tester2.get('y')).resolves.toBe('y-2-plugin'); - await expect(tester2.get('x')).resolves.toBe('x-3-plugin'); - await expect(tester2.get('x')).resolves.toBe('x-3-plugin'); - await expect(tester2.get('y')).resolves.toBe('y-2-plugin'); - await expect(tester2.get('z')).resolves.toBe('z-1-plugin'); + await expect(tester2.getSubject('z')).resolves.toBe('z-1-plugin'); + await expect(tester2.getSubject('y')).resolves.toBe('y-2-plugin'); + await expect(tester2.getSubject('x')).resolves.toBe('x-3-plugin'); + await expect(tester2.getSubject('x')).resolves.toBe('x-3-plugin'); + await expect(tester2.getSubject('y')).resolves.toBe('y-2-plugin'); + await expect(tester2.getSubject('z')).resolves.toBe('z-1-plugin'); }); it('should use dependencies', async () => { @@ -96,7 +96,7 @@ describe('ServiceFactoryTester', () => { { dependencies: [rootFactory, pluginFactory()] }, ); - await expect(tester.get('x')).resolves.toBe('root, x-plugin'); + await expect(tester.getSubject('x')).resolves.toBe('root, x-plugin'); }); it('should use dependencies with root context', async () => { @@ -109,11 +109,11 @@ describe('ServiceFactoryTester', () => { { dependencies: [sharedPluginFactory(), pluginFactory] }, ); - await expect(tester.get('x')).resolves.toBe('x-1-plugin, x-plugin'); - await expect(tester.get('y')).resolves.toBe('y-2-plugin, y-plugin'); - await expect(tester.get('y')).resolves.toBe('y-2-plugin, y-plugin'); - await expect(tester.get('y')).resolves.toBe('y-2-plugin, y-plugin'); - await expect(tester.get('z')).resolves.toBe('z-3-plugin, z-plugin'); + await expect(tester.getSubject('x')).resolves.toBe('x-1-plugin, x-plugin'); + await expect(tester.getSubject('y')).resolves.toBe('y-2-plugin, y-plugin'); + await expect(tester.getSubject('y')).resolves.toBe('y-2-plugin, y-plugin'); + await expect(tester.getSubject('y')).resolves.toBe('y-2-plugin, y-plugin'); + await expect(tester.getSubject('z')).resolves.toBe('z-3-plugin, z-plugin'); }); it('should prioritize the subject implementation', async () => { @@ -126,7 +126,7 @@ describe('ServiceFactoryTester', () => { { dependencies: [rootFactory] }, ); - await expect(tester.get()).resolves.toBe('other-root'); + await expect(tester.getSubject()).resolves.toBe('other-root'); }); it('should throw on missing dependencies', async () => { @@ -138,7 +138,7 @@ describe('ServiceFactoryTester', () => { }), ); - await expect(tester.get('x')).rejects.toThrow( + await expect(tester.getSubject('x')).rejects.toThrow( "Failed to instantiate service 'b' for 'x' because the following dependent services are missing: 'a'", ); }); diff --git a/packages/backend-test-utils/src/next/wiring/ServiceFactoryTester.ts b/packages/backend-test-utils/src/next/wiring/ServiceFactoryTester.ts index 0555ab10a4..40b473663b 100644 --- a/packages/backend-test-utils/src/next/wiring/ServiceFactoryTester.ts +++ b/packages/backend-test-utils/src/next/wiring/ServiceFactoryTester.ts @@ -79,6 +79,17 @@ export class ServiceFactoryTester { this.#registry = registry; } + /** + * Returns the service instance for the subject. + * + * @deprecated Use `getSubject` instead. + */ + async get( + ...args: 'root' extends TScope ? [] : [pluginId?: string] + ): Promise { + return this.getSubject(...args); + } + /** * Returns the service instance for the subject. * @@ -89,7 +100,7 @@ export class ServiceFactoryTester { * * By default the plugin ID 'test' is used. */ - async get( + async getSubject( ...args: 'root' extends TScope ? [] : [pluginId?: string] ): Promise { const [pluginId] = args; From 062c01c7c411aa13eb3c28d3726bf757c80d74a6 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 10 Jul 2024 12:12:22 +0200 Subject: [PATCH 207/416] backend-plugin-api: deprecate service factories with callback form Signed-off-by: Patrik Oldsberg --- .changeset/spotty-apricots-tan.md | 55 ++++++++++ packages/backend-app-api/api-report-alpha.md | 7 +- packages/backend-app-api/api-report.md | 103 +++++++++++------- packages/backend-defaults/api-report-auth.md | 8 +- packages/backend-defaults/api-report-cache.md | 8 +- .../backend-defaults/api-report-database.md | 7 +- .../backend-defaults/api-report-discovery.md | 7 +- .../backend-defaults/api-report-httpAuth.md | 7 +- .../backend-defaults/api-report-httpRouter.md | 7 +- .../backend-defaults/api-report-lifecycle.md | 7 +- .../backend-defaults/api-report-logger.md | 7 +- .../api-report-permissions.md | 7 +- .../backend-defaults/api-report-rootConfig.md | 10 +- .../backend-defaults/api-report-rootHealth.md | 7 +- .../api-report-rootHttpRouter.md | 10 +- .../api-report-rootLifecycle.md | 7 +- .../backend-defaults/api-report-rootLogger.md | 7 +- .../backend-defaults/api-report-scheduler.md | 7 +- .../backend-defaults/api-report-urlReader.md | 7 +- .../backend-defaults/api-report-userInfo.md | 7 +- .../api-report.md | 28 +++-- packages/backend-plugin-api/api-report.md | 34 ++++-- .../src/services/system/index.ts | 1 + .../src/services/system/types.ts | 59 ++++++++-- packages/backend-test-utils/api-report.md | 51 +++++---- plugins/events-node/api-report.md | 7 +- 26 files changed, 321 insertions(+), 151 deletions(-) create mode 100644 .changeset/spotty-apricots-tan.md diff --git a/.changeset/spotty-apricots-tan.md b/.changeset/spotty-apricots-tan.md new file mode 100644 index 0000000000..bc1b26e2f4 --- /dev/null +++ b/.changeset/spotty-apricots-tan.md @@ -0,0 +1,55 @@ +--- +'@backstage/backend-plugin-api': patch +--- + +Deprecated the ability to define options for service factories through `createServiceFactory`. In the future all service factories will return a plain `ServiceFactory` object, rather than allowing users to pass options to the factory. To allow for customization of a service implementation one can instead export one or a few building blocks that allows for simple re-implementation of the service instead. + +For example, instead of: + +```ts +export const fooServiceFactory = createServiceFactory( + (options?: { bar: string }) => ({ + service: fooServiceRef, + deps: { logger: coreServices.logger }, + factory({ logger }) { + return { + // Implementation of the foo service using the `bar` option. + }; + }, + }), +); +``` + +We instead encourage service implementations to provide an easy to use API for re-implementing the service for advanced use-cases: + +```ts +/** @public */ +export class DefaultFooService implements FooService { + static create(options: { bar: string; logger: LoggerService }) { + return new DefaultFooService(options.logger, options.bar ?? 'default'); + } + + private constructor( + private readonly logger: string, + private readonly bar: string, + ) {} + + // The rest of the implementation +} +``` + +A user that wishes to customize the service can then easily do so by defining their own factory: + +```ts +export const fooServiceFactory = createServiceFactory({ + service: fooServiceRef, + deps: { logger: coreServices.logger }, + factory({ logger }) { + return DefaultFooService.create({ logger, bar: 'baz' }); + }, +}); +``` + +This is of course more verbose than the previous solution where the factory could be customized through `fooServiceFactory({ bar: 'baz' })`, but this is a simplified which in practice should be using static configuration instead. + +This change is being made because the ability to define an options callback encourages bad design of services factories. When possible, a service should be configurable through static configuration, and the existence of options may discourage that. More importantly though, the existing options do not work well with the dependency injection system of services, which is a problem for callbacks an other more advanced options. This lead to a bad pattern where only a few explicit dependencies where made available in callbacks, rather than providing an API that allowed simple re-implementation of the service with full access to dependency injection. diff --git a/packages/backend-app-api/api-report-alpha.md b/packages/backend-app-api/api-report-alpha.md index 488feedf2c..e4769f4e72 100644 --- a/packages/backend-app-api/api-report-alpha.md +++ b/packages/backend-app-api/api-report-alpha.md @@ -4,12 +4,13 @@ ```ts import { FeatureDiscoveryService } from '@backstage/backend-plugin-api/alpha'; -import { ServiceFactory } from '@backstage/backend-plugin-api'; +import { ServiceFactoryCompat } from '@backstage/backend-plugin-api'; // @alpha (undocumented) -export const featureDiscoveryServiceFactory: () => ServiceFactory< +export const featureDiscoveryServiceFactory: ServiceFactoryCompat< FeatureDiscoveryService, - 'root' + 'root', + undefined >; // (No @packageDocumentation comment for this package) diff --git a/packages/backend-app-api/api-report.md b/packages/backend-app-api/api-report.md index c577084a58..51839b88be 100644 --- a/packages/backend-app-api/api-report.md +++ b/packages/backend-app-api/api-report.md @@ -38,7 +38,7 @@ import { RootLifecycleService } from '@backstage/backend-plugin-api'; import { RootLoggerService } from '@backstage/backend-plugin-api'; import { SchedulerService } from '@backstage/backend-plugin-api'; import type { Server } from 'node:http'; -import { ServiceFactory } from '@backstage/backend-plugin-api'; +import { ServiceFactoryCompat } from '@backstage/backend-plugin-api'; import { ServiceFactoryOrFunction } from '@backstage/backend-plugin-api'; import { TokenManagerService } from '@backstage/backend-plugin-api'; import { transport } from 'winston'; @@ -46,7 +46,11 @@ import { UrlReaderService } from '@backstage/backend-plugin-api'; import { UserInfoService } from '@backstage/backend-plugin-api'; // @public @deprecated (undocumented) -export const authServiceFactory: () => ServiceFactory; +export const authServiceFactory: ServiceFactoryCompat< + AuthService, + 'plugin', + undefined +>; // @public (undocumented) export interface Backend { @@ -66,7 +70,11 @@ export interface Backend { } // @public @deprecated (undocumented) -export const cacheServiceFactory: () => ServiceFactory; +export const cacheServiceFactory: ServiceFactoryCompat< + CacheService, + 'plugin', + undefined +>; // Warning: (ae-forgotten-export) The symbol "createConfigSecretEnumerator_2" needs to be exported by the entry point index.d.ts // @@ -95,9 +103,10 @@ export interface CreateSpecializedBackendOptions { } // @public @deprecated (undocumented) -export const databaseServiceFactory: () => ServiceFactory< +export const databaseServiceFactory: ServiceFactoryCompat< DatabaseService, - 'plugin' + 'plugin', + undefined >; // @public @deprecated @@ -116,9 +125,10 @@ export class DefaultRootHttpRouter implements RootHttpRouterService { export type DefaultRootHttpRouterOptions = DefaultRootHttpRouterOptions_2; // @public @deprecated (undocumented) -export const discoveryServiceFactory: () => ServiceFactory< +export const discoveryServiceFactory: ServiceFactoryCompat< DiscoveryService, - 'plugin' + 'plugin', + undefined >; // Warning: (ae-forgotten-export) The symbol "ExtendedHttpServer_2" needs to be exported by the entry point index.d.ts @@ -141,15 +151,17 @@ export class HostDiscovery implements DiscoveryService { } // @public @deprecated (undocumented) -export const httpAuthServiceFactory: () => ServiceFactory< +export const httpAuthServiceFactory: ServiceFactoryCompat< HttpAuthService, - 'plugin' + 'plugin', + undefined >; // @public @deprecated -export const httpRouterServiceFactory: () => ServiceFactory< +export const httpRouterServiceFactory: ServiceFactoryCompat< HttpRouterService, - 'plugin' + 'plugin', + undefined >; // Warning: (ae-forgotten-export) The symbol "HttpServerCertificateOptions_2" needs to be exported by the entry point index.d.ts @@ -169,9 +181,11 @@ export type IdentityFactoryOptions = { }; // @public @deprecated (undocumented) -export const identityServiceFactory: ( - options?: IdentityFactoryOptions | undefined, -) => ServiceFactory; +export const identityServiceFactory: ServiceFactoryCompat< + IdentityService, + 'plugin', + IdentityFactoryOptions +>; // Warning: (ae-forgotten-export) The symbol "LifecycleMiddlewareOptions_2" needs to be exported by the entry point index.d.ts // @@ -179,9 +193,10 @@ export const identityServiceFactory: ( export type LifecycleMiddlewareOptions = LifecycleMiddlewareOptions_2; // @public @deprecated -export const lifecycleServiceFactory: () => ServiceFactory< +export const lifecycleServiceFactory: ServiceFactoryCompat< LifecycleService, - 'plugin' + 'plugin', + undefined >; // @public @deprecated @@ -195,9 +210,10 @@ export function loadBackendConfig(options: { }>; // @public @deprecated -export const loggerServiceFactory: () => ServiceFactory< +export const loggerServiceFactory: ServiceFactoryCompat< LoggerService, - 'plugin' + 'plugin', + undefined >; // @public @deprecated (undocumented) @@ -222,9 +238,10 @@ export type MiddlewareFactoryErrorOptions = MiddlewareFactoryErrorOptions_2; export type MiddlewareFactoryOptions = MiddlewareFactoryOptions_2; // @public @deprecated (undocumented) -export const permissionsServiceFactory: () => ServiceFactory< +export const permissionsServiceFactory: ServiceFactoryCompat< PermissionsService, - 'plugin' + 'plugin', + undefined >; // Warning: (ae-forgotten-export) The symbol "readCorsOptions_2" needs to be exported by the entry point index.d.ts @@ -251,9 +268,11 @@ export interface RootConfigFactoryOptions { } // @public @deprecated (undocumented) -export const rootConfigServiceFactory: ( - options?: RootConfigFactoryOptions | undefined, -) => ServiceFactory; +export const rootConfigServiceFactory: ServiceFactoryCompat< + RootConfigService, + 'root', + RootConfigFactoryOptions +>; // Warning: (ae-forgotten-export) The symbol "RootHttpRouterConfigureContext_2" needs to be exported by the entry point index.d.ts // @@ -266,44 +285,52 @@ export type RootHttpRouterConfigureContext = RootHttpRouterConfigureContext_2; export type RootHttpRouterFactoryOptions = RootHttpRouterFactoryOptions_2; // @public @deprecated (undocumented) -export const rootHttpRouterServiceFactory: ( - options?: RootHttpRouterFactoryOptions_2 | undefined, -) => ServiceFactory; +export const rootHttpRouterServiceFactory: ServiceFactoryCompat< + RootHttpRouterService, + 'root', + RootHttpRouterFactoryOptions_2 +>; // @public @deprecated -export const rootLifecycleServiceFactory: () => ServiceFactory< +export const rootLifecycleServiceFactory: ServiceFactoryCompat< RootLifecycleService, - 'root' + 'root', + undefined >; // @public @deprecated -export const rootLoggerServiceFactory: () => ServiceFactory< +export const rootLoggerServiceFactory: ServiceFactoryCompat< RootLoggerService, - 'root' + 'root', + undefined >; // @public @deprecated (undocumented) -export const schedulerServiceFactory: () => ServiceFactory< +export const schedulerServiceFactory: ServiceFactoryCompat< SchedulerService, - 'plugin' + 'plugin', + undefined >; // @public @deprecated (undocumented) -export const tokenManagerServiceFactory: () => ServiceFactory< +export const tokenManagerServiceFactory: ServiceFactoryCompat< TokenManagerService, - 'plugin' + 'plugin', + undefined >; // @public @deprecated (undocumented) -export const urlReaderServiceFactory: () => ServiceFactory< +export const urlReaderServiceFactory: ServiceFactoryCompat< UrlReaderService, - 'plugin' + 'plugin', + undefined >; // @public @deprecated (undocumented) -export const userInfoServiceFactory: () => ServiceFactory< +export const userInfoServiceFactory: ServiceFactoryCompat< UserInfoService, - 'plugin' + 'plugin', + undefined >; // @public @deprecated diff --git a/packages/backend-defaults/api-report-auth.md b/packages/backend-defaults/api-report-auth.md index d64ce5bc2a..7df0b394e3 100644 --- a/packages/backend-defaults/api-report-auth.md +++ b/packages/backend-defaults/api-report-auth.md @@ -4,10 +4,14 @@ ```ts import { AuthService } from '@backstage/backend-plugin-api'; -import { ServiceFactory } from '@backstage/backend-plugin-api'; +import { ServiceFactoryCompat } from '@backstage/backend-plugin-api'; // @public -export const authServiceFactory: () => ServiceFactory; +export const authServiceFactory: ServiceFactoryCompat< + AuthService, + 'plugin', + undefined +>; // (No @packageDocumentation comment for this package) ``` diff --git a/packages/backend-defaults/api-report-cache.md b/packages/backend-defaults/api-report-cache.md index 0bfd7eb463..0b2d8706df 100644 --- a/packages/backend-defaults/api-report-cache.md +++ b/packages/backend-defaults/api-report-cache.md @@ -7,7 +7,7 @@ import { CacheService } from '@backstage/backend-plugin-api'; import { CacheServiceOptions } from '@backstage/backend-plugin-api'; import { Config } from '@backstage/config'; import { LoggerService } from '@backstage/backend-plugin-api'; -import { ServiceFactory } from '@backstage/backend-plugin-api'; +import { ServiceFactoryCompat } from '@backstage/backend-plugin-api'; // @public export class CacheManager { @@ -25,7 +25,11 @@ export type CacheManagerOptions = { }; // @public -export const cacheServiceFactory: () => ServiceFactory; +export const cacheServiceFactory: ServiceFactoryCompat< + CacheService, + 'plugin', + undefined +>; // @public (undocumented) export interface PluginCacheManager { diff --git a/packages/backend-defaults/api-report-database.md b/packages/backend-defaults/api-report-database.md index 116830343a..0d54b43777 100644 --- a/packages/backend-defaults/api-report-database.md +++ b/packages/backend-defaults/api-report-database.md @@ -8,7 +8,7 @@ import { DatabaseService } from '@backstage/backend-plugin-api'; import { LifecycleService } from '@backstage/backend-plugin-api'; import { LoggerService } from '@backstage/backend-plugin-api'; import { PluginMetadataService } from '@backstage/backend-plugin-api'; -import { ServiceFactory } from '@backstage/backend-plugin-api'; +import { ServiceFactoryCompat } from '@backstage/backend-plugin-api'; // @public export class DatabaseManager implements LegacyRootDatabaseService { @@ -32,9 +32,10 @@ export type DatabaseManagerOptions = { }; // @public -export const databaseServiceFactory: () => ServiceFactory< +export const databaseServiceFactory: ServiceFactoryCompat< DatabaseService, - 'plugin' + 'plugin', + undefined >; // @public @deprecated diff --git a/packages/backend-defaults/api-report-discovery.md b/packages/backend-defaults/api-report-discovery.md index b434dab6fc..dbb469f758 100644 --- a/packages/backend-defaults/api-report-discovery.md +++ b/packages/backend-defaults/api-report-discovery.md @@ -5,12 +5,13 @@ ```ts import { Config } from '@backstage/config'; import { DiscoveryService } from '@backstage/backend-plugin-api'; -import { ServiceFactory } from '@backstage/backend-plugin-api'; +import { ServiceFactoryCompat } from '@backstage/backend-plugin-api'; // @public -export const discoveryServiceFactory: () => ServiceFactory< +export const discoveryServiceFactory: ServiceFactoryCompat< DiscoveryService, - 'plugin' + 'plugin', + undefined >; // @public diff --git a/packages/backend-defaults/api-report-httpAuth.md b/packages/backend-defaults/api-report-httpAuth.md index 6ffe3d6539..613e6a4452 100644 --- a/packages/backend-defaults/api-report-httpAuth.md +++ b/packages/backend-defaults/api-report-httpAuth.md @@ -4,12 +4,13 @@ ```ts import { HttpAuthService } from '@backstage/backend-plugin-api'; -import { ServiceFactory } from '@backstage/backend-plugin-api'; +import { ServiceFactoryCompat } from '@backstage/backend-plugin-api'; // @public -export const httpAuthServiceFactory: () => ServiceFactory< +export const httpAuthServiceFactory: ServiceFactoryCompat< HttpAuthService, - 'plugin' + 'plugin', + undefined >; // (No @packageDocumentation comment for this package) diff --git a/packages/backend-defaults/api-report-httpRouter.md b/packages/backend-defaults/api-report-httpRouter.md index f191a5a847..a2bf1cd39b 100644 --- a/packages/backend-defaults/api-report-httpRouter.md +++ b/packages/backend-defaults/api-report-httpRouter.md @@ -7,7 +7,7 @@ import { HttpRouterService } from '@backstage/backend-plugin-api'; import { HumanDuration } from '@backstage/types'; import { LifecycleService } from '@backstage/backend-plugin-api'; import { RequestHandler } from 'express'; -import { ServiceFactory } from '@backstage/backend-plugin-api'; +import { ServiceFactoryCompat } from '@backstage/backend-plugin-api'; // @public export function createLifecycleMiddleware( @@ -15,9 +15,10 @@ export function createLifecycleMiddleware( ): RequestHandler; // @public -export const httpRouterServiceFactory: () => ServiceFactory< +export const httpRouterServiceFactory: ServiceFactoryCompat< HttpRouterService, - 'plugin' + 'plugin', + undefined >; // @public diff --git a/packages/backend-defaults/api-report-lifecycle.md b/packages/backend-defaults/api-report-lifecycle.md index 4233584664..36adbbf6e7 100644 --- a/packages/backend-defaults/api-report-lifecycle.md +++ b/packages/backend-defaults/api-report-lifecycle.md @@ -4,12 +4,13 @@ ```ts import { LifecycleService } from '@backstage/backend-plugin-api'; -import { ServiceFactory } from '@backstage/backend-plugin-api'; +import { ServiceFactoryCompat } from '@backstage/backend-plugin-api'; // @public -export const lifecycleServiceFactory: () => ServiceFactory< +export const lifecycleServiceFactory: ServiceFactoryCompat< LifecycleService, - 'plugin' + 'plugin', + undefined >; // (No @packageDocumentation comment for this package) diff --git a/packages/backend-defaults/api-report-logger.md b/packages/backend-defaults/api-report-logger.md index fa9018a40c..c66f886bf4 100644 --- a/packages/backend-defaults/api-report-logger.md +++ b/packages/backend-defaults/api-report-logger.md @@ -4,12 +4,13 @@ ```ts import { LoggerService } from '@backstage/backend-plugin-api'; -import { ServiceFactory } from '@backstage/backend-plugin-api'; +import { ServiceFactoryCompat } from '@backstage/backend-plugin-api'; // @public -export const loggerServiceFactory: () => ServiceFactory< +export const loggerServiceFactory: ServiceFactoryCompat< LoggerService, - 'plugin' + 'plugin', + undefined >; // (No @packageDocumentation comment for this package) diff --git a/packages/backend-defaults/api-report-permissions.md b/packages/backend-defaults/api-report-permissions.md index c436443ff1..86b9605606 100644 --- a/packages/backend-defaults/api-report-permissions.md +++ b/packages/backend-defaults/api-report-permissions.md @@ -4,12 +4,13 @@ ```ts import { PermissionsService } from '@backstage/backend-plugin-api'; -import { ServiceFactory } from '@backstage/backend-plugin-api'; +import { ServiceFactoryCompat } from '@backstage/backend-plugin-api'; // @public -export const permissionsServiceFactory: () => ServiceFactory< +export const permissionsServiceFactory: ServiceFactoryCompat< PermissionsService, - 'plugin' + 'plugin', + undefined >; // (No @packageDocumentation comment for this package) diff --git a/packages/backend-defaults/api-report-rootConfig.md b/packages/backend-defaults/api-report-rootConfig.md index 317c451e1b..24e827f520 100644 --- a/packages/backend-defaults/api-report-rootConfig.md +++ b/packages/backend-defaults/api-report-rootConfig.md @@ -8,7 +8,7 @@ import { ConfigSchema } from '@backstage/config-loader'; import { LoggerService } from '@backstage/backend-plugin-api'; import { RemoteConfigSourceOptions } from '@backstage/config-loader'; import { RootConfigService } from '@backstage/backend-plugin-api'; -import { ServiceFactory } from '@backstage/backend-plugin-api'; +import { ServiceFactoryCompat } from '@backstage/backend-plugin-api'; // @public (undocumented) export function createConfigSecretEnumerator(options: { @@ -26,9 +26,11 @@ export interface RootConfigFactoryOptions { } // @public (undocumented) -export const rootConfigServiceFactory: ( - options?: RootConfigFactoryOptions | undefined, -) => ServiceFactory; +export const rootConfigServiceFactory: ServiceFactoryCompat< + RootConfigService, + 'root', + RootConfigFactoryOptions +>; // (No @packageDocumentation comment for this package) ``` diff --git a/packages/backend-defaults/api-report-rootHealth.md b/packages/backend-defaults/api-report-rootHealth.md index ffa067605a..c69f66e747 100644 --- a/packages/backend-defaults/api-report-rootHealth.md +++ b/packages/backend-defaults/api-report-rootHealth.md @@ -4,12 +4,13 @@ ```ts import { RootHealthService } from '@backstage/backend-plugin-api'; -import { ServiceFactory } from '@backstage/backend-plugin-api'; +import { ServiceFactoryCompat } from '@backstage/backend-plugin-api'; // @public (undocumented) -export const rootHealthServiceFactory: () => ServiceFactory< +export const rootHealthServiceFactory: ServiceFactoryCompat< RootHealthService, - 'root' + 'root', + undefined >; // (No @packageDocumentation comment for this package) diff --git a/packages/backend-defaults/api-report-rootHttpRouter.md b/packages/backend-defaults/api-report-rootHttpRouter.md index d9727fd36d..9ea4cd7ebb 100644 --- a/packages/backend-defaults/api-report-rootHttpRouter.md +++ b/packages/backend-defaults/api-report-rootHttpRouter.md @@ -19,7 +19,7 @@ import { RequestListener } from 'http'; import { RootConfigService } from '@backstage/backend-plugin-api'; import { RootHttpRouterService } from '@backstage/backend-plugin-api'; import type { Server } from 'node:http'; -import { ServiceFactory } from '@backstage/backend-plugin-api'; +import { ServiceFactoryCompat } from '@backstage/backend-plugin-api'; // @public export function createHttpServer( @@ -141,9 +141,11 @@ export type RootHttpRouterFactoryOptions = { }; // @public (undocumented) -export const rootHttpRouterServiceFactory: ( - options?: RootHttpRouterFactoryOptions | undefined, -) => ServiceFactory; +export const rootHttpRouterServiceFactory: ServiceFactoryCompat< + RootHttpRouterService, + 'root', + RootHttpRouterFactoryOptions +>; // (No @packageDocumentation comment for this package) ``` diff --git a/packages/backend-defaults/api-report-rootLifecycle.md b/packages/backend-defaults/api-report-rootLifecycle.md index 00eb9c1ebb..faa83706a7 100644 --- a/packages/backend-defaults/api-report-rootLifecycle.md +++ b/packages/backend-defaults/api-report-rootLifecycle.md @@ -4,12 +4,13 @@ ```ts import { RootLifecycleService } from '@backstage/backend-plugin-api'; -import { ServiceFactory } from '@backstage/backend-plugin-api'; +import { ServiceFactoryCompat } from '@backstage/backend-plugin-api'; // @public -export const rootLifecycleServiceFactory: () => ServiceFactory< +export const rootLifecycleServiceFactory: ServiceFactoryCompat< RootLifecycleService, - 'root' + 'root', + undefined >; // (No @packageDocumentation comment for this package) diff --git a/packages/backend-defaults/api-report-rootLogger.md b/packages/backend-defaults/api-report-rootLogger.md index 70dc0deee6..075a8b4aa9 100644 --- a/packages/backend-defaults/api-report-rootLogger.md +++ b/packages/backend-defaults/api-report-rootLogger.md @@ -7,13 +7,14 @@ import { Format } from 'logform'; import { JsonObject } from '@backstage/types'; import { LoggerService } from '@backstage/backend-plugin-api'; import { RootLoggerService } from '@backstage/backend-plugin-api'; -import { ServiceFactory } from '@backstage/backend-plugin-api'; +import { ServiceFactoryCompat } from '@backstage/backend-plugin-api'; import { transport } from 'winston'; // @public -export const rootLoggerServiceFactory: () => ServiceFactory< +export const rootLoggerServiceFactory: ServiceFactoryCompat< RootLoggerService, - 'root' + 'root', + undefined >; // @public diff --git a/packages/backend-defaults/api-report-scheduler.md b/packages/backend-defaults/api-report-scheduler.md index 58991ddca3..a3467b97de 100644 --- a/packages/backend-defaults/api-report-scheduler.md +++ b/packages/backend-defaults/api-report-scheduler.md @@ -6,7 +6,7 @@ import { DatabaseService } from '@backstage/backend-plugin-api'; import { LoggerService } from '@backstage/backend-plugin-api'; import { SchedulerService } from '@backstage/backend-plugin-api'; -import { ServiceFactory } from '@backstage/backend-plugin-api'; +import { ServiceFactoryCompat } from '@backstage/backend-plugin-api'; // @public export class DefaultSchedulerService { @@ -18,9 +18,10 @@ export class DefaultSchedulerService { } // @public -export const schedulerServiceFactory: () => ServiceFactory< +export const schedulerServiceFactory: ServiceFactoryCompat< SchedulerService, - 'plugin' + 'plugin', + undefined >; // (No @packageDocumentation comment for this package) diff --git a/packages/backend-defaults/api-report-urlReader.md b/packages/backend-defaults/api-report-urlReader.md index c56cdba69b..0980e3cd67 100644 --- a/packages/backend-defaults/api-report-urlReader.md +++ b/packages/backend-defaults/api-report-urlReader.md @@ -21,7 +21,7 @@ import { GitLabIntegration } from '@backstage/integration'; import { HarnessIntegration } from '@backstage/integration'; import { LoggerService } from '@backstage/backend-plugin-api'; import { Readable } from 'stream'; -import { ServiceFactory } from '@backstage/backend-plugin-api'; +import { ServiceFactoryCompat } from '@backstage/backend-plugin-api'; import { UrlReaderService } from '@backstage/backend-plugin-api'; import { UrlReaderServiceReadTreeOptions } from '@backstage/backend-plugin-api'; import { UrlReaderServiceReadTreeResponse } from '@backstage/backend-plugin-api'; @@ -426,9 +426,10 @@ export class UrlReaders { } // @public -export const urlReaderServiceFactory: () => ServiceFactory< +export const urlReaderServiceFactory: ServiceFactoryCompat< UrlReaderService, - 'plugin' + 'plugin', + undefined >; // @public diff --git a/packages/backend-defaults/api-report-userInfo.md b/packages/backend-defaults/api-report-userInfo.md index d11fb69718..b77878ff34 100644 --- a/packages/backend-defaults/api-report-userInfo.md +++ b/packages/backend-defaults/api-report-userInfo.md @@ -3,13 +3,14 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts -import { ServiceFactory } from '@backstage/backend-plugin-api'; +import { ServiceFactoryCompat } from '@backstage/backend-plugin-api'; import { UserInfoService } from '@backstage/backend-plugin-api'; // @public -export const userInfoServiceFactory: () => ServiceFactory< +export const userInfoServiceFactory: ServiceFactoryCompat< UserInfoService, - 'plugin' + 'plugin', + undefined >; // (No @packageDocumentation comment for this package) diff --git a/packages/backend-dynamic-feature-service/api-report.md b/packages/backend-dynamic-feature-service/api-report.md index 20db7db71b..39aa60b09b 100644 --- a/packages/backend-dynamic-feature-service/api-report.md +++ b/packages/backend-dynamic-feature-service/api-report.md @@ -28,7 +28,7 @@ import { PluginEndpointDiscovery } from '@backstage/backend-common'; import { PluginTaskScheduler } from '@backstage/backend-tasks'; import { RootLoggerService } from '@backstage/backend-plugin-api'; import { Router } from 'express'; -import { ServiceFactory } from '@backstage/backend-plugin-api'; +import { ServiceFactoryCompat } from '@backstage/backend-plugin-api'; import { ServiceRef } from '@backstage/backend-plugin-api'; import { TaskRunner } from '@backstage/backend-tasks'; import { TemplateAction } from '@backstage/plugin-scaffolder-node'; @@ -114,18 +114,20 @@ export interface DynamicPluginsFactoryOptions { } // @public (undocumented) -export const dynamicPluginsFeatureDiscoveryServiceFactory: () => ServiceFactory< +export const dynamicPluginsFeatureDiscoveryServiceFactory: ServiceFactoryCompat< FeatureDiscoveryService, - 'root' + 'root', + undefined >; // @public (undocumented) export const dynamicPluginsFrontendSchemas: BackendFeatureCompat; // @public (undocumented) -export const dynamicPluginsRootLoggerServiceFactory: () => ServiceFactory< +export const dynamicPluginsRootLoggerServiceFactory: ServiceFactoryCompat< RootLoggerService, - 'root' + 'root', + undefined >; // @public (undocumented) @@ -142,14 +144,18 @@ export interface DynamicPluginsSchemasService { } // @public (undocumented) -export const dynamicPluginsSchemasServiceFactory: ( - options?: DynamicPluginsSchemasOptions | undefined, -) => ServiceFactory; +export const dynamicPluginsSchemasServiceFactory: ServiceFactoryCompat< + DynamicPluginsSchemasService, + 'root', + DynamicPluginsSchemasOptions +>; // @public (undocumented) -export const dynamicPluginsServiceFactory: ( - options?: DynamicPluginsFactoryOptions | undefined, -) => ServiceFactory; +export const dynamicPluginsServiceFactory: ServiceFactoryCompat< + DynamicPluginProvider, + 'root', + DynamicPluginsFactoryOptions +>; // @public (undocumented) export const dynamicPluginsServiceRef: ServiceRef< diff --git a/packages/backend-plugin-api/api-report.md b/packages/backend-plugin-api/api-report.md index 7b1e6ef2d3..0a01878148 100644 --- a/packages/backend-plugin-api/api-report.md +++ b/packages/backend-plugin-api/api-report.md @@ -257,9 +257,9 @@ export function createServiceFactory< TOpts extends object | undefined = undefined, >( options: RootServiceFactoryOptions, -): () => ServiceFactory; +): ServiceFactoryCompat; -// @public +// @public @deprecated export function createServiceFactory< TService, TImpl extends TService, @@ -271,7 +271,7 @@ export function createServiceFactory< options: ( options?: TOpts, ) => RootServiceFactoryOptions, -): (options?: TOpts) => ServiceFactory; +): ServiceFactoryCompat; // @public export function createServiceFactory< @@ -284,9 +284,9 @@ export function createServiceFactory< TOpts extends object | undefined = undefined, >( options: PluginServiceFactoryOptions, -): () => ServiceFactory; +): ServiceFactoryCompat; -// @public +// @public @deprecated export function createServiceFactory< TService, TImpl extends TService, @@ -299,7 +299,7 @@ export function createServiceFactory< options: ( options?: TOpts, ) => PluginServiceFactoryOptions, -): (options?: TOpts) => ServiceFactory; +): ServiceFactoryCompat; // @public export function createServiceRef( @@ -645,7 +645,19 @@ export interface ServiceFactory< service: ServiceRef; } -// @public +// @public @deprecated (undocumented) +export interface ServiceFactoryCompat< + TService = unknown, + TScope extends 'plugin' | 'root' = 'plugin' | 'root', + TOpts extends object | undefined = undefined, +> extends ServiceFactory { + // @deprecated (undocumented) + ( + ...options: undefined extends TOpts ? [] : [options?: TOpts] + ): ServiceFactory; +} + +// @public @deprecated export type ServiceFactoryOrFunction = ServiceFactory | (() => ServiceFactory); // @public @@ -668,9 +680,13 @@ export type ServiceRefConfig< // @public (undocumented) export interface ServiceRefOptions { // (undocumented) - defaultFactory?: ( + defaultFactory?( service: ServiceRef, - ) => Promise; + ): Promise; + // @deprecated (undocumented) + defaultFactory?( + service: ServiceRef, + ): Promise<() => ServiceFactory>; // (undocumented) id: string; // (undocumented) diff --git a/packages/backend-plugin-api/src/services/system/index.ts b/packages/backend-plugin-api/src/services/system/index.ts index 9f62968ecd..c2d3b9c6fc 100644 --- a/packages/backend-plugin-api/src/services/system/index.ts +++ b/packages/backend-plugin-api/src/services/system/index.ts @@ -21,5 +21,6 @@ export type { PluginServiceFactoryOptions, RootServiceFactoryOptions, ServiceFactoryOrFunction, + ServiceFactoryCompat, } from './types'; export { createServiceRef, createServiceFactory } from './types'; diff --git a/packages/backend-plugin-api/src/services/system/types.ts b/packages/backend-plugin-api/src/services/system/types.ts index 2d6951ffea..9545408ff2 100644 --- a/packages/backend-plugin-api/src/services/system/types.ts +++ b/packages/backend-plugin-api/src/services/system/types.ts @@ -55,6 +55,23 @@ export interface ServiceFactory< service: ServiceRef; } +/** + * @public + * @deprecated This type exists only as a helper for old code that relied on `createServiceFactory` to return `() => ServiceFactory` instead of `ServiceFactory`. You should remove the `()` parentheses at the end of your usages. This type will be removed in a future release. + */ +export interface ServiceFactoryCompat< + TService = unknown, + TScope extends 'plugin' | 'root' = 'plugin' | 'root', + TOpts extends object | undefined = undefined, +> extends ServiceFactory { + /** + * @deprecated You do not need to use this call signature; use the type directly instead by removing the `()` parentheses at the end. This call signature will be removed in a future release. + */ + ( + ...options: undefined extends TOpts ? [] : [options?: TOpts] + ): ServiceFactory; +} + /** @internal */ export interface InternalServiceFactory< TService = unknown, @@ -73,6 +90,7 @@ export interface InternalServiceFactory< /** * Represents either a {@link ServiceFactory} or a function that returns one. * + * @deprecated The support for service factory functions is deprecated and will be removed. * @public */ export type ServiceFactoryOrFunction = ServiceFactory | (() => ServiceFactory); @@ -81,9 +99,15 @@ export type ServiceFactoryOrFunction = ServiceFactory | (() => ServiceFactory); export interface ServiceRefOptions { id: string; scope?: TScope; - defaultFactory?: ( + defaultFactory?( service: ServiceRef, - ) => Promise; + ): Promise; + /** + * @deprecated The defaultFactory must return a plain `ServiceFactory` object, support for returning a function will be removed. + */ + defaultFactory?( + service: ServiceRef, + ): Promise<() => ServiceFactory>; } /** @@ -198,10 +222,14 @@ export function createServiceFactory< TOpts extends object | undefined = undefined, >( options: RootServiceFactoryOptions, -): () => ServiceFactory; +): ServiceFactoryCompat; /** * Creates a root scoped service factory with optional options. * + * @deprecated The ability to define options for service factories is deprecated + * and will be removed. Please use the non-callback form of createServiceFactory + * and provide an API that allows for a simple re-implementation of the service + * factory instead. * @public * @param options - The service factory configuration. */ @@ -214,7 +242,7 @@ export function createServiceFactory< options: ( options?: TOpts, ) => RootServiceFactoryOptions, -): (options?: TOpts) => ServiceFactory; +): ServiceFactoryCompat; /** * Creates a plugin scoped service factory without options. * @@ -229,10 +257,14 @@ export function createServiceFactory< TOpts extends object | undefined = undefined, >( options: PluginServiceFactoryOptions, -): () => ServiceFactory; +): ServiceFactoryCompat; /** * Creates a plugin scoped service factory with optional options. * + * @deprecated The ability to define options for service factories is deprecated + * and will be removed. Please use the non-callback form of createServiceFactory + * and provide an API that allows for a simple re-implementation of the service + * factory instead. * @public * @param options - The service factory configuration. */ @@ -246,7 +278,7 @@ export function createServiceFactory< options: ( options?: TOpts, ) => PluginServiceFactoryOptions, -): (options?: TOpts) => ServiceFactory; +): ServiceFactoryCompat; export function createServiceFactory< TService, TImpl extends TService, @@ -263,13 +295,13 @@ export function createServiceFactory< ) => PluginServiceFactoryOptions) | (() => RootServiceFactoryOptions) | (() => PluginServiceFactoryOptions), -): (options: TOpts) => ServiceFactory { +): ServiceFactoryCompat { const configCallback = typeof options === 'function' ? options : () => options; const factory = ( - o: TOpts, + o?: TOpts, ): InternalServiceFactory => { - const anyConf = configCallback(o); + const anyConf = configCallback(o!); if (anyConf.service.scope === 'root') { const c = anyConf as RootServiceFactoryOptions; return { @@ -303,7 +335,10 @@ export function createServiceFactory< }; }; - factory.$$type = '@backstage/BackendFeatureFactory'; - - return factory; + // This constructs the `ServiceFactoryCompat` type, which is both a plain + // factory object as well as a function that can be called to construct a + // factory, potentially with options. In the future only the plain factory + // form will be supported, but for now we need to allow callers to call the + // factory too. + return Object.assign(factory, factory(undefined as TOpts)); } diff --git a/packages/backend-test-utils/api-report.md b/packages/backend-test-utils/api-report.md index 0a44fa5ed3..566ac5b888 100644 --- a/packages/backend-test-utils/api-report.md +++ b/packages/backend-test-utils/api-report.md @@ -38,6 +38,7 @@ import { RootLifecycleService } from '@backstage/backend-plugin-api'; import { RootLoggerService } from '@backstage/backend-plugin-api'; import { SchedulerService } from '@backstage/backend-plugin-api'; import { ServiceFactory } from '@backstage/backend-plugin-api'; +import { ServiceFactoryCompat } from '@backstage/backend-plugin-api'; import { ServiceRef } from '@backstage/backend-plugin-api'; import { TokenManagerService } from '@backstage/backend-plugin-api'; import { UrlReaderService } from '@backstage/backend-plugin-api'; @@ -155,7 +156,7 @@ export namespace mockServices { // (undocumented) export namespace auth { const // (undocumented) - factory: () => ServiceFactory; + factory: ServiceFactoryCompat; const // (undocumented) mock: ( partialImpl?: Partial | undefined, @@ -164,7 +165,7 @@ export namespace mockServices { // (undocumented) export namespace cache { const // (undocumented) - factory: () => ServiceFactory; + factory: ServiceFactoryCompat; const // (undocumented) mock: ( partialImpl?: Partial | undefined, @@ -173,7 +174,7 @@ export namespace mockServices { // (undocumented) export namespace database { const // (undocumented) - factory: () => ServiceFactory; + factory: ServiceFactoryCompat; const // (undocumented) mock: ( partialImpl?: Partial | undefined, @@ -184,7 +185,7 @@ export namespace mockServices { // (undocumented) export namespace discovery { const // (undocumented) - factory: () => ServiceFactory; + factory: ServiceFactoryCompat; const // (undocumented) mock: ( partialImpl?: Partial | undefined, @@ -193,7 +194,7 @@ export namespace mockServices { // (undocumented) export namespace events { const // (undocumented) - factory: () => ServiceFactory; + factory: ServiceFactoryCompat; const // (undocumented) mock: ( partialImpl?: Partial | undefined, @@ -205,13 +206,13 @@ export namespace mockServices { }): HttpAuthService; // (undocumented) export namespace httpAuth { - const factory: ( - options?: - | { - defaultCredentials?: BackstageCredentials | undefined; - } - | undefined, - ) => ServiceFactory; + const factory: ServiceFactoryCompat< + HttpAuthService, + 'plugin', + { + defaultCredentials?: BackstageCredentials | undefined; + } + >; const // (undocumented) mock: ( partialImpl?: Partial | undefined, @@ -220,7 +221,7 @@ export namespace mockServices { // (undocumented) export namespace httpRouter { const // (undocumented) - factory: () => ServiceFactory; + factory: ServiceFactoryCompat; const // (undocumented) mock: ( partialImpl?: Partial | undefined, @@ -240,7 +241,7 @@ export namespace mockServices { // (undocumented) export namespace lifecycle { const // (undocumented) - factory: () => ServiceFactory; + factory: ServiceFactoryCompat; const // (undocumented) mock: ( partialImpl?: Partial | undefined, @@ -249,7 +250,7 @@ export namespace mockServices { // (undocumented) export namespace logger { const // (undocumented) - factory: () => ServiceFactory; + factory: ServiceFactoryCompat; const // (undocumented) mock: ( partialImpl?: Partial | undefined, @@ -258,7 +259,7 @@ export namespace mockServices { // (undocumented) export namespace permissions { const // (undocumented) - factory: () => ServiceFactory; + factory: ServiceFactoryCompat; const // (undocumented) mock: ( partialImpl?: Partial | undefined, @@ -280,7 +281,7 @@ export namespace mockServices { // (undocumented) export namespace rootHealth { const // (undocumented) - factory: () => ServiceFactory; + factory: ServiceFactoryCompat; const // (undocumented) mock: ( partialImpl?: Partial | undefined, @@ -289,9 +290,11 @@ export namespace mockServices { // (undocumented) export namespace rootHttpRouter { const // (undocumented) - factory: ( - options?: RootHttpRouterFactoryOptions | undefined, - ) => ServiceFactory; + factory: ServiceFactoryCompat< + RootHttpRouterService, + 'root', + RootHttpRouterFactoryOptions + >; const // (undocumented) mock: ( partialImpl?: Partial | undefined, @@ -300,7 +303,7 @@ export namespace mockServices { // (undocumented) export namespace rootLifecycle { const // (undocumented) - factory: () => ServiceFactory; + factory: ServiceFactoryCompat; const // (undocumented) mock: ( partialImpl?: Partial | undefined, @@ -326,7 +329,7 @@ export namespace mockServices { // (undocumented) export namespace scheduler { const // (undocumented) - factory: () => ServiceFactory; + factory: ServiceFactoryCompat; const // (undocumented) mock: ( partialImpl?: Partial | undefined, @@ -346,7 +349,7 @@ export namespace mockServices { // (undocumented) export namespace urlReader { const // (undocumented) - factory: () => ServiceFactory; + factory: ServiceFactoryCompat; const // (undocumented) mock: ( partialImpl?: Partial | undefined, @@ -357,7 +360,7 @@ export namespace mockServices { ): UserInfoService; // (undocumented) export namespace userInfo { - const factory: () => ServiceFactory; + const factory: ServiceFactoryCompat; const // (undocumented) mock: ( partialImpl?: Partial | undefined, diff --git a/plugins/events-node/api-report.md b/plugins/events-node/api-report.md index 46646d2ce8..5b45b4419e 100644 --- a/plugins/events-node/api-report.md +++ b/plugins/events-node/api-report.md @@ -4,7 +4,7 @@ ```ts import { LoggerService } from '@backstage/backend-plugin-api'; -import { ServiceFactory } from '@backstage/backend-plugin-api'; +import { ServiceFactoryCompat } from '@backstage/backend-plugin-api'; import { ServiceRef } from '@backstage/backend-plugin-api'; // @public @@ -63,9 +63,10 @@ export interface EventsService { export type EventsServiceEventHandler = (params: EventParams) => Promise; // @public (undocumented) -export const eventsServiceFactory: () => ServiceFactory< +export const eventsServiceFactory: ServiceFactoryCompat< EventsService, - 'plugin' + 'plugin', + undefined >; // @public From edf5cc349ef822619e19534690ec7a659b9ce0ad Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Wed, 10 Jul 2024 12:53:32 +0200 Subject: [PATCH 208/416] refactor(test-utils): deprecate the `isDockerDisabledForTests` function Signed-off-by: Camila Belo --- .changeset/forty-buttons-cover.md | 5 +++++ packages/backend-test-utils/api-report.md | 2 +- packages/backend-test-utils/src/deprecated.ts | 9 +++++++++ packages/backend-test-utils/src/index.ts | 1 - .../src/util/isDockerDisabledForTests.ts | 1 - 5 files changed, 15 insertions(+), 3 deletions(-) create mode 100644 .changeset/forty-buttons-cover.md diff --git a/.changeset/forty-buttons-cover.md b/.changeset/forty-buttons-cover.md new file mode 100644 index 0000000000..16e66df061 --- /dev/null +++ b/.changeset/forty-buttons-cover.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-test-utils': patch +--- + +The function `isDockerDisabledForTests` is deprecated and will no longer be exported in the near future as it should only be used internally. diff --git a/packages/backend-test-utils/api-report.md b/packages/backend-test-utils/api-report.md index a61d1ccb58..d3a618d214 100644 --- a/packages/backend-test-utils/api-report.md +++ b/packages/backend-test-utils/api-report.md @@ -54,7 +54,7 @@ export interface CreateMockDirectoryOptions { mockOsTmpDir?: boolean; } -// @public (undocumented) +// @public @deprecated (undocumented) export function isDockerDisabledForTests(): boolean; // @public (undocumented) diff --git a/packages/backend-test-utils/src/deprecated.ts b/packages/backend-test-utils/src/deprecated.ts index fad7523367..5fe74e7ef3 100644 --- a/packages/backend-test-utils/src/deprecated.ts +++ b/packages/backend-test-utils/src/deprecated.ts @@ -15,9 +15,18 @@ */ import { CreateMockDirectoryOptions } from './filesystem'; +import { isDockerDisabledForTests as _isDockerDisabledForTests } from './util'; /** * @public * @deprecated Use `CreateMockDirectoryOptions` from `@backstage/backend-test-utils` instead. */ export type MockDirectoryOptions = CreateMockDirectoryOptions; + +/** + * @public + * @deprecated This is an internal function and will no longer be exported from this package. + */ +export function isDockerDisabledForTests(): boolean { + return _isDockerDisabledForTests(); +} diff --git a/packages/backend-test-utils/src/index.ts b/packages/backend-test-utils/src/index.ts index a9feacbacd..4124a861f4 100644 --- a/packages/backend-test-utils/src/index.ts +++ b/packages/backend-test-utils/src/index.ts @@ -26,4 +26,3 @@ export * from './database'; export * from './msw'; export * from './filesystem'; export * from './next'; -export * from './util'; diff --git a/packages/backend-test-utils/src/util/isDockerDisabledForTests.ts b/packages/backend-test-utils/src/util/isDockerDisabledForTests.ts index 05eeabd91a..ca7cc95425 100644 --- a/packages/backend-test-utils/src/util/isDockerDisabledForTests.ts +++ b/packages/backend-test-utils/src/util/isDockerDisabledForTests.ts @@ -14,7 +14,6 @@ * limitations under the License. */ -/** @public */ export function isDockerDisabledForTests() { // If we are not running in continuous integration, the default is to skip // the (relatively heavy, long running) docker based tests. If you want to From 2414d8666862d00cbed6b6b4292d7e3a7e777d1e Mon Sep 17 00:00:00 2001 From: Seba <17096352+sebalaini@users.noreply.github.com> Date: Wed, 10 Jul 2024 14:28:50 +0200 Subject: [PATCH 209/416] Kubernetes react -> Warning: validateDOMNesting(...):
      cannot appear as a descendant of

      (#25559) * fix html markup in FixDialog Signed-off-by: sebalaini * Update .changeset/short-impalas-suffer.md Co-authored-by: Camila Belo Signed-off-by: Seba <17096352+sebalaini@users.noreply.github.com> --------- Signed-off-by: sebalaini Signed-off-by: Seba <17096352+sebalaini@users.noreply.github.com> Co-authored-by: Camila Belo --- .changeset/short-impalas-suffer.md | 5 +++++ .../components/Pods/FixDialog/FixDialog.tsx | 22 +++++++++---------- 2 files changed, 16 insertions(+), 11 deletions(-) create mode 100644 .changeset/short-impalas-suffer.md diff --git a/.changeset/short-impalas-suffer.md b/.changeset/short-impalas-suffer.md new file mode 100644 index 0000000000..34bc31e85d --- /dev/null +++ b/.changeset/short-impalas-suffer.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-kubernetes-react': patch +--- + +Fix the `HTML` markup of the `FixDialog` component, `ul` and `li` are not allowed inside a `p` tag. diff --git a/plugins/kubernetes-react/src/components/Pods/FixDialog/FixDialog.tsx b/plugins/kubernetes-react/src/components/Pods/FixDialog/FixDialog.tsx index fd7440870f..99386b3d40 100644 --- a/plugins/kubernetes-react/src/components/Pods/FixDialog/FixDialog.tsx +++ b/plugins/kubernetes-react/src/components/Pods/FixDialog/FixDialog.tsx @@ -33,6 +33,8 @@ import { DetectedError } from '@backstage/plugin-kubernetes-common'; import { PodLogs } from '../PodLogs'; import { Events } from '../Events'; import { LinkButton } from '@backstage/core-components'; +import List from '@material-ui/core/List'; +import ListItem from '@material-ui/core/ListItem'; const useStyles = makeStyles((theme: Theme) => createStyles({ @@ -96,17 +98,15 @@ export const FixDialog: React.FC = ({ Fix: - -

        - {(error.proposedFix?.actions ?? []).map((fix, i) => { - return ( -
      • - {fix} -
      • - ); - })} -
      - + + {(error.proposedFix?.actions ?? []).map((fix, i) => { + return ( + + {fix} + + ); + })} + {pf && pf.type === 'logs' && ( From 6e4d937728c66d55e2ffde3986d1386cd12bf3f2 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 10 Jul 2024 15:19:03 +0200 Subject: [PATCH 210/416] docs/backend-system: update service factory options section Signed-off-by: Patrik Oldsberg --- .../architecture/03-services.md | 51 ++++++++----------- 1 file changed, 22 insertions(+), 29 deletions(-) diff --git a/docs/backend-system/architecture/03-services.md b/docs/backend-system/architecture/03-services.md index 777eddd3c4..7d6824c41e 100644 --- a/docs/backend-system/architecture/03-services.md +++ b/docs/backend-system/architecture/03-services.md @@ -190,43 +190,36 @@ If a service defines a default factory, that factory will be used if there is no When defining a default factory for a service, it is possible for it to end up with duplicate implementations at runtime. This applies both to any shared root context in your factory, as well as plugin specific instances of your service. This is because package dependency version ranges may not line up perfectly, causing duplicate installations of the same package. This can happen both for two different plugins using the same service, but also across a plugin and its modules. If your service would break in this scenario, you should not define a default factory for it, but instead require that users of your service explicitly install a factory in their backend instance. -## Service Factory Options +## Service Factory Customization -:::note Note - -This pattern is discouraged, only use it when necessary. If possible you should prefer to make services configurable via static configuration instead. - -::: - -When declaring a service factory it's possible to include an options callback. This allows you to customize the factory through code when installing it in the backend. For example, this is how you install an explicit factory instance in the backend without any options: +When declaring a service factory you may also want to make the export the building blocks of the implementation itself. This is to allow for further customization of the service implementation through code, beyond what is possible with static configuration, without the need to re-implement the entire service from scratch. For example, we might export our example `DefaultFooService` class, while moving construction to a static factory method to make it easier to evolve: ```ts -const backend = createBackend(); +export class DefaultFooService { + static create(options: { transform: (foo: string) => string }) { + return new DefaultFooService(options.transform ?? (foo) => foo); + } -backend.add(fooServiceFactory()); -``` + private constructor(private readonly transform: (foo: string) => string) {} -Note that we call `fooServiceFactory` to create the service factory instance. This is because `createServiceFactory` always returns a factory function that creates the actual service factory. To add options to your service factory, you wrap the object passed to `createServiceFactory` in a callback that accepts the desired options. Note that the options must always be optional. For example: - -```ts -export interface FooFactoryOptions { - transform: (foo: string) => string; + foo(foo: string): string { + return this.transform(foo); + } } - -export const fooServiceFactory = createServiceFactory( - (options?: FooFactoryOptions) => ({ - service: fooServiceRef, - factory() { - return new DefaultFooService(options?.transform); - }, - }), -); ``` -This lets us use the options to customize the factory implementation in any way we want. From the outside the service factory looks just like before, except that we're now also able to pass options when installing the factory: +By exporting `DefaultFooService` we now make it relatively simple for advanced users of our service to customize the implementation. To do so, they can define their own service factory that uses our provided implementation: ```ts -const backend = createBackend(); - -backend.add(fooServiceFactory({ transform: foo => foo.toUpperCase() })); +export const customFooServiceFactory = createServiceFactory({ + service: fooServiceRef, + deps: {}, + factory() { + return DefaultFooService.create({ + transform: foo => foo.toUpperCase(), + }); + }, +}); ``` + +This allows lets you provide more advanced options for the service implementation that couldn't be expressed through static configuration. It also gives users of the service implementation access to other services through dependency injection, which can be useful for their customizations. From b9451dd573a1dd3d095c49bfc2d96bf5009a03fc Mon Sep 17 00:00:00 2001 From: CasperJ Date: Wed, 10 Jul 2024 15:22:56 +0200 Subject: [PATCH 211/416] Fixed log message to output the correct file name being written to Signed-off-by: CasperJ --- .changeset/dirty-wasps-do.md | 5 +++++ .../src/scaffolder/actions/builtin/catalog/write.ts | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 .changeset/dirty-wasps-do.md diff --git a/.changeset/dirty-wasps-do.md b/.changeset/dirty-wasps-do.md new file mode 100644 index 0000000000..fbf6799baf --- /dev/null +++ b/.changeset/dirty-wasps-do.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend': patch +--- + +Catalog:Write scaffolder action shows incorrect log message diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/catalog/write.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/catalog/write.ts index 9feaa14c07..a957adb71a 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/catalog/write.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/catalog/write.ts @@ -49,10 +49,10 @@ export function createCatalogWriteAction() { examples, supportsDryRun: true, async handler(ctx) { - ctx.logger.info(`Writing catalog-info.yaml`); const { filePath, entity } = ctx.input; const entityRef = ctx.templateInfo?.entityRef; const path = filePath ?? 'catalog-info.yaml'; + ctx.logger.info(`Writing ${path}`); await fs.writeFile( resolveSafeChildPath(ctx.workspacePath, path), From c6c6e2d33427eff8fd9d8f8044ccaee18d0fc63a Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 10 Jul 2024 15:38:28 +0200 Subject: [PATCH 212/416] changesets: add node about TS improvement when removing service factory options Signed-off-by: Patrik Oldsberg --- .changeset/spotty-apricots-tan.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.changeset/spotty-apricots-tan.md b/.changeset/spotty-apricots-tan.md index bc1b26e2f4..2b88e3a7f5 100644 --- a/.changeset/spotty-apricots-tan.md +++ b/.changeset/spotty-apricots-tan.md @@ -53,3 +53,5 @@ export const fooServiceFactory = createServiceFactory({ This is of course more verbose than the previous solution where the factory could be customized through `fooServiceFactory({ bar: 'baz' })`, but this is a simplified which in practice should be using static configuration instead. This change is being made because the ability to define an options callback encourages bad design of services factories. When possible, a service should be configurable through static configuration, and the existence of options may discourage that. More importantly though, the existing options do not work well with the dependency injection system of services, which is a problem for callbacks an other more advanced options. This lead to a bad pattern where only a few explicit dependencies where made available in callbacks, rather than providing an API that allowed simple re-implementation of the service with full access to dependency injection. + +A separate benefit of this change is that it simplifies the TypeScript types in a way that allows TypeScript to provide a much better error message when a service factory doesn't properly implement the service interface. From b05e1e115789f44a65bd13b4ddb60299acf9a5c0 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 10 Jul 2024 15:41:02 +0200 Subject: [PATCH 213/416] changesets: add changeset for packages with updated service factory exports Signed-off-by: Patrik Oldsberg --- .changeset/hot-items-kick.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .changeset/hot-items-kick.md diff --git a/.changeset/hot-items-kick.md b/.changeset/hot-items-kick.md new file mode 100644 index 0000000000..a3a9f129c1 --- /dev/null +++ b/.changeset/hot-items-kick.md @@ -0,0 +1,9 @@ +--- +'@backstage/backend-dynamic-feature-service': patch +'@backstage/backend-test-utils': patch +'@backstage/backend-defaults': patch +'@backstage/backend-app-api': patch +'@backstage/plugin-events-node': patch +--- + +Service factories exported by this package have been updated to use the new service factory format that doesn't use a callback. From 95a3a0b91c5403f35dc5d9520a8e0b3ce5e5c8ae Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Wed, 10 Jul 2024 13:28:48 +0200 Subject: [PATCH 214/416] refactor(test-utils): rename `setupRequestMockHandlers` to `setupMswHandler` Signed-off-by: Camila Belo --- .changeset/tiny-schools-draw.md | 53 +++++++++++++++++++ .../auth/authServiceFactory.test.ts | 4 +- .../external/ExternalTokenHandler.test.ts | 7 +-- .../entrypoints/auth/external/jwks.test.ts | 4 +- .../auth/user/UserTokenHandler.test.ts | 7 +-- .../urlReader/lib/AzureUrlReader.test.ts | 4 +- .../lib/BitbucketCloudUrlReader.test.ts | 4 +- .../lib/BitbucketServerUrlReader.test.ts | 4 +- .../urlReader/lib/BitbucketUrlReader.test.ts | 4 +- .../urlReader/lib/FetchUrlReader.test.ts | 7 +-- .../urlReader/lib/GerritUrlReader.test.ts | 4 +- .../urlReader/lib/GiteaUrlReader.test.ts | 7 +-- .../urlReader/lib/GithubUrlReader.test.ts | 4 +- .../urlReader/lib/GitlabUrlReader.test.ts | 4 +- .../urlReader/lib/HarnessUrlReader.test.ts | 7 +-- .../userInfo/DefaultUserInfoService.test.ts | 7 +-- packages/backend-test-utils/api-report.md | 7 +++ packages/backend-test-utils/src/deprecated.ts | 13 +++++ packages/backend-test-utils/src/msw/index.ts | 2 +- .../src/msw/setupRequestMockHandlers.ts | 2 +- .../cli/src/commands/versions/bump.test.ts | 7 +-- .../src/sources/RemoteConfigSource.test.ts | 4 +- .../auth/microsoft/MicrosoftAuth.test.ts | 4 +- .../DefaultAuthConnector.test.ts | 4 +- .../ProxiedSignInIdentity.test.ts | 4 +- .../ProxiedSignInPage.test.tsx | 4 +- packages/create-app/src/lib/tasks.test.ts | 4 +- packages/frontend-test-utils/api-report.md | 2 +- packages/frontend-test-utils/src/index.ts | 2 +- .../release-manifests/src/manifest.test.ts | 4 +- packages/test-utils/api-report.md | 7 +++ packages/test-utils/src/deprecated.ts | 29 ++++++++++ packages/test-utils/src/index.ts | 1 + .../apis/FetchApi/MockFetchApi.test.ts | 4 +- .../test-utils/src/testUtils/msw/index.ts | 2 +- ...estMockHandlers.ts => setupMswHandlers.ts} | 2 +- .../src/helpers.test.ts | 4 +- .../src/helpers.test.ts | 7 +-- .../src/authenticator.test.ts | 4 +- .../src/authenticator.test.ts | 4 +- .../src/module.test.ts | 4 +- .../src/authenticator.test.ts | 4 +- .../src/module.test.ts | 4 +- .../src/authenticator.test.ts | 4 +- .../bitbucketServer/provider.test.ts | 6 +-- .../src/providers/oidc/provider.test.ts | 7 +-- .../src/identity/IdentityClient.test.ts | 4 +- .../src/lib/azure.test.ts | 4 +- .../BitbucketCloudEntityProvider.test.ts | 7 +-- .../src/lib/BitbucketServerClient.test.ts | 4 +- .../BitbucketServerEntityProvider.test.ts | 7 +-- .../providers/GerritEntityProvider.test.ts | 7 +-- .../analyzers/GithubLocationAnalyzer.test.ts | 7 +-- .../src/lib/github.test.ts | 4 +- .../src/GitLabDiscoveryProcessor.test.ts | 7 +-- .../src/lib/client.test.ts | 7 +-- .../GitlabDiscoveryEntityProvider.test.ts | 7 +-- .../GitlabOrgDiscoveryEntityProvider.test.ts | 7 +-- .../src/microsoftGraph/client.test.ts | 4 +- .../src/puppet/read.test.ts | 4 +- .../modules/core/UrlReaderProcessor.test.ts | 7 +-- .../src/search/DefaultCatalogCollator.test.ts | 4 +- .../src/api/AzureRepoApiClient.test.ts | 4 +- .../src/api/CatalogImportClient.test.ts | 4 +- .../src/service/KubernetesBuilder.test.ts | 4 +- .../service/KubernetesFanOutHandler.test.ts | 7 +-- .../src/service/KubernetesFetcher.test.ts | 4 +- .../src/service/KubernetesProxy.test.ts | 4 +- .../src/auth/PinnipedHelper.test.ts | 4 +- .../src/api/KubernetesBackendClient.test.ts | 4 +- .../DefaultNotificationService.test.ts | 4 +- .../src/api/NotificationsClient.test.ts | 4 +- .../src/ServerPermissionClient.test.ts | 4 +- .../src/service/router.config.test.ts | 4 +- .../src/service/router.credentials.test.ts | 4 +- .../actions/bitbucketCloud.examples.test.ts | 4 +- .../src/actions/bitbucketCloud.test.ts | 4 +- ...itbucketCloudPipelinesRun.examples.test.ts | 4 +- .../bitbucketCloudPipelinesRun.test.ts | 4 +- .../actions/bitbucketServer.examples.test.ts | 4 +- .../src/actions/bitbucketServer.test.ts | 4 +- ...itbucketServerPullRequest.examples.test.ts | 4 +- .../src/actions/bitbucket.examples.test.ts | 4 +- .../src/actions/bitbucket.test.ts | 4 +- .../confluenceToMarkdown.examples.test.ts | 4 +- .../confluence/confluenceToMarkdown.test.ts | 4 +- .../src/actions/gerrit.test.ts | 4 +- .../src/actions/gitea.test.ts | 4 +- .../src/actions/createProject.test.ts | 4 +- plugins/scaffolder/src/api.test.ts | 4 +- .../DefaultCatalogCollatorFactory.test.ts | 4 +- .../ToolDocumentCollatorFactory.test.ts | 7 +-- ...ckOverflowQuestionsCollatorFactory.test.ts | 7 +-- .../DefaultTechDocsCollatorFactory.test.ts | 7 +-- .../search/DefaultTechDocsCollator.test.ts | 7 +-- .../StorageApi/UserSettingsStorage.test.ts | 4 +- 96 files changed, 285 insertions(+), 244 deletions(-) create mode 100644 .changeset/tiny-schools-draw.md create mode 100644 packages/test-utils/src/deprecated.ts rename packages/test-utils/src/testUtils/msw/{setupRequestMockHandlers.ts => setupMswHandlers.ts} (94%) diff --git a/.changeset/tiny-schools-draw.md b/.changeset/tiny-schools-draw.md new file mode 100644 index 0000000000..02f57308fb --- /dev/null +++ b/.changeset/tiny-schools-draw.md @@ -0,0 +1,53 @@ +--- +'@backstage/plugin-scaffolder-backend-module-confluence-to-markdown': patch +'@backstage/plugin-auth-backend-module-cloudflare-access-provider': patch +'@backstage/plugin-search-backend-module-stack-overflow-collator': patch +'@backstage/plugin-scaffolder-backend-module-bitbucket-server': patch +'@backstage/plugin-auth-backend-module-vmware-cloud-provider': patch +'@backstage/plugin-scaffolder-backend-module-bitbucket-cloud': patch +'@backstage/plugin-catalog-backend-module-bitbucket-server': patch +'@backstage/plugin-auth-backend-module-microsoft-provider': patch +'@backstage/plugin-catalog-backend-module-bitbucket-cloud': patch +'@backstage/plugin-auth-backend-module-pinniped-provider': patch +'@backstage/plugin-auth-backend-module-aws-alb-provider': patch +'@backstage/plugin-scaffolder-backend-module-bitbucket': patch +'@backstage/plugin-auth-backend-module-oidc-provider': patch +'@backstage/plugin-scaffolder-backend-module-gerrit': patch +'@backstage/plugin-scaffolder-backend-module-sentry': patch +'@backstage/plugin-catalog-backend-module-puppetdb': patch +'@backstage/plugin-scaffolder-backend-module-gitea': patch +'@backstage/plugin-catalog-backend-module-msgraph': 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-search-backend-module-catalog': patch +'@backstage/plugin-search-backend-module-explore': patch +'@backstage/plugin-catalog-backend-module-azure': patch +'@backstage/frontend-test-utils': patch +'@backstage/backend-test-utils': patch +'@backstage/release-manifests': patch +'@backstage/plugin-kubernetes-backend': patch +'@backstage/plugin-notifications-node': patch +'@backstage/backend-defaults': patch +'@backstage/core-components': patch +'@backstage/plugin-kubernetes-react': patch +'@backstage/plugin-techdocs-backend': patch +'@backstage/plugin-catalog-backend': patch +'@backstage/plugin-kubernetes-node': patch +'@backstage/plugin-permission-node': patch +'@backstage/config-loader': patch +'@backstage/plugin-catalog-import': patch +'@backstage/core-app-api': patch +'@backstage/plugin-notifications': patch +'@backstage/plugin-proxy-backend': patch +'@backstage/plugin-user-settings': patch +'@backstage/plugin-auth-backend': patch +'@backstage/create-app': patch +'@backstage/test-utils': patch +'@backstage/plugin-scaffolder': patch +'@backstage/plugin-auth-node': patch +'@backstage/cli': patch +--- + +Rename frontend and backend `setupRequestMockHandlers` methods to `setupMswHandlers`. diff --git a/packages/backend-defaults/src/entrypoints/auth/authServiceFactory.test.ts b/packages/backend-defaults/src/entrypoints/auth/authServiceFactory.test.ts index de89efa351..385bc17a36 100644 --- a/packages/backend-defaults/src/entrypoints/auth/authServiceFactory.test.ts +++ b/packages/backend-defaults/src/entrypoints/auth/authServiceFactory.test.ts @@ -17,7 +17,7 @@ import { ServiceFactoryTester, mockServices, - setupRequestMockHandlers, + setupMswHandlers, } from '@backstage/backend-test-utils'; import { tokenManagerServiceFactory } from '@backstage/backend-app-api'; import { authServiceFactory } from './authServiceFactory'; @@ -68,7 +68,7 @@ const mockDeps = [ ]; describe('authServiceFactory', () => { - setupRequestMockHandlers(server); + setupMswHandlers(server); afterEach(() => { jest.useRealTimers(); diff --git a/packages/backend-defaults/src/entrypoints/auth/external/ExternalTokenHandler.test.ts b/packages/backend-defaults/src/entrypoints/auth/external/ExternalTokenHandler.test.ts index 559107c59c..2e413c73d6 100644 --- a/packages/backend-defaults/src/entrypoints/auth/external/ExternalTokenHandler.test.ts +++ b/packages/backend-defaults/src/entrypoints/auth/external/ExternalTokenHandler.test.ts @@ -17,10 +17,7 @@ import { BackstagePrincipalAccessRestrictions } from '@backstage/backend-plugin-api'; import { ExternalTokenHandler } from './ExternalTokenHandler'; import { TokenHandler } from './types'; -import { - mockServices, - setupRequestMockHandlers, -} from '@backstage/backend-test-utils'; +import { mockServices, setupMswHandlers } from '@backstage/backend-test-utils'; import { randomBytes } from 'crypto'; import { SignJWT, exportJWK, generateKeyPair } from 'jose'; import { DateTime } from 'luxon'; @@ -81,7 +78,7 @@ class FakeTokenFactory { describe('ExternalTokenHandler', () => { const server = setupServer(); - setupRequestMockHandlers(server); + setupMswHandlers(server); it('skips over inner handlers that do not match, and applies plugin restrictions', async () => { const handler1: TokenHandler = { diff --git a/packages/backend-defaults/src/entrypoints/auth/external/jwks.test.ts b/packages/backend-defaults/src/entrypoints/auth/external/jwks.test.ts index 56930e4480..02abd1e889 100644 --- a/packages/backend-defaults/src/entrypoints/auth/external/jwks.test.ts +++ b/packages/backend-defaults/src/entrypoints/auth/external/jwks.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { setupMswHandlers } from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; import { SignJWT, exportJWK, generateKeyPair } from 'jose'; import { rest } from 'msw'; @@ -81,7 +81,7 @@ describe('JWKSHandler', () => { let mockSubject: string; const keyDurationSeconds = 5; - setupRequestMockHandlers(server); + setupMswHandlers(server); beforeEach(() => { mockSubject = 'test_subject'; diff --git a/packages/backend-defaults/src/entrypoints/auth/user/UserTokenHandler.test.ts b/packages/backend-defaults/src/entrypoints/auth/user/UserTokenHandler.test.ts index 76bafb2a8f..9078be81e0 100644 --- a/packages/backend-defaults/src/entrypoints/auth/user/UserTokenHandler.test.ts +++ b/packages/backend-defaults/src/entrypoints/auth/user/UserTokenHandler.test.ts @@ -16,10 +16,7 @@ import { JsonObject } from '@backstage/types'; import { UserTokenHandler } from './UserTokenHandler'; -import { - mockServices, - setupRequestMockHandlers, -} from '@backstage/backend-test-utils'; +import { mockServices, setupMswHandlers } from '@backstage/backend-test-utils'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { AuthenticationError } from '@backstage/errors'; @@ -64,7 +61,7 @@ async function createToken(options: { describe('UserTokenHandler', () => { let userTokenHandler: UserTokenHandler; - setupRequestMockHandlers(server); + setupMswHandlers(server); beforeEach(() => { jest.useRealTimers(); diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/AzureUrlReader.test.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/AzureUrlReader.test.ts index ce2385507b..9e2aec1b56 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/AzureUrlReader.test.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/AzureUrlReader.test.ts @@ -26,7 +26,7 @@ import { import { createMockDirectory, mockServices, - setupRequestMockHandlers, + setupMswHandlers, } from '@backstage/backend-test-utils'; import fs from 'fs-extra'; import { rest } from 'msw'; @@ -76,7 +76,7 @@ describe('AzureUrlReader', () => { beforeEach(mockDir.clear); const worker = setupServer(); - setupRequestMockHandlers(worker); + setupMswHandlers(worker); describe('read', () => { beforeEach(() => { diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketCloudUrlReader.test.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketCloudUrlReader.test.ts index dc182af619..43be9b1a92 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketCloudUrlReader.test.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketCloudUrlReader.test.ts @@ -21,7 +21,7 @@ import { } from '@backstage/integration'; import { createMockDirectory, - setupRequestMockHandlers, + setupMswHandlers, } from '@backstage/backend-test-utils'; import fs from 'fs-extra'; import { rest } from 'msw'; @@ -56,7 +56,7 @@ describe('BitbucketCloudUrlReader', () => { beforeEach(mockDir.clear); const worker = setupServer(); - setupRequestMockHandlers(worker); + setupMswHandlers(worker); describe('readUrl', () => { it('should be able to readUrl via buffer without ETag', async () => { diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketServerUrlReader.test.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketServerUrlReader.test.ts index 2870138535..b63e557f3e 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketServerUrlReader.test.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketServerUrlReader.test.ts @@ -21,7 +21,7 @@ import { } from '@backstage/integration'; import { createMockDirectory, - setupRequestMockHandlers, + setupMswHandlers, } from '@backstage/backend-test-utils'; import fs from 'fs-extra'; import { rest } from 'msw'; @@ -51,7 +51,7 @@ const reader = new BitbucketServerUrlReader( describe('BitbucketServerUrlReader', () => { const worker = setupServer(); - setupRequestMockHandlers(worker); + setupMswHandlers(worker); describe('readTree', () => { const repoBuffer = fs.readFileSync( diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketUrlReader.test.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketUrlReader.test.ts index edd8d6d3fc..67953cd020 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketUrlReader.test.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketUrlReader.test.ts @@ -22,7 +22,7 @@ import { import { createMockDirectory, mockServices, - setupRequestMockHandlers, + setupMswHandlers, } from '@backstage/backend-test-utils'; import fs from 'fs-extra'; import { rest } from 'msw'; @@ -104,7 +104,7 @@ describe('BitbucketUrlReader', () => { ); const worker = setupServer(); - setupRequestMockHandlers(worker); + setupMswHandlers(worker); describe('readUrl', () => { it('should be able to readUrl via buffer without ETag', async () => { diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/FetchUrlReader.test.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/FetchUrlReader.test.ts index 38936806c6..31ad87178e 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/FetchUrlReader.test.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/FetchUrlReader.test.ts @@ -16,10 +16,7 @@ import { ConfigReader } from '@backstage/config'; import { NotFoundError, NotModifiedError } from '@backstage/errors'; -import { - mockServices, - setupRequestMockHandlers, -} from '@backstage/backend-test-utils'; +import { mockServices, setupMswHandlers } from '@backstage/backend-test-utils'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { FetchUrlReader } from './FetchUrlReader'; @@ -30,7 +27,7 @@ const fetchUrlReader = new FetchUrlReader(); describe('FetchUrlReader', () => { const worker = setupServer(); - setupRequestMockHandlers(worker); + setupMswHandlers(worker); beforeEach(() => { jest.clearAllMocks(); diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/GerritUrlReader.test.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/GerritUrlReader.test.ts index 94627e074f..61ae9eba6a 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/GerritUrlReader.test.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/GerritUrlReader.test.ts @@ -17,7 +17,7 @@ import { createMockDirectory, mockServices, - setupRequestMockHandlers, + setupMswHandlers, } from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; import { NotModifiedError, NotFoundError } from '@backstage/errors'; @@ -92,7 +92,7 @@ const createReader = (config: JsonObject): UrlReaderPredicateTuple[] => { // eslint-disable-next-line jest/no-disabled-tests describe.skip('GerritUrlReader', () => { const worker = setupServer(); - setupRequestMockHandlers(worker); + setupMswHandlers(worker); beforeEach(() => { mockDir.clear(); diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/GiteaUrlReader.test.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/GiteaUrlReader.test.ts index 0b5983eefd..c3b744a792 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/GiteaUrlReader.test.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/GiteaUrlReader.test.ts @@ -14,10 +14,7 @@ * limitations under the License. */ -import { - mockServices, - setupRequestMockHandlers, -} from '@backstage/backend-test-utils'; +import { mockServices, setupMswHandlers } from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; import { GiteaIntegration, readGiteaConfig } from '@backstage/integration'; import { JsonObject } from '@backstage/types'; @@ -64,7 +61,7 @@ const createReader = (config: JsonObject): UrlReaderPredicateTuple[] => { describe('GiteaUrlReader', () => { const worker = setupServer(); - setupRequestMockHandlers(worker); + setupMswHandlers(worker); afterAll(() => { jest.clearAllMocks(); diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/GithubUrlReader.test.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/GithubUrlReader.test.ts index f07ada0cc3..b0734a0f0e 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/GithubUrlReader.test.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/GithubUrlReader.test.ts @@ -22,7 +22,7 @@ import { } from '@backstage/integration'; import { createMockDirectory, - setupRequestMockHandlers, + setupMswHandlers, } from '@backstage/backend-test-utils'; import fs from 'fs-extra'; import { rest } from 'msw'; @@ -74,7 +74,7 @@ const gheProcessor = new GithubUrlReader( describe('GithubUrlReader', () => { const worker = setupServer(); - setupRequestMockHandlers(worker); + setupMswHandlers(worker); beforeEach(mockDir.clear); diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/GitlabUrlReader.test.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/GitlabUrlReader.test.ts index 46276fcdda..62f7d84c84 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/GitlabUrlReader.test.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/GitlabUrlReader.test.ts @@ -18,7 +18,7 @@ import { ConfigReader } from '@backstage/config'; import { createMockDirectory, mockServices, - setupRequestMockHandlers, + setupMswHandlers, } from '@backstage/backend-test-utils'; import fs from 'fs-extra'; import { rest } from 'msw'; @@ -72,7 +72,7 @@ describe('GitlabUrlReader', () => { beforeEach(mockDir.clear); const worker = setupServer(); - setupRequestMockHandlers(worker); + setupMswHandlers(worker); describe('read', () => { beforeEach(() => { diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/HarnessUrlReader.test.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/HarnessUrlReader.test.ts index f1efbca108..a95cf7f479 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/HarnessUrlReader.test.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/HarnessUrlReader.test.ts @@ -14,10 +14,7 @@ * limitations under the License. */ -import { - mockServices, - setupRequestMockHandlers, -} from '@backstage/backend-test-utils'; +import { mockServices, setupMswHandlers } from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; import { HarnessIntegration, readHarnessConfig } from '@backstage/integration'; import { JsonObject } from '@backstage/types'; @@ -120,7 +117,7 @@ const handlers = [ describe('HarnessUrlReader', () => { const worker = setupServer(...handlers); - setupRequestMockHandlers(worker); + setupMswHandlers(worker); beforeAll(() => worker.listen({ onUnhandledRequest: 'bypass' })); afterAll(() => { jest.clearAllMocks(); diff --git a/packages/backend-defaults/src/entrypoints/userInfo/DefaultUserInfoService.test.ts b/packages/backend-defaults/src/entrypoints/userInfo/DefaultUserInfoService.test.ts index b63b24fb18..bba0c5145a 100644 --- a/packages/backend-defaults/src/entrypoints/userInfo/DefaultUserInfoService.test.ts +++ b/packages/backend-defaults/src/entrypoints/userInfo/DefaultUserInfoService.test.ts @@ -15,10 +15,7 @@ */ import { BackstageUserPrincipal } from '@backstage/backend-plugin-api'; -import { - mockServices, - setupRequestMockHandlers, -} from '@backstage/backend-test-utils'; +import { mockServices, setupMswHandlers } from '@backstage/backend-test-utils'; import { JsonObject } from '@backstage/types'; import { SignJWT, base64url, importJWK } from 'jose'; import { rest } from 'msw'; @@ -28,7 +25,7 @@ import { DefaultUserInfoService } from './DefaultUserInfoService'; describe('DefaultUserInfoService', () => { const server = setupServer(); - setupRequestMockHandlers(server); + setupMswHandlers(server); const mockPublicKey = { kty: 'EC', diff --git a/packages/backend-test-utils/api-report.md b/packages/backend-test-utils/api-report.md index d3a618d214..ac14bae321 100644 --- a/packages/backend-test-utils/api-report.md +++ b/packages/backend-test-utils/api-report.md @@ -403,6 +403,13 @@ export type ServiceMock = { }; // @public +export function setupMswHandlers(worker: { + listen: (t: any) => void; + close: () => void; + resetHandlers: () => void; +}): void; + +// @public @deprecated (undocumented) export function setupRequestMockHandlers(worker: { listen: (t: any) => void; close: () => void; diff --git a/packages/backend-test-utils/src/deprecated.ts b/packages/backend-test-utils/src/deprecated.ts index 5fe74e7ef3..a349030b12 100644 --- a/packages/backend-test-utils/src/deprecated.ts +++ b/packages/backend-test-utils/src/deprecated.ts @@ -16,6 +16,7 @@ import { CreateMockDirectoryOptions } from './filesystem'; import { isDockerDisabledForTests as _isDockerDisabledForTests } from './util'; +import { setupMswHandlers } from './msw'; /** * @public @@ -30,3 +31,15 @@ export type MockDirectoryOptions = CreateMockDirectoryOptions; export function isDockerDisabledForTests(): boolean { return _isDockerDisabledForTests(); } + +/** + * @public + * @deprecated Use `setupMswHandlers` from `@backstage/backend-test-utils` instead. + */ +export function setupRequestMockHandlers(worker: { + listen: (t: any) => void; + close: () => void; + resetHandlers: () => void; +}): void { + setupMswHandlers(worker); +} diff --git a/packages/backend-test-utils/src/msw/index.ts b/packages/backend-test-utils/src/msw/index.ts index 29cbdf854a..a339721ba5 100644 --- a/packages/backend-test-utils/src/msw/index.ts +++ b/packages/backend-test-utils/src/msw/index.ts @@ -14,4 +14,4 @@ * limitations under the License. */ -export { setupRequestMockHandlers } from './setupRequestMockHandlers'; +export { setupMswHandlers } from './setupRequestMockHandlers'; diff --git a/packages/backend-test-utils/src/msw/setupRequestMockHandlers.ts b/packages/backend-test-utils/src/msw/setupRequestMockHandlers.ts index 625ef0e0fc..e123bc91c0 100644 --- a/packages/backend-test-utils/src/msw/setupRequestMockHandlers.ts +++ b/packages/backend-test-utils/src/msw/setupRequestMockHandlers.ts @@ -19,7 +19,7 @@ * @public * @param worker - service worker */ -export function setupRequestMockHandlers(worker: { +export function setupMswHandlers(worker: { listen: (t: any) => void; close: () => void; resetHandlers: () => void; diff --git a/packages/cli/src/commands/versions/bump.test.ts b/packages/cli/src/commands/versions/bump.test.ts index 0dfe2f61c3..c7f8b7ed0c 100644 --- a/packages/cli/src/commands/versions/bump.test.ts +++ b/packages/cli/src/commands/versions/bump.test.ts @@ -18,10 +18,7 @@ import fs from 'fs-extra'; import { Command } from 'commander'; import * as runObj from '../../lib/run'; import bump, { bumpBackstageJsonVersion, createVersionFinder } from './bump'; -import { - setupRequestMockHandlers, - withLogCollector, -} from '@backstage/test-utils'; +import { setupMswHandlers, withLogCollector } from '@backstage/test-utils'; import { YarnInfoInspectData } from '../../lib/versioning/packages'; import { setupServer } from 'msw/node'; import { rest } from 'msw'; @@ -156,7 +153,7 @@ describe('bump', () => { }); const worker = setupServer(); - setupRequestMockHandlers(worker); + setupMswHandlers(worker); it('should bump backstage dependencies', async () => { mockDir.setContent({ diff --git a/packages/config-loader/src/sources/RemoteConfigSource.test.ts b/packages/config-loader/src/sources/RemoteConfigSource.test.ts index 6082c05e65..5fb16bf0c8 100644 --- a/packages/config-loader/src/sources/RemoteConfigSource.test.ts +++ b/packages/config-loader/src/sources/RemoteConfigSource.test.ts @@ -15,14 +15,14 @@ */ import { rest } from 'msw'; -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { setupMswHandlers } from '@backstage/backend-test-utils'; import { setupServer } from 'msw/node'; import { RemoteConfigSource } from './RemoteConfigSource'; import { readN } from './__testUtils__/testUtils'; describe('RemoteConfigSource', () => { const worker = setupServer(); - setupRequestMockHandlers(worker); + setupMswHandlers(worker); it('should load config from a remote URL', async () => { worker.use( diff --git a/packages/core-app-api/src/apis/implementations/auth/microsoft/MicrosoftAuth.test.ts b/packages/core-app-api/src/apis/implementations/auth/microsoft/MicrosoftAuth.test.ts index b6d59bd3f2..698c9930b7 100644 --- a/packages/core-app-api/src/apis/implementations/auth/microsoft/MicrosoftAuth.test.ts +++ b/packages/core-app-api/src/apis/implementations/auth/microsoft/MicrosoftAuth.test.ts @@ -19,13 +19,13 @@ import MockOAuthApi from '../../OAuthRequestApi/MockOAuthApi'; import { UrlPatternDiscovery } from '../../DiscoveryApi'; import { ConfigReader } from '@backstage/config'; import { microsoftAuthApiRef } from '@backstage/core-plugin-api'; -import { setupRequestMockHandlers } from '@backstage/test-utils'; +import { setupMswHandlers } from '@backstage/test-utils'; import { setupServer } from 'msw/node'; import { rest } from 'msw'; describe('MicrosoftAuth', () => { const server = setupServer(); - setupRequestMockHandlers(server); + setupMswHandlers(server); const microsoftAuth = MicrosoftAuth.create({ configApi: new ConfigReader(undefined), oauthRequestApi: new MockOAuthApi(), diff --git a/packages/core-app-api/src/lib/AuthConnector/DefaultAuthConnector.test.ts b/packages/core-app-api/src/lib/AuthConnector/DefaultAuthConnector.test.ts index 4273ea99ee..d4bd136201 100644 --- a/packages/core-app-api/src/lib/AuthConnector/DefaultAuthConnector.test.ts +++ b/packages/core-app-api/src/lib/AuthConnector/DefaultAuthConnector.test.ts @@ -18,7 +18,7 @@ import { DefaultAuthConnector } from './DefaultAuthConnector'; import MockOAuthApi from '../../apis/implementations/OAuthRequestApi/MockOAuthApi'; import * as loginPopup from '../loginPopup'; import { UrlPatternDiscovery } from '../../apis'; -import { setupRequestMockHandlers } from '@backstage/test-utils'; +import { setupMswHandlers } from '@backstage/test-utils'; import { setupServer } from 'msw/node'; import { rest } from 'msw'; import { ConfigReader } from '@backstage/config'; @@ -53,7 +53,7 @@ const defaultOptions = { describe('DefaultAuthConnector', () => { const server = setupServer(); - setupRequestMockHandlers(server); + setupMswHandlers(server); afterEach(() => { jest.resetAllMocks(); diff --git a/packages/core-components/src/layout/ProxiedSignInPage/ProxiedSignInIdentity.test.ts b/packages/core-components/src/layout/ProxiedSignInPage/ProxiedSignInIdentity.test.ts index b8c2b84085..4780b174e0 100644 --- a/packages/core-components/src/layout/ProxiedSignInPage/ProxiedSignInIdentity.test.ts +++ b/packages/core-components/src/layout/ProxiedSignInPage/ProxiedSignInIdentity.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { setupRequestMockHandlers } from '@backstage/test-utils'; +import { setupMswHandlers } from '@backstage/test-utils'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { @@ -60,7 +60,7 @@ describe('ProxiedSignInIdentity', () => { afterEach(() => jest.useRealTimers()); const worker = setupServer(); - setupRequestMockHandlers(worker); + setupMswHandlers(worker); it('runs the happy path', async () => { const getBaseUrl = jest.fn(); diff --git a/packages/core-components/src/layout/ProxiedSignInPage/ProxiedSignInPage.test.tsx b/packages/core-components/src/layout/ProxiedSignInPage/ProxiedSignInPage.test.tsx index 05960cd213..3cfde3d0f0 100644 --- a/packages/core-components/src/layout/ProxiedSignInPage/ProxiedSignInPage.test.tsx +++ b/packages/core-components/src/layout/ProxiedSignInPage/ProxiedSignInPage.test.tsx @@ -20,7 +20,7 @@ import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { TestApiProvider, - setupRequestMockHandlers, + setupMswHandlers, wrapInTestApp, } from '@backstage/test-utils'; import { ProxiedSignInPage } from './ProxiedSignInPage'; @@ -28,7 +28,7 @@ import { discoveryApiRef } from '@backstage/core-plugin-api'; describe('ProxiedSignInPage', () => { const worker = setupServer(); - setupRequestMockHandlers(worker); + setupMswHandlers(worker); const Subject = wrapInTestApp(
      authenticated
      , { components: { diff --git a/packages/create-app/src/lib/tasks.test.ts b/packages/create-app/src/lib/tasks.test.ts index 1f507b95ed..f26c3306f1 100644 --- a/packages/create-app/src/lib/tasks.test.ts +++ b/packages/create-app/src/lib/tasks.test.ts @@ -31,7 +31,7 @@ import { } from './tasks'; import { createMockDirectory, - setupRequestMockHandlers, + setupMswHandlers, } from '@backstage/backend-test-utils'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; @@ -423,7 +423,7 @@ describe('tasks', () => { describe('fetchYarnLockSeedTask', () => { const worker = setupServer(); - setupRequestMockHandlers(worker); + setupMswHandlers(worker); it('should fetch the yarn.lock seed file', async () => { worker.use( diff --git a/packages/frontend-test-utils/api-report.md b/packages/frontend-test-utils/api-report.md index 2605499a96..7c8f5a5837 100644 --- a/packages/frontend-test-utils/api-report.md +++ b/packages/frontend-test-utils/api-report.md @@ -20,7 +20,7 @@ import { MockStorageApi } from '@backstage/test-utils'; import { MockStorageBucket } from '@backstage/test-utils'; import { RenderResult } from '@testing-library/react'; import { RouteRef } from '@backstage/frontend-plugin-api'; -import { setupRequestMockHandlers } from '@backstage/test-utils'; +import { setupMswHandlers as setupRequestMockHandlers } from '@backstage/test-utils'; import { TestApiProvider } from '@backstage/test-utils'; import { TestApiProviderProps } from '@backstage/test-utils'; import { TestApiRegistry } from '@backstage/test-utils'; diff --git a/packages/frontend-test-utils/src/index.ts b/packages/frontend-test-utils/src/index.ts index 0dab8e75b7..9d41699073 100644 --- a/packages/frontend-test-utils/src/index.ts +++ b/packages/frontend-test-utils/src/index.ts @@ -28,4 +28,4 @@ export type { TestApiProviderProps } from '@backstage/test-utils'; export { withLogCollector } from '@backstage/test-utils'; -export { setupRequestMockHandlers } from '@backstage/test-utils'; +export { setupMswHandlers as setupRequestMockHandlers } from '@backstage/test-utils'; diff --git a/packages/release-manifests/src/manifest.test.ts b/packages/release-manifests/src/manifest.test.ts index 6a53f993c8..8192bf867e 100644 --- a/packages/release-manifests/src/manifest.test.ts +++ b/packages/release-manifests/src/manifest.test.ts @@ -16,7 +16,7 @@ import { setupServer } from 'msw/node'; import { rest } from 'msw'; -import { setupRequestMockHandlers } from '@backstage/test-utils'; +import { setupMswHandlers } from '@backstage/test-utils'; import { getManifestByReleaseLine, getManifestByVersion, @@ -25,7 +25,7 @@ import { describe('Release Manifests', () => { const worker = setupServer(); - setupRequestMockHandlers(worker); + setupMswHandlers(worker); describe('getManifestByVersion', () => { it('should return a list of packages in a release', async () => { diff --git a/packages/test-utils/api-report.md b/packages/test-utils/api-report.md index e31a820a1c..82816d931a 100644 --- a/packages/test-utils/api-report.md +++ b/packages/test-utils/api-report.md @@ -210,6 +210,13 @@ export function renderWithEffects( ): Promise; // @public +export function setupMswHandlers(worker: { + listen: (t: any) => void; + close: () => void; + resetHandlers: () => void; +}): void; + +// @public @deprecated (undocumented) export function setupRequestMockHandlers(worker: { listen: (t: any) => void; close: () => void; diff --git a/packages/test-utils/src/deprecated.ts b/packages/test-utils/src/deprecated.ts new file mode 100644 index 0000000000..6825f9d0da --- /dev/null +++ b/packages/test-utils/src/deprecated.ts @@ -0,0 +1,29 @@ +/* + * Copyright 2024 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 { setupMswHandlers } from './testUtils/msw'; + +/** + * @public + * @deprecated Use `CreateMockDirectoryOptions` from `@backstage/backend-test-utils` instead. + */ +export function setupRequestMockHandlers(worker: { + listen: (t: any) => void; + close: () => void; + resetHandlers: () => void; +}): void { + setupMswHandlers(worker); +} diff --git a/packages/test-utils/src/index.ts b/packages/test-utils/src/index.ts index 83a955baa7..b971825f66 100644 --- a/packages/test-utils/src/index.ts +++ b/packages/test-utils/src/index.ts @@ -20,4 +20,5 @@ * @packageDocumentation */ +export * from './deprecated'; export * from './testUtils'; diff --git a/packages/test-utils/src/testUtils/apis/FetchApi/MockFetchApi.test.ts b/packages/test-utils/src/testUtils/apis/FetchApi/MockFetchApi.test.ts index 37b9d874f9..d51f4c7aee 100644 --- a/packages/test-utils/src/testUtils/apis/FetchApi/MockFetchApi.test.ts +++ b/packages/test-utils/src/testUtils/apis/FetchApi/MockFetchApi.test.ts @@ -16,12 +16,12 @@ import { rest } from 'msw'; import { setupServer } from 'msw/node'; -import { setupRequestMockHandlers } from '../../msw'; +import { setupMswHandlers } from '../../msw'; import { MockFetchApi } from './MockFetchApi'; describe('MockFetchApi', () => { const worker = setupServer(); - setupRequestMockHandlers(worker); + setupMswHandlers(worker); it('works with default constructor', async () => { worker.use( diff --git a/packages/test-utils/src/testUtils/msw/index.ts b/packages/test-utils/src/testUtils/msw/index.ts index 29cbdf854a..a924676d06 100644 --- a/packages/test-utils/src/testUtils/msw/index.ts +++ b/packages/test-utils/src/testUtils/msw/index.ts @@ -14,4 +14,4 @@ * limitations under the License. */ -export { setupRequestMockHandlers } from './setupRequestMockHandlers'; +export { setupMswHandlers } from './setupMswHandlers'; diff --git a/packages/test-utils/src/testUtils/msw/setupRequestMockHandlers.ts b/packages/test-utils/src/testUtils/msw/setupMswHandlers.ts similarity index 94% rename from packages/test-utils/src/testUtils/msw/setupRequestMockHandlers.ts rename to packages/test-utils/src/testUtils/msw/setupMswHandlers.ts index 625ef0e0fc..e123bc91c0 100644 --- a/packages/test-utils/src/testUtils/msw/setupRequestMockHandlers.ts +++ b/packages/test-utils/src/testUtils/msw/setupMswHandlers.ts @@ -19,7 +19,7 @@ * @public * @param worker - service worker */ -export function setupRequestMockHandlers(worker: { +export function setupMswHandlers(worker: { listen: (t: any) => void; close: () => void; resetHandlers: () => void; diff --git a/plugins/auth-backend-module-aws-alb-provider/src/helpers.test.ts b/plugins/auth-backend-module-aws-alb-provider/src/helpers.test.ts index 0bbcf9b5c1..1b902246fb 100644 --- a/plugins/auth-backend-module-aws-alb-provider/src/helpers.test.ts +++ b/plugins/auth-backend-module-aws-alb-provider/src/helpers.test.ts @@ -19,7 +19,7 @@ import { JWTHeaderParameters, UnsecuredJWT } from 'jose'; import NodeCache from 'node-cache'; import { http, HttpResponse } from 'msw'; import { setupServer } from 'msw/node'; -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { setupMswHandlers } from '@backstage/backend-test-utils'; import { PassportProfile } from '@backstage/plugin-auth-node'; import { makeProfileInfo, provisionKeyCache } from './helpers'; @@ -34,7 +34,7 @@ describe.each([ ], ])('helpers', (region, url) => { const server = setupServer(); - setupRequestMockHandlers(server); + setupMswHandlers(server); const nodeCache = jest.fn() as unknown as NodeCache; nodeCache.set = jest.fn(); diff --git a/plugins/auth-backend-module-cloudflare-access-provider/src/helpers.test.ts b/plugins/auth-backend-module-cloudflare-access-provider/src/helpers.test.ts index 8043f4e214..a0b3335874 100644 --- a/plugins/auth-backend-module-cloudflare-access-provider/src/helpers.test.ts +++ b/plugins/auth-backend-module-cloudflare-access-provider/src/helpers.test.ts @@ -14,10 +14,7 @@ * limitations under the License. */ -import { - mockServices, - setupRequestMockHandlers, -} from '@backstage/backend-test-utils'; +import { mockServices, setupMswHandlers } from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; import { SignJWT, exportJWK, generateKeyPair } from 'jose'; import { HttpResponse, http } from 'msw'; @@ -89,7 +86,7 @@ describe('helpers', () => { const tokenFactory = new MockTokenFactory(); const cache = mockServices.cache.mock(); const server = setupServer(); - setupRequestMockHandlers(server); + setupMswHandlers(server); beforeEach(() => { jest.clearAllMocks(); diff --git a/plugins/auth-backend-module-microsoft-provider/src/authenticator.test.ts b/plugins/auth-backend-module-microsoft-provider/src/authenticator.test.ts index 21a60a229b..fc392f68c2 100644 --- a/plugins/auth-backend-module-microsoft-provider/src/authenticator.test.ts +++ b/plugins/auth-backend-module-microsoft-provider/src/authenticator.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { setupMswHandlers } from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; import { encodeOAuthState, @@ -43,7 +43,7 @@ describe('microsoftAuthenticator', () => { const microsoftApi = new FakeMicrosoftAPI(); const server = setupServer(); - setupRequestMockHandlers(server); + setupMswHandlers(server); let implementation: { domainHint: string | undefined; diff --git a/plugins/auth-backend-module-oidc-provider/src/authenticator.test.ts b/plugins/auth-backend-module-oidc-provider/src/authenticator.test.ts index 4203a70153..05ccebdf7d 100644 --- a/plugins/auth-backend-module-oidc-provider/src/authenticator.test.ts +++ b/plugins/auth-backend-module-oidc-provider/src/authenticator.test.ts @@ -23,7 +23,7 @@ import { } from '@backstage/plugin-auth-node'; import { oidcAuthenticator } from './authenticator'; import { setupServer } from 'msw/node'; -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { setupMswHandlers } from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; import { JWK, SignJWT, exportJWK, generateKeyPair } from 'jose'; import { rest } from 'msw'; @@ -38,7 +38,7 @@ describe('oidcAuthenticator', () => { const revokedTokenMap: Record = {}; const mswServer = setupServer(); - setupRequestMockHandlers(mswServer); + setupMswHandlers(mswServer); const issuerMetadata = { issuer: 'https://oidc.test', diff --git a/plugins/auth-backend-module-oidc-provider/src/module.test.ts b/plugins/auth-backend-module-oidc-provider/src/module.test.ts index 1359634950..827ff9dd01 100644 --- a/plugins/auth-backend-module-oidc-provider/src/module.test.ts +++ b/plugins/auth-backend-module-oidc-provider/src/module.test.ts @@ -20,7 +20,7 @@ import { setupServer } from 'msw/node'; import { rest } from 'msw'; import { mockServices, - setupRequestMockHandlers, + setupMswHandlers, startTestBackend, } from '@backstage/backend-test-utils'; import { Server } from 'http'; @@ -35,7 +35,7 @@ describe('authModuleOidcProvider', () => { let publicKey: JWK; const mswServer = setupServer(); - setupRequestMockHandlers(mswServer); + setupMswHandlers(mswServer); const issuerMetadata = { issuer: 'https://oidc.test', diff --git a/plugins/auth-backend-module-pinniped-provider/src/authenticator.test.ts b/plugins/auth-backend-module-pinniped-provider/src/authenticator.test.ts index e2dedf2129..4cef747416 100644 --- a/plugins/auth-backend-module-pinniped-provider/src/authenticator.test.ts +++ b/plugins/auth-backend-module-pinniped-provider/src/authenticator.test.ts @@ -23,7 +23,7 @@ import { } from '@backstage/plugin-auth-node'; import { pinnipedAuthenticator } from './authenticator'; import { setupServer } from 'msw/node'; -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { setupMswHandlers } from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; import { JWK, SignJWT, exportJWK, generateKeyPair } from 'jose'; import { rest } from 'msw'; @@ -37,7 +37,7 @@ describe('pinnipedAuthenticator', () => { let publicKey: JWK; const mswServer = setupServer(); - setupRequestMockHandlers(mswServer); + setupMswHandlers(mswServer); const issuerMetadata = { issuer: 'https://pinniped.test', diff --git a/plugins/auth-backend-module-pinniped-provider/src/module.test.ts b/plugins/auth-backend-module-pinniped-provider/src/module.test.ts index a5c8fb4599..a7cbcaa0da 100644 --- a/plugins/auth-backend-module-pinniped-provider/src/module.test.ts +++ b/plugins/auth-backend-module-pinniped-provider/src/module.test.ts @@ -15,7 +15,7 @@ */ import { mockServices, - setupRequestMockHandlers, + setupMswHandlers, startTestBackend, } from '@backstage/backend-test-utils'; import { Server } from 'http'; @@ -32,7 +32,7 @@ describe('authModulePinnipedProvider', () => { let publicKey: JWK; const mswServer = setupServer(); - setupRequestMockHandlers(mswServer); + setupMswHandlers(mswServer); const issuerMetadata = { issuer: 'https://pinniped.test', diff --git a/plugins/auth-backend-module-vmware-cloud-provider/src/authenticator.test.ts b/plugins/auth-backend-module-vmware-cloud-provider/src/authenticator.test.ts index c69d4e9ab1..b5b335a112 100644 --- a/plugins/auth-backend-module-vmware-cloud-provider/src/authenticator.test.ts +++ b/plugins/auth-backend-module-vmware-cloud-provider/src/authenticator.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { setupMswHandlers } from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; import { AuthResolverContext, @@ -37,7 +37,7 @@ jest.mock('uid2', () => jest.fn().mockReturnValue('sessionid')); describe('vmwareCloudAuthenticator', () => { const server = setupServer(); - setupRequestMockHandlers(server); + setupMswHandlers(server); let oAuthState: OAuthState = { nonce: 'nonce', diff --git a/plugins/auth-backend/src/providers/bitbucketServer/provider.test.ts b/plugins/auth-backend/src/providers/bitbucketServer/provider.test.ts index 187c3b09a5..8e71b2e8bb 100644 --- a/plugins/auth-backend/src/providers/bitbucketServer/provider.test.ts +++ b/plugins/auth-backend/src/providers/bitbucketServer/provider.test.ts @@ -22,7 +22,7 @@ import { BitbucketServerOAuthResult, } from './provider'; import { setupServer } from 'msw/node'; -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { setupMswHandlers } from '@backstage/backend-test-utils'; import { rest } from 'msw'; import { AuthResolverContext } from '@backstage/plugin-auth-node'; @@ -131,7 +131,7 @@ describe('BitbucketServerAuthProvider', () => { describe('when transforming to type OAuthResponse', () => { const server = setupServer(); - setupRequestMockHandlers(server); + setupMswHandlers(server); it('should map to a valid response', async () => { server.use(whoAmIHandler(), getUserHandler()); @@ -311,7 +311,7 @@ describe('BitbucketServerAuthProvider', () => { describe('when authenticating', () => { const server = setupServer(); - setupRequestMockHandlers(server); + setupMswHandlers(server); it('should forward the refresh token', async () => { server.use(whoAmIHandler(), getUserHandler()); diff --git a/plugins/auth-backend/src/providers/oidc/provider.test.ts b/plugins/auth-backend/src/providers/oidc/provider.test.ts index c7e9c68580..01c3e04bc5 100644 --- a/plugins/auth-backend/src/providers/oidc/provider.test.ts +++ b/plugins/auth-backend/src/providers/oidc/provider.test.ts @@ -13,10 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { - mockServices, - setupRequestMockHandlers, -} from '@backstage/backend-test-utils'; +import { mockServices, setupMswHandlers } from '@backstage/backend-test-utils'; import { LoggerService } from '@backstage/backend-plugin-api'; import { Config, ConfigReader } from '@backstage/config'; import { @@ -38,7 +35,7 @@ describe('oidc.create', () => { nonce: 'foo', }; const server = setupServer(); - setupRequestMockHandlers(server); + setupMswHandlers(server); let publicKey: JWK; let tokenset: object; diff --git a/plugins/auth-node/src/identity/IdentityClient.test.ts b/plugins/auth-node/src/identity/IdentityClient.test.ts index bdc7dd5cd7..beefe43173 100644 --- a/plugins/auth-node/src/identity/IdentityClient.test.ts +++ b/plugins/auth-node/src/identity/IdentityClient.test.ts @@ -15,7 +15,7 @@ */ import { PluginEndpointDiscovery } from '@backstage/backend-common'; -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { setupMswHandlers } from '@backstage/backend-test-utils'; import { decodeProtectedHeader, exportJWK, @@ -102,7 +102,7 @@ describe('IdentityClient', () => { let factory: FakeTokenFactory; const keyDurationSeconds = 5; - setupRequestMockHandlers(server); + setupMswHandlers(server); beforeEach(() => { client = IdentityClient.create({ discovery, issuer: mockBaseUrl }); diff --git a/plugins/catalog-backend-module-azure/src/lib/azure.test.ts b/plugins/catalog-backend-module-azure/src/lib/azure.test.ts index ef00610dc0..9d153e630c 100644 --- a/plugins/catalog-backend-module-azure/src/lib/azure.test.ts +++ b/plugins/catalog-backend-module-azure/src/lib/azure.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { setupMswHandlers } from '@backstage/backend-test-utils'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { codeSearch, CodeSearchResponse } from './azure'; @@ -26,7 +26,7 @@ import { ConfigReader } from '@backstage/config'; describe('azure', () => { const server = setupServer(); - setupRequestMockHandlers(server); + setupMswHandlers(server); const createFixture = (host: string, token: string) => { const azureConfig = { diff --git a/plugins/catalog-backend-module-bitbucket-cloud/src/providers/BitbucketCloudEntityProvider.test.ts b/plugins/catalog-backend-module-bitbucket-cloud/src/providers/BitbucketCloudEntityProvider.test.ts index 55b701e016..1c6128ef9c 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/src/providers/BitbucketCloudEntityProvider.test.ts +++ b/plugins/catalog-backend-module-bitbucket-cloud/src/providers/BitbucketCloudEntityProvider.test.ts @@ -20,10 +20,7 @@ import { TaskInvocationDefinition, TaskRunner, } from '@backstage/backend-tasks'; -import { - mockServices, - setupRequestMockHandlers, -} from '@backstage/backend-test-utils'; +import { mockServices, setupMswHandlers } from '@backstage/backend-test-utils'; import { CatalogApi } from '@backstage/catalog-client'; import { Entity, LocationEntity } from '@backstage/catalog-model'; import { ConfigReader } from '@backstage/config'; @@ -62,7 +59,7 @@ const logger = mockServices.logger.mock(); const server = setupServer(); describe('BitbucketCloudEntityProvider', () => { - setupRequestMockHandlers(server); + setupMswHandlers(server); const simpleConfig = new ConfigReader({ catalog: { diff --git a/plugins/catalog-backend-module-bitbucket-server/src/lib/BitbucketServerClient.test.ts b/plugins/catalog-backend-module-bitbucket-server/src/lib/BitbucketServerClient.test.ts index a3d4155121..31ee011c23 100644 --- a/plugins/catalog-backend-module-bitbucket-server/src/lib/BitbucketServerClient.test.ts +++ b/plugins/catalog-backend-module-bitbucket-server/src/lib/BitbucketServerClient.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { setupMswHandlers } from '@backstage/backend-test-utils'; import { BitbucketServerIntegrationConfig } from '@backstage/integration'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; @@ -50,7 +50,7 @@ describe('BitbucketServerClient', () => { config: config, }); - setupRequestMockHandlers(server); + setupMswHandlers(server); it('listProjects', async () => { server.use( diff --git a/plugins/catalog-backend-module-bitbucket-server/src/providers/BitbucketServerEntityProvider.test.ts b/plugins/catalog-backend-module-bitbucket-server/src/providers/BitbucketServerEntityProvider.test.ts index 9624e396cd..fce1102aab 100644 --- a/plugins/catalog-backend-module-bitbucket-server/src/providers/BitbucketServerEntityProvider.test.ts +++ b/plugins/catalog-backend-module-bitbucket-server/src/providers/BitbucketServerEntityProvider.test.ts @@ -19,10 +19,7 @@ import { TaskInvocationDefinition, TaskRunner, } from '@backstage/backend-tasks'; -import { - mockServices, - setupRequestMockHandlers, -} from '@backstage/backend-test-utils'; +import { mockServices, setupMswHandlers } from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; import { EntityProviderConnection } from '@backstage/plugin-catalog-node'; import { rest } from 'msw'; @@ -103,7 +100,7 @@ function setupStubs(projects: Project[], baseUrl: string) { } describe('BitbucketServerEntityProvider', () => { - setupRequestMockHandlers(server); + setupMswHandlers(server); afterEach(() => { jest.clearAllMocks(); }); diff --git a/plugins/catalog-backend-module-gerrit/src/providers/GerritEntityProvider.test.ts b/plugins/catalog-backend-module-gerrit/src/providers/GerritEntityProvider.test.ts index 8b1acbdbaa..0a5baba297 100644 --- a/plugins/catalog-backend-module-gerrit/src/providers/GerritEntityProvider.test.ts +++ b/plugins/catalog-backend-module-gerrit/src/providers/GerritEntityProvider.test.ts @@ -19,10 +19,7 @@ import { TaskInvocationDefinition, TaskRunner, } from '@backstage/backend-tasks'; -import { - mockServices, - setupRequestMockHandlers, -} from '@backstage/backend-test-utils'; +import { mockServices, setupMswHandlers } from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; import { EntityProviderConnection } from '@backstage/plugin-catalog-node'; import fs from 'fs-extra'; @@ -57,7 +54,7 @@ class PersistingTaskRunner implements TaskRunner { const logger = mockServices.logger.mock(); describe('GerritEntityProvider', () => { - setupRequestMockHandlers(server); + setupMswHandlers(server); afterEach(() => { jest.clearAllMocks(); diff --git a/plugins/catalog-backend-module-github/src/analyzers/GithubLocationAnalyzer.test.ts b/plugins/catalog-backend-module-github/src/analyzers/GithubLocationAnalyzer.test.ts index e5c7eb5896..7b496a45c5 100644 --- a/plugins/catalog-backend-module-github/src/analyzers/GithubLocationAnalyzer.test.ts +++ b/plugins/catalog-backend-module-github/src/analyzers/GithubLocationAnalyzer.test.ts @@ -34,10 +34,7 @@ jest.mock('@octokit/rest', () => { import { PluginEndpointDiscovery } from '@backstage/backend-common'; import { GithubLocationAnalyzer } from './GithubLocationAnalyzer'; -import { - setupRequestMockHandlers, - mockServices, -} from '@backstage/backend-test-utils'; +import { setupMswHandlers, mockServices } from '@backstage/backend-test-utils'; import { setupServer } from 'msw/node'; import { rest } from 'msw'; import { ConfigReader } from '@backstage/config'; @@ -63,7 +60,7 @@ describe('GithubLocationAnalyzer', () => { }, }); - setupRequestMockHandlers(server); + setupMswHandlers(server); beforeEach(() => { server.use( diff --git a/plugins/catalog-backend-module-github/src/lib/github.test.ts b/plugins/catalog-backend-module-github/src/lib/github.test.ts index d83e8031cc..ac88a79bee 100644 --- a/plugins/catalog-backend-module-github/src/lib/github.test.ts +++ b/plugins/catalog-backend-module-github/src/lib/github.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { setupMswHandlers } from '@backstage/backend-test-utils'; import { GroupEntity, UserEntity } from '@backstage/catalog-model'; import { graphql as graphqlOctokit } from '@octokit/graphql'; import { graphql as graphqlMsw } from 'msw'; @@ -39,7 +39,7 @@ describe('github', () => { const graphql = graphqlOctokit.defaults({ request: { fetch } }); const server = setupServer(); - setupRequestMockHandlers(server); + setupMswHandlers(server); describe('getOrganizationUsers using defaultUserMapper', () => { it('reads members', async () => { diff --git a/plugins/catalog-backend-module-gitlab/src/GitLabDiscoveryProcessor.test.ts b/plugins/catalog-backend-module-gitlab/src/GitLabDiscoveryProcessor.test.ts index c1608cd386..10751ad615 100644 --- a/plugins/catalog-backend-module-gitlab/src/GitLabDiscoveryProcessor.test.ts +++ b/plugins/catalog-backend-module-gitlab/src/GitLabDiscoveryProcessor.test.ts @@ -14,10 +14,7 @@ * limitations under the License. */ -import { - mockServices, - setupRequestMockHandlers, -} from '@backstage/backend-test-utils'; +import { mockServices, setupMswHandlers } from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; import { LocationSpec } from '@backstage/plugin-catalog-node'; import { rest, RestRequest } from 'msw'; @@ -157,7 +154,7 @@ function getProcessor({ } describe('GitlabDiscoveryProcessor', () => { - setupRequestMockHandlers(server); + setupMswHandlers(server); beforeAll(() => { jest.useFakeTimers(); diff --git a/plugins/catalog-backend-module-gitlab/src/lib/client.test.ts b/plugins/catalog-backend-module-gitlab/src/lib/client.test.ts index 7d40eb1204..212c5cd4a4 100644 --- a/plugins/catalog-backend-module-gitlab/src/lib/client.test.ts +++ b/plugins/catalog-backend-module-gitlab/src/lib/client.test.ts @@ -14,10 +14,7 @@ * limitations under the License. */ -import { - mockServices, - setupRequestMockHandlers, -} from '@backstage/backend-test-utils'; +import { mockServices, setupMswHandlers } from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; import { readGitLabIntegrationConfig } from '@backstage/integration'; import { setupServer } from 'msw/node'; @@ -27,7 +24,7 @@ import { GitLabClient, paginated } from './client'; import { GitLabGroup, GitLabUser } from './types'; const server = setupServer(...handlers); -setupRequestMockHandlers(server); +setupMswHandlers(server); describe('GitLabClient', () => { describe('isSelfManaged', () => { diff --git a/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.test.ts b/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.test.ts index e89b378cfe..c23a897df2 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.test.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.test.ts @@ -19,10 +19,7 @@ import { TaskInvocationDefinition, TaskRunner, } from '@backstage/backend-tasks'; -import { - mockServices, - setupRequestMockHandlers, -} from '@backstage/backend-test-utils'; +import { mockServices, setupMswHandlers } from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; import { EntityProviderConnection } from '@backstage/plugin-catalog-node'; import { DefaultEventsService } from '@backstage/plugin-events-node'; @@ -32,7 +29,7 @@ import * as mock from '../__testUtils__/mocks'; import { GitlabDiscoveryEntityProvider } from './GitlabDiscoveryEntityProvider'; const server = setupServer(...handlers); -setupRequestMockHandlers(server); +setupMswHandlers(server); afterEach(() => jest.clearAllMocks()); class PersistingTaskRunner implements TaskRunner { diff --git a/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.test.ts b/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.test.ts index ddc0d03570..2fb8a6c839 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.test.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.test.ts @@ -19,10 +19,7 @@ import { TaskInvocationDefinition, TaskRunner, } from '@backstage/backend-tasks'; -import { - mockServices, - setupRequestMockHandlers, -} from '@backstage/backend-test-utils'; +import { mockServices, setupMswHandlers } from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; import { EntityProviderConnection } from '@backstage/plugin-catalog-node'; import { DefaultEventsService } from '@backstage/plugin-events-node'; @@ -33,7 +30,7 @@ import { GroupNameTransformerOptions } from '../lib/types'; import { GitlabOrgDiscoveryEntityProvider } from './GitlabOrgDiscoveryEntityProvider'; const server = setupServer(...handlers); -setupRequestMockHandlers(server); +setupMswHandlers(server); afterEach(() => jest.clearAllMocks()); class PersistingTaskRunner implements TaskRunner { diff --git a/plugins/catalog-backend-module-msgraph/src/microsoftGraph/client.test.ts b/plugins/catalog-backend-module-msgraph/src/microsoftGraph/client.test.ts index 6d63537b54..a58db08bfc 100644 --- a/plugins/catalog-backend-module-msgraph/src/microsoftGraph/client.test.ts +++ b/plugins/catalog-backend-module-msgraph/src/microsoftGraph/client.test.ts @@ -15,7 +15,7 @@ */ import { TokenCredential } from '@azure/identity'; -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { setupMswHandlers } from '@backstage/backend-test-utils'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { MicrosoftGraphClient } from './client'; @@ -27,7 +27,7 @@ describe('MicrosoftGraphClient', () => { let client: MicrosoftGraphClient; const worker = setupServer(); - setupRequestMockHandlers(worker); + setupMswHandlers(worker); beforeEach(() => { tokenCredential.getToken.mockResolvedValue({ diff --git a/plugins/catalog-backend-module-puppetdb/src/puppet/read.test.ts b/plugins/catalog-backend-module-puppetdb/src/puppet/read.test.ts index ac28f04503..05ae65f85c 100644 --- a/plugins/catalog-backend-module-puppetdb/src/puppet/read.test.ts +++ b/plugins/catalog-backend-module-puppetdb/src/puppet/read.test.ts @@ -20,14 +20,14 @@ import { PuppetDbEntityProviderConfig, } from '../providers'; import { DEFAULT_NAMESPACE } from '@backstage/catalog-model'; -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { setupMswHandlers } from '@backstage/backend-test-utils'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { ANNOTATION_PUPPET_CERTNAME, ENDPOINT_FACTSETS } from './constants'; describe('readPuppetNodes', () => { const worker = setupServer(); - setupRequestMockHandlers(worker); + setupMswHandlers(worker); beforeEach(() => { jest.clearAllMocks(); diff --git a/plugins/catalog-backend/src/modules/core/UrlReaderProcessor.test.ts b/plugins/catalog-backend/src/modules/core/UrlReaderProcessor.test.ts index dd80f8f0c4..2d46ce2256 100644 --- a/plugins/catalog-backend/src/modules/core/UrlReaderProcessor.test.ts +++ b/plugins/catalog-backend/src/modules/core/UrlReaderProcessor.test.ts @@ -15,10 +15,7 @@ */ import { UrlReader, UrlReaders } from '@backstage/backend-common'; -import { - mockServices, - setupRequestMockHandlers, -} from '@backstage/backend-test-utils'; +import { mockServices, setupMswHandlers } from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; @@ -39,7 +36,7 @@ describe('UrlReaderProcessor', () => { set: jest.fn(), }; const server = setupServer(); - setupRequestMockHandlers(server); + setupMswHandlers(server); beforeEach(() => { jest.resetAllMocks(); diff --git a/plugins/catalog-backend/src/search/DefaultCatalogCollator.test.ts b/plugins/catalog-backend/src/search/DefaultCatalogCollator.test.ts index 4c1673b785..8dc22f6ea0 100644 --- a/plugins/catalog-backend/src/search/DefaultCatalogCollator.test.ts +++ b/plugins/catalog-backend/src/search/DefaultCatalogCollator.test.ts @@ -18,7 +18,7 @@ import { PluginEndpointDiscovery, TokenManager, } from '@backstage/backend-common'; -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { setupMswHandlers } from '@backstage/backend-test-utils'; import { Entity } from '@backstage/catalog-model'; import { DefaultCatalogCollator } from './DefaultCatalogCollator'; import { setupServer } from 'msw/node'; @@ -62,7 +62,7 @@ describe('DefaultCatalogCollator', () => { let mockTokenManager: jest.Mocked; let collator: DefaultCatalogCollator; - setupRequestMockHandlers(server); + setupMswHandlers(server); beforeAll(() => { mockDiscoveryApi = { getBaseUrl: jest.fn().mockResolvedValue('http://localhost:7007'), diff --git a/plugins/catalog-import/src/api/AzureRepoApiClient.test.ts b/plugins/catalog-import/src/api/AzureRepoApiClient.test.ts index a8fbe9db76..65ef2c035e 100644 --- a/plugins/catalog-import/src/api/AzureRepoApiClient.test.ts +++ b/plugins/catalog-import/src/api/AzureRepoApiClient.test.ts @@ -26,7 +26,7 @@ import { RepoApiClient, } from './AzureRepoApiClient'; import { setupServer } from 'msw/node'; -import { setupRequestMockHandlers } from '@backstage/test-utils'; +import { setupMswHandlers } from '@backstage/test-utils'; function mockRepoEndpoint() { return rest.get( @@ -153,7 +153,7 @@ function mockPrEndpoint() { describe('RepoApiClient', () => { const server = setupServer(); - setupRequestMockHandlers(server); + setupMswHandlers(server); const testToken = new Date().toString(); const sut = new RepoApiClient({ project: 'project', diff --git a/plugins/catalog-import/src/api/CatalogImportClient.test.ts b/plugins/catalog-import/src/api/CatalogImportClient.test.ts index 1f16840c33..67a019cc1b 100644 --- a/plugins/catalog-import/src/api/CatalogImportClient.test.ts +++ b/plugins/catalog-import/src/api/CatalogImportClient.test.ts @@ -57,7 +57,7 @@ import { ConfigReader, UrlPatternDiscovery } from '@backstage/core-app-api'; import { ScmIntegrations } from '@backstage/integration'; import { ScmAuthApi } from '@backstage/integration-react'; import { CatalogApi } from '@backstage/plugin-catalog-react'; -import { MockFetchApi, setupRequestMockHandlers } from '@backstage/test-utils'; +import { MockFetchApi, setupMswHandlers } from '@backstage/test-utils'; import { Octokit } from '@octokit/rest'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; @@ -70,7 +70,7 @@ import { describe('CatalogImportClient', () => { const server = setupServer(); - setupRequestMockHandlers(server); + setupMswHandlers(server); const mockBaseUrl = 'http://backstage:9191/api/catalog'; const discoveryApi = UrlPatternDiscovery.compile(mockBaseUrl); diff --git a/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts b/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts index 1ac653bb58..7b61a22009 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts @@ -38,7 +38,7 @@ import { ServiceMock, mockCredentials, mockServices, - setupRequestMockHandlers, + setupMswHandlers, startTestBackend, } from '@backstage/backend-test-utils'; import { rest } from 'msw'; @@ -508,7 +508,7 @@ describe('API integration tests', () => { describe('/proxy', () => { const worker = setupServer(); - setupRequestMockHandlers(worker); + setupMswHandlers(worker); beforeEach(() => { worker.use( diff --git a/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.test.ts b/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.test.ts index a433374a2c..7a2aba2977 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.test.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.test.ts @@ -26,10 +26,7 @@ import { KubernetesFanOutHandler } from './KubernetesFanOutHandler'; import { KubernetesClientBasedFetcher } from './KubernetesFetcher'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; -import { - mockServices, - setupRequestMockHandlers, -} from '@backstage/backend-test-utils'; +import { mockServices, setupMswHandlers } from '@backstage/backend-test-utils'; import { FetchResponse, KubernetesRequestAuth, @@ -1128,7 +1125,7 @@ describe('KubernetesFanOutHandler', () => { describe('with a real fetcher', () => { const worker = setupServer(); - setupRequestMockHandlers(worker); + setupMswHandlers(worker); it('fetch error short-circuits requests to a single cluster, recovering across the fleet', async () => { const pods = [{ metadata: { name: 'pod-name' } }]; diff --git a/plugins/kubernetes-backend/src/service/KubernetesFetcher.test.ts b/plugins/kubernetes-backend/src/service/KubernetesFetcher.test.ts index dafb073bb1..e7196d9dc6 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesFetcher.test.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesFetcher.test.ts @@ -28,7 +28,7 @@ import { setupServer } from 'msw/node'; import { createMockDirectory, mockServices, - setupRequestMockHandlers, + setupMswHandlers, } from '@backstage/backend-test-utils'; import { Config } from '@kubernetes/client-node'; @@ -71,7 +71,7 @@ const POD_METRICS_FIXTURE = [ describe('KubernetesFetcher', () => { const worker = setupServer(); - setupRequestMockHandlers(worker); + setupMswHandlers(worker); const labels = (req: MockedRequest): object => { const selectorParam = req.url.searchParams.get('labelSelector'); diff --git a/plugins/kubernetes-backend/src/service/KubernetesProxy.test.ts b/plugins/kubernetes-backend/src/service/KubernetesProxy.test.ts index 02eeb8c7ed..45a131439b 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesProxy.test.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesProxy.test.ts @@ -20,7 +20,7 @@ import { errorHandler } from '@backstage/backend-common'; import { createMockDirectory, mockServices, - setupRequestMockHandlers, + setupMswHandlers, } from '@backstage/backend-test-utils'; import { NotFoundError } from '@backstage/errors'; import { @@ -90,7 +90,7 @@ describe('KubernetesProxy', () => { getExternalBaseUrl: jest.fn(), }; - setupRequestMockHandlers(worker); + setupMswHandlers(worker); const buildMockRequest = (clusterName: any, path: string): Request => { const req = getMockReq({ diff --git a/plugins/kubernetes-node/src/auth/PinnipedHelper.test.ts b/plugins/kubernetes-node/src/auth/PinnipedHelper.test.ts index fdfea030a5..f882d2373c 100644 --- a/plugins/kubernetes-node/src/auth/PinnipedHelper.test.ts +++ b/plugins/kubernetes-node/src/auth/PinnipedHelper.test.ts @@ -18,7 +18,7 @@ import { ExtendedHttpServer } from '@backstage/backend-app-api'; import { ClusterDetails } from '../types'; import { mockServices, - setupRequestMockHandlers, + setupMswHandlers, startTestBackend, } from '@backstage/backend-test-utils'; import { createBackendModule } from '@backstage/backend-plugin-api'; @@ -43,7 +43,7 @@ describe('Pinniped - tokenCredentialRequest', () => { const logger = loggerToWinstonLogger(mockServices.logger.mock()); let httpsRequest: jest.SpyInstance; const worker = setupServer(); - setupRequestMockHandlers(worker); + setupMswHandlers(worker); beforeAll(() => { httpsRequest = jest.spyOn( diff --git a/plugins/kubernetes-react/src/api/KubernetesBackendClient.test.ts b/plugins/kubernetes-react/src/api/KubernetesBackendClient.test.ts index 82ac7c84e2..eecaed20b6 100644 --- a/plugins/kubernetes-react/src/api/KubernetesBackendClient.test.ts +++ b/plugins/kubernetes-react/src/api/KubernetesBackendClient.test.ts @@ -19,7 +19,7 @@ import { KubernetesBackendClient } from './KubernetesBackendClient'; import { rest } from 'msw'; import { UrlPatternDiscovery } from '@backstage/core-app-api'; import { setupServer } from 'msw/node'; -import { MockFetchApi, setupRequestMockHandlers } from '@backstage/test-utils'; +import { MockFetchApi, setupMswHandlers } from '@backstage/test-utils'; import { CustomObjectsByEntityRequest, KubernetesRequestBody, @@ -36,7 +36,7 @@ describe('KubernetesBackendClient', () => { }; let mockResponse: ObjectsByEntityResponse; const worker = setupServer(); - setupRequestMockHandlers(worker); + setupMswHandlers(worker); const identityApi = { getCredentials: jest.fn(), diff --git a/plugins/notifications-node/src/service/DefaultNotificationService.test.ts b/plugins/notifications-node/src/service/DefaultNotificationService.test.ts index d5c327e788..843852af21 100644 --- a/plugins/notifications-node/src/service/DefaultNotificationService.test.ts +++ b/plugins/notifications-node/src/service/DefaultNotificationService.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { setupRequestMockHandlers } from '@backstage/test-utils'; +import { setupMswHandlers } from '@backstage/test-utils'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { NotificationPayload } from '@backstage/plugin-notifications-common'; @@ -32,7 +32,7 @@ const testNotification: NotificationPayload = { describe('DefaultNotificationService', () => { const server = setupServer(); - setupRequestMockHandlers(server); + setupMswHandlers(server); const discovery = mockServices.discovery.mock({ getBaseUrl: jest.fn().mockResolvedValue('http://example.com'), diff --git a/plugins/notifications/src/api/NotificationsClient.test.ts b/plugins/notifications/src/api/NotificationsClient.test.ts index e9acd04fc9..b4be073738 100644 --- a/plugins/notifications/src/api/NotificationsClient.test.ts +++ b/plugins/notifications/src/api/NotificationsClient.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { MockFetchApi, setupRequestMockHandlers } from '@backstage/test-utils'; +import { MockFetchApi, setupMswHandlers } from '@backstage/test-utils'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { NotificationsClient } from './NotificationsClient'; @@ -33,7 +33,7 @@ const testNotification: Partial = { }; describe('NotificationsClient', () => { - setupRequestMockHandlers(server); + setupMswHandlers(server); const mockBaseUrl = 'http://backstage/api/notifications'; const discoveryApi = { getBaseUrl: async () => mockBaseUrl }; const fetchApi = new MockFetchApi(); diff --git a/plugins/permission-node/src/ServerPermissionClient.test.ts b/plugins/permission-node/src/ServerPermissionClient.test.ts index 6e99ff71ab..b09c25eeb7 100644 --- a/plugins/permission-node/src/ServerPermissionClient.test.ts +++ b/plugins/permission-node/src/ServerPermissionClient.test.ts @@ -25,7 +25,7 @@ import { import { mockCredentials, mockServices, - setupRequestMockHandlers, + setupMswHandlers, } from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; import { setupServer } from 'msw/node'; @@ -54,7 +54,7 @@ const config = new ConfigReader({ }); describe('ServerPermissionClient', () => { - setupRequestMockHandlers(server); + setupMswHandlers(server); const discovery = mockServices.discovery.mock(); diff --git a/plugins/proxy-backend/src/service/router.config.test.ts b/plugins/proxy-backend/src/service/router.config.test.ts index ba81553a4f..3f11faea46 100644 --- a/plugins/proxy-backend/src/service/router.config.test.ts +++ b/plugins/proxy-backend/src/service/router.config.test.ts @@ -19,7 +19,7 @@ import { createServiceFactory, } from '@backstage/backend-plugin-api'; import { - setupRequestMockHandlers, + setupMswHandlers, startTestBackend, } from '@backstage/backend-test-utils'; import { @@ -36,7 +36,7 @@ import fetch from 'node-fetch'; describe('createRouter reloadable configuration', () => { const server = setupServer(); - setupRequestMockHandlers(server); + setupMswHandlers(server); it('should be able to observe the config', async () => { // Grab the subscriber function and use mutable config data to mock a config file change diff --git a/plugins/proxy-backend/src/service/router.credentials.test.ts b/plugins/proxy-backend/src/service/router.credentials.test.ts index 54c865ba11..aede6bb353 100644 --- a/plugins/proxy-backend/src/service/router.credentials.test.ts +++ b/plugins/proxy-backend/src/service/router.credentials.test.ts @@ -20,7 +20,7 @@ import { } from '@backstage/backend-app-api'; import { mockServices, - setupRequestMockHandlers, + setupMswHandlers, startTestBackend, } from '@backstage/backend-test-utils'; import { ResponseError } from '@backstage/errors'; @@ -34,7 +34,7 @@ import fetch from 'node-fetch'; describe('credentials', () => { const worker = setupServer(); - setupRequestMockHandlers(worker); + setupMswHandlers(worker); it('handles all valid credentials settings', async () => { const config = { diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloud.examples.test.ts b/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloud.examples.test.ts index 5e95f41751..ef745fbd18 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloud.examples.test.ts +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloud.examples.test.ts @@ -29,7 +29,7 @@ jest.mock('@backstage/plugin-scaffolder-node', () => { import { createPublishBitbucketCloudAction } from './bitbucketCloud'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { setupMswHandlers } from '@backstage/backend-test-utils'; import { ScmIntegrations } from '@backstage/integration'; import { ConfigReader } from '@backstage/config'; import { initRepoAndPush } from '@backstage/plugin-scaffolder-node'; @@ -66,7 +66,7 @@ describe('publish:bitbucketCloud', () => { }, }); const server = setupServer(); - setupRequestMockHandlers(server); + setupMswHandlers(server); beforeEach(() => { jest.resetAllMocks(); diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloud.test.ts b/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloud.test.ts index 6a079a3f9b..57215ac06d 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloud.test.ts +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloud.test.ts @@ -29,7 +29,7 @@ jest.mock('@backstage/plugin-scaffolder-node', () => { import { createPublishBitbucketCloudAction } from './bitbucketCloud'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { setupMswHandlers } from '@backstage/backend-test-utils'; import { ScmIntegrations } from '@backstage/integration'; import { ConfigReader } from '@backstage/config'; import { initRepoAndPush } from '@backstage/plugin-scaffolder-node'; @@ -56,7 +56,7 @@ describe('publish:bitbucketCloud', () => { }, }); const server = setupServer(); - setupRequestMockHandlers(server); + setupMswHandlers(server); beforeEach(() => { jest.resetAllMocks(); diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudPipelinesRun.examples.test.ts b/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudPipelinesRun.examples.test.ts index 472c7a6a03..6a4f82066e 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudPipelinesRun.examples.test.ts +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudPipelinesRun.examples.test.ts @@ -21,7 +21,7 @@ import yaml from 'yaml'; import { examples } from './bitbucketCloudPipelinesRun.examples'; import { ConfigReader } from '@backstage/config'; import { ScmIntegrations } from '@backstage/integration'; -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { setupMswHandlers } from '@backstage/backend-test-utils'; import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test-utils'; describe('bitbucket:pipelines:run', () => { @@ -48,7 +48,7 @@ describe('bitbucket:pipelines:run', () => { build_number: 1, }; const worker = setupServer(); - setupRequestMockHandlers(worker); + setupMswHandlers(worker); beforeEach(() => { jest.resetAllMocks(); diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudPipelinesRun.test.ts b/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudPipelinesRun.test.ts index 9386246868..be8500895a 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudPipelinesRun.test.ts +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudPipelinesRun.test.ts @@ -16,7 +16,7 @@ import { rest } from 'msw'; import { setupServer } from 'msw/node'; -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { setupMswHandlers } from '@backstage/backend-test-utils'; import { createBitbucketPipelinesRunAction } from './bitbucketCloudPipelinesRun'; import { ConfigReader } from '@backstage/config'; import { ScmIntegrations } from '@backstage/integration'; @@ -48,7 +48,7 @@ describe('bitbucket:pipelines:run', () => { build_number: 1, }; const worker = setupServer(); - setupRequestMockHandlers(worker); + setupMswHandlers(worker); beforeEach(() => { jest.clearAllMocks(); diff --git a/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServer.examples.test.ts b/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServer.examples.test.ts index eae8385822..8e6356df18 100644 --- a/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServer.examples.test.ts +++ b/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServer.examples.test.ts @@ -29,7 +29,7 @@ jest.mock('@backstage/plugin-scaffolder-node', () => { import { createPublishBitbucketServerAction } from './bitbucketServer'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { setupMswHandlers } from '@backstage/backend-test-utils'; import { ScmIntegrations } from '@backstage/integration'; import { ConfigReader } from '@backstage/config'; import yaml from 'yaml'; @@ -68,7 +68,7 @@ describe('publish:bitbucketServer', () => { }, }); const server = setupServer(); - setupRequestMockHandlers(server); + setupMswHandlers(server); beforeEach(() => { jest.resetAllMocks(); diff --git a/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServer.test.ts b/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServer.test.ts index 1d42e7368c..fb7d17c0ba 100644 --- a/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServer.test.ts +++ b/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServer.test.ts @@ -29,7 +29,7 @@ jest.mock('@backstage/plugin-scaffolder-node', () => { import { createPublishBitbucketServerAction } from './bitbucketServer'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { setupMswHandlers } from '@backstage/backend-test-utils'; import { ScmIntegrations } from '@backstage/integration'; import { ConfigReader } from '@backstage/config'; import { initRepoAndPush } from '@backstage/plugin-scaffolder-node'; @@ -66,7 +66,7 @@ describe('publish:bitbucketServer', () => { }, }); const server = setupServer(); - setupRequestMockHandlers(server); + setupMswHandlers(server); beforeEach(() => { jest.resetAllMocks(); diff --git a/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServerPullRequest.examples.test.ts b/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServerPullRequest.examples.test.ts index 1d3556fc88..0bc6d1464b 100644 --- a/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServerPullRequest.examples.test.ts +++ b/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServerPullRequest.examples.test.ts @@ -29,7 +29,7 @@ jest.mock('@backstage/plugin-scaffolder-node', () => { import { createPublishBitbucketServerPullRequestAction } from './bitbucketServerPullRequest'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { setupMswHandlers } from '@backstage/backend-test-utils'; import { ScmIntegrations } from '@backstage/integration'; import { ConfigReader } from '@backstage/config'; import yaml from 'yaml'; @@ -191,7 +191,7 @@ describe('publish:bitbucketServer:pull-request', () => { }; const server = setupServer(); - setupRequestMockHandlers(server); + setupMswHandlers(server); beforeEach(() => { jest.resetAllMocks(); diff --git a/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucket.examples.test.ts b/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucket.examples.test.ts index 6633246d70..964b2f207c 100644 --- a/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucket.examples.test.ts +++ b/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucket.examples.test.ts @@ -29,7 +29,7 @@ jest.mock('@backstage/plugin-scaffolder-node', () => { import { createPublishBitbucketAction } from './bitbucket'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { setupMswHandlers } from '@backstage/backend-test-utils'; import { ScmIntegrations } from '@backstage/integration'; import { ConfigReader } from '@backstage/config'; import { initRepoAndPush } from '@backstage/plugin-scaffolder-node'; @@ -67,7 +67,7 @@ describe('publish:bitbucket', () => { }, }); const server = setupServer(); - setupRequestMockHandlers(server); + setupMswHandlers(server); beforeEach(() => { jest.resetAllMocks(); diff --git a/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucket.test.ts b/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucket.test.ts index a63d657904..dddbcde828 100644 --- a/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucket.test.ts +++ b/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucket.test.ts @@ -28,7 +28,7 @@ jest.mock('@backstage/plugin-scaffolder-node', () => { import { createPublishBitbucketAction } from './bitbucket'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { setupMswHandlers } from '@backstage/backend-test-utils'; import { ScmIntegrations } from '@backstage/integration'; import { ConfigReader } from '@backstage/config'; import { initRepoAndPush } from '@backstage/plugin-scaffolder-node'; @@ -63,7 +63,7 @@ describe('publish:bitbucket', () => { }, }); const server = setupServer(); - setupRequestMockHandlers(server); + setupMswHandlers(server); beforeEach(() => { jest.resetAllMocks(); diff --git a/plugins/scaffolder-backend-module-confluence-to-markdown/src/actions/confluence/confluenceToMarkdown.examples.test.ts b/plugins/scaffolder-backend-module-confluence-to-markdown/src/actions/confluence/confluenceToMarkdown.examples.test.ts index da82849c1e..3aff044b89 100644 --- a/plugins/scaffolder-backend-module-confluence-to-markdown/src/actions/confluence/confluenceToMarkdown.examples.test.ts +++ b/plugins/scaffolder-backend-module-confluence-to-markdown/src/actions/confluence/confluenceToMarkdown.examples.test.ts @@ -20,7 +20,7 @@ import { ScmIntegrations } from '@backstage/integration'; import { createMockDirectory, mockServices, - setupRequestMockHandlers, + setupMswHandlers, } from '@backstage/backend-test-utils'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; @@ -32,7 +32,7 @@ import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test- describe('confluence:transform:markdown examples', () => { const baseUrl = `https://confluence.example.com`; const worker = setupServer(); - setupRequestMockHandlers(worker); + setupMswHandlers(worker); const config = new ConfigReader({ confluence: { diff --git a/plugins/scaffolder-backend-module-confluence-to-markdown/src/actions/confluence/confluenceToMarkdown.test.ts b/plugins/scaffolder-backend-module-confluence-to-markdown/src/actions/confluence/confluenceToMarkdown.test.ts index b19259b3df..5958f1407b 100644 --- a/plugins/scaffolder-backend-module-confluence-to-markdown/src/actions/confluence/confluenceToMarkdown.test.ts +++ b/plugins/scaffolder-backend-module-confluence-to-markdown/src/actions/confluence/confluenceToMarkdown.test.ts @@ -21,7 +21,7 @@ import { ScmIntegrations } from '@backstage/integration'; import { createMockDirectory, mockServices, - setupRequestMockHandlers, + setupMswHandlers, } from '@backstage/backend-test-utils'; import type { ActionContext } from '@backstage/plugin-scaffolder-node'; import { rest } from 'msw'; @@ -31,7 +31,7 @@ import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test- describe('confluence:transform:markdown', () => { const baseUrl = `https://nodomain.confluence.com`; const worker = setupServer(); - setupRequestMockHandlers(worker); + setupMswHandlers(worker); const config = new ConfigReader({ confluence: { diff --git a/plugins/scaffolder-backend-module-gerrit/src/actions/gerrit.test.ts b/plugins/scaffolder-backend-module-gerrit/src/actions/gerrit.test.ts index 1f069d3835..b91cc2d84d 100644 --- a/plugins/scaffolder-backend-module-gerrit/src/actions/gerrit.test.ts +++ b/plugins/scaffolder-backend-module-gerrit/src/actions/gerrit.test.ts @@ -30,7 +30,7 @@ import path from 'path'; import { createPublishGerritAction } from './gerrit'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { setupMswHandlers } from '@backstage/backend-test-utils'; import { ScmIntegrations } from '@backstage/integration'; import { ConfigReader } from '@backstage/config'; import { initRepoAndPush } from '@backstage/plugin-scaffolder-node'; @@ -61,7 +61,7 @@ describe('publish:gerrit', () => { }, }); const server = setupServer(); - setupRequestMockHandlers(server); + setupMswHandlers(server); beforeEach(() => { jest.resetAllMocks(); diff --git a/plugins/scaffolder-backend-module-gitea/src/actions/gitea.test.ts b/plugins/scaffolder-backend-module-gitea/src/actions/gitea.test.ts index 8a72265df0..ab4d4641d0 100644 --- a/plugins/scaffolder-backend-module-gitea/src/actions/gitea.test.ts +++ b/plugins/scaffolder-backend-module-gitea/src/actions/gitea.test.ts @@ -18,7 +18,7 @@ import { ConfigReader } from '@backstage/config'; import { createPublishGiteaAction } from './gitea'; import { initRepoAndPush } from '@backstage/plugin-scaffolder-node'; import { rest } from 'msw'; -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { setupMswHandlers } from '@backstage/backend-test-utils'; import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test-utils'; import { setupServer } from 'msw/node'; @@ -62,7 +62,7 @@ describe('publish:gitea', () => { }); const server = setupServer(); - setupRequestMockHandlers(server); + setupMswHandlers(server); beforeEach(() => { jest.resetAllMocks(); 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 158b7db4ae..9eef522ddc 100644 --- a/plugins/scaffolder-backend-module-sentry/src/actions/createProject.test.ts +++ b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { setupMswHandlers } from '@backstage/backend-test-utils'; import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test-utils'; import { ConfigReader } from '@backstage/config'; import { InputError } from '@backstage/errors'; @@ -27,7 +27,7 @@ import { createSentryCreateProjectAction } from './createProject'; describe('sentry:project:create action', () => { const worker = setupServer(); - setupRequestMockHandlers(worker); + setupMswHandlers(worker); const createScaffolderConfig = (configData: JsonObject = {}) => ({ config: new ConfigReader({ diff --git a/plugins/scaffolder/src/api.test.ts b/plugins/scaffolder/src/api.test.ts index 488169719d..1da440ab7b 100644 --- a/plugins/scaffolder/src/api.test.ts +++ b/plugins/scaffolder/src/api.test.ts @@ -16,7 +16,7 @@ import { ConfigReader } from '@backstage/core-app-api'; import { ScmIntegrations } from '@backstage/integration'; -import { MockFetchApi, setupRequestMockHandlers } from '@backstage/test-utils'; +import { MockFetchApi, setupMswHandlers } from '@backstage/test-utils'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { ScaffolderClient } from './api'; @@ -30,7 +30,7 @@ const mockFetchEventSource = fetchEventSource as jest.MockedFunction< const server = setupServer(); describe('api', () => { - setupRequestMockHandlers(server); + setupMswHandlers(server); const mockBaseUrl = 'http://backstage/api'; const discoveryApi = { getBaseUrl: async () => mockBaseUrl }; diff --git a/plugins/search-backend-module-catalog/src/collators/DefaultCatalogCollatorFactory.test.ts b/plugins/search-backend-module-catalog/src/collators/DefaultCatalogCollatorFactory.test.ts index 7af3a8e9a2..0d9320f3dd 100644 --- a/plugins/search-backend-module-catalog/src/collators/DefaultCatalogCollatorFactory.test.ts +++ b/plugins/search-backend-module-catalog/src/collators/DefaultCatalogCollatorFactory.test.ts @@ -18,7 +18,7 @@ import { PluginEndpointDiscovery, TokenManager, } from '@backstage/backend-common'; -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { setupMswHandlers } from '@backstage/backend-test-utils'; import { Entity } from '@backstage/catalog-model'; import { ConfigReader } from '@backstage/config'; import { TestPipeline } from '@backstage/plugin-search-backend-node'; @@ -74,7 +74,7 @@ describe('DefaultCatalogCollatorFactory', () => { tokenManager: mockTokenManager, }; - setupRequestMockHandlers(server); + setupMswHandlers(server); beforeEach(() => { server.use( diff --git a/plugins/search-backend-module-explore/src/collators/ToolDocumentCollatorFactory.test.ts b/plugins/search-backend-module-explore/src/collators/ToolDocumentCollatorFactory.test.ts index 82305d0d86..e69b48b1c3 100644 --- a/plugins/search-backend-module-explore/src/collators/ToolDocumentCollatorFactory.test.ts +++ b/plugins/search-backend-module-explore/src/collators/ToolDocumentCollatorFactory.test.ts @@ -19,10 +19,7 @@ import { } from '@backstage/backend-common'; import { ConfigReader } from '@backstage/config'; import { TestPipeline } from '@backstage/plugin-search-backend-node'; -import { - mockServices, - setupRequestMockHandlers, -} from '@backstage/backend-test-utils'; +import { mockServices, setupMswHandlers } from '@backstage/backend-test-utils'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { Readable } from 'stream'; @@ -82,7 +79,7 @@ describe('ToolDocumentCollatorFactory', () => { let collator: Readable; const worker = setupServer(); - setupRequestMockHandlers(worker); + setupMswHandlers(worker); beforeEach(async () => { factory = ToolDocumentCollatorFactory.fromConfig(config, options); diff --git a/plugins/search-backend-module-stack-overflow-collator/src/collators/StackOverflowQuestionsCollatorFactory.test.ts b/plugins/search-backend-module-stack-overflow-collator/src/collators/StackOverflowQuestionsCollatorFactory.test.ts index f4d4a77c3c..3698f7c8f6 100644 --- a/plugins/search-backend-module-stack-overflow-collator/src/collators/StackOverflowQuestionsCollatorFactory.test.ts +++ b/plugins/search-backend-module-stack-overflow-collator/src/collators/StackOverflowQuestionsCollatorFactory.test.ts @@ -17,10 +17,7 @@ import { StackOverflowQuestionsCollatorFactory, StackOverflowQuestionsCollatorFactoryOptions, } from './StackOverflowQuestionsCollatorFactory'; -import { - mockServices, - setupRequestMockHandlers, -} from '@backstage/backend-test-utils'; +import { mockServices, setupMswHandlers } from '@backstage/backend-test-utils'; import { TestPipeline } from '@backstage/plugin-search-backend-node'; import { ConfigReader } from '@backstage/config'; import { Readable } from 'stream'; @@ -95,7 +92,7 @@ describe('StackOverflowQuestionsCollatorFactory', () => { describe('getCollator', () => { const worker = setupServer(); - setupRequestMockHandlers(worker); + setupMswHandlers(worker); it('returns a readable stream', async () => { const factory = StackOverflowQuestionsCollatorFactory.fromConfig( diff --git a/plugins/search-backend-module-techdocs/src/collators/DefaultTechDocsCollatorFactory.test.ts b/plugins/search-backend-module-techdocs/src/collators/DefaultTechDocsCollatorFactory.test.ts index 26329e5ed6..a2e8cc9992 100644 --- a/plugins/search-backend-module-techdocs/src/collators/DefaultTechDocsCollatorFactory.test.ts +++ b/plugins/search-backend-module-techdocs/src/collators/DefaultTechDocsCollatorFactory.test.ts @@ -20,10 +20,7 @@ import { import { Entity } from '@backstage/catalog-model'; import { ConfigReader } from '@backstage/config'; import { TestPipeline } from '@backstage/plugin-search-backend-node'; -import { - mockServices, - setupRequestMockHandlers, -} from '@backstage/backend-test-utils'; +import { mockServices, setupMswHandlers } from '@backstage/backend-test-utils'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { Readable } from 'stream'; @@ -106,7 +103,7 @@ describe('DefaultTechDocsCollatorFactory', () => { let collator: Readable; const worker = setupServer(); - setupRequestMockHandlers(worker); + setupMswHandlers(worker); beforeEach(async () => { factory = DefaultTechDocsCollatorFactory.fromConfig(config, options); diff --git a/plugins/techdocs-backend/src/search/DefaultTechDocsCollator.test.ts b/plugins/techdocs-backend/src/search/DefaultTechDocsCollator.test.ts index a0fc908ee5..47245dc6fc 100644 --- a/plugins/techdocs-backend/src/search/DefaultTechDocsCollator.test.ts +++ b/plugins/techdocs-backend/src/search/DefaultTechDocsCollator.test.ts @@ -21,10 +21,7 @@ import { } from '@backstage/backend-common'; import { Entity } from '@backstage/catalog-model'; import { DefaultTechDocsCollator } from './DefaultTechDocsCollator'; -import { - mockServices, - setupRequestMockHandlers, -} from '@backstage/backend-test-utils'; +import { mockServices, setupMswHandlers } from '@backstage/backend-test-utils'; import { setupServer } from 'msw/node'; import { rest } from 'msw'; import { ConfigReader } from '@backstage/config'; @@ -79,7 +76,7 @@ const expectedEntities: Entity[] = [ describe('TechDocs Collator', () => { const worker = setupServer(); - setupRequestMockHandlers(worker); + setupMswHandlers(worker); describe('DefaultTechDocsCollator with legacyPathCasing configuration', () => { let mockDiscoveryApi: jest.Mocked; diff --git a/plugins/user-settings/src/apis/StorageApi/UserSettingsStorage.test.ts b/plugins/user-settings/src/apis/StorageApi/UserSettingsStorage.test.ts index a421c413dc..6ee6a3df2f 100644 --- a/plugins/user-settings/src/apis/StorageApi/UserSettingsStorage.test.ts +++ b/plugins/user-settings/src/apis/StorageApi/UserSettingsStorage.test.ts @@ -21,14 +21,14 @@ import { IdentityApi, StorageApi, } from '@backstage/core-plugin-api'; -import { MockFetchApi, setupRequestMockHandlers } from '@backstage/test-utils'; +import { MockFetchApi, setupMswHandlers } from '@backstage/test-utils'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { UserSettingsStorage } from './UserSettingsStorage'; describe('Persistent Storage API', () => { const server = setupServer(); - setupRequestMockHandlers(server); + setupMswHandlers(server); const mockBaseUrl = 'http://backstage:9191/api'; const mockErrorApi = { post: jest.fn(), error$: jest.fn() }; From b82aff92aaa3b270e661dcd1a198e512b7a16099 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Wed, 10 Jul 2024 12:53:32 +0200 Subject: [PATCH 215/416] refactor(test-utils): deprecate the `isDockerDisabledForTests` function Signed-off-by: Camila Belo --- .changeset/tiny-schools-draw.md | 50 +------------------ .../02-testing.md | 6 +-- .../auth/authServiceFactory.test.ts | 4 +- .../external/ExternalTokenHandler.test.ts | 7 ++- .../entrypoints/auth/external/jwks.test.ts | 4 +- .../auth/user/UserTokenHandler.test.ts | 7 ++- .../urlReader/lib/AzureUrlReader.test.ts | 4 +- .../lib/BitbucketCloudUrlReader.test.ts | 4 +- .../lib/BitbucketServerUrlReader.test.ts | 4 +- .../urlReader/lib/BitbucketUrlReader.test.ts | 4 +- .../urlReader/lib/FetchUrlReader.test.ts | 7 ++- .../urlReader/lib/GerritUrlReader.test.ts | 4 +- .../urlReader/lib/GiteaUrlReader.test.ts | 7 ++- .../urlReader/lib/GithubUrlReader.test.ts | 4 +- .../urlReader/lib/GitlabUrlReader.test.ts | 4 +- .../urlReader/lib/HarnessUrlReader.test.ts | 7 ++- .../userInfo/DefaultUserInfoService.test.ts | 7 ++- packages/backend-test-utils/api-report.md | 14 +++--- packages/backend-test-utils/src/deprecated.ts | 22 ++++---- packages/backend-test-utils/src/msw/index.ts | 2 +- ...ockHandlers.ts => registerMswTestHooks.ts} | 2 +- .../cli/src/commands/versions/bump.test.ts | 4 +- .../ExampleComponent.test.tsx.hbs | 4 +- .../src/sources/RemoteConfigSource.test.ts | 4 +- .../auth/microsoft/MicrosoftAuth.test.ts | 4 +- .../DefaultAuthConnector.test.ts | 4 +- .../ProxiedSignInIdentity.test.ts | 4 +- .../ProxiedSignInPage.test.tsx | 4 +- packages/create-app/src/lib/tasks.test.ts | 4 +- packages/frontend-test-utils/api-report.md | 11 +++- .../frontend-test-utils/src/deprecated.ts | 29 +++++++++++ packages/frontend-test-utils/src/index.ts | 3 +- .../integration/src/bitbucket/core.test.ts | 4 +- .../src/bitbucketCloud/core.test.ts | 4 +- .../src/bitbucketServer/core.test.ts | 4 +- packages/integration/src/gerrit/core.test.ts | 4 +- packages/integration/src/gitea/core.test.ts | 4 +- packages/integration/src/harness/core.test.ts | 4 +- packages/integration/src/helpers.ts | 2 +- .../release-manifests/src/manifest.test.ts | 4 +- packages/test-utils/api-report.md | 14 +++--- packages/test-utils/src/deprecated.ts | 6 +-- .../apis/FetchApi/MockFetchApi.test.ts | 4 +- .../test-utils/src/testUtils/msw/index.ts | 2 +- ...MswHandlers.ts => registerMswTestHooks.ts} | 2 +- .../src/helpers.test.ts | 4 +- .../src/helpers.test.ts | 7 ++- .../src/authenticator.test.ts | 4 +- .../src/authenticator.test.ts | 4 +- .../src/module.test.ts | 4 +- .../src/authenticator.test.ts | 4 +- .../src/module.test.ts | 4 +- .../src/authenticator.test.ts | 4 +- .../bitbucketServer/provider.test.ts | 6 +-- .../src/providers/oidc/provider.test.ts | 7 ++- .../src/identity/IdentityClient.test.ts | 4 +- .../src/lib/azure.test.ts | 4 +- .../BitbucketCloudEntityProvider.test.ts | 7 ++- .../src/lib/BitbucketServerClient.test.ts | 4 +- .../BitbucketServerEntityProvider.test.ts | 7 ++- .../providers/GerritEntityProvider.test.ts | 7 ++- .../analyzers/GithubLocationAnalyzer.test.ts | 7 ++- .../src/lib/github.test.ts | 4 +- .../src/GitLabDiscoveryProcessor.test.ts | 7 ++- .../src/lib/client.test.ts | 7 ++- .../GitlabDiscoveryEntityProvider.test.ts | 7 ++- .../GitlabOrgDiscoveryEntityProvider.test.ts | 7 ++- .../src/microsoftGraph/client.test.ts | 4 +- .../src/puppet/read.test.ts | 4 +- .../modules/core/UrlReaderProcessor.test.ts | 7 ++- .../src/search/DefaultCatalogCollator.test.ts | 4 +- .../src/api/AzureRepoApiClient.test.ts | 4 +- .../src/api/CatalogImportClient.test.ts | 4 +- .../src/service/KubernetesBuilder.test.ts | 4 +- .../service/KubernetesFanOutHandler.test.ts | 7 ++- .../src/service/KubernetesFetcher.test.ts | 4 +- .../src/service/KubernetesProxy.test.ts | 4 +- .../src/auth/PinnipedHelper.test.ts | 4 +- .../src/api/KubernetesBackendClient.test.ts | 4 +- .../DefaultNotificationService.test.ts | 4 +- .../src/api/NotificationsClient.test.ts | 4 +- .../src/ServerPermissionClient.test.ts | 4 +- .../src/service/router.config.test.ts | 4 +- .../src/service/router.credentials.test.ts | 4 +- .../actions/bitbucketCloud.examples.test.ts | 4 +- .../src/actions/bitbucketCloud.test.ts | 4 +- ...itbucketCloudPipelinesRun.examples.test.ts | 4 +- .../bitbucketCloudPipelinesRun.test.ts | 4 +- .../actions/bitbucketServer.examples.test.ts | 4 +- .../src/actions/bitbucketServer.test.ts | 4 +- ...itbucketServerPullRequest.examples.test.ts | 4 +- .../bitbucketServerPullRequest.test.ts | 4 +- .../src/actions/bitbucket.examples.test.ts | 4 +- .../src/actions/bitbucket.test.ts | 4 +- .../confluenceToMarkdown.examples.test.ts | 4 +- .../confluence/confluenceToMarkdown.test.ts | 4 +- .../src/actions/gerrit.test.ts | 4 +- .../src/actions/gitea.test.ts | 4 +- .../src/actions/createProject.test.ts | 4 +- plugins/scaffolder/src/api.test.ts | 4 +- .../DefaultCatalogCollatorFactory.test.ts | 4 +- .../ToolDocumentCollatorFactory.test.ts | 7 ++- ...ckOverflowQuestionsCollatorFactory.test.ts | 7 ++- .../DefaultTechDocsCollatorFactory.test.ts | 7 ++- .../search/DefaultTechDocsCollator.test.ts | 7 ++- .../StorageApi/UserSettingsStorage.test.ts | 4 +- 106 files changed, 329 insertions(+), 272 deletions(-) rename packages/backend-test-utils/src/msw/{setupRequestMockHandlers.ts => registerMswTestHooks.ts} (95%) create mode 100644 packages/frontend-test-utils/src/deprecated.ts rename packages/test-utils/src/testUtils/msw/{setupMswHandlers.ts => registerMswTestHooks.ts} (95%) diff --git a/.changeset/tiny-schools-draw.md b/.changeset/tiny-schools-draw.md index 02f57308fb..2042f13fac 100644 --- a/.changeset/tiny-schools-draw.md +++ b/.changeset/tiny-schools-draw.md @@ -1,53 +1,7 @@ --- -'@backstage/plugin-scaffolder-backend-module-confluence-to-markdown': patch -'@backstage/plugin-auth-backend-module-cloudflare-access-provider': patch -'@backstage/plugin-search-backend-module-stack-overflow-collator': patch -'@backstage/plugin-scaffolder-backend-module-bitbucket-server': patch -'@backstage/plugin-auth-backend-module-vmware-cloud-provider': patch -'@backstage/plugin-scaffolder-backend-module-bitbucket-cloud': patch -'@backstage/plugin-catalog-backend-module-bitbucket-server': patch -'@backstage/plugin-auth-backend-module-microsoft-provider': patch -'@backstage/plugin-catalog-backend-module-bitbucket-cloud': patch -'@backstage/plugin-auth-backend-module-pinniped-provider': patch -'@backstage/plugin-auth-backend-module-aws-alb-provider': patch -'@backstage/plugin-scaffolder-backend-module-bitbucket': patch -'@backstage/plugin-auth-backend-module-oidc-provider': patch -'@backstage/plugin-scaffolder-backend-module-gerrit': patch -'@backstage/plugin-scaffolder-backend-module-sentry': patch -'@backstage/plugin-catalog-backend-module-puppetdb': patch -'@backstage/plugin-scaffolder-backend-module-gitea': patch -'@backstage/plugin-catalog-backend-module-msgraph': 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-search-backend-module-catalog': patch -'@backstage/plugin-search-backend-module-explore': patch -'@backstage/plugin-catalog-backend-module-azure': patch -'@backstage/frontend-test-utils': patch '@backstage/backend-test-utils': patch -'@backstage/release-manifests': patch -'@backstage/plugin-kubernetes-backend': patch -'@backstage/plugin-notifications-node': patch -'@backstage/backend-defaults': patch -'@backstage/core-components': patch -'@backstage/plugin-kubernetes-react': patch -'@backstage/plugin-techdocs-backend': patch -'@backstage/plugin-catalog-backend': patch -'@backstage/plugin-kubernetes-node': patch -'@backstage/plugin-permission-node': patch -'@backstage/config-loader': patch -'@backstage/plugin-catalog-import': patch -'@backstage/core-app-api': patch -'@backstage/plugin-notifications': patch -'@backstage/plugin-proxy-backend': patch -'@backstage/plugin-user-settings': patch -'@backstage/plugin-auth-backend': patch -'@backstage/create-app': patch +'@backstage/frontend-test-utils': patch '@backstage/test-utils': patch -'@backstage/plugin-scaffolder': patch -'@backstage/plugin-auth-node': patch -'@backstage/cli': patch --- -Rename frontend and backend `setupRequestMockHandlers` methods to `setupMswHandlers`. +Rename frontend and backend `setupRequestMockHandlers` methods to `registerMswTestHooks`. diff --git a/docs/backend-system/building-plugins-and-modules/02-testing.md b/docs/backend-system/building-plugins-and-modules/02-testing.md index 0739ad24aa..addcc72c84 100644 --- a/docs/backend-system/building-plugins-and-modules/02-testing.md +++ b/docs/backend-system/building-plugins-and-modules/02-testing.md @@ -61,7 +61,7 @@ requests and return mock responses. This lets you stub out remote services rather than the local clients, leading to more thorough and robust tests. You can read more about how it works [in their documentation](https://mswjs.io/). -The `@backstage/backend-test-utils` package exports a `setupRequestMockHandlers` +The `@backstage/backend-test-utils` package exports a `registerMswTestHooks` function which ensures that the correct `jest` lifecycle hooks are invoked to set up and tear down your `msw` instance, and enables the option that completely rejects requests that don't match one of your mock rules. This ensures that your @@ -70,13 +70,13 @@ tests cannot accidentally leak traffic into production from tests. Example: ```ts -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; describe('read from remote', () => { const worker = setupServer(); - setupRequestMockHandlers(worker); + registerMswTestHooks(worker); it('should auth and read successfully', async () => { expect.assertions(1); diff --git a/packages/backend-defaults/src/entrypoints/auth/authServiceFactory.test.ts b/packages/backend-defaults/src/entrypoints/auth/authServiceFactory.test.ts index 385bc17a36..f9ef4c9762 100644 --- a/packages/backend-defaults/src/entrypoints/auth/authServiceFactory.test.ts +++ b/packages/backend-defaults/src/entrypoints/auth/authServiceFactory.test.ts @@ -17,7 +17,7 @@ import { ServiceFactoryTester, mockServices, - setupMswHandlers, + registerMswTestHooks, } from '@backstage/backend-test-utils'; import { tokenManagerServiceFactory } from '@backstage/backend-app-api'; import { authServiceFactory } from './authServiceFactory'; @@ -68,7 +68,7 @@ const mockDeps = [ ]; describe('authServiceFactory', () => { - setupMswHandlers(server); + registerMswTestHooks(server); afterEach(() => { jest.useRealTimers(); diff --git a/packages/backend-defaults/src/entrypoints/auth/external/ExternalTokenHandler.test.ts b/packages/backend-defaults/src/entrypoints/auth/external/ExternalTokenHandler.test.ts index 2e413c73d6..39b01c46b6 100644 --- a/packages/backend-defaults/src/entrypoints/auth/external/ExternalTokenHandler.test.ts +++ b/packages/backend-defaults/src/entrypoints/auth/external/ExternalTokenHandler.test.ts @@ -17,7 +17,10 @@ import { BackstagePrincipalAccessRestrictions } from '@backstage/backend-plugin-api'; import { ExternalTokenHandler } from './ExternalTokenHandler'; import { TokenHandler } from './types'; -import { mockServices, setupMswHandlers } from '@backstage/backend-test-utils'; +import { + mockServices, + registerMswTestHooks, +} from '@backstage/backend-test-utils'; import { randomBytes } from 'crypto'; import { SignJWT, exportJWK, generateKeyPair } from 'jose'; import { DateTime } from 'luxon'; @@ -78,7 +81,7 @@ class FakeTokenFactory { describe('ExternalTokenHandler', () => { const server = setupServer(); - setupMswHandlers(server); + registerMswTestHooks(server); it('skips over inner handlers that do not match, and applies plugin restrictions', async () => { const handler1: TokenHandler = { diff --git a/packages/backend-defaults/src/entrypoints/auth/external/jwks.test.ts b/packages/backend-defaults/src/entrypoints/auth/external/jwks.test.ts index 02abd1e889..321e1823aa 100644 --- a/packages/backend-defaults/src/entrypoints/auth/external/jwks.test.ts +++ b/packages/backend-defaults/src/entrypoints/auth/external/jwks.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { setupMswHandlers } from '@backstage/backend-test-utils'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; import { SignJWT, exportJWK, generateKeyPair } from 'jose'; import { rest } from 'msw'; @@ -81,7 +81,7 @@ describe('JWKSHandler', () => { let mockSubject: string; const keyDurationSeconds = 5; - setupMswHandlers(server); + registerMswTestHooks(server); beforeEach(() => { mockSubject = 'test_subject'; diff --git a/packages/backend-defaults/src/entrypoints/auth/user/UserTokenHandler.test.ts b/packages/backend-defaults/src/entrypoints/auth/user/UserTokenHandler.test.ts index 9078be81e0..e85ec8db63 100644 --- a/packages/backend-defaults/src/entrypoints/auth/user/UserTokenHandler.test.ts +++ b/packages/backend-defaults/src/entrypoints/auth/user/UserTokenHandler.test.ts @@ -16,7 +16,10 @@ import { JsonObject } from '@backstage/types'; import { UserTokenHandler } from './UserTokenHandler'; -import { mockServices, setupMswHandlers } from '@backstage/backend-test-utils'; +import { + mockServices, + registerMswTestHooks, +} from '@backstage/backend-test-utils'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { AuthenticationError } from '@backstage/errors'; @@ -61,7 +64,7 @@ async function createToken(options: { describe('UserTokenHandler', () => { let userTokenHandler: UserTokenHandler; - setupMswHandlers(server); + registerMswTestHooks(server); beforeEach(() => { jest.useRealTimers(); diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/AzureUrlReader.test.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/AzureUrlReader.test.ts index 9e2aec1b56..f53a7b6c11 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/AzureUrlReader.test.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/AzureUrlReader.test.ts @@ -26,7 +26,7 @@ import { import { createMockDirectory, mockServices, - setupMswHandlers, + registerMswTestHooks, } from '@backstage/backend-test-utils'; import fs from 'fs-extra'; import { rest } from 'msw'; @@ -76,7 +76,7 @@ describe('AzureUrlReader', () => { beforeEach(mockDir.clear); const worker = setupServer(); - setupMswHandlers(worker); + registerMswTestHooks(worker); describe('read', () => { beforeEach(() => { diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketCloudUrlReader.test.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketCloudUrlReader.test.ts index 43be9b1a92..f5caade3fa 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketCloudUrlReader.test.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketCloudUrlReader.test.ts @@ -21,7 +21,7 @@ import { } from '@backstage/integration'; import { createMockDirectory, - setupMswHandlers, + registerMswTestHooks, } from '@backstage/backend-test-utils'; import fs from 'fs-extra'; import { rest } from 'msw'; @@ -56,7 +56,7 @@ describe('BitbucketCloudUrlReader', () => { beforeEach(mockDir.clear); const worker = setupServer(); - setupMswHandlers(worker); + registerMswTestHooks(worker); describe('readUrl', () => { it('should be able to readUrl via buffer without ETag', async () => { diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketServerUrlReader.test.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketServerUrlReader.test.ts index b63e557f3e..6af2858cde 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketServerUrlReader.test.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketServerUrlReader.test.ts @@ -21,7 +21,7 @@ import { } from '@backstage/integration'; import { createMockDirectory, - setupMswHandlers, + registerMswTestHooks, } from '@backstage/backend-test-utils'; import fs from 'fs-extra'; import { rest } from 'msw'; @@ -51,7 +51,7 @@ const reader = new BitbucketServerUrlReader( describe('BitbucketServerUrlReader', () => { const worker = setupServer(); - setupMswHandlers(worker); + registerMswTestHooks(worker); describe('readTree', () => { const repoBuffer = fs.readFileSync( diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketUrlReader.test.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketUrlReader.test.ts index 67953cd020..54880aaa75 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketUrlReader.test.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketUrlReader.test.ts @@ -22,7 +22,7 @@ import { import { createMockDirectory, mockServices, - setupMswHandlers, + registerMswTestHooks, } from '@backstage/backend-test-utils'; import fs from 'fs-extra'; import { rest } from 'msw'; @@ -104,7 +104,7 @@ describe('BitbucketUrlReader', () => { ); const worker = setupServer(); - setupMswHandlers(worker); + registerMswTestHooks(worker); describe('readUrl', () => { it('should be able to readUrl via buffer without ETag', async () => { diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/FetchUrlReader.test.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/FetchUrlReader.test.ts index 31ad87178e..f84422c564 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/FetchUrlReader.test.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/FetchUrlReader.test.ts @@ -16,7 +16,10 @@ import { ConfigReader } from '@backstage/config'; import { NotFoundError, NotModifiedError } from '@backstage/errors'; -import { mockServices, setupMswHandlers } from '@backstage/backend-test-utils'; +import { + mockServices, + registerMswTestHooks, +} from '@backstage/backend-test-utils'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { FetchUrlReader } from './FetchUrlReader'; @@ -27,7 +30,7 @@ const fetchUrlReader = new FetchUrlReader(); describe('FetchUrlReader', () => { const worker = setupServer(); - setupMswHandlers(worker); + registerMswTestHooks(worker); beforeEach(() => { jest.clearAllMocks(); diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/GerritUrlReader.test.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/GerritUrlReader.test.ts index 61ae9eba6a..14ca4c018e 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/GerritUrlReader.test.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/GerritUrlReader.test.ts @@ -17,7 +17,7 @@ import { createMockDirectory, mockServices, - setupMswHandlers, + registerMswTestHooks, } from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; import { NotModifiedError, NotFoundError } from '@backstage/errors'; @@ -92,7 +92,7 @@ const createReader = (config: JsonObject): UrlReaderPredicateTuple[] => { // eslint-disable-next-line jest/no-disabled-tests describe.skip('GerritUrlReader', () => { const worker = setupServer(); - setupMswHandlers(worker); + registerMswTestHooks(worker); beforeEach(() => { mockDir.clear(); diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/GiteaUrlReader.test.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/GiteaUrlReader.test.ts index c3b744a792..77c995c552 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/GiteaUrlReader.test.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/GiteaUrlReader.test.ts @@ -14,7 +14,10 @@ * limitations under the License. */ -import { mockServices, setupMswHandlers } from '@backstage/backend-test-utils'; +import { + mockServices, + registerMswTestHooks, +} from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; import { GiteaIntegration, readGiteaConfig } from '@backstage/integration'; import { JsonObject } from '@backstage/types'; @@ -61,7 +64,7 @@ const createReader = (config: JsonObject): UrlReaderPredicateTuple[] => { describe('GiteaUrlReader', () => { const worker = setupServer(); - setupMswHandlers(worker); + registerMswTestHooks(worker); afterAll(() => { jest.clearAllMocks(); diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/GithubUrlReader.test.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/GithubUrlReader.test.ts index b0734a0f0e..f1dd7c0dc6 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/GithubUrlReader.test.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/GithubUrlReader.test.ts @@ -22,7 +22,7 @@ import { } from '@backstage/integration'; import { createMockDirectory, - setupMswHandlers, + registerMswTestHooks, } from '@backstage/backend-test-utils'; import fs from 'fs-extra'; import { rest } from 'msw'; @@ -74,7 +74,7 @@ const gheProcessor = new GithubUrlReader( describe('GithubUrlReader', () => { const worker = setupServer(); - setupMswHandlers(worker); + registerMswTestHooks(worker); beforeEach(mockDir.clear); diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/GitlabUrlReader.test.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/GitlabUrlReader.test.ts index 62f7d84c84..dd6a0970d2 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/GitlabUrlReader.test.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/GitlabUrlReader.test.ts @@ -18,7 +18,7 @@ import { ConfigReader } from '@backstage/config'; import { createMockDirectory, mockServices, - setupMswHandlers, + registerMswTestHooks, } from '@backstage/backend-test-utils'; import fs from 'fs-extra'; import { rest } from 'msw'; @@ -72,7 +72,7 @@ describe('GitlabUrlReader', () => { beforeEach(mockDir.clear); const worker = setupServer(); - setupMswHandlers(worker); + registerMswTestHooks(worker); describe('read', () => { beforeEach(() => { diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/HarnessUrlReader.test.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/HarnessUrlReader.test.ts index a95cf7f479..004e1931d0 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/HarnessUrlReader.test.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/HarnessUrlReader.test.ts @@ -14,7 +14,10 @@ * limitations under the License. */ -import { mockServices, setupMswHandlers } from '@backstage/backend-test-utils'; +import { + mockServices, + registerMswTestHooks, +} from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; import { HarnessIntegration, readHarnessConfig } from '@backstage/integration'; import { JsonObject } from '@backstage/types'; @@ -117,7 +120,7 @@ const handlers = [ describe('HarnessUrlReader', () => { const worker = setupServer(...handlers); - setupMswHandlers(worker); + registerMswTestHooks(worker); beforeAll(() => worker.listen({ onUnhandledRequest: 'bypass' })); afterAll(() => { jest.clearAllMocks(); diff --git a/packages/backend-defaults/src/entrypoints/userInfo/DefaultUserInfoService.test.ts b/packages/backend-defaults/src/entrypoints/userInfo/DefaultUserInfoService.test.ts index bba0c5145a..692d179ee2 100644 --- a/packages/backend-defaults/src/entrypoints/userInfo/DefaultUserInfoService.test.ts +++ b/packages/backend-defaults/src/entrypoints/userInfo/DefaultUserInfoService.test.ts @@ -15,7 +15,10 @@ */ import { BackstageUserPrincipal } from '@backstage/backend-plugin-api'; -import { mockServices, setupMswHandlers } from '@backstage/backend-test-utils'; +import { + mockServices, + registerMswTestHooks, +} from '@backstage/backend-test-utils'; import { JsonObject } from '@backstage/types'; import { SignJWT, base64url, importJWK } from 'jose'; import { rest } from 'msw'; @@ -25,7 +28,7 @@ import { DefaultUserInfoService } from './DefaultUserInfoService'; describe('DefaultUserInfoService', () => { const server = setupServer(); - setupMswHandlers(server); + registerMswTestHooks(server); const mockPublicKey = { kty: 'EC', diff --git a/packages/backend-test-utils/api-report.md b/packages/backend-test-utils/api-report.md index ac14bae321..37dc5d097d 100644 --- a/packages/backend-test-utils/api-report.md +++ b/packages/backend-test-utils/api-report.md @@ -365,6 +365,13 @@ export namespace mockServices { } } +// @public +export function registerMswTestHooks(worker: { + listen: (t: any) => void; + close: () => void; + resetHandlers: () => void; +}): void; + // @public export class ServiceFactoryTester { static from( @@ -402,13 +409,6 @@ export type ServiceMock = { : TService[Key]; }; -// @public -export function setupMswHandlers(worker: { - listen: (t: any) => void; - close: () => void; - resetHandlers: () => void; -}): void; - // @public @deprecated (undocumented) export function setupRequestMockHandlers(worker: { listen: (t: any) => void; diff --git a/packages/backend-test-utils/src/deprecated.ts b/packages/backend-test-utils/src/deprecated.ts index a349030b12..9790580a9c 100644 --- a/packages/backend-test-utils/src/deprecated.ts +++ b/packages/backend-test-utils/src/deprecated.ts @@ -14,9 +14,9 @@ * limitations under the License. */ +import { registerMswTestHooks } from './msw'; import { CreateMockDirectoryOptions } from './filesystem'; import { isDockerDisabledForTests as _isDockerDisabledForTests } from './util'; -import { setupMswHandlers } from './msw'; /** * @public @@ -26,20 +26,20 @@ export type MockDirectoryOptions = CreateMockDirectoryOptions; /** * @public - * @deprecated This is an internal function and will no longer be exported from this package. - */ -export function isDockerDisabledForTests(): boolean { - return _isDockerDisabledForTests(); -} - -/** - * @public - * @deprecated Use `setupMswHandlers` from `@backstage/backend-test-utils` instead. + * @deprecated Use `registerMswTestHooks` from `@backstage/backend-test-utils` instead. */ export function setupRequestMockHandlers(worker: { listen: (t: any) => void; close: () => void; resetHandlers: () => void; }): void { - setupMswHandlers(worker); + registerMswTestHooks(worker); +} + +/** + * @public + * @deprecated This is an internal function and will no longer be exported from this package. + */ +export function isDockerDisabledForTests(): boolean { + return _isDockerDisabledForTests(); } diff --git a/packages/backend-test-utils/src/msw/index.ts b/packages/backend-test-utils/src/msw/index.ts index a339721ba5..fa6a37445f 100644 --- a/packages/backend-test-utils/src/msw/index.ts +++ b/packages/backend-test-utils/src/msw/index.ts @@ -14,4 +14,4 @@ * limitations under the License. */ -export { setupMswHandlers } from './setupRequestMockHandlers'; +export { registerMswTestHooks } from './registerMswTestHooks'; diff --git a/packages/backend-test-utils/src/msw/setupRequestMockHandlers.ts b/packages/backend-test-utils/src/msw/registerMswTestHooks.ts similarity index 95% rename from packages/backend-test-utils/src/msw/setupRequestMockHandlers.ts rename to packages/backend-test-utils/src/msw/registerMswTestHooks.ts index e123bc91c0..4e26c38321 100644 --- a/packages/backend-test-utils/src/msw/setupRequestMockHandlers.ts +++ b/packages/backend-test-utils/src/msw/registerMswTestHooks.ts @@ -19,7 +19,7 @@ * @public * @param worker - service worker */ -export function setupMswHandlers(worker: { +export function registerMswTestHooks(worker: { listen: (t: any) => void; close: () => void; resetHandlers: () => void; diff --git a/packages/cli/src/commands/versions/bump.test.ts b/packages/cli/src/commands/versions/bump.test.ts index c7f8b7ed0c..b8677a48c5 100644 --- a/packages/cli/src/commands/versions/bump.test.ts +++ b/packages/cli/src/commands/versions/bump.test.ts @@ -18,7 +18,7 @@ import fs from 'fs-extra'; import { Command } from 'commander'; import * as runObj from '../../lib/run'; import bump, { bumpBackstageJsonVersion, createVersionFinder } from './bump'; -import { setupMswHandlers, withLogCollector } from '@backstage/test-utils'; +import { registerMswTestHooks, withLogCollector } from '@backstage/test-utils'; import { YarnInfoInspectData } from '../../lib/versioning/packages'; import { setupServer } from 'msw/node'; import { rest } from 'msw'; @@ -153,7 +153,7 @@ describe('bump', () => { }); const worker = setupServer(); - setupMswHandlers(worker); + registerMswTestHooks(worker); it('should bump backstage dependencies', async () => { mockDir.setContent({ diff --git a/packages/cli/templates/default-plugin/src/components/ExampleComponent/ExampleComponent.test.tsx.hbs b/packages/cli/templates/default-plugin/src/components/ExampleComponent/ExampleComponent.test.tsx.hbs index 9db62feebc..c79977f301 100644 --- a/packages/cli/templates/default-plugin/src/components/ExampleComponent/ExampleComponent.test.tsx.hbs +++ b/packages/cli/templates/default-plugin/src/components/ExampleComponent/ExampleComponent.test.tsx.hbs @@ -4,14 +4,14 @@ import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { screen } from '@testing-library/react'; import { - setupRequestMockHandlers, + registerMswTestHooks, renderInTestApp, } from '@backstage/test-utils'; describe('ExampleComponent', () => { const server = setupServer(); // Enable sane handlers for network requests - setupRequestMockHandlers(server); + registerMswTestHooks(server); // setup mock response beforeEach(() => { diff --git a/packages/config-loader/src/sources/RemoteConfigSource.test.ts b/packages/config-loader/src/sources/RemoteConfigSource.test.ts index 5fb16bf0c8..e825bf3434 100644 --- a/packages/config-loader/src/sources/RemoteConfigSource.test.ts +++ b/packages/config-loader/src/sources/RemoteConfigSource.test.ts @@ -15,14 +15,14 @@ */ import { rest } from 'msw'; -import { setupMswHandlers } from '@backstage/backend-test-utils'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { setupServer } from 'msw/node'; import { RemoteConfigSource } from './RemoteConfigSource'; import { readN } from './__testUtils__/testUtils'; describe('RemoteConfigSource', () => { const worker = setupServer(); - setupMswHandlers(worker); + registerMswTestHooks(worker); it('should load config from a remote URL', async () => { worker.use( diff --git a/packages/core-app-api/src/apis/implementations/auth/microsoft/MicrosoftAuth.test.ts b/packages/core-app-api/src/apis/implementations/auth/microsoft/MicrosoftAuth.test.ts index 698c9930b7..0143aa2ded 100644 --- a/packages/core-app-api/src/apis/implementations/auth/microsoft/MicrosoftAuth.test.ts +++ b/packages/core-app-api/src/apis/implementations/auth/microsoft/MicrosoftAuth.test.ts @@ -19,13 +19,13 @@ import MockOAuthApi from '../../OAuthRequestApi/MockOAuthApi'; import { UrlPatternDiscovery } from '../../DiscoveryApi'; import { ConfigReader } from '@backstage/config'; import { microsoftAuthApiRef } from '@backstage/core-plugin-api'; -import { setupMswHandlers } from '@backstage/test-utils'; +import { registerMswTestHooks } from '@backstage/test-utils'; import { setupServer } from 'msw/node'; import { rest } from 'msw'; describe('MicrosoftAuth', () => { const server = setupServer(); - setupMswHandlers(server); + registerMswTestHooks(server); const microsoftAuth = MicrosoftAuth.create({ configApi: new ConfigReader(undefined), oauthRequestApi: new MockOAuthApi(), diff --git a/packages/core-app-api/src/lib/AuthConnector/DefaultAuthConnector.test.ts b/packages/core-app-api/src/lib/AuthConnector/DefaultAuthConnector.test.ts index d4bd136201..60c4a3b8d9 100644 --- a/packages/core-app-api/src/lib/AuthConnector/DefaultAuthConnector.test.ts +++ b/packages/core-app-api/src/lib/AuthConnector/DefaultAuthConnector.test.ts @@ -18,7 +18,7 @@ import { DefaultAuthConnector } from './DefaultAuthConnector'; import MockOAuthApi from '../../apis/implementations/OAuthRequestApi/MockOAuthApi'; import * as loginPopup from '../loginPopup'; import { UrlPatternDiscovery } from '../../apis'; -import { setupMswHandlers } from '@backstage/test-utils'; +import { registerMswTestHooks } from '@backstage/test-utils'; import { setupServer } from 'msw/node'; import { rest } from 'msw'; import { ConfigReader } from '@backstage/config'; @@ -53,7 +53,7 @@ const defaultOptions = { describe('DefaultAuthConnector', () => { const server = setupServer(); - setupMswHandlers(server); + registerMswTestHooks(server); afterEach(() => { jest.resetAllMocks(); diff --git a/packages/core-components/src/layout/ProxiedSignInPage/ProxiedSignInIdentity.test.ts b/packages/core-components/src/layout/ProxiedSignInPage/ProxiedSignInIdentity.test.ts index 4780b174e0..7eebc13d56 100644 --- a/packages/core-components/src/layout/ProxiedSignInPage/ProxiedSignInIdentity.test.ts +++ b/packages/core-components/src/layout/ProxiedSignInPage/ProxiedSignInIdentity.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { setupMswHandlers } from '@backstage/test-utils'; +import { registerMswTestHooks } from '@backstage/test-utils'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { @@ -60,7 +60,7 @@ describe('ProxiedSignInIdentity', () => { afterEach(() => jest.useRealTimers()); const worker = setupServer(); - setupMswHandlers(worker); + registerMswTestHooks(worker); it('runs the happy path', async () => { const getBaseUrl = jest.fn(); diff --git a/packages/core-components/src/layout/ProxiedSignInPage/ProxiedSignInPage.test.tsx b/packages/core-components/src/layout/ProxiedSignInPage/ProxiedSignInPage.test.tsx index 3cfde3d0f0..e4e65b613f 100644 --- a/packages/core-components/src/layout/ProxiedSignInPage/ProxiedSignInPage.test.tsx +++ b/packages/core-components/src/layout/ProxiedSignInPage/ProxiedSignInPage.test.tsx @@ -20,7 +20,7 @@ import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { TestApiProvider, - setupMswHandlers, + registerMswTestHooks, wrapInTestApp, } from '@backstage/test-utils'; import { ProxiedSignInPage } from './ProxiedSignInPage'; @@ -28,7 +28,7 @@ import { discoveryApiRef } from '@backstage/core-plugin-api'; describe('ProxiedSignInPage', () => { const worker = setupServer(); - setupMswHandlers(worker); + registerMswTestHooks(worker); const Subject = wrapInTestApp(
      authenticated
      , { components: { diff --git a/packages/create-app/src/lib/tasks.test.ts b/packages/create-app/src/lib/tasks.test.ts index f26c3306f1..deba27273c 100644 --- a/packages/create-app/src/lib/tasks.test.ts +++ b/packages/create-app/src/lib/tasks.test.ts @@ -31,7 +31,7 @@ import { } from './tasks'; import { createMockDirectory, - setupMswHandlers, + registerMswTestHooks, } from '@backstage/backend-test-utils'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; @@ -423,7 +423,7 @@ describe('tasks', () => { describe('fetchYarnLockSeedTask', () => { const worker = setupServer(); - setupMswHandlers(worker); + registerMswTestHooks(worker); it('should fetch the yarn.lock seed file', async () => { worker.use( diff --git a/packages/frontend-test-utils/api-report.md b/packages/frontend-test-utils/api-report.md index 7c8f5a5837..9629e13bfa 100644 --- a/packages/frontend-test-utils/api-report.md +++ b/packages/frontend-test-utils/api-report.md @@ -18,9 +18,9 @@ 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 { registerMswTestHooks } from '@backstage/test-utils'; import { RenderResult } from '@testing-library/react'; import { RouteRef } from '@backstage/frontend-plugin-api'; -import { setupMswHandlers as setupRequestMockHandlers } from '@backstage/test-utils'; import { TestApiProvider } from '@backstage/test-utils'; import { TestApiProviderProps } from '@backstage/test-utils'; import { TestApiRegistry } from '@backstage/test-utils'; @@ -73,13 +73,20 @@ export { MockStorageApi }; export { MockStorageBucket }; +export { registerMswTestHooks }; + // @public export function renderInTestApp( element: JSX.Element, options?: TestAppOptions, ): RenderResult; -export { setupRequestMockHandlers }; +// @public @deprecated (undocumented) +export function setupRequestMockHandlers(worker: { + listen: (t: any) => void; + close: () => void; + resetHandlers: () => void; +}): void; export { TestApiProvider }; diff --git a/packages/frontend-test-utils/src/deprecated.ts b/packages/frontend-test-utils/src/deprecated.ts new file mode 100644 index 0000000000..1b67f73e6b --- /dev/null +++ b/packages/frontend-test-utils/src/deprecated.ts @@ -0,0 +1,29 @@ +/* + * Copyright 2024 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 { registerMswTestHooks } from '@backstage/test-utils'; + +/** + * @public + * @deprecated Use `registerMswTestHooks` from `@backstage/frontend-test-utils` instead. + */ +export function setupRequestMockHandlers(worker: { + listen: (t: any) => void; + close: () => void; + resetHandlers: () => void; +}): void { + registerMswTestHooks(worker); +} diff --git a/packages/frontend-test-utils/src/index.ts b/packages/frontend-test-utils/src/index.ts index 9d41699073..20f393706e 100644 --- a/packages/frontend-test-utils/src/index.ts +++ b/packages/frontend-test-utils/src/index.ts @@ -20,6 +20,7 @@ * Contains utilities that can be used when testing frontend features such as extensions. */ +export * from './deprecated'; export * from './apis'; export * from './app'; @@ -28,4 +29,4 @@ export type { TestApiProviderProps } from '@backstage/test-utils'; export { withLogCollector } from '@backstage/test-utils'; -export { setupMswHandlers as setupRequestMockHandlers } from '@backstage/test-utils'; +export { registerMswTestHooks } from '@backstage/test-utils'; diff --git a/packages/integration/src/bitbucket/core.test.ts b/packages/integration/src/bitbucket/core.test.ts index 6af974723f..f1b4e04f15 100644 --- a/packages/integration/src/bitbucket/core.test.ts +++ b/packages/integration/src/bitbucket/core.test.ts @@ -16,7 +16,7 @@ import { rest } from 'msw'; import { setupServer } from 'msw/node'; -import { setupRequestMockHandlers } from '../helpers'; +import { registerMswTestHooks } from '../helpers'; import { BitbucketIntegrationConfig } from './config'; import { getBitbucketDefaultBranch, @@ -27,7 +27,7 @@ import { describe('bitbucket core', () => { const worker = setupServer(); - setupRequestMockHandlers(worker); + registerMswTestHooks(worker); describe('getBitbucketRequestOptions', () => { it('inserts a token when needed', () => { diff --git a/packages/integration/src/bitbucketCloud/core.test.ts b/packages/integration/src/bitbucketCloud/core.test.ts index 3a342bae8b..56a53b924d 100644 --- a/packages/integration/src/bitbucketCloud/core.test.ts +++ b/packages/integration/src/bitbucketCloud/core.test.ts @@ -16,7 +16,7 @@ import { rest } from 'msw'; import { setupServer } from 'msw/node'; -import { setupRequestMockHandlers } from '../helpers'; +import { registerMswTestHooks } from '../helpers'; import { BitbucketCloudIntegrationConfig } from './config'; import { getBitbucketCloudDefaultBranch, @@ -27,7 +27,7 @@ import { describe('bitbucketCloud core', () => { const worker = setupServer(); - setupRequestMockHandlers(worker); + registerMswTestHooks(worker); describe('getBitbucketCloudRequestOptions', () => { it('insert basic auth when needed', () => { diff --git a/packages/integration/src/bitbucketServer/core.test.ts b/packages/integration/src/bitbucketServer/core.test.ts index b03a8dda83..c1c72b38dd 100644 --- a/packages/integration/src/bitbucketServer/core.test.ts +++ b/packages/integration/src/bitbucketServer/core.test.ts @@ -16,7 +16,7 @@ import { rest } from 'msw'; import { setupServer } from 'msw/node'; -import { setupRequestMockHandlers } from '../helpers'; +import { registerMswTestHooks } from '../helpers'; import { BitbucketServerIntegrationConfig } from './config'; import { getBitbucketServerDefaultBranch, @@ -27,7 +27,7 @@ import { describe('bitbucketServer core', () => { const worker = setupServer(); - setupRequestMockHandlers(worker); + registerMswTestHooks(worker); describe('getBitbucketServerRequestOptions', () => { it('inserts a token when needed', () => { diff --git a/packages/integration/src/gerrit/core.test.ts b/packages/integration/src/gerrit/core.test.ts index c2bf5d3ed2..35632c654e 100644 --- a/packages/integration/src/gerrit/core.test.ts +++ b/packages/integration/src/gerrit/core.test.ts @@ -17,7 +17,7 @@ import { rest } from 'msw'; import { setupServer } from 'msw/node'; import fetch from 'cross-fetch'; -import { setupRequestMockHandlers } from '../helpers'; +import { registerMswTestHooks } from '../helpers'; import { GerritIntegrationConfig } from './config'; import { buildGerritGitilesArchiveUrl, @@ -32,7 +32,7 @@ import { describe('gerrit core', () => { const worker = setupServer(); - setupRequestMockHandlers(worker); + registerMswTestHooks(worker); describe('buildGerritGitilesArchiveUrl', () => { const config: GerritIntegrationConfig = { diff --git a/packages/integration/src/gitea/core.test.ts b/packages/integration/src/gitea/core.test.ts index ac29c469b6..e9d7c592f0 100644 --- a/packages/integration/src/gitea/core.test.ts +++ b/packages/integration/src/gitea/core.test.ts @@ -15,7 +15,7 @@ */ import { setupServer } from 'msw/node'; -import { setupRequestMockHandlers } from '../helpers'; +import { registerMswTestHooks } from '../helpers'; import { GiteaIntegrationConfig } from './config'; import { getGiteaArchiveUrl, @@ -28,7 +28,7 @@ import { describe('gitea core', () => { const worker = setupServer(); - setupRequestMockHandlers(worker); + registerMswTestHooks(worker); describe('getGiteaFileCatalogInfoCntentsUrl', () => { it('can create an url from arguments', () => { diff --git a/packages/integration/src/harness/core.test.ts b/packages/integration/src/harness/core.test.ts index 78ca68a98a..90f37aaa08 100644 --- a/packages/integration/src/harness/core.test.ts +++ b/packages/integration/src/harness/core.test.ts @@ -15,7 +15,7 @@ */ import { setupServer } from 'msw/node'; -import { setupRequestMockHandlers } from '../helpers'; +import { registerMswTestHooks } from '../helpers'; import { HarnessIntegrationConfig } from './config'; import { getHarnessArchiveUrl, @@ -28,7 +28,7 @@ import { describe('Harness code core', () => { const worker = setupServer(); - setupRequestMockHandlers(worker); + registerMswTestHooks(worker); describe('getHarnessFileContentsUrl', () => { it('can create an url from arguments', () => { diff --git a/packages/integration/src/helpers.ts b/packages/integration/src/helpers.ts index b403155cc5..f56d360325 100644 --- a/packages/integration/src/helpers.ts +++ b/packages/integration/src/helpers.ts @@ -114,7 +114,7 @@ export function defaultScmResolveUrl(options: { * * @param worker - service worker */ -export function setupRequestMockHandlers(worker: { +export function registerMswTestHooks(worker: { listen: (t: any) => void; close: () => void; resetHandlers: () => void; diff --git a/packages/release-manifests/src/manifest.test.ts b/packages/release-manifests/src/manifest.test.ts index 8192bf867e..3c7657a83f 100644 --- a/packages/release-manifests/src/manifest.test.ts +++ b/packages/release-manifests/src/manifest.test.ts @@ -16,7 +16,7 @@ import { setupServer } from 'msw/node'; import { rest } from 'msw'; -import { setupMswHandlers } from '@backstage/test-utils'; +import { registerMswTestHooks } from '@backstage/test-utils'; import { getManifestByReleaseLine, getManifestByVersion, @@ -25,7 +25,7 @@ import { describe('Release Manifests', () => { const worker = setupServer(); - setupMswHandlers(worker); + registerMswTestHooks(worker); describe('getManifestByVersion', () => { it('should return a list of packages in a release', async () => { diff --git a/packages/test-utils/api-report.md b/packages/test-utils/api-report.md index 82816d931a..cc1c645387 100644 --- a/packages/test-utils/api-report.md +++ b/packages/test-utils/api-report.md @@ -197,6 +197,13 @@ export type MockStorageBucket = { [key: string]: any; }; +// @public +export function registerMswTestHooks(worker: { + listen: (t: any) => void; + close: () => void; + resetHandlers: () => void; +}): void; + // @public export function renderInTestApp( Component: ComponentType> | ReactNode, @@ -209,13 +216,6 @@ export function renderWithEffects( options?: Pick & LegacyRootOption, ): Promise; -// @public -export function setupMswHandlers(worker: { - listen: (t: any) => void; - close: () => void; - resetHandlers: () => void; -}): void; - // @public @deprecated (undocumented) export function setupRequestMockHandlers(worker: { listen: (t: any) => void; diff --git a/packages/test-utils/src/deprecated.ts b/packages/test-utils/src/deprecated.ts index 6825f9d0da..2033bbea2e 100644 --- a/packages/test-utils/src/deprecated.ts +++ b/packages/test-utils/src/deprecated.ts @@ -14,16 +14,16 @@ * limitations under the License. */ -import { setupMswHandlers } from './testUtils/msw'; +import { registerMswTestHooks } from './testUtils/msw'; /** * @public - * @deprecated Use `CreateMockDirectoryOptions` from `@backstage/backend-test-utils` instead. + * @deprecated Use `registerMswTestHooks` from `@backstage/test-utils` instead. */ export function setupRequestMockHandlers(worker: { listen: (t: any) => void; close: () => void; resetHandlers: () => void; }): void { - setupMswHandlers(worker); + registerMswTestHooks(worker); } diff --git a/packages/test-utils/src/testUtils/apis/FetchApi/MockFetchApi.test.ts b/packages/test-utils/src/testUtils/apis/FetchApi/MockFetchApi.test.ts index d51f4c7aee..d33036ca8c 100644 --- a/packages/test-utils/src/testUtils/apis/FetchApi/MockFetchApi.test.ts +++ b/packages/test-utils/src/testUtils/apis/FetchApi/MockFetchApi.test.ts @@ -16,12 +16,12 @@ import { rest } from 'msw'; import { setupServer } from 'msw/node'; -import { setupMswHandlers } from '../../msw'; +import { registerMswTestHooks } from '../../msw'; import { MockFetchApi } from './MockFetchApi'; describe('MockFetchApi', () => { const worker = setupServer(); - setupMswHandlers(worker); + registerMswTestHooks(worker); it('works with default constructor', async () => { worker.use( diff --git a/packages/test-utils/src/testUtils/msw/index.ts b/packages/test-utils/src/testUtils/msw/index.ts index a924676d06..fa6a37445f 100644 --- a/packages/test-utils/src/testUtils/msw/index.ts +++ b/packages/test-utils/src/testUtils/msw/index.ts @@ -14,4 +14,4 @@ * limitations under the License. */ -export { setupMswHandlers } from './setupMswHandlers'; +export { registerMswTestHooks } from './registerMswTestHooks'; diff --git a/packages/test-utils/src/testUtils/msw/setupMswHandlers.ts b/packages/test-utils/src/testUtils/msw/registerMswTestHooks.ts similarity index 95% rename from packages/test-utils/src/testUtils/msw/setupMswHandlers.ts rename to packages/test-utils/src/testUtils/msw/registerMswTestHooks.ts index e123bc91c0..4e26c38321 100644 --- a/packages/test-utils/src/testUtils/msw/setupMswHandlers.ts +++ b/packages/test-utils/src/testUtils/msw/registerMswTestHooks.ts @@ -19,7 +19,7 @@ * @public * @param worker - service worker */ -export function setupMswHandlers(worker: { +export function registerMswTestHooks(worker: { listen: (t: any) => void; close: () => void; resetHandlers: () => void; diff --git a/plugins/auth-backend-module-aws-alb-provider/src/helpers.test.ts b/plugins/auth-backend-module-aws-alb-provider/src/helpers.test.ts index 1b902246fb..81251584e9 100644 --- a/plugins/auth-backend-module-aws-alb-provider/src/helpers.test.ts +++ b/plugins/auth-backend-module-aws-alb-provider/src/helpers.test.ts @@ -19,7 +19,7 @@ import { JWTHeaderParameters, UnsecuredJWT } from 'jose'; import NodeCache from 'node-cache'; import { http, HttpResponse } from 'msw'; import { setupServer } from 'msw/node'; -import { setupMswHandlers } from '@backstage/backend-test-utils'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { PassportProfile } from '@backstage/plugin-auth-node'; import { makeProfileInfo, provisionKeyCache } from './helpers'; @@ -34,7 +34,7 @@ describe.each([ ], ])('helpers', (region, url) => { const server = setupServer(); - setupMswHandlers(server); + registerMswTestHooks(server); const nodeCache = jest.fn() as unknown as NodeCache; nodeCache.set = jest.fn(); diff --git a/plugins/auth-backend-module-cloudflare-access-provider/src/helpers.test.ts b/plugins/auth-backend-module-cloudflare-access-provider/src/helpers.test.ts index a0b3335874..9efab07ba5 100644 --- a/plugins/auth-backend-module-cloudflare-access-provider/src/helpers.test.ts +++ b/plugins/auth-backend-module-cloudflare-access-provider/src/helpers.test.ts @@ -14,7 +14,10 @@ * limitations under the License. */ -import { mockServices, setupMswHandlers } from '@backstage/backend-test-utils'; +import { + mockServices, + registerMswTestHooks, +} from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; import { SignJWT, exportJWK, generateKeyPair } from 'jose'; import { HttpResponse, http } from 'msw'; @@ -86,7 +89,7 @@ describe('helpers', () => { const tokenFactory = new MockTokenFactory(); const cache = mockServices.cache.mock(); const server = setupServer(); - setupMswHandlers(server); + registerMswTestHooks(server); beforeEach(() => { jest.clearAllMocks(); diff --git a/plugins/auth-backend-module-microsoft-provider/src/authenticator.test.ts b/plugins/auth-backend-module-microsoft-provider/src/authenticator.test.ts index fc392f68c2..74a7ab9974 100644 --- a/plugins/auth-backend-module-microsoft-provider/src/authenticator.test.ts +++ b/plugins/auth-backend-module-microsoft-provider/src/authenticator.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { setupMswHandlers } from '@backstage/backend-test-utils'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; import { encodeOAuthState, @@ -43,7 +43,7 @@ describe('microsoftAuthenticator', () => { const microsoftApi = new FakeMicrosoftAPI(); const server = setupServer(); - setupMswHandlers(server); + registerMswTestHooks(server); let implementation: { domainHint: string | undefined; diff --git a/plugins/auth-backend-module-oidc-provider/src/authenticator.test.ts b/plugins/auth-backend-module-oidc-provider/src/authenticator.test.ts index 05ccebdf7d..38e134bcd0 100644 --- a/plugins/auth-backend-module-oidc-provider/src/authenticator.test.ts +++ b/plugins/auth-backend-module-oidc-provider/src/authenticator.test.ts @@ -23,7 +23,7 @@ import { } from '@backstage/plugin-auth-node'; import { oidcAuthenticator } from './authenticator'; import { setupServer } from 'msw/node'; -import { setupMswHandlers } from '@backstage/backend-test-utils'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; import { JWK, SignJWT, exportJWK, generateKeyPair } from 'jose'; import { rest } from 'msw'; @@ -38,7 +38,7 @@ describe('oidcAuthenticator', () => { const revokedTokenMap: Record = {}; const mswServer = setupServer(); - setupMswHandlers(mswServer); + registerMswTestHooks(mswServer); const issuerMetadata = { issuer: 'https://oidc.test', diff --git a/plugins/auth-backend-module-oidc-provider/src/module.test.ts b/plugins/auth-backend-module-oidc-provider/src/module.test.ts index 827ff9dd01..1bbb5c1cff 100644 --- a/plugins/auth-backend-module-oidc-provider/src/module.test.ts +++ b/plugins/auth-backend-module-oidc-provider/src/module.test.ts @@ -20,7 +20,7 @@ import { setupServer } from 'msw/node'; import { rest } from 'msw'; import { mockServices, - setupMswHandlers, + registerMswTestHooks, startTestBackend, } from '@backstage/backend-test-utils'; import { Server } from 'http'; @@ -35,7 +35,7 @@ describe('authModuleOidcProvider', () => { let publicKey: JWK; const mswServer = setupServer(); - setupMswHandlers(mswServer); + registerMswTestHooks(mswServer); const issuerMetadata = { issuer: 'https://oidc.test', diff --git a/plugins/auth-backend-module-pinniped-provider/src/authenticator.test.ts b/plugins/auth-backend-module-pinniped-provider/src/authenticator.test.ts index 4cef747416..359e497e5f 100644 --- a/plugins/auth-backend-module-pinniped-provider/src/authenticator.test.ts +++ b/plugins/auth-backend-module-pinniped-provider/src/authenticator.test.ts @@ -23,7 +23,7 @@ import { } from '@backstage/plugin-auth-node'; import { pinnipedAuthenticator } from './authenticator'; import { setupServer } from 'msw/node'; -import { setupMswHandlers } from '@backstage/backend-test-utils'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; import { JWK, SignJWT, exportJWK, generateKeyPair } from 'jose'; import { rest } from 'msw'; @@ -37,7 +37,7 @@ describe('pinnipedAuthenticator', () => { let publicKey: JWK; const mswServer = setupServer(); - setupMswHandlers(mswServer); + registerMswTestHooks(mswServer); const issuerMetadata = { issuer: 'https://pinniped.test', diff --git a/plugins/auth-backend-module-pinniped-provider/src/module.test.ts b/plugins/auth-backend-module-pinniped-provider/src/module.test.ts index a7cbcaa0da..e170c8d4ed 100644 --- a/plugins/auth-backend-module-pinniped-provider/src/module.test.ts +++ b/plugins/auth-backend-module-pinniped-provider/src/module.test.ts @@ -15,7 +15,7 @@ */ import { mockServices, - setupMswHandlers, + registerMswTestHooks, startTestBackend, } from '@backstage/backend-test-utils'; import { Server } from 'http'; @@ -32,7 +32,7 @@ describe('authModulePinnipedProvider', () => { let publicKey: JWK; const mswServer = setupServer(); - setupMswHandlers(mswServer); + registerMswTestHooks(mswServer); const issuerMetadata = { issuer: 'https://pinniped.test', diff --git a/plugins/auth-backend-module-vmware-cloud-provider/src/authenticator.test.ts b/plugins/auth-backend-module-vmware-cloud-provider/src/authenticator.test.ts index b5b335a112..0e363d4700 100644 --- a/plugins/auth-backend-module-vmware-cloud-provider/src/authenticator.test.ts +++ b/plugins/auth-backend-module-vmware-cloud-provider/src/authenticator.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { setupMswHandlers } from '@backstage/backend-test-utils'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; import { AuthResolverContext, @@ -37,7 +37,7 @@ jest.mock('uid2', () => jest.fn().mockReturnValue('sessionid')); describe('vmwareCloudAuthenticator', () => { const server = setupServer(); - setupMswHandlers(server); + registerMswTestHooks(server); let oAuthState: OAuthState = { nonce: 'nonce', diff --git a/plugins/auth-backend/src/providers/bitbucketServer/provider.test.ts b/plugins/auth-backend/src/providers/bitbucketServer/provider.test.ts index 8e71b2e8bb..3756e00b38 100644 --- a/plugins/auth-backend/src/providers/bitbucketServer/provider.test.ts +++ b/plugins/auth-backend/src/providers/bitbucketServer/provider.test.ts @@ -22,7 +22,7 @@ import { BitbucketServerOAuthResult, } from './provider'; import { setupServer } from 'msw/node'; -import { setupMswHandlers } from '@backstage/backend-test-utils'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { rest } from 'msw'; import { AuthResolverContext } from '@backstage/plugin-auth-node'; @@ -131,7 +131,7 @@ describe('BitbucketServerAuthProvider', () => { describe('when transforming to type OAuthResponse', () => { const server = setupServer(); - setupMswHandlers(server); + registerMswTestHooks(server); it('should map to a valid response', async () => { server.use(whoAmIHandler(), getUserHandler()); @@ -311,7 +311,7 @@ describe('BitbucketServerAuthProvider', () => { describe('when authenticating', () => { const server = setupServer(); - setupMswHandlers(server); + registerMswTestHooks(server); it('should forward the refresh token', async () => { server.use(whoAmIHandler(), getUserHandler()); diff --git a/plugins/auth-backend/src/providers/oidc/provider.test.ts b/plugins/auth-backend/src/providers/oidc/provider.test.ts index 01c3e04bc5..89cf9c3b2c 100644 --- a/plugins/auth-backend/src/providers/oidc/provider.test.ts +++ b/plugins/auth-backend/src/providers/oidc/provider.test.ts @@ -13,7 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { mockServices, setupMswHandlers } from '@backstage/backend-test-utils'; +import { + mockServices, + registerMswTestHooks, +} from '@backstage/backend-test-utils'; import { LoggerService } from '@backstage/backend-plugin-api'; import { Config, ConfigReader } from '@backstage/config'; import { @@ -35,7 +38,7 @@ describe('oidc.create', () => { nonce: 'foo', }; const server = setupServer(); - setupMswHandlers(server); + registerMswTestHooks(server); let publicKey: JWK; let tokenset: object; diff --git a/plugins/auth-node/src/identity/IdentityClient.test.ts b/plugins/auth-node/src/identity/IdentityClient.test.ts index beefe43173..418eb544ad 100644 --- a/plugins/auth-node/src/identity/IdentityClient.test.ts +++ b/plugins/auth-node/src/identity/IdentityClient.test.ts @@ -15,7 +15,7 @@ */ import { PluginEndpointDiscovery } from '@backstage/backend-common'; -import { setupMswHandlers } from '@backstage/backend-test-utils'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { decodeProtectedHeader, exportJWK, @@ -102,7 +102,7 @@ describe('IdentityClient', () => { let factory: FakeTokenFactory; const keyDurationSeconds = 5; - setupMswHandlers(server); + registerMswTestHooks(server); beforeEach(() => { client = IdentityClient.create({ discovery, issuer: mockBaseUrl }); diff --git a/plugins/catalog-backend-module-azure/src/lib/azure.test.ts b/plugins/catalog-backend-module-azure/src/lib/azure.test.ts index 9d153e630c..4839b625d2 100644 --- a/plugins/catalog-backend-module-azure/src/lib/azure.test.ts +++ b/plugins/catalog-backend-module-azure/src/lib/azure.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { setupMswHandlers } from '@backstage/backend-test-utils'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { codeSearch, CodeSearchResponse } from './azure'; @@ -26,7 +26,7 @@ import { ConfigReader } from '@backstage/config'; describe('azure', () => { const server = setupServer(); - setupMswHandlers(server); + registerMswTestHooks(server); const createFixture = (host: string, token: string) => { const azureConfig = { diff --git a/plugins/catalog-backend-module-bitbucket-cloud/src/providers/BitbucketCloudEntityProvider.test.ts b/plugins/catalog-backend-module-bitbucket-cloud/src/providers/BitbucketCloudEntityProvider.test.ts index 1c6128ef9c..80d09f3e2f 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/src/providers/BitbucketCloudEntityProvider.test.ts +++ b/plugins/catalog-backend-module-bitbucket-cloud/src/providers/BitbucketCloudEntityProvider.test.ts @@ -20,7 +20,10 @@ import { TaskInvocationDefinition, TaskRunner, } from '@backstage/backend-tasks'; -import { mockServices, setupMswHandlers } from '@backstage/backend-test-utils'; +import { + mockServices, + registerMswTestHooks, +} from '@backstage/backend-test-utils'; import { CatalogApi } from '@backstage/catalog-client'; import { Entity, LocationEntity } from '@backstage/catalog-model'; import { ConfigReader } from '@backstage/config'; @@ -59,7 +62,7 @@ const logger = mockServices.logger.mock(); const server = setupServer(); describe('BitbucketCloudEntityProvider', () => { - setupMswHandlers(server); + registerMswTestHooks(server); const simpleConfig = new ConfigReader({ catalog: { diff --git a/plugins/catalog-backend-module-bitbucket-server/src/lib/BitbucketServerClient.test.ts b/plugins/catalog-backend-module-bitbucket-server/src/lib/BitbucketServerClient.test.ts index 31ee011c23..db2a05d0b1 100644 --- a/plugins/catalog-backend-module-bitbucket-server/src/lib/BitbucketServerClient.test.ts +++ b/plugins/catalog-backend-module-bitbucket-server/src/lib/BitbucketServerClient.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { setupMswHandlers } from '@backstage/backend-test-utils'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { BitbucketServerIntegrationConfig } from '@backstage/integration'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; @@ -50,7 +50,7 @@ describe('BitbucketServerClient', () => { config: config, }); - setupMswHandlers(server); + registerMswTestHooks(server); it('listProjects', async () => { server.use( diff --git a/plugins/catalog-backend-module-bitbucket-server/src/providers/BitbucketServerEntityProvider.test.ts b/plugins/catalog-backend-module-bitbucket-server/src/providers/BitbucketServerEntityProvider.test.ts index fce1102aab..49b69f0fa6 100644 --- a/plugins/catalog-backend-module-bitbucket-server/src/providers/BitbucketServerEntityProvider.test.ts +++ b/plugins/catalog-backend-module-bitbucket-server/src/providers/BitbucketServerEntityProvider.test.ts @@ -19,7 +19,10 @@ import { TaskInvocationDefinition, TaskRunner, } from '@backstage/backend-tasks'; -import { mockServices, setupMswHandlers } from '@backstage/backend-test-utils'; +import { + mockServices, + registerMswTestHooks, +} from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; import { EntityProviderConnection } from '@backstage/plugin-catalog-node'; import { rest } from 'msw'; @@ -100,7 +103,7 @@ function setupStubs(projects: Project[], baseUrl: string) { } describe('BitbucketServerEntityProvider', () => { - setupMswHandlers(server); + registerMswTestHooks(server); afterEach(() => { jest.clearAllMocks(); }); diff --git a/plugins/catalog-backend-module-gerrit/src/providers/GerritEntityProvider.test.ts b/plugins/catalog-backend-module-gerrit/src/providers/GerritEntityProvider.test.ts index 0a5baba297..ee3555c7f9 100644 --- a/plugins/catalog-backend-module-gerrit/src/providers/GerritEntityProvider.test.ts +++ b/plugins/catalog-backend-module-gerrit/src/providers/GerritEntityProvider.test.ts @@ -19,7 +19,10 @@ import { TaskInvocationDefinition, TaskRunner, } from '@backstage/backend-tasks'; -import { mockServices, setupMswHandlers } from '@backstage/backend-test-utils'; +import { + mockServices, + registerMswTestHooks, +} from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; import { EntityProviderConnection } from '@backstage/plugin-catalog-node'; import fs from 'fs-extra'; @@ -54,7 +57,7 @@ class PersistingTaskRunner implements TaskRunner { const logger = mockServices.logger.mock(); describe('GerritEntityProvider', () => { - setupMswHandlers(server); + registerMswTestHooks(server); afterEach(() => { jest.clearAllMocks(); diff --git a/plugins/catalog-backend-module-github/src/analyzers/GithubLocationAnalyzer.test.ts b/plugins/catalog-backend-module-github/src/analyzers/GithubLocationAnalyzer.test.ts index 7b496a45c5..29c8cbc66d 100644 --- a/plugins/catalog-backend-module-github/src/analyzers/GithubLocationAnalyzer.test.ts +++ b/plugins/catalog-backend-module-github/src/analyzers/GithubLocationAnalyzer.test.ts @@ -34,7 +34,10 @@ jest.mock('@octokit/rest', () => { import { PluginEndpointDiscovery } from '@backstage/backend-common'; import { GithubLocationAnalyzer } from './GithubLocationAnalyzer'; -import { setupMswHandlers, mockServices } from '@backstage/backend-test-utils'; +import { + registerMswTestHooks, + mockServices, +} from '@backstage/backend-test-utils'; import { setupServer } from 'msw/node'; import { rest } from 'msw'; import { ConfigReader } from '@backstage/config'; @@ -60,7 +63,7 @@ describe('GithubLocationAnalyzer', () => { }, }); - setupMswHandlers(server); + registerMswTestHooks(server); beforeEach(() => { server.use( diff --git a/plugins/catalog-backend-module-github/src/lib/github.test.ts b/plugins/catalog-backend-module-github/src/lib/github.test.ts index ac88a79bee..9eae9e1161 100644 --- a/plugins/catalog-backend-module-github/src/lib/github.test.ts +++ b/plugins/catalog-backend-module-github/src/lib/github.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { setupMswHandlers } from '@backstage/backend-test-utils'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { GroupEntity, UserEntity } from '@backstage/catalog-model'; import { graphql as graphqlOctokit } from '@octokit/graphql'; import { graphql as graphqlMsw } from 'msw'; @@ -39,7 +39,7 @@ describe('github', () => { const graphql = graphqlOctokit.defaults({ request: { fetch } }); const server = setupServer(); - setupMswHandlers(server); + registerMswTestHooks(server); describe('getOrganizationUsers using defaultUserMapper', () => { it('reads members', async () => { diff --git a/plugins/catalog-backend-module-gitlab/src/GitLabDiscoveryProcessor.test.ts b/plugins/catalog-backend-module-gitlab/src/GitLabDiscoveryProcessor.test.ts index 10751ad615..d7ce338d6d 100644 --- a/plugins/catalog-backend-module-gitlab/src/GitLabDiscoveryProcessor.test.ts +++ b/plugins/catalog-backend-module-gitlab/src/GitLabDiscoveryProcessor.test.ts @@ -14,7 +14,10 @@ * limitations under the License. */ -import { mockServices, setupMswHandlers } from '@backstage/backend-test-utils'; +import { + mockServices, + registerMswTestHooks, +} from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; import { LocationSpec } from '@backstage/plugin-catalog-node'; import { rest, RestRequest } from 'msw'; @@ -154,7 +157,7 @@ function getProcessor({ } describe('GitlabDiscoveryProcessor', () => { - setupMswHandlers(server); + registerMswTestHooks(server); beforeAll(() => { jest.useFakeTimers(); diff --git a/plugins/catalog-backend-module-gitlab/src/lib/client.test.ts b/plugins/catalog-backend-module-gitlab/src/lib/client.test.ts index 212c5cd4a4..1eebe7d6e0 100644 --- a/plugins/catalog-backend-module-gitlab/src/lib/client.test.ts +++ b/plugins/catalog-backend-module-gitlab/src/lib/client.test.ts @@ -14,7 +14,10 @@ * limitations under the License. */ -import { mockServices, setupMswHandlers } from '@backstage/backend-test-utils'; +import { + mockServices, + registerMswTestHooks, +} from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; import { readGitLabIntegrationConfig } from '@backstage/integration'; import { setupServer } from 'msw/node'; @@ -24,7 +27,7 @@ import { GitLabClient, paginated } from './client'; import { GitLabGroup, GitLabUser } from './types'; const server = setupServer(...handlers); -setupMswHandlers(server); +registerMswTestHooks(server); describe('GitLabClient', () => { describe('isSelfManaged', () => { diff --git a/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.test.ts b/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.test.ts index c23a897df2..473e547a57 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.test.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.test.ts @@ -19,7 +19,10 @@ import { TaskInvocationDefinition, TaskRunner, } from '@backstage/backend-tasks'; -import { mockServices, setupMswHandlers } from '@backstage/backend-test-utils'; +import { + mockServices, + registerMswTestHooks, +} from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; import { EntityProviderConnection } from '@backstage/plugin-catalog-node'; import { DefaultEventsService } from '@backstage/plugin-events-node'; @@ -29,7 +32,7 @@ import * as mock from '../__testUtils__/mocks'; import { GitlabDiscoveryEntityProvider } from './GitlabDiscoveryEntityProvider'; const server = setupServer(...handlers); -setupMswHandlers(server); +registerMswTestHooks(server); afterEach(() => jest.clearAllMocks()); class PersistingTaskRunner implements TaskRunner { diff --git a/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.test.ts b/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.test.ts index 2fb8a6c839..9706384ff0 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.test.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.test.ts @@ -19,7 +19,10 @@ import { TaskInvocationDefinition, TaskRunner, } from '@backstage/backend-tasks'; -import { mockServices, setupMswHandlers } from '@backstage/backend-test-utils'; +import { + mockServices, + registerMswTestHooks, +} from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; import { EntityProviderConnection } from '@backstage/plugin-catalog-node'; import { DefaultEventsService } from '@backstage/plugin-events-node'; @@ -30,7 +33,7 @@ import { GroupNameTransformerOptions } from '../lib/types'; import { GitlabOrgDiscoveryEntityProvider } from './GitlabOrgDiscoveryEntityProvider'; const server = setupServer(...handlers); -setupMswHandlers(server); +registerMswTestHooks(server); afterEach(() => jest.clearAllMocks()); class PersistingTaskRunner implements TaskRunner { diff --git a/plugins/catalog-backend-module-msgraph/src/microsoftGraph/client.test.ts b/plugins/catalog-backend-module-msgraph/src/microsoftGraph/client.test.ts index a58db08bfc..624b6e42b0 100644 --- a/plugins/catalog-backend-module-msgraph/src/microsoftGraph/client.test.ts +++ b/plugins/catalog-backend-module-msgraph/src/microsoftGraph/client.test.ts @@ -15,7 +15,7 @@ */ import { TokenCredential } from '@azure/identity'; -import { setupMswHandlers } from '@backstage/backend-test-utils'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { MicrosoftGraphClient } from './client'; @@ -27,7 +27,7 @@ describe('MicrosoftGraphClient', () => { let client: MicrosoftGraphClient; const worker = setupServer(); - setupMswHandlers(worker); + registerMswTestHooks(worker); beforeEach(() => { tokenCredential.getToken.mockResolvedValue({ diff --git a/plugins/catalog-backend-module-puppetdb/src/puppet/read.test.ts b/plugins/catalog-backend-module-puppetdb/src/puppet/read.test.ts index 05ae65f85c..8ad4c2b850 100644 --- a/plugins/catalog-backend-module-puppetdb/src/puppet/read.test.ts +++ b/plugins/catalog-backend-module-puppetdb/src/puppet/read.test.ts @@ -20,14 +20,14 @@ import { PuppetDbEntityProviderConfig, } from '../providers'; import { DEFAULT_NAMESPACE } from '@backstage/catalog-model'; -import { setupMswHandlers } from '@backstage/backend-test-utils'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { ANNOTATION_PUPPET_CERTNAME, ENDPOINT_FACTSETS } from './constants'; describe('readPuppetNodes', () => { const worker = setupServer(); - setupMswHandlers(worker); + registerMswTestHooks(worker); beforeEach(() => { jest.clearAllMocks(); diff --git a/plugins/catalog-backend/src/modules/core/UrlReaderProcessor.test.ts b/plugins/catalog-backend/src/modules/core/UrlReaderProcessor.test.ts index 2d46ce2256..7d1578db00 100644 --- a/plugins/catalog-backend/src/modules/core/UrlReaderProcessor.test.ts +++ b/plugins/catalog-backend/src/modules/core/UrlReaderProcessor.test.ts @@ -15,7 +15,10 @@ */ import { UrlReader, UrlReaders } from '@backstage/backend-common'; -import { mockServices, setupMswHandlers } from '@backstage/backend-test-utils'; +import { + mockServices, + registerMswTestHooks, +} from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; @@ -36,7 +39,7 @@ describe('UrlReaderProcessor', () => { set: jest.fn(), }; const server = setupServer(); - setupMswHandlers(server); + registerMswTestHooks(server); beforeEach(() => { jest.resetAllMocks(); diff --git a/plugins/catalog-backend/src/search/DefaultCatalogCollator.test.ts b/plugins/catalog-backend/src/search/DefaultCatalogCollator.test.ts index 8dc22f6ea0..aee65bd2e1 100644 --- a/plugins/catalog-backend/src/search/DefaultCatalogCollator.test.ts +++ b/plugins/catalog-backend/src/search/DefaultCatalogCollator.test.ts @@ -18,7 +18,7 @@ import { PluginEndpointDiscovery, TokenManager, } from '@backstage/backend-common'; -import { setupMswHandlers } from '@backstage/backend-test-utils'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { Entity } from '@backstage/catalog-model'; import { DefaultCatalogCollator } from './DefaultCatalogCollator'; import { setupServer } from 'msw/node'; @@ -62,7 +62,7 @@ describe('DefaultCatalogCollator', () => { let mockTokenManager: jest.Mocked; let collator: DefaultCatalogCollator; - setupMswHandlers(server); + registerMswTestHooks(server); beforeAll(() => { mockDiscoveryApi = { getBaseUrl: jest.fn().mockResolvedValue('http://localhost:7007'), diff --git a/plugins/catalog-import/src/api/AzureRepoApiClient.test.ts b/plugins/catalog-import/src/api/AzureRepoApiClient.test.ts index 65ef2c035e..9f058dc744 100644 --- a/plugins/catalog-import/src/api/AzureRepoApiClient.test.ts +++ b/plugins/catalog-import/src/api/AzureRepoApiClient.test.ts @@ -26,7 +26,7 @@ import { RepoApiClient, } from './AzureRepoApiClient'; import { setupServer } from 'msw/node'; -import { setupMswHandlers } from '@backstage/test-utils'; +import { registerMswTestHooks } from '@backstage/test-utils'; function mockRepoEndpoint() { return rest.get( @@ -153,7 +153,7 @@ function mockPrEndpoint() { describe('RepoApiClient', () => { const server = setupServer(); - setupMswHandlers(server); + registerMswTestHooks(server); const testToken = new Date().toString(); const sut = new RepoApiClient({ project: 'project', diff --git a/plugins/catalog-import/src/api/CatalogImportClient.test.ts b/plugins/catalog-import/src/api/CatalogImportClient.test.ts index 67a019cc1b..fa646e3ca4 100644 --- a/plugins/catalog-import/src/api/CatalogImportClient.test.ts +++ b/plugins/catalog-import/src/api/CatalogImportClient.test.ts @@ -57,7 +57,7 @@ import { ConfigReader, UrlPatternDiscovery } from '@backstage/core-app-api'; import { ScmIntegrations } from '@backstage/integration'; import { ScmAuthApi } from '@backstage/integration-react'; import { CatalogApi } from '@backstage/plugin-catalog-react'; -import { MockFetchApi, setupMswHandlers } from '@backstage/test-utils'; +import { MockFetchApi, registerMswTestHooks } from '@backstage/test-utils'; import { Octokit } from '@octokit/rest'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; @@ -70,7 +70,7 @@ import { describe('CatalogImportClient', () => { const server = setupServer(); - setupMswHandlers(server); + registerMswTestHooks(server); const mockBaseUrl = 'http://backstage:9191/api/catalog'; const discoveryApi = UrlPatternDiscovery.compile(mockBaseUrl); diff --git a/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts b/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts index 7b61a22009..5edb8845d4 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts @@ -38,7 +38,7 @@ import { ServiceMock, mockCredentials, mockServices, - setupMswHandlers, + registerMswTestHooks, startTestBackend, } from '@backstage/backend-test-utils'; import { rest } from 'msw'; @@ -508,7 +508,7 @@ describe('API integration tests', () => { describe('/proxy', () => { const worker = setupServer(); - setupMswHandlers(worker); + registerMswTestHooks(worker); beforeEach(() => { worker.use( diff --git a/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.test.ts b/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.test.ts index 7a2aba2977..3491268d39 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.test.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.test.ts @@ -26,7 +26,10 @@ import { KubernetesFanOutHandler } from './KubernetesFanOutHandler'; import { KubernetesClientBasedFetcher } from './KubernetesFetcher'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; -import { mockServices, setupMswHandlers } from '@backstage/backend-test-utils'; +import { + mockServices, + registerMswTestHooks, +} from '@backstage/backend-test-utils'; import { FetchResponse, KubernetesRequestAuth, @@ -1125,7 +1128,7 @@ describe('KubernetesFanOutHandler', () => { describe('with a real fetcher', () => { const worker = setupServer(); - setupMswHandlers(worker); + registerMswTestHooks(worker); it('fetch error short-circuits requests to a single cluster, recovering across the fleet', async () => { const pods = [{ metadata: { name: 'pod-name' } }]; diff --git a/plugins/kubernetes-backend/src/service/KubernetesFetcher.test.ts b/plugins/kubernetes-backend/src/service/KubernetesFetcher.test.ts index e7196d9dc6..8666e0ef16 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesFetcher.test.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesFetcher.test.ts @@ -28,7 +28,7 @@ import { setupServer } from 'msw/node'; import { createMockDirectory, mockServices, - setupMswHandlers, + registerMswTestHooks, } from '@backstage/backend-test-utils'; import { Config } from '@kubernetes/client-node'; @@ -71,7 +71,7 @@ const POD_METRICS_FIXTURE = [ describe('KubernetesFetcher', () => { const worker = setupServer(); - setupMswHandlers(worker); + registerMswTestHooks(worker); const labels = (req: MockedRequest): object => { const selectorParam = req.url.searchParams.get('labelSelector'); diff --git a/plugins/kubernetes-backend/src/service/KubernetesProxy.test.ts b/plugins/kubernetes-backend/src/service/KubernetesProxy.test.ts index 45a131439b..fe4feaee11 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesProxy.test.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesProxy.test.ts @@ -20,7 +20,7 @@ import { errorHandler } from '@backstage/backend-common'; import { createMockDirectory, mockServices, - setupMswHandlers, + registerMswTestHooks, } from '@backstage/backend-test-utils'; import { NotFoundError } from '@backstage/errors'; import { @@ -90,7 +90,7 @@ describe('KubernetesProxy', () => { getExternalBaseUrl: jest.fn(), }; - setupMswHandlers(worker); + registerMswTestHooks(worker); const buildMockRequest = (clusterName: any, path: string): Request => { const req = getMockReq({ diff --git a/plugins/kubernetes-node/src/auth/PinnipedHelper.test.ts b/plugins/kubernetes-node/src/auth/PinnipedHelper.test.ts index f882d2373c..24cd459fde 100644 --- a/plugins/kubernetes-node/src/auth/PinnipedHelper.test.ts +++ b/plugins/kubernetes-node/src/auth/PinnipedHelper.test.ts @@ -18,7 +18,7 @@ import { ExtendedHttpServer } from '@backstage/backend-app-api'; import { ClusterDetails } from '../types'; import { mockServices, - setupMswHandlers, + registerMswTestHooks, startTestBackend, } from '@backstage/backend-test-utils'; import { createBackendModule } from '@backstage/backend-plugin-api'; @@ -43,7 +43,7 @@ describe('Pinniped - tokenCredentialRequest', () => { const logger = loggerToWinstonLogger(mockServices.logger.mock()); let httpsRequest: jest.SpyInstance; const worker = setupServer(); - setupMswHandlers(worker); + registerMswTestHooks(worker); beforeAll(() => { httpsRequest = jest.spyOn( diff --git a/plugins/kubernetes-react/src/api/KubernetesBackendClient.test.ts b/plugins/kubernetes-react/src/api/KubernetesBackendClient.test.ts index eecaed20b6..4698f01dfe 100644 --- a/plugins/kubernetes-react/src/api/KubernetesBackendClient.test.ts +++ b/plugins/kubernetes-react/src/api/KubernetesBackendClient.test.ts @@ -19,7 +19,7 @@ import { KubernetesBackendClient } from './KubernetesBackendClient'; import { rest } from 'msw'; import { UrlPatternDiscovery } from '@backstage/core-app-api'; import { setupServer } from 'msw/node'; -import { MockFetchApi, setupMswHandlers } from '@backstage/test-utils'; +import { MockFetchApi, registerMswTestHooks } from '@backstage/test-utils'; import { CustomObjectsByEntityRequest, KubernetesRequestBody, @@ -36,7 +36,7 @@ describe('KubernetesBackendClient', () => { }; let mockResponse: ObjectsByEntityResponse; const worker = setupServer(); - setupMswHandlers(worker); + registerMswTestHooks(worker); const identityApi = { getCredentials: jest.fn(), diff --git a/plugins/notifications-node/src/service/DefaultNotificationService.test.ts b/plugins/notifications-node/src/service/DefaultNotificationService.test.ts index 843852af21..3872f898ee 100644 --- a/plugins/notifications-node/src/service/DefaultNotificationService.test.ts +++ b/plugins/notifications-node/src/service/DefaultNotificationService.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { setupMswHandlers } from '@backstage/test-utils'; +import { registerMswTestHooks } from '@backstage/test-utils'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { NotificationPayload } from '@backstage/plugin-notifications-common'; @@ -32,7 +32,7 @@ const testNotification: NotificationPayload = { describe('DefaultNotificationService', () => { const server = setupServer(); - setupMswHandlers(server); + registerMswTestHooks(server); const discovery = mockServices.discovery.mock({ getBaseUrl: jest.fn().mockResolvedValue('http://example.com'), diff --git a/plugins/notifications/src/api/NotificationsClient.test.ts b/plugins/notifications/src/api/NotificationsClient.test.ts index b4be073738..f378269e45 100644 --- a/plugins/notifications/src/api/NotificationsClient.test.ts +++ b/plugins/notifications/src/api/NotificationsClient.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { MockFetchApi, setupMswHandlers } from '@backstage/test-utils'; +import { MockFetchApi, registerMswTestHooks } from '@backstage/test-utils'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { NotificationsClient } from './NotificationsClient'; @@ -33,7 +33,7 @@ const testNotification: Partial = { }; describe('NotificationsClient', () => { - setupMswHandlers(server); + registerMswTestHooks(server); const mockBaseUrl = 'http://backstage/api/notifications'; const discoveryApi = { getBaseUrl: async () => mockBaseUrl }; const fetchApi = new MockFetchApi(); diff --git a/plugins/permission-node/src/ServerPermissionClient.test.ts b/plugins/permission-node/src/ServerPermissionClient.test.ts index b09c25eeb7..529b0db907 100644 --- a/plugins/permission-node/src/ServerPermissionClient.test.ts +++ b/plugins/permission-node/src/ServerPermissionClient.test.ts @@ -25,7 +25,7 @@ import { import { mockCredentials, mockServices, - setupMswHandlers, + registerMswTestHooks, } from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; import { setupServer } from 'msw/node'; @@ -54,7 +54,7 @@ const config = new ConfigReader({ }); describe('ServerPermissionClient', () => { - setupMswHandlers(server); + registerMswTestHooks(server); const discovery = mockServices.discovery.mock(); diff --git a/plugins/proxy-backend/src/service/router.config.test.ts b/plugins/proxy-backend/src/service/router.config.test.ts index 3f11faea46..be26ddb9bc 100644 --- a/plugins/proxy-backend/src/service/router.config.test.ts +++ b/plugins/proxy-backend/src/service/router.config.test.ts @@ -19,7 +19,7 @@ import { createServiceFactory, } from '@backstage/backend-plugin-api'; import { - setupMswHandlers, + registerMswTestHooks, startTestBackend, } from '@backstage/backend-test-utils'; import { @@ -36,7 +36,7 @@ import fetch from 'node-fetch'; describe('createRouter reloadable configuration', () => { const server = setupServer(); - setupMswHandlers(server); + registerMswTestHooks(server); it('should be able to observe the config', async () => { // Grab the subscriber function and use mutable config data to mock a config file change diff --git a/plugins/proxy-backend/src/service/router.credentials.test.ts b/plugins/proxy-backend/src/service/router.credentials.test.ts index aede6bb353..ac32179ef3 100644 --- a/plugins/proxy-backend/src/service/router.credentials.test.ts +++ b/plugins/proxy-backend/src/service/router.credentials.test.ts @@ -20,7 +20,7 @@ import { } from '@backstage/backend-app-api'; import { mockServices, - setupMswHandlers, + registerMswTestHooks, startTestBackend, } from '@backstage/backend-test-utils'; import { ResponseError } from '@backstage/errors'; @@ -34,7 +34,7 @@ import fetch from 'node-fetch'; describe('credentials', () => { const worker = setupServer(); - setupMswHandlers(worker); + registerMswTestHooks(worker); it('handles all valid credentials settings', async () => { const config = { diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloud.examples.test.ts b/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloud.examples.test.ts index ef745fbd18..6b4b77879e 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloud.examples.test.ts +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloud.examples.test.ts @@ -29,7 +29,7 @@ jest.mock('@backstage/plugin-scaffolder-node', () => { import { createPublishBitbucketCloudAction } from './bitbucketCloud'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; -import { setupMswHandlers } from '@backstage/backend-test-utils'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { ScmIntegrations } from '@backstage/integration'; import { ConfigReader } from '@backstage/config'; import { initRepoAndPush } from '@backstage/plugin-scaffolder-node'; @@ -66,7 +66,7 @@ describe('publish:bitbucketCloud', () => { }, }); const server = setupServer(); - setupMswHandlers(server); + registerMswTestHooks(server); beforeEach(() => { jest.resetAllMocks(); diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloud.test.ts b/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloud.test.ts index 57215ac06d..6cac8a0e1c 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloud.test.ts +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloud.test.ts @@ -29,7 +29,7 @@ jest.mock('@backstage/plugin-scaffolder-node', () => { import { createPublishBitbucketCloudAction } from './bitbucketCloud'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; -import { setupMswHandlers } from '@backstage/backend-test-utils'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { ScmIntegrations } from '@backstage/integration'; import { ConfigReader } from '@backstage/config'; import { initRepoAndPush } from '@backstage/plugin-scaffolder-node'; @@ -56,7 +56,7 @@ describe('publish:bitbucketCloud', () => { }, }); const server = setupServer(); - setupMswHandlers(server); + registerMswTestHooks(server); beforeEach(() => { jest.resetAllMocks(); diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudPipelinesRun.examples.test.ts b/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudPipelinesRun.examples.test.ts index 6a4f82066e..3e306c4065 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudPipelinesRun.examples.test.ts +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudPipelinesRun.examples.test.ts @@ -21,7 +21,7 @@ import yaml from 'yaml'; import { examples } from './bitbucketCloudPipelinesRun.examples'; import { ConfigReader } from '@backstage/config'; import { ScmIntegrations } from '@backstage/integration'; -import { setupMswHandlers } from '@backstage/backend-test-utils'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test-utils'; describe('bitbucket:pipelines:run', () => { @@ -48,7 +48,7 @@ describe('bitbucket:pipelines:run', () => { build_number: 1, }; const worker = setupServer(); - setupMswHandlers(worker); + registerMswTestHooks(worker); beforeEach(() => { jest.resetAllMocks(); diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudPipelinesRun.test.ts b/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudPipelinesRun.test.ts index be8500895a..edabe2a7ba 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudPipelinesRun.test.ts +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudPipelinesRun.test.ts @@ -16,7 +16,7 @@ import { rest } from 'msw'; import { setupServer } from 'msw/node'; -import { setupMswHandlers } from '@backstage/backend-test-utils'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { createBitbucketPipelinesRunAction } from './bitbucketCloudPipelinesRun'; import { ConfigReader } from '@backstage/config'; import { ScmIntegrations } from '@backstage/integration'; @@ -48,7 +48,7 @@ describe('bitbucket:pipelines:run', () => { build_number: 1, }; const worker = setupServer(); - setupMswHandlers(worker); + registerMswTestHooks(worker); beforeEach(() => { jest.clearAllMocks(); diff --git a/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServer.examples.test.ts b/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServer.examples.test.ts index 8e6356df18..101379d1e6 100644 --- a/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServer.examples.test.ts +++ b/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServer.examples.test.ts @@ -29,7 +29,7 @@ jest.mock('@backstage/plugin-scaffolder-node', () => { import { createPublishBitbucketServerAction } from './bitbucketServer'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; -import { setupMswHandlers } from '@backstage/backend-test-utils'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { ScmIntegrations } from '@backstage/integration'; import { ConfigReader } from '@backstage/config'; import yaml from 'yaml'; @@ -68,7 +68,7 @@ describe('publish:bitbucketServer', () => { }, }); const server = setupServer(); - setupMswHandlers(server); + registerMswTestHooks(server); beforeEach(() => { jest.resetAllMocks(); diff --git a/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServer.test.ts b/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServer.test.ts index fb7d17c0ba..250b3f9b54 100644 --- a/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServer.test.ts +++ b/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServer.test.ts @@ -29,7 +29,7 @@ jest.mock('@backstage/plugin-scaffolder-node', () => { import { createPublishBitbucketServerAction } from './bitbucketServer'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; -import { setupMswHandlers } from '@backstage/backend-test-utils'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { ScmIntegrations } from '@backstage/integration'; import { ConfigReader } from '@backstage/config'; import { initRepoAndPush } from '@backstage/plugin-scaffolder-node'; @@ -66,7 +66,7 @@ describe('publish:bitbucketServer', () => { }, }); const server = setupServer(); - setupMswHandlers(server); + registerMswTestHooks(server); beforeEach(() => { jest.resetAllMocks(); diff --git a/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServerPullRequest.examples.test.ts b/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServerPullRequest.examples.test.ts index 0bc6d1464b..b83ba2be55 100644 --- a/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServerPullRequest.examples.test.ts +++ b/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServerPullRequest.examples.test.ts @@ -29,7 +29,7 @@ jest.mock('@backstage/plugin-scaffolder-node', () => { import { createPublishBitbucketServerPullRequestAction } from './bitbucketServerPullRequest'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; -import { setupMswHandlers } from '@backstage/backend-test-utils'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { ScmIntegrations } from '@backstage/integration'; import { ConfigReader } from '@backstage/config'; import yaml from 'yaml'; @@ -191,7 +191,7 @@ describe('publish:bitbucketServer:pull-request', () => { }; const server = setupServer(); - setupMswHandlers(server); + registerMswTestHooks(server); beforeEach(() => { jest.resetAllMocks(); diff --git a/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServerPullRequest.test.ts b/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServerPullRequest.test.ts index 61adf0e3c8..37df535fec 100644 --- a/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServerPullRequest.test.ts +++ b/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServerPullRequest.test.ts @@ -29,7 +29,7 @@ jest.mock('@backstage/plugin-scaffolder-node', () => { import { createPublishBitbucketServerPullRequestAction } from './bitbucketServerPullRequest'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { ScmIntegrations } from '@backstage/integration'; import { ConfigReader } from '@backstage/config'; import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test-utils'; @@ -221,7 +221,7 @@ describe('publish:bitbucketServer:pull-request', () => { ]; const server = setupServer(); - setupRequestMockHandlers(server); + registerMswTestHooks(server); beforeEach(() => { jest.resetAllMocks(); diff --git a/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucket.examples.test.ts b/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucket.examples.test.ts index 964b2f207c..d452f2e11f 100644 --- a/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucket.examples.test.ts +++ b/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucket.examples.test.ts @@ -29,7 +29,7 @@ jest.mock('@backstage/plugin-scaffolder-node', () => { import { createPublishBitbucketAction } from './bitbucket'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; -import { setupMswHandlers } from '@backstage/backend-test-utils'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { ScmIntegrations } from '@backstage/integration'; import { ConfigReader } from '@backstage/config'; import { initRepoAndPush } from '@backstage/plugin-scaffolder-node'; @@ -67,7 +67,7 @@ describe('publish:bitbucket', () => { }, }); const server = setupServer(); - setupMswHandlers(server); + registerMswTestHooks(server); beforeEach(() => { jest.resetAllMocks(); diff --git a/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucket.test.ts b/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucket.test.ts index dddbcde828..654b0fffcb 100644 --- a/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucket.test.ts +++ b/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucket.test.ts @@ -28,7 +28,7 @@ jest.mock('@backstage/plugin-scaffolder-node', () => { import { createPublishBitbucketAction } from './bitbucket'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; -import { setupMswHandlers } from '@backstage/backend-test-utils'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { ScmIntegrations } from '@backstage/integration'; import { ConfigReader } from '@backstage/config'; import { initRepoAndPush } from '@backstage/plugin-scaffolder-node'; @@ -63,7 +63,7 @@ describe('publish:bitbucket', () => { }, }); const server = setupServer(); - setupMswHandlers(server); + registerMswTestHooks(server); beforeEach(() => { jest.resetAllMocks(); diff --git a/plugins/scaffolder-backend-module-confluence-to-markdown/src/actions/confluence/confluenceToMarkdown.examples.test.ts b/plugins/scaffolder-backend-module-confluence-to-markdown/src/actions/confluence/confluenceToMarkdown.examples.test.ts index 3aff044b89..36ae750723 100644 --- a/plugins/scaffolder-backend-module-confluence-to-markdown/src/actions/confluence/confluenceToMarkdown.examples.test.ts +++ b/plugins/scaffolder-backend-module-confluence-to-markdown/src/actions/confluence/confluenceToMarkdown.examples.test.ts @@ -20,7 +20,7 @@ import { ScmIntegrations } from '@backstage/integration'; import { createMockDirectory, mockServices, - setupMswHandlers, + registerMswTestHooks, } from '@backstage/backend-test-utils'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; @@ -32,7 +32,7 @@ import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test- describe('confluence:transform:markdown examples', () => { const baseUrl = `https://confluence.example.com`; const worker = setupServer(); - setupMswHandlers(worker); + registerMswTestHooks(worker); const config = new ConfigReader({ confluence: { diff --git a/plugins/scaffolder-backend-module-confluence-to-markdown/src/actions/confluence/confluenceToMarkdown.test.ts b/plugins/scaffolder-backend-module-confluence-to-markdown/src/actions/confluence/confluenceToMarkdown.test.ts index 5958f1407b..4c3c6b891f 100644 --- a/plugins/scaffolder-backend-module-confluence-to-markdown/src/actions/confluence/confluenceToMarkdown.test.ts +++ b/plugins/scaffolder-backend-module-confluence-to-markdown/src/actions/confluence/confluenceToMarkdown.test.ts @@ -21,7 +21,7 @@ import { ScmIntegrations } from '@backstage/integration'; import { createMockDirectory, mockServices, - setupMswHandlers, + registerMswTestHooks, } from '@backstage/backend-test-utils'; import type { ActionContext } from '@backstage/plugin-scaffolder-node'; import { rest } from 'msw'; @@ -31,7 +31,7 @@ import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test- describe('confluence:transform:markdown', () => { const baseUrl = `https://nodomain.confluence.com`; const worker = setupServer(); - setupMswHandlers(worker); + registerMswTestHooks(worker); const config = new ConfigReader({ confluence: { diff --git a/plugins/scaffolder-backend-module-gerrit/src/actions/gerrit.test.ts b/plugins/scaffolder-backend-module-gerrit/src/actions/gerrit.test.ts index b91cc2d84d..c102353209 100644 --- a/plugins/scaffolder-backend-module-gerrit/src/actions/gerrit.test.ts +++ b/plugins/scaffolder-backend-module-gerrit/src/actions/gerrit.test.ts @@ -30,7 +30,7 @@ import path from 'path'; import { createPublishGerritAction } from './gerrit'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; -import { setupMswHandlers } from '@backstage/backend-test-utils'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { ScmIntegrations } from '@backstage/integration'; import { ConfigReader } from '@backstage/config'; import { initRepoAndPush } from '@backstage/plugin-scaffolder-node'; @@ -61,7 +61,7 @@ describe('publish:gerrit', () => { }, }); const server = setupServer(); - setupMswHandlers(server); + registerMswTestHooks(server); beforeEach(() => { jest.resetAllMocks(); diff --git a/plugins/scaffolder-backend-module-gitea/src/actions/gitea.test.ts b/plugins/scaffolder-backend-module-gitea/src/actions/gitea.test.ts index ab4d4641d0..7812ded60a 100644 --- a/plugins/scaffolder-backend-module-gitea/src/actions/gitea.test.ts +++ b/plugins/scaffolder-backend-module-gitea/src/actions/gitea.test.ts @@ -18,7 +18,7 @@ import { ConfigReader } from '@backstage/config'; import { createPublishGiteaAction } from './gitea'; import { initRepoAndPush } from '@backstage/plugin-scaffolder-node'; import { rest } from 'msw'; -import { setupMswHandlers } from '@backstage/backend-test-utils'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test-utils'; import { setupServer } from 'msw/node'; @@ -62,7 +62,7 @@ describe('publish:gitea', () => { }); const server = setupServer(); - setupMswHandlers(server); + registerMswTestHooks(server); beforeEach(() => { jest.resetAllMocks(); 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 9eef522ddc..48c437d2a4 100644 --- a/plugins/scaffolder-backend-module-sentry/src/actions/createProject.test.ts +++ b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { setupMswHandlers } from '@backstage/backend-test-utils'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test-utils'; import { ConfigReader } from '@backstage/config'; import { InputError } from '@backstage/errors'; @@ -27,7 +27,7 @@ import { createSentryCreateProjectAction } from './createProject'; describe('sentry:project:create action', () => { const worker = setupServer(); - setupMswHandlers(worker); + registerMswTestHooks(worker); const createScaffolderConfig = (configData: JsonObject = {}) => ({ config: new ConfigReader({ diff --git a/plugins/scaffolder/src/api.test.ts b/plugins/scaffolder/src/api.test.ts index 1da440ab7b..805828a9fe 100644 --- a/plugins/scaffolder/src/api.test.ts +++ b/plugins/scaffolder/src/api.test.ts @@ -16,7 +16,7 @@ import { ConfigReader } from '@backstage/core-app-api'; import { ScmIntegrations } from '@backstage/integration'; -import { MockFetchApi, setupMswHandlers } from '@backstage/test-utils'; +import { MockFetchApi, registerMswTestHooks } from '@backstage/test-utils'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { ScaffolderClient } from './api'; @@ -30,7 +30,7 @@ const mockFetchEventSource = fetchEventSource as jest.MockedFunction< const server = setupServer(); describe('api', () => { - setupMswHandlers(server); + registerMswTestHooks(server); const mockBaseUrl = 'http://backstage/api'; const discoveryApi = { getBaseUrl: async () => mockBaseUrl }; diff --git a/plugins/search-backend-module-catalog/src/collators/DefaultCatalogCollatorFactory.test.ts b/plugins/search-backend-module-catalog/src/collators/DefaultCatalogCollatorFactory.test.ts index 0d9320f3dd..4bdb8a5ae9 100644 --- a/plugins/search-backend-module-catalog/src/collators/DefaultCatalogCollatorFactory.test.ts +++ b/plugins/search-backend-module-catalog/src/collators/DefaultCatalogCollatorFactory.test.ts @@ -18,7 +18,7 @@ import { PluginEndpointDiscovery, TokenManager, } from '@backstage/backend-common'; -import { setupMswHandlers } from '@backstage/backend-test-utils'; +import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { Entity } from '@backstage/catalog-model'; import { ConfigReader } from '@backstage/config'; import { TestPipeline } from '@backstage/plugin-search-backend-node'; @@ -74,7 +74,7 @@ describe('DefaultCatalogCollatorFactory', () => { tokenManager: mockTokenManager, }; - setupMswHandlers(server); + registerMswTestHooks(server); beforeEach(() => { server.use( diff --git a/plugins/search-backend-module-explore/src/collators/ToolDocumentCollatorFactory.test.ts b/plugins/search-backend-module-explore/src/collators/ToolDocumentCollatorFactory.test.ts index e69b48b1c3..82f5cffbc0 100644 --- a/plugins/search-backend-module-explore/src/collators/ToolDocumentCollatorFactory.test.ts +++ b/plugins/search-backend-module-explore/src/collators/ToolDocumentCollatorFactory.test.ts @@ -19,7 +19,10 @@ import { } from '@backstage/backend-common'; import { ConfigReader } from '@backstage/config'; import { TestPipeline } from '@backstage/plugin-search-backend-node'; -import { mockServices, setupMswHandlers } from '@backstage/backend-test-utils'; +import { + mockServices, + registerMswTestHooks, +} from '@backstage/backend-test-utils'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { Readable } from 'stream'; @@ -79,7 +82,7 @@ describe('ToolDocumentCollatorFactory', () => { let collator: Readable; const worker = setupServer(); - setupMswHandlers(worker); + registerMswTestHooks(worker); beforeEach(async () => { factory = ToolDocumentCollatorFactory.fromConfig(config, options); diff --git a/plugins/search-backend-module-stack-overflow-collator/src/collators/StackOverflowQuestionsCollatorFactory.test.ts b/plugins/search-backend-module-stack-overflow-collator/src/collators/StackOverflowQuestionsCollatorFactory.test.ts index 3698f7c8f6..90b324866f 100644 --- a/plugins/search-backend-module-stack-overflow-collator/src/collators/StackOverflowQuestionsCollatorFactory.test.ts +++ b/plugins/search-backend-module-stack-overflow-collator/src/collators/StackOverflowQuestionsCollatorFactory.test.ts @@ -17,7 +17,10 @@ import { StackOverflowQuestionsCollatorFactory, StackOverflowQuestionsCollatorFactoryOptions, } from './StackOverflowQuestionsCollatorFactory'; -import { mockServices, setupMswHandlers } from '@backstage/backend-test-utils'; +import { + mockServices, + registerMswTestHooks, +} from '@backstage/backend-test-utils'; import { TestPipeline } from '@backstage/plugin-search-backend-node'; import { ConfigReader } from '@backstage/config'; import { Readable } from 'stream'; @@ -92,7 +95,7 @@ describe('StackOverflowQuestionsCollatorFactory', () => { describe('getCollator', () => { const worker = setupServer(); - setupMswHandlers(worker); + registerMswTestHooks(worker); it('returns a readable stream', async () => { const factory = StackOverflowQuestionsCollatorFactory.fromConfig( diff --git a/plugins/search-backend-module-techdocs/src/collators/DefaultTechDocsCollatorFactory.test.ts b/plugins/search-backend-module-techdocs/src/collators/DefaultTechDocsCollatorFactory.test.ts index a2e8cc9992..476c07ff48 100644 --- a/plugins/search-backend-module-techdocs/src/collators/DefaultTechDocsCollatorFactory.test.ts +++ b/plugins/search-backend-module-techdocs/src/collators/DefaultTechDocsCollatorFactory.test.ts @@ -20,7 +20,10 @@ import { import { Entity } from '@backstage/catalog-model'; import { ConfigReader } from '@backstage/config'; import { TestPipeline } from '@backstage/plugin-search-backend-node'; -import { mockServices, setupMswHandlers } from '@backstage/backend-test-utils'; +import { + mockServices, + registerMswTestHooks, +} from '@backstage/backend-test-utils'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { Readable } from 'stream'; @@ -103,7 +106,7 @@ describe('DefaultTechDocsCollatorFactory', () => { let collator: Readable; const worker = setupServer(); - setupMswHandlers(worker); + registerMswTestHooks(worker); beforeEach(async () => { factory = DefaultTechDocsCollatorFactory.fromConfig(config, options); diff --git a/plugins/techdocs-backend/src/search/DefaultTechDocsCollator.test.ts b/plugins/techdocs-backend/src/search/DefaultTechDocsCollator.test.ts index 47245dc6fc..64b0917202 100644 --- a/plugins/techdocs-backend/src/search/DefaultTechDocsCollator.test.ts +++ b/plugins/techdocs-backend/src/search/DefaultTechDocsCollator.test.ts @@ -21,7 +21,10 @@ import { } from '@backstage/backend-common'; import { Entity } from '@backstage/catalog-model'; import { DefaultTechDocsCollator } from './DefaultTechDocsCollator'; -import { mockServices, setupMswHandlers } from '@backstage/backend-test-utils'; +import { + mockServices, + registerMswTestHooks, +} from '@backstage/backend-test-utils'; import { setupServer } from 'msw/node'; import { rest } from 'msw'; import { ConfigReader } from '@backstage/config'; @@ -76,7 +79,7 @@ const expectedEntities: Entity[] = [ describe('TechDocs Collator', () => { const worker = setupServer(); - setupMswHandlers(worker); + registerMswTestHooks(worker); describe('DefaultTechDocsCollator with legacyPathCasing configuration', () => { let mockDiscoveryApi: jest.Mocked; diff --git a/plugins/user-settings/src/apis/StorageApi/UserSettingsStorage.test.ts b/plugins/user-settings/src/apis/StorageApi/UserSettingsStorage.test.ts index 6ee6a3df2f..6bb0035b83 100644 --- a/plugins/user-settings/src/apis/StorageApi/UserSettingsStorage.test.ts +++ b/plugins/user-settings/src/apis/StorageApi/UserSettingsStorage.test.ts @@ -21,14 +21,14 @@ import { IdentityApi, StorageApi, } from '@backstage/core-plugin-api'; -import { MockFetchApi, setupMswHandlers } from '@backstage/test-utils'; +import { MockFetchApi, registerMswTestHooks } from '@backstage/test-utils'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { UserSettingsStorage } from './UserSettingsStorage'; describe('Persistent Storage API', () => { const server = setupServer(); - setupMswHandlers(server); + registerMswTestHooks(server); const mockBaseUrl = 'http://backstage:9191/api'; const mockErrorApi = { post: jest.fn(), error$: jest.fn() }; From ccfc9d12c11db4d5a64d551a56bda686cd036346 Mon Sep 17 00:00:00 2001 From: Mccaskey Skye Date: Wed, 10 Jul 2024 12:57:23 -0500 Subject: [PATCH 216/416] fix: Added owner and repo args to getEnvironmentPublicKey Signed-off-by: Mccaskey Skye --- .changeset/early-deers-beg.md | 16 ++++++++++++++++ .../src/actions/githubEnvironment.test.ts | 11 +++++++++++ .../src/actions/githubEnvironment.ts | 2 ++ 3 files changed, 29 insertions(+) create mode 100644 .changeset/early-deers-beg.md diff --git a/.changeset/early-deers-beg.md b/.changeset/early-deers-beg.md new file mode 100644 index 0000000000..2814273afa --- /dev/null +++ b/.changeset/early-deers-beg.md @@ -0,0 +1,16 @@ +--- +'@backstage/plugin-scaffolder-backend-module-github': patch +--- + +Fixed bug resulting from missing required owner and repo arguments in `octokit getEnvironmentPublicKey in action `github:environment:create`. + +Adding environment secrets now works as expected. + +```diff + const publicKeyResponse = await client.rest.actions.getEnvironmentPublicKey({ + repository_id: repository.data.id, ++ owner, ++ repo, + environment_name: name + }); +``` diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.test.ts b/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.test.ts index c4eae41029..139d8028eb 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.test.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.test.ts @@ -304,5 +304,16 @@ describe('github:environment:create', () => { key_id: 'keyid', encrypted_value: expect.any(String), }); + expect( + mockOctokit.rest.actions.getEnvironmentPublicKey, + ).toHaveBeenCalledTimes(1); + expect( + mockOctokit.rest.actions.getEnvironmentPublicKey, + ).toHaveBeenCalledWith({ + repository_id: 'repoid', + owner: 'owner', + repo: 'repository', + environment_name: 'envname', + }); }); }); diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.ts b/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.ts index 98e7cea1a9..d3e8d0e5d2 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.ts @@ -199,6 +199,8 @@ export function createGithubEnvironmentAction(options: { const publicKeyResponse = await client.rest.actions.getEnvironmentPublicKey({ repository_id: repository.data.id, + owner: owner, + repo: repo, environment_name: name, }); From a7d9216e505d7ee8c4b397bbd3810633ab174a14 Mon Sep 17 00:00:00 2001 From: Mccaskey Skye Date: Wed, 10 Jul 2024 13:38:35 -0500 Subject: [PATCH 217/416] Update early-deers-beg.md Signed-off-by: Mccaskey Skye --- .changeset/early-deers-beg.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/early-deers-beg.md b/.changeset/early-deers-beg.md index 2814273afa..4bac074d8c 100644 --- a/.changeset/early-deers-beg.md +++ b/.changeset/early-deers-beg.md @@ -2,7 +2,7 @@ '@backstage/plugin-scaffolder-backend-module-github': patch --- -Fixed bug resulting from missing required owner and repo arguments in `octokit getEnvironmentPublicKey in action `github:environment:create`. +Fixed bug resulting from missing required owner and repo arguments in `getEnvironmentPublicKey` in action `github:environment:create`. Adding environment secrets now works as expected. From e149572b1a5a2dbe49225a5b5589b52f4172d32d Mon Sep 17 00:00:00 2001 From: CasperJ Date: Wed, 10 Jul 2024 21:03:43 +0200 Subject: [PATCH 218/416] Update .changeset/dirty-wasps-do.md Co-authored-by: Andre Wanlin <67169551+awanlin@users.noreply.github.com> Signed-off-by: CasperJ --- .changeset/dirty-wasps-do.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/dirty-wasps-do.md b/.changeset/dirty-wasps-do.md index fbf6799baf..f8b4e614eb 100644 --- a/.changeset/dirty-wasps-do.md +++ b/.changeset/dirty-wasps-do.md @@ -2,4 +2,4 @@ '@backstage/plugin-scaffolder-backend': patch --- -Catalog:Write scaffolder action shows incorrect log message +Updated `catalog:write` scaffolder action to show correct file path location in log message From bebd569c565516fb411c276bf47b1aef80c5bc9e Mon Sep 17 00:00:00 2001 From: Stephen Glass Date: Wed, 10 Jul 2024 20:44:25 -0400 Subject: [PATCH 219/416] Fix extra divider displayed on user list picker component Signed-off-by: Stephen Glass --- .changeset/pink-gorillas-brake.md | 5 +++++ .../src/components/UserListPicker/UserListPicker.tsx | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 .changeset/pink-gorillas-brake.md diff --git a/.changeset/pink-gorillas-brake.md b/.changeset/pink-gorillas-brake.md new file mode 100644 index 0000000000..188884f13c --- /dev/null +++ b/.changeset/pink-gorillas-brake.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-react': patch +--- + +Fix extra divider displayed on user list picker component diff --git a/plugins/catalog-react/src/components/UserListPicker/UserListPicker.tsx b/plugins/catalog-react/src/components/UserListPicker/UserListPicker.tsx index 7f0ff8be74..c6b515aa67 100644 --- a/plugins/catalog-react/src/components/UserListPicker/UserListPicker.tsx +++ b/plugins/catalog-react/src/components/UserListPicker/UserListPicker.tsx @@ -247,11 +247,11 @@ export const UserListPicker = (props: UserListPickerProps) => { - {group.items.map(item => ( + {group.items.map((item, index) => ( setSelectedUserFilter(item.id)} selected={item.id === filters.user?.value} className={classes.menuItem} From 707eb3989dfd3ddf32dc14564ba06a4649935905 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 11 Jul 2024 10:16:25 +0200 Subject: [PATCH 220/416] Apply suggestions from code review Co-authored-by: Camila Belo Signed-off-by: Patrik Oldsberg --- .changeset/spotty-apricots-tan.md | 2 +- docs/backend-system/architecture/03-services.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.changeset/spotty-apricots-tan.md b/.changeset/spotty-apricots-tan.md index 2b88e3a7f5..8eea2b1dce 100644 --- a/.changeset/spotty-apricots-tan.md +++ b/.changeset/spotty-apricots-tan.md @@ -41,7 +41,7 @@ export class DefaultFooService implements FooService { A user that wishes to customize the service can then easily do so by defining their own factory: ```ts -export const fooServiceFactory = createServiceFactory({ +export const customFooServiceFactory = createServiceFactory({ service: fooServiceRef, deps: { logger: coreServices.logger }, factory({ logger }) { diff --git a/docs/backend-system/architecture/03-services.md b/docs/backend-system/architecture/03-services.md index 7d6824c41e..e1d86164c3 100644 --- a/docs/backend-system/architecture/03-services.md +++ b/docs/backend-system/architecture/03-services.md @@ -192,7 +192,7 @@ When defining a default factory for a service, it is possible for it to end up w ## Service Factory Customization -When declaring a service factory you may also want to make the export the building blocks of the implementation itself. This is to allow for further customization of the service implementation through code, beyond what is possible with static configuration, without the need to re-implement the entire service from scratch. For example, we might export our example `DefaultFooService` class, while moving construction to a static factory method to make it easier to evolve: +When declaring a service factory you may also want to make the export the building blocks of the implementation itself. This is to allow for further customization of the service implementation through code, beyond what is possible with static configuration, without the need to re-implement the entire service from scratch. For example, we might export our example `DefaultFooService` class, while moving construction to a static `create` factory method to make it easier to evolve: ```ts export class DefaultFooService { @@ -222,4 +222,4 @@ export const customFooServiceFactory = createServiceFactory({ }); ``` -This allows lets you provide more advanced options for the service implementation that couldn't be expressed through static configuration. It also gives users of the service implementation access to other services through dependency injection, which can be useful for their customizations. +This allows you to provide more advanced options for the service implementation that couldn't be expressed through static configuration. It also gives users of the service implementation access to other services through dependency injection, which can be useful for their customizations. From 87d3f665f820c3520716a3a0415e6d86552d28a7 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 11 Jul 2024 10:45:18 +0200 Subject: [PATCH 221/416] backend-plugin-api: update deprecation message for ServiceFactoryCompat Signed-off-by: Patrik Oldsberg --- packages/backend-plugin-api/src/services/system/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/backend-plugin-api/src/services/system/types.ts b/packages/backend-plugin-api/src/services/system/types.ts index 9545408ff2..d31350806d 100644 --- a/packages/backend-plugin-api/src/services/system/types.ts +++ b/packages/backend-plugin-api/src/services/system/types.ts @@ -65,7 +65,7 @@ export interface ServiceFactoryCompat< TOpts extends object | undefined = undefined, > extends ServiceFactory { /** - * @deprecated You do not need to use this call signature; use the type directly instead by removing the `()` parentheses at the end. This call signature will be removed in a future release. + * @deprecated Callable service factories will be removed in a future release, please re-implement the service factory using the available APIs instead. If no options are being passed, you can simply remove the trailing `()`. */ ( ...options: undefined extends TOpts ? [] : [options?: TOpts] From 617a7d29c242679b9659ab15944856b85a27a2ca Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 11 Jul 2024 11:18:18 +0200 Subject: [PATCH 222/416] backend-app-api: avoid using service factory options for plugin meta service Signed-off-by: Patrik Oldsberg --- .changeset/nice-cats-nail.md | 5 +++++ .../backend-app-api/src/wiring/ServiceRegistry.ts | 12 ++++++------ 2 files changed, 11 insertions(+), 6 deletions(-) create mode 100644 .changeset/nice-cats-nail.md diff --git a/.changeset/nice-cats-nail.md b/.changeset/nice-cats-nail.md new file mode 100644 index 0000000000..0e9b1603b8 --- /dev/null +++ b/.changeset/nice-cats-nail.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-app-api': patch +--- + +Internal refactor that avoids the use of service factory options. diff --git a/packages/backend-app-api/src/wiring/ServiceRegistry.ts b/packages/backend-app-api/src/wiring/ServiceRegistry.ts index 6e20dd98e8..56d8d611bb 100644 --- a/packages/backend-app-api/src/wiring/ServiceRegistry.ts +++ b/packages/backend-app-api/src/wiring/ServiceRegistry.ts @@ -48,13 +48,13 @@ function toInternalServiceFactory( return f; } -const pluginMetadataServiceFactory = createServiceFactory( - (options?: { pluginId: string }) => ({ +function createPluginMetadataServiceFactory(pluginId: string) { + return createServiceFactory({ service: coreServices.pluginMetadata, deps: {}, - factory: async () => ({ getId: () => options?.pluginId! }), - }), -); + factory: async () => ({ getId: () => pluginId }), + }); +} export class ServiceRegistry { static create(factories: Array): ServiceRegistry { @@ -97,7 +97,7 @@ export class ServiceRegistry { // Special case handling of the plugin metadata service, generating a custom factory for it each time if (ref.id === coreServices.pluginMetadata.id) { return Promise.resolve( - toInternalServiceFactory(pluginMetadataServiceFactory({ pluginId })), + toInternalServiceFactory(createPluginMetadataServiceFactory(pluginId)), ); } From a8bd40162c55b9311438e7fd95b55688c213459a Mon Sep 17 00:00:00 2001 From: MT Lewis Date: Tue, 23 Apr 2024 10:01:22 +0100 Subject: [PATCH 223/416] yarn-plugin: validate version of yarn in yarn plugin Signed-off-by: MT Lewis --- packages/yarn-plugin/package.json | 1 + packages/yarn-plugin/src/index.ts | 13 ++++++++++++- yarn.lock | 1 + 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/packages/yarn-plugin/package.json b/packages/yarn-plugin/package.json index ad42bdba23..fd70dc8600 100644 --- a/packages/yarn-plugin/package.json +++ b/packages/yarn-plugin/package.json @@ -34,6 +34,7 @@ "@backstage/release-manifests": "workspace:^", "@yarnpkg/core": "^4.0.3", "@yarnpkg/fslib": "^3.0.2", + "chalk": "^4.0.0", "semver": "^7.6.0" }, "devDependencies": { diff --git a/packages/yarn-plugin/src/index.ts b/packages/yarn-plugin/src/index.ts index 6c1c805fd8..f548463829 100644 --- a/packages/yarn-plugin/src/index.ts +++ b/packages/yarn-plugin/src/index.ts @@ -21,10 +21,21 @@ * @packageDocumentation */ -import { Plugin } from '@yarnpkg/core'; +import { Plugin, semverUtils, YarnVersion } from '@yarnpkg/core'; +import chalk from 'chalk'; import { beforeWorkspacePacking } from './handlers/beforeWorkspacePacking'; import { BackstageResolver } from './resolver/BackstageResolver'; +if (!semverUtils.satisfiesWithPrereleases(YarnVersion, '^4.1.1')) { + console.error(); + console.error( + `${chalk.bold.red( + 'Unsupported yarn version.', + )}: The Backstage yarn plugin only works with yarn ^4.1.1. Please upgrade yarn, or remove this plugin with "yarn plugin remove @yarnpkg/plugin-backstage".`, + ); + console.error(); +} + /** * @public */ diff --git a/yarn.lock b/yarn.lock index f50727e805..afe89e4263 100644 --- a/yarn.lock +++ b/yarn.lock @@ -44721,6 +44721,7 @@ __metadata: "@yarnpkg/builder": ^4.0.0 "@yarnpkg/core": ^4.0.3 "@yarnpkg/fslib": ^3.0.2 + chalk: ^4.0.0 nodemon: ^3.0.1 semver: ^7.6.0 languageName: unknown From f9e4e22e5f80dbaadca4cc9ab65e334bd9df836c Mon Sep 17 00:00:00 2001 From: MT Lewis Date: Sun, 14 Apr 2024 21:08:08 +0100 Subject: [PATCH 224/416] sync_release-manifest: full yarn install Since we now need to build the yarn-plugin before pushing it to the versions repo for each release, we need a full yarn install in this repo. Signed-off-by: MT Lewis --- .github/workflows/sync_release-manifest.yml | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/.github/workflows/sync_release-manifest.yml b/.github/workflows/sync_release-manifest.yml index db35945550..34bbabcd0b 100644 --- a/.github/workflows/sync_release-manifest.yml +++ b/.github/workflows/sync_release-manifest.yml @@ -12,14 +12,6 @@ jobs: with: egress-policy: audit - # Setup node & install deps before checkout, keeping install quick - - uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 - with: - node-version: 18.x - - name: Install dependencies - # Just the deps for the assemble manifest script - run: npm install semver@7.3.5 fs-extra@10.0.0 @manypkg/get-packages@1.1.1 - - name: Checkout uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 with: @@ -27,6 +19,18 @@ jobs: # 'v' prefix is added here for the tag, we keep it out of the manifest logic ref: v${{ github.event.client_payload.version }} + - name: use node.js 18.x + uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 + with: + node-version: 18.x + registry-url: https://registry.npmjs.org/ # Needed for auth + + - name: yarn install + uses: backstage/actions/yarn-install@a674369920067381b450d398b27df7039b7ef635 # v0.6.5 + with: + path: backstage + cache-prefix: ${{ runner.os }}-v18.x + # Checkout backstage/versions into /backstage/versions, which is where store the output - name: Checkout versions uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 From 0bdf7ab1ebfdc211a72a394788cfc892a8eb3388 Mon Sep 17 00:00:00 2001 From: MT Lewis Date: Sun, 14 Apr 2024 21:16:04 +0100 Subject: [PATCH 225/416] sync_release-manifest: add yarn-plugin to release directory Since yarn plugins aren't installable via npm, we need a place to make the version available for each release. Since versions.backstage.io already provides an API backed by a git repo organized by release (and even includes release line links), it seems like the perfect spot. This commit adds the yarn plugin to the appropriate directory when the sync_release-management workflow runs, reorganizing the existing functionality for pushing the changes to the versions repo with a little bit of refactoring. Signed-off-by: MT Lewis --- .github/workflows/sync_release-manifest.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/.github/workflows/sync_release-manifest.yml b/.github/workflows/sync_release-manifest.yml index 34bbabcd0b..e7c06747f7 100644 --- a/.github/workflows/sync_release-manifest.yml +++ b/.github/workflows/sync_release-manifest.yml @@ -31,6 +31,10 @@ jobs: path: backstage cache-prefix: ${{ runner.os }}-v18.x + - name: Build yarn plugin + working-directory: backstage/packages/yarn-plugin + run: yarn build + # Checkout backstage/versions into /backstage/versions, which is where store the output - name: Checkout versions uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 @@ -51,6 +55,20 @@ jobs: mkdir -p scripts wget -O scripts/assemble-manifest.js https://raw.githubusercontent.com/backstage/backstage/master/scripts/assemble-manifest.js node scripts/assemble-manifest.js ${{ github.event.client_payload.version }} + + # Copies the build output of the yarn-plugin package to the appropriate + # directory, allowing the plugin to be installed with a command like + # `yarn plugin import https://versions.backstage.io/v1/tags/main/yarn-plugin` + - name: Add yarn plugin to release + working-directory: backstage/packages/yarn-plugin + run: >- + cp + bundles/@yarnpkg/plugin-backstage.js + ../../versions/v1/releases/${{ github.event.client_payload.version }}/yarn-plugin + + - name: Commit to versions repo + working-directory: backstage/versions + run: | cd versions git add . git commit -am "${{ github.event.client_payload.version }}" From 513175ae970a34a29b900d4660a2ff45ebc9bedb Mon Sep 17 00:00:00 2001 From: MT Lewis Date: Sun, 14 Apr 2024 21:31:38 +0100 Subject: [PATCH 226/416] sync_release-manifest: remove top-level backstage directory The top-level backstage/ directory included in this repo means we can't use the yarn-install backstage action (or we'd have to add a `path` input option to it). Looking at this workflow, I can't actually spot why the top-level `backstage` dir is needed - nothing is ever written outside it as far as I can spot. With that in mind, proposing we remove it to simplify the workflow and enable the use of the `yarn-install` action without needing to extend it. Signed-off-by: MT Lewis --- .github/workflows/sync_release-manifest.yml | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/.github/workflows/sync_release-manifest.yml b/.github/workflows/sync_release-manifest.yml index e7c06747f7..6d02309f8a 100644 --- a/.github/workflows/sync_release-manifest.yml +++ b/.github/workflows/sync_release-manifest.yml @@ -15,7 +15,6 @@ jobs: - name: Checkout uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 with: - path: backstage # 'v' prefix is added here for the tag, we keep it out of the manifest logic ref: v${{ github.event.client_payload.version }} @@ -28,11 +27,10 @@ jobs: - name: yarn install uses: backstage/actions/yarn-install@a674369920067381b450d398b27df7039b7ef635 # v0.6.5 with: - path: backstage cache-prefix: ${{ runner.os }}-v18.x - name: Build yarn plugin - working-directory: backstage/packages/yarn-plugin + working-directory: packages/yarn-plugin run: yarn build # Checkout backstage/versions into /backstage/versions, which is where store the output @@ -40,7 +38,7 @@ jobs: uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 with: repository: backstage/versions - path: backstage/versions + path: versions token: ${{ secrets.GH_SERVICE_ACCOUNT_TOKEN }} - name: Configure Git @@ -51,7 +49,6 @@ jobs: - name: Create release # This grabs the scripts from master in order to support backfills run: | - cd backstage mkdir -p scripts wget -O scripts/assemble-manifest.js https://raw.githubusercontent.com/backstage/backstage/master/scripts/assemble-manifest.js node scripts/assemble-manifest.js ${{ github.event.client_payload.version }} @@ -60,16 +57,15 @@ jobs: # directory, allowing the plugin to be installed with a command like # `yarn plugin import https://versions.backstage.io/v1/tags/main/yarn-plugin` - name: Add yarn plugin to release - working-directory: backstage/packages/yarn-plugin + working-directory: packages/yarn-plugin run: >- cp bundles/@yarnpkg/plugin-backstage.js ../../versions/v1/releases/${{ github.event.client_payload.version }}/yarn-plugin - name: Commit to versions repo - working-directory: backstage/versions + working-directory: versions run: | - cd versions git add . git commit -am "${{ github.event.client_payload.version }}" git push @@ -87,7 +83,7 @@ jobs: workflow_id: 'release.yml', ref: 'master', inputs: { - version: require('./backstage/packages/create-app/package.json').version, - releaseVersion: require('./backstage/package.json').version + version: require('./packages/create-app/package.json').version, + releaseVersion: require('./package.json').version }, }); From 0600286c95a0f9409954facf1ec01826e8248f4f Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 11 Jul 2024 13:22:51 +0200 Subject: [PATCH 227/416] Update .changeset/early-deers-beg.md Signed-off-by: Patrik Oldsberg --- .changeset/early-deers-beg.md | 9 --------- 1 file changed, 9 deletions(-) diff --git a/.changeset/early-deers-beg.md b/.changeset/early-deers-beg.md index 4bac074d8c..735c68aace 100644 --- a/.changeset/early-deers-beg.md +++ b/.changeset/early-deers-beg.md @@ -5,12 +5,3 @@ Fixed bug resulting from missing required owner and repo arguments in `getEnvironmentPublicKey` in action `github:environment:create`. Adding environment secrets now works as expected. - -```diff - const publicKeyResponse = await client.rest.actions.getEnvironmentPublicKey({ - repository_id: repository.data.id, -+ owner, -+ repo, - environment_name: name - }); -``` From 4a77a91da87f67ef91e1f35b2b7269b957e754fd Mon Sep 17 00:00:00 2001 From: Andre Wanlin Date: Thu, 11 Jul 2024 06:58:33 -0500 Subject: [PATCH 228/416] Added comment to resolvers Signed-off-by: Andre Wanlin --- docs/auth/microsoft/azure-easyauth.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/auth/microsoft/azure-easyauth.md b/docs/auth/microsoft/azure-easyauth.md index e8d6f2f105..c2a6eab218 100644 --- a/docs/auth/microsoft/azure-easyauth.md +++ b/docs/auth/microsoft/azure-easyauth.md @@ -66,6 +66,7 @@ auth: azureEasyAuth: signIn: resolvers: + # typically you would pick one of these - resolver: emailMatchingUserEntityProfileEmail - resolver: emailLocalPartMatchingUserEntityName - resolver: idMatchingUserEntityAnnotation From b652b6de1fb647cc8fe65af2f6e6baa71574c9ac Mon Sep 17 00:00:00 2001 From: Chap Ambrose Date: Thu, 11 Jul 2024 08:16:21 -0500 Subject: [PATCH 229/416] add deploy buttuon to heroku.md Signed-off-by: Chap Ambrose --- docs/deployment/heroku.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/deployment/heroku.md b/docs/deployment/heroku.md index 74732bb431..faf1c2106e 100644 --- a/docs/deployment/heroku.md +++ b/docs/deployment/heroku.md @@ -7,6 +7,8 @@ description: How to deploy Backstage to Heroku Heroku is a Platform as a Service (PaaS) designed to simplify application deployment. +[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/chap/backstage-button) + ## Create App Starting with an existing Backstage app or follow the [getting started guide](https://backstage.io/docs/getting-started/) to create a new one. From 8fc26223c26e2fe642414f28c8486fd1ef44349d Mon Sep 17 00:00:00 2001 From: Bond Yan Date: Thu, 11 Jul 2024 11:20:17 -0400 Subject: [PATCH 230/416] setting useNavigate in a ref Signed-off-by: Bond Yan --- .changeset/chatty-adults-boil.md | 5 +++++ .../TechDocsReaderPageContent/useNavigateUrl.tsx | 9 +++++---- 2 files changed, 10 insertions(+), 4 deletions(-) create mode 100644 .changeset/chatty-adults-boil.md diff --git a/.changeset/chatty-adults-boil.md b/.changeset/chatty-adults-boil.md new file mode 100644 index 0000000000..76f3bddf41 --- /dev/null +++ b/.changeset/chatty-adults-boil.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs': patch +--- + +Fixed an issue that was causing techdocs pages unnecessarily re-render on navigate. diff --git a/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/useNavigateUrl.tsx b/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/useNavigateUrl.tsx index 02d181dccf..f036edef65 100644 --- a/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/useNavigateUrl.tsx +++ b/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/useNavigateUrl.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ import { configApiRef, useApi } from '@backstage/core-plugin-api'; -import { useCallback } from 'react'; +import { useCallback, useRef } from 'react'; import { useNavigate } from 'react-router-dom'; /** @@ -53,7 +53,8 @@ export function resolveUrlToRelative(url: string, baseUrl: string) { * @public */ export function useNavigateUrl() { - const navigate = useNavigate(); + // useRef prevents useNavigate from causing unnecessary re-renders + const navigate = useRef(useNavigate()); const configApi = useApi(configApiRef); const appBaseUrl = configApi.getOptionalString('app.baseUrl'); const navigateFn = useCallback( @@ -70,9 +71,9 @@ export function useNavigateUrl() { // URL passed in was relative. } } - navigate(url); + navigate.current(url); }, - [navigate, appBaseUrl], + [appBaseUrl], ); return navigateFn; } From a3449e0767d0ce17bee320341ec1309e6830dc88 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 12 Jul 2024 07:40:53 +0000 Subject: [PATCH 231/416] chore(deps): update snyk/actions digest to 640e317 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/sync_snyk-github-issues.yml | 2 +- .github/workflows/sync_snyk-monitor.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/sync_snyk-github-issues.yml b/.github/workflows/sync_snyk-github-issues.yml index fb3456bfb6..1cdc0cb22a 100644 --- a/.github/workflows/sync_snyk-github-issues.yml +++ b/.github/workflows/sync_snyk-github-issues.yml @@ -29,7 +29,7 @@ jobs: cache-prefix: ${{ runner.os }}-v18.x - name: Create Snyk report - uses: snyk/actions/node@d406fd286b663eb8c6f8adcced4f7bcd199c0a3f # master + uses: snyk/actions/node@640e31719aac3e44867d239dc86c20c3e34c8e4f # master continue-on-error: true # Snyk CLI exits with error when vulnerabilities are found with: args: > diff --git a/.github/workflows/sync_snyk-monitor.yml b/.github/workflows/sync_snyk-monitor.yml index a3c72c1d7b..b1e50397ce 100644 --- a/.github/workflows/sync_snyk-monitor.yml +++ b/.github/workflows/sync_snyk-monitor.yml @@ -31,7 +31,7 @@ jobs: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Monitor and Synchronize Snyk Policies - uses: snyk/actions/node@d406fd286b663eb8c6f8adcced4f7bcd199c0a3f # master + uses: snyk/actions/node@640e31719aac3e44867d239dc86c20c3e34c8e4f # master with: command: monitor args: > @@ -46,7 +46,7 @@ jobs: # Above we run the `monitor` command, this runs the `test` command which is # the one that generates the SARIF report that we can upload to GitHub. - name: Create Snyk report - uses: snyk/actions/node@d406fd286b663eb8c6f8adcced4f7bcd199c0a3f # master + uses: snyk/actions/node@640e31719aac3e44867d239dc86c20c3e34c8e4f # master continue-on-error: true # To make sure that SARIF upload gets called with: args: > From f691c9bf75dc4562f45e51c02ec5e132bfdd8433 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 10 Jul 2024 13:24:37 +0200 Subject: [PATCH 232/416] backend-app-api: simplify defaultServiceFactories option Signed-off-by: Patrik Oldsberg --- .changeset/dry-wombats-type.md | 5 +++ packages/backend-app-api/api-report.md | 4 +- .../src/wiring/createSpecializedBackend.ts | 8 +--- packages/backend-app-api/src/wiring/types.ts | 4 +- .../backend-defaults/src/CreateBackend.ts | 40 +++++++++---------- 5 files changed, 31 insertions(+), 30 deletions(-) create mode 100644 .changeset/dry-wombats-type.md diff --git a/.changeset/dry-wombats-type.md b/.changeset/dry-wombats-type.md new file mode 100644 index 0000000000..31fed70293 --- /dev/null +++ b/.changeset/dry-wombats-type.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-app-api': minor +--- + +**BREAKING**: Removed the ability to pass callback-form service factories through the `defaultServiceFactories` option of `createSpecializedBackend`. This is an immediate breaking change as usage of this function is expected to be very rare. diff --git a/packages/backend-app-api/api-report.md b/packages/backend-app-api/api-report.md index 51839b88be..2a447d52ef 100644 --- a/packages/backend-app-api/api-report.md +++ b/packages/backend-app-api/api-report.md @@ -38,8 +38,8 @@ import { RootLifecycleService } from '@backstage/backend-plugin-api'; import { RootLoggerService } from '@backstage/backend-plugin-api'; import { SchedulerService } from '@backstage/backend-plugin-api'; import type { Server } from 'node:http'; +import { ServiceFactory } from '@backstage/backend-plugin-api'; import { ServiceFactoryCompat } from '@backstage/backend-plugin-api'; -import { ServiceFactoryOrFunction } from '@backstage/backend-plugin-api'; import { TokenManagerService } from '@backstage/backend-plugin-api'; import { transport } from 'winston'; import { UrlReaderService } from '@backstage/backend-plugin-api'; @@ -99,7 +99,7 @@ export function createSpecializedBackend( // @public (undocumented) export interface CreateSpecializedBackendOptions { // (undocumented) - defaultServiceFactories: ServiceFactoryOrFunction[]; + defaultServiceFactories: ServiceFactory[]; } // @public @deprecated (undocumented) diff --git a/packages/backend-app-api/src/wiring/createSpecializedBackend.ts b/packages/backend-app-api/src/wiring/createSpecializedBackend.ts index f5c4d8b152..fd449be541 100644 --- a/packages/backend-app-api/src/wiring/createSpecializedBackend.ts +++ b/packages/backend-app-api/src/wiring/createSpecializedBackend.ts @@ -24,13 +24,9 @@ import { Backend, CreateSpecializedBackendOptions } from './types'; export function createSpecializedBackend( options: CreateSpecializedBackendOptions, ): Backend { - const services = options.defaultServiceFactories.map(sf => - typeof sf === 'function' ? sf() : sf, - ); - const exists = new Set(); const duplicates = new Set(); - for (const { service } of services) { + for (const { service } of options.defaultServiceFactories) { if (exists.has(service.id)) { duplicates.add(service.id); } else { @@ -47,5 +43,5 @@ export function createSpecializedBackend( ); } - return new BackstageBackend(services); + return new BackstageBackend(options.defaultServiceFactories); } diff --git a/packages/backend-app-api/src/wiring/types.ts b/packages/backend-app-api/src/wiring/types.ts index 027b2bf254..776dcdcb35 100644 --- a/packages/backend-app-api/src/wiring/types.ts +++ b/packages/backend-app-api/src/wiring/types.ts @@ -18,7 +18,7 @@ import { BackendFeature, ExtensionPoint, ServiceRef, - ServiceFactoryOrFunction, + ServiceFactory, } from '@backstage/backend-plugin-api'; /** @@ -39,7 +39,7 @@ export interface Backend { * @public */ export interface CreateSpecializedBackendOptions { - defaultServiceFactories: ServiceFactoryOrFunction[]; + defaultServiceFactories: ServiceFactory[]; } /** diff --git a/packages/backend-defaults/src/CreateBackend.ts b/packages/backend-defaults/src/CreateBackend.ts index e3195748a6..47fa09da49 100644 --- a/packages/backend-defaults/src/CreateBackend.ts +++ b/packages/backend-defaults/src/CreateBackend.ts @@ -40,26 +40,26 @@ import { userInfoServiceFactory } from '@backstage/backend-defaults/userInfo'; import { eventsServiceFactory } from '@backstage/plugin-events-node'; export const defaultServiceFactories = [ - authServiceFactory(), - cacheServiceFactory(), - rootConfigServiceFactory(), - databaseServiceFactory(), - discoveryServiceFactory(), - httpAuthServiceFactory(), - httpRouterServiceFactory(), - identityServiceFactory(), - lifecycleServiceFactory(), - loggerServiceFactory(), - permissionsServiceFactory(), - rootHealthServiceFactory(), - rootHttpRouterServiceFactory(), - rootLifecycleServiceFactory(), - rootLoggerServiceFactory(), - schedulerServiceFactory(), - tokenManagerServiceFactory(), - userInfoServiceFactory(), - urlReaderServiceFactory(), - eventsServiceFactory(), + authServiceFactory, + cacheServiceFactory, + rootConfigServiceFactory, + databaseServiceFactory, + discoveryServiceFactory, + httpAuthServiceFactory, + httpRouterServiceFactory, + identityServiceFactory, + lifecycleServiceFactory, + loggerServiceFactory, + permissionsServiceFactory, + rootHealthServiceFactory, + rootHttpRouterServiceFactory, + rootLifecycleServiceFactory, + rootLoggerServiceFactory, + schedulerServiceFactory, + tokenManagerServiceFactory, + userInfoServiceFactory, + urlReaderServiceFactory, + eventsServiceFactory, ]; /** From 18b96b15edeb2526bf36c60530e1739cb8d8f274 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 10 Jul 2024 13:30:14 +0200 Subject: [PATCH 233/416] backend-app-api: deprecate callback form of backend.add(...) Signed-off-by: Patrik Oldsberg --- .changeset/three-lizards-crash.md | 5 +++++ packages/backend-app-api/api-report.md | 9 ++++++++- packages/backend-app-api/src/wiring/types.ts | 11 +++++++++-- 3 files changed, 22 insertions(+), 3 deletions(-) create mode 100644 .changeset/three-lizards-crash.md diff --git a/.changeset/three-lizards-crash.md b/.changeset/three-lizards-crash.md new file mode 100644 index 0000000000..5dffed0f3b --- /dev/null +++ b/.changeset/three-lizards-crash.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-app-api': patch +--- + +The ability to install backend features in callback form (`() => BackendFeature`) has been deprecated. This typically means that you need to update the installed features to use the latest version of `@backstage/backend-plugin-api`. If the feature is from a third-party package, please reach out to the package maintainer to update it. diff --git a/packages/backend-app-api/api-report.md b/packages/backend-app-api/api-report.md index 2a447d52ef..54e2900cc2 100644 --- a/packages/backend-app-api/api-report.md +++ b/packages/backend-app-api/api-report.md @@ -58,9 +58,16 @@ export interface Backend { add( feature: | BackendFeature + | Promise<{ + default: BackendFeature; + }>, + ): void; + // @deprecated (undocumented) + add( + feature: | (() => BackendFeature) | Promise<{ - default: BackendFeature | (() => BackendFeature); + default: () => BackendFeature; }>, ): void; // (undocumented) diff --git a/packages/backend-app-api/src/wiring/types.ts b/packages/backend-app-api/src/wiring/types.ts index 776dcdcb35..075eb58b3f 100644 --- a/packages/backend-app-api/src/wiring/types.ts +++ b/packages/backend-app-api/src/wiring/types.ts @@ -25,11 +25,18 @@ import { * @public */ export interface Backend { + add(feature: BackendFeature | Promise<{ default: BackendFeature }>): void; + /** + * @deprecated The ability to add features defined as a callback is being + * removed. Please update the installed feature to no longer be defined as a + * callback, typically this means updating it to use the latest version of + * `@backstage/backend-plugin-api`. If the feature is from a third-party + * package, please reach out to the package maintainer to update it. + */ add( feature: - | BackendFeature | (() => BackendFeature) - | Promise<{ default: BackendFeature | (() => BackendFeature) }>, + | Promise<{ default: () => BackendFeature }>, ): void; start(): Promise; stop(): Promise; From 906c817fd342f1efcd4bbd8dda5c4d9e59345c99 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Fri, 12 Jul 2024 10:43:19 +0200 Subject: [PATCH 234/416] backend-test-utils: update ServiceFactoryTester to not accept callback form Signed-off-by: Patrik Oldsberg --- .changeset/smooth-pianos-argue.md | 5 +++++ packages/backend-test-utils/api-report.md | 6 ++---- .../src/next/wiring/ServiceFactoryTester.ts | 15 +++++---------- 3 files changed, 12 insertions(+), 14 deletions(-) create mode 100644 .changeset/smooth-pianos-argue.md diff --git a/.changeset/smooth-pianos-argue.md b/.changeset/smooth-pianos-argue.md new file mode 100644 index 0000000000..5ab8be8136 --- /dev/null +++ b/.changeset/smooth-pianos-argue.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-test-utils': patch +--- + +Updated `ServiceFactoryTester` to only accept plain service factory objects, no longer supporting the callback form. This lines up with the changes to `@backstage/backend-plugin-api` and should not require any code changes. diff --git a/packages/backend-test-utils/api-report.md b/packages/backend-test-utils/api-report.md index 566ac5b888..d122e038a6 100644 --- a/packages/backend-test-utils/api-report.md +++ b/packages/backend-test-utils/api-report.md @@ -371,9 +371,7 @@ export namespace mockServices { // @public export class ServiceFactoryTester { static from( - subject: - | ServiceFactory - | (() => ServiceFactory), + subject: ServiceFactory, options?: ServiceFactoryTesterOptions, ): ServiceFactoryTester; get( @@ -387,7 +385,7 @@ export class ServiceFactoryTester { // @public export interface ServiceFactoryTesterOptions { - dependencies?: Array ServiceFactory)>; + dependencies?: Array; } // @public (undocumented) diff --git a/packages/backend-test-utils/src/next/wiring/ServiceFactoryTester.ts b/packages/backend-test-utils/src/next/wiring/ServiceFactoryTester.ts index 0555ab10a4..9247a9132e 100644 --- a/packages/backend-test-utils/src/next/wiring/ServiceFactoryTester.ts +++ b/packages/backend-test-utils/src/next/wiring/ServiceFactoryTester.ts @@ -35,7 +35,7 @@ export interface ServiceFactoryTesterOptions { * If a service factory is provided for a service that already has a default * implementation, the provided factory will override the default. */ - dependencies?: Array ServiceFactory)>; + dependencies?: Array; } /** @@ -55,20 +55,15 @@ export class ServiceFactoryTester { * @returns A new tester instance for the provided subject. */ static from( - subject: - | ServiceFactory - | (() => ServiceFactory), + subject: ServiceFactory, options?: ServiceFactoryTesterOptions, ) { - const subjectFactory = typeof subject === 'function' ? subject() : subject; const registry = ServiceRegistry.create([ ...defaultServiceFactories, - ...(options?.dependencies?.map(f => - typeof f === 'function' ? f() : f, - ) ?? []), - subjectFactory, + ...(options?.dependencies ?? []), + subject, ]); - return new ServiceFactoryTester(subjectFactory.service, registry); + return new ServiceFactoryTester(subject.service, registry); } private constructor( From 972bcbb57af95ed825056b0608b8f1057892bf48 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Fri, 12 Jul 2024 10:49:44 +0200 Subject: [PATCH 235/416] backend-test-utils: remove callback form features from startTestBackend Signed-off-by: Patrik Oldsberg --- .changeset/smooth-pianos-argue.md | 2 +- packages/backend-test-utils/api-report.md | 3 +-- packages/backend-test-utils/src/next/wiring/TestBackend.ts | 6 +----- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/.changeset/smooth-pianos-argue.md b/.changeset/smooth-pianos-argue.md index 5ab8be8136..e7fc66dee4 100644 --- a/.changeset/smooth-pianos-argue.md +++ b/.changeset/smooth-pianos-argue.md @@ -2,4 +2,4 @@ '@backstage/backend-test-utils': patch --- -Updated `ServiceFactoryTester` to only accept plain service factory objects, no longer supporting the callback form. This lines up with the changes to `@backstage/backend-plugin-api` and should not require any code changes. +Updated `startTestBackend` and `ServiceFactoryTester` to only accept plain service factory or backend feature objects, no longer supporting the callback form. This lines up with the changes to `@backstage/backend-plugin-api` and should not require any code changes. diff --git a/packages/backend-test-utils/api-report.md b/packages/backend-test-utils/api-report.md index d122e038a6..be6c22192d 100644 --- a/packages/backend-test-utils/api-report.md +++ b/packages/backend-test-utils/api-report.md @@ -430,9 +430,8 @@ export interface TestBackendOptions { // (undocumented) features?: Array< | BackendFeature - | (() => BackendFeature) | Promise<{ - default: BackendFeature | (() => BackendFeature); + default: BackendFeature; }> >; } diff --git a/packages/backend-test-utils/src/next/wiring/TestBackend.ts b/packages/backend-test-utils/src/next/wiring/TestBackend.ts index f23883ba3e..16ee6b78d2 100644 --- a/packages/backend-test-utils/src/next/wiring/TestBackend.ts +++ b/packages/backend-test-utils/src/next/wiring/TestBackend.ts @@ -48,11 +48,7 @@ export interface TestBackendOptions { ]; }, ]; - features?: Array< - | BackendFeature - | (() => BackendFeature) - | Promise<{ default: BackendFeature | (() => BackendFeature) }> - >; + features?: Array>; } /** @public */ From f4085b87f5bd2fc707a0970395a4b1f129ad7ca4 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Fri, 12 Jul 2024 12:14:17 +0200 Subject: [PATCH 236/416] permission-common: removed the token option from the base evaluator options Signed-off-by: Patrik Oldsberg --- .changeset/eight-dancers-burn.md | 5 +++++ plugins/permission-common/api-report.md | 21 ++++++++++++------ .../permission-common/src/PermissionClient.ts | 14 +++++++++--- plugins/permission-common/src/types/api.ts | 22 +++++++++---------- 4 files changed, 40 insertions(+), 22 deletions(-) create mode 100644 .changeset/eight-dancers-burn.md diff --git a/.changeset/eight-dancers-burn.md b/.changeset/eight-dancers-burn.md new file mode 100644 index 0000000000..228ff036ab --- /dev/null +++ b/.changeset/eight-dancers-burn.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-permission-common': minor +--- + +**BREAKING**: Removed the deprecated and unused `token` option from `EvaluatorRequestOptions`. The `PermissionsClient` now has its own `PermissionClientRequestOptions` type that declares the `token` option instead. diff --git a/plugins/permission-common/api-report.md b/plugins/permission-common/api-report.md index 1c2476d20d..e9935c612d 100644 --- a/plugins/permission-common/api-report.md +++ b/plugins/permission-common/api-report.md @@ -94,9 +94,7 @@ export type EvaluatePermissionResponseBatch = PermissionMessageBatch; // @public -export type EvaluatorRequestOptions = { - token?: string; -}; +export interface EvaluatorRequestOptions {} // @public export type IdentifiedPermissionMessage = T & { @@ -162,14 +160,19 @@ export class PermissionClient implements PermissionEvaluator { constructor(options: { discovery: DiscoveryApi; config: Config }); authorize( requests: AuthorizePermissionRequest[], - options?: EvaluatorRequestOptions, + options?: PermissionClientRequestOptions, ): Promise; authorizeConditional( queries: QueryPermissionRequest[], - options?: EvaluatorRequestOptions, + options?: PermissionClientRequestOptions, ): Promise; } +// @public +export type PermissionClientRequestOptions = { + token?: string; +}; + // @public export type PermissionCondition< TResourceType extends string = string, @@ -191,11 +194,15 @@ export type PermissionCriteria = export interface PermissionEvaluator { authorize( requests: AuthorizePermissionRequest[], - options?: EvaluatorRequestOptions, + options?: EvaluatorRequestOptions & { + _ignored?: never; + }, ): Promise; authorizeConditional( requests: QueryPermissionRequest[], - options?: EvaluatorRequestOptions, + options?: EvaluatorRequestOptions & { + _ignored?: never; + }, ): Promise; } diff --git a/plugins/permission-common/src/PermissionClient.ts b/plugins/permission-common/src/PermissionClient.ts index a5d08205d8..2414774775 100644 --- a/plugins/permission-common/src/PermissionClient.ts +++ b/plugins/permission-common/src/PermissionClient.ts @@ -27,7 +27,6 @@ import { PermissionEvaluator, QueryPermissionRequest, AuthorizePermissionRequest, - EvaluatorRequestOptions, AuthorizePermissionResponse, QueryPermissionResponse, } from './types/api'; @@ -93,6 +92,15 @@ const responseSchema = ( ), }); +/** + * Options for {@link PermissionClient} requests. + * + * @public + */ +export type PermissionClientRequestOptions = { + token?: string; +}; + /** * An isomorphic client for requesting authorization for Backstage permissions. * @public @@ -112,7 +120,7 @@ export class PermissionClient implements PermissionEvaluator { */ async authorize( requests: AuthorizePermissionRequest[], - options?: EvaluatorRequestOptions, + options?: PermissionClientRequestOptions, ): Promise { return this.makeRequest( requests, @@ -126,7 +134,7 @@ export class PermissionClient implements PermissionEvaluator { */ async authorizeConditional( queries: QueryPermissionRequest[], - options?: EvaluatorRequestOptions, + options?: PermissionClientRequestOptions, ): Promise { return this.makeRequest(queries, queryPermissionResponseSchema, options); } diff --git a/plugins/permission-common/src/types/api.ts b/plugins/permission-common/src/types/api.ts index e597384a56..072615989b 100644 --- a/plugins/permission-common/src/types/api.ts +++ b/plugins/permission-common/src/types/api.ts @@ -244,7 +244,7 @@ export interface PermissionEvaluator { */ authorize( requests: AuthorizePermissionRequest[], - options?: EvaluatorRequestOptions, + options?: EvaluatorRequestOptions & { _ignored?: never }, // Since the options are empty we add this placeholder to reject all options ): Promise; /** @@ -257,22 +257,20 @@ export interface PermissionEvaluator { */ authorizeConditional( requests: QueryPermissionRequest[], - options?: EvaluatorRequestOptions, + options?: EvaluatorRequestOptions & { _ignored?: never }, // Since the options are empty we add this placeholder to reject all options ): Promise; } +// Note(Rugvip): I kept the below type around in case we want to add new options +// in the future, for example a signal. It also helps out enabling API +// constraints, as without this we can't have the permissions service implement +// the evaluator interface due to the mismatch in parameter count. + /** * Options for {@link PermissionEvaluator} requests. * + * This is currently empty, as there are no longer any common options for the permission evaluator. + * * @public */ -export type EvaluatorRequestOptions = { - /** - * @deprecated Backend plugins should no longer depend on the - * `PermissionEvaluator`, but instead use the `PermissionService` from - * `@backstage/backend-plugin-api`. Frontend plugins should not need to inject - * this token at all, but instead implicitly rely on underlying fetchApi to do - * it for them. - */ - token?: string; -}; +export interface EvaluatorRequestOptions {} From 36f91e8956a6e6308c066c26f49f34e3542e7b8c Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Fri, 12 Jul 2024 12:17:39 +0200 Subject: [PATCH 237/416] backend-plugin-api,permission-node: remove deprecated token option from permissions service Signed-off-by: Patrik Oldsberg --- .changeset/gold-worms-complain.md | 5 + .changeset/swift-seals-drive.md | 5 + packages/backend-plugin-api/api-report.md | 17 +- .../definitions/PermissionsService.ts | 19 +- .../src/ServerPermissionClient.test.ts | 232 ++++-------------- .../src/ServerPermissionClient.ts | 8 - 6 files changed, 77 insertions(+), 209 deletions(-) create mode 100644 .changeset/gold-worms-complain.md create mode 100644 .changeset/swift-seals-drive.md diff --git a/.changeset/gold-worms-complain.md b/.changeset/gold-worms-complain.md new file mode 100644 index 0000000000..229293cc2f --- /dev/null +++ b/.changeset/gold-worms-complain.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-permission-node': minor +--- + +**BREAKING**: Updated the `ServerPermissionClient` to match the new `PermissionsService` interface, where the deprecated `token` option has been removed and the options are now required. diff --git a/.changeset/swift-seals-drive.md b/.changeset/swift-seals-drive.md new file mode 100644 index 0000000000..a03f490d3f --- /dev/null +++ b/.changeset/swift-seals-drive.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-plugin-api': minor +--- + +**BREAKING**: The `PermissionsService` no longer supports passing the deprecated `token` option, and the request options are now required. diff --git a/packages/backend-plugin-api/api-report.md b/packages/backend-plugin-api/api-report.md index 7b1e6ef2d3..1937ba6ca9 100644 --- a/packages/backend-plugin-api/api-report.md +++ b/packages/backend-plugin-api/api-report.md @@ -9,6 +9,7 @@ import { AuthorizePermissionRequest } from '@backstage/plugin-permission-common' import { AuthorizePermissionResponse } from '@backstage/plugin-permission-common'; import { Config } from '@backstage/config'; import { Duration } from 'luxon'; +import { EvaluatorRequestOptions } from '@backstage/plugin-permission-common'; import { Handler } from 'express'; import { HumanDuration } from '@backstage/types'; import { IdentityApi } from '@backstage/plugin-auth-node'; @@ -423,22 +424,20 @@ export interface LoggerService { export interface PermissionsService extends PermissionEvaluator { authorize( requests: AuthorizePermissionRequest[], - options?: PermissionsServiceRequestOptions, + options: PermissionsServiceRequestOptions, ): Promise; authorizeConditional( requests: QueryPermissionRequest[], - options?: PermissionsServiceRequestOptions, + options: PermissionsServiceRequestOptions, ): Promise; } // @public -export type PermissionsServiceRequestOptions = - | { - token?: string; - } - | { - credentials: BackstageCredentials; - }; +export interface PermissionsServiceRequestOptions + extends EvaluatorRequestOptions { + // (undocumented) + credentials: BackstageCredentials; +} // @public export interface PluginMetadataService { diff --git a/packages/backend-plugin-api/src/services/definitions/PermissionsService.ts b/packages/backend-plugin-api/src/services/definitions/PermissionsService.ts index c5046a988b..a25081d17a 100644 --- a/packages/backend-plugin-api/src/services/definitions/PermissionsService.ts +++ b/packages/backend-plugin-api/src/services/definitions/PermissionsService.ts @@ -17,6 +17,7 @@ import { AuthorizePermissionRequest, AuthorizePermissionResponse, + EvaluatorRequestOptions, PermissionEvaluator, QueryPermissionRequest, QueryPermissionResponse, @@ -24,18 +25,14 @@ import { import { BackstageCredentials } from './AuthService'; /** - * Options for {@link @backstage/plugin-permission-common#PermissionEvaluator} requests. + * Options for {@link PermissionsService} requests. * * @public */ -export type PermissionsServiceRequestOptions = - | { - /** @deprecated use the `credentials` option instead. */ - token?: string; - } - | { - credentials: BackstageCredentials; - }; +export interface PermissionsServiceRequestOptions + extends EvaluatorRequestOptions { + credentials: BackstageCredentials; +} /** * Permission system integration for authorization of user/service actions. @@ -59,7 +56,7 @@ export interface PermissionsService extends PermissionEvaluator { */ authorize( requests: AuthorizePermissionRequest[], - options?: PermissionsServiceRequestOptions, + options: PermissionsServiceRequestOptions, ): Promise; /** @@ -79,6 +76,6 @@ export interface PermissionsService extends PermissionEvaluator { */ authorizeConditional( requests: QueryPermissionRequest[], - options?: PermissionsServiceRequestOptions, + options: PermissionsServiceRequestOptions, ): Promise; } diff --git a/plugins/permission-node/src/ServerPermissionClient.test.ts b/plugins/permission-node/src/ServerPermissionClient.test.ts index 6e99ff71ab..028517c5e0 100644 --- a/plugins/permission-node/src/ServerPermissionClient.test.ts +++ b/plugins/permission-node/src/ServerPermissionClient.test.ts @@ -83,18 +83,22 @@ describe('ServerPermissionClient', () => { const client = ServerPermissionClient.fromConfig(new ConfigReader({}), { discovery, tokenManager: mockServices.tokenManager.mock(), + auth: mockServices.auth(), }); - await client.authorize([ - { - permission: testBasicPermission, - }, - ]); + await client.authorize( + [ + { + permission: testBasicPermission, + }, + ], + { credentials: mockCredentials.none() }, + ); expect(mockAuthorizeHandler).not.toHaveBeenCalled(); }); - it('should bypass the permission backend if permissions are enabled and request has valid server token', async () => { + it('should bypass the permission backend if permissions are enabled and request has valid server credentials', async () => { const client = ServerPermissionClient.fromConfig(config, { discovery, tokenManager: mockServices.tokenManager.mock(), @@ -102,13 +106,13 @@ describe('ServerPermissionClient', () => { }); await client.authorize([{ permission: testBasicPermission }], { - token: mockCredentials.service.token(), + credentials: mockCredentials.service(), }); expect(mockAuthorizeHandler).not.toHaveBeenCalled(); }); - it('should call the permission backend if permissions are enabled and request does not have valid server token', async () => { + it('should call the permission backend if permissions are enabled and request does not have valid server credentials', async () => { const client = ServerPermissionClient.fromConfig(config, { discovery, tokenManager: mockServices.tokenManager.mock(), @@ -116,10 +120,18 @@ describe('ServerPermissionClient', () => { }); await client.authorize([{ permission: testBasicPermission }], { - token: mockCredentials.user.token(), + credentials: mockCredentials.user(), }); expect(mockAuthorizeHandler).toHaveBeenCalled(); + expect( + mockAuthorizeHandler.mock.calls[0][0].headers.get('authorization'), + ).toBe( + mockCredentials.service.header({ + onBehalfOf: mockCredentials.user(), + targetPluginId: 'permission', + }), + ); }); }); @@ -145,201 +157,59 @@ describe('ServerPermissionClient', () => { const client = ServerPermissionClient.fromConfig(new ConfigReader({}), { discovery, tokenManager: mockServices.tokenManager.mock(), - }); - - await client.authorizeConditional([ - { permission: testResourcePermission }, - ]); - - expect(mockAuthorizeHandler).not.toHaveBeenCalled(); - }); - - it('should bypass the permission backend if permissions are enabled and request has valid server token', async () => { - const client = ServerPermissionClient.fromConfig(config, { - discovery, - tokenManager: mockServices.tokenManager.mock(), + auth: mockServices.auth(), }); await client.authorizeConditional( [{ permission: testResourcePermission }], { - token: mockCredentials.service.token(), + credentials: mockCredentials.none(), }, ); expect(mockAuthorizeHandler).not.toHaveBeenCalled(); }); - it('should call the permission backend if permissions are enabled and request does not have valid server token', async () => { - const auth = mockServices.auth(); + it('should bypass the permission backend if permissions are enabled and request has valid server credentials', async () => { const client = ServerPermissionClient.fromConfig(config, { discovery, tokenManager: mockServices.tokenManager.mock(), - auth, + auth: mockServices.auth(), }); await client.authorizeConditional( [{ permission: testResourcePermission }], { - token: mockCredentials.user.token(), + credentials: mockCredentials.service(), + }, + ); + + expect(mockAuthorizeHandler).not.toHaveBeenCalled(); + }); + + it('should call the permission backend if permissions are enabled and request does not have valid server credentials', async () => { + const client = ServerPermissionClient.fromConfig(config, { + discovery, + tokenManager: mockServices.tokenManager.mock(), + auth: mockServices.auth(), + }); + + await client.authorizeConditional( + [{ permission: testResourcePermission }], + { + credentials: mockCredentials.user(), }, ); expect(mockAuthorizeHandler).toHaveBeenCalled(); - }); - }); - - describe('with credentials', () => { - describe('authorize', () => { - let mockAuthorizeHandler: jest.Mock; - - beforeEach(() => { - mockAuthorizeHandler = jest.fn((req, res, { json }: RestContext) => { - const responses = req.body.items.map( - (r: IdentifiedPermissionMessage) => ({ - id: r.id, - result: AuthorizeResult.ALLOW, - }), - ); - - return res(json({ items: responses })); - }); - - server.use(rest.post(`${mockBaseUrl}/authorize`, mockAuthorizeHandler)); - }); - - it('should bypass the permission backend if permissions are disabled', async () => { - const client = ServerPermissionClient.fromConfig(new ConfigReader({}), { - discovery, - tokenManager: mockServices.tokenManager.mock(), - auth: mockServices.auth(), - }); - - await client.authorize( - [ - { - permission: testBasicPermission, - }, - ], - { credentials: mockCredentials.none() }, - ); - - expect(mockAuthorizeHandler).not.toHaveBeenCalled(); - }); - - it('should bypass the permission backend if permissions are enabled and request has valid server token', async () => { - const client = ServerPermissionClient.fromConfig(config, { - discovery, - tokenManager: mockServices.tokenManager.mock(), - auth: mockServices.auth(), - }); - - await client.authorize([{ permission: testBasicPermission }], { - credentials: mockCredentials.service(), - }); - - expect(mockAuthorizeHandler).not.toHaveBeenCalled(); - }); - - it('should call the permission backend if permissions are enabled and request does not have valid server token', async () => { - const client = ServerPermissionClient.fromConfig(config, { - discovery, - tokenManager: mockServices.tokenManager.mock(), - auth: mockServices.auth(), - }); - - await client.authorize([{ permission: testBasicPermission }], { - credentials: mockCredentials.user(), - }); - - expect(mockAuthorizeHandler).toHaveBeenCalled(); - expect( - mockAuthorizeHandler.mock.calls[0][0].headers.get('authorization'), - ).toBe( - mockCredentials.service.header({ - onBehalfOf: mockCredentials.user(), - targetPluginId: 'permission', - }), - ); - }); - }); - - describe('authorizeConditional', () => { - let mockAuthorizeHandler: jest.Mock; - - beforeEach(() => { - mockAuthorizeHandler = jest.fn((req, res, { json }: RestContext) => { - const responses = req.body.items.map( - (r: IdentifiedPermissionMessage) => ({ - id: r.id, - result: AuthorizeResult.ALLOW, - }), - ); - - return res(json({ items: responses })); - }); - - server.use(rest.post(`${mockBaseUrl}/authorize`, mockAuthorizeHandler)); - }); - - it('should bypass the permission backend if permissions are disabled', async () => { - const client = ServerPermissionClient.fromConfig(new ConfigReader({}), { - discovery, - tokenManager: mockServices.tokenManager.mock(), - auth: mockServices.auth(), - }); - - await client.authorizeConditional( - [{ permission: testResourcePermission }], - { - credentials: mockCredentials.none(), - }, - ); - - expect(mockAuthorizeHandler).not.toHaveBeenCalled(); - }); - - it('should bypass the permission backend if permissions are enabled and request has valid server token', async () => { - const client = ServerPermissionClient.fromConfig(config, { - discovery, - tokenManager: mockServices.tokenManager.mock(), - auth: mockServices.auth(), - }); - - await client.authorizeConditional( - [{ permission: testResourcePermission }], - { - credentials: mockCredentials.service(), - }, - ); - - expect(mockAuthorizeHandler).not.toHaveBeenCalled(); - }); - - it('should call the permission backend if permissions are enabled and request does not have valid server token', async () => { - const client = ServerPermissionClient.fromConfig(config, { - discovery, - tokenManager: mockServices.tokenManager.mock(), - auth: mockServices.auth(), - }); - - await client.authorizeConditional( - [{ permission: testResourcePermission }], - { - credentials: mockCredentials.user(), - }, - ); - - expect(mockAuthorizeHandler).toHaveBeenCalled(); - expect( - mockAuthorizeHandler.mock.calls[0][0].headers.get('authorization'), - ).toBe( - mockCredentials.service.header({ - onBehalfOf: mockCredentials.user(), - targetPluginId: 'permission', - }), - ); - }); + expect( + mockAuthorizeHandler.mock.calls[0][0].headers.get('authorization'), + ).toBe( + mockCredentials.service.header({ + onBehalfOf: mockCredentials.user(), + targetPluginId: 'permission', + }), + ); }); }); diff --git a/plugins/permission-node/src/ServerPermissionClient.ts b/plugins/permission-node/src/ServerPermissionClient.ts index cf54f3b894..e21067bfa1 100644 --- a/plugins/permission-node/src/ServerPermissionClient.ts +++ b/plugins/permission-node/src/ServerPermissionClient.ts @@ -146,14 +146,6 @@ export class ServerPermissionClient implements PermissionsService { return options.credentials; } - if (options?.token) { - try { - return await this.#auth.authenticate(options.token); - } catch { - // ignore - } - } - return undefined; } From 343f656eb15315164a2722e8b32553494b4b5d69 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Fri, 12 Jul 2024 12:21:41 +0200 Subject: [PATCH 238/416] search-backend: update to treat requests without credentials as unauthenticated Signed-off-by: Patrik Oldsberg --- .changeset/tiny-pianos-work.md | 5 ++ .../service/AuthorizedSearchEngine.test.ts | 49 ++++++++++++------- .../src/service/AuthorizedSearchEngine.ts | 16 ++++-- plugins/search-backend/src/service/router.ts | 1 + 4 files changed, 48 insertions(+), 23 deletions(-) create mode 100644 .changeset/tiny-pianos-work.md diff --git a/.changeset/tiny-pianos-work.md b/.changeset/tiny-pianos-work.md new file mode 100644 index 0000000000..033e8272e5 --- /dev/null +++ b/.changeset/tiny-pianos-work.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-search-backend': patch +--- + +The `AuthorizedSearchEngine` will now ignore the deprecated `token` option, and treat it as an unauthorized request. This will not have any effect in practice, since credentials are always provided by the router. diff --git a/plugins/search-backend/src/service/AuthorizedSearchEngine.test.ts b/plugins/search-backend/src/service/AuthorizedSearchEngine.test.ts index 420af5744b..e41f3f888b 100644 --- a/plugins/search-backend/src/service/AuthorizedSearchEngine.test.ts +++ b/plugins/search-backend/src/service/AuthorizedSearchEngine.test.ts @@ -32,6 +32,7 @@ import { decodePageCursor, AuthorizedSearchEngine, } from './AuthorizedSearchEngine'; +import { mockCredentials, mockServices } from '@backstage/backend-test-utils'; describe('AuthorizedSearchEngine', () => { const typeUsers = 'users'; @@ -117,10 +118,11 @@ describe('AuthorizedSearchEngine', () => { searchEngine, defaultTypes, permissionEvaluator, + mockServices.auth(), new ConfigReader({}), ); - const options = { token: 'token' }; + const options = { credentials: mockCredentials.user() }; const allowAll: PermissionEvaluator['authorize'] & PermissionEvaluator['authorizeConditional'] = async queries => { @@ -149,7 +151,7 @@ describe('AuthorizedSearchEngine', () => { types: ['one', 'two'], filters, }, - { token: 'token' }, + options, ); }); @@ -160,7 +162,18 @@ describe('AuthorizedSearchEngine', () => { await authorizedSearchEngine.query({ term: '' }, options); expect(mockedQuery).toHaveBeenCalledWith( { term: '', types: ['users', 'templates', 'services', 'groups'] }, - { token: 'token' }, + options, + ); + }); + + it('should fall back to none credentials if a token is provided', async () => { + mockedQuery.mockImplementation(async () => ({ results })); + mockedPermissionQuery.mockImplementation(allowAll); + + await authorizedSearchEngine.query({ term: '' }, { token: 'token' }); + expect(mockedQuery).toHaveBeenCalledWith( + { term: '', types: ['users', 'templates', 'services', 'groups'] }, + { credentials: mockCredentials.none() }, ); }); @@ -184,7 +197,7 @@ describe('AuthorizedSearchEngine', () => { ); expect(mockedQuery).toHaveBeenCalledWith( { term: '', types: ['users', 'templates'] }, - { token: 'token' }, + options, ); expect(mockedPermissionQuery).toHaveBeenCalledTimes(1); expect(mockedPermissionQuery).toHaveBeenLastCalledWith( @@ -192,7 +205,7 @@ describe('AuthorizedSearchEngine', () => { { permission: defaultTypes[typeUsers].visibilityPermission }, { permission: defaultTypes[typeTemplates].visibilityPermission }, ], - { token: 'token' }, + options, ); }); @@ -218,7 +231,7 @@ describe('AuthorizedSearchEngine', () => { expect(mockedQuery).toHaveBeenCalledWith( { term: '', types: ['templates', 'services', 'groups'] }, - { token: 'token' }, + options, ); expect(mockedPermissionQuery).toHaveBeenCalledTimes(1); @@ -270,7 +283,7 @@ describe('AuthorizedSearchEngine', () => { expect(mockedQuery).toHaveBeenCalledWith( { term: '', types: ['users'] }, - { token: 'token' }, + options, ); }); @@ -326,7 +339,7 @@ describe('AuthorizedSearchEngine', () => { }), }, ], - { token: 'token' }, + options, ); expect(mockedAuthorize).toHaveBeenCalledTimes(1); expect(mockedAuthorize).toHaveBeenCalledWith( @@ -338,7 +351,7 @@ describe('AuthorizedSearchEngine', () => { resourceRef: 'template_doc_0', }, ], - { token: 'token' }, + options, ); }); @@ -403,7 +416,7 @@ describe('AuthorizedSearchEngine', () => { expect(mockedQuery).toHaveBeenNthCalledWith( 1, { term: '', types: ['users', 'templates', 'services'] }, - { token: 'token' }, + options, ); expect(mockedQuery).toHaveBeenNthCalledWith( 2, @@ -412,7 +425,7 @@ describe('AuthorizedSearchEngine', () => { types: ['users', 'templates', 'services'], pageCursor: 'MQ==', }, - { token: 'token' }, + options, ); expect(mockedQuery).toHaveBeenNthCalledWith( 3, @@ -421,7 +434,7 @@ describe('AuthorizedSearchEngine', () => { types: ['users', 'templates', 'services'], pageCursor: 'Mg==', }, - { token: 'token' }, + options, ); const expectedResult = allDocuments @@ -494,7 +507,7 @@ describe('AuthorizedSearchEngine', () => { expect(mockedQuery).toHaveBeenNthCalledWith( 1, { term: '', types: ['users', 'templates', 'services', 'groups'] }, - { token: 'token' }, + options, ); expect(mockedQuery).toHaveBeenNthCalledWith( 2, @@ -503,7 +516,7 @@ describe('AuthorizedSearchEngine', () => { types: ['users', 'templates', 'services', 'groups'], pageCursor: 'MQ==', }, - { token: 'token' }, + options, ); expect(mockedQuery).toHaveBeenNthCalledWith( 3, @@ -512,7 +525,7 @@ describe('AuthorizedSearchEngine', () => { types: ['users', 'templates', 'services', 'groups'], pageCursor: 'Mg==', }, - { token: 'token' }, + options, ); const expectedResult = allDocuments @@ -574,7 +587,7 @@ describe('AuthorizedSearchEngine', () => { expect(mockedQuery).toHaveBeenNthCalledWith( 1, { term: '', types: ['users', 'templates', 'services'] }, - { token: 'token' }, + options, ); expect(mockedQuery).toHaveBeenNthCalledWith( 2, @@ -583,7 +596,7 @@ describe('AuthorizedSearchEngine', () => { types: ['users', 'templates', 'services'], pageCursor: 'MQ==', }, - { token: 'token' }, + options, ); expect(mockedQuery).toHaveBeenNthCalledWith( 3, @@ -592,7 +605,7 @@ describe('AuthorizedSearchEngine', () => { types: ['users', 'templates', 'services'], pageCursor: 'Mg==', }, - { token: 'token' }, + options, ); const expectedResults = servicesWithAuth diff --git a/plugins/search-backend/src/service/AuthorizedSearchEngine.ts b/plugins/search-backend/src/service/AuthorizedSearchEngine.ts index defb535f42..d9d3feeacf 100644 --- a/plugins/search-backend/src/service/AuthorizedSearchEngine.ts +++ b/plugins/search-backend/src/service/AuthorizedSearchEngine.ts @@ -39,7 +39,7 @@ import { import { Config } from '@backstage/config'; import { InputError } from '@backstage/errors'; import { Writable } from 'stream'; -import { PermissionsService } from '@backstage/backend-plugin-api'; +import { AuthService, PermissionsService } from '@backstage/backend-plugin-api'; export function decodePageCursor(pageCursor?: string): { page: number } { if (!pageCursor) { @@ -71,6 +71,7 @@ export class AuthorizedSearchEngine implements SearchEngine { private readonly searchEngine: SearchEngine, private readonly types: Record, private readonly permissions: PermissionsService, + private readonly auth: AuthService, config: Config, ) { this.queryLatencyBudgetMs = @@ -92,9 +93,14 @@ export class AuthorizedSearchEngine implements SearchEngine { ): Promise { const queryStartTime = Date.now(); + const compatOptions = + 'credentials' in options + ? options + : { credentials: await this.auth.getNoneCredentials() }; + const conditionFetcher = new DataLoader( (requests: readonly QueryPermissionRequest[]) => - this.permissions.authorizeConditional(requests.slice(), options), + this.permissions.authorizeConditional(requests.slice(), compatOptions), { cacheKeyFn: ({ permission: { name } }) => name, }, @@ -102,7 +108,7 @@ export class AuthorizedSearchEngine implements SearchEngine { const authorizer = new DataLoader( (requests: readonly AuthorizePermissionRequest[]) => - this.permissions.authorize(requests.slice(), options), + this.permissions.authorize(requests.slice(), compatOptions), { // Serialize the permission name and resourceRef as // a query string to avoid collisions from overlapping @@ -159,7 +165,7 @@ export class AuthorizedSearchEngine implements SearchEngine { if (!resultByResultFilteringRequired) { return this.searchEngine.query( { ...query, types: authorizedTypes }, - options, + compatOptions, ); } @@ -174,7 +180,7 @@ export class AuthorizedSearchEngine implements SearchEngine { do { const nextPage = await this.searchEngine.query( { ...query, types: authorizedTypes, pageCursor: nextPageCursor }, - options, + compatOptions, ); filteredResults = filteredResults.concat( diff --git a/plugins/search-backend/src/service/router.ts b/plugins/search-backend/src/service/router.ts index 250be2853c..d226805baf 100644 --- a/plugins/search-backend/src/service/router.ts +++ b/plugins/search-backend/src/service/router.ts @@ -145,6 +145,7 @@ export async function createRouter( inputEngine, types, permissionEvaluator, + auth, config, ) : inputEngine; From ed10fd202c81f4114480fd3f831ad01507f5b021 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Fri, 12 Jul 2024 13:39:40 +0200 Subject: [PATCH 239/416] permission-node: update policy handler to work with new auth system Signed-off-by: Patrik Oldsberg --- .changeset/brown-rats-judge.md | 5 ++ .changeset/eleven-foxes-sip.md | 11 +++++ .../building-backends/08-migrating.md | 4 +- docs/features/kubernetes/proxy.md | 4 +- ...authorizing-scaffolder-template-details.md | 24 ++++----- docs/permissions/custom-rules.md | 9 ++-- .../02-adding-a-basic-permission-check.md | 11 ++--- .../03-adding-a-resource-permission-check.md | 8 +-- docs/permissions/writing-a-policy.md | 23 ++++----- .../src/policy.ts | 4 +- .../src/service/router.test.ts | 7 +++ .../permission-backend/src/service/router.ts | 14 +++--- plugins/permission-node/api-report.md | 18 +++++-- plugins/permission-node/src/policy/index.ts | 2 +- plugins/permission-node/src/policy/types.ts | 49 +++++++++++++++++-- 15 files changed, 127 insertions(+), 66 deletions(-) create mode 100644 .changeset/brown-rats-judge.md create mode 100644 .changeset/eleven-foxes-sip.md diff --git a/.changeset/brown-rats-judge.md b/.changeset/brown-rats-judge.md new file mode 100644 index 0000000000..0076c65d77 --- /dev/null +++ b/.changeset/brown-rats-judge.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-permission-backend-module-allow-all-policy': patch +--- + +Internal refactor to use new `PolicyQueryUser` type. diff --git a/.changeset/eleven-foxes-sip.md b/.changeset/eleven-foxes-sip.md new file mode 100644 index 0000000000..8b21ddb20f --- /dev/null +++ b/.changeset/eleven-foxes-sip.md @@ -0,0 +1,11 @@ +--- +'@backstage/plugin-permission-backend': patch +'@backstage/plugin-permission-node': patch +--- + +The `PermissionPolicy` interface has been updated to align with the recent changes to the Backstage auth system. The second argument to the `handle` method is now of the new `PolicyQueryUser` type. This type maintains the old fields from the `BackstageIdentityResponse`, which are now all deprecated. Instead, two new fields have been added, which allows access to the same information: + +- `credentials` - A `BackstageCredentials` object, which is useful for making requests to other services on behalf of the user as part of evaluating the policy. This replaces the deprecated `token` field. See the [Auth Service documentation](https://backstage.io/docs/backend-system/core-services/auth#creating-request-tokens) for information about how to create a token using these credentials. +- `info` - A `BackstageUserInfo` object, which contains the same information as the deprecated `identity`, except for the `type` field that was redundant. + +Most existing policies can be updated by replacing the `BackstageIdentityResponse` type with `PolicyQueryUser`, which is exported from `@backstage/plugin-permission-node`, as well as replacing any occurrences of `user?.identity` with `user?.info`. diff --git a/docs/backend-system/building-backends/08-migrating.md b/docs/backend-system/building-backends/08-migrating.md index d38acb695e..c6db44078e 100644 --- a/docs/backend-system/building-backends/08-migrating.md +++ b/docs/backend-system/building-backends/08-migrating.md @@ -1254,7 +1254,6 @@ In order to add your own permission policy you'll need to do the following: ```ts import { createBackendModule } from '@backstage/backend-plugin-api'; -import { BackstageIdentityResponse } from '@backstage/plugin-auth-node'; import { PolicyDecision, AuthorizeResult, @@ -1262,13 +1261,14 @@ import { import { PermissionPolicy, PolicyQuery, + PolicyQueryUser, } from '@backstage/plugin-permission-node'; import { policyExtensionPoint } from '@backstage/plugin-permission-node/alpha'; class CustomPermissionPolicy implements PermissionPolicy { async handle( request: PolicyQuery, - user?: BackstageIdentityResponse, + user?: PolicyQueryUser, ): Promise { // TODO: Add code here that inspects the incoming request and user, and returns AuthorizeResult.ALLOW, AuthorizeResult.DENY, or AuthorizeResult.CONDITIONAL as needed. See the docs at https://backstage.io/docs/permissions/writing-a-policy for more information diff --git a/docs/features/kubernetes/proxy.md b/docs/features/kubernetes/proxy.md index 2da797d8ef..85ad86f83b 100644 --- a/docs/features/kubernetes/proxy.md +++ b/docs/features/kubernetes/proxy.md @@ -60,7 +60,6 @@ This feature assumes your backstage instance has enabled the [permissions framew A sample policy like: ```typescript -import { BackstageIdentityResponse } from '@backstage/plugin-auth-node'; import { AuthorizeResult, PolicyDecision, @@ -68,12 +67,13 @@ import { import { PermissionPolicy, PolicyQuery, + PolicyQueryUser, } from '@backstage/plugin-permission-node'; class KubernetesDenyAllProxyEndpointPolicy implements PermissionPolicy { async handle( request: PolicyQuery, - user?: BackstageIdentityResponse, + user?: PolicyQueryUser, ): Promise { if (request.permission.name === 'kubernetes.proxy') { return { diff --git a/docs/features/software-templates/authorizing-scaffolder-template-details.md b/docs/features/software-templates/authorizing-scaffolder-template-details.md index 127677757c..942431c993 100644 --- a/docs/features/software-templates/authorizing-scaffolder-template-details.md +++ b/docs/features/software-templates/authorizing-scaffolder-template-details.md @@ -66,14 +66,14 @@ import { class ExamplePermissionPolicy implements PermissionPolicy { async handle( request: PolicyQuery, - user?: BackstageIdentityResponse, + user?: PolicyQueryUser, ): Promise { /* highlight-add-start */ if ( isPermission(request.permission, templateParameterReadPermission) || isPermission(request.permission, templateStepReadPermission) ) { - if (user?.identity.userEntityRef === 'user:default/spiderman') + if (user?.info.userEntityRef === 'user:default/spiderman') return createScaffolderTemplateConditionalDecision(request.permission, { not: scaffolderTemplateConditions.hasTag({ tag: 'secret' }), }); @@ -109,11 +109,11 @@ import { class ExamplePermissionPolicy implements PermissionPolicy { async handle( request: PolicyQuery, - user?: BackstageIdentityResponse, + user?: PolicyQueryUser, ): Promise { /* highlight-add-start */ if (isPermission(request.permission, actionExecutePermission)) { - if (user?.identity.userEntityRef === 'user:default/spiderman') { + if (user?.info.userEntityRef === 'user:default/spiderman') { return createScaffolderActionConditionalDecision(request.permission, { not: scaffolderActionConditions.hasActionId({ actionId: 'debug:log', @@ -147,11 +147,11 @@ import { class ExamplePermissionPolicy implements PermissionPolicy { async handle( request: PolicyQuery, - user?: BackstageIdentityResponse, + user?: PolicyQueryUser, ): Promise { /* highlight-add-start */ if (isPermission(request.permission, actionExecutePermission)) { - if (user?.identity.userEntityRef === 'user:default/spiderman') { + if (user?.info.userEntityRef === 'user:default/spiderman') { return createScaffolderActionConditionalDecision(request.permission, { not: { allOf: [ @@ -190,25 +190,25 @@ import { class ExamplePermissionPolicy implements PermissionPolicy { async handle( request: PolicyQuery, - user?: BackstageIdentityResponse, + user?: PolicyQueryUser, ): Promise { /* highlight-add-start */ if (isPermission(request.permission, taskCreatePermission)) { - if (user?.identity.userEntityRef === 'user:default/spiderman') { + if (user?.info.userEntityRef === 'user:default/spiderman') { return { result: AuthorizeResult.ALLOW, }; } } if (isPermission(request.permission, taskCancelPermission)) { - if (user?.identity.userEntityRef === 'user:default/spiderman') { + if (user?.info.userEntityRef === 'user:default/spiderman') { return { result: AuthorizeResult.ALLOW, }; } } if (isPermission(request.permission, taskReadPermission)) { - if (user?.identity.userEntityRef === 'user:default/spiderman') { + if (user?.info.userEntityRef === 'user:default/spiderman') { return { result: AuthorizeResult.ALLOW, }; @@ -239,7 +239,6 @@ Instead of the changes in `permission.ts` noted in the above example you will ma ```ts title="packages/backend/src/index.ts" import { createBackendModule } from '@backstage/backend-plugin-api'; -import { BackstageIdentityResponse } from '@backstage/plugin-auth-node'; import { PolicyDecision, AuthorizeResult, @@ -247,13 +246,14 @@ import { import { PermissionPolicy, PolicyQuery, + PolicyQueryUser, } from '@backstage/plugin-permission-node'; import { policyExtensionPoint } from '@backstage/plugin-permission-node/alpha'; class ExamplePermissionPolicy implements PermissionPolicy { async handle( request: PolicyQuery, - user?: BackstageIdentityResponse, + user?: PolicyQueryUser, ): Promise { // Various scaffolder permission checks ... diff --git a/docs/permissions/custom-rules.md b/docs/permissions/custom-rules.md index 9063ed7257..57565755fb 100644 --- a/docs/permissions/custom-rules.md +++ b/docs/permissions/custom-rules.md @@ -66,9 +66,8 @@ import { catalogConditions, createCatalogConditionalDecision, createCatalogPermi /* highlight-remove-next-line */ import { createConditionFactory } from '@backstage/plugin-permission-node'; /* highlight-add-next-line */ -import { PermissionPolicy, PolicyQuery, createConditionFactory } from '@backstage/plugin-permission-node'; +import { PermissionPolicy, PolicyQuery, PolicyQueryUser, createConditionFactory } from '@backstage/plugin-permission-node'; /* highlight-add-start */ -import { BackstageIdentityResponse } from '@backstage/plugin-auth-node'; import { AuthorizeResult, PolicyDecision, isResourcePermission } from '@backstage/plugin-permission-common'; /* highlight-add-end */ ... @@ -102,21 +101,21 @@ const isInSystem = createConditionFactory(isInSystemRule); class TestPermissionPolicy implements PermissionPolicy { async handle( request: PolicyQuery, - user?: BackstageIdentityResponse, + user?: PolicyQueryUser, ): Promise { if (isResourcePermission(request.permission, 'catalog-entity')) { return createCatalogConditionalDecision( request.permission, /* highlight-remove-start */ catalogConditions.isEntityOwner({ - claims: user?.identity.ownershipEntityRefs ?? [], + claims: user?.info.ownershipEntityRefs ?? [], }), /* highlight-remove-end */ /* highlight-add-start */ { anyOf: [ catalogConditions.isEntityOwner({ - claims: user?.identity.ownershipEntityRefs ?? [], + claims: user?.info.ownershipEntityRefs ?? [], }), isInSystem({ systemRef: 'interviewing' }), ], diff --git a/docs/permissions/plugin-authors/02-adding-a-basic-permission-check.md b/docs/permissions/plugin-authors/02-adding-a-basic-permission-check.md index aacd60af8c..724edb7ccb 100644 --- a/docs/permissions/plugin-authors/02-adding-a-basic-permission-check.md +++ b/docs/permissions/plugin-authors/02-adding-a-basic-permission-check.md @@ -169,15 +169,12 @@ Before running this step, please make sure you followed the steps described in [ In order to test the logic above, the integrators of your backstage instance need to change their permission policy to return `DENY` for our newly-created permission: ```ts title="packages/backend/src/plugins/permission.ts" -/* highlight-add-start */ -import { - BackstageIdentityResponse, -} from '@backstage/plugin-auth-node'; -/* highlight-add-end */ import { PermissionPolicy, - /* highlight-add-next-line */ + /* highlight-add-start */ PolicyQuery, + PolicyQueryUser, + /* highlight-add-end */ } from '@backstage/plugin-permission-node'; /* highlight-add-start */ import { isPermission } from '@backstage/plugin-permission-common'; @@ -190,7 +187,7 @@ class TestPermissionPolicy implements PermissionPolicy { /* highlight-add-start */ async handle( request: PolicyQuery, - _user?: BackstageIdentityResponse, + _user?: PolicyQueryUser, ): Promise { if (isPermission(request.permission, todoListCreatePermission)) { return { diff --git a/docs/permissions/plugin-authors/03-adding-a-resource-permission-check.md b/docs/permissions/plugin-authors/03-adding-a-resource-permission-check.md index b3aeb13a68..7ad551e926 100644 --- a/docs/permissions/plugin-authors/03-adding-a-resource-permission-check.md +++ b/docs/permissions/plugin-authors/03-adding-a-resource-permission-check.md @@ -237,12 +237,12 @@ Let's go back to the permission policy's handle function and try to authorize ou ```ts title="packages/backend/src/plugins/permission.ts" import { - BackstageIdentityResponse, IdentityClient } from '@backstage/plugin-auth-node'; import { PermissionPolicy, PolicyQuery, + PolicyQueryUser, } from '@backstage/plugin-permission-node'; import { isPermission } from '@backstage/plugin-permission-common'; /* highlight-remove-next-line */ @@ -262,9 +262,9 @@ import { async handle( request: PolicyQuery, /* highlight-remove-next-line */ - _user?: BackstageIdentityResponse, + _user?: PolicyQueryUser, /* highlight-add-next-line */ - user?: BackstageIdentityResponse, + user?: PolicyQueryUser, ): Promise { if (isPermission(request.permission, todoListCreatePermission)) { return { @@ -276,7 +276,7 @@ async handle( return createTodoListConditionalDecision( request.permission, todoListConditions.isOwner({ - userId: user?.identity.userEntityRef ?? '', + userId: user?.info.userEntityRef ?? '', }), ); } diff --git a/docs/permissions/writing-a-policy.md b/docs/permissions/writing-a-policy.md index 3d4371f038..0f2d4fe091 100644 --- a/docs/permissions/writing-a-policy.md +++ b/docs/permissions/writing-a-policy.md @@ -10,7 +10,10 @@ That policy looked like this: ```typescript title="packages/backend/src/plugins/permission.ts" class TestPermissionPolicy implements PermissionPolicy { - async handle(request: PolicyQuery): Promise { + async handle( + request: PolicyQuery, + _user?: PolicyQueryUser, + ): Promise { if (request.permission.name === 'catalog.entity.delete') { return { result: AuthorizeResult.DENY, @@ -35,14 +38,6 @@ As we confirmed in the previous section, we know that this now prevents us from Let's change the policy to the following: ```ts -/* highlight-remove-next-line */ -import { IdentityClient } from '@backstage/plugin-auth-node'; -/* highlight-add-start */ -import { - BackstageIdentityResponse, - IdentityClient -} from '@backstage/plugin-auth-node'; - /* highlight-add-end */ import { AuthorizeResult, PolicyDecision, @@ -65,7 +60,7 @@ class TestPermissionPolicy implements PermissionPolicy { /* highlight-add-start */ async handle( request: PolicyQuery, - user?: BackstageIdentityResponse, + user?: PolicyQueryUser, ): Promise { /* highlight-add-end */ /* highlight-remove-next-line */ @@ -81,7 +76,7 @@ class TestPermissionPolicy implements PermissionPolicy { return createCatalogConditionalDecision( request.permission, catalogConditions.isEntityOwner({ - claims: user?.identity.ownershipEntityRefs ?? [], + claims: user?.info.ownershipEntityRefs ?? [], }), ); /* highlight-add-end */ @@ -95,7 +90,7 @@ Let's walk through the new code that we just added. Instead of returning an Definitive Policy Decision, we use factory methods to construct a [Conditional Policy Decision](https://backstage.io/docs/reference/plugin-permission-common.conditionalpolicydecision) (See the [Concepts page](./concepts.md) for more details). Since the policy doesn't have enough information to determine if `user` is the entity owner, this criteria is encapsulated within the conditional decision. However, `createCatalogConditionalDecision` will not compile unless `request.permission` is a catalog entity [`ResourcePermission`](https://backstage.io/docs/reference/plugin-permission-common.resourcepermission). This type constraint ensures that policies return conditional decisions that are compatible with the requested permission. To address this, we use [`isPermission`](https://backstage.io/docs/reference/plugin-permission-common.ispermission) to ["narrow"](https://www.typescriptlang.org/docs/handbook/2/narrowing.html) the type of `request.permission` to `ResourcePermission<'catalog-entity'>`. This matches the runtime behavior that was in place before, but you'll notice that the type of `request.permission` has changed within the scope of that `if` statement. -The `catalogConditions` object contains all of the rules defined by the catalog plugin. These rules can be combined to form a [`PermissionCriteria`](https://backstage.io/docs/reference/plugin-permission-common.permissioncriteria) object, but for this case we only need to use the `isEntityOwner` rule. This rule accepts a list of entity refs that represent User identity and Group membership used to determine ownership. The second argument to `PermissionPolicy#handle` provides us with a `BackstageIdentityResponse` object, from which we can grab the user's `ownershipEntityRefs`. We provide an empty array as a fallback since the user may be anonymous. +The `catalogConditions` object contains all of the rules defined by the catalog plugin. These rules can be combined to form a [`PermissionCriteria`](https://backstage.io/docs/reference/plugin-permission-common.permissioncriteria) object, but for this case we only need to use the `isEntityOwner` rule. This rule accepts a list of entity refs that represent User identity and Group membership used to determine ownership. The second argument to `PermissionPolicy#handle` provides us with a `PolicyQueryUser` object, from which we can grab the user's `ownershipEntityRefs`. We provide an empty array as a fallback since the user may be anonymous. You should now be able to see in your Backstage app that the unregister entity button is enabled for entities that you own, but disabled for all other entities! @@ -125,7 +120,7 @@ import { class TestPermissionPolicy implements PermissionPolicy { async handle( request: PolicyQuery, - user?: BackstageIdentityResponse, + user?: PolicyQueryUser, ): Promise { /* highlight-remove-next-line */ if (isPermission(request.permission, catalogEntityDeletePermission)) { @@ -134,7 +129,7 @@ class TestPermissionPolicy implements PermissionPolicy { return createCatalogConditionalDecision( request.permission, catalogConditions.isEntityOwner({ - claims: user?.identity.ownershipEntityRefs ?? [], + claims: user?.info.ownershipEntityRefs ?? [], }), ); } diff --git a/plugins/permission-backend-module-policy-allow-all/src/policy.ts b/plugins/permission-backend-module-policy-allow-all/src/policy.ts index da853e47db..90ae21f341 100644 --- a/plugins/permission-backend-module-policy-allow-all/src/policy.ts +++ b/plugins/permission-backend-module-policy-allow-all/src/policy.ts @@ -14,7 +14,6 @@ * limitations under the License. */ -import { BackstageIdentityResponse } from '@backstage/plugin-auth-node'; import { AuthorizeResult, PolicyDecision, @@ -22,12 +21,13 @@ import { import { PermissionPolicy, PolicyQuery, + PolicyQueryUser, } from '@backstage/plugin-permission-node'; export class AllowAllPermissionPolicy implements PermissionPolicy { async handle( _request: PolicyQuery, - _user?: BackstageIdentityResponse, + _user?: PolicyQueryUser, ): Promise { return { result: AuthorizeResult.ALLOW, diff --git a/plugins/permission-backend/src/service/router.test.ts b/plugins/permission-backend/src/service/router.test.ts index be90c5f628..f12bacc61d 100644 --- a/plugins/permission-backend/src/service/router.test.ts +++ b/plugins/permission-backend/src/service/router.test.ts @@ -186,6 +186,13 @@ describe('createRouter', () => { mockCredentials.user().principal.userEntityRef, ], }, + info: { + userEntityRef: mockCredentials.user().principal.userEntityRef, + ownershipEntityRefs: [ + mockCredentials.user().principal.userEntityRef, + ], + }, + credentials: mockCredentials.user(), }, ); expect(response.body).toEqual({ diff --git a/plugins/permission-backend/src/service/router.ts b/plugins/permission-backend/src/service/router.ts index cc45d0b41a..fd33f0b629 100644 --- a/plugins/permission-backend/src/service/router.ts +++ b/plugins/permission-backend/src/service/router.ts @@ -22,10 +22,7 @@ import { errorHandler, } from '@backstage/backend-common'; import { InputError } from '@backstage/errors'; -import { - BackstageIdentityResponse, - IdentityApi, -} from '@backstage/plugin-auth-node'; +import { IdentityApi } from '@backstage/plugin-auth-node'; import { AuthorizeResult, EvaluatePermissionRequest, @@ -40,6 +37,7 @@ import { ApplyConditionsRequestEntry, ApplyConditionsResponseEntry, PermissionPolicy, + PolicyQueryUser, } from '@backstage/plugin-permission-node'; import { PermissionIntegrationClient } from './PermissionIntegrationClient'; import { memoize } from 'lodash'; @@ -130,9 +128,9 @@ const handleRequest = async ( ); }); - let user: BackstageIdentityResponse | undefined; + let user: PolicyQueryUser | undefined; if (auth.isPrincipal(credentials, 'user')) { - const { ownershipEntityRefs } = await userInfo.getUserInfo(credentials); + const info = await userInfo.getUserInfo(credentials); const { token } = await auth.getPluginRequestToken({ onBehalfOf: credentials, targetPluginId: 'catalog', // TODO: unknown at this point @@ -141,9 +139,11 @@ const handleRequest = async ( identity: { type: 'user', userEntityRef: credentials.principal.userEntityRef, - ownershipEntityRefs, + ownershipEntityRefs: info.ownershipEntityRefs, }, token, + credentials, + info, }; } diff --git a/plugins/permission-node/api-report.md b/plugins/permission-node/api-report.md index 290c586f2c..81460ef630 100644 --- a/plugins/permission-node/api-report.md +++ b/plugins/permission-node/api-report.md @@ -8,7 +8,9 @@ import { AnyOfCriteria } from '@backstage/plugin-permission-common'; import { AuthorizePermissionRequest } from '@backstage/plugin-permission-common'; import { AuthorizePermissionResponse } from '@backstage/plugin-permission-common'; import { AuthService } from '@backstage/backend-plugin-api'; -import { BackstageIdentityResponse } from '@backstage/plugin-auth-node'; +import { BackstageCredentials } from '@backstage/backend-plugin-api'; +import { BackstageUserIdentity } from '@backstage/plugin-auth-node'; +import { BackstageUserInfo } from '@backstage/backend-plugin-api'; import { ConditionalPolicyDecision } from '@backstage/plugin-permission-common'; import { Config } from '@backstage/config'; import { DefinitivePolicyDecision } from '@backstage/plugin-permission-common'; @@ -246,10 +248,7 @@ export type PermissionIntegrationRouterOptions< // @public export interface PermissionPolicy { // (undocumented) - handle( - request: PolicyQuery, - user?: BackstageIdentityResponse, - ): Promise; + handle(request: PolicyQuery, user?: PolicyQueryUser): Promise; } // @public @@ -272,6 +271,15 @@ export type PolicyQuery = { permission: Permission; }; +// @public +export type PolicyQueryUser = { + token: string; + expiresInSeconds?: number; + identity: BackstageUserIdentity; + credentials: BackstageCredentials; + info: BackstageUserInfo; +}; + // @public export class ServerPermissionClient implements PermissionsService { // (undocumented) diff --git a/plugins/permission-node/src/policy/index.ts b/plugins/permission-node/src/policy/index.ts index f151cfb4fb..fd47ed7e62 100644 --- a/plugins/permission-node/src/policy/index.ts +++ b/plugins/permission-node/src/policy/index.ts @@ -14,4 +14,4 @@ * limitations under the License. */ -export type { PermissionPolicy, PolicyQuery } from './types'; +export type { PermissionPolicy, PolicyQuery, PolicyQueryUser } from './types'; diff --git a/plugins/permission-node/src/policy/types.ts b/plugins/permission-node/src/policy/types.ts index 0f469cfbfe..a7b8b75218 100644 --- a/plugins/permission-node/src/policy/types.ts +++ b/plugins/permission-node/src/policy/types.ts @@ -18,7 +18,11 @@ import { Permission, PolicyDecision, } from '@backstage/plugin-permission-common'; -import { BackstageIdentityResponse } from '@backstage/plugin-auth-node'; +import { BackstageUserIdentity } from '@backstage/plugin-auth-node'; +import { + BackstageCredentials, + BackstageUserInfo, +} from '@backstage/backend-plugin-api'; /** * A query to be evaluated by the {@link PermissionPolicy}. @@ -34,6 +38,44 @@ export type PolicyQuery = { permission: Permission; }; +/** + * The context within which a policy query is evaluated. + * + * @public + */ +export type PolicyQueryUser = { + /** + * The token used to authenticate the user within Backstage. + * + * @deprecated User the `credentials` field in combination with `coreServices.auth` to generate a request token instead. + */ + token: string; + + /** + * The number of seconds until the token expires. If not set, it can be assumed that the token does not expire. + * + * @deprecated This field is deprecated and will be removed in a future release. + */ + expiresInSeconds?: number; + + /** + * A plaintext description of the identity that is encapsulated within the token. + * + * @deprecated Use the `info` field instead. + */ + identity: BackstageUserIdentity; + + /** + * The credentials of the user making the request. + */ + credentials: BackstageCredentials; + + /** + * The information for the user making the request. + */ + info: BackstageUserInfo; +}; + /** * A policy to evaluate authorization requests for any permissioned action performed in Backstage. * @@ -51,8 +93,5 @@ export type PolicyQuery = { * @public */ export interface PermissionPolicy { - handle( - request: PolicyQuery, - user?: BackstageIdentityResponse, - ): Promise; + handle(request: PolicyQuery, user?: PolicyQueryUser): Promise; } From 4d7e11f0149b5940fc43b79e2d4d0fa08af4ad8f Mon Sep 17 00:00:00 2001 From: Frank Kong <50030060+Zaperex@users.noreply.github.com> Date: Fri, 12 Jul 2024 10:06:01 -0400 Subject: [PATCH 240/416] chore(scaffolder): allow task viewer to be resizable and disable rendering of empty output (#25495) chore(scaffolder): allow task viewer to be resizable and disable rendering of empty output (#25495) --- .changeset/four-donuts-switch.md | 5 +++ .changeset/witty-keys-share.md | 5 +++ .../DefaultTemplateOutputs.test.tsx | 21 +++++++++-- .../DefaultTemplateOutputs.tsx | 35 ++++++++++++------- plugins/scaffolder/package.json | 2 ++ .../components/OngoingTask/OngoingTask.tsx | 5 +-- yarn.lock | 13 ++++++- 7 files changed, 68 insertions(+), 18 deletions(-) create mode 100644 .changeset/four-donuts-switch.md create mode 100644 .changeset/witty-keys-share.md diff --git a/.changeset/four-donuts-switch.md b/.changeset/four-donuts-switch.md new file mode 100644 index 0000000000..bb876a4341 --- /dev/null +++ b/.changeset/four-donuts-switch.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder': patch +--- + +enable resizing of the task log stream viewer diff --git a/.changeset/witty-keys-share.md b/.changeset/witty-keys-share.md new file mode 100644 index 0000000000..0ef89e56e2 --- /dev/null +++ b/.changeset/witty-keys-share.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-react': patch +--- + +disables rendering of output box if no output is returned diff --git a/plugins/scaffolder-react/src/next/components/TemplateOutputs/DefaultTemplateOutputs.test.tsx b/plugins/scaffolder-react/src/next/components/TemplateOutputs/DefaultTemplateOutputs.test.tsx index 4c631b86b0..7ec3b0867c 100644 --- a/plugins/scaffolder-react/src/next/components/TemplateOutputs/DefaultTemplateOutputs.test.tsx +++ b/plugins/scaffolder-react/src/next/components/TemplateOutputs/DefaultTemplateOutputs.test.tsx @@ -31,7 +31,7 @@ describe('', () => { ], }; - const { getByRole } = await renderInTestApp( + const { getByRole, queryByTestId } = await renderInTestApp( , { mountedRoutes: { @@ -39,7 +39,8 @@ describe('', () => { }, }, ); - + expect(queryByTestId('output-box')).not.toBeNull(); + expect(queryByTestId('text-output-box')).not.toBeNull(); // first text output default visible expect(getByRole('heading', { level: 2 }).innerHTML).toBe( output.text[0].title, @@ -61,4 +62,20 @@ describe('', () => { expect(getByRole('heading', { level: 2 }).innerHTML).toBe(text.title); } }); + it('should not render anything when output is empty', async () => { + // This is the default case when no output field is present in the template + const output = {}; + const { queryByTestId } = await renderInTestApp( + , + { + mountedRoutes: { + '/catalog/:namespace/:kind/:name': entityRouteRef, + }, + }, + ); + + // Ensure that nothing renders from this component + expect(queryByTestId('output-box')).toBeNull(); + expect(queryByTestId('text-output-box')).toBeNull(); + }); }); diff --git a/plugins/scaffolder-react/src/next/components/TemplateOutputs/DefaultTemplateOutputs.tsx b/plugins/scaffolder-react/src/next/components/TemplateOutputs/DefaultTemplateOutputs.tsx index 7d90623077..cbc299bf1c 100644 --- a/plugins/scaffolder-react/src/next/components/TemplateOutputs/DefaultTemplateOutputs.tsx +++ b/plugins/scaffolder-react/src/next/components/TemplateOutputs/DefaultTemplateOutputs.tsx @@ -56,22 +56,31 @@ export const DefaultTemplateOutputs = (props: { return null; } + const emptyOutput = Object.keys(output).length === 0; + return ( <> - - - - - - - - + {!emptyOutput ? ( + + + + + + + + + ) : null} {textOutput ? ( - + + - + ) : null} diff --git a/yarn.lock b/yarn.lock index afe89e4263..b0bff82017 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7314,6 +7314,7 @@ __metadata: "@types/humanize-duration": ^3.18.1 "@types/json-schema": ^7.0.9 "@types/react": ^16.13.1 || ^17.0.0 || ^18.0.0 + "@types/react-resizable": ^3.0.8 "@types/react-window": ^1.8.8 "@uiw/react-codemirror": ^4.9.3 classnames: ^2.2.6 @@ -7326,6 +7327,7 @@ __metadata: luxon: ^3.0.0 msw: ^1.0.0 qs: ^6.9.4 + react-resizable: ^3.0.5 react-use: ^17.2.4 react-window: ^1.8.10 swr: ^2.0.0 @@ -18461,6 +18463,15 @@ __metadata: languageName: node linkType: hard +"@types/react-resizable@npm:^3.0.8": + version: 3.0.8 + resolution: "@types/react-resizable@npm:3.0.8" + dependencies: + "@types/react": "*" + checksum: aabdef8056bbab3065559bce7ce93232e645fb4f915fd55f0903a2f4df5d2395762dfd75bb0242d5a73d39461e8c062d81eaab87b91213dddfd973ff908f79e4 + languageName: node + linkType: hard + "@types/react-sparklines@npm:^1.7.0": version: 1.7.5 resolution: "@types/react-sparklines@npm:1.7.5" @@ -38371,7 +38382,7 @@ __metadata: languageName: node linkType: hard -"react-resizable@npm:^3.0.4": +"react-resizable@npm:^3.0.4, react-resizable@npm:^3.0.5": version: 3.0.5 resolution: "react-resizable@npm:3.0.5" dependencies: From 842457d9ad2d2be4f43c6f859f6e4198e1f2f24e Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Fri, 12 Jul 2024 16:14:59 +0200 Subject: [PATCH 241/416] docs: update root logger service docs Signed-off-by: Camila Belo --- docs/backend-system/core-services/logger.md | 44 ------------------- .../core-services/root-logger.md | 44 ++++++++++++++++++- 2 files changed, 43 insertions(+), 45 deletions(-) diff --git a/docs/backend-system/core-services/logger.md b/docs/backend-system/core-services/logger.md index 015d2055d5..e18bd6a4c0 100644 --- a/docs/backend-system/core-services/logger.md +++ b/docs/backend-system/core-services/logger.md @@ -31,47 +31,3 @@ createBackendPlugin({ }, }); ``` - -## Root Logger - -The root logger is the logger that is used by other root services. It's where the implementation lies for creating child loggers around the backstage ecosystem including child loggers for plugins with the correct metadata and annotations. - -If you want to override the implementation for logging across all of the backend, this is the service that you should override. - -## Configuring the service - -The following example is how you can override the root logger service to add additional metadata to all log lines. - -```ts -import { coreServices } from '@backstage/backend-plugin-api'; -import { WinstonLogger } from '@backstage/backend-app-api'; - -const backend = createBackend(); - -backend.add( - createServiceFactory({ - service: coreServices.rootLogger, - deps: { - config: coreServices.rootConfig, - }, - async factory({ config }) { - const logger = WinstonLogger.create({ - meta: { - service: 'backstage', - // here's some additional information that is not part of the - // original implementation - podName: 'myk8spod', - }, - level: process.env.LOG_LEVEL || 'info', - format: - process.env.NODE_ENV === 'production' - ? format.json() - : WinstonLogger.colorFormat(), - transports: [new transports.Console()], - }); - - return logger; - }, - }), -); -``` diff --git a/docs/backend-system/core-services/root-logger.md b/docs/backend-system/core-services/root-logger.md index 09b7929efe..733b7b8277 100644 --- a/docs/backend-system/core-services/root-logger.md +++ b/docs/backend-system/core-services/root-logger.md @@ -5,4 +5,46 @@ sidebar_label: Root Logger description: Documentation for the Root Logger service --- -TODO +## Root Logger + +The root logger is the logger that is used by other root services. It's where the implementation lies for creating child loggers around the backstage ecosystem including child loggers for plugins with the correct metadata and annotations. + +If you want to override the implementation for logging across all of the backend, this is the service that you should override. + +## Configuring the service + +The following example is how you can override the root logger service to add additional metadata to all log lines. + +```ts +import { coreServices } from '@backstage/backend-plugin-api'; +import { WinstonLogger } from '@backstage/backend-app-api'; + +const backend = createBackend(); + +backend.add( + createServiceFactory({ + service: coreServices.rootLogger, + deps: { + config: coreServices.rootConfig, + }, + async factory({ config }) { + const logger = WinstonLogger.create({ + meta: { + service: 'backstage', + // here's some additional information that is not part of the + // original implementation + podName: 'myk8spod', + }, + level: process.env.LOG_LEVEL || 'info', + format: + process.env.NODE_ENV === 'production' + ? format.json() + : WinstonLogger.colorFormat(), + transports: [new transports.Console()], + }); + + return logger; + }, + }), +); +``` From dae85dfd213b1711fd850e48777361065725b1e4 Mon Sep 17 00:00:00 2001 From: parmar-abhinav Date: Sat, 13 Jul 2024 14:07:56 +0530 Subject: [PATCH 242/416] Add examples for fetch:cookiecutter scaffolder action & improve related tests Signed-off-by: parmar-abhinav --- .changeset/stupid-dots-relate.md | 5 + .../package.json | 1 + .../fetch/cookiecutter.examples.test.ts | 274 ++++++++++++++++++ .../actions/fetch/cookiecutter.examples.ts | 119 ++++++++ .../src/actions/fetch/cookiecutter.ts | 2 + 5 files changed, 401 insertions(+) create mode 100644 .changeset/stupid-dots-relate.md create mode 100644 plugins/scaffolder-backend-module-cookiecutter/src/actions/fetch/cookiecutter.examples.test.ts create mode 100644 plugins/scaffolder-backend-module-cookiecutter/src/actions/fetch/cookiecutter.examples.ts diff --git a/.changeset/stupid-dots-relate.md b/.changeset/stupid-dots-relate.md new file mode 100644 index 0000000000..a83777bff9 --- /dev/null +++ b/.changeset/stupid-dots-relate.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend-module-cookiecutter': patch +--- + +Add examples for `fetch:cookiecutter` scaffolder action & improve related tests diff --git a/plugins/scaffolder-backend-module-cookiecutter/package.json b/plugins/scaffolder-backend-module-cookiecutter/package.json index 43a7e348a4..261010f681 100644 --- a/plugins/scaffolder-backend-module-cookiecutter/package.json +++ b/plugins/scaffolder-backend-module-cookiecutter/package.json @@ -53,6 +53,7 @@ "command-exists": "^1.2.9", "fs-extra": "^11.2.0", "winston": "^3.2.1", + "yaml": "^2.0.0", "yn": "^4.0.0" }, "devDependencies": { diff --git a/plugins/scaffolder-backend-module-cookiecutter/src/actions/fetch/cookiecutter.examples.test.ts b/plugins/scaffolder-backend-module-cookiecutter/src/actions/fetch/cookiecutter.examples.test.ts new file mode 100644 index 0000000000..ae46ef1bd6 --- /dev/null +++ b/plugins/scaffolder-backend-module-cookiecutter/src/actions/fetch/cookiecutter.examples.test.ts @@ -0,0 +1,274 @@ +/* + * 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 { UrlReader, ContainerRunner } from '@backstage/backend-common'; +import { ConfigReader } from '@backstage/config'; +import { JsonObject } from '@backstage/types'; +import { ScmIntegrations } from '@backstage/integration'; +import { createMockDirectory } from '@backstage/backend-test-utils'; +import { createFetchCookiecutterAction } from './cookiecutter'; +import { join } from 'path'; +import type { ActionContext } from '@backstage/plugin-scaffolder-node'; +import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test-utils'; +import { examples } from './cookiecutter.examples'; +import yaml from 'yaml'; + +const executeShellCommand = jest.fn(); +const commandExists = jest.fn(); +const fetchContents = jest.fn(); + +jest.mock('@backstage/plugin-scaffolder-node', () => ({ + ...jest.requireActual('@backstage/plugin-scaffolder-node'), + fetchContents: (...args: any[]) => fetchContents(...args), + executeShellCommand: (...args: any[]) => executeShellCommand(...args), +})); + +jest.mock( + 'command-exists', + () => + (...args: any[]) => + commandExists(...args), +); + +describe('fetch:cookiecutter', () => { + const mockDir = createMockDirectory({ mockOsTmpDir: true }); + const integrations = ScmIntegrations.fromConfig( + new ConfigReader({ + integrations: { + azure: [ + { host: 'dev.azure.com', token: 'tokenlols' }, + { host: 'myazurehostnotoken.com' }, + ], + }, + }), + ); + + const mockTmpDir = mockDir.path; + + let mockContext: ActionContext<{ + url: string; + targetPath?: string; + values: JsonObject; + copyWithoutRender?: string[]; + extensions?: string[]; + imageName?: string; + }>; + + const containerRunner: jest.Mocked = { + runContainer: jest.fn(), + }; + + const mockReader: UrlReader = { + readUrl: jest.fn(), + readTree: jest.fn(), + search: jest.fn(), + }; + + const action = createFetchCookiecutterAction({ + integrations, + containerRunner, + reader: mockReader, + }); + + beforeEach(() => { + jest.resetAllMocks(); + + mockContext = createMockActionContext({ + input: { + url: 'https://google.com/cookie/cutter', + targetPath: 'something', + values: { + help: 'me', + }, + }, + templateInfo: { + entityRef: 'template:default/cookiecutter', + baseUrl: 'somebase', + }, + workspacePath: mockTmpDir, + }); + mockDir.setContent({ template: {} }); + + commandExists.mockResolvedValue(null); + + // Mock when run container is called it creates some new files in the mock filesystem + containerRunner.runContainer.mockImplementation(async () => { + mockDir.setContent({ + 'intermediate/testfile.json': '{}', + }); + }); + + // Mock when executeShellCommand is called it creates some new files in the mock filesystem + executeShellCommand.mockImplementation(async () => { + mockDir.setContent({ + 'intermediate/testfile.json': '{}', + }); + }); + }); + + it(`should ${examples[0].description}`, async () => { + const input = yaml.parse(examples[0].example).steps[0].input; + + commandExists.mockResolvedValue(false); + + fetchContents.mockImplementation(() => Promise.resolve()); + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(fetchContents).toHaveBeenCalledWith( + expect.objectContaining({ + reader: mockReader, + integrations, + baseUrl: mockContext.templateInfo?.baseUrl, + fetchUrl: mockContext.input.url, + outputPath: join( + mockTmpDir, + 'template', + "{{cookiecutter and 'contents'}}", + ), + }), + ); + expect(containerRunner.runContainer).toHaveBeenCalled(); + }); + + it(`should ${examples[1].description}`, async () => { + const input = yaml.parse(examples[1].example).steps[0].input; + + commandExists.mockResolvedValue(false); + + fetchContents.mockImplementation(() => Promise.resolve()); + + await action.handler({ + ...mockContext, + input: input, + }); + + expect(fetchContents).toHaveBeenCalledWith( + expect.objectContaining({ + reader: mockReader, + integrations, + baseUrl: mockContext.templateInfo?.baseUrl, + fetchUrl: mockContext.input.url, + outputPath: join( + mockTmpDir, + 'template', + "{{cookiecutter and 'contents'}}", + ), + }), + ); + expect(containerRunner.runContainer).toHaveBeenCalled(); + }); + + it(`should ${examples[2].description}`, async () => { + const input = yaml.parse(examples[2].example).steps[0].input; + + commandExists.mockResolvedValue(false); + + fetchContents.mockImplementation(() => Promise.resolve()); + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(fetchContents).toHaveBeenCalledWith( + expect.objectContaining({ + reader: mockReader, + integrations, + baseUrl: mockContext.templateInfo?.baseUrl, + fetchUrl: mockContext.input.url, + outputPath: join( + mockTmpDir, + 'template', + "{{cookiecutter and 'contents'}}", + ), + }), + ); + + expect(containerRunner.runContainer).toHaveBeenCalled(); + }); + + it(`should ${examples[3].description}`, async () => { + const input = yaml.parse(examples[3].example).steps[0].input; + + commandExists.mockResolvedValue(false); + + fetchContents.mockImplementation(() => Promise.resolve()); + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(fetchContents).toHaveBeenCalledWith( + expect.objectContaining({ + reader: mockReader, + integrations, + baseUrl: mockContext.templateInfo?.baseUrl, + fetchUrl: mockContext.input.url, + outputPath: join( + mockTmpDir, + 'template', + "{{cookiecutter and 'contents'}}", + ), + }), + ); + expect(containerRunner.runContainer).toHaveBeenCalled(); + }); + + it(`should ${examples[4].description}`, async () => { + const input = yaml.parse(examples[4].example).steps[0].input; + + commandExists.mockResolvedValue(false); + + fetchContents.mockImplementation(() => Promise.resolve()); + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(fetchContents).toHaveBeenCalledWith( + expect.objectContaining({ + reader: mockReader, + integrations, + baseUrl: mockContext.templateInfo?.baseUrl, + fetchUrl: mockContext.input.url, + outputPath: join( + mockTmpDir, + 'template', + "{{cookiecutter and 'contents'}}", + ), + }), + ); + expect(containerRunner.runContainer).toHaveBeenCalled(); + }); +}); diff --git a/plugins/scaffolder-backend-module-cookiecutter/src/actions/fetch/cookiecutter.examples.ts b/plugins/scaffolder-backend-module-cookiecutter/src/actions/fetch/cookiecutter.examples.ts new file mode 100644 index 0000000000..6ebada50f0 --- /dev/null +++ b/plugins/scaffolder-backend-module-cookiecutter/src/actions/fetch/cookiecutter.examples.ts @@ -0,0 +1,119 @@ +/* + * 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: 'Fetch and template using cookiecutter with minimal options.', + example: yaml.stringify({ + steps: [ + { + id: 'fetchTemplate', + action: 'fetch:cookiecutter', + name: 'Fetch and Template Using Cookiecutter', + input: { + url: 'https://google.com/cookie/cutter', + values: { + help: 'me', + }, + }, + }, + ], + }), + }, + { + description: + 'Fetch and template using cookiecutter with custom target path.', + example: yaml.stringify({ + steps: [ + { + id: 'fetchTemplate', + action: 'fetch:cookiecutter', + name: 'Fetch and Template Using Cookiecutter', + input: { + url: 'https://google.com/cookie/cutter', + targetPath: 'custom-path', + values: { + help: 'me', + }, + }, + }, + ], + }), + }, + { + description: + 'Fetch and template using cookiecutter with copyWithoutRender.', + example: yaml.stringify({ + steps: [ + { + id: 'fetchTemplate', + action: 'fetch:cookiecutter', + name: 'Fetch and Template Using Cookiecutter', + input: { + url: 'https://google.com/cookie/cutter', + values: { + help: 'me', + }, + copyWithoutRender: ['.github/*', '*.md'], + }, + }, + ], + }), + }, + { + description: + 'Fetch and template using cookiecutter with custom extensions.', + example: yaml.stringify({ + steps: [ + { + id: 'fetchTemplate', + action: 'fetch:cookiecutter', + name: 'Fetch and Template Using Cookiecutter', + input: { + url: 'https://google.com/cookie/cutter', + values: { + help: 'me', + }, + extensions: ['jinja2_time.TimeExtension'], + }, + }, + ], + }), + }, + { + description: + 'Fetch and template using cookiecutter with a custom Docker image.', + example: yaml.stringify({ + steps: [ + { + id: 'fetchTemplate', + action: 'fetch:cookiecutter', + name: 'Fetch and Template Using Cookiecutter', + input: { + url: 'https://google.com/cookie/cutter', + values: { + help: 'me', + }, + imageName: 'custom/cookiecutter-image', + }, + }, + ], + }), + }, +]; diff --git a/plugins/scaffolder-backend-module-cookiecutter/src/actions/fetch/cookiecutter.ts b/plugins/scaffolder-backend-module-cookiecutter/src/actions/fetch/cookiecutter.ts index d170acb5d0..efbe0a07cf 100644 --- a/plugins/scaffolder-backend-module-cookiecutter/src/actions/fetch/cookiecutter.ts +++ b/plugins/scaffolder-backend-module-cookiecutter/src/actions/fetch/cookiecutter.ts @@ -28,6 +28,7 @@ import { fetchContents, executeShellCommand, } from '@backstage/plugin-scaffolder-node'; +import { examples } from './cookiecutter.examples'; export class CookiecutterRunner { private readonly containerRunner?: ContainerRunner; @@ -156,6 +157,7 @@ export function createFetchCookiecutterAction(options: { id: 'fetch:cookiecutter', description: 'Downloads a template from the given URL into the workspace, and runs cookiecutter on it.', + examples, schema: { input: { type: 'object', From 6fc03c7d3ab0b1ff75ea037c113314bf47fecb99 Mon Sep 17 00:00:00 2001 From: parmar-abhinav Date: Sat, 13 Jul 2024 16:06:42 +0530 Subject: [PATCH 243/416] Add examples for notification:send scaffolder action & improve related tests Signed-off-by: parmar-abhinav --- .changeset/cool-insects-remember.md | 5 + .../package.json | 3 +- .../actions/sendNotification.examples.test.ts | 272 ++++++++++++++++++ .../src/actions/sendNotification.examples.ts | 255 ++++++++++++++++ .../src/actions/sendNotification.ts | 2 + 5 files changed, 536 insertions(+), 1 deletion(-) create mode 100644 .changeset/cool-insects-remember.md create mode 100644 plugins/scaffolder-backend-module-notifications/src/actions/sendNotification.examples.test.ts create mode 100644 plugins/scaffolder-backend-module-notifications/src/actions/sendNotification.examples.ts diff --git a/.changeset/cool-insects-remember.md b/.changeset/cool-insects-remember.md new file mode 100644 index 0000000000..ab33015377 --- /dev/null +++ b/.changeset/cool-insects-remember.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend-module-notifications': patch +--- + +Add examples for notification:send scaffolder action & improve related tests diff --git a/plugins/scaffolder-backend-module-notifications/package.json b/plugins/scaffolder-backend-module-notifications/package.json index 7c983c36ce..5e45676f99 100644 --- a/plugins/scaffolder-backend-module-notifications/package.json +++ b/plugins/scaffolder-backend-module-notifications/package.json @@ -38,7 +38,8 @@ "@backstage/plugin-notifications-common": "workspace:^", "@backstage/plugin-notifications-node": "workspace:^", "@backstage/plugin-scaffolder-node": "workspace:^", - "octokit": "^3.0.0" + "octokit": "^3.0.0", + "yaml": "^2.0.0" }, "devDependencies": { "@backstage/cli": "workspace:^", diff --git a/plugins/scaffolder-backend-module-notifications/src/actions/sendNotification.examples.test.ts b/plugins/scaffolder-backend-module-notifications/src/actions/sendNotification.examples.test.ts new file mode 100644 index 0000000000..84473335e0 --- /dev/null +++ b/plugins/scaffolder-backend-module-notifications/src/actions/sendNotification.examples.test.ts @@ -0,0 +1,272 @@ +/* + * Copyright 2024 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 { createSendNotificationAction } from './sendNotification'; +import { NotificationService } from '@backstage/plugin-notifications-node'; +import { TemplateAction } from '@backstage/plugin-scaffolder-node'; +import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test-utils'; +import { examples } from './sendNotification.examples'; +import yaml from 'yaml'; + +describe('notification:send', () => { + const notificationService: jest.Mocked = { + send: jest.fn(), + }; + + let action: TemplateAction; + + beforeEach(() => { + jest.resetAllMocks(); + action = createSendNotificationAction({ + notifications: notificationService, + }); + }); + + const mockContext = createMockActionContext({ + input: { + recipients: 'broadcast', + title: 'Test notification', + }, + }); + + it(`should ${examples[0].description}`, async () => { + const input = yaml.parse(examples[0].example).steps[0].input; + const ctx = Object.assign({}, mockContext, { + input: input, + }); + await action.handler(ctx); + expect(notificationService.send).toHaveBeenCalledWith({ + recipients: { type: 'broadcast' }, + payload: { + title: 'Test notification', + }, + }); + }); + + it(`should ${examples[1].description}`, async () => { + const input = yaml.parse(examples[1].example).steps[0].input; + const ctx = Object.assign({}, mockContext, { + input: input, + }); + await action.handler(ctx); + expect(notificationService.send).toHaveBeenCalledWith({ + recipients: { + entityRef: ['entity:component:1'], + type: 'entity', + }, + payload: { + description: 'A security update has been applied. Please review.', + title: 'Security Update', + link: 'https://example.com/security/update', + severity: 'high', + scope: 'internal', + }, + }); + }); + + it(`should ${examples[2].description}`, async () => { + const input = yaml.parse(examples[2].example).steps[0].input; + const ctx = Object.assign({}, mockContext, { + input: input, + }); + await action.handler(ctx); + expect(notificationService.send).toHaveBeenCalledWith({ + recipients: { + type: 'entity', + entityRef: ['entity:component:1'], + }, + payload: { + description: 'Here is your weekly update.', + link: undefined, + severity: 'low', + scope: undefined, + title: 'Weekly Update', + }, + }); + }); + + it(`should ${examples[3].description}`, async () => { + const input = yaml.parse(examples[3].example).steps[0].input; + const ctx = Object.assign({}, mockContext, { + input: input, + }); + await action.handler(ctx); + expect(notificationService.send).toHaveBeenCalledWith({ + recipients: { type: 'broadcast' }, + payload: { + description: 'Version 2.0.0 is now available. Upgrade now!', + link: undefined, + severity: 'normal', + scope: 'public', + title: 'New Release Available', + }, + }); + }); + + it(`should ${examples[4].description}`, async () => { + const input = yaml.parse(examples[4].example).steps[0].input; + const ctx = Object.assign({}, mockContext, { + input: input, + }); + await action.handler(ctx); + expect(notificationService.send).toHaveBeenCalledWith({ + recipients: { + type: 'entity', + entityRef: ['entity:component:1'], + }, + payload: { + description: + 'A critical bug has been identified. Immediate action required.', + link: undefined, + scope: 'internal', + severity: 'critical', + title: 'Critical Bug Found', + }, + }); + }); + + it(`should ${examples[5].description}`, async () => { + const input = yaml.parse(examples[5].example).steps[0].input; + const ctx = Object.assign({}, mockContext, { + input: input, + }); + await action.handler(ctx); + expect(notificationService.send).toHaveBeenCalledWith({ + recipients: { + type: 'broadcast', + }, + payload: { + description: 'Server maintenance will occur tonight at 11 PM.', + link: undefined, + scope: 'internal', + severity: 'normal', + title: 'Server Maintenance Scheduled', + }, + }); + }); + + it(`should ${examples[6].description}`, async () => { + const input = yaml.parse(examples[6].example).steps[0].input; + const ctx = Object.assign({}, mockContext, { + input: input, + }); + await action.handler(ctx); + expect(notificationService.send).toHaveBeenCalledWith({ + recipients: { type: 'broadcast' }, + payload: { + description: 'New features have been deployed. Explore them now!', + link: undefined, + scope: undefined, + severity: 'normal', + title: 'New Feature Deployment', + }, + }); + }); + + it(`should ${examples[7].description}`, async () => { + const input = yaml.parse(examples[7].example).steps[0].input; + const ctx = Object.assign({}, mockContext, { + input: input, + }); + await action.handler(ctx); + expect(notificationService.send).toHaveBeenCalledWith({ + recipients: { type: 'broadcast' }, + payload: { + description: undefined, + link: undefined, + scope: 'internal', + severity: 'low', + title: 'Holiday Office Closure', + }, + }); + }); + + it(`should ${examples[8].description}`, async () => { + const input = yaml.parse(examples[8].example).steps[0].input; + const ctx = Object.assign({}, mockContext, { + input: input, + }); + await action.handler(ctx); + expect(notificationService.send).toHaveBeenCalledWith({ + recipients: { type: 'broadcast' }, + payload: { + description: + "Don't forget, the weekly meeting is scheduled for tomorrow.", + link: undefined, + scope: 'internal', + severity: undefined, + title: 'Reminder: Weekly Meeting Tomorrow', + }, + }); + }); + + it(`should ${examples[9].description}`, async () => { + const input = yaml.parse(examples[9].example).steps[0].input; + const ctx = Object.assign({}, mockContext, { + input: input, + }); + await action.handler(ctx); + expect(notificationService.send).toHaveBeenCalledWith({ + recipients: { type: 'broadcast' }, + payload: { + title: 'Important Announcement', + description: + 'Please read the latest announcement regarding the upcoming changes.', + link: undefined, + scope: undefined, + severity: 'high', + }, + }); + }); + + it(`should ${examples[10].description}`, async () => { + const input = yaml.parse(examples[10].example).steps[0].input; + const ctx = Object.assign({}, mockContext, { + input: input, + }); + await action.handler(ctx); + expect(notificationService.send).toHaveBeenCalledWith({ + recipients: { type: 'broadcast' }, + payload: { + title: 'Broadcast Notification', + description: 'This is a broadcast notification', + link: undefined, + scope: undefined, + severity: 'low', + }, + }); + }); + + it(`should ${examples[11].description}`, async () => { + const input = yaml.parse(examples[11].example).steps[0].input; + const ctx = Object.assign({}, mockContext, { + input: input, + }); + await action.handler(ctx); + expect(notificationService.send).toHaveBeenCalledWith({ + recipients: { + type: 'entity', + entityRef: ['entity:service1'], + }, + payload: { + title: 'Entity Notification', + description: 'This is a notification for entity service1', + link: undefined, + scope: undefined, + severity: 'normal', + }, + }); + }); +}); diff --git a/plugins/scaffolder-backend-module-notifications/src/actions/sendNotification.examples.ts b/plugins/scaffolder-backend-module-notifications/src/actions/sendNotification.examples.ts new file mode 100644 index 0000000000..05bbd368f8 --- /dev/null +++ b/plugins/scaffolder-backend-module-notifications/src/actions/sendNotification.examples.ts @@ -0,0 +1,255 @@ +/* + * 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 { TemplateExample } from '@backstage/plugin-scaffolder-node'; +import yaml from 'yaml'; + +export const examples: TemplateExample[] = [ + { + description: 'Sends a notification with minimal options', + example: yaml.stringify({ + steps: [ + { + id: 'sendNotification', + action: 'notification:send', + name: 'Send Notification', + input: { + recipients: 'broadcast', + title: 'Test notification', + }, + }, + ], + }), + }, + { + description: 'Sends a notification with entity recipients and link', + example: yaml.stringify({ + steps: [ + { + id: 'sendNotification', + action: 'notification:send', + name: 'Send Notification', + input: { + recipients: 'entity', + entityRefs: ['entity:component:1'], + title: 'Security Update', + info: 'A security update has been applied. Please review.', + link: 'https://example.com/security/update', + severity: 'high', + scope: 'internal', + }, + }, + ], + }), + }, + { + description: + 'Sends a notification with entity recipients and optional flag', + example: yaml.stringify({ + steps: [ + { + id: 'sendNotification', + action: 'notification:send', + name: 'Send Notification', + input: { + recipients: 'entity', + entityRefs: ['entity:component:1'], + title: 'Weekly Update', + info: 'Here is your weekly update.', + severity: 'low', + optional: true, + }, + }, + ], + }), + }, + { + description: + 'Sends a notification with broadcast recipients and custom scope', + example: yaml.stringify({ + steps: [ + { + id: 'sendNotification', + action: 'notification:send', + name: 'Send Notification', + input: { + recipients: 'broadcast', + title: 'New Release Available', + info: 'Version 2.0.0 is now available. Upgrade now!', + severity: 'normal', + scope: 'public', + }, + }, + ], + }), + }, + { + description: + 'Sends a notification with entity recipients and custom severity', + example: yaml.stringify({ + steps: [ + { + id: 'sendNotification', + action: 'notification:send', + name: 'Send Notification', + input: { + recipients: 'entity', + entityRefs: ['entity:component:1'], + title: 'Critical Bug Found', + info: 'A critical bug has been identified. Immediate action required.', + severity: 'critical', + scope: 'internal', + }, + }, + ], + }), + }, + { + description: 'Sends a notification with broadcast recipients and no link', + example: yaml.stringify({ + steps: [ + { + id: 'sendNotification', + action: 'notification:send', + name: 'Send Notification', + input: { + recipients: 'broadcast', + title: 'Server Maintenance Scheduled', + info: 'Server maintenance will occur tonight at 11 PM.', + severity: 'normal', + scope: 'internal', + }, + }, + ], + }), + }, + { + description: + 'Sends a notification with broadcast recipients and optional flag', + example: yaml.stringify({ + steps: [ + { + id: 'sendNotification', + action: 'notification:send', + name: 'Send Notification', + input: { + recipients: 'broadcast', + title: 'New Feature Deployment', + info: 'New features have been deployed. Explore them now!', + severity: 'normal', + optional: true, + }, + }, + ], + }), + }, + { + description: + 'Sends a notification with broadcast recipients and no description', + example: yaml.stringify({ + steps: [ + { + id: 'sendNotification', + action: 'notification:send', + name: 'Send Notification', + input: { + recipients: 'broadcast', + title: 'Holiday Office Closure', + severity: 'low', + scope: 'internal', + }, + }, + ], + }), + }, + { + description: + 'Sends a notification with broadcast recipients and no severity', + example: yaml.stringify({ + steps: [ + { + id: 'sendNotification', + action: 'notification:send', + name: 'Send Notification', + input: { + recipients: 'broadcast', + title: 'Reminder: Weekly Meeting Tomorrow', + info: "Don't forget, the weekly meeting is scheduled for tomorrow.", + scope: 'internal', + }, + }, + ], + }), + }, + { + description: 'Sends a notification with broadcast recipients and no scope', + example: yaml.stringify({ + steps: [ + { + id: 'sendNotification', + action: 'notification:send', + name: 'Send Notification', + input: { + recipients: 'broadcast', + title: 'Important Announcement', + info: 'Please read the latest announcement regarding the upcoming changes.', + severity: 'high', + }, + }, + ], + }), + }, + { + description: 'Sends a notification with optional parameters', + example: yaml.stringify({ + steps: [ + { + id: 'sendNotification', + action: 'notification:send', + name: 'Send Notification', + input: { + recipients: 'broadcast', + title: 'Broadcast Notification', + info: 'This is a broadcast notification', + severity: 'low', + optional: true, + }, + }, + ], + }), + }, + { + description: + 'Sends a notification with entity recipients and optional set to false', + example: yaml.stringify({ + steps: [ + { + id: 'sendNotification', + action: 'notification:send', + name: 'Send Notification to Entity', + input: { + recipients: 'entity', + entityRefs: ['entity:service1'], + title: 'Entity Notification', + info: 'This is a notification for entity service1', + severity: 'normal', + optional: false, + }, + }, + ], + }), + }, +]; diff --git a/plugins/scaffolder-backend-module-notifications/src/actions/sendNotification.ts b/plugins/scaffolder-backend-module-notifications/src/actions/sendNotification.ts index f50e178174..9646de0001 100644 --- a/plugins/scaffolder-backend-module-notifications/src/actions/sendNotification.ts +++ b/plugins/scaffolder-backend-module-notifications/src/actions/sendNotification.ts @@ -22,6 +22,7 @@ import { NotificationSeverity, } from '@backstage/plugin-notifications-common'; import { createTemplateAction } from '@backstage/plugin-scaffolder-node'; +import { examples } from './sendNotification.examples'; /** * @public @@ -42,6 +43,7 @@ export function createSendNotificationAction(options: { }>({ id: 'notification:send', description: 'Sends a notification using NotificationService', + examples, schema: { input: { type: 'object', From 449def7c2c3445f234106becf9e8b74291758ddf Mon Sep 17 00:00:00 2001 From: parmar-abhinav Date: Sat, 13 Jul 2024 17:30:14 +0530 Subject: [PATCH 244/416] Add examples for fetch:rails scaffolder action & improve related tests Signed-off-by: parmar-abhinav --- .changeset/friendly-feet-refuse.md | 5 + .../package.json | 3 +- .../fetch/rails/index.examples.test.ts | 292 ++++++++++++++ .../src/actions/fetch/rails/index.examples.ts | 370 ++++++++++++++++++ .../src/actions/fetch/rails/index.ts | 2 + 5 files changed, 671 insertions(+), 1 deletion(-) create mode 100644 .changeset/friendly-feet-refuse.md create mode 100644 plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/index.examples.test.ts create mode 100644 plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/index.examples.ts diff --git a/.changeset/friendly-feet-refuse.md b/.changeset/friendly-feet-refuse.md new file mode 100644 index 0000000000..677d21d48a --- /dev/null +++ b/.changeset/friendly-feet-refuse.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend-module-rails': patch +--- + +Add examples for fetch:rails scaffolder action & improve related tests diff --git a/plugins/scaffolder-backend-module-rails/package.json b/plugins/scaffolder-backend-module-rails/package.json index c15815d2fa..fb917f4e25 100644 --- a/plugins/scaffolder-backend-module-rails/package.json +++ b/plugins/scaffolder-backend-module-rails/package.json @@ -51,7 +51,8 @@ "@backstage/plugin-scaffolder-node": "workspace:^", "@backstage/types": "workspace:^", "command-exists": "^1.2.9", - "fs-extra": "^11.0.0" + "fs-extra": "^11.0.0", + "yaml": "^2.0.0" }, "devDependencies": { "@backstage/backend-test-utils": "workspace:^", diff --git a/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/index.examples.test.ts b/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/index.examples.test.ts new file mode 100644 index 0000000000..d35cb3f319 --- /dev/null +++ b/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/index.examples.test.ts @@ -0,0 +1,292 @@ +/* + * 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. + */ + +const mockRailsTemplater = { run: jest.fn() }; +jest.mock('@backstage/plugin-scaffolder-node', () => ({ + ...jest.requireActual('@backstage/plugin-scaffolder-node'), + fetchContents: jest.fn(), +})); +jest.mock('./railsNewRunner', () => { + return { + RailsNewRunner: jest.fn().mockImplementation(() => { + return mockRailsTemplater; + }), + }; +}); + +import { ContainerRunner, UrlReader } from '@backstage/backend-common'; +import { ConfigReader } from '@backstage/config'; +import { ScmIntegrations } from '@backstage/integration'; +import { resolve as resolvePath } from 'path'; +import { createFetchRailsAction } from './index'; +import { fetchContents } from '@backstage/plugin-scaffolder-node'; +import { createMockDirectory } from '@backstage/backend-test-utils'; +import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test-utils'; +import { Writable } from 'stream'; +import { examples } from './index.examples'; +import yaml from 'yaml'; + +describe('fetch:rails', () => { + const mockDir = createMockDirectory(); + const integrations = ScmIntegrations.fromConfig( + new ConfigReader({ + integrations: { + azure: [ + { host: 'dev.azure.com', token: 'tokenlols' }, + { host: 'myazurehostnotoken.com' }, + ], + }, + }), + ); + + const mockContext = createMockActionContext({ + input: { + url: 'https://rubyonrails.org/generator', + targetPath: 'something', + values: { + help: 'me', + }, + }, + templateInfo: { + baseUrl: 'somebase', + entityRef: 'template:default/myTemplate', + }, + workspacePath: mockDir.path, + }); + + const mockReader: UrlReader = { + readUrl: jest.fn(), + readTree: jest.fn(), + search: jest.fn(), + }; + const containerRunner: ContainerRunner = { + runContainer: jest.fn(), + }; + + const action = createFetchRailsAction({ + integrations, + reader: mockReader, + containerRunner, + allowedImageNames: ['foo/rails-custom-image'], + }); + + beforeEach(() => { + mockDir.setContent({ + result: '{}', + }); + jest.clearAllMocks(); + }); + + it(`should ${examples[0].description}`, async () => { + const input = yaml.parse(examples[0].example).steps[0].input; + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(fetchContents).toHaveBeenCalledWith({ + reader: mockReader, + integrations, + baseUrl: mockContext.templateInfo?.baseUrl, + fetchUrl: input.url, + outputPath: resolvePath(mockContext.workspacePath), + }); + }); + + it(`should ${examples[1].description}`, async () => { + const input = yaml.parse(examples[1].example).steps[0].input; + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(fetchContents).toHaveBeenCalledWith({ + reader: mockReader, + integrations, + baseUrl: mockContext.templateInfo?.baseUrl, + fetchUrl: input.url, + outputPath: resolvePath(mockContext.workspacePath), + }); + }); + + it(`should ${examples[2].description}`, async () => { + const input = yaml.parse(examples[2].example).steps[0].input; + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(fetchContents).toHaveBeenCalledWith({ + reader: mockReader, + integrations, + baseUrl: mockContext.templateInfo?.baseUrl, + fetchUrl: input.url, + outputPath: resolvePath(mockContext.workspacePath), + }); + }); + + it(`should ${examples[3].description}`, async () => { + const input = yaml.parse(examples[3].example).steps[0].input; + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(fetchContents).toHaveBeenCalledWith({ + reader: mockReader, + integrations, + baseUrl: mockContext.templateInfo?.baseUrl, + fetchUrl: input.url, + outputPath: resolvePath(mockContext.workspacePath), + }); + }); + + it(`should ${examples[4].description}`, async () => { + const input = yaml.parse(examples[4].example).steps[0].input; + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(fetchContents).toHaveBeenCalledWith({ + reader: mockReader, + integrations, + baseUrl: mockContext.templateInfo?.baseUrl, + fetchUrl: input.url, + outputPath: resolvePath(mockContext.workspacePath), + }); + }); + + it(`should ${examples[5].description}`, async () => { + const input = yaml.parse(examples[5].example).steps[0].input; + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(fetchContents).toHaveBeenCalledWith({ + reader: mockReader, + integrations, + baseUrl: mockContext.templateInfo?.baseUrl, + fetchUrl: input.url, + outputPath: resolvePath(mockContext.workspacePath), + }); + }); + + it(`should ${examples[6].description}`, async () => { + const input = yaml.parse(examples[6].example).steps[0].input; + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(fetchContents).toHaveBeenCalledWith({ + reader: mockReader, + integrations, + baseUrl: mockContext.templateInfo?.baseUrl, + fetchUrl: input.url, + outputPath: resolvePath(mockContext.workspacePath), + }); + }); + + it(`should ${examples[7].description}`, async () => { + const input = yaml.parse(examples[7].example).steps[0].input; + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(fetchContents).toHaveBeenCalledWith({ + reader: mockReader, + integrations, + baseUrl: mockContext.templateInfo?.baseUrl, + fetchUrl: input.url, + outputPath: resolvePath(mockContext.workspacePath), + }); + }); + + it(`should ${examples[8].description}`, async () => { + const input = yaml.parse(examples[8].example).steps[0].input; + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(fetchContents).toHaveBeenCalledWith({ + reader: mockReader, + integrations, + baseUrl: mockContext.templateInfo?.baseUrl, + fetchUrl: input.url, + outputPath: resolvePath(mockContext.workspacePath), + }); + }); + + it(`should ${examples[9].description}`, async () => { + const input = yaml.parse(examples[9].example).steps[0].input; + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(fetchContents).toHaveBeenCalledWith({ + reader: mockReader, + integrations, + baseUrl: mockContext.templateInfo?.baseUrl, + fetchUrl: input.url, + outputPath: resolvePath(mockContext.workspacePath), + }); + }); +}); diff --git a/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/index.examples.ts b/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/index.examples.ts new file mode 100644 index 0000000000..4c77eb3c1b --- /dev/null +++ b/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/index.examples.ts @@ -0,0 +1,370 @@ +/* + * 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: 'Fetch and template a minimal Rails app', + example: yaml.stringify({ + steps: [ + { + id: 'fetchTemplate', + action: 'fetch:rails', + name: 'Fetch and Template Rails App', + input: { + url: 'https://github.com/backstage/backstage', + values: { + railsArguments: { + minimal: true, + skipBundle: true, + skipWebpackInstall: true, + skipTest: true, + skipActionCable: true, + skipActionMailer: true, + skipActionMailbox: true, + skipActiveStorage: true, + skipActionText: true, + skipActiveRecord: true, + force: true, + api: true, + webpacker: 'react', + database: 'postgresql', + railsVersion: 'dev', + }, + }, + }, + }, + ], + }), + }, + { + description: 'Fetch and template a Rails app with custom options', + example: yaml.stringify({ + steps: [ + { + id: 'fetchTemplate', + action: 'fetch:rails', + name: 'Fetch and Template Rails App', + input: { + url: 'https://github.com/backstage/backstage', + targetPath: 'custom-path', + values: { + railsArguments: { + minimal: false, + skipBundle: false, + skipWebpackInstall: false, + skipTest: false, + skipActionCable: false, + skipActionMailer: false, + skipActionMailbox: false, + skipActiveStorage: false, + skipActionText: false, + skipActiveRecord: false, + force: false, + api: false, + webpacker: 'vue', + database: 'mysql', + railsVersion: 'edge', + }, + }, + }, + }, + ], + }), + }, + { + description: 'Fetch and template a Rails app with Docker image', + example: yaml.stringify({ + steps: [ + { + id: 'fetchTemplate', + action: 'fetch:rails', + name: 'Fetch and Template Rails App', + input: { + url: 'https://github.com/backstage/backstage', + values: { + railsArguments: { + minimal: true, + skipBundle: true, + skipWebpackInstall: true, + skipTest: true, + skipActionCable: true, + skipActionMailer: true, + skipActionMailbox: true, + skipActiveStorage: true, + skipActionText: true, + skipActiveRecord: true, + force: true, + api: true, + webpacker: 'react', + database: 'postgresql', + railsVersion: 'dev', + }, + imageName: 'custom/rails-image', + }, + }, + }, + ], + }), + }, + { + description: + 'Fetch and template a Rails app with different database and action mailer settings', + example: yaml.stringify({ + steps: [ + { + id: 'fetchTemplate', + action: 'fetch:rails', + name: 'Fetch and Template Rails App', + input: { + url: 'https://github.com/backstage/backstage', + values: { + railsArguments: { + minimal: false, + skipBundle: false, + skipWebpackInstall: false, + skipTest: false, + skipActionCable: false, + skipActionMailer: false, + skipActionMailbox: true, + skipActiveStorage: false, + skipActionText: false, + skipActiveRecord: false, + force: true, + api: true, + webpacker: 'angular', + database: 'sqlite3', + railsVersion: 'master', + }, + }, + }, + }, + ], + }), + }, + { + description: + 'Fetch and template a Rails app with full options including action mailer and active storage', + example: yaml.stringify({ + steps: [ + { + id: 'fetchTemplate', + action: 'fetch:rails', + name: 'Fetch and Template Rails App', + input: { + url: 'https://github.com/backstage/backstage', + values: { + railsArguments: { + minimal: false, + skipBundle: false, + skipWebpackInstall: false, + skipTest: false, + skipActionCable: false, + skipActionMailer: false, + skipActionMailbox: false, + skipActiveStorage: false, + skipActionText: false, + skipActiveRecord: false, + force: false, + api: false, + webpacker: 'stimulus', + database: 'postgresql', + railsVersion: 'fromImage', + }, + }, + }, + }, + ], + }), + }, + { + description: + 'Fetch and template a Rails app with API-only stack and custom template path', + example: yaml.stringify({ + steps: [ + { + id: 'fetchTemplate', + action: 'fetch:rails', + name: 'Fetch and Template Rails App', + input: { + url: 'https://github.com/backstage/backstage', + values: { + railsArguments: { + minimal: false, + skipBundle: true, + skipWebpackInstall: true, + skipTest: true, + skipActionCable: true, + skipActionMailer: true, + skipActionMailbox: true, + skipActiveStorage: true, + skipActionText: true, + skipActiveRecord: true, + force: true, + api: true, + webpacker: 'elm', + database: 'mysql', + railsVersion: 'dev', + template: 'path/to/custom/template', + }, + }, + }, + }, + ], + }), + }, + { + description: 'Fetch and template a Rails app with custom Webpack setup', + example: yaml.stringify({ + steps: [ + { + id: 'fetchTemplate', + action: 'fetch:rails', + name: 'Fetch and Template Rails App', + input: { + url: 'https://github.com/backstage/backstage', + values: { + railsArguments: { + minimal: false, + skipBundle: false, + skipWebpackInstall: false, + skipTest: false, + skipActionCable: false, + skipActionMailer: false, + skipActionMailbox: false, + skipActiveStorage: false, + skipActionText: false, + skipActiveRecord: false, + force: false, + api: false, + webpacker: 'angular', + database: 'postgresql', + railsVersion: 'dev', + }, + }, + }, + }, + ], + }), + }, + { + description: + 'Fetch and template a Rails app with specific Rails version and Action Mailer enabled', + example: yaml.stringify({ + steps: [ + { + id: 'fetchTemplate', + action: 'fetch:rails', + name: 'Fetch and Template Rails App', + input: { + url: 'https://github.com/backstage/backstage', + values: { + railsArguments: { + minimal: false, + skipBundle: false, + skipWebpackInstall: false, + skipTest: false, + skipActionCable: false, + skipActionMailer: false, + skipActionMailbox: false, + skipActiveStorage: false, + skipActionText: false, + skipActiveRecord: false, + force: true, + api: true, + webpacker: 'react', + database: 'sqlite3', + railsVersion: 'master', + }, + }, + }, + }, + ], + }), + }, + { + description: + 'Fetch and template a Rails app with specific database and Active Storage enabled', + example: yaml.stringify({ + steps: [ + { + id: 'fetchTemplate', + action: 'fetch:rails', + name: 'Fetch and Template Rails App', + input: { + url: 'https://github.com/backstage/backstage', + values: { + railsArguments: { + minimal: false, + skipBundle: false, + skipWebpackInstall: false, + skipTest: false, + skipActionCable: false, + skipActionMailer: false, + skipActionMailbox: false, + skipActiveStorage: false, + skipActionText: false, + skipActiveRecord: false, + force: true, + api: true, + webpacker: 'vue', + database: 'postgresql', + railsVersion: 'fromImage', + }, + }, + }, + }, + ], + }), + }, + { + description: + 'Fetch and template a Rails app with full options including database and skip options', + example: yaml.stringify({ + steps: [ + { + id: 'fetchTemplate', + action: 'fetch:rails', + name: 'Fetch and Template Rails App', + input: { + url: 'https://github.com/backstage/backstage', + values: { + railsArguments: { + minimal: false, + skipBundle: true, + skipWebpackInstall: true, + skipTest: true, + skipActionCable: true, + skipActionMailer: true, + skipActionMailbox: true, + skipActiveStorage: true, + skipActionText: true, + skipActiveRecord: true, + force: false, + api: false, + webpacker: 'stimulus', + database: 'sqlite3', + railsVersion: 'dev', + }, + }, + }, + }, + ], + }), + }, +]; diff --git a/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/index.ts b/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/index.ts index 394d0fb02c..94a2a3539b 100644 --- a/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/index.ts +++ b/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/index.ts @@ -27,6 +27,7 @@ import { import { resolve as resolvePath } from 'path'; import { RailsNewRunner } from './railsNewRunner'; import { PassThrough } from 'stream'; +import { examples } from './index.examples'; /** * Creates the `fetch:rails` Scaffolder action. @@ -56,6 +57,7 @@ export function createFetchRailsAction(options: { id: 'fetch:rails', description: 'Downloads a template from the given `url` into the workspace, and runs a rails new generator on it.', + examples, schema: { input: { type: 'object', From 1145181834f58328fc846c6776fdb8ff26c1d79f Mon Sep 17 00:00:00 2001 From: Andre Wanlin Date: Sat, 13 Jul 2024 10:45:17 -0500 Subject: [PATCH 245/416] Moved from root note to title Signed-off-by: Andre Wanlin --- docs/auth/guest/provider.md | 3 +-- docs/features/kubernetes/authenticationstrategy.md | 3 +-- docs/features/kubernetes/installation.md | 9 +++------ docs/features/search/getting-started.md | 6 ++---- docs/features/software-catalog/configuration.md | 6 ++---- docs/features/software-templates/builtin-actions.md | 3 +-- docs/features/techdocs/getting-started.md | 9 +++------ docs/getting-started/config/database.md | 3 +-- docs/getting-started/configure-app-with-plugins.md | 3 +-- docs/getting-started/homepage.md | 3 +-- docs/integrations/aws-s3/discovery--old.md | 3 +-- docs/integrations/aws-s3/discovery.md | 3 +-- docs/integrations/azure/discovery--old.md | 3 +-- docs/integrations/azure/discovery.md | 3 +-- docs/integrations/azure/org--old.md | 3 +-- docs/integrations/azure/org.md | 3 +-- docs/integrations/bitbucketCloud/discovery.md | 3 +-- docs/integrations/bitbucketServer/discovery.md | 3 +-- docs/integrations/gerrit/discovery.md | 3 +-- docs/integrations/github/discovery--old.md | 6 ++---- docs/integrations/github/discovery.md | 3 +-- docs/integrations/github/org--old.md | 6 ++---- docs/integrations/github/org.md | 3 +-- docs/integrations/gitlab/discovery.md | 3 +-- docs/integrations/gitlab/org.md | 3 +-- docs/integrations/ldap/org--old.md | 3 +-- docs/integrations/ldap/org.md | 3 +-- docs/permissions/getting-started.md | 3 +-- docs/permissions/plugin-authors/01-setup.md | 3 +-- docs/plugins/backend-plugin.md | 3 +-- docs/releases/v1.6.0-changelog.md | 6 ++---- docs/releases/v1.6.0-next.0-changelog.md | 6 ++---- docs/tutorials/configuring-plugin-databases.md | 13 ++++++++----- docs/tutorials/switching-sqlite-postgres.md | 3 +-- 34 files changed, 51 insertions(+), 91 deletions(-) diff --git a/docs/auth/guest/provider.md b/docs/auth/guest/provider.md index b28274d2ba..b541178571 100644 --- a/docs/auth/guest/provider.md +++ b/docs/auth/guest/provider.md @@ -25,8 +25,7 @@ This will only work with the new backend system. There is no support for this in Add the `@backstage/plugin-auth-backend-module-guest-provider` to your backend installation. -```sh -# From your Backstage root directory +```sh title="From your Backstage root directory" yarn --cwd packages/backend add @backstage/plugin-auth-backend-module-guest-provider ``` diff --git a/docs/features/kubernetes/authenticationstrategy.md b/docs/features/kubernetes/authenticationstrategy.md index a7d093248a..ffea69d610 100644 --- a/docs/features/kubernetes/authenticationstrategy.md +++ b/docs/features/kubernetes/authenticationstrategy.md @@ -173,8 +173,7 @@ To create the Backend module, run `yarn new`, select `backend-module`. Then fill This will create a new package at `plugins/kubernetes-backend-module-pinniped`. We are going to need also the `@backstage/plugin-kubernetes-node` and `@backstage/plugin-kubernetes-common` dependencies, the `@backstage/plugin-kubernetes-node` houses the [kubernetesAuthStrategyExtensionPoint](https://github.com/backstage/backstage/blob/ebe7afad9d19f279469168ca0d4feceb92c1ad36/plugins/kubernetes-node/src/extensions.ts#L77) and a [Pinniped Helper](https://github.com/backstage/backstage/blob/ebe7afad9d19f279469168ca0d4feceb92c1ad36/plugins/kubernetes-node/src/auth/PinnipedHelper.ts#L53) class. -```bash -# From your Backstage root directory +```bash title="From your Backstage root directory" yarn --cwd plugins/kubernetes-backend-module-pinniped add @backstage/plugin-kubernetes-node yarn --cwd plugins/kubernetes-backend-module-pinniped add @backstage/plugin-kubernetes-common ``` diff --git a/docs/features/kubernetes/installation.md b/docs/features/kubernetes/installation.md index b3d03cc0b4..279c9cbf3f 100644 --- a/docs/features/kubernetes/installation.md +++ b/docs/features/kubernetes/installation.md @@ -15,8 +15,7 @@ If you haven't setup Backstage already, read the The first step is to add the Kubernetes frontend plugin to your Backstage application. -```bash -# From your Backstage root directory +```bash title="From your Backstage root directory" yarn --cwd packages/app add @backstage/plugin-kubernetes ``` @@ -53,8 +52,7 @@ work. Navigate to `packages/backend` of your Backstage app, and install the `@backstage/plugin-kubernetes-backend` package. -```bash -# From your Backstage root directory +```bash title="From your Backstage root directory" yarn --cwd packages/backend add @backstage/plugin-kubernetes-backend ``` @@ -109,8 +107,7 @@ To get the Kubernetes plugin install using the New Backend System you will need Run this command to add the package: -```bash -# From your Backstage root directory +```bash title="From your Backstage root directory" yarn --cwd packages/backend add @backstage/plugin-kubernetes-backend ``` diff --git a/docs/features/search/getting-started.md b/docs/features/search/getting-started.md index 7989b60ae2..b2a074974f 100644 --- a/docs/features/search/getting-started.md +++ b/docs/features/search/getting-started.md @@ -16,8 +16,7 @@ If you haven't setup Backstage already, start ## Adding Search to the Frontend -```bash -# From your Backstage root directory +```bash title="From your Backstage root directory" yarn --cwd packages/app add @backstage/plugin-search @backstage/plugin-search-react ``` @@ -133,8 +132,7 @@ For more information about using `Root.tsx`, please see Add the following plugins into your backend app: -```bash -# From your Backstage root directory +```bash title="From your Backstage root directory" yarn --cwd packages/backend add @backstage/plugin-search-backend @backstage/plugin-search-backend-node ``` diff --git a/docs/features/software-catalog/configuration.md b/docs/features/software-catalog/configuration.md index f5df9eafca..17d5f49205 100644 --- a/docs/features/software-catalog/configuration.md +++ b/docs/features/software-catalog/configuration.md @@ -184,8 +184,7 @@ Catalog errors are published to the [events plugin](https://github.com/backstage The first step is to add the events backend plugin to your Backstage application. Navigate to your Backstage application directory and add the plugin package. -```ts -# From your Backstage root directory +```ts title="From your Backstage root directory" yarn --cwd packages/backend add @backstage/plugin-events-backend ``` @@ -201,8 +200,7 @@ If you want to log catalog errors you can install the `@backstage/plugin-catalog Install the catalog logs module. -```ts -# From your Backstage root directory +```ts title="From your Backstage root directory" yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-logs ``` diff --git a/docs/features/software-templates/builtin-actions.md b/docs/features/software-templates/builtin-actions.md index 5b1e4347da..301fb4c457 100644 --- a/docs/features/software-templates/builtin-actions.md +++ b/docs/features/software-templates/builtin-actions.md @@ -24,8 +24,7 @@ There are also several modules available for various SCM tools: Here's how to add an action module, first you need to run this command: -```sh -# From your Backstage root directory +```sh title="From your Backstage root directory" yarn --cwd packages/backend add @backstage/plugin-scaffolder-backend-module-github ``` diff --git a/docs/features/techdocs/getting-started.md b/docs/features/techdocs/getting-started.md index 7909f8166f..a157d29c0d 100644 --- a/docs/features/techdocs/getting-started.md +++ b/docs/features/techdocs/getting-started.md @@ -21,8 +21,7 @@ The first step is to add the TechDocs plugin to your Backstage application. Navigate to your new Backstage application directory. And then to your `packages/app` directory, and install the `@backstage/plugin-techdocs` package. -```bash -# From your Backstage root directory +```bash title="From your Backstage root directory" yarn --cwd packages/app add @backstage/plugin-techdocs ``` @@ -106,8 +105,7 @@ That's it! Now, we need the TechDocs Backend plugin for the frontend to work. Navigate to `packages/backend` of your Backstage app, and install the `@backstage/plugin-techdocs-backend` package. -```bash -# From your Backstage root directory +```bash title="From your Backstage root directory" yarn --cwd packages/backend add @backstage/plugin-techdocs-backend ``` @@ -199,8 +197,7 @@ To install TechDocs when using the New Backend system you will need to do the fo Navigate to `packages/backend` of your Backstage app, and install the `@backstage/plugin-techdocs-backend` package. -```bash -# From your Backstage root directory +```bash title="From your Backstage root directory" yarn --cwd packages/backend add @backstage/plugin-techdocs-backend ``` diff --git a/docs/getting-started/config/database.md b/docs/getting-started/config/database.md index a560fe507b..0fbd66d5a3 100644 --- a/docs/getting-started/config/database.md +++ b/docs/getting-started/config/database.md @@ -73,8 +73,7 @@ to install and configure the client. Go to the root directory of your freshly installed Backstage App. Run the following to install the PostgreSQL client into your backend: -```bash -# From your Backstage root directory +```bash title="From your Backstage root directory" yarn --cwd packages/backend add pg ``` diff --git a/docs/getting-started/configure-app-with-plugins.md b/docs/getting-started/configure-app-with-plugins.md index 2fdb016e7b..95fd456dc0 100644 --- a/docs/getting-started/configure-app-with-plugins.md +++ b/docs/getting-started/configure-app-with-plugins.md @@ -21,8 +21,7 @@ to an entity in the software catalog. 1. Add the plugin's npm package to the repo: - ```bash - # From your Backstage root directory + ```bash title="From your Backstage root directory" yarn --cwd packages/app add @circleci/backstage-plugin ``` diff --git a/docs/getting-started/homepage.md b/docs/getting-started/homepage.md index 7e1a2ed909..d7c9b46faa 100644 --- a/docs/getting-started/homepage.md +++ b/docs/getting-started/homepage.md @@ -28,8 +28,7 @@ Now, let's get started by installing the home plugin and creating a simple homep #### 1. Install the plugin -```bash -# From your Backstage root directory +```bash title="From your Backstage root directory" yarn --cwd packages/app add @backstage/plugin-home ``` diff --git a/docs/integrations/aws-s3/discovery--old.md b/docs/integrations/aws-s3/discovery--old.md index bff63af9e5..09b6eb6cc0 100644 --- a/docs/integrations/aws-s3/discovery--old.md +++ b/docs/integrations/aws-s3/discovery--old.md @@ -66,8 +66,7 @@ catalog: As this provider is not one of the default providers, you will first need to install the AWS catalog plugin: -```bash -# From your Backstage root directory +```bash title="From your Backstage root directory" yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-aws ``` diff --git a/docs/integrations/aws-s3/discovery.md b/docs/integrations/aws-s3/discovery.md index cce410ea8b..db9119680e 100644 --- a/docs/integrations/aws-s3/discovery.md +++ b/docs/integrations/aws-s3/discovery.md @@ -66,8 +66,7 @@ catalog: As this provider is not one of the default providers, you will first need to install the AWS catalog plugin: -```bash -# From your Backstage root directory +```bash title="From your Backstage root directory" yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-aws ``` diff --git a/docs/integrations/azure/discovery--old.md b/docs/integrations/azure/discovery--old.md index be490d70fe..56a2fe559f 100644 --- a/docs/integrations/azure/discovery--old.md +++ b/docs/integrations/azure/discovery--old.md @@ -102,8 +102,7 @@ It may take some time before the branch is indexed and searchable. As this provider is not one of the default providers, you will first need to install the Azure catalog plugin: -```bash -# From your Backstage root directory +```bash title="From your Backstage root directory" yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-azure ``` diff --git a/docs/integrations/azure/discovery.md b/docs/integrations/azure/discovery.md index 7e7b465118..c8a8a3af7c 100644 --- a/docs/integrations/azure/discovery.md +++ b/docs/integrations/azure/discovery.md @@ -102,8 +102,7 @@ It may take some time before the branch is indexed and searchable. As this provider is not one of the default providers, you will first need to install the Azure catalog plugin: -```bash -# From your Backstage root directory +```bash title="From your Backstage root directory" yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-azure ``` diff --git a/docs/integrations/azure/org--old.md b/docs/integrations/azure/org--old.md index 13d53b24b3..899120e88a 100644 --- a/docs/integrations/azure/org--old.md +++ b/docs/integrations/azure/org--old.md @@ -18,8 +18,7 @@ Microsoft Graph API. The package is not installed by default, therefore you have to add `@backstage/plugin-catalog-backend-module-msgraph` to your backend package. -```bash -# From your Backstage root directory +```bash title="From your Backstage root directory" yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-msgraph ``` diff --git a/docs/integrations/azure/org.md b/docs/integrations/azure/org.md index 2dfdee7bce..0a4eda2db5 100644 --- a/docs/integrations/azure/org.md +++ b/docs/integrations/azure/org.md @@ -18,8 +18,7 @@ Microsoft Graph API. The package is not installed by default, therefore you have to add `@backstage/plugin-catalog-backend-module-msgraph` to your backend package. -```bash -# From your Backstage root directory +```bash title="From your Backstage root directory" yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-msgraph ``` diff --git a/docs/integrations/bitbucketCloud/discovery.md b/docs/integrations/bitbucketCloud/discovery.md index 160827cb0a..04dc111d30 100644 --- a/docs/integrations/bitbucketCloud/discovery.md +++ b/docs/integrations/bitbucketCloud/discovery.md @@ -19,8 +19,7 @@ backend. The provider is not installed by default, therefore you have to add a dependency to `@backstage/plugin-catalog-backend-module-bitbucket-cloud` to your backend package. -```bash -# From your Backstage root directory +```bash title="From your Backstage root directory" yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-bitbucket-cloud ``` diff --git a/docs/integrations/bitbucketServer/discovery.md b/docs/integrations/bitbucketServer/discovery.md index d9fc946460..99e04affa8 100644 --- a/docs/integrations/bitbucketServer/discovery.md +++ b/docs/integrations/bitbucketServer/discovery.md @@ -19,8 +19,7 @@ backend. The provider is not installed by default, therefore you have to add a dependency to `@backstage/plugin-catalog-backend-module-bitbucket-server` to your backend package. -```bash -# From your Backstage root directory +```bash title="From your Backstage root directory" yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-bitbucket-server ``` diff --git a/docs/integrations/gerrit/discovery.md b/docs/integrations/gerrit/discovery.md index e2922c1f76..96dfbd47fb 100644 --- a/docs/integrations/gerrit/discovery.md +++ b/docs/integrations/gerrit/discovery.md @@ -16,8 +16,7 @@ stored in the root of the matching projects. As this provider is not one of the default providers, you will first need to install the Gerrit provider plugin: -```bash -# From your Backstage root directory +```bash title="From your Backstage root directory" yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-gerrit ``` diff --git a/docs/integrations/github/discovery--old.md b/docs/integrations/github/discovery--old.md index 138e54a538..752aa51bde 100644 --- a/docs/integrations/github/discovery--old.md +++ b/docs/integrations/github/discovery--old.md @@ -25,8 +25,7 @@ backend. They are not installed by default, therefore you have to add a dependency on `@backstage/plugin-catalog-backend-module-github` to your backend package. -```bash -# From your Backstage root directory +```bash title="From your Backstage root directory" yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-github ``` @@ -273,8 +272,7 @@ backend. They are not installed by default, therefore you have to add a dependency on `@backstage/plugin-catalog-backend-module-github` to your backend package, plus `@backstage/integration` for the basic credentials management: -```bash -# From your Backstage root directory +```bash title="From your Backstage root directory" yarn --cwd packages/backend add @backstage/integration @backstage/plugin-catalog-backend-module-github ``` diff --git a/docs/integrations/github/discovery.md b/docs/integrations/github/discovery.md index d8374932b8..43e63a618c 100644 --- a/docs/integrations/github/discovery.md +++ b/docs/integrations/github/discovery.md @@ -24,8 +24,7 @@ You will have to add the GitHub Entity provider to your backend as it is not ins dependency on `@backstage/plugin-catalog-backend-module-github` to your backend package. -```bash -# From your Backstage root directory +```bash title="From your Backstage root directory" yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-github ``` diff --git a/docs/integrations/github/org--old.md b/docs/integrations/github/org--old.md index 3d1639a924..bf12cad036 100644 --- a/docs/integrations/github/org--old.md +++ b/docs/integrations/github/org--old.md @@ -29,8 +29,7 @@ the Processor method (not recommended), it is described separately below. The provider is not installed by default, therefore you have to add a dependency to `@backstage/plugin-catalog-backend-module-github` to your backend package. -```bash -# From your Backstage root directory +```bash title="From your Backstage root directory" yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-github ``` @@ -334,8 +333,7 @@ frequency with which they are refreshed, separately from other processors. The `GithubOrgReaderProcessor` is not registered by default, so you have to install and register it in the catalog plugin: -```bash -# From your Backstage root directory +```bash title="From your Backstage root directory" yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-github ``` diff --git a/docs/integrations/github/org.md b/docs/integrations/github/org.md index f94ffe6c7a..18865cd630 100644 --- a/docs/integrations/github/org.md +++ b/docs/integrations/github/org.md @@ -38,8 +38,7 @@ You will have to add the GitHub Org provider to your backend as it is not instal dependency on `@backstage/plugin-catalog-backend-module-github-org` to your backend package. -```bash -# From your Backstage root directory +```bash title="From your Backstage root directory" yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-github-org ``` diff --git a/docs/integrations/gitlab/discovery.md b/docs/integrations/gitlab/discovery.md index 98fbb0fbce..13ffd79801 100644 --- a/docs/integrations/gitlab/discovery.md +++ b/docs/integrations/gitlab/discovery.md @@ -20,8 +20,7 @@ This provider can also be configured to ingest GitLab data based on [GitLab Webh As this provider is not one of the default providers, you will first need to install the gitlab catalog plugin: -```bash -# From your Backstage root directory +```bash title="From your Backstage root directory" yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-gitlab ``` diff --git a/docs/integrations/gitlab/org.md b/docs/integrations/gitlab/org.md index 46d720c164..65f66aa763 100644 --- a/docs/integrations/gitlab/org.md +++ b/docs/integrations/gitlab/org.md @@ -25,8 +25,7 @@ This provider can also be configured to ingest GitLab data based on [GitLab Syst As this provider is not one of the default providers, you will first need to install the Gitlab provider plugin: -```bash -# From your Backstage root directory +```bash title="From your Backstage root directory" yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-gitlab @backstage/plugin-catalog-backend-module-gitlab-org ``` diff --git a/docs/integrations/ldap/org--old.md b/docs/integrations/ldap/org--old.md index 63f052371f..448e9bbed1 100644 --- a/docs/integrations/ldap/org--old.md +++ b/docs/integrations/ldap/org--old.md @@ -24,8 +24,7 @@ the Processor method (not recommended), it is described separately below. The provider is not installed by default, therefore you have to add a dependency to `@backstage/plugin-catalog-backend-module-ldap` to your backend package. -```bash -# From your Backstage root directory +```bash title="From your Backstage root directory" yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-ldap ``` diff --git a/docs/integrations/ldap/org.md b/docs/integrations/ldap/org.md index 36cffb9b1f..b1aa460bd6 100644 --- a/docs/integrations/ldap/org.md +++ b/docs/integrations/ldap/org.md @@ -21,8 +21,7 @@ Backstage in general supports OpenLDAP compatible vendors, as well as Active Dir The provider is not installed by default, therefore you have to add a dependency to `@backstage/plugin-catalog-backend-module-ldap` to your backend package. -```bash -# From your Backstage root directory +```bash title="From your Backstage root directory" yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-ldap ``` diff --git a/docs/permissions/getting-started.md b/docs/permissions/getting-started.md index 4dabf3fcbd..e8132e571b 100644 --- a/docs/permissions/getting-started.md +++ b/docs/permissions/getting-started.md @@ -50,8 +50,7 @@ The permissions framework uses a new `permission-backend` plugin to accept autho 1. Add `@backstage/plugin-permission-backend` as a dependency of your Backstage backend: - ```bash - # From your Backstage root directory + ```bash title="From your Backstage root directory" yarn --cwd packages/backend add @backstage/plugin-permission-backend ``` diff --git a/docs/permissions/plugin-authors/01-setup.md b/docs/permissions/plugin-authors/01-setup.md index a674d82e25..f11bdff930 100644 --- a/docs/permissions/plugin-authors/01-setup.md +++ b/docs/permissions/plugin-authors/01-setup.md @@ -39,8 +39,7 @@ The source code is available here: 2. Add these packages as dependencies for your Backstage app: - ```sh - # From your Backstage root directory + ```sh title="From your Backstage root directory" yarn --cwd packages/backend add @internal/plugin-todo-list-backend @internal/plugin-todo-list-common yarn --cwd packages/app add @internal/plugin-todo-list ``` diff --git a/docs/plugins/backend-plugin.md b/docs/plugins/backend-plugin.md index 7f155f3b05..1366a59099 100644 --- a/docs/plugins/backend-plugin.md +++ b/docs/plugins/backend-plugin.md @@ -71,8 +71,7 @@ Backstage application / backend exposes it. To actually attach and run the plugin router, you will make some modifications to your backend. -```bash -# From your Backstage root directory +```bash title="From your Backstage root directory" yarn --cwd packages/backend add @internal/plugin-carmen-backend@^0.1.0 # Change this to match the plugin's package.json ``` diff --git a/docs/releases/v1.6.0-changelog.md b/docs/releases/v1.6.0-changelog.md index 0532243cbf..e9692f4f1b 100644 --- a/docs/releases/v1.6.0-changelog.md +++ b/docs/releases/v1.6.0-changelog.md @@ -248,8 +248,7 @@ 1. First we need to add the @backstage/plugin-azure-devops package to your frontend app: - ```bash - # From your Backstage root directory + ```bash title="From your Backstage root directory" yarn add --cwd packages/app @backstage/plugin-azure-devops ``` @@ -313,8 +312,7 @@ 1. First we need to add the @backstage/plugin-azure-devops package to your frontend app: - ```bash - # From your Backstage root directory + ```bash title="From your Backstage root directory" yarn add --cwd packages/app @backstage/plugin-azure-devops ``` diff --git a/docs/releases/v1.6.0-next.0-changelog.md b/docs/releases/v1.6.0-next.0-changelog.md index 5ff2311b79..fbe9caefde 100644 --- a/docs/releases/v1.6.0-next.0-changelog.md +++ b/docs/releases/v1.6.0-next.0-changelog.md @@ -10,8 +10,7 @@ 1. First we need to add the @backstage/plugin-azure-devops package to your frontend app: - ```bash - # From your Backstage root directory + ```bash title="From your Backstage root directory" yarn add --cwd packages/app @backstage/plugin-azure-devops ``` @@ -69,8 +68,7 @@ 1. First we need to add the @backstage/plugin-azure-devops package to your frontend app: - ```bash - # From your Backstage root directory + ```bash title="From your Backstage root directory" yarn add --cwd packages/app @backstage/plugin-azure-devops ``` diff --git a/docs/tutorials/configuring-plugin-databases.md b/docs/tutorials/configuring-plugin-databases.md index 528d2c6325..db3f126de7 100644 --- a/docs/tutorials/configuring-plugin-databases.md +++ b/docs/tutorials/configuring-plugin-databases.md @@ -36,12 +36,15 @@ Please ensure the appropriate database drivers are installed in your `backend` package. If you intend to use both PostgreSQL and SQLite, you can install both of them. -```bash -# From your Backstage root directory -# install pg if you need PostgreSQL -yarn --cwd packages/backend add pg +Install pg if you need PostgreSQL: -# install SQLite 3 if you intend to set it as the client +```bash title="From your Backstage root directory" +yarn --cwd packages/backend add pg +``` + +Install SQLite 3 if you intend to set it as the client: + +```bash title="From your Backstage root directory" yarn --cwd packages/backend add better-sqlite3 ``` diff --git a/docs/tutorials/switching-sqlite-postgres.md b/docs/tutorials/switching-sqlite-postgres.md index 2ef481dbf3..aec9ca2ee9 100644 --- a/docs/tutorials/switching-sqlite-postgres.md +++ b/docs/tutorials/switching-sqlite-postgres.md @@ -19,8 +19,7 @@ switch between database backends. First, add PostgreSQL to your `backend` package: -```bash -# From your Backstage root directory +```bash title="From your Backstage root directory" yarn --cwd packages/backend add pg ``` From b9e73a0e5a7545bb659f626b02fba9a6d82e7c3e Mon Sep 17 00:00:00 2001 From: parmar-abhinav Date: Sun, 14 Jul 2024 10:45:49 +0530 Subject: [PATCH 246/416] chore: run yarn install to update dependencies Signed-off-by: parmar-abhinav --- yarn.lock | 1 + 1 file changed, 1 insertion(+) diff --git a/yarn.lock b/yarn.lock index b0bff82017..574792b052 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7055,6 +7055,7 @@ __metadata: command-exists: ^1.2.9 fs-extra: ^11.0.0 jest-when: ^3.1.0 + yaml: ^2.0.0 languageName: unknown linkType: soft From b687beb2dcc16eddc89b85675b425fec7cc02c51 Mon Sep 17 00:00:00 2001 From: parmar-abhinav Date: Sun, 14 Jul 2024 10:52:16 +0530 Subject: [PATCH 247/416] chore: run yarn install to update dependencies Signed-off-by: parmar-abhinav --- yarn.lock | 1 + 1 file changed, 1 insertion(+) diff --git a/yarn.lock b/yarn.lock index b0bff82017..18f51570ec 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7032,6 +7032,7 @@ __metadata: "@backstage/plugin-scaffolder-node": "workspace:^" "@backstage/plugin-scaffolder-node-test-utils": "workspace:^" octokit: ^3.0.0 + yaml: ^2.0.0 languageName: unknown linkType: soft From b084597b3299049b92c9cbc3e76c704ec8f41a7e Mon Sep 17 00:00:00 2001 From: parmar-abhinav Date: Sun, 14 Jul 2024 10:55:19 +0530 Subject: [PATCH 248/416] chore: run yarn install to update dependencies Signed-off-by: parmar-abhinav --- yarn.lock | 1 + 1 file changed, 1 insertion(+) diff --git a/yarn.lock b/yarn.lock index b0bff82017..4dcfba4743 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6917,6 +6917,7 @@ __metadata: command-exists: ^1.2.9 fs-extra: ^11.2.0 winston: ^3.2.1 + yaml: ^2.0.0 yn: ^4.0.0 languageName: unknown linkType: soft From 065353f144c00589e5f4cbb427738ccc6f74deb4 Mon Sep 17 00:00:00 2001 From: parmar-abhinav Date: Sun, 14 Jul 2024 10:58:53 +0530 Subject: [PATCH 249/416] chore: removed unused imports Signed-off-by: parmar-abhinav --- .../src/actions/fetch/rails/index.examples.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/index.examples.test.ts b/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/index.examples.test.ts index d35cb3f319..a80985321e 100644 --- a/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/index.examples.test.ts +++ b/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/index.examples.test.ts @@ -35,7 +35,6 @@ import { createFetchRailsAction } from './index'; import { fetchContents } from '@backstage/plugin-scaffolder-node'; import { createMockDirectory } from '@backstage/backend-test-utils'; import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test-utils'; -import { Writable } from 'stream'; import { examples } from './index.examples'; import yaml from 'yaml'; From 0ab868dfd1510b6ef85d1967db2ac3688de496bd Mon Sep 17 00:00:00 2001 From: Stephen Glass Date: Sun, 14 Jul 2024 04:00:51 -0400 Subject: [PATCH 250/416] Wip Signed-off-by: Stephen Glass --- .../components/ReviewState/ReviewState.tsx | 42 +--------- .../src/next/components/ReviewState/util.ts | 84 +++++++++++++------ 2 files changed, 59 insertions(+), 67 deletions(-) diff --git a/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.tsx b/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.tsx index 95f5d76212..d320ad80a6 100644 --- a/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.tsx +++ b/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.tsx @@ -18,7 +18,7 @@ import { StructuredMetadataTable } from '@backstage/core-components'; import { JsonObject } from '@backstage/types'; import { Draft07 as JSONSchema } from 'json-schema-library'; import { ParsedTemplateSchema } from '../../hooks/useTemplateSchema'; -import { flattenObject, isJsonObject } from './util'; +import { processEntry } from './util'; /** * The props for the {@link ReviewState} component. @@ -38,49 +38,11 @@ export const ReviewState = (props: ReviewStateProps) => { Object.entries(props.formState) .flatMap(([key, value]) => { for (const step of props.schemas) { - const parsedSchema = new JSONSchema(step.mergedSchema); - const definitionInSchema = parsedSchema.getSchema({ - pointer: `#/${key}`, - data: props.formState, - }); - - if (definitionInSchema) { - const backstageReviewOptions = - definitionInSchema['ui:backstage']?.review; - - if (backstageReviewOptions) { - if (backstageReviewOptions.mask) { - return [[key, backstageReviewOptions.mask]]; - } - if (backstageReviewOptions.show === false) { - return []; - } - if (backstageReviewOptions.explode && isJsonObject(value)) { - return flattenObject(value, key, parsedSchema, props.formState); - } - } - - if (definitionInSchema['ui:widget'] === 'password') { - return [[key, '******']]; - } - - if (definitionInSchema.enum && definitionInSchema.enumNames) { - return [ - [ - key, - definitionInSchema.enumNames[ - definitionInSchema.enum.indexOf(value) - ] || value, - ], - ]; - } - } + return processEntry(key, value, step, props.formState); } - return [[key, value]]; }) .filter(prop => prop.length > 0), ); - return ; }; diff --git a/plugins/scaffolder-react/src/next/components/ReviewState/util.ts b/plugins/scaffolder-react/src/next/components/ReviewState/util.ts index 0bb6fc08d2..e040b851d3 100644 --- a/plugins/scaffolder-react/src/next/components/ReviewState/util.ts +++ b/plugins/scaffolder-react/src/next/components/ReviewState/util.ts @@ -1,3 +1,4 @@ +/* eslint-disable no-console */ /* * Copyright 2022 The Backstage Authors * @@ -16,34 +17,63 @@ import { JsonObject, JsonValue } from '@backstage/types'; import { Draft07 as JSONSchema } from 'json-schema-library'; - -export function flattenObject( - obj: JsonObject, - prefix: string, - schema: JSONSchema, - formState: JsonObject, -): [string, JsonValue | undefined][] { - return Object.entries(obj).flatMap(([key, value]) => { - const prefixedKey = prefix ? `${prefix}/${key}` : key; - - const definitionInSchema = schema.getSchema({ - pointer: `#/${prefixedKey}`, - data: formState, - }); - - if (definitionInSchema) { - const backstageReviewOptions = definitionInSchema['ui:backstage']?.review; - - // Recurse into nested objects - if (backstageReviewOptions?.explode && isJsonObject(value)) { - return flattenObject(value, prefixedKey, schema, formState); - } - } - - return [[key, value]]; - }); -} +import { ParsedTemplateSchema } from '../../hooks'; export function isJsonObject(value?: JsonValue): value is JsonObject { return typeof value === 'object' && value !== null && !Array.isArray(value); } + +export function processEntry( + key: string, + value: JsonValue | undefined, + schema: ParsedTemplateSchema, + formState: JsonObject, +): [string, JsonValue | undefined][] { + const parsedSchema = new JSONSchema(schema.mergedSchema); + const definitionInSchema = parsedSchema.getSchema({ + pointer: `#/${key}`, + data: formState, + }); + + if (definitionInSchema) { + const backstageReviewOptions = definitionInSchema['ui:backstage']?.review; + if (backstageReviewOptions) { + if (backstageReviewOptions.mask) { + return [[getLastKey(key), backstageReviewOptions.mask]]; + } + if (backstageReviewOptions.show === false) { + return []; + } + } + + if (isJsonObject(value)) { + // Process nested objects + return Object.entries(value).flatMap(([nestedKey, nestedValue]) => + processEntry(`${key}/${nestedKey}`, nestedValue, schema, formState), + ); + } + + if (definitionInSchema['ui:widget'] === 'password') { + return [[getLastKey(key), '******']]; + } + + if (definitionInSchema.enum && definitionInSchema.enumNames) { + return [ + [ + getLastKey(key), + definitionInSchema.enumNames[ + definitionInSchema.enum.indexOf(value) + ] || value, + ], + ]; + } + } + + return [[getLastKey(key), value]]; +} + +// Helper function to get the last part of the key +function getLastKey(key: string): string { + const parts = key.split('/'); + return parts[parts.length - 1]; +} From 3ac2a6a6b85f5ac054a421c661d24fb67d45a770 Mon Sep 17 00:00:00 2001 From: Andre Wanlin Date: Sun, 14 Jul 2024 13:05:51 -0500 Subject: [PATCH 251/416] Added the Postgres Search Engine to the `create-app` template Signed-off-by: Andre Wanlin --- .changeset/twenty-buses-carry.md | 5 +++++ .../templates/default-app/packages/backend/package.json.hbs | 1 + .../templates/default-app/packages/backend/src/index.ts | 6 ++++++ 3 files changed, 12 insertions(+) create mode 100644 .changeset/twenty-buses-carry.md diff --git a/.changeset/twenty-buses-carry.md b/.changeset/twenty-buses-carry.md new file mode 100644 index 0000000000..00347e60d8 --- /dev/null +++ b/.changeset/twenty-buses-carry.md @@ -0,0 +1,5 @@ +--- +'@backstage/create-app': patch +--- + +Added the Postgres Search Engine to the `create-app` template diff --git a/packages/create-app/templates/default-app/packages/backend/package.json.hbs b/packages/create-app/templates/default-app/packages/backend/package.json.hbs index e26c788496..1ec475b0ed 100644 --- a/packages/create-app/templates/default-app/packages/backend/package.json.hbs +++ b/packages/create-app/templates/default-app/packages/backend/package.json.hbs @@ -36,6 +36,7 @@ "@backstage/plugin-scaffolder-backend": "^{{version '@backstage/plugin-scaffolder-backend'}}", "@backstage/plugin-search-backend": "^{{version '@backstage/plugin-search-backend'}}", "@backstage/plugin-search-backend-module-catalog": "^{{version '@backstage/plugin-search-backend-module-catalog'}}", + "@backstage/plugin-search-backend-module-pg": "^{{version '@backstage/plugin-search-backend-module-pg'}}", "@backstage/plugin-search-backend-module-techdocs": "^{{version '@backstage/plugin-search-backend-module-techdocs'}}", "@backstage/plugin-search-backend-node": "^{{version '@backstage/plugin-search-backend-node'}}", "@backstage/plugin-techdocs-backend": "^{{version '@backstage/plugin-techdocs-backend'}}", diff --git a/packages/create-app/templates/default-app/packages/backend/src/index.ts b/packages/create-app/templates/default-app/packages/backend/src/index.ts index 239269288e..6bb9b1322d 100644 --- a/packages/create-app/templates/default-app/packages/backend/src/index.ts +++ b/packages/create-app/templates/default-app/packages/backend/src/index.ts @@ -38,6 +38,12 @@ backend.add( // search plugin backend.add(import('@backstage/plugin-search-backend/alpha')); + +// search engine +// See https://backstage.io/docs/features/search/search-engines +backend.add(import('@backstage/plugin-search-backend-module-pg/alpha')); + +// search collators backend.add(import('@backstage/plugin-search-backend-module-catalog/alpha')); backend.add(import('@backstage/plugin-search-backend-module-techdocs/alpha')); From c0a705d44298c5274f1d94b230d642a86cada2c9 Mon Sep 17 00:00:00 2001 From: Andre Wanlin Date: Fri, 14 Jun 2024 10:49:04 -0500 Subject: [PATCH 252/416] Added the Kubernetes plugin to `create-app` Signed-off-by: Andre Wanlin --- .changeset/blue-pumas-cheer.md | 5 +++++ packages/create-app/src/lib/versions.ts | 4 ++++ .../templates/default-app/app-config.yaml.hbs | 3 +++ .../default-app/packages/app/package.json.hbs | 1 + .../app/src/components/catalog/EntityPage.tsx | 21 +++++++++++++++++++ .../packages/backend/package.json.hbs | 1 + .../default-app/packages/backend/src/index.ts | 3 +++ 7 files changed, 38 insertions(+) create mode 100644 .changeset/blue-pumas-cheer.md diff --git a/.changeset/blue-pumas-cheer.md b/.changeset/blue-pumas-cheer.md new file mode 100644 index 0000000000..f6cbf180ff --- /dev/null +++ b/.changeset/blue-pumas-cheer.md @@ -0,0 +1,5 @@ +--- +'@backstage/create-app': patch +--- + +Added the Kubernetes plugin to `create-app` diff --git a/packages/create-app/src/lib/versions.ts b/packages/create-app/src/lib/versions.ts index 25fd7b7c3c..194ffa21d9 100644 --- a/packages/create-app/src/lib/versions.ts +++ b/packages/create-app/src/lib/versions.ts @@ -62,6 +62,8 @@ import { version as pluginCatalogBackendModuleLogs } from '../../../../plugins/c 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 pluginKubernetes } from '../../../../plugins/kubernetes/package.json'; +import { version as pluginKubernetesBackend } from '../../../../plugins/kubernetes-backend/package.json'; import { version as pluginOrg } from '../../../../plugins/org/package.json'; import { version as pluginPermissionBackend } from '../../../../plugins/permission-backend/package.json'; import { version as pluginPermissionBackendModulePolicyAllowAll } from '../../../../plugins/permission-backend-module-policy-allow-all/package.json'; @@ -118,6 +120,8 @@ export const packageVersions = { pluginCatalogBackendModuleScaffolderEntityModel, '@backstage/plugin-catalog-graph': pluginCatalogGraph, '@backstage/plugin-catalog-import': pluginCatalogImport, + '@backstage/plugin-kubernetes': pluginKubernetes, + '@backstage/plugin-kubernetes-backend': pluginKubernetesBackend, '@backstage/plugin-org': pluginOrg, '@backstage/plugin-permission-backend': pluginPermissionBackend, '@backstage/plugin-permission-backend-module-allow-all-policy': diff --git a/packages/create-app/templates/default-app/app-config.yaml.hbs b/packages/create-app/templates/default-app/app-config.yaml.hbs index 248cff137a..a4797d4c41 100644 --- a/packages/create-app/templates/default-app/app-config.yaml.hbs +++ b/packages/create-app/templates/default-app/app-config.yaml.hbs @@ -103,3 +103,6 @@ catalog: # target: https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/acme-corp.yaml # rules: # - allow: [User, Group] + +kubernetes: + # see https://backstage.io/docs/features/kubernetes/configuration for kubernetes configuration options \ No newline at end of file diff --git a/packages/create-app/templates/default-app/packages/app/package.json.hbs b/packages/create-app/templates/default-app/packages/app/package.json.hbs index d4db9e5885..08a1d58362 100644 --- a/packages/create-app/templates/default-app/packages/app/package.json.hbs +++ b/packages/create-app/templates/default-app/packages/app/package.json.hbs @@ -27,6 +27,7 @@ "@backstage/plugin-catalog-graph": "^{{version '@backstage/plugin-catalog-graph'}}", "@backstage/plugin-catalog-import": "^{{version '@backstage/plugin-catalog-import'}}", "@backstage/plugin-catalog-react": "^{{version '@backstage/plugin-catalog-react'}}", + "@backstage/plugin-kubernetes": "^{{version '@backstage/plugin-kubernetes'}}", "@backstage/plugin-org": "^{{version '@backstage/plugin-org'}}", "@backstage/plugin-permission-react": "^{{version '@backstage/plugin-permission-react'}}", "@backstage/plugin-scaffolder": "^{{version '@backstage/plugin-scaffolder'}}", diff --git a/packages/create-app/templates/default-app/packages/app/src/components/catalog/EntityPage.tsx b/packages/create-app/templates/default-app/packages/app/src/components/catalog/EntityPage.tsx index 53b6685c3f..6164c76004 100644 --- a/packages/create-app/templates/default-app/packages/app/src/components/catalog/EntityPage.tsx +++ b/packages/create-app/templates/default-app/packages/app/src/components/catalog/EntityPage.tsx @@ -54,6 +54,11 @@ import { import { TechDocsAddons } from '@backstage/plugin-techdocs-react'; import { ReportIssue } from '@backstage/plugin-techdocs-module-addons-contrib'; +import { + EntityKubernetesContent, + isKubernetesAvailable, +} from '@backstage/plugin-kubernetes'; + const techdocsContent = ( @@ -150,6 +155,14 @@ const serviceEntityPage = ( {cicdContent} + + + + @@ -188,6 +201,14 @@ const websiteEntityPage = ( {cicdContent} + + + + diff --git a/packages/create-app/templates/default-app/packages/backend/package.json.hbs b/packages/create-app/templates/default-app/packages/backend/package.json.hbs index e26c788496..8aad8a4b5d 100644 --- a/packages/create-app/templates/default-app/packages/backend/package.json.hbs +++ b/packages/create-app/templates/default-app/packages/backend/package.json.hbs @@ -28,6 +28,7 @@ "@backstage/plugin-catalog-backend": "^{{version '@backstage/plugin-catalog-backend'}}", "@backstage/plugin-catalog-backend-module-logs": "^{{version '@backstage/plugin-catalog-backend-module-logs'}}", "@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "^{{version '@backstage/plugin-catalog-backend-module-scaffolder-entity-model'}}", + "@backstage/plugin-kubernetes-backend": "^{{version '@backstage/plugin-kubernetes-backend'}}", "@backstage/plugin-permission-backend": "^{{version '@backstage/plugin-permission-backend'}}", "@backstage/plugin-permission-backend-module-allow-all-policy": "^{{version '@backstage/plugin-permission-backend-module-allow-all-policy'}}", "@backstage/plugin-permission-common": "^{{version '@backstage/plugin-permission-common'}}", diff --git a/packages/create-app/templates/default-app/packages/backend/src/index.ts b/packages/create-app/templates/default-app/packages/backend/src/index.ts index 239269288e..983202caa6 100644 --- a/packages/create-app/templates/default-app/packages/backend/src/index.ts +++ b/packages/create-app/templates/default-app/packages/backend/src/index.ts @@ -41,4 +41,7 @@ backend.add(import('@backstage/plugin-search-backend/alpha')); backend.add(import('@backstage/plugin-search-backend-module-catalog/alpha')); backend.add(import('@backstage/plugin-search-backend-module-techdocs/alpha')); +// kubernetes +backend.add(import('@backstage/plugin-kubernetes-backend/alpha')); + backend.start(); From dba4a14ee9b4ec8e2b99f94e9271cc9c26c951b8 Mon Sep 17 00:00:00 2001 From: Andre Wanlin Date: Fri, 14 Jun 2024 11:17:30 -0500 Subject: [PATCH 253/416] Added new line Signed-off-by: Andre Wanlin --- packages/create-app/templates/default-app/app-config.yaml.hbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/create-app/templates/default-app/app-config.yaml.hbs b/packages/create-app/templates/default-app/app-config.yaml.hbs index a4797d4c41..f784d5ba88 100644 --- a/packages/create-app/templates/default-app/app-config.yaml.hbs +++ b/packages/create-app/templates/default-app/app-config.yaml.hbs @@ -105,4 +105,4 @@ catalog: # - allow: [User, Group] kubernetes: - # see https://backstage.io/docs/features/kubernetes/configuration for kubernetes configuration options \ No newline at end of file + # see https://backstage.io/docs/features/kubernetes/configuration for kubernetes configuration options From f26905d7a88559eb5ca5472a3842afe745e15059 Mon Sep 17 00:00:00 2001 From: Andre Wanlin Date: Fri, 14 Jun 2024 11:48:09 -0500 Subject: [PATCH 254/416] Fixed test Signed-off-by: Andre Wanlin --- packages/create-app/src/lib/tasks.test.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/create-app/src/lib/tasks.test.ts b/packages/create-app/src/lib/tasks.test.ts index 1f507b95ed..7b17307721 100644 --- a/packages/create-app/src/lib/tasks.test.ts +++ b/packages/create-app/src/lib/tasks.test.ts @@ -88,6 +88,8 @@ jest.mock('./versions', () => ({ '@backstage/plugin-catalog-graph': '1.0.0', '@backstage/plugin-catalog-import': '1.0.0', '@backstage/plugin-catalog-react': '1.0.0', + '@backstage/plugin-kubernetes': '1.0.0', + '@backstage/plugin-kubernetes-backend': '1.0.0', '@backstage/plugin-org': '1.0.0', '@backstage/plugin-scaffolder': '1.0.0', '@backstage/plugin-permission-react': '1.0.0', From fe6ab86d9207cd1c2586aa016efdfbc007915ade Mon Sep 17 00:00:00 2001 From: Stephen Glass Date: Sun, 14 Jul 2024 15:24:38 -0400 Subject: [PATCH 255/416] Refactor review state schema processing code to support nested objects Signed-off-by: Stephen Glass --- .../ReviewState/ReviewState.test.tsx | 179 +++++++++++------- .../components/ReviewState/ReviewState.tsx | 55 +++++- .../next/components/ReviewState/util.test.ts | 170 +++-------------- .../src/next/components/ReviewState/util.ts | 55 +----- 4 files changed, 189 insertions(+), 270 deletions(-) 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 dfa1c9c097..194c5f3e77 100644 --- a/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.test.tsx +++ b/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.test.tsx @@ -69,6 +69,9 @@ describe('ReviewState', () => { const formState = { name: 'John Doe', test: 'bob', + nest: { + foo: 'bar', + }, }; const schemas: ParsedTemplateSchema[] = [ @@ -85,6 +88,20 @@ describe('ReviewState', () => { }, }, }, + nest: { + type: 'object', + properties: { + foo: { + type: 'string', + 'ui:widget': 'password', + 'ui:backstage': { + review: { + show: false, + }, + }, + }, + }, + }, }, }, schema: {}, @@ -99,12 +116,16 @@ describe('ReviewState', () => { ); expect(getAllByRole('row').length).toEqual(1); expect(queryByRole('row', { name: 'Name ******' })).not.toBeInTheDocument(); + expect(queryByRole('row', { name: 'Foo ******' })).not.toBeInTheDocument(); }); it('should allow for masking an option with a set text', () => { const formState = { name: 'John Doe', test: 'bob', + nest: { + foo: 'bar', + }, }; const schemas: ParsedTemplateSchema[] = [ @@ -121,6 +142,20 @@ describe('ReviewState', () => { }, }, }, + nest: { + type: 'object', + properties: { + foo: { + type: 'string', + 'ui:widget': 'password', + 'ui:backstage': { + review: { + mask: 'lols', + }, + }, + }, + }, + }, }, }, schema: {}, @@ -135,11 +170,15 @@ describe('ReviewState', () => { ); expect(getByRole('row', { name: 'Name lols' })).toBeInTheDocument(); + expect(getByRole('row', { name: 'Foo lols' })).toBeInTheDocument(); }); it('should display enum label from enumNames', async () => { const formState = { name: 'type2', + nest: { + foo: 'type2', + }, }; const schemas: ParsedTemplateSchema[] = [ @@ -153,6 +192,17 @@ describe('ReviewState', () => { enum: ['type1', 'type2', 'type3'], enumNames: ['Label-type1', 'Label-type2', 'Label-type3'], }, + nest: { + type: 'object', + properties: { + foo: { + type: 'string', + default: 'type1', + enum: ['type1', 'type2', 'type3'], + enumNames: ['Label-type1', 'Label-type2', 'Label-type3'], + }, + }, + }, }, }, schema: {}, @@ -169,6 +219,7 @@ describe('ReviewState', () => { expect( queryByRole('row', { name: 'Name Label-type2' }), ).toBeInTheDocument(); + expect(queryByRole('row', { name: 'Foo Label-type2' })).toBeInTheDocument(); }); it('should display enum value if no corresponding enumNames', async () => { @@ -203,7 +254,7 @@ describe('ReviewState', () => { expect(queryByRole('row', { name: 'Name type4' })).toBeInTheDocument(); }); - it('should display exploded object in separate rows', async () => { + it('should display object in separate rows', async () => { const formState = { name: { foo: 'type3', @@ -218,11 +269,6 @@ describe('ReviewState', () => { properties: { name: { type: 'object', - 'ui:backstage': { - review: { - explode: true, - }, - }, properties: { foo: { type: 'string', @@ -239,7 +285,6 @@ describe('ReviewState', () => { schema: {}, title: 'test', uiSchema: {}, - description: 'asd', }, ]; @@ -251,7 +296,7 @@ describe('ReviewState', () => { expect(queryByRole('row', { name: 'Bar type4' })).toBeInTheDocument(); }); - it('should display exploded nested objects', async () => { + it('should display nested objects in separate rows', async () => { const formState = { name: { foo: 'type3', @@ -269,11 +314,60 @@ describe('ReviewState', () => { properties: { name: { type: 'object', - 'ui:backstage': { - review: { - explode: true, + properties: { + foo: { + type: 'string', + default: 'type1', + }, + bar: { + type: 'string', + default: 'type2', + }, + example: { + type: 'object', + properties: { + test: { + type: 'string', + }, + }, }, }, + }, + }, + }, + schema: {}, + title: 'test', + uiSchema: {}, + }, + ]; + + const { queryByRole } = render( + , + ); + + expect(queryByRole('row', { name: 'Foo type3' })).toBeInTheDocument(); + expect(queryByRole('row', { name: 'Bar type4' })).toBeInTheDocument(); + expect(queryByRole('row', { name: 'Test type6' })).toBeInTheDocument(); + }); + + it('should display partially nested objects', async () => { + const formState = { + name: { + foo: 'type3', + bar: 'type4', + example: { + test: 'type6', + }, + }, + }; + + const schemas: ParsedTemplateSchema[] = [ + { + mergedSchema: { + type: 'object', + properties: { + name: { + type: 'object', properties: { foo: { type: 'string', @@ -287,7 +381,7 @@ describe('ReviewState', () => { type: 'object', 'ui:backstage': { review: { - explode: true, + explode: false, }, }, properties: { @@ -303,67 +397,6 @@ describe('ReviewState', () => { schema: {}, title: 'test', uiSchema: {}, - description: 'asd', - }, - ]; - - const { queryByRole } = render( - , - ); - - expect(queryByRole('row', { name: 'Foo type3' })).toBeInTheDocument(); - expect(queryByRole('row', { name: 'Bar type4' })).toBeInTheDocument(); - expect(queryByRole('row', { name: 'Test type6' })).toBeInTheDocument(); - }); - - it('should display partially exploded nested objects', async () => { - const formState = { - name: { - foo: 'type3', - bar: 'type4', - example: { - test: 'type6', - }, - }, - }; - - const schemas: ParsedTemplateSchema[] = [ - { - mergedSchema: { - type: 'object', - properties: { - name: { - type: 'object', - 'ui:backstage': { - review: { - explode: true, - }, - }, - properties: { - foo: { - type: 'string', - default: 'type1', - }, - bar: { - type: 'string', - default: 'type2', - }, - example: { - type: 'object', - properties: { - test: { - type: 'string', - }, - }, - }, - }, - }, - }, - }, - schema: {}, - title: 'test', - uiSchema: {}, - description: 'asd', }, ]; diff --git a/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.tsx b/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.tsx index d320ad80a6..d87584afff 100644 --- a/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.tsx +++ b/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.tsx @@ -15,10 +15,10 @@ */ import React from 'react'; import { StructuredMetadataTable } from '@backstage/core-components'; -import { JsonObject } from '@backstage/types'; +import { JsonObject, JsonValue } from '@backstage/types'; import { Draft07 as JSONSchema } from 'json-schema-library'; import { ParsedTemplateSchema } from '../../hooks/useTemplateSchema'; -import { processEntry } from './util'; +import { isJsonObject, getLastKey } from './util'; /** * The props for the {@link ReviewState} component. @@ -29,6 +29,55 @@ export type ReviewStateProps = { formState: JsonObject; }; +function processSchema( + key: string, + value: JsonValue | undefined, + schema: ParsedTemplateSchema, + formState: JsonObject, +): [string, JsonValue | undefined][] { + const parsedSchema = new JSONSchema(schema.mergedSchema); + const definitionInSchema = parsedSchema.getSchema({ + pointer: `#/${key}`, + data: formState, + }); + + if (definitionInSchema) { + const backstageReviewOptions = definitionInSchema['ui:backstage']?.review; + if (backstageReviewOptions) { + if (backstageReviewOptions.mask) { + return [[getLastKey(key), backstageReviewOptions.mask]]; + } + if (backstageReviewOptions.show === false) { + return []; + } + } + + if (definitionInSchema['ui:widget'] === 'password') { + return [[getLastKey(key), '******']]; + } + + if (definitionInSchema.enum && definitionInSchema.enumNames) { + return [ + [ + getLastKey(key), + definitionInSchema.enumNames[ + definitionInSchema.enum.indexOf(value) + ] || value, + ], + ]; + } + + if (backstageReviewOptions?.explode !== false && isJsonObject(value)) { + // Recurse nested objects + return Object.entries(value).flatMap(([nestedKey, nestedValue]) => + processSchema(`${key}/${nestedKey}`, nestedValue, schema, formState), + ); + } + } + + return [[getLastKey(key), value]]; +} + /** * The component used by the {@link Stepper} to render the review step. * @alpha @@ -38,7 +87,7 @@ export const ReviewState = (props: ReviewStateProps) => { Object.entries(props.formState) .flatMap(([key, value]) => { for (const step of props.schemas) { - return processEntry(key, value, step, props.formState); + return processSchema(key, value, step, props.formState); } return [[key, value]]; }) diff --git a/plugins/scaffolder-react/src/next/components/ReviewState/util.test.ts b/plugins/scaffolder-react/src/next/components/ReviewState/util.test.ts index e2a10587dc..9b88ff157e 100644 --- a/plugins/scaffolder-react/src/next/components/ReviewState/util.test.ts +++ b/plugins/scaffolder-react/src/next/components/ReviewState/util.test.ts @@ -14,9 +14,7 @@ * limitations under the License. */ -import { flattenObject, isJsonObject } from './util'; -import { Draft07 as JSONSchema } from 'json-schema-library'; -import { ParsedTemplateSchema } from '../../hooks/useTemplateSchema'; +import { isJsonObject, getLastKey } from './util'; describe('isJsonObject', () => { it('should return true for non-null objects', () => { @@ -24,10 +22,6 @@ describe('isJsonObject', () => { expect(isJsonObject({ key: 'value' })).toBe(true); }); - it('should return false for null', () => { - expect(isJsonObject(null)).toBe(false); - }); - it('should return false for arrays', () => { expect(isJsonObject([])).toBe(false); expect(isJsonObject([1, 2, 3])).toBe(false); @@ -41,146 +35,40 @@ describe('isJsonObject', () => { }); }); -describe('flattenObject', () => { - it('should handle an empty object', () => { - const schemas: ParsedTemplateSchema[] = [ - { - mergedSchema: { - type: 'object', - properties: { - name: { - type: 'object', - 'ui:backstage': { - review: { - explode: true, - }, - }, - properties: {}, - }, - }, - }, - schema: {}, - title: 'test', - uiSchema: {}, - }, - ]; - - const parsedSchema = new JSONSchema(schemas[0].mergedSchema); - - const result = flattenObject({}, '', parsedSchema, {}); - - expect(result).toEqual([]); +describe('getLastKey', () => { + it('should return the last part of a simple key', () => { + expect(getLastKey('simple')).toBe('simple'); }); - it('should flatten a simple object', () => { - const formState = { - name: { - foo: 'value1', - bar: 'value2', - }, - }; - - const schemas: ParsedTemplateSchema[] = [ - { - mergedSchema: { - type: 'object', - properties: { - name: { - type: 'object', - 'ui:backstage': { - review: { - explode: true, - }, - }, - properties: { - foo: { - type: 'string', - }, - bar: { - type: 'string', - }, - }, - }, - }, - }, - schema: {}, - title: 'test', - uiSchema: {}, - }, - ]; - - const [key, value] = Object.entries(formState)[0]; - const parsedSchema = new JSONSchema(schemas[0].mergedSchema); - - const result = flattenObject(value, key, parsedSchema, formState); - - expect(result).toEqual([ - ['foo', 'value1'], - ['bar', 'value2'], - ]); + it('should return the last part of a nested key', () => { + expect(getLastKey('parent/child')).toBe('child'); }); - it('should recurse into a nested object', () => { - const formState = { - name: { - foo: 'value1', - bar: 'value2', - example: { - test: 'value3', - }, - }, - }; - const schemas: ParsedTemplateSchema[] = [ - { - mergedSchema: { - type: 'object', - properties: { - name: { - type: 'object', - 'ui:backstage': { - review: { - explode: true, - }, - }, - properties: { - foo: { - type: 'string', - }, - bar: { - type: 'string', - }, - example: { - type: 'object', - 'ui:backstage': { - review: { - explode: true, - }, - }, - properties: { - test: { - type: 'string', - }, - }, - }, - }, - }, - }, - }, - schema: {}, - title: 'test', - uiSchema: {}, - }, - ]; + it('should return the last part of a deeply nested key', () => { + expect(getLastKey('grandparent/parent/child')).toBe('child'); + }); - const [key, value] = Object.entries(formState)[0]; - const parsedSchema = new JSONSchema(schemas[0].mergedSchema); + it('should handle keys with trailing slash', () => { + expect(getLastKey('parent/child/')).toBe(''); + }); - const result = flattenObject(value, key, parsedSchema, formState); + it('should handle empty string', () => { + expect(getLastKey('')).toBe(''); + }); - expect(result).toEqual([ - ['foo', 'value1'], - ['bar', 'value2'], - ['test', 'value3'], - ]); + it('should handle keys with multiple consecutive slashes', () => { + expect(getLastKey('parent//child')).toBe('child'); + }); + + it('should handle keys with only slashes', () => { + expect(getLastKey('////')).toBe(''); + }); + + it('should handle keys with spaces', () => { + expect(getLastKey('parent/child with spaces')).toBe('child with spaces'); + }); + + it('should handle keys with special characters', () => { + expect(getLastKey('parent/child@!#$%^&*()')).toBe('child@!#$%^&*()'); }); }); diff --git a/plugins/scaffolder-react/src/next/components/ReviewState/util.ts b/plugins/scaffolder-react/src/next/components/ReviewState/util.ts index e040b851d3..52503bedfd 100644 --- a/plugins/scaffolder-react/src/next/components/ReviewState/util.ts +++ b/plugins/scaffolder-react/src/next/components/ReviewState/util.ts @@ -16,64 +16,13 @@ */ import { JsonObject, JsonValue } from '@backstage/types'; -import { Draft07 as JSONSchema } from 'json-schema-library'; -import { ParsedTemplateSchema } from '../../hooks'; export function isJsonObject(value?: JsonValue): value is JsonObject { - return typeof value === 'object' && value !== null && !Array.isArray(value); -} - -export function processEntry( - key: string, - value: JsonValue | undefined, - schema: ParsedTemplateSchema, - formState: JsonObject, -): [string, JsonValue | undefined][] { - const parsedSchema = new JSONSchema(schema.mergedSchema); - const definitionInSchema = parsedSchema.getSchema({ - pointer: `#/${key}`, - data: formState, - }); - - if (definitionInSchema) { - const backstageReviewOptions = definitionInSchema['ui:backstage']?.review; - if (backstageReviewOptions) { - if (backstageReviewOptions.mask) { - return [[getLastKey(key), backstageReviewOptions.mask]]; - } - if (backstageReviewOptions.show === false) { - return []; - } - } - - if (isJsonObject(value)) { - // Process nested objects - return Object.entries(value).flatMap(([nestedKey, nestedValue]) => - processEntry(`${key}/${nestedKey}`, nestedValue, schema, formState), - ); - } - - if (definitionInSchema['ui:widget'] === 'password') { - return [[getLastKey(key), '******']]; - } - - if (definitionInSchema.enum && definitionInSchema.enumNames) { - return [ - [ - getLastKey(key), - definitionInSchema.enumNames[ - definitionInSchema.enum.indexOf(value) - ] || value, - ], - ]; - } - } - - return [[getLastKey(key), value]]; + return typeof value === 'object' && !Array.isArray(value); } // Helper function to get the last part of the key -function getLastKey(key: string): string { +export function getLastKey(key: string): string { const parts = key.split('/'); return parts[parts.length - 1]; } From ba67e2884712d3036c10e3d9b19c126305a5d16d Mon Sep 17 00:00:00 2001 From: Stephen Glass Date: Sun, 14 Jul 2024 15:37:16 -0400 Subject: [PATCH 256/416] Remove comment Signed-off-by: Stephen Glass --- plugins/scaffolder-react/src/next/components/ReviewState/util.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/scaffolder-react/src/next/components/ReviewState/util.ts b/plugins/scaffolder-react/src/next/components/ReviewState/util.ts index 52503bedfd..49c3b30e7a 100644 --- a/plugins/scaffolder-react/src/next/components/ReviewState/util.ts +++ b/plugins/scaffolder-react/src/next/components/ReviewState/util.ts @@ -1,4 +1,3 @@ -/* eslint-disable no-console */ /* * Copyright 2022 The Backstage Authors * From 486c7d7b2638263c252ead495ad04113bb32dcdd Mon Sep 17 00:00:00 2001 From: Evan Shortiss Date: Sun, 14 Jul 2024 21:36:53 -0700 Subject: [PATCH 257/416] docs: fix typo and link in contributing.md Signed-off-by: Evan Shortiss --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ce0e97c781..f10116844b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -99,7 +99,7 @@ You'll see how you get both logs for the frontend `webpack-dev-server` which ser Visit and you should see the bleeding edge of Backstage ready for contributions! -If you want to get a better understanding of the layout of the repo not that you have a local copy running feel free to review the [Backstage Project Structure](https://backstage.io/docs/getting-started/project-structure) documentation. +If you want to get a better understanding of the layout of the repo now that you have a local copy running feel free to review the [Backstage Project Structure](https://backstage.io/docs/getting-started/#general-folder-structure) documentation. ## Coding Guidelines From 8c4d6bca9af7ae412d700d5d049dfa9e4e6665af Mon Sep 17 00:00:00 2001 From: David Weber Date: Mon, 15 Jul 2024 08:11:36 +0200 Subject: [PATCH 258/416] ci: add timeout to cron job Signed-off-by: David Weber Signed-off-by: David Weber --- .github/workflows/cron.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/cron.yml b/.github/workflows/cron.yml index 923293667a..bdbe22aae8 100644 --- a/.github/workflows/cron.yml +++ b/.github/workflows/cron.yml @@ -7,6 +7,7 @@ on: jobs: cron: runs-on: ubuntu-latest + timeout-minutes: 10 steps: - name: Harden Runner uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 From e6e293ca30256d8d7641f5c9ff27e29b76f149de Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Mon, 15 Jul 2024 10:22:21 +0200 Subject: [PATCH 259/416] chore: extract BaseRepoUrlPickerProps Signed-off-by: Benjamin Janssens --- .../fields/RepoUrlPicker/AzureRepoPicker.tsx | 15 +++++++-------- .../RepoUrlPicker/BitbucketRepoPicker.tsx | 17 ++++++++--------- .../fields/RepoUrlPicker/GerritRepoPicker.tsx | 8 ++------ .../fields/RepoUrlPicker/GiteaRepoPicker.tsx | 15 +++++++-------- .../fields/RepoUrlPicker/GithubRepoPicker.tsx | 13 ++++++------- .../fields/RepoUrlPicker/GitlabRepoPicker.tsx | 15 +++++++-------- .../components/fields/RepoUrlPicker/types.ts | 6 ++++++ 7 files changed, 43 insertions(+), 46 deletions(-) diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/AzureRepoPicker.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/AzureRepoPicker.tsx index 833a0849fb..48fcb4f6af 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/AzureRepoPicker.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/AzureRepoPicker.tsx @@ -19,16 +19,15 @@ import FormControl from '@material-ui/core/FormControl'; import FormHelperText from '@material-ui/core/FormHelperText'; import Input from '@material-ui/core/Input'; import InputLabel from '@material-ui/core/InputLabel'; -import { RepoUrlPickerState } from './types'; +import { BaseRepoUrlPickerProps } from './types'; import { Select, SelectItem } from '@backstage/core-components'; -export const AzureRepoPicker = (props: { - allowedOrganizations?: string[]; - allowedProject?: string[]; - rawErrors: string[]; - state: RepoUrlPickerState; - onChange: (state: RepoUrlPickerState) => void; -}) => { +export const AzureRepoPicker = ( + props: BaseRepoUrlPickerProps<{ + allowedOrganizations?: string[]; + allowedProject?: string[]; + }>, +) => { const { allowedOrganizations = [], allowedProject = [], diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx index 10d4a6e6c3..5d627e9512 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx @@ -17,7 +17,7 @@ import React, { useEffect, useState } from 'react'; import FormControl from '@material-ui/core/FormControl'; import FormHelperText from '@material-ui/core/FormHelperText'; import { Select, SelectItem } from '@backstage/core-components'; -import { RepoUrlPickerState } from './types'; +import { BaseRepoUrlPickerProps } from './types'; import Autocomplete from '@material-ui/lab/Autocomplete'; import TextField from '@material-ui/core/TextField'; import useDebounce from 'react-use/esm/useDebounce'; @@ -33,14 +33,13 @@ import { scaffolderApiRef } from '@backstage/plugin-scaffolder-react'; * @param allowedProjects - Allowed projects for the Bitbucket cloud repository * */ -export const BitbucketRepoPicker = (props: { - allowedOwners?: string[]; - allowedProjects?: string[]; - onChange: (state: RepoUrlPickerState) => void; - state: RepoUrlPickerState; - rawErrors: string[]; - accessToken?: string; -}) => { +export const BitbucketRepoPicker = ( + props: BaseRepoUrlPickerProps<{ + allowedOwners?: string[]; + allowedProjects?: string[]; + accessToken?: string; + }>, +) => { const { allowedOwners = [], allowedProjects = [], diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/GerritRepoPicker.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/GerritRepoPicker.tsx index 13af966c25..1b13c5eb29 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/GerritRepoPicker.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/GerritRepoPicker.tsx @@ -18,13 +18,9 @@ import FormControl from '@material-ui/core/FormControl'; import FormHelperText from '@material-ui/core/FormHelperText'; import Input from '@material-ui/core/Input'; import InputLabel from '@material-ui/core/InputLabel'; -import { RepoUrlPickerState } from './types'; +import { BaseRepoUrlPickerProps } from './types'; -export const GerritRepoPicker = (props: { - onChange: (state: RepoUrlPickerState) => void; - state: RepoUrlPickerState; - rawErrors: string[]; -}) => { +export const GerritRepoPicker = (props: BaseRepoUrlPickerProps) => { const { onChange, rawErrors, state } = props; const { workspace, owner } = state; return ( diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/GiteaRepoPicker.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/GiteaRepoPicker.tsx index 566a2732e3..9fb3af211f 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/GiteaRepoPicker.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/GiteaRepoPicker.tsx @@ -19,15 +19,14 @@ import FormHelperText from '@material-ui/core/FormHelperText'; import Input from '@material-ui/core/Input'; import InputLabel from '@material-ui/core/InputLabel'; import { Select, SelectItem } from '@backstage/core-components'; -import { RepoUrlPickerState } from './types'; +import { BaseRepoUrlPickerProps } from './types'; -export const GiteaRepoPicker = (props: { - allowedOwners?: string[]; - allowedRepos?: string[]; - state: RepoUrlPickerState; - onChange: (state: RepoUrlPickerState) => void; - rawErrors: string[]; -}) => { +export const GiteaRepoPicker = ( + props: BaseRepoUrlPickerProps<{ + allowedOwners?: string[]; + allowedRepos?: string[]; + }>, +) => { const { allowedOwners = [], state, onChange, rawErrors } = props; const ownerItems: SelectItem[] = allowedOwners ? allowedOwners.map(i => ({ label: i, value: i })) diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/GithubRepoPicker.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/GithubRepoPicker.tsx index ec59d89ef8..5d46dc4333 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/GithubRepoPicker.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/GithubRepoPicker.tsx @@ -19,14 +19,13 @@ import FormHelperText from '@material-ui/core/FormHelperText'; import Input from '@material-ui/core/Input'; import InputLabel from '@material-ui/core/InputLabel'; import { Select, SelectItem } from '@backstage/core-components'; -import { RepoUrlPickerState } from './types'; +import { BaseRepoUrlPickerProps } from './types'; -export const GithubRepoPicker = (props: { - allowedOwners?: string[]; - rawErrors: string[]; - state: RepoUrlPickerState; - onChange: (state: RepoUrlPickerState) => void; -}) => { +export const GithubRepoPicker = ( + props: BaseRepoUrlPickerProps<{ + allowedOwners?: string[]; + }>, +) => { const { allowedOwners = [], rawErrors, state, onChange } = props; const ownerItems: SelectItem[] = allowedOwners ? allowedOwners.map(i => ({ label: i, value: i })) diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/GitlabRepoPicker.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/GitlabRepoPicker.tsx index fbcc13c846..12ae37bf15 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/GitlabRepoPicker.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/GitlabRepoPicker.tsx @@ -19,15 +19,14 @@ import FormHelperText from '@material-ui/core/FormHelperText'; import Input from '@material-ui/core/Input'; import InputLabel from '@material-ui/core/InputLabel'; import { Select, SelectItem } from '@backstage/core-components'; -import { RepoUrlPickerState } from './types'; +import { BaseRepoUrlPickerProps } from './types'; -export const GitlabRepoPicker = (props: { - allowedOwners?: string[]; - allowedRepos?: string[]; - state: RepoUrlPickerState; - onChange: (state: RepoUrlPickerState) => void; - rawErrors: string[]; -}) => { +export const GitlabRepoPicker = ( + props: BaseRepoUrlPickerProps<{ + allowedOwners?: string[]; + allowedRepos?: string[]; + }>, +) => { const { allowedOwners = [], state, onChange, rawErrors } = props; const ownerItems: SelectItem[] = allowedOwners ? allowedOwners.map(i => ({ label: i, value: i })) diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/types.ts b/plugins/scaffolder/src/components/fields/RepoUrlPicker/types.ts index 1430b10b84..9489901d61 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/types.ts +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/types.ts @@ -22,3 +22,9 @@ export interface RepoUrlPickerState { project?: string; availableRepos?: string[]; } + +export type BaseRepoUrlPickerProps = T & { + onChange: (state: RepoUrlPickerState) => void; + state: RepoUrlPickerState; + rawErrors: string[]; +}; From 6b8bab93beaee731a7db18b818cb13af21e848c3 Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Mon, 15 Jul 2024 10:40:19 +0200 Subject: [PATCH 260/416] refactor: use useCallback for autocompletion updates in BitbucketRepoPicker Signed-off-by: Benjamin Janssens --- .../RepoUrlPicker/BitbucketRepoPicker.tsx | 153 +++++++++--------- 1 file changed, 75 insertions(+), 78 deletions(-) diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx index 5d627e9512..0b7ee49525 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import React, { useEffect, useState } from 'react'; +import React, { useCallback, useEffect, useState } from 'react'; import FormControl from '@material-ui/core/FormControl'; import FormHelperText from '@material-ui/core/FormHelperText'; import { Select, SelectItem } from '@backstage/core-components'; @@ -68,93 +68,90 @@ export const BitbucketRepoPicker = ( const [availableProjects, setAvailableProjects] = useState([]); // Update available workspaces when client is available - useDebounce( - () => { - const updateAvailableWorkspaces = async () => { - if ( - host === 'bitbucket.org' && - accessToken && - scaffolderApi.autocomplete - ) { - const { results } = await scaffolderApi.autocomplete({ - token: accessToken, - resource: 'workspaces', - context: {}, - provider: 'bitbucket-cloud', - }); + const updateAvailableWorkspaces = useCallback(() => { + if ( + !scaffolderApi.autocomplete || + !accessToken || + host !== 'bitbucket.org' + ) { + setAvailableWorkspaces([]); + return; + } - setAvailableWorkspaces(results.map(r => r.title)); - } else { - setAvailableWorkspaces([]); - } - }; + scaffolderApi + .autocomplete({ + token: accessToken, + resource: 'workspaces', + provider: 'bitbucket-cloud', + }) + .then(({ results }) => { + setAvailableWorkspaces(results.map(r => r.title)); + }) + .catch(() => { + setAvailableWorkspaces([]); + }); + }, [scaffolderApi, accessToken, host]); - updateAvailableWorkspaces().catch(() => setAvailableWorkspaces([])); - }, - 500, - [host, accessToken], - ); + useDebounce(updateAvailableWorkspaces, 500, [updateAvailableWorkspaces]); // Update available projects when client is available and workspace changes - useDebounce( - () => { - const updateAvailableProjects = async () => { - if ( - host === 'bitbucket.org' && - accessToken && - workspace && - scaffolderApi.autocomplete - ) { - const { results } = await scaffolderApi.autocomplete({ - token: accessToken, - resource: 'projects', - context: { workspace }, - provider: 'bitbucket-cloud', - }); + const updateAvailableProjects = useCallback(() => { + if ( + !scaffolderApi.autocomplete || + !accessToken || + host !== 'bitbucket.org' || + !workspace + ) { + setAvailableProjects([]); + return; + } - setAvailableProjects(results.map(r => r.title)); - } else { - setAvailableProjects([]); - } - }; + scaffolderApi + .autocomplete({ + token: accessToken, + resource: 'projects', + context: { workspace }, + provider: 'bitbucket-cloud', + }) + .then(({ results }) => { + setAvailableProjects(results.map(r => r.title)); + }) + .catch(() => { + setAvailableProjects([]); + }); + }, [scaffolderApi, accessToken, host, workspace]); - updateAvailableProjects().catch(() => setAvailableProjects([])); - }, - 500, - [host, accessToken, workspace], - ); + useDebounce(updateAvailableProjects, 500, [updateAvailableProjects]); // Update available repositories when client is available and workspace or project changes - useDebounce( - () => { - const updateAvailableRepositories = async () => { - if ( - host === 'bitbucket.org' && - accessToken && - workspace && - project && - scaffolderApi.autocomplete - ) { - const { results } = await scaffolderApi.autocomplete({ - token: accessToken, - resource: 'repositories', - context: { workspace, project }, - provider: 'bitbucket-cloud', - }); + const updateAvailableRepositories = useCallback(() => { + if ( + !scaffolderApi.autocomplete || + !accessToken || + host !== 'bitbucket.org' || + !workspace || + !project + ) { + onChange({ availableRepos: [] }); + return; + } - onChange({ availableRepos: results.map(r => r.title) }); - } else { - onChange({ availableRepos: [] }); - } - }; + scaffolderApi + .autocomplete({ + token: accessToken, + resource: 'repositories', + context: { workspace, project }, + provider: 'bitbucket-cloud', + }) + .then(({ results }) => { + onChange({ availableRepos: results.map(r => r.title) }); + }) + .catch(() => { + onChange({ availableRepos: [] }); + }); + }, [scaffolderApi, accessToken, host, workspace, project, onChange]); - updateAvailableRepositories().catch(() => - onChange({ availableRepos: [] }), - ); - }, - 500, - [host, accessToken, workspace, project], - ); + useDebounce(updateAvailableRepositories, 500, [updateAvailableRepositories]); return ( <> From 7f153f94c1c3d1849e418109e097b03914941113 Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Mon, 15 Jul 2024 10:44:22 +0200 Subject: [PATCH 261/416] test: simplify checking for the secret in the document; remove SecretsComponent from test that didn't use it Signed-off-by: Benjamin Janssens --- .../RepoUrlPicker/RepoUrlPicker.test.tsx | 47 ++++++------------- 1 file changed, 15 insertions(+), 32 deletions(-) diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.test.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.test.tsx index 002652cfab..f0e47a2504 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.test.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.test.tsx @@ -214,13 +214,14 @@ describe('RepoUrlPicker', () => { describe('requestUserCredentials', () => { it('should call the scmAuthApi with the correct params', async () => { + const secretsKey = 'testKey'; + const SecretsComponent = () => { const { secrets } = useTemplateSecrets(); - return ( -
      {JSON.stringify({ secrets })}
      - ); + const secret = secrets[secretsKey]; + return secret ?
      {secret}
      : null; }; - const { getByTestId } = await renderInTestApp( + const { getByText } = await renderInTestApp( { 'ui:field': 'RepoUrlPicker', 'ui:options': { requestUserCredentials: { - secretsKey: 'testKey', + secretsKey, additionalScopes: { github: ['workflow'] }, }, }, @@ -265,21 +266,9 @@ describe('RepoUrlPicker', () => { }, }); - const currentSecrets = JSON.parse( - getByTestId('current-secrets').textContent!, - ); - - expect(currentSecrets).toEqual({ - secrets: { testKey: 'abc123' }, - }); + expect(getByText('abc123')).toBeInTheDocument(); }); it('should call the scmAuthApi with the correct params if workspace is nested', async () => { - const SecretsComponent = () => { - const { secrets } = useTemplateSecrets(); - return ( -
      {JSON.stringify({ secrets })}
      - ); - }; await renderInTestApp( { RepoUrlPicker: RepoUrlPicker as ScaffolderRJSFField, }} /> - , ); @@ -324,13 +312,14 @@ describe('RepoUrlPicker', () => { }); it('should not call the scmAuthApi if secret is available in the state', async () => { + const secretsKey = 'testKey'; + const SecretsComponent = () => { const { secrets } = useTemplateSecrets(); - return ( -
      {JSON.stringify({ secrets })}
      - ); + const secret = secrets[secretsKey]; + return secret ?
      {secret}
      : null; }; - const { getByTestId } = await renderInTestApp( + const { getByText } = await renderInTestApp( { [scaffolderApiRef, mockScaffolderApi], ]} > - +
      { 'ui:field': 'RepoUrlPicker', 'ui:options': { requestUserCredentials: { - secretsKey: 'testKey', + secretsKey, additionalScopes: { github: ['workflow'] }, }, }, @@ -368,13 +357,7 @@ describe('RepoUrlPicker', () => { // as we already have a secret in the state, getCredentials should not be called again. expect(mockScmAuthApi.getCredentials).toHaveBeenCalledTimes(0); - const currentSecrets = JSON.parse( - getByTestId('current-secrets').textContent!, - ); - - expect(currentSecrets).toEqual({ - secrets: { testKey: 'abc123' }, - }); + expect(getByText('abc123')).toBeInTheDocument(); }); }); }); From bbd9f56c764b3fc22c79a279bca48f70d6c83dea Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Mon, 15 Jul 2024 10:49:56 +0200 Subject: [PATCH 262/416] chore: add changeset Signed-off-by: Benjamin Janssens --- .changeset/spotty-planets-accept.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/spotty-planets-accept.md diff --git a/.changeset/spotty-planets-accept.md b/.changeset/spotty-planets-accept.md new file mode 100644 index 0000000000..db262dd8b5 --- /dev/null +++ b/.changeset/spotty-planets-accept.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder': patch +--- + +Cleaned up codebase From 9a5e7f1c36934b6eca39c8c13fbc35bcc43fefb2 Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Mon, 15 Jul 2024 10:51:24 +0200 Subject: [PATCH 263/416] chore: update changeset Signed-off-by: Benjamin Janssens --- .changeset/spotty-planets-accept.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/spotty-planets-accept.md b/.changeset/spotty-planets-accept.md index db262dd8b5..7342f89bd1 100644 --- a/.changeset/spotty-planets-accept.md +++ b/.changeset/spotty-planets-accept.md @@ -2,4 +2,4 @@ '@backstage/plugin-scaffolder': patch --- -Cleaned up codebase +Cleaned up codebase of RepoUrlPicker From c4a4a69912e004dbfa622d9f2107410af8fffd34 Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Mon, 15 Jul 2024 11:15:21 +0200 Subject: [PATCH 264/416] test: fix BitbucketRepoPicker tests Signed-off-by: Benjamin Janssens --- .../fields/RepoUrlPicker/BitbucketRepoPicker.test.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.test.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.test.tsx index 2ae89233ff..570c5bd664 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.test.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.test.tsx @@ -27,9 +27,11 @@ import { act } from 'react-dom/test-utils'; describe('BitbucketRepoPicker', () => { const scaffolderApiMock: Partial = { - autocomplete: jest.fn().mockImplementation(opts => ({ - results: [{ title: `${opts.resource}_example` }], - })), + autocomplete: jest.fn().mockImplementation(opts => + Promise.resolve({ + results: [{ title: `${opts.resource}_example` }], + }), + ), }; it('renders a select if there is a list of allowed owners', async () => { From a5bcb9c4d59af4c50bff0160bec566e49753a3a0 Mon Sep 17 00:00:00 2001 From: Niall Thomson Date: Mon, 15 Jul 2024 05:58:02 -0600 Subject: [PATCH 265/416] Update plugins/catalog-backend-module-aws/src/awsOrganization/config.ts Co-authored-by: Vincenzo Scamporlino Signed-off-by: Niall Thomson --- plugins/catalog-backend-module-aws/src/awsOrganization/config.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/catalog-backend-module-aws/src/awsOrganization/config.ts b/plugins/catalog-backend-module-aws/src/awsOrganization/config.ts index ff00af48e4..ea16394e0a 100644 --- a/plugins/catalog-backend-module-aws/src/awsOrganization/config.ts +++ b/plugins/catalog-backend-module-aws/src/awsOrganization/config.ts @@ -22,6 +22,7 @@ import { Config } from '@backstage/config'; export type AwsOrganizationProviderConfig = { /** * The role to assume for the processor. + * @deprecated Use `accountId` instead. */ roleArn?: string; From 133464cfe04566513fc26633fadd2874a9d61bdc Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 15 Jul 2024 13:14:03 +0200 Subject: [PATCH 266/416] cli: add initial experimental support for dynamic plugins Signed-off-by: Patrik Oldsberg --- .changeset/clever-carrots-refuse.md | 5 + .changeset/fair-meals-juggle.md | 5 + packages/cli-node/src/roles/PackageRoles.ts | 5 + packages/cli/package.json | 1 + .../cli/src/commands/build/buildFrontend.ts | 8 + packages/cli/src/commands/build/command.ts | 19 + packages/cli/src/lib/bundler/bundle.ts | 48 +- packages/cli/src/lib/bundler/config.ts | 92 ++- packages/cli/src/lib/bundler/optimization.ts | 7 + packages/cli/src/lib/bundler/types.ts | 9 + yarn.lock | 577 ++++++++++++++++-- 11 files changed, 696 insertions(+), 80 deletions(-) create mode 100644 .changeset/clever-carrots-refuse.md create mode 100644 .changeset/fair-meals-juggle.md diff --git a/.changeset/clever-carrots-refuse.md b/.changeset/clever-carrots-refuse.md new file mode 100644 index 0000000000..24217b1045 --- /dev/null +++ b/.changeset/clever-carrots-refuse.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli-node': patch +--- + +Added internal metadata for the new experimental `frontend-dynamic-container` role. diff --git a/.changeset/fair-meals-juggle.md b/.changeset/fair-meals-juggle.md new file mode 100644 index 0000000000..94db114170 --- /dev/null +++ b/.changeset/fair-meals-juggle.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Added experimental support for dynamic frontend plugin builds, enabled via setting `EXPERIMENTAL_MODULE_FEDERATION` for the app build, and using the `frontend-dynamic-container` package role to create a container. Both of these are experimental and will change in the future. diff --git a/packages/cli-node/src/roles/PackageRoles.ts b/packages/cli-node/src/roles/PackageRoles.ts index 401568ad6d..70b62e2479 100644 --- a/packages/cli-node/src/roles/PackageRoles.ts +++ b/packages/cli-node/src/roles/PackageRoles.ts @@ -58,6 +58,11 @@ const packageRoleInfos: PackageRoleInfo[] = [ platform: 'web', output: ['types', 'esm'], }, + { + role: 'frontend-dynamic-container' as PackageRole, // experimental + platform: 'web', + output: ['bundle'], + }, { role: 'backend-plugin', platform: 'node', diff --git a/packages/cli/package.json b/packages/cli/package.json index 393f1217e1..97c15b16f2 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -53,6 +53,7 @@ "@backstage/release-manifests": "workspace:^", "@backstage/types": "workspace:^", "@manypkg/get-packages": "^1.1.3", + "@module-federation/enhanced": "^0.1.19", "@octokit/graphql": "^5.0.0", "@octokit/graphql-schema": "^13.7.0", "@octokit/oauth-app": "^4.2.0", diff --git a/packages/cli/src/commands/build/buildFrontend.ts b/packages/cli/src/commands/build/buildFrontend.ts index 6d7ca2e6a9..931a3b376a 100644 --- a/packages/cli/src/commands/build/buildFrontend.ts +++ b/packages/cli/src/commands/build/buildFrontend.ts @@ -24,6 +24,7 @@ interface BuildAppOptions { targetDir: string; writeStats: boolean; configPaths: string[]; + moduleFederationMode?: 'host' | 'remote'; } export async function buildFrontend(options: BuildAppOptions) { @@ -34,6 +35,13 @@ export async function buildFrontend(options: BuildAppOptions) { entry: 'src/index', parallelism: getEnvironmentParallelism(), statsJsonEnabled: writeStats, + moduleFederation: options.moduleFederationMode && { + // The default output mode requires the name to be a usable as a code + // symbol, there might be better options here but for now we need to + // sanitize the name. + name: name.replaceAll('@', '').replaceAll(/[/\\_-]/g, '_'), + mode: options.moduleFederationMode, + }, ...(await loadCliConfig({ args: configPaths, fromPackage: name, diff --git a/packages/cli/src/commands/build/command.ts b/packages/cli/src/commands/build/command.ts index f15ae27ee0..285cba0e81 100644 --- a/packages/cli/src/commands/build/command.ts +++ b/packages/cli/src/commands/build/command.ts @@ -22,6 +22,7 @@ import { paths } from '../../lib/paths'; import { buildFrontend } from './buildFrontend'; import { buildBackend } from './buildBackend'; import { isValidUrl } from '../../lib/urls'; +import chalk from 'chalk'; export async function command(opts: OptionValues): Promise { const role = await findRoleFromCommand(opts); @@ -39,6 +40,9 @@ export async function command(opts: OptionValues): Promise { targetDir: paths.targetDir, configPaths, writeStats: Boolean(opts.stats), + moduleFederationMode: process.env.EXPERIMENTAL_MODULE_FEDERATION + ? 'host' + : undefined, }); } return buildBackend({ @@ -49,6 +53,21 @@ export async function command(opts: OptionValues): Promise { }); } + // experimental + if ((role as string) === 'frontend-dynamic-container') { + console.log( + chalk.yellow( + `⚠️ WARNING: The 'frontend-dynamic-container' package role is experimental and will receive immediate breaking changes in the future.`, + ), + ); + return buildFrontend({ + targetDir: paths.targetDir, + configPaths: [], + writeStats: Boolean(opts.stats), + moduleFederationMode: 'remote', + }); + } + const roleInfo = PackageRoles.getRoleInfo(role); const outputs = new Set(); diff --git a/packages/cli/src/lib/bundler/bundle.ts b/packages/cli/src/lib/bundler/bundle.ts index 232657a3f2..d24d4252f4 100644 --- a/packages/cli/src/lib/bundler/bundle.ts +++ b/packages/cli/src/lib/bundler/bundle.ts @@ -46,37 +46,45 @@ export async function buildBundle(options: BuildOptions) { dist: 'dist/public', }); - const detectedModulesEntryPoint = await createDetectedModulesEntryPoint({ - config: options.fullConfig, - targetPath: paths.targetPath, - }); - const commonConfigOptions = { ...options, checksEnabled: false, isDev: false, getFrontendAppConfigs: () => options.frontendAppConfigs, }; - const configs = [ - await createConfig(paths, { - ...commonConfigOptions, - additionalEntryPoints: detectedModulesEntryPoint, - appMode: publicPaths ? 'protected' : 'public', - }), - ]; - if (publicPaths) { - console.log( - chalk.yellow( - `⚠️ WARNING: The app /public entry point is an experimental feature that may receive immediate breaking changes.`, - ), - ); + const configs = []; + + if (options.moduleFederation?.mode === 'remote') { + // Package detection is disabled for remote bundles + configs.push(await createConfig(paths, commonConfigOptions)); + } else { + const detectedModulesEntryPoint = await createDetectedModulesEntryPoint({ + config: options.fullConfig, + targetPath: paths.targetPath, + }); + configs.push( - await createConfig(publicPaths, { + await createConfig(paths, { ...commonConfigOptions, - appMode: 'public', + additionalEntryPoints: detectedModulesEntryPoint, + appMode: publicPaths ? 'protected' : 'public', }), ); + + if (publicPaths) { + console.log( + chalk.yellow( + `⚠️ WARNING: The app /public entry point is an experimental feature that may receive immediate breaking changes.`, + ), + ); + configs.push( + await createConfig(publicPaths, { + ...commonConfigOptions, + appMode: 'public', + }), + ); + } } const isCi = yn(process.env.CI, { default: false }); diff --git a/packages/cli/src/lib/bundler/config.ts b/packages/cli/src/lib/bundler/config.ts index 53db7f3597..c2621b20a4 100644 --- a/packages/cli/src/lib/bundler/config.ts +++ b/packages/cli/src/lib/bundler/config.ts @@ -24,6 +24,7 @@ import { Config } from '@backstage/config'; import ESLintPlugin from 'eslint-webpack-plugin'; import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin'; import HtmlWebpackPlugin from 'html-webpack-plugin'; +import { ModuleFederationPlugin } from '@module-federation/enhanced'; import { LinkedPackageResolvePlugin } from './LinkedPackageResolvePlugin'; import ModuleScopePlugin from 'react-dev-utils/ModuleScopePlugin'; import { RunScriptWebpackPlugin } from 'run-script-webpack-plugin'; @@ -128,18 +129,81 @@ export async function createConfig( }), ); - plugins.push( - new HtmlWebpackPlugin({ - meta: { - 'backstage-app-mode': options?.appMode ?? 'public', - }, - template: paths.targetHtml, - templateParameters: { - publicPath, - config: frontendConfig, - }, - }), - ); + if (options.moduleFederation?.mode !== 'remote') { + plugins.push( + new HtmlWebpackPlugin({ + meta: { + 'backstage-app-mode': options?.appMode ?? 'public', + }, + template: paths.targetHtml, + templateParameters: { + publicPath, + config: frontendConfig, + }, + }), + ); + } + + if (options.moduleFederation) { + plugins.push( + new ModuleFederationPlugin({ + ...(options.moduleFederation?.mode === 'remote' && { + filename: 'remoteEntry.js', + exposes: { + '.': paths.targetEntry, + }, + }), + name: options.moduleFederation.name, + runtime: false, + shared: { + // React + react: { + singleton: true, + requiredVersion: '*', + eager: true, + }, + 'react-dom': { + singleton: true, + requiredVersion: '*', + eager: true, + }, + // React Router + 'react-router': { + singleton: true, + requiredVersion: '*', + eager: true, + }, + 'react-router-dom': { + singleton: true, + requiredVersion: '*', + eager: true, + }, + // MUI v4 + '@material-ui/core/styles': { + singleton: true, + requiredVersion: '*', + eager: true, + }, + '@material-ui/styles': { + singleton: true, + requiredVersion: '*', + eager: true, + }, + // MUI v5 + '@mui/material/styles/': { + singleton: true, + requiredVersion: '*', + eager: true, + }, + '@emotion/react': { + singleton: true, + requiredVersion: '*', + eager: true, + }, + }, + }), + ); + } const buildInfo = await readBuildInfo(); plugins.push( @@ -211,8 +275,10 @@ export async function createConfig( rules: loaders, }, output: { + uniqueName: options.moduleFederation?.name, path: paths.targetDist, - publicPath: `${publicPath}/`, + publicPath: + options.moduleFederation?.mode === 'remote' ? 'auto' : `${publicPath}/`, filename: isDev ? '[name].js' : 'static/[name].[fullhash:8].js', chunkFilename: isDev ? '[name].chunk.js' diff --git a/packages/cli/src/lib/bundler/optimization.ts b/packages/cli/src/lib/bundler/optimization.ts index 88a0343099..891e0793fe 100644 --- a/packages/cli/src/lib/bundler/optimization.ts +++ b/packages/cli/src/lib/bundler/optimization.ts @@ -30,6 +30,13 @@ export const optimization = ( new EsbuildPlugin({ target: 'es2019', format: 'iife', + exclude: 'remoteEntry.js', + }), + // Avoid iife wrapping of module federation remote entry as it breaks the variable assignment + new EsbuildPlugin({ + target: 'es2019', + format: undefined, + include: 'remoteEntry.js', }), ], runtimeChunk: 'single', diff --git a/packages/cli/src/lib/bundler/types.ts b/packages/cli/src/lib/bundler/types.ts index 85a641465f..7291ac0818 100644 --- a/packages/cli/src/lib/bundler/types.ts +++ b/packages/cli/src/lib/bundler/types.ts @@ -18,6 +18,13 @@ import { AppConfig, Config } from '@backstage/config'; import { BundlingPathsOptions } from './paths'; import { ConfigSchema } from '@backstage/config-loader'; +export type ModuleFederationOptions = { + // Unique name for this module federation bundle + name: string; + // Whether this is a host or remote bundle + mode: 'host' | 'remote'; +}; + export type BundlingOptions = { checksEnabled: boolean; isDev: boolean; @@ -29,6 +36,7 @@ export type BundlingOptions = { publicSubPath?: string; // Mode that the app is running in, 'protected' or 'public', default is 'public' appMode?: string; + moduleFederation?: ModuleFederationOptions; }; export type ServeOptions = BundlingPathsOptions & { @@ -46,6 +54,7 @@ export type BuildOptions = BundlingPathsOptions & { frontendConfig: Config; frontendAppConfigs: AppConfig[]; fullConfig: Config; + moduleFederation?: ModuleFederationOptions; }; export type BackendBundlingOptions = { diff --git a/yarn.lock b/yarn.lock index afe89e4263..14f731a803 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3917,6 +3917,7 @@ __metadata: "@backstage/theme": "workspace:^" "@backstage/types": "workspace:^" "@manypkg/get-packages": ^1.1.3 + "@module-federation/enhanced": ^0.1.19 "@octokit/graphql": ^5.0.0 "@octokit/graphql-schema": ^13.7.0 "@octokit/oauth-app": ^4.2.0 @@ -11038,6 +11039,145 @@ __metadata: languageName: node linkType: hard +"@module-federation/dts-plugin@npm:0.1.21": + version: 0.1.21 + resolution: "@module-federation/dts-plugin@npm:0.1.21" + dependencies: + "@module-federation/managers": 0.1.21 + "@module-federation/sdk": 0.1.21 + "@module-federation/third-party-dts-extractor": 0.1.21 + adm-zip: ^0.5.10 + ansi-colors: ^4.1.3 + axios: ^1.6.7 + chalk: 3.0.0 + fs-extra: 9.1.0 + isomorphic-ws: 5.0.0 + koa: 2.11.0 + lodash.clonedeepwith: 4.5.0 + log4js: 6.9.1 + node-schedule: 2.1.1 + rambda: ^9.1.0 + ws: 8.17.0 + peerDependencies: + typescript: ^4.9.0 || ^5.0.0 + vue-tsc: ^1.0.24 + peerDependenciesMeta: + vue-tsc: + optional: true + checksum: ec4cd030a25617698754cbac2da5463f8942cdd0a64bdc95f6ff5fd29fff6b88cf3db90e53e6b260cd3593893fe6ee2d6e149d0a46698eb7f9cc19a9df26193d + languageName: node + linkType: hard + +"@module-federation/enhanced@npm:^0.1.19": + version: 0.1.21 + resolution: "@module-federation/enhanced@npm:0.1.21" + dependencies: + "@module-federation/dts-plugin": 0.1.21 + "@module-federation/managers": 0.1.21 + "@module-federation/manifest": 0.1.21 + "@module-federation/rspack": 0.1.21 + "@module-federation/runtime-tools": 0.1.21 + "@module-federation/sdk": 0.1.21 + upath: 2.0.1 + peerDependencies: + typescript: ^4.9.0 || ^5.0.0 + vue-tsc: ^1.0.24 + webpack: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + vue-tsc: + optional: true + webpack: + optional: true + checksum: bc0ff541db1066b290b3ad9ab868437dc3d0754b9d06ab263f8fb7f54e08238eae9232a482a681dd6152e4a175578d65df9f27fe181fc8fb602d7cc1ae34807d + languageName: node + linkType: hard + +"@module-federation/managers@npm:0.1.21": + version: 0.1.21 + resolution: "@module-federation/managers@npm:0.1.21" + dependencies: + "@module-federation/sdk": 0.1.21 + find-pkg: 2.0.0 + fs-extra: 9.1.0 + checksum: 5f230d5795d86dfd68c404ee2b7a1264950c283a4b1c6f4ee9cc9579fabb413718dfbc1ff726b9c213f9d3223d944dd38dd9d04b700962e6398c3c3728d6323e + languageName: node + linkType: hard + +"@module-federation/manifest@npm:0.1.21": + version: 0.1.21 + resolution: "@module-federation/manifest@npm:0.1.21" + dependencies: + "@module-federation/dts-plugin": 0.1.21 + "@module-federation/managers": 0.1.21 + "@module-federation/sdk": 0.1.21 + chalk: 3.0.0 + find-pkg: 2.0.0 + checksum: cef2011875f14e853a355626ae1dbc8ae3b0714d31140e329b5dd71525782b08c2e1d6ca45276a563bb3c3b7f7c4e64a31f0698ef12606f05aa6da46e759f345 + languageName: node + linkType: hard + +"@module-federation/rspack@npm:0.1.21": + version: 0.1.21 + resolution: "@module-federation/rspack@npm:0.1.21" + dependencies: + "@module-federation/dts-plugin": 0.1.21 + "@module-federation/managers": 0.1.21 + "@module-federation/manifest": 0.1.21 + "@module-federation/runtime-tools": 0.1.21 + "@module-federation/sdk": 0.1.21 + checksum: 55516285e23f4ca7127afafb14af667defbe46dc3224f85d7e07edbc8937d7fac909dfebc2f9dd73120b99bbe5135372cf0fbbe282990d80e6953a60dfa4c93e + languageName: node + linkType: hard + +"@module-federation/runtime-tools@npm:0.1.21": + version: 0.1.21 + resolution: "@module-federation/runtime-tools@npm:0.1.21" + dependencies: + "@module-federation/runtime": 0.1.21 + "@module-federation/webpack-bundler-runtime": 0.1.21 + checksum: 628c0c4834093520f9c71481d587c9e18163f82e481b05b1900f04e2d5da4abb69af6d814ac5cd1951057b28d73f3adeb1cee7cd83628305b10cc7988405fbc5 + languageName: node + linkType: hard + +"@module-federation/runtime@npm:0.1.21": + version: 0.1.21 + resolution: "@module-federation/runtime@npm:0.1.21" + dependencies: + "@module-federation/sdk": 0.1.21 + checksum: ce4de8515b54f1cd07a3c7c4cbd35fea163294b9fb24be10827872f3ebb62cd5c289f3602efe4149d963282739f79b51947afa039ee6f36be7f66dea83d590fc + languageName: node + linkType: hard + +"@module-federation/sdk@npm:0.1.21": + version: 0.1.21 + resolution: "@module-federation/sdk@npm:0.1.21" + checksum: 6856dcfe2ef5ae939890b82010aaad911fa6c4330a05f290ae054c316c9b532d3691456a1f9e176fe05f1df2d6f2d8c7e0c842ca5648a0fd7abf270e44ed9ecb + languageName: node + linkType: hard + +"@module-federation/third-party-dts-extractor@npm:0.1.21": + version: 0.1.21 + resolution: "@module-federation/third-party-dts-extractor@npm:0.1.21" + dependencies: + find-pkg: 2.0.0 + fs-extra: 9.1.0 + resolve: 1.22.8 + checksum: e394fd7c2e6dbdf8df6937628680e7356ac897ee6f1309d7fbc38c00bcf4be9c0363f8bc1a75c29f7987a5a2f11f7855481813889b18e8b444ee9006aeb4a299 + languageName: node + linkType: hard + +"@module-federation/webpack-bundler-runtime@npm:0.1.21": + version: 0.1.21 + resolution: "@module-federation/webpack-bundler-runtime@npm:0.1.21" + dependencies: + "@module-federation/runtime": 0.1.21 + "@module-federation/sdk": 0.1.21 + checksum: 7d96002066e63bdb503964fd5fb2798be25f4135a599d87721f4d26ebe1de1affbf447c56b082f7ee850ae7798d0ac637f6a486f58591269065e114051b466e5 + languageName: node + linkType: hard + "@motionone/animation@npm:^10.12.0": version: 10.16.3 resolution: "@motionone/animation@npm:10.16.3" @@ -20325,7 +20465,7 @@ __metadata: languageName: node linkType: hard -"accepts@npm:^1.3.7, accepts@npm:~1.3.4, accepts@npm:~1.3.5, accepts@npm:~1.3.8": +"accepts@npm:^1.3.5, accepts@npm:^1.3.7, accepts@npm:~1.3.4, accepts@npm:~1.3.5, accepts@npm:~1.3.8": version: 1.3.8 resolution: "accepts@npm:1.3.8" dependencies: @@ -20402,6 +20542,13 @@ __metadata: languageName: node linkType: hard +"adm-zip@npm:^0.5.10": + version: 0.5.14 + resolution: "adm-zip@npm:0.5.14" + checksum: 83a4bc0bdff70f3276992810db96b10ffbf3c07667a9c3395e3dc60ca40ecbb920812dde212e1e21633b1508f1ea6fc427ac451aa68ee1a597b7251b2c1fc844 + languageName: node + linkType: hard + "agent-base@npm:6, agent-base@npm:^6.0.2": version: 6.0.2 resolution: "agent-base@npm:6.0.2" @@ -20695,7 +20842,7 @@ __metadata: languageName: node linkType: hard -"any-promise@npm:^1.0.0": +"any-promise@npm:^1.0.0, any-promise@npm:^1.1.0": version: 1.3.0 resolution: "any-promise@npm:1.3.0" checksum: 0ee8a9bdbe882c90464d75d1f55cf027f5458650c4bd1f0467e65aec38ccccda07ca5844969ee77ed46d04e7dded3eaceb027e8d32f385688523fe305fa7e1de @@ -21342,7 +21489,7 @@ __metadata: languageName: node linkType: hard -"axios@npm:1.6.8, axios@npm:^1.0.0, axios@npm:^1.4.0, axios@npm:^1.6.0": +"axios@npm:1.6.8": version: 1.6.8 resolution: "axios@npm:1.6.8" dependencies: @@ -21363,6 +21510,17 @@ __metadata: languageName: node linkType: hard +"axios@npm:^1.0.0, axios@npm:^1.4.0, axios@npm:^1.6.0, axios@npm:^1.6.7": + version: 1.7.2 + resolution: "axios@npm:1.7.2" + dependencies: + follow-redirects: ^1.15.6 + form-data: ^4.0.0 + proxy-from-env: ^1.1.0 + checksum: e457e2b0ab748504621f6fa6609074ac08c824bf0881592209dfa15098ece7e88495300e02cd22ba50b3468fd712fe687e629dcb03d6a3f6a51989727405aedf + languageName: node + linkType: hard + "axobject-query@npm:^3.2.1": version: 3.2.1 resolution: "axobject-query@npm:3.2.1" @@ -22292,6 +22450,16 @@ __metadata: languageName: node linkType: hard +"cache-content-type@npm:^1.0.0": + version: 1.0.1 + resolution: "cache-content-type@npm:1.0.1" + dependencies: + mime-types: ^2.1.18 + ylru: ^1.2.0 + checksum: 18db4d59452669ccbfd7146a1510a37eb28e9eccf18ca7a4eb603dff2edc5cccdca7498fc3042a2978f76f11151fba486eb9eb69d9afa3fb124957870aef4fd3 + languageName: node + linkType: hard + "cacheable-lookup@npm:^5.0.3": version: 5.0.3 resolution: "cacheable-lookup@npm:5.0.3" @@ -22457,6 +22625,16 @@ __metadata: languageName: node linkType: hard +"chalk@npm:3.0.0, chalk@npm:^3.0.0": + version: 3.0.0 + resolution: "chalk@npm:3.0.0" + dependencies: + ansi-styles: ^4.1.0 + supports-color: ^7.1.0 + checksum: 8e3ddf3981c4da405ddbd7d9c8d91944ddf6e33d6837756979f7840a29272a69a5189ecae0ff84006750d6d1e92368d413335eab4db5476db6e6703a1d1e0505 + languageName: node + linkType: hard + "chalk@npm:4.1.2, chalk@npm:^4.0.0, chalk@npm:^4.0.2, chalk@npm:^4.1.0, chalk@npm:^4.1.1, chalk@npm:^4.1.2": version: 4.1.2 resolution: "chalk@npm:4.1.2" @@ -22467,16 +22645,6 @@ __metadata: languageName: node linkType: hard -"chalk@npm:^3.0.0": - version: 3.0.0 - resolution: "chalk@npm:3.0.0" - dependencies: - ansi-styles: ^4.1.0 - supports-color: ^7.1.0 - checksum: 8e3ddf3981c4da405ddbd7d9c8d91944ddf6e33d6837756979f7840a29272a69a5189ecae0ff84006750d6d1e92368d413335eab4db5476db6e6703a1d1e0505 - languageName: node - linkType: hard - "chalk@npm:~5.3.0": version: 5.3.0 resolution: "chalk@npm:5.3.0" @@ -23478,7 +23646,7 @@ __metadata: languageName: node linkType: hard -"content-disposition@npm:0.5.4, content-disposition@npm:^0.5.3": +"content-disposition@npm:0.5.4, content-disposition@npm:^0.5.3, content-disposition@npm:~0.5.2": version: 0.5.4 resolution: "content-disposition@npm:0.5.4" dependencies: @@ -23487,7 +23655,7 @@ __metadata: languageName: node linkType: hard -"content-type@npm:^1.0.5, content-type@npm:~1.0.4, content-type@npm:~1.0.5": +"content-type@npm:^1.0.4, content-type@npm:^1.0.5, content-type@npm:~1.0.4, content-type@npm:~1.0.5": version: 1.0.5 resolution: "content-type@npm:1.0.5" checksum: 566271e0a251642254cde0f845f9dd4f9856e52d988f4eb0d0dcffbb7a1f8ec98de7a5215fc628f3bce30fe2fb6fd2bc064b562d721658c59b544e2d34ea2766 @@ -23574,6 +23742,16 @@ __metadata: languageName: node linkType: hard +"cookies@npm:~0.8.0": + version: 0.8.0 + resolution: "cookies@npm:0.8.0" + dependencies: + depd: ~2.0.0 + keygrip: ~1.1.0 + checksum: 806055a44f128705265b1bc6a853058da18bf80dea3654ad99be20985b1fa1b14f86c1eef73644aab8071241f8a78acd57202b54c4c5c70769fc694fbb9c4edc + languageName: node + linkType: hard + "copy-to-clipboard@npm:^3.2.0, copy-to-clipboard@npm:^3.3.1": version: 3.3.1 resolution: "copy-to-clipboard@npm:3.3.1" @@ -23791,6 +23969,15 @@ __metadata: languageName: node linkType: hard +"cron-parser@npm:^4.2.0": + version: 4.9.0 + resolution: "cron-parser@npm:4.9.0" + dependencies: + luxon: ^3.2.1 + checksum: 3cf248fc5cae6c19ec7124962b1cd84b76f02b9bc4f58976b3bd07624db3ef10aaf1548efcc2d2dcdab0dad4f12029d640a55ecce05ea5e1596af9db585502cf + languageName: node + linkType: hard + "cron@npm:^3.0.0": version: 3.1.7 resolution: "cron@npm:3.1.7" @@ -24400,6 +24587,13 @@ __metadata: languageName: node linkType: hard +"date-format@npm:^4.0.14": + version: 4.0.14 + resolution: "date-format@npm:4.0.14" + checksum: dfe5139df6af5759b9dd3c007b899b3f60d45a9240ffeee6314ab74e6ab52e9b519a44ccf285888bdd6b626c66ee9b4c8a523075fa1140617b5beb1cbb9b18d1 + languageName: node + linkType: hard + "dateformat@npm:^3.0.3": version: 3.0.3 resolution: "dateformat@npm:3.0.3" @@ -24460,6 +24654,15 @@ __metadata: languageName: node linkType: hard +"debug@npm:~3.1.0": + version: 3.1.0 + resolution: "debug@npm:3.1.0" + dependencies: + ms: 2.0.0 + checksum: 0b52718ab957254a5b3ca07fc34543bc778f358620c206a08452251eb7fc193c3ea3505072acbf4350219c14e2d71ceb7bdaa0d3370aa630b50da790458d08b3 + languageName: node + linkType: hard + "debuglog@npm:^1.0.1": version: 1.0.1 resolution: "debuglog@npm:1.0.1" @@ -24529,6 +24732,13 @@ __metadata: languageName: node linkType: hard +"deep-equal@npm:~1.0.1": + version: 1.0.1 + resolution: "deep-equal@npm:1.0.1" + checksum: 5af8cbfcebf190491878a498caccc7dc9592f8ebd1685b976eacc3825619d222b5e929923163b92c4f414494e2b884f7ebf00c022e8198e8292deb70dd9785f4 + languageName: node + linkType: hard + "deep-extend@npm:0.6.0, deep-extend@npm:^0.6.0": version: 0.6.0 resolution: "deep-extend@npm:0.6.0" @@ -24735,7 +24945,7 @@ __metadata: languageName: node linkType: hard -"destroy@npm:1.2.0": +"destroy@npm:1.2.0, destroy@npm:^1.0.4": version: 1.2.0 resolution: "destroy@npm:1.2.0" checksum: 0acb300b7478a08b92d810ab229d5afe0d2f4399272045ab22affa0d99dbaf12637659411530a6fcd597a9bdac718fc94373a61a95b4651bbc7b83684a565e38 @@ -25401,7 +25611,7 @@ __metadata: languageName: node linkType: hard -"encodeurl@npm:~1.0.2": +"encodeurl@npm:^1.0.2, encodeurl@npm:~1.0.2": version: 1.0.2 resolution: "encodeurl@npm:1.0.2" checksum: e50e3d508cdd9c4565ba72d2012e65038e5d71bdc9198cb125beb6237b5b1ade6c0d343998da9e170fb2eae52c1bed37d4d6d98a46ea423a0cddbed5ac3f780c @@ -25490,6 +25700,13 @@ __metadata: languageName: node linkType: hard +"error-inject@npm:^1.0.0": + version: 1.0.0 + resolution: "error-inject@npm:1.0.0" + checksum: 258cb26c7c7e04d9b730d074926ff5e18755b6945781540fdd124cafc5015610d97e4b971eb3226469f407fd34fa899a60fbcf9ade8923ab42fa2a3c61e246cf + languageName: node + linkType: hard + "error-stack-parser@npm:^2.0.6": version: 2.0.6 resolution: "error-stack-parser@npm:2.0.6" @@ -26861,6 +27078,15 @@ __metadata: languageName: node linkType: hard +"expand-tilde@npm:^2.0.0, expand-tilde@npm:^2.0.2": + version: 2.0.2 + resolution: "expand-tilde@npm:2.0.2" + dependencies: + homedir-polyfill: ^1.0.1 + checksum: 2efe6ed407d229981b1b6ceb552438fbc9e5c7d6a6751ad6ced3e0aa5cf12f0b299da695e90d6c2ac79191b5c53c613e508f7149e4573abfbb540698ddb7301a + languageName: node + linkType: hard + "expect@npm:>28.1.3, expect@npm:^29.0.0, expect@npm:^29.7.0": version: 29.7.0 resolution: "expect@npm:29.7.0" @@ -27400,6 +27626,15 @@ __metadata: languageName: node linkType: hard +"find-file-up@npm:^2.0.1": + version: 2.0.1 + resolution: "find-file-up@npm:2.0.1" + dependencies: + resolve-dir: ^1.0.1 + checksum: dfe820bfb80e75bed5dd5080057858c0ad2393e1438c48a3bb682663e9ecdcfbe3224ed4768bfedd00776800b4ae76bc8953d250d15ae3feabf381d2c6d04268 + languageName: node + linkType: hard + "find-my-way@npm:^4.3.3": version: 4.5.1 resolution: "find-my-way@npm:4.5.1" @@ -27412,6 +27647,15 @@ __metadata: languageName: node linkType: hard +"find-pkg@npm:2.0.0": + version: 2.0.0 + resolution: "find-pkg@npm:2.0.0" + dependencies: + find-file-up: ^2.0.1 + checksum: 44785204c8bbbdfeaece6b834ba81a35163421c30e20f531281d26e6b5890663d7ac884b82a9aebf6ce23e479336cd6f70ea5597da35495c16abdeba2fd4f845 + languageName: node + linkType: hard + "find-process@npm:^1.4.5": version: 1.4.7 resolution: "find-process@npm:1.4.7" @@ -27497,7 +27741,7 @@ __metadata: languageName: node linkType: hard -"flatted@npm:3.3.1, flatted@npm:^3.1.0": +"flatted@npm:3.3.1, flatted@npm:^3.1.0, flatted@npm:^3.2.7": version: 3.3.1 resolution: "flatted@npm:3.3.1" checksum: 85ae7181650bb728c221e7644cbc9f4bf28bc556f2fc89bb21266962bdf0ce1029cc7acc44bb646cd469d9baac7c317f64e841c4c4c00516afa97320cdac7f94 @@ -27727,7 +27971,7 @@ __metadata: languageName: node linkType: hard -"fresh@npm:0.5.2, fresh@npm:^0.5.2": +"fresh@npm:0.5.2, fresh@npm:^0.5.2, fresh@npm:~0.5.2": version: 0.5.2 resolution: "fresh@npm:0.5.2" checksum: 13ea8b08f91e669a64e3ba3a20eb79d7ca5379a81f1ff7f4310d54e2320645503cc0c78daedc93dfb6191287295f6479544a649c64d8e41a1c0fb0c221552346 @@ -27769,6 +28013,18 @@ __metadata: languageName: node linkType: hard +"fs-extra@npm:9.1.0, fs-extra@npm:^9.0.0": + version: 9.1.0 + resolution: "fs-extra@npm:9.1.0" + dependencies: + at-least-node: ^1.0.0 + graceful-fs: ^4.2.0 + jsonfile: ^6.0.1 + universalify: ^2.0.0 + checksum: ba71ba32e0faa74ab931b7a0031d1523c66a73e225de7426e275e238e312d07313d2da2d33e34a52aa406c8763ade5712eb3ec9ba4d9edce652bcacdc29e6b20 + languageName: node + linkType: hard + "fs-extra@npm:^11.0.0, fs-extra@npm:^11.1.0, fs-extra@npm:^11.2.0": version: 11.2.0 resolution: "fs-extra@npm:11.2.0" @@ -27802,18 +28058,6 @@ __metadata: languageName: node linkType: hard -"fs-extra@npm:^9.0.0": - version: 9.1.0 - resolution: "fs-extra@npm:9.1.0" - dependencies: - at-least-node: ^1.0.0 - graceful-fs: ^4.2.0 - jsonfile: ^6.0.1 - universalify: ^2.0.0 - checksum: ba71ba32e0faa74ab931b7a0031d1523c66a73e225de7426e275e238e312d07313d2da2d33e34a52aa406c8763ade5712eb3ec9ba4d9edce652bcacdc29e6b20 - languageName: node - linkType: hard - "fs-minipass@npm:^2.0.0, fs-minipass@npm:^2.1.0": version: 2.1.0 resolution: "fs-minipass@npm:2.1.0" @@ -28265,6 +28509,17 @@ __metadata: languageName: node linkType: hard +"global-modules@npm:^1.0.0": + version: 1.0.0 + resolution: "global-modules@npm:1.0.0" + dependencies: + global-prefix: ^1.0.1 + is-windows: ^1.0.1 + resolve-dir: ^1.0.0 + checksum: 10be68796c1e1abc1e2ba87ec4ea507f5629873b119ab0cd29c07284ef2b930f1402d10df01beccb7391dedd9cd479611dd6a24311c71be58937beaf18edf85e + languageName: node + linkType: hard + "global-modules@npm:^2.0.0": version: 2.0.0 resolution: "global-modules@npm:2.0.0" @@ -28274,6 +28529,19 @@ __metadata: languageName: node linkType: hard +"global-prefix@npm:^1.0.1": + version: 1.0.2 + resolution: "global-prefix@npm:1.0.2" + dependencies: + expand-tilde: ^2.0.2 + homedir-polyfill: ^1.0.1 + ini: ^1.3.4 + is-windows: ^1.0.1 + which: ^1.2.14 + checksum: 061b43470fe498271bcd514e7746e8a8535032b17ab9570517014ae27d700ff0dca749f76bbde13ba384d185be4310d8ba5712cb0e74f7d54d59390db63dd9a0 + languageName: node + linkType: hard + "global-prefix@npm:^3.0.0": version: 3.0.0 resolution: "global-prefix@npm:3.0.0" @@ -28895,6 +29163,15 @@ __metadata: languageName: node linkType: hard +"homedir-polyfill@npm:^1.0.1": + version: 1.0.3 + resolution: "homedir-polyfill@npm:1.0.3" + dependencies: + parse-passwd: ^1.0.0 + checksum: 18dd4db87052c6a2179d1813adea0c4bfcfa4f9996f0e226fefb29eb3d548e564350fa28ec46b0bf1fbc0a1d2d6922ceceb80093115ea45ff8842a4990139250 + languageName: node + linkType: hard + "hoopy@npm:^0.1.4": version: 0.1.4 resolution: "hoopy@npm:0.1.4" @@ -29019,6 +29296,16 @@ __metadata: languageName: node linkType: hard +"http-assert@npm:^1.3.0": + version: 1.5.0 + resolution: "http-assert@npm:1.5.0" + dependencies: + deep-equal: ~1.0.1 + http-errors: ~1.8.0 + checksum: 69c9b3c14cf8b2822916360a365089ce936c883c49068f91c365eccba5c141a9964d19fdda589150a480013bf503bf37d8936c732e9635819339e730ab0e7527 + languageName: node + linkType: hard + "http-cache-semantics@npm:^4.0.0, http-cache-semantics@npm:^4.1.0, http-cache-semantics@npm:^4.1.1": version: 4.1.1 resolution: "http-cache-semantics@npm:4.1.1" @@ -29057,6 +29344,19 @@ __metadata: languageName: node linkType: hard +"http-errors@npm:^1.6.3, http-errors@npm:~1.8.0": + version: 1.8.1 + resolution: "http-errors@npm:1.8.1" + dependencies: + depd: ~1.1.2 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: ">= 1.5.0 < 2" + toidentifier: 1.0.1 + checksum: d3c7e7e776fd51c0a812baff570bdf06fe49a5dc448b700ab6171b1250e4cf7db8b8f4c0b133e4bfe2451022a5790c1ca6c2cae4094dedd6ac8304a1267f91d2 + languageName: node + linkType: hard + "http-errors@npm:~1.6.2": version: 1.6.3 resolution: "http-errors@npm:1.6.3" @@ -29520,7 +29820,7 @@ __metadata: languageName: node linkType: hard -"ini@npm:^1.3.5, ini@npm:~1.3.0": +"ini@npm:^1.3.4, ini@npm:^1.3.5, ini@npm:~1.3.0": version: 1.3.8 resolution: "ini@npm:1.3.8" checksum: dfd98b0ca3a4fc1e323e38a6c8eb8936e31a97a918d3b377649ea15bdb15d481207a0dda1021efbd86b464cae29a0d33c1d7dcaf6c5672bee17fa849bc50a1b3 @@ -30417,7 +30717,7 @@ __metadata: languageName: node linkType: hard -"is-windows@npm:^1.0.0, is-windows@npm:^1.0.2": +"is-windows@npm:^1.0.0, is-windows@npm:^1.0.1, is-windows@npm:^1.0.2": version: 1.0.2 resolution: "is-windows@npm:1.0.2" checksum: 438b7e52656fe3b9b293b180defb4e448088e7023a523ec21a91a80b9ff8cdb3377ddb5b6e60f7c7de4fa8b63ab56e121b6705fe081b3cf1b828b0a380009ad7 @@ -31989,6 +32289,15 @@ __metadata: languageName: node linkType: hard +"keygrip@npm:~1.1.0": + version: 1.1.0 + resolution: "keygrip@npm:1.1.0" + dependencies: + tsscmp: 1.0.6 + checksum: 078cd16a463d187121f0a27c1c9c95c52ad392b620f823431689f345a0501132cee60f6e96914b07d570105af470b96960402accd6c48a0b1f3cd8fac4fa2cae + languageName: node + linkType: hard + "keyv@npm:*, keyv@npm:^4.0.0, keyv@npm:^4.5.2": version: 4.5.4 resolution: "keyv@npm:4.5.4" @@ -32099,6 +32408,64 @@ __metadata: languageName: node linkType: hard +"koa-compose@npm:^3.0.0": + version: 3.2.1 + resolution: "koa-compose@npm:3.2.1" + dependencies: + any-promise: ^1.1.0 + checksum: ff8e5fc0348455acf751179c6c613eb030a5fac6406d3b49ae9e00460b7ee8770db3ef62633fd3db0306cd4a6d2a0b5152399ebd5bb5e684418f9eeeb251c2de + languageName: node + linkType: hard + +"koa-compose@npm:^4.1.0": + version: 4.1.0 + resolution: "koa-compose@npm:4.1.0" + checksum: 46cb16792d96425e977c2ae4e5cb04930280740e907242ec9c25e3fb8b4a1d7b54451d7432bc24f40ec62255edea71894d2ceeb8238501842b4e48014f2e83db + languageName: node + linkType: hard + +"koa-convert@npm:^1.2.0": + version: 1.2.0 + resolution: "koa-convert@npm:1.2.0" + dependencies: + co: ^4.6.0 + koa-compose: ^3.0.0 + checksum: a33944dbda4ed87565985f5b37ba1122a012db872724b216b6fd8f9176d4bba42c4a9bf3c129330e45f6474d28f50ca0ed28d41b9bccd2ab5d36d6436cf0d676 + languageName: node + linkType: hard + +"koa@npm:2.11.0": + version: 2.11.0 + resolution: "koa@npm:2.11.0" + dependencies: + accepts: ^1.3.5 + cache-content-type: ^1.0.0 + content-disposition: ~0.5.2 + content-type: ^1.0.4 + cookies: ~0.8.0 + debug: ~3.1.0 + delegates: ^1.0.0 + depd: ^1.1.2 + destroy: ^1.0.4 + encodeurl: ^1.0.2 + error-inject: ^1.0.0 + escape-html: ^1.0.3 + fresh: ~0.5.2 + http-assert: ^1.3.0 + http-errors: ^1.6.3 + is-generator-function: ^1.0.7 + koa-compose: ^4.1.0 + koa-convert: ^1.2.0 + on-finished: ^2.3.0 + only: ~0.0.2 + parseurl: ^1.3.2 + statuses: ^1.5.0 + type-is: ^1.6.16 + vary: ^1.1.2 + checksum: b08e1aea03e70fe4ff6e35dee9f9e979e8608461ee1002f6e8dd72f45fc49404873888ea9a3aab2904e24bf43522df7c601033522f4151189e4055e87f94a979 + languageName: node + linkType: hard + "kubernetes-models@npm:^4.1.0, kubernetes-models@npm:^4.3.1": version: 4.3.1 resolution: "kubernetes-models@npm:4.3.1" @@ -32445,6 +32812,13 @@ __metadata: languageName: node linkType: hard +"lodash.clonedeepwith@npm:4.5.0": + version: 4.5.0 + resolution: "lodash.clonedeepwith@npm:4.5.0" + checksum: 9fbf4ebfa04b381df226a2298eba680327bea3d0d5d19c5118de7ae218fd219186e30e9fd0d33b13729f34ffbc83c1cf09cb27aff265ba94cb602b8a2b1e71c9 + languageName: node + linkType: hard + "lodash.curry@npm:^4.0.1, lodash.curry@npm:^4.1.1": version: 4.1.1 resolution: "lodash.curry@npm:4.1.1" @@ -32689,6 +33063,19 @@ __metadata: languageName: node linkType: hard +"log4js@npm:6.9.1": + version: 6.9.1 + resolution: "log4js@npm:6.9.1" + dependencies: + date-format: ^4.0.14 + debug: ^4.3.4 + flatted: ^3.2.7 + rfdc: ^1.3.0 + streamroller: ^3.1.5 + checksum: 59d98c37d4163138dab5d9b06ae26965d1353106fece143973d57b1003b3a482791aa21374fd2cca81a953b8837b2f9756ac225404e60cbfa4dd3ab59f082e2e + languageName: node + linkType: hard + "log@npm:^6.3.1": version: 6.3.1 resolution: "log@npm:6.3.1" @@ -32725,6 +33112,13 @@ __metadata: languageName: node linkType: hard +"long-timeout@npm:0.1.1": + version: 0.1.1 + resolution: "long-timeout@npm:0.1.1" + checksum: 48668e5362cb74c4b77a6b833d59f149b9bb9e99c5a5097609807e2597cd0920613b2a42b89bd0870848298be3691064d95599a04ae010023d07dba39932afa7 + languageName: node + linkType: hard + "long@npm:^5.0.0, long@npm:^5.2.1": version: 5.2.3 resolution: "long@npm:5.2.3" @@ -32862,7 +33256,7 @@ __metadata: languageName: node linkType: hard -"luxon@npm:^3.0.0, luxon@npm:^3.4.3, luxon@npm:~3.4.0": +"luxon@npm:^3.0.0, luxon@npm:^3.2.1, luxon@npm:^3.4.3, luxon@npm:~3.4.0": version: 3.4.4 resolution: "luxon@npm:3.4.4" checksum: 36c1f99c4796ee4bfddf7dc94fa87815add43ebc44c8934c924946260a58512f0fd2743a629302885df7f35ccbd2d13f178c15df046d0e3b6eb71db178f1c60c @@ -33808,7 +34202,7 @@ __metadata: languageName: node linkType: hard -"mime-types@npm:2.1.35, mime-types@npm:^2.1.12, mime-types@npm:^2.1.27, mime-types@npm:^2.1.31, mime-types@npm:~2.1.17, mime-types@npm:~2.1.19, mime-types@npm:~2.1.24, mime-types@npm:~2.1.34": +"mime-types@npm:2.1.35, mime-types@npm:^2.1.12, mime-types@npm:^2.1.18, mime-types@npm:^2.1.27, mime-types@npm:^2.1.31, mime-types@npm:~2.1.17, mime-types@npm:~2.1.19, mime-types@npm:~2.1.24, mime-types@npm:~2.1.34": version: 2.1.35 resolution: "mime-types@npm:2.1.35" dependencies: @@ -34856,6 +35250,17 @@ __metadata: languageName: node linkType: hard +"node-schedule@npm:2.1.1": + version: 2.1.1 + resolution: "node-schedule@npm:2.1.1" + dependencies: + cron-parser: ^4.2.0 + long-timeout: 0.1.1 + sorted-array-functions: ^1.3.0 + checksum: 6a8822b16fb024277c42efe710bdb35b6f1f6ab3a2f826283640511247d693f34ebd5ddf2863cd91609e7f323574e36c81cd2084dc204fa521f931380f0f963f + languageName: node + linkType: hard + "node-stdlib-browser@npm:^1.2.0": version: 1.2.0 resolution: "node-stdlib-browser@npm:1.2.0" @@ -35450,6 +35855,13 @@ __metadata: languageName: node linkType: hard +"only@npm:~0.0.2": + version: 0.0.2 + resolution: "only@npm:0.0.2" + checksum: d399710db867a1ef436dd3ce74499c87ece794aa81ab0370b5d153968766ee4aed2f98d3f92fc87c963e45b7a74d400d6f463ef651a5e7cfb861b15e88e9efe6 + languageName: node + linkType: hard + "ono@npm:^7.1.3": version: 7.1.3 resolution: "ono@npm:7.1.3" @@ -35971,6 +36383,13 @@ __metadata: languageName: node linkType: hard +"parse-passwd@npm:^1.0.0": + version: 1.0.0 + resolution: "parse-passwd@npm:1.0.0" + checksum: 4e55e0231d58f828a41d0f1da2bf2ff7bcef8f4cb6146e69d16ce499190de58b06199e6bd9b17fbf0d4d8aef9052099cdf8c4f13a6294b1a522e8e958073066e + languageName: node + linkType: hard + "parse-path@npm:^7.0.0": version: 7.0.0 resolution: "parse-path@npm:7.0.0" @@ -36005,7 +36424,7 @@ __metadata: languageName: node linkType: hard -"parseurl@npm:^1.3.3, parseurl@npm:~1.3.2, parseurl@npm:~1.3.3": +"parseurl@npm:^1.3.2, parseurl@npm:^1.3.3, parseurl@npm:~1.3.2, parseurl@npm:~1.3.3": version: 1.3.3 resolution: "parseurl@npm:1.3.3" checksum: 407cee8e0a3a4c5cd472559bca8b6a45b82c124e9a4703302326e9ab60fc1081442ada4e02628efef1eb16197ddc7f8822f5a91fd7d7c86b51f530aedb17dfa2 @@ -37802,6 +38221,13 @@ __metadata: languageName: node linkType: hard +"rambda@npm:^9.1.0": + version: 9.2.1 + resolution: "rambda@npm:9.2.1" + checksum: d877b61f2c1e8a1878ca1e40a181702b360f6c3978bf0e55e62315a1aa215863b7ecb8f00077e2bc0f1ca0d455387fafd7a84b5c8dd004eb3cf071b15827cff7 + languageName: node + linkType: hard + "ramda-adjunct@npm:^5.0.0": version: 5.0.1 resolution: "ramda-adjunct@npm:5.0.1" @@ -39199,6 +39625,16 @@ __metadata: languageName: node linkType: hard +"resolve-dir@npm:^1.0.0, resolve-dir@npm:^1.0.1": + version: 1.0.1 + resolution: "resolve-dir@npm:1.0.1" + dependencies: + expand-tilde: ^2.0.0 + global-modules: ^1.0.0 + checksum: ef736b8ed60d6645c3b573da17d329bfb50ec4e1d6c5ffd6df49e3497acef9226f9810ea6823b8ece1560e01dcb13f77a9f6180d4f242d00cc9a8f4de909c65c + languageName: node + linkType: hard + "resolve-from@npm:5.0.0, resolve-from@npm:^5.0.0": version: 5.0.0 resolution: "resolve-from@npm:5.0.0" @@ -39227,7 +39663,7 @@ __metadata: languageName: node linkType: hard -"resolve@npm:^1.1.6, 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.8, resolve@npm:~1.22.1": +"resolve@npm:1.22.8, resolve@npm:^1.1.6, 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.8, resolve@npm:~1.22.1": version: 1.22.8 resolution: "resolve@npm:1.22.8" dependencies: @@ -39263,7 +39699,7 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@^1.1.6#~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.8#~builtin, resolve@patch:resolve@~1.22.1#~builtin": +"resolve@patch:resolve@1.22.8#~builtin, resolve@patch:resolve@^1.1.6#~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.8#~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=c3c19d" dependencies: @@ -39398,10 +39834,10 @@ __metadata: languageName: node linkType: hard -"rfdc@npm:^1.3.1": - version: 1.3.1 - resolution: "rfdc@npm:1.3.1" - checksum: d5d1e930aeac7e0e0a485f97db1356e388bdbeff34906d206fe524dd5ada76e95f186944d2e68307183fdc39a54928d4426bbb6734851692cfe9195efba58b79 +"rfdc@npm:^1.3.0, rfdc@npm:^1.3.1": + version: 1.4.1 + resolution: "rfdc@npm:1.4.1" + checksum: 3b05bd55062c1d78aaabfcea43840cdf7e12099968f368e9a4c3936beb744adb41cbdb315eac6d4d8c6623005d6f87fdf16d8a10e1ff3722e84afea7281c8d13 languageName: node linkType: hard @@ -40618,6 +41054,13 @@ __metadata: languageName: node linkType: hard +"sorted-array-functions@npm:^1.3.0": + version: 1.3.0 + resolution: "sorted-array-functions@npm:1.3.0" + checksum: 673fd39ca3b6c92644d4483eac1700bb7d7555713a536822a7522a35af559bef3e72f10d89356b75042dc394cd7c2e2ab6f40024385218ec3c85bb7335032857 + languageName: node + linkType: hard + "source-list-map@npm:^2.0.0": version: 2.0.1 resolution: "source-list-map@npm:2.0.1" @@ -40974,7 +41417,7 @@ __metadata: languageName: node linkType: hard -"statuses@npm:>= 1.4.0 < 2, statuses@npm:~1.5.0": +"statuses@npm:>= 1.4.0 < 2, statuses@npm:>= 1.5.0 < 2, statuses@npm:^1.5.0, statuses@npm:~1.5.0": version: 1.5.0 resolution: "statuses@npm:1.5.0" checksum: c469b9519de16a4bb19600205cffb39ee471a5f17b82589757ca7bd40a8d92ebb6ed9f98b5a540c5d302ccbc78f15dc03cc0280dd6e00df1335568a5d5758a5c @@ -41072,6 +41515,17 @@ __metadata: languageName: node linkType: hard +"streamroller@npm:^3.1.5": + version: 3.1.5 + resolution: "streamroller@npm:3.1.5" + dependencies: + date-format: ^4.0.14 + debug: ^4.3.4 + fs-extra: ^8.1.0 + checksum: c1df5612b785ffa4b6bbf16460590b62994c57265bc55a5166eebeeb0daf648e84bc52dc6d57e0cd4e5c7609bda93076753c63ff54589febd1e0b95590f0e443 + languageName: node + linkType: hard + "streamsearch@npm:^1.1.0": version: 1.1.0 resolution: "streamsearch@npm:1.1.0" @@ -42542,6 +42996,13 @@ __metadata: languageName: node linkType: hard +"tsscmp@npm:1.0.6": + version: 1.0.6 + resolution: "tsscmp@npm:1.0.6" + checksum: 1512384def36bccc9125cabbd4c3b0e68608d7ee08127ceaa0b84a71797263f1a01c7f82fa69be8a3bd3c1396e2965d2f7b52d581d3a5eeaf3967fbc52e3b3bf + languageName: node + linkType: hard + "tsutils@npm:^3.21.0": version: 3.21.0 resolution: "tsutils@npm:3.21.0" @@ -42678,7 +43139,7 @@ __metadata: languageName: node linkType: hard -"type-is@npm:^1.6.18, type-is@npm:^1.6.4, type-is@npm:~1.6.18": +"type-is@npm:^1.6.16, type-is@npm:^1.6.18, type-is@npm:^1.6.4, type-is@npm:~1.6.18": version: 1.6.18 resolution: "type-is@npm:1.6.18" dependencies: @@ -43228,7 +43689,7 @@ __metadata: languageName: node linkType: hard -"upath@npm:^2.0.1": +"upath@npm:2.0.1, upath@npm:^2.0.1": version: 2.0.1 resolution: "upath@npm:2.0.1" checksum: 2db04f24a03ef72204c7b969d6991abec9e2cb06fb4c13a1fd1c59bc33b46526b16c3325e55930a11ff86a77a8cbbcda8f6399bf914087028c5beae21ecdb33c @@ -43647,7 +44108,7 @@ __metadata: languageName: node linkType: hard -"vary@npm:^1, vary@npm:~1.1.2": +"vary@npm:^1, vary@npm:^1.1.2, vary@npm:~1.1.2": version: 1.1.2 resolution: "vary@npm:1.1.2" checksum: ae0123222c6df65b437669d63dfa8c36cee20a504101b2fcd97b8bf76f91259c17f9f2b4d70a1e3c6bbcee7f51b28392833adb6b2770b23b01abec84e369660b @@ -44234,7 +44695,7 @@ __metadata: languageName: node linkType: hard -"which@npm:^1.2.9, which@npm:^1.3.1": +"which@npm:^1.2.14, which@npm:^1.2.9, which@npm:^1.3.1": version: 1.3.1 resolution: "which@npm:1.3.1" dependencies: @@ -44443,6 +44904,21 @@ __metadata: languageName: node linkType: hard +"ws@npm:8.17.0": + version: 8.17.0 + resolution: "ws@npm:8.17.0" + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ">=5.0.2" + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + checksum: 147ef9eab0251364e1d2c55338ad0efb15e6913923ccbfdf20f7a8a6cb8f88432bcd7f4d8f66977135bfad35575644f9983201c1a361019594a4e53977bf6d4e + languageName: node + linkType: hard + "ws@npm:^7, ws@npm:^7.4.6, ws@npm:^7.5.5": version: 7.5.10 resolution: "ws@npm:7.5.10" @@ -44784,6 +45260,13 @@ __metadata: languageName: node linkType: hard +"ylru@npm:^1.2.0": + version: 1.4.0 + resolution: "ylru@npm:1.4.0" + checksum: e0bf797476487e3d57a6e8790cbb749cff2089e2afc87e46bc84ce7605c329d578ff422c8e8c2ddf167681ddd218af0f58e099733ae1044cba9e9472ebedc01d + languageName: node + linkType: hard + "yml-loader@npm:^2.1.0": version: 2.1.0 resolution: "yml-loader@npm:2.1.0" From b56723adf0afed281fb6d85c0efaf8fb731a466a Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 15 Jul 2024 14:00:23 +0200 Subject: [PATCH 267/416] cli: only eagely load shared dependencies in the host Signed-off-by: Patrik Oldsberg --- packages/cli/src/lib/bundler/config.ts | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/packages/cli/src/lib/bundler/config.ts b/packages/cli/src/lib/bundler/config.ts index c2621b20a4..ee201ef2db 100644 --- a/packages/cli/src/lib/bundler/config.ts +++ b/packages/cli/src/lib/bundler/config.ts @@ -145,9 +145,11 @@ export async function createConfig( } if (options.moduleFederation) { + const isRemote = options.moduleFederation?.mode === 'remote'; + plugins.push( new ModuleFederationPlugin({ - ...(options.moduleFederation?.mode === 'remote' && { + ...(isRemote && { filename: 'remoteEntry.js', exposes: { '.': paths.targetEntry, @@ -160,45 +162,45 @@ export async function createConfig( react: { singleton: true, requiredVersion: '*', - eager: true, + eager: !isRemote, }, 'react-dom': { singleton: true, requiredVersion: '*', - eager: true, + eager: !isRemote, }, // React Router 'react-router': { singleton: true, requiredVersion: '*', - eager: true, + eager: !isRemote, }, 'react-router-dom': { singleton: true, requiredVersion: '*', - eager: true, + eager: !isRemote, }, // MUI v4 '@material-ui/core/styles': { singleton: true, requiredVersion: '*', - eager: true, + eager: !isRemote, }, '@material-ui/styles': { singleton: true, requiredVersion: '*', - eager: true, + eager: !isRemote, }, // MUI v5 '@mui/material/styles/': { singleton: true, requiredVersion: '*', - eager: true, + eager: !isRemote, }, '@emotion/react': { singleton: true, requiredVersion: '*', - eager: true, + eager: !isRemote, }, }, }), From 5e7f0491fa9c41a3c69c33c795e8d6f0ad16597c Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 15 Jul 2024 14:08:31 +0200 Subject: [PATCH 268/416] cli: update ModuleFederationPlugin import to avoid type error Signed-off-by: Patrik Oldsberg --- packages/cli/src/lib/bundler/config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli/src/lib/bundler/config.ts b/packages/cli/src/lib/bundler/config.ts index ee201ef2db..60c8a7be66 100644 --- a/packages/cli/src/lib/bundler/config.ts +++ b/packages/cli/src/lib/bundler/config.ts @@ -24,7 +24,7 @@ import { Config } from '@backstage/config'; import ESLintPlugin from 'eslint-webpack-plugin'; import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin'; import HtmlWebpackPlugin from 'html-webpack-plugin'; -import { ModuleFederationPlugin } from '@module-federation/enhanced'; +import { ModuleFederationPlugin } from '@module-federation/enhanced/webpack'; import { LinkedPackageResolvePlugin } from './LinkedPackageResolvePlugin'; import ModuleScopePlugin from 'react-dev-utils/ModuleScopePlugin'; import { RunScriptWebpackPlugin } from 'run-script-webpack-plugin'; From 8e2aba9bd01343d72915a69148ccaa3d40658cbd Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 15 Jul 2024 17:25:11 +0200 Subject: [PATCH 269/416] cli: add a warning when app is build with module federation enabled Signed-off-by: Patrik Oldsberg --- packages/cli/src/commands/build/command.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/cli/src/commands/build/command.ts b/packages/cli/src/commands/build/command.ts index 285cba0e81..f868ca462c 100644 --- a/packages/cli/src/commands/build/command.ts +++ b/packages/cli/src/commands/build/command.ts @@ -36,13 +36,19 @@ export async function command(opts: OptionValues): Promise { }); if (role === 'frontend') { + const enableModuleFederation = process.env.EXPERIMENTAL_MODULE_FEDERATION; + if (enableModuleFederation) { + console.log( + chalk.yellow( + `⚠️ WARNING: Module federation is experimental and will receive immediate breaking changes in the future.`, + ), + ); + } return buildFrontend({ targetDir: paths.targetDir, configPaths, writeStats: Boolean(opts.stats), - moduleFederationMode: process.env.EXPERIMENTAL_MODULE_FEDERATION - ? 'host' - : undefined, + moduleFederationMode: enableModuleFederation ? 'host' : undefined, }); } return buildBackend({ From 59375fc411deb3e418893720875c6c697ae9a8c5 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 15 Jul 2024 17:36:58 +0200 Subject: [PATCH 270/416] cli: refactor module federation check to support all paths to calling buildFrontend Signed-off-by: Patrik Oldsberg --- .../cli/src/commands/build/buildFrontend.ts | 39 +++++++++++++++---- packages/cli/src/commands/build/command.ts | 11 +----- 2 files changed, 32 insertions(+), 18 deletions(-) diff --git a/packages/cli/src/commands/build/buildFrontend.ts b/packages/cli/src/commands/build/buildFrontend.ts index 931a3b376a..62da74e6d3 100644 --- a/packages/cli/src/commands/build/buildFrontend.ts +++ b/packages/cli/src/commands/build/buildFrontend.ts @@ -19,29 +19,52 @@ import { resolve as resolvePath } from 'path'; import { buildBundle } from '../../lib/bundler'; import { getEnvironmentParallelism } from '../../lib/parallel'; import { loadCliConfig } from '../../lib/config'; +import chalk from 'chalk'; +import { BuildOptions } from '../../lib/bundler/types'; interface BuildAppOptions { targetDir: string; writeStats: boolean; configPaths: string[]; - moduleFederationMode?: 'host' | 'remote'; + isModuleFederationRemote?: true; +} + +function getModuleFederationOptions( + name: string, + isRemote?: boolean, +): BuildOptions['moduleFederation'] { + if (!isRemote && !process.env.EXPERIMENTAL_MODULE_FEDERATION) { + return undefined; + } + + console.log( + chalk.yellow( + `⚠️ WARNING: Module federation is experimental and will receive immediate breaking changes in the future.`, + ), + ); + + return { + mode: isRemote ? 'remote' : 'host', + // The default output mode requires the name to be a usable as a code + // symbol, there might be better options here but for now we need to + // sanitize the name. + name: name.replaceAll('@', '').replaceAll('/', '__').replaceAll('-', '_'), + }; } export async function buildFrontend(options: BuildAppOptions) { const { targetDir, writeStats, configPaths } = options; const { name } = await fs.readJson(resolvePath(targetDir, 'package.json')); + await buildBundle({ targetDir, entry: 'src/index', parallelism: getEnvironmentParallelism(), statsJsonEnabled: writeStats, - moduleFederation: options.moduleFederationMode && { - // The default output mode requires the name to be a usable as a code - // symbol, there might be better options here but for now we need to - // sanitize the name. - name: name.replaceAll('@', '').replaceAll(/[/\\_-]/g, '_'), - mode: options.moduleFederationMode, - }, + moduleFederation: getModuleFederationOptions( + name, + options.isModuleFederationRemote, + ), ...(await loadCliConfig({ args: configPaths, fromPackage: name, diff --git a/packages/cli/src/commands/build/command.ts b/packages/cli/src/commands/build/command.ts index f868ca462c..c0ad3c912b 100644 --- a/packages/cli/src/commands/build/command.ts +++ b/packages/cli/src/commands/build/command.ts @@ -36,19 +36,10 @@ export async function command(opts: OptionValues): Promise { }); if (role === 'frontend') { - const enableModuleFederation = process.env.EXPERIMENTAL_MODULE_FEDERATION; - if (enableModuleFederation) { - console.log( - chalk.yellow( - `⚠️ WARNING: Module federation is experimental and will receive immediate breaking changes in the future.`, - ), - ); - } return buildFrontend({ targetDir: paths.targetDir, configPaths, writeStats: Boolean(opts.stats), - moduleFederationMode: enableModuleFederation ? 'host' : undefined, }); } return buildBackend({ @@ -70,7 +61,7 @@ export async function command(opts: OptionValues): Promise { targetDir: paths.targetDir, configPaths: [], writeStats: Boolean(opts.stats), - moduleFederationMode: 'remote', + isModuleFederationRemote: true, }); } From 24a98c940b384efa245d044e07fae5ac37bc2ee7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 Jul 2024 08:08:47 +0000 Subject: [PATCH 271/416] Bump ws from 8.8.1 to 8.18.0 in /storybook Bumps [ws](https://github.com/websockets/ws) from 8.8.1 to 8.18.0. - [Release notes](https://github.com/websockets/ws/releases) - [Commits](https://github.com/websockets/ws/compare/8.8.1...8.18.0) --- updated-dependencies: - dependency-name: ws dependency-type: indirect ... Signed-off-by: dependabot[bot] --- storybook/yarn.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/storybook/yarn.lock b/storybook/yarn.lock index 1702d6f4cc..28bbe4b144 100644 --- a/storybook/yarn.lock +++ b/storybook/yarn.lock @@ -11912,17 +11912,17 @@ __metadata: linkType: hard "ws@npm:^8.2.3": - version: 8.8.1 - resolution: "ws@npm:8.8.1" + version: 8.18.0 + resolution: "ws@npm:8.18.0" peerDependencies: bufferutil: ^4.0.1 - utf-8-validate: ^5.0.2 + utf-8-validate: ">=5.0.2" peerDependenciesMeta: bufferutil: optional: true utf-8-validate: optional: true - checksum: 2152cf862cae0693f3775bc688a6afb2e989d19d626d215e70f5fcd8eb55b1c3b0d3a6a4052905ec320e2d7734e20aeedbf9744496d62f15a26ad79cf4cf7dae + checksum: 91d4d35bc99ff6df483bdf029b9ea4bfd7af1f16fc91231a96777a63d263e1eabf486e13a2353970efc534f9faa43bdbf9ee76525af22f4752cbc5ebda333975 languageName: node linkType: hard From 419f3878bd519d40db3bbad21cb8760c0da64e97 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 11 Jul 2024 14:29:18 +0200 Subject: [PATCH 272/416] backend-defaults: refactor rootHttpRouterServiceFactory to define options on its own Signed-off-by: Patrik Oldsberg --- .changeset/lucky-wolves-pull.md | 5 +++++ packages/backend-app-api/api-report.md | 9 ++++----- .../backend-defaults/api-report-rootHttpRouter.md | 11 +++++------ .../rootHttpRouter/rootHttpRouterServiceFactory.ts | 14 ++++++++++---- packages/backend-test-utils/api-report.md | 9 ++++----- 5 files changed, 28 insertions(+), 20 deletions(-) create mode 100644 .changeset/lucky-wolves-pull.md diff --git a/.changeset/lucky-wolves-pull.md b/.changeset/lucky-wolves-pull.md new file mode 100644 index 0000000000..17ed4572b6 --- /dev/null +++ b/.changeset/lucky-wolves-pull.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-defaults': patch +--- + +Refactor of `rootHttpRouterServiceFactory` to allow it to be constructed with options, but without declaring options via `createServiceFactory`. diff --git a/packages/backend-app-api/api-report.md b/packages/backend-app-api/api-report.md index 54e2900cc2..7f9b54dd8f 100644 --- a/packages/backend-app-api/api-report.md +++ b/packages/backend-app-api/api-report.md @@ -292,11 +292,10 @@ export type RootHttpRouterConfigureContext = RootHttpRouterConfigureContext_2; export type RootHttpRouterFactoryOptions = RootHttpRouterFactoryOptions_2; // @public @deprecated (undocumented) -export const rootHttpRouterServiceFactory: ServiceFactoryCompat< - RootHttpRouterService, - 'root', - RootHttpRouterFactoryOptions_2 ->; +export const rootHttpRouterServiceFactory: (( + options?: RootHttpRouterFactoryOptions_2 | undefined, +) => ServiceFactory) & + ServiceFactory; // @public @deprecated export const rootLifecycleServiceFactory: ServiceFactoryCompat< diff --git a/packages/backend-defaults/api-report-rootHttpRouter.md b/packages/backend-defaults/api-report-rootHttpRouter.md index 9ea4cd7ebb..329398a7b8 100644 --- a/packages/backend-defaults/api-report-rootHttpRouter.md +++ b/packages/backend-defaults/api-report-rootHttpRouter.md @@ -19,7 +19,7 @@ import { RequestListener } from 'http'; import { RootConfigService } from '@backstage/backend-plugin-api'; import { RootHttpRouterService } from '@backstage/backend-plugin-api'; import type { Server } from 'node:http'; -import { ServiceFactoryCompat } from '@backstage/backend-plugin-api'; +import { ServiceFactory } from '@backstage/backend-plugin-api'; // @public export function createHttpServer( @@ -141,11 +141,10 @@ export type RootHttpRouterFactoryOptions = { }; // @public (undocumented) -export const rootHttpRouterServiceFactory: ServiceFactoryCompat< - RootHttpRouterService, - 'root', - RootHttpRouterFactoryOptions ->; +export const rootHttpRouterServiceFactory: (( + options?: RootHttpRouterFactoryOptions, +) => ServiceFactory) & + ServiceFactory; // (No @packageDocumentation comment for this package) ``` diff --git a/packages/backend-defaults/src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.ts b/packages/backend-defaults/src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.ts index 22f5c2f310..c3a97737e4 100644 --- a/packages/backend-defaults/src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.ts +++ b/packages/backend-defaults/src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.ts @@ -69,9 +69,10 @@ function defaultConfigure({ applyDefaults }: RootHttpRouterConfigureContext) { applyDefaults(); } -/** @public */ -export const rootHttpRouterServiceFactory = createServiceFactory( - (options?: RootHttpRouterFactoryOptions) => ({ +const rootHttpRouterServiceFactoryWithOptions = ( + options?: RootHttpRouterFactoryOptions, +) => + createServiceFactory({ service: coreServices.rootHttpRouter, deps: { config: coreServices.rootConfig, @@ -122,5 +123,10 @@ export const rootHttpRouterServiceFactory = createServiceFactory( return router; }, - }), + })(); + +/** @public */ +export const rootHttpRouterServiceFactory = Object.assign( + rootHttpRouterServiceFactoryWithOptions, + rootHttpRouterServiceFactoryWithOptions(), ); diff --git a/packages/backend-test-utils/api-report.md b/packages/backend-test-utils/api-report.md index af7edba061..3439d37231 100644 --- a/packages/backend-test-utils/api-report.md +++ b/packages/backend-test-utils/api-report.md @@ -290,11 +290,10 @@ export namespace mockServices { // (undocumented) export namespace rootHttpRouter { const // (undocumented) - factory: ServiceFactoryCompat< - RootHttpRouterService, - 'root', - RootHttpRouterFactoryOptions - >; + factory: (( + options?: RootHttpRouterFactoryOptions | undefined, + ) => ServiceFactory) & + ServiceFactory; const // (undocumented) mock: ( partialImpl?: Partial | undefined, From e28af58b4ba24495d7d1db03feb53e5737fe33e7 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 11 Jul 2024 11:12:21 +0200 Subject: [PATCH 273/416] backend-defaults: deprecate config service options Signed-off-by: Patrik Oldsberg --- .changeset/wet-rivers-travel.md | 5 ++++ .../core-services/root-config.md | 30 ++++++++++++------- .../backend-defaults/api-report-rootConfig.md | 2 +- .../rootConfig/rootConfigServiceFactory.ts | 1 + 4 files changed, 27 insertions(+), 11 deletions(-) create mode 100644 .changeset/wet-rivers-travel.md diff --git a/.changeset/wet-rivers-travel.md b/.changeset/wet-rivers-travel.md new file mode 100644 index 0000000000..44dedf3ccb --- /dev/null +++ b/.changeset/wet-rivers-travel.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-defaults': patch +--- + +The `RootConfigFactoryOptions` have been deprecated alongside the deprecation of service factory options. For more information on how to customize the config service, see the [Root Config Service docs](https://backstage.io/docs/backend-system/core-services/root-config#configuring-the-service). diff --git a/docs/backend-system/core-services/root-config.md b/docs/backend-system/core-services/root-config.md index 7cdc10f38c..9561a8f0cd 100644 --- a/docs/backend-system/core-services/root-config.md +++ b/docs/backend-system/core-services/root-config.md @@ -36,12 +36,12 @@ createBackendPlugin({ ## Configuring the service -There's additional configuration that you can optionally pass to setup the `config` core service. +There are several APIs from the `@backstage/config-loader` package that allow you to customize the implementation of the config service. The default implementation uses the `ConfigSources.default` method, which has several options, for example: - `argv` - Override the arguments that are passed to the config loader, instead of using `process.argv` - `remote` - Configure remote configuration loading -You can configure these additional options by adding an override for the core service when calling `createBackend` like follows: +You can use these to create your own config service implementation: ```ts import { rootConfigServiceFactory } from '@backstage/backend-app-api'; @@ -49,14 +49,24 @@ import { rootConfigServiceFactory } from '@backstage/backend-app-api'; const backend = createBackend(); backend.add( - rootConfigServiceFactory({ - argv: [ - '--config', - '/backstage/app-config.development.yaml', - '--config', - '/backstage/app-config.yaml', - ], - remote: { reloadIntervalSeconds: 60 }, + createServiceFactory({ + service: coreServices.rootConfig, + deps: {}, + async factory() { + const source = ConfigSources.default({ + argv: [ + '--config', + '/backstage/app-config.development.yaml', + '--config', + '/backstage/app-config.yaml', + ], + remote: { reloadIntervalSeconds: 60 }, + }); + console.log(`Loading config from ${source}`); + return await ConfigSources.toConfig(source); + }, }), ); ``` + +You can also use other config source such as `StaticConfigSource` and combine them with other sources using `ConfigSources.merge(...)`. You can also create your own config source by implementing the `ConfigSource` interface. diff --git a/packages/backend-defaults/api-report-rootConfig.md b/packages/backend-defaults/api-report-rootConfig.md index 24e827f520..8ad2e01a90 100644 --- a/packages/backend-defaults/api-report-rootConfig.md +++ b/packages/backend-defaults/api-report-rootConfig.md @@ -17,7 +17,7 @@ export function createConfigSecretEnumerator(options: { schema?: ConfigSchema; }): Promise<(config: Config) => Iterable>; -// @public +// @public @deprecated export interface RootConfigFactoryOptions { argv?: string[]; remote?: Pick; diff --git a/packages/backend-defaults/src/entrypoints/rootConfig/rootConfigServiceFactory.ts b/packages/backend-defaults/src/entrypoints/rootConfig/rootConfigServiceFactory.ts index 5752a9c634..7bcb9ef56b 100644 --- a/packages/backend-defaults/src/entrypoints/rootConfig/rootConfigServiceFactory.ts +++ b/packages/backend-defaults/src/entrypoints/rootConfig/rootConfigServiceFactory.ts @@ -31,6 +31,7 @@ import { * for more information. * * @public + * @deprecated These service options will be removed, please use the `ConfigSources` API from `@backstage/config-loader` to implement your own version of the service factory instead. */ export interface RootConfigFactoryOptions { /** From e375bb93df617dc101df8bb8a7a2da7b743c752b Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 16 Jul 2024 10:20:11 +0200 Subject: [PATCH 274/416] backend-defaults: update root config implementation to use manual factory pattern + update docs Signed-off-by: Patrik Oldsberg --- .changeset/wet-rivers-travel.md | 2 +- .../core-services/root-config.md | 25 +++++++++++++++++-- .../backend-defaults/api-report-rootConfig.md | 13 +++++----- .../rootConfig/rootConfigServiceFactory.ts | 19 ++++++++------ 4 files changed, 42 insertions(+), 17 deletions(-) diff --git a/.changeset/wet-rivers-travel.md b/.changeset/wet-rivers-travel.md index 44dedf3ccb..1778a3db23 100644 --- a/.changeset/wet-rivers-travel.md +++ b/.changeset/wet-rivers-travel.md @@ -2,4 +2,4 @@ '@backstage/backend-defaults': patch --- -The `RootConfigFactoryOptions` have been deprecated alongside the deprecation of service factory options. For more information on how to customize the config service, see the [Root Config Service docs](https://backstage.io/docs/backend-system/core-services/root-config#configuring-the-service). +Refactor of `rootConfigServiceFactory` to allow it to be constructed with options, but without declaring options via `createServiceFactory`. diff --git a/docs/backend-system/core-services/root-config.md b/docs/backend-system/core-services/root-config.md index 9561a8f0cd..8505b9e7ec 100644 --- a/docs/backend-system/core-services/root-config.md +++ b/docs/backend-system/core-services/root-config.md @@ -36,18 +36,39 @@ createBackendPlugin({ ## Configuring the service -There are several APIs from the `@backstage/config-loader` package that allow you to customize the implementation of the config service. The default implementation uses the `ConfigSources.default` method, which has several options, for example: +There's additional configuration that you can optionally pass to setup the `config` core service. - `argv` - Override the arguments that are passed to the config loader, instead of using `process.argv` - `remote` - Configure remote configuration loading -You can use these to create your own config service implementation: +You can configure these additional options by adding an override for the core service when calling `createBackend` like follows: ```ts import { rootConfigServiceFactory } from '@backstage/backend-app-api'; const backend = createBackend(); +backend.add( + rootConfigServiceFactory({ + argv: [ + '--config', + '/backstage/app-config.development.yaml', + '--config', + '/backstage/app-config.yaml', + ], + remote: { reloadIntervalSeconds: 60 }, + }), +); +``` + +For more advanced customization, there are several APIs from the `@backstage/config-loader` package that allow you to customize the implementation of the config service. The default implementation uses the `ConfigSources.default` method, which has the same options as the `rootConfigServiceFactory` function. You can use these to create your own config service implementation: + +```ts +import { ConfigSources } from '@backstage/config-loader'; +import { createServiceFactory } from '@backstage/backend-plugin-api'; + +const backend = createBackend(); + backend.add( createServiceFactory({ service: coreServices.rootConfig, diff --git a/packages/backend-defaults/api-report-rootConfig.md b/packages/backend-defaults/api-report-rootConfig.md index 8ad2e01a90..61f5c9dc9d 100644 --- a/packages/backend-defaults/api-report-rootConfig.md +++ b/packages/backend-defaults/api-report-rootConfig.md @@ -8,7 +8,7 @@ import { ConfigSchema } from '@backstage/config-loader'; import { LoggerService } from '@backstage/backend-plugin-api'; import { RemoteConfigSourceOptions } from '@backstage/config-loader'; import { RootConfigService } from '@backstage/backend-plugin-api'; -import { ServiceFactoryCompat } from '@backstage/backend-plugin-api'; +import { ServiceFactory } from '@backstage/backend-plugin-api'; // @public (undocumented) export function createConfigSecretEnumerator(options: { @@ -17,7 +17,7 @@ export function createConfigSecretEnumerator(options: { schema?: ConfigSchema; }): Promise<(config: Config) => Iterable>; -// @public @deprecated +// @public export interface RootConfigFactoryOptions { argv?: string[]; remote?: Pick; @@ -26,11 +26,10 @@ export interface RootConfigFactoryOptions { } // @public (undocumented) -export const rootConfigServiceFactory: ServiceFactoryCompat< - RootConfigService, - 'root', - RootConfigFactoryOptions ->; +export const rootConfigServiceFactory: (( + options?: RootConfigFactoryOptions, +) => ServiceFactory) & + ServiceFactory; // (No @packageDocumentation comment for this package) ``` diff --git a/packages/backend-defaults/src/entrypoints/rootConfig/rootConfigServiceFactory.ts b/packages/backend-defaults/src/entrypoints/rootConfig/rootConfigServiceFactory.ts index 7bcb9ef56b..63a7353241 100644 --- a/packages/backend-defaults/src/entrypoints/rootConfig/rootConfigServiceFactory.ts +++ b/packages/backend-defaults/src/entrypoints/rootConfig/rootConfigServiceFactory.ts @@ -31,7 +31,6 @@ import { * for more information. * * @public - * @deprecated These service options will be removed, please use the `ConfigSources` API from `@backstage/config-loader` to implement your own version of the service factory instead. */ export interface RootConfigFactoryOptions { /** @@ -46,11 +45,10 @@ export interface RootConfigFactoryOptions { watch?: boolean; } -/** - * @public - */ -export const rootConfigServiceFactory = createServiceFactory( - (options?: RootConfigFactoryOptions) => ({ +export const rootConfigServiceFactoryWithOptions = ( + options?: RootConfigFactoryOptions, +) => + createServiceFactory({ service: coreServices.rootConfig, deps: {}, async factory() { @@ -62,5 +60,12 @@ export const rootConfigServiceFactory = createServiceFactory( console.log(`Loading config from ${source}`); return await ConfigSources.toConfig(source); }, - }), + })(); + +/** + * @public + */ +export const rootConfigServiceFactory = Object.assign( + rootConfigServiceFactoryWithOptions, + rootConfigServiceFactoryWithOptions(), ); From 98ccf0020a5ed6d8a3da2f7e1ff0ac7678f95297 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 11 Jul 2024 14:21:48 +0200 Subject: [PATCH 275/416] backend-test-utils: refactor httpAuth.factory to define options on its own Signed-off-by: Patrik Oldsberg --- .changeset/wicked-impalas-explode.md | 5 ++++ packages/backend-test-utils/api-report.md | 11 +++----- .../src/next/services/mockServices.ts | 25 +++++++++++-------- 3 files changed, 24 insertions(+), 17 deletions(-) create mode 100644 .changeset/wicked-impalas-explode.md diff --git a/.changeset/wicked-impalas-explode.md b/.changeset/wicked-impalas-explode.md new file mode 100644 index 0000000000..f8a01bc36e --- /dev/null +++ b/.changeset/wicked-impalas-explode.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-test-utils': patch +--- + +Internal refactor of `mockServices.httpAuth.factory` to allow it to still be constructed with options, but without declaring options via `createServiceFactory`. diff --git a/packages/backend-test-utils/api-report.md b/packages/backend-test-utils/api-report.md index af7edba061..d77aea09a8 100644 --- a/packages/backend-test-utils/api-report.md +++ b/packages/backend-test-utils/api-report.md @@ -206,13 +206,10 @@ export namespace mockServices { }): HttpAuthService; // (undocumented) export namespace httpAuth { - const factory: ServiceFactoryCompat< - HttpAuthService, - 'plugin', - { - defaultCredentials?: BackstageCredentials | undefined; - } - >; + const factory: ((options?: { + defaultCredentials?: BackstageCredentials; + }) => ServiceFactory) & + ServiceFactory; const // (undocumented) mock: ( partialImpl?: Partial | undefined, diff --git a/packages/backend-test-utils/src/next/services/mockServices.ts b/packages/backend-test-utils/src/next/services/mockServices.ts index d56179d958..38ff819228 100644 --- a/packages/backend-test-utils/src/next/services/mockServices.ts +++ b/packages/backend-test-utils/src/next/services/mockServices.ts @@ -270,15 +270,10 @@ export namespace mockServices { ); } export namespace httpAuth { - /** - * Creates a mock service factory for the `HttpAuthService`. - * - * By default all requests without credentials are treated as requests from - * the default mock user principal. This behavior can be configured with the - * `defaultCredentials` option. - */ - export const factory = createServiceFactory( - (options?: { defaultCredentials?: BackstageCredentials }) => ({ + const factoryWithOptions = (options?: { + defaultCredentials?: BackstageCredentials; + }) => + createServiceFactory({ service: coreServices.httpAuth, deps: { plugin: coreServices.pluginMetadata }, factory: ({ plugin }) => @@ -286,7 +281,17 @@ export namespace mockServices { plugin.getId(), options?.defaultCredentials ?? mockCredentials.user(), ), - }), + })(); + /** + * Creates a mock service factory for the `HttpAuthService`. + * + * By default all requests without credentials are treated as requests from + * the default mock user principal. This behavior can be configured with the + * `defaultCredentials` option. + */ + export const factory = Object.assign( + factoryWithOptions, + factoryWithOptions(), ); export const mock = simpleMock(coreServices.httpAuth, () => ({ credentials: jest.fn(), From fccc99b7d902ce1f4d062fa14d5d1fb2a935fac6 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Fri, 12 Jul 2024 11:07:51 +0200 Subject: [PATCH 276/416] backend-test-utils: refactor other services to declare options on their own too Signed-off-by: Patrik Oldsberg --- packages/backend-test-utils/api-report.md | 18 ++++--- .../src/next/services/mockServices.ts | 50 +++++++++++++------ 2 files changed, 44 insertions(+), 24 deletions(-) diff --git a/packages/backend-test-utils/api-report.md b/packages/backend-test-utils/api-report.md index d77aea09a8..b888168827 100644 --- a/packages/backend-test-utils/api-report.md +++ b/packages/backend-test-utils/api-report.md @@ -229,7 +229,7 @@ export namespace mockServices { // (undocumented) export namespace identity { const // (undocumented) - factory: () => ServiceFactory; + factory: ServiceFactoryCompat; const // (undocumented) mock: ( partialImpl?: Partial | undefined, @@ -271,9 +271,10 @@ export namespace mockServices { data?: JsonObject; }; const // (undocumented) - factory: ( - options?: Options | undefined, - ) => ServiceFactory; + factory: ServiceFactory & + (( + options?: Options | undefined, + ) => ServiceFactory); } // (undocumented) export namespace rootHealth { @@ -315,9 +316,10 @@ export namespace mockServices { level?: 'none' | 'error' | 'warn' | 'info' | 'debug'; }; const // (undocumented) - factory: ( - options?: Options | undefined, - ) => ServiceFactory; + factory: ServiceFactory & + (( + options?: Options | undefined, + ) => ServiceFactory); const // (undocumented) mock: ( partialImpl?: Partial | undefined, @@ -337,7 +339,7 @@ export namespace mockServices { // (undocumented) export namespace tokenManager { const // (undocumented) - factory: () => ServiceFactory; + factory: ServiceFactoryCompat; const // (undocumented) mock: ( partialImpl?: Partial | undefined, diff --git a/packages/backend-test-utils/src/next/services/mockServices.ts b/packages/backend-test-utils/src/next/services/mockServices.ts index 38ff819228..8d36fec50e 100644 --- a/packages/backend-test-utils/src/next/services/mockServices.ts +++ b/packages/backend-test-utils/src/next/services/mockServices.ts @@ -70,21 +70,28 @@ function createLoggerMock() { } /** @internal */ -function simpleFactory< +function simpleFactoryWithOptions< TService, TScope extends 'root' | 'plugin', TOptions extends [options?: object] = [], >( ref: ServiceRef, factory: (...options: TOptions) => TService, -): (...options: TOptions) => ServiceFactory { - return createServiceFactory((options: unknown) => ({ - service: ref as ServiceRef, - deps: {}, - async factory() { - return (factory as any)(options); - }, - })) as (...options: TOptions) => ServiceFactory; +): ServiceFactory & + ((...options: TOptions) => ServiceFactory) { + const factoryWithOptions = (...options: TOptions) => + createServiceFactory({ + service: ref as ServiceRef, + deps: {}, + async factory() { + return factory(...options); + }, + })(); + return Object.assign( + factoryWithOptions, + factoryWithOptions(...([undefined] as unknown as TOptions)), + ) as ServiceFactory & + ((...options: TOptions) => ServiceFactory); } /** @public */ @@ -134,7 +141,10 @@ export namespace mockServices { export namespace rootConfig { export type Options = { data?: JsonObject }; - export const factory = simpleFactory(coreServices.rootConfig, rootConfig); + export const factory = simpleFactoryWithOptions( + coreServices.rootConfig, + rootConfig, + ); } export function rootLogger(options?: rootLogger.Options): LoggerService { @@ -145,7 +155,10 @@ export namespace mockServices { level?: 'none' | 'error' | 'warn' | 'info' | 'debug'; }; - export const factory = simpleFactory(coreServices.rootLogger, rootLogger); + export const factory = simpleFactoryWithOptions( + coreServices.rootLogger, + rootLogger, + ); export const mock = simpleMock(coreServices.rootLogger, () => ({ child: jest.fn(), debug: jest.fn(), @@ -168,10 +181,11 @@ export namespace mockServices { }; } export namespace tokenManager { - export const factory = simpleFactory( - coreServices.tokenManager, - tokenManager, - ); + export const factory = createServiceFactory({ + service: coreServices.tokenManager, + deps: {}, + factory: () => tokenManager(), + }); export const mock = simpleMock(coreServices.tokenManager, () => ({ authenticate: jest.fn(), getToken: jest.fn(), @@ -182,7 +196,11 @@ export namespace mockServices { return new MockIdentityService(); } export namespace identity { - export const factory = simpleFactory(coreServices.identity, identity); + export const factory = createServiceFactory({ + service: coreServices.identity, + deps: {}, + factory: () => identity(), + }); export const mock = simpleMock(coreServices.identity, () => ({ getIdentity: jest.fn(), })); From 994211d1110410b6febb2c96fdc158dfaa16fac7 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 16 Jul 2024 10:49:24 +0200 Subject: [PATCH 277/416] changesets: exit prerelease Signed-off-by: Patrik Oldsberg --- .changeset/pre.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/pre.json b/.changeset/pre.json index acd37c2559..cebbc6e919 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -1,5 +1,5 @@ { - "mode": "pre", + "mode": "exit", "tag": "next", "initialVersions": { "example-app": "0.2.98", From 8e6ba753bc2da001c53edc79e387d443311d5fca Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 16 Jul 2024 10:58:31 +0200 Subject: [PATCH 278/416] docs: prepare 1.29 release notes Signed-off-by: Patrik Oldsberg --- docs/releases/v1.29.0.md | 40 ++++++++++++++++++++++++++++++++++ microsite/docusaurus.config.ts | 2 +- microsite/sidebars.json | 1 + 3 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 docs/releases/v1.29.0.md diff --git a/docs/releases/v1.29.0.md b/docs/releases/v1.29.0.md new file mode 100644 index 0000000000..7b17abd544 --- /dev/null +++ b/docs/releases/v1.29.0.md @@ -0,0 +1,40 @@ +--- +id: v1.29.0 +title: v1.29.0 +description: Backstage Release v1.29.0 +--- + +These are the release notes for the v1.29.0 release of [Backstage](https://backstage.io/). + +A huge thanks to the whole team of maintainers and contributors as well as the amazing Backstage Community for the hard work in getting this release developed and done. + +## Highlights + +### + +<short description>. Contributed by @<user> in [#<pr>](https://github.com/backstage/backstage/pull/<pr>) + +## Security Fixes + +This release does not contain any security fixes. + +<or> + +@backstage/<package-name>, please upgrade to the latest version if you are using this module. + +## Upgrade path + +We recommend that you keep your Backstage project up to date with this latest release. For more guidance on how to upgrade, check out the documentation for [keeping Backstage updated](https://backstage.io/docs/getting-started/keeping-backstage-updated). + +## Links and References + +Below you can find a list of links and references to help you learn about and start using this new release. + +- [Backstage official website](https://backstage.io/), [documentation](https://backstage.io/docs/), and [getting started guide](https://backstage.io/docs/getting-started/) +- [GitHub repository](https://github.com/backstage/backstage) +- Backstage's [versioning and support policy](https://backstage.io/docs/overview/versioning-policy) +- [Community Discord](https://discord.gg/backstage-687207715902193673) for discussions and support +- [Changelog](https://github.com/backstage/backstage/tree/master/docs/releases/v1.29.0-changelog.md) +- Backstage [Demos](https://backstage.io/demos), [Blog](https://backstage.io/blog), [Roadmap](https://backstage.io/docs/overview/roadmap) and [Plugins](https://backstage.io/plugins) + +Sign up for our [newsletter](https://info.backstage.spotify.com/newsletter_subscribe) if you want to be informed about what is happening in the world of Backstage. diff --git a/microsite/docusaurus.config.ts b/microsite/docusaurus.config.ts index b1a6533ab9..67f6de4962 100644 --- a/microsite/docusaurus.config.ts +++ b/microsite/docusaurus.config.ts @@ -241,7 +241,7 @@ const config: Config = { position: 'left', }, { - to: 'docs/releases/v1.28.0', + to: 'docs/releases/v1.29.0', label: 'Releases', position: 'left', }, diff --git a/microsite/sidebars.json b/microsite/sidebars.json index 075025afbb..1a3a0eb4d3 100644 --- a/microsite/sidebars.json +++ b/microsite/sidebars.json @@ -1,6 +1,7 @@ { "releases": { "Release Notes": [ + "releases/v1.29.0", "releases/v1.28.0", "releases/v1.27.0", "releases/v1.26.0", From 2764d6453f91b4416e76e5fe923c6ed2552ea14a Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg <poldsberg@gmail.com> Date: Tue, 16 Jul 2024 11:32:50 +0200 Subject: [PATCH 279/416] docs,changesets: update to mention the manual service factory options pattern Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com> --- .changeset/spotty-apricots-tan.md | 20 ++++++++++ .../architecture/03-services.md | 40 +++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/.changeset/spotty-apricots-tan.md b/.changeset/spotty-apricots-tan.md index 8eea2b1dce..a2be38d775 100644 --- a/.changeset/spotty-apricots-tan.md +++ b/.changeset/spotty-apricots-tan.md @@ -52,6 +52,26 @@ export const customFooServiceFactory = createServiceFactory<FooService>({ This is of course more verbose than the previous solution where the factory could be customized through `fooServiceFactory({ bar: 'baz' })`, but this is a simplified which in practice should be using static configuration instead. +In cases where the old options patterns significantly improves the usability of the service factory, the old pattern can still be implemented like this: + +```ts +const fooServiceFactoryWithOptions = (options?: { bar: string }) => + createServiceFactory<FooService>({ + service: fooServiceRef, + deps: { logger: coreServices.logger }, + factory({ logger }) { + return { + // Implementation of the foo service using the `bar` option. + }; + }, + }); + +export const fooServiceFactory = Object.assign( + fooServiceFactoryWithOptions, + fooServiceFactoryWithOptions(), +); +``` + This change is being made because the ability to define an options callback encourages bad design of services factories. When possible, a service should be configurable through static configuration, and the existence of options may discourage that. More importantly though, the existing options do not work well with the dependency injection system of services, which is a problem for callbacks an other more advanced options. This lead to a bad pattern where only a few explicit dependencies where made available in callbacks, rather than providing an API that allowed simple re-implementation of the service with full access to dependency injection. A separate benefit of this change is that it simplifies the TypeScript types in a way that allows TypeScript to provide a much better error message when a service factory doesn't properly implement the service interface. diff --git a/docs/backend-system/architecture/03-services.md b/docs/backend-system/architecture/03-services.md index e1d86164c3..95e3d5305a 100644 --- a/docs/backend-system/architecture/03-services.md +++ b/docs/backend-system/architecture/03-services.md @@ -223,3 +223,43 @@ export const customFooServiceFactory = createServiceFactory({ ``` This allows you to provide more advanced options for the service implementation that couldn't be expressed through static configuration. It also gives users of the service implementation access to other services through dependency injection, which can be useful for their customizations. + +## Service Factory Options Pattern + +:::note Note + +This pattern is discouraged, only use it when necessary. If possible you should prefer to make services configurable via static configuration or re-implementation instead. + +::: + +In some cases it might be beneficial to allow users of your service factory to pass options to the factory itself, rather than to the service implementation. This can be enabled by also defining the service factory as a function that returns a reconfigured factory. For example: + +```ts +const fooServiceFactoryWithOptions = (options?: { + transform: (foo: string) => string; +}) => + createServiceFactory<FooService>({ + service: fooServiceRef, + deps: {}, + factory() { + return DefaultFooService.create({ + transform: options?.transform, + }); + }, + }); + +export const fooServiceFactory = Object.assign( + fooServiceFactoryWithOptions, + fooServiceFactoryWithOptions(), +); +``` + +This makes it possible to use the `fooServiceFactory` directly, as well passing additional options to create a customized factory: + +```ts +backend.add(fooServiceFactory); +// OR +backend.add(fooServiceFactory({ transform: foo => foo.toLowerCase() })); +``` + +This pattern is discouraged due to the inability to access other services through dependency injection. It is however used in a few places in the Backstage framework where the ability to directly pass options without re-implementing the service is very convenient, such as the `mockServices` from `@backstage/backend-test-utils`. From 8dd6843f03c64f4a2b9abf40eb625eb2fc8f14b5 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg <poldsberg@gmail.com> Date: Tue, 16 Jul 2024 12:39:55 +0200 Subject: [PATCH 280/416] docs: add root-health to sidebar Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com> --- microsite/sidebars.json | 1 + 1 file changed, 1 insertion(+) diff --git a/microsite/sidebars.json b/microsite/sidebars.json index 075025afbb..6d34798f03 100644 --- a/microsite/sidebars.json +++ b/microsite/sidebars.json @@ -429,6 +429,7 @@ "backend-system/core-services/permissions", "backend-system/core-services/plugin-metadata", "backend-system/core-services/root-config", + "backend-system/core-services/root-health", "backend-system/core-services/root-http-router", "backend-system/core-services/root-lifecycle", "backend-system/core-services/root-logger", From 8f794cf022834c888b3440aef9dc6bf372c40225 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg <poldsberg@gmail.com> Date: Tue, 16 Jul 2024 11:31:57 +0200 Subject: [PATCH 281/416] docs: 1.29 release notes Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com> --- docs/releases/v1.29.0.md | 89 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 83 insertions(+), 6 deletions(-) diff --git a/docs/releases/v1.29.0.md b/docs/releases/v1.29.0.md index 7b17abd544..5f7ed1db19 100644 --- a/docs/releases/v1.29.0.md +++ b/docs/releases/v1.29.0.md @@ -10,18 +10,95 @@ A huge thanks to the whole team of maintainers and contributors as well as the a ## Highlights -### <title> +### BREAKING: Backend System deprecations and removals -<short description>. Contributed by @<user> in [#<pr>](https://github.com/backstage/backstage/pull/<pr>) +As part of the [work towards a stable 1.0 release of the new backend system](https://github.com/backstage/backstage/issues/24493), there are several new deprecations and breaking changes in the backend system packages: + +**Breaking**: + +- The deprecated `token` option has been removed from `PermissionsService`, and the request options are now required and must contain a `credentials` object. +- The deprecated `getPath` option has been removed from `httpRouterServiceFactory`, the plugin paths are now always `/api/<pluginId>`. +- It is no longer possible to pass service factory callbacks to the `defaultServiceFactories` option of `createSpecializedBackend`. + +**Deprecations**: + +- The ability to define options for service factories through `createServiceFactory` has been deprecated. See the [service architecture documentation](https://backstage.io/docs/backend-system/architecture/services) for more information on how to define customizable services. +- The ability to install backend features in callback form, i.e. `() => BackendFeature`, has been deprecated. This also includes other usages such as `startTestBackend`, and dynamically imported backend features. No manual changes should be needed for this change, as all backend feature creators have been updated to return `BackendFeature` instances directly. +- The `ServiceFactoryTest.get` method has been renamed to `ServiceFactoryTest.getSubject`, and is now deprecated. +- The following types have been renamed to use an `*Options` suffix instead: `ServiceRefConfig`, `RootServiceFactoryConfig`, `PluginServiceFactoryConfig`. +- Deprecated all exports related to the legacy status checker in `@backstage/backend-common`. +- The `isDockerDisabledForTests` function exported by `@backstage/backend-test-utils` has been deprecated. + +### Backend Health Service + +A new health service as been added to the new backend system. This service provides health check endpoints for the backend, and replaces `createStatusCheckRouter` from `@backstage/backend-common`. + +The service helps implement the new `/.backstage/health/v1/readiness` and `/.backstage/health/v1/liveness` endpoints, which provide health checks for the entire backend instance. + +You can read more about this new service and how to customize it in the [Root Health Service documentation](https://backstage.io/docs/backend-system/core-services/root-health). + +### New Catalog Logs module + +This new `@backstage/plugin-catalog-backend-module-logs` module is a minimal module that will log any error events that are published by the catalog. This module is useful for making sure that catalog errors are visible in the logs, but you may want to replace it with a more customized solution if the resulting logs are too verbose. + +### Updates to the `@backstage/create-app` template + +New backstage projects created with `@backstage/create-app` will now include the Catalog Logs module for logging catalog error events, as well as support for the Postgres Search Engine. + +### Permission Policy deprecations + +The `PermissionPolicy` interface has been updated to align with the recent changes to the Backstage auth system. The second argument to the `handle` method is now of the new `PolicyQueryUser` type. This type maintains the old fields from the `BackstageIdentityResponse`, which are now all deprecated. Instead, two new fields have been added, which allows access to the same information: + +- `credentials` - A `BackstageCredentials` object, which is useful for making requests to other services on behalf of the user as part of evaluating the policy. This replaces the deprecated `token` field. See the [Auth Service documentation](https://backstage.io/docs/backend-system/core-services/auth#creating-request-tokens) for information about how to create a token using these credentials. +- `info` - A `BackstageUserInfo` object, which contains the same information as the deprecated `identity`, except for the `type` field that was redundant. + +Most existing policies can be updated by replacing the `BackstageIdentityResponse` type with `PolicyQueryUser`, which is exported from `@backstage/plugin-permission-node`, as well as replacing any occurrences of `user?.identity` with `user?.info`. + +### Renaming the `setupRequestMockHandlers` test utility + +The `setupRequestMockHandlers` utility function exported by `@backstage/test-utils` and `@backstage/backend-test-utils` has been renamed to `registerMswTestHooks`. This is done to better reflect the context and the purpose of the function. The old name is deprecated and will be removed in a future release. + +### Catalog GitHub module support for `repository` events + +The GitHub provider module and `GithubEntityProvider` for the Catalog now supports event driven ingestion of repositories by subscribing to `repository` events from GitHub. This includes the actions `archived`, `deleted`, `edited`, `renamed`, `transferred`, and `unarchived`. This is in addition to the existing support for `push` events, which you can read more about in the integration documentation for [GitHub Discovery](https://backstage.io/docs/integrations/github/discovery#events-support). + +Contributed by [@pjungermann](https://github.com/pjungermann) in [#25360](https://github.com/backstage/backstage/pull/25360) + +### Catalog i18n support + +The Catalog plugin as well as the Catalog React library now support internationalization (i18n). This means that you can customize the messaging in the catalog, as well as add translations. You can read more about this in the [i18n documentation](https://backstage.io/docs/plugins/internationalization/). + +Contributed by [@mario-mui](https://github.com/mario-mui) in [#23392](https://github.com/backstage/backstage/pull/23392) + +### Route Binding configuration improvements + +It is now possible to explicitly remove default route bindings, for cases where you don't want a plugin route to be bound to any target at all: + +```yaml +app: + routes: + bindings: + # This has the effect of removing the button for registering new + # catalog entities in the scaffolder template list view + scaffolder.registerComponent: false +``` + +### Scaffolder Fields performance improvements + +The `EntityPicker` and `MultiEntityPicker` fields have been updated to improve performance with large catalogs. Contributed by [@kmikko](https://github.com/kmikko) in [#25315](https://github.com/backstage/backstage/pull/25315), [#25380](https://github.com/backstage/backstage/pull/25380) + +### BREAKING: Catalog LDAP Module improvements + +The `@backstage/plugin-catalog-backend-module-ldap` module has been improved to support multiple or no declarations of both user and group configs. + +This change is breaking for `readLdapOrg` and `LdapProviderConfig`, which now both always accept arrays of `users` and `groups` configurations. + +Contributed by [@Jenson3210](https://github.com/Jenson3210) in [#25261](https://github.com/backstage/backstage/pull/25261) ## Security Fixes This release does not contain any security fixes. -<or> - -@backstage/<package-name>, please upgrade to the latest version if you are using this module. - ## Upgrade path We recommend that you keep your Backstage project up to date with this latest release. For more guidance on how to upgrade, check out the documentation for [keeping Backstage updated](https://backstage.io/docs/getting-started/keeping-backstage-updated). From e9c39485fffb0cc9cf9185208ac2906961055753 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg <poldsberg@gmail.com> Date: Tue, 16 Jul 2024 13:23:40 +0200 Subject: [PATCH 282/416] create-app: add lock seed for @mui/material Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com> --- packages/create-app/seed-yarn.lock | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/create-app/seed-yarn.lock b/packages/create-app/seed-yarn.lock index 2f41ba9ca3..b09a0ce1a7 100644 --- a/packages/create-app/seed-yarn.lock +++ b/packages/create-app/seed-yarn.lock @@ -21,3 +21,8 @@ ajv@^8.0.0, ajv@^8.10.0, ajv@^8.11.0, ajv@^8.12.0, ajv@^8.14.0, ajv@^8.6.0, ajv@ version "8.14.0" resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.14.0.tgz#f514ddfd4756abb200e1704414963620a625ebbb" integrity sha512-oYs1UUtO97ZO2lJ4bwnWeQW8/zvOIQLGKcvPTsWmvc2SYgBb+upuNS5NxoLaMU4h8Ju3Nbj6Cq8mD2LQoqVKFA== + +"@mui/material@^5.12.2": + version "5.16.1" + resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.16.1.tgz#6fcef9b5709df5864cf0b0bc0ea7b453a9d9e420" + integrity sha512-BGTgJRb0d/hX9tus5CEb6N/Fo8pE4tYA+s9r4/S0PCrtZ3urCLXlTH4qrAvggQbiF1cYRAbHCkVHoQ+4Pdxl+w== From 8d2fe707cbd584f4492013b31bc52f968aab08b6 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <github-actions[bot]@users.noreply.github.com> Date: Tue, 16 Jul 2024 12:06:55 +0000 Subject: [PATCH 283/416] Version Packages --- .changeset/bright-fireants-sit.md | 5 - .changeset/bright-panthers-leave.md | 6 - .changeset/brown-rats-judge.md | 5 - .changeset/calm-jeans-ring.md | 5 - .changeset/chatty-adults-boil.md | 5 - .changeset/chilly-coats-report.md | 7 - .changeset/chilly-rabbits-sneeze.md | 5 - .changeset/chilly-roses-trade.md | 5 - .changeset/clever-carrots-refuse.md | 5 - .changeset/clever-geese-jump.md | 5 - .changeset/clever-waves-judge.md | 5 - .changeset/cold-jars-punch.md | 6 - .changeset/create-app-1719320674.md | 5 - .changeset/curvy-teachers-smell.md | 8 - .changeset/dirty-wasps-do.md | 5 - .changeset/dry-wombats-type.md | 5 - .changeset/early-deers-beg.md | 7 - .changeset/eight-dancers-burn.md | 5 - .changeset/eighty-games-wink.md | 5 - .changeset/eleven-foxes-sip.md | 11 - .changeset/eleven-radios-begin.md | 5 - .changeset/fair-fans-flow.md | 6 - .changeset/fair-meals-juggle.md | 5 - .changeset/fair-pillows-know.md | 7 - .changeset/fair-rockets-leave.md | 6 - .changeset/fair-spoons-work.md | 5 - .changeset/famous-clocks-visit.md | 5 - .changeset/famous-dodos-crash.md | 15 - .changeset/fast-pens-smell.md | 5 - .changeset/fifty-pumpkins-smell.md | 5 - .changeset/forty-buttons-cover.md | 5 - .changeset/four-donuts-switch.md | 5 - .changeset/friendly-bulldogs-pay.md | 7 - .changeset/friendly-experts-fail.md | 5 - .changeset/friendly-masks-type.md | 5 - .changeset/friendly-oranges-greet.md | 6 - .changeset/friendly-stingrays-occur.md | 7 - .changeset/funny-laws-tease.md | 5 - .changeset/fuzzy-socks-do.md | 5 - .changeset/gentle-avocados-obey.md | 5 - .changeset/gold-worms-complain.md | 5 - .changeset/grumpy-wolves-hang.md | 5 - .changeset/heavy-moose-pull.md | 5 - .changeset/honest-pears-run.md | 7 - .changeset/hot-items-kick.md | 9 - .changeset/khaki-rivers-obey.md | 6 - .changeset/kind-dancers-boil.md | 5 - .changeset/light-avocados-worry.md | 6 - .changeset/little-games-fail.md | 7 - .changeset/lucky-wolves-pull.md | 5 - .changeset/metal-jokes-add.md | 5 - .changeset/metal-parents-brush.md | 5 - .changeset/metal-suits-drum.md | 5 - .changeset/mighty-keys-bow.md | 5 - .changeset/moody-llamas-breathe.md | 5 - .changeset/neat-dingos-tickle.md | 5 - .changeset/new-sheep-arrive.md | 5 - .changeset/nice-cats-nail.md | 5 - .changeset/poor-cheetahs-raise.md | 30 - .changeset/pre.json | 258 -- .changeset/rare-peas-dream.md | 5 - .changeset/renovate-7b61228.md | 6 - .changeset/renovate-ced359b.md | 11 - .changeset/rich-bears-march.md | 5 - .changeset/selfish-turtles-jog.md | 6 - .changeset/serious-kings-trade.md | 5 - .changeset/sharp-rice-tickle.md | 5 - .changeset/short-flowers-cry.md | 5 - .changeset/short-impalas-suffer.md | 5 - .changeset/shy-hounds-battle.md | 5 - .changeset/silent-experts-move.md | 5 - .changeset/silent-lobsters-tease.md | 5 - .changeset/silent-moose-eat.md | 5 - .changeset/smooth-pianos-argue.md | 5 - .changeset/soft-clocks-bake.md | 5 - .changeset/sour-jokes-sneeze.md | 5 - .changeset/spotty-apricots-tan.md | 77 - .changeset/spotty-crabs-shop.md | 5 - .changeset/stale-beds-sneeze.md | 5 - .changeset/swift-dots-cough.md | 5 - .changeset/swift-seals-drive.md | 5 - .changeset/tall-walls-learn.md | 9 - .changeset/ten-dancers-drum.md | 5 - .changeset/ten-nails-hear.md | 7 - .changeset/ten-pots-walk.md | 8 - .changeset/tender-turkeys-begin.md | 5 - .changeset/thick-lizards-divide.md | 6 - .changeset/thick-moose-decide.md | 5 - .changeset/three-carpets-smoke.md | 5 - .changeset/three-lizards-crash.md | 5 - .changeset/tiny-pianos-work.md | 5 - .changeset/tiny-schools-draw.md | 7 - .changeset/tough-lies-mate.md | 7 - .changeset/twenty-buses-carry.md | 5 - .changeset/weak-boats-float.md | 8 - .changeset/weak-emus-doubt.md | 7 - .changeset/wet-rivers-travel.md | 5 - .changeset/wicked-impalas-explode.md | 5 - .changeset/witty-keys-share.md | 5 - .changeset/yellow-cows-kick.md | 5 - .changeset/young-donuts-swim.md | 6 - .changeset/young-fishes-lie.md | 5 - .changeset/young-houses-unite.md | 5 - docs/releases/v1.29.0-changelog.md | 2495 +++++++++++++++++ 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 | 43 + packages/app-next/package.json | 2 +- packages/app/CHANGELOG.md | 41 + packages/app/package.json | 2 +- packages/backend-app-api/CHANGELOG.md | 28 + packages/backend-app-api/package.json | 2 +- packages/backend-common/CHANGELOG.md | 21 + packages/backend-common/package.json | 2 +- packages/backend-defaults/CHANGELOG.md | 32 + packages/backend-defaults/package.json | 2 +- .../CHANGELOG.md | 27 + .../package.json | 2 +- packages/backend-legacy/CHANGELOG.md | 42 + packages/backend-legacy/package.json | 2 +- packages/backend-openapi-utils/CHANGELOG.md | 8 + packages/backend-openapi-utils/package.json | 2 +- packages/backend-plugin-api/CHANGELOG.md | 98 + packages/backend-plugin-api/package.json | 2 +- packages/backend-tasks/CHANGELOG.md | 12 + packages/backend-tasks/package.json | 2 +- packages/backend-test-utils/CHANGELOG.md | 22 + packages/backend-test-utils/package.json | 2 +- packages/backend/CHANGELOG.md | 37 + packages/backend/package.json | 2 +- packages/cli-node/CHANGELOG.md | 10 + packages/cli-node/package.json | 2 +- packages/cli/CHANGELOG.md | 28 + packages/cli/package.json | 2 +- packages/core-app-api/CHANGELOG.md | 24 + 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 | 13 + packages/core-components/package.json | 2 +- packages/create-app/CHANGELOG.md | 11 + 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/frontend-app-api/CHANGELOG.md | 26 + packages/frontend-app-api/package.json | 2 +- packages/frontend-plugin-api/CHANGELOG.md | 10 + packages/frontend-plugin-api/package.json | 2 +- packages/frontend-test-utils/CHANGELOG.md | 11 + packages/frontend-test-utils/package.json | 2 +- packages/integration-react/CHANGELOG.md | 9 + packages/integration-react/package.json | 2 +- packages/integration/CHANGELOG.md | 12 + packages/integration/package.json | 2 +- packages/repo-tools/CHANGELOG.md | 12 + 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 | 12 + packages/techdocs-cli/package.json | 2 +- packages/test-utils/CHANGELOG.md | 14 + packages/test-utils/package.json | 2 +- plugins/api-docs/CHANGELOG.md | 15 + plugins/api-docs/package.json | 2 +- plugins/app-backend/CHANGELOG.md | 14 + plugins/app-backend/package.json | 2 +- plugins/app-node/CHANGELOG.md | 8 + plugins/app-node/package.json | 2 +- plugins/app-visualizer/CHANGELOG.md | 9 + plugins/app-visualizer/package.json | 2 +- .../CHANGELOG.md | 9 + .../package.json | 2 +- .../CHANGELOG.md | 11 + .../package.json | 2 +- .../CHANGELOG.md | 10 + .../package.json | 2 +- .../CHANGELOG.md | 8 + .../package.json | 2 +- .../CHANGELOG.md | 10 + .../package.json | 2 +- .../CHANGELOG.md | 10 + .../package.json | 2 +- .../CHANGELOG.md | 8 + .../package.json | 2 +- .../CHANGELOG.md | 8 + .../package.json | 2 +- .../CHANGELOG.md | 8 + .../package.json | 2 +- .../CHANGELOG.md | 11 + .../package.json | 2 +- .../CHANGELOG.md | 8 + .../package.json | 2 +- .../CHANGELOG.md | 8 + .../package.json | 2 +- .../CHANGELOG.md | 9 + .../package.json | 2 +- .../CHANGELOG.md | 10 + .../package.json | 2 +- .../CHANGELOG.md | 8 + .../package.json | 2 +- .../CHANGELOG.md | 8 + .../package.json | 2 +- .../CHANGELOG.md | 9 + .../package.json | 2 +- .../CHANGELOG.md | 9 + .../package.json | 2 +- plugins/auth-backend/CHANGELOG.md | 30 + plugins/auth-backend/package.json | 2 +- plugins/auth-node/CHANGELOG.md | 14 + plugins/auth-node/package.json | 2 +- plugins/auth-react/CHANGELOG.md | 9 + plugins/auth-react/package.json | 2 +- plugins/bitbucket-cloud-common/CHANGELOG.md | 8 + plugins/bitbucket-cloud-common/package.json | 2 +- .../catalog-backend-module-aws/CHANGELOG.md | 18 + .../catalog-backend-module-aws/package.json | 2 +- .../catalog-backend-module-azure/CHANGELOG.md | 13 + .../catalog-backend-module-azure/package.json | 2 +- .../CHANGELOG.md | 13 + .../package.json | 2 +- .../CHANGELOG.md | 17 + .../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 | 13 + .../package.json | 2 +- .../CHANGELOG.md | 13 + .../package.json | 2 +- .../CHANGELOG.md | 44 + .../package.json | 2 +- .../CHANGELOG.md | 11 + .../package.json | 2 +- .../CHANGELOG.md | 16 + .../package.json | 2 +- .../CHANGELOG.md | 16 + .../package.json | 2 +- .../catalog-backend-module-ldap/CHANGELOG.md | 21 + .../catalog-backend-module-ldap/package.json | 2 +- .../catalog-backend-module-logs/CHANGELOG.md | 14 + .../catalog-backend-module-logs/package.json | 2 +- .../CHANGELOG.md | 14 + .../package.json | 2 +- .../CHANGELOG.md | 15 + .../package.json | 2 +- .../CHANGELOG.md | 14 + .../package.json | 2 +- .../CHANGELOG.md | 11 + .../package.json | 2 +- .../CHANGELOG.md | 14 + .../package.json | 2 +- plugins/catalog-backend/CHANGELOG.md | 26 + plugins/catalog-backend/package.json | 2 +- plugins/catalog-common/CHANGELOG.md | 9 + plugins/catalog-common/package.json | 2 +- plugins/catalog-graph/CHANGELOG.md | 14 + plugins/catalog-graph/package.json | 2 +- plugins/catalog-import/CHANGELOG.md | 18 + plugins/catalog-import/package.json | 2 +- plugins/catalog-node/CHANGELOG.md | 14 + plugins/catalog-node/package.json | 2 +- plugins/catalog-react/CHANGELOG.md | 20 + plugins/catalog-react/package.json | 2 +- .../CHANGELOG.md | 7 + .../package.json | 2 +- .../catalog-unprocessed-entities/CHANGELOG.md | 10 + .../catalog-unprocessed-entities/package.json | 2 +- plugins/catalog/CHANGELOG.md | 23 + plugins/catalog/package.json | 2 +- plugins/config-schema/CHANGELOG.md | 10 + plugins/config-schema/package.json | 2 +- plugins/devtools-backend/CHANGELOG.md | 16 + plugins/devtools-backend/package.json | 2 +- plugins/devtools-common/CHANGELOG.md | 8 + plugins/devtools-common/package.json | 2 +- plugins/devtools/CHANGELOG.md | 13 + plugins/devtools/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 | 8 + plugins/events-node/package.json | 2 +- .../example-todo-list-backend/CHANGELOG.md | 10 + .../example-todo-list-backend/package.json | 2 +- plugins/example-todo-list-common/CHANGELOG.md | 7 + plugins/example-todo-list-common/package.json | 2 +- plugins/example-todo-list/CHANGELOG.md | 8 + plugins/example-todo-list/package.json | 2 +- plugins/home-react/CHANGELOG.md | 12 + plugins/home-react/package.json | 2 +- plugins/home/CHANGELOG.md | 21 + plugins/home/package.json | 2 +- plugins/kubernetes-backend/CHANGELOG.md | 20 + plugins/kubernetes-backend/package.json | 2 +- plugins/kubernetes-cluster/CHANGELOG.md | 12 + plugins/kubernetes-cluster/package.json | 2 +- plugins/kubernetes-common/CHANGELOG.md | 9 + plugins/kubernetes-common/package.json | 2 +- plugins/kubernetes-node/CHANGELOG.md | 10 + plugins/kubernetes-node/package.json | 2 +- plugins/kubernetes-react/CHANGELOG.md | 14 + plugins/kubernetes-react/package.json | 2 +- plugins/kubernetes/CHANGELOG.md | 12 + plugins/kubernetes/package.json | 2 +- .../CHANGELOG.md | 16 + .../package.json | 2 +- plugins/notifications-backend/CHANGELOG.md | 18 + plugins/notifications-backend/package.json | 2 +- plugins/notifications-common/CHANGELOG.md | 8 + plugins/notifications-common/package.json | 2 +- plugins/notifications-node/CHANGELOG.md | 13 + plugins/notifications-node/package.json | 2 +- plugins/notifications/CHANGELOG.md | 14 + plugins/notifications/package.json | 2 +- plugins/org-react/CHANGELOG.md | 11 + plugins/org-react/package.json | 2 +- plugins/org/CHANGELOG.md | 18 + plugins/org/package.json | 2 +- .../CHANGELOG.md | 11 + .../package.json | 2 +- plugins/permission-backend/CHANGELOG.md | 20 + plugins/permission-backend/package.json | 2 +- plugins/permission-common/CHANGELOG.md | 13 + plugins/permission-common/package.json | 2 +- plugins/permission-node/CHANGELOG.md | 24 + plugins/permission-node/package.json | 2 +- plugins/permission-react/CHANGELOG.md | 10 + plugins/permission-react/package.json | 2 +- plugins/proxy-backend/CHANGELOG.md | 10 + plugins/proxy-backend/package.json | 2 +- .../CHANGELOG.md | 12 + .../package.json | 2 +- .../CHANGELOG.md | 13 + .../package.json | 2 +- .../CHANGELOG.md | 13 + .../package.json | 2 +- .../CHANGELOG.md | 13 + .../package.json | 2 +- .../CHANGELOG.md | 12 + .../package.json | 2 +- .../CHANGELOG.md | 14 + .../package.json | 2 +- .../CHANGELOG.md | 15 + .../package.json | 2 +- .../CHANGELOG.md | 11 + .../package.json | 2 +- .../CHANGELOG.md | 11 + .../package.json | 2 +- .../CHANGELOG.md | 26 + .../package.json | 2 +- .../CHANGELOG.md | 14 + .../package.json | 2 +- .../CHANGELOG.md | 11 + .../package.json | 2 +- .../CHANGELOG.md | 14 + .../package.json | 2 +- .../CHANGELOG.md | 10 + .../package.json | 2 +- .../CHANGELOG.md | 10 + .../package.json | 2 +- plugins/scaffolder-backend/CHANGELOG.md | 40 + plugins/scaffolder-backend/package.json | 2 +- plugins/scaffolder-common/CHANGELOG.md | 9 + plugins/scaffolder-common/package.json | 2 +- .../scaffolder-node-test-utils/CHANGELOG.md | 11 + .../scaffolder-node-test-utils/package.json | 2 +- plugins/scaffolder-node/CHANGELOG.md | 16 + plugins/scaffolder-node/package.json | 2 +- plugins/scaffolder-react/CHANGELOG.md | 26 + plugins/scaffolder-react/package.json | 2 +- plugins/scaffolder/CHANGELOG.md | 34 + plugins/scaffolder/package.json | 2 +- .../CHANGELOG.md | 18 + .../package.json | 2 +- .../CHANGELOG.md | 12 + .../package.json | 2 +- .../CHANGELOG.md | 12 + .../package.json | 2 +- plugins/search-backend-module-pg/CHANGELOG.md | 12 + 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 | 18 + plugins/search-backend/package.json | 2 +- plugins/search-common/CHANGELOG.md | 8 + plugins/search-common/package.json | 2 +- plugins/search-react/CHANGELOG.md | 13 + plugins/search-react/package.json | 2 +- plugins/search/CHANGELOG.md | 17 + plugins/search/package.json | 2 +- plugins/signals-backend/CHANGELOG.md | 13 + plugins/signals-backend/package.json | 2 +- plugins/signals-node/CHANGELOG.md | 12 + plugins/signals-node/package.json | 2 +- plugins/signals/CHANGELOG.md | 11 + plugins/signals/package.json | 2 +- .../techdocs-addons-test-utils/CHANGELOG.md | 15 + .../techdocs-addons-test-utils/package.json | 2 +- plugins/techdocs-backend/CHANGELOG.md | 18 + plugins/techdocs-backend/package.json | 2 +- .../CHANGELOG.md | 11 + .../package.json | 2 +- plugins/techdocs-node/CHANGELOG.md | 16 + plugins/techdocs-node/package.json | 2 +- plugins/techdocs-react/CHANGELOG.md | 12 + plugins/techdocs-react/package.json | 2 +- plugins/techdocs/CHANGELOG.md | 25 + plugins/techdocs/package.json | 2 +- plugins/user-settings-backend/CHANGELOG.md | 14 + plugins/user-settings-backend/package.json | 2 +- plugins/user-settings/CHANGELOG.md | 17 + plugins/user-settings/package.json | 2 +- yarn.lock | 264 +- 436 files changed, 5209 insertions(+), 1305 deletions(-) delete mode 100644 .changeset/bright-fireants-sit.md delete mode 100644 .changeset/bright-panthers-leave.md delete mode 100644 .changeset/brown-rats-judge.md delete mode 100644 .changeset/calm-jeans-ring.md delete mode 100644 .changeset/chatty-adults-boil.md delete mode 100644 .changeset/chilly-coats-report.md delete mode 100644 .changeset/chilly-rabbits-sneeze.md delete mode 100644 .changeset/chilly-roses-trade.md delete mode 100644 .changeset/clever-carrots-refuse.md delete mode 100644 .changeset/clever-geese-jump.md delete mode 100644 .changeset/clever-waves-judge.md delete mode 100644 .changeset/cold-jars-punch.md delete mode 100644 .changeset/create-app-1719320674.md delete mode 100644 .changeset/curvy-teachers-smell.md delete mode 100644 .changeset/dirty-wasps-do.md delete mode 100644 .changeset/dry-wombats-type.md delete mode 100644 .changeset/early-deers-beg.md delete mode 100644 .changeset/eight-dancers-burn.md delete mode 100644 .changeset/eighty-games-wink.md delete mode 100644 .changeset/eleven-foxes-sip.md delete mode 100644 .changeset/eleven-radios-begin.md delete mode 100644 .changeset/fair-fans-flow.md delete mode 100644 .changeset/fair-meals-juggle.md delete mode 100644 .changeset/fair-pillows-know.md delete mode 100644 .changeset/fair-rockets-leave.md delete mode 100644 .changeset/fair-spoons-work.md delete mode 100644 .changeset/famous-clocks-visit.md delete mode 100644 .changeset/famous-dodos-crash.md delete mode 100644 .changeset/fast-pens-smell.md delete mode 100644 .changeset/fifty-pumpkins-smell.md delete mode 100644 .changeset/forty-buttons-cover.md delete mode 100644 .changeset/four-donuts-switch.md delete mode 100644 .changeset/friendly-bulldogs-pay.md delete mode 100644 .changeset/friendly-experts-fail.md delete mode 100644 .changeset/friendly-masks-type.md delete mode 100644 .changeset/friendly-oranges-greet.md delete mode 100644 .changeset/friendly-stingrays-occur.md delete mode 100644 .changeset/funny-laws-tease.md delete mode 100644 .changeset/fuzzy-socks-do.md delete mode 100644 .changeset/gentle-avocados-obey.md delete mode 100644 .changeset/gold-worms-complain.md delete mode 100644 .changeset/grumpy-wolves-hang.md delete mode 100644 .changeset/heavy-moose-pull.md delete mode 100644 .changeset/honest-pears-run.md delete mode 100644 .changeset/hot-items-kick.md delete mode 100644 .changeset/khaki-rivers-obey.md delete mode 100644 .changeset/kind-dancers-boil.md delete mode 100644 .changeset/light-avocados-worry.md delete mode 100644 .changeset/little-games-fail.md delete mode 100644 .changeset/lucky-wolves-pull.md delete mode 100644 .changeset/metal-jokes-add.md delete mode 100644 .changeset/metal-parents-brush.md delete mode 100644 .changeset/metal-suits-drum.md delete mode 100644 .changeset/mighty-keys-bow.md delete mode 100644 .changeset/moody-llamas-breathe.md delete mode 100644 .changeset/neat-dingos-tickle.md delete mode 100644 .changeset/new-sheep-arrive.md delete mode 100644 .changeset/nice-cats-nail.md delete mode 100644 .changeset/poor-cheetahs-raise.md delete mode 100644 .changeset/pre.json delete mode 100644 .changeset/rare-peas-dream.md delete mode 100644 .changeset/renovate-7b61228.md delete mode 100644 .changeset/renovate-ced359b.md delete mode 100644 .changeset/rich-bears-march.md delete mode 100644 .changeset/selfish-turtles-jog.md delete mode 100644 .changeset/serious-kings-trade.md delete mode 100644 .changeset/sharp-rice-tickle.md delete mode 100644 .changeset/short-flowers-cry.md delete mode 100644 .changeset/short-impalas-suffer.md delete mode 100644 .changeset/shy-hounds-battle.md delete mode 100644 .changeset/silent-experts-move.md delete mode 100644 .changeset/silent-lobsters-tease.md delete mode 100644 .changeset/silent-moose-eat.md delete mode 100644 .changeset/smooth-pianos-argue.md delete mode 100644 .changeset/soft-clocks-bake.md delete mode 100644 .changeset/sour-jokes-sneeze.md delete mode 100644 .changeset/spotty-apricots-tan.md delete mode 100644 .changeset/spotty-crabs-shop.md delete mode 100644 .changeset/stale-beds-sneeze.md delete mode 100644 .changeset/swift-dots-cough.md delete mode 100644 .changeset/swift-seals-drive.md delete mode 100644 .changeset/tall-walls-learn.md delete mode 100644 .changeset/ten-dancers-drum.md delete mode 100644 .changeset/ten-nails-hear.md delete mode 100644 .changeset/ten-pots-walk.md delete mode 100644 .changeset/tender-turkeys-begin.md delete mode 100644 .changeset/thick-lizards-divide.md delete mode 100644 .changeset/thick-moose-decide.md delete mode 100644 .changeset/three-carpets-smoke.md delete mode 100644 .changeset/three-lizards-crash.md delete mode 100644 .changeset/tiny-pianos-work.md delete mode 100644 .changeset/tiny-schools-draw.md delete mode 100644 .changeset/tough-lies-mate.md delete mode 100644 .changeset/twenty-buses-carry.md delete mode 100644 .changeset/weak-boats-float.md delete mode 100644 .changeset/weak-emus-doubt.md delete mode 100644 .changeset/wet-rivers-travel.md delete mode 100644 .changeset/wicked-impalas-explode.md delete mode 100644 .changeset/witty-keys-share.md delete mode 100644 .changeset/yellow-cows-kick.md delete mode 100644 .changeset/young-donuts-swim.md delete mode 100644 .changeset/young-fishes-lie.md delete mode 100644 .changeset/young-houses-unite.md create mode 100644 docs/releases/v1.29.0-changelog.md diff --git a/.changeset/bright-fireants-sit.md b/.changeset/bright-fireants-sit.md deleted file mode 100644 index 320bc69ff9..0000000000 --- a/.changeset/bright-fireants-sit.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -Added `MyGroupsSidebarItem` to the sidebar in the `create-app` template diff --git a/.changeset/bright-panthers-leave.md b/.changeset/bright-panthers-leave.md deleted file mode 100644 index 35d9c0f869..0000000000 --- a/.changeset/bright-panthers-leave.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/backend-plugin-api': patch -'@backstage/backend-defaults': patch ---- - -Added a new Root Health Service which adds new endpoints for health checks. diff --git a/.changeset/brown-rats-judge.md b/.changeset/brown-rats-judge.md deleted file mode 100644 index 0076c65d77..0000000000 --- a/.changeset/brown-rats-judge.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-permission-backend-module-allow-all-policy': patch ---- - -Internal refactor to use new `PolicyQueryUser` type. diff --git a/.changeset/calm-jeans-ring.md b/.changeset/calm-jeans-ring.md deleted file mode 100644 index 3d1efcf7bd..0000000000 --- a/.changeset/calm-jeans-ring.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder': minor ---- - -Use virtualization with `EntityPicker` as done earlier with `MultiEntityPicker` to fix performance issues with large data sets. `VirtualizedListbox` extracted into reusable component. diff --git a/.changeset/chatty-adults-boil.md b/.changeset/chatty-adults-boil.md deleted file mode 100644 index 76f3bddf41..0000000000 --- a/.changeset/chatty-adults-boil.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-techdocs': patch ---- - -Fixed an issue that was causing techdocs pages unnecessarily re-render on navigate. diff --git a/.changeset/chilly-coats-report.md b/.changeset/chilly-coats-report.md deleted file mode 100644 index 2fd044b57c..0000000000 --- a/.changeset/chilly-coats-report.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/backend-test-utils': patch -'@backstage/backend-defaults': patch -'@backstage/backend-app-api': patch ---- - -The `ServiceFactoryTest.get` method was deprecated and the `ServiceFactoryTest.getSubject` should be used instead. The `getSubject` method has the same behavior, but has a better method name to indicate that the service instance returned is the subject currently being tested. diff --git a/.changeset/chilly-rabbits-sneeze.md b/.changeset/chilly-rabbits-sneeze.md deleted file mode 100644 index cbce80ebbc..0000000000 --- a/.changeset/chilly-rabbits-sneeze.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-auth-backend-module-atlassian-provider': patch ---- - -Fix several issues with the Atlassian auth provider (type definition, profile url, profile transformation, scopes) diff --git a/.changeset/chilly-roses-trade.md b/.changeset/chilly-roses-trade.md deleted file mode 100644 index 73fc3ff766..0000000000 --- a/.changeset/chilly-roses-trade.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-common': patch ---- - -Deprecate legacy status check factory, handler and types. diff --git a/.changeset/clever-carrots-refuse.md b/.changeset/clever-carrots-refuse.md deleted file mode 100644 index 24217b1045..0000000000 --- a/.changeset/clever-carrots-refuse.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli-node': patch ---- - -Added internal metadata for the new experimental `frontend-dynamic-container` role. diff --git a/.changeset/clever-geese-jump.md b/.changeset/clever-geese-jump.md deleted file mode 100644 index 1c4694fa33..0000000000 --- a/.changeset/clever-geese-jump.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-msgraph': patch ---- - -Adds a dynamic provider for the plugin-catalog-backend-module-msgraph. Configuration is now runtime configurable through the ProviderConfigTransformer. diff --git a/.changeset/clever-waves-judge.md b/.changeset/clever-waves-judge.md deleted file mode 100644 index 100ab66f90..0000000000 --- a/.changeset/clever-waves-judge.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-techdocs-react': patch ---- - -Resolved the issue where changes in TechDoc add-ons, including the TextSize add-on, were not reapplying during navigation diff --git a/.changeset/cold-jars-punch.md b/.changeset/cold-jars-punch.md deleted file mode 100644 index 8708e1f670..0000000000 --- a/.changeset/cold-jars-punch.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/backend-defaults': minor -'@backstage/backend-app-api': minor ---- - -**BREAKING**: Removed the depreacted `getPath` option from `httpRouterServiceFactory`, as well as the `HttpRouterFactoryOptions` type. diff --git a/.changeset/create-app-1719320674.md b/.changeset/create-app-1719320674.md deleted file mode 100644 index b50d431d4b..0000000000 --- a/.changeset/create-app-1719320674.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -Bumped create-app version. diff --git a/.changeset/curvy-teachers-smell.md b/.changeset/curvy-teachers-smell.md deleted file mode 100644 index 3f032f2177..0000000000 --- a/.changeset/curvy-teachers-smell.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-ldap': patch -'@backstage/backend-plugin-api': patch -'@backstage/backend-defaults': patch -'@backstage/backend-tasks': patch ---- - -Fix bug where ISO durations could no longer be used for schedules diff --git a/.changeset/dirty-wasps-do.md b/.changeset/dirty-wasps-do.md deleted file mode 100644 index f8b4e614eb..0000000000 --- a/.changeset/dirty-wasps-do.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': patch ---- - -Updated `catalog:write` scaffolder action to show correct file path location in log message diff --git a/.changeset/dry-wombats-type.md b/.changeset/dry-wombats-type.md deleted file mode 100644 index 31fed70293..0000000000 --- a/.changeset/dry-wombats-type.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-app-api': minor ---- - -**BREAKING**: Removed the ability to pass callback-form service factories through the `defaultServiceFactories` option of `createSpecializedBackend`. This is an immediate breaking change as usage of this function is expected to be very rare. diff --git a/.changeset/early-deers-beg.md b/.changeset/early-deers-beg.md deleted file mode 100644 index 735c68aace..0000000000 --- a/.changeset/early-deers-beg.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-github': patch ---- - -Fixed bug resulting from missing required owner and repo arguments in `getEnvironmentPublicKey` in action `github:environment:create`. - -Adding environment secrets now works as expected. diff --git a/.changeset/eight-dancers-burn.md b/.changeset/eight-dancers-burn.md deleted file mode 100644 index 228ff036ab..0000000000 --- a/.changeset/eight-dancers-burn.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-permission-common': minor ---- - -**BREAKING**: Removed the deprecated and unused `token` option from `EvaluatorRequestOptions`. The `PermissionsClient` now has its own `PermissionClientRequestOptions` type that declares the `token` option instead. diff --git a/.changeset/eighty-games-wink.md b/.changeset/eighty-games-wink.md deleted file mode 100644 index e87dc56b5f..0000000000 --- a/.changeset/eighty-games-wink.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-components': patch ---- - -Fixed bug where `<Select>` component with empty string as placeholder gave an error diff --git a/.changeset/eleven-foxes-sip.md b/.changeset/eleven-foxes-sip.md deleted file mode 100644 index 8b21ddb20f..0000000000 --- a/.changeset/eleven-foxes-sip.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -'@backstage/plugin-permission-backend': patch -'@backstage/plugin-permission-node': patch ---- - -The `PermissionPolicy` interface has been updated to align with the recent changes to the Backstage auth system. The second argument to the `handle` method is now of the new `PolicyQueryUser` type. This type maintains the old fields from the `BackstageIdentityResponse`, which are now all deprecated. Instead, two new fields have been added, which allows access to the same information: - -- `credentials` - A `BackstageCredentials` object, which is useful for making requests to other services on behalf of the user as part of evaluating the policy. This replaces the deprecated `token` field. See the [Auth Service documentation](https://backstage.io/docs/backend-system/core-services/auth#creating-request-tokens) for information about how to create a token using these credentials. -- `info` - A `BackstageUserInfo` object, which contains the same information as the deprecated `identity`, except for the `type` field that was redundant. - -Most existing policies can be updated by replacing the `BackstageIdentityResponse` type with `PolicyQueryUser`, which is exported from `@backstage/plugin-permission-node`, as well as replacing any occurrences of `user?.identity` with `user?.info`. diff --git a/.changeset/eleven-radios-begin.md b/.changeset/eleven-radios-begin.md deleted file mode 100644 index 3fc2dd7895..0000000000 --- a/.changeset/eleven-radios-begin.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-techdocs': patch ---- - -Improve default sorting of docs table diff --git a/.changeset/fair-fans-flow.md b/.changeset/fair-fans-flow.md deleted file mode 100644 index abdc22440b..0000000000 --- a/.changeset/fair-fans-flow.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-techdocs-backend': patch -'@backstage/plugin-techdocs-node': patch ---- - -Adds extension point for publishers to the techdocs backend diff --git a/.changeset/fair-meals-juggle.md b/.changeset/fair-meals-juggle.md deleted file mode 100644 index 94db114170..0000000000 --- a/.changeset/fair-meals-juggle.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Added experimental support for dynamic frontend plugin builds, enabled via setting `EXPERIMENTAL_MODULE_FEDERATION` for the app build, and using the `frontend-dynamic-container` package role to create a container. Both of these are experimental and will change in the future. diff --git a/.changeset/fair-pillows-know.md b/.changeset/fair-pillows-know.md deleted file mode 100644 index f0e5034393..0000000000 --- a/.changeset/fair-pillows-know.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-cookiecutter': patch -'@backstage/plugin-scaffolder-backend-module-gitlab': patch -'@backstage/plugin-scaffolder-backend-module-rails': patch ---- - -Updated configuration instructions diff --git a/.changeset/fair-rockets-leave.md b/.changeset/fair-rockets-leave.md deleted file mode 100644 index 20f2e97552..0000000000 --- a/.changeset/fair-rockets-leave.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-bitbucket-server': patch ---- - -Instead of using hardcoded `targetBranch` now fetch the default branch from Bitbucket repository. -This prevents from errors when no `targetBranch` is provided and the default repository branch is different from `master`, for example: `main`. diff --git a/.changeset/fair-spoons-work.md b/.changeset/fair-spoons-work.md deleted file mode 100644 index e4b94625db..0000000000 --- a/.changeset/fair-spoons-work.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -Added the Catalog logs module to the `create-app` template diff --git a/.changeset/famous-clocks-visit.md b/.changeset/famous-clocks-visit.md deleted file mode 100644 index 66c2048872..0000000000 --- a/.changeset/famous-clocks-visit.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-permission-node': patch ---- - -Fix invalid cross-reference in API Reference docs diff --git a/.changeset/famous-dodos-crash.md b/.changeset/famous-dodos-crash.md deleted file mode 100644 index 5442c1b378..0000000000 --- a/.changeset/famous-dodos-crash.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -'@backstage/core-app-api': minor -'@backstage/frontend-app-api': patch ---- - -Allow for the disabling of external routes through config, which was rendered impossible after the introduction of default targets. - -```yaml -app: - routes: - bindings: - # This has the effect of removing the button for registering new - # catalog entities in the scaffolder template list view - scaffolder.registerComponent: false -``` diff --git a/.changeset/fast-pens-smell.md b/.changeset/fast-pens-smell.md deleted file mode 100644 index 6d909a397c..0000000000 --- a/.changeset/fast-pens-smell.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-org': patch ---- - -The `useGetEntities` hook could result in requests to `/api/catalog/entities` where the headers exceed the default maximum Node.js header size of 16KB. The hook logic has been adjusted to batch the requests. diff --git a/.changeset/fifty-pumpkins-smell.md b/.changeset/fifty-pumpkins-smell.md deleted file mode 100644 index 95f4fd3fc1..0000000000 --- a/.changeset/fifty-pumpkins-smell.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-gitlab': patch ---- - -The Gitlab configuration supports an additional optional boolean key `catalog.providers.gitlab.<your-org>.restrictUsersToGroup`. Setting this to `true` will make Backstage only import users from the group defined in the `group` key, instead of all users in the organisation (self-hosted) or of the root group (SaaS). It will default to false, keeping the original implementation intact, when not explicitly set. diff --git a/.changeset/forty-buttons-cover.md b/.changeset/forty-buttons-cover.md deleted file mode 100644 index 16e66df061..0000000000 --- a/.changeset/forty-buttons-cover.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-test-utils': patch ---- - -The function `isDockerDisabledForTests` is deprecated and will no longer be exported in the near future as it should only be used internally. diff --git a/.changeset/four-donuts-switch.md b/.changeset/four-donuts-switch.md deleted file mode 100644 index bb876a4341..0000000000 --- a/.changeset/four-donuts-switch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder': patch ---- - -enable resizing of the task log stream viewer diff --git a/.changeset/friendly-bulldogs-pay.md b/.changeset/friendly-bulldogs-pay.md deleted file mode 100644 index d77c739bb0..0000000000 --- a/.changeset/friendly-bulldogs-pay.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-ldap': minor ---- - -**BREAKING**: `readLdapOrg` and the `LdapProviderConfig` type now always accept arrays of user and group configs, not just single items. - -Added support for single ldap catalog provider to provide list and undefined user and group bindings next to standard single one. diff --git a/.changeset/friendly-experts-fail.md b/.changeset/friendly-experts-fail.md deleted file mode 100644 index df2d2e2b24..0000000000 --- a/.changeset/friendly-experts-fail.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-app-api': patch ---- - -Updated config schema to support app.routes.bindings diff --git a/.changeset/friendly-masks-type.md b/.changeset/friendly-masks-type.md deleted file mode 100644 index 6f38ddefa3..0000000000 --- a/.changeset/friendly-masks-type.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/integration': minor ---- - -Add support for `token` for `bitbucketCloud` integration diff --git a/.changeset/friendly-oranges-greet.md b/.changeset/friendly-oranges-greet.md deleted file mode 100644 index d327c40640..0000000000 --- a/.changeset/friendly-oranges-greet.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-catalog-react': patch -'@backstage/plugin-catalog': patch ---- - -Support i18n for catalog and catalog-react plugins diff --git a/.changeset/friendly-stingrays-occur.md b/.changeset/friendly-stingrays-occur.md deleted file mode 100644 index 3383203b40..0000000000 --- a/.changeset/friendly-stingrays-occur.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/cli': patch ---- - -- remove unused dependencies `winston` and `yn` from the template of backend plugins; -- update `msw` to version `2.3.1` in the template of backend plugins; - starting with v1 and switching later to v2 is tedious and not straight forward; it's easier to start with v2; diff --git a/.changeset/funny-laws-tease.md b/.changeset/funny-laws-tease.md deleted file mode 100644 index 8ecbc87b65..0000000000 --- a/.changeset/funny-laws-tease.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Updated the scaffolding output message for `plugin-common` in `backstage-cli`. Now, when executing `backstage-cli new` to create a new `plugin-common` package, the output message accurately reflects the action by displaying `Creating common plugin package...` instead of the previous, less accurate `Creating backend plugin...`. diff --git a/.changeset/fuzzy-socks-do.md b/.changeset/fuzzy-socks-do.md deleted file mode 100644 index aabc10f0cd..0000000000 --- a/.changeset/fuzzy-socks-do.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-techdocs': patch ---- - -Allow for searching TechDocs by entity title diff --git a/.changeset/gentle-avocados-obey.md b/.changeset/gentle-avocados-obey.md deleted file mode 100644 index 80bf5f89c7..0000000000 --- a/.changeset/gentle-avocados-obey.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Only bootstrap global-agent if it's actually being used diff --git a/.changeset/gold-worms-complain.md b/.changeset/gold-worms-complain.md deleted file mode 100644 index 229293cc2f..0000000000 --- a/.changeset/gold-worms-complain.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-permission-node': minor ---- - -**BREAKING**: Updated the `ServerPermissionClient` to match the new `PermissionsService` interface, where the deprecated `token` option has been removed and the options are now required. diff --git a/.changeset/grumpy-wolves-hang.md b/.changeset/grumpy-wolves-hang.md deleted file mode 100644 index 8ab3740e74..0000000000 --- a/.changeset/grumpy-wolves-hang.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Fix issue with CLI that was preventing upgrading from 1.28 diff --git a/.changeset/heavy-moose-pull.md b/.changeset/heavy-moose-pull.md deleted file mode 100644 index 86b2753a28..0000000000 --- a/.changeset/heavy-moose-pull.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder': minor ---- - -Use virtualization with `MultiEntityPicker`. Fixes performance issues with large data sets. diff --git a/.changeset/honest-pears-run.md b/.changeset/honest-pears-run.md deleted file mode 100644 index 65ea8d1721..0000000000 --- a/.changeset/honest-pears-run.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-azure': patch -'@backstage/plugin-scaffolder-node': patch -'@backstage/plugin-scaffolder': patch ---- - -Fixed a bug where the `RepoUrlPicker` would still require the `owner` field for `azure` diff --git a/.changeset/hot-items-kick.md b/.changeset/hot-items-kick.md deleted file mode 100644 index a3a9f129c1..0000000000 --- a/.changeset/hot-items-kick.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'@backstage/backend-dynamic-feature-service': patch -'@backstage/backend-test-utils': patch -'@backstage/backend-defaults': patch -'@backstage/backend-app-api': patch -'@backstage/plugin-events-node': patch ---- - -Service factories exported by this package have been updated to use the new service factory format that doesn't use a callback. diff --git a/.changeset/khaki-rivers-obey.md b/.changeset/khaki-rivers-obey.md deleted file mode 100644 index 856c8caf09..0000000000 --- a/.changeset/khaki-rivers-obey.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/backend-common': patch -'@backstage/cli': patch ---- - -Update default backend plugin created by the cli to use non-deprecated error handling middleware diff --git a/.changeset/kind-dancers-boil.md b/.changeset/kind-dancers-boil.md deleted file mode 100644 index 4451cab4f4..0000000000 --- a/.changeset/kind-dancers-boil.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': patch ---- - -Added a documentation how to use checkpoints diff --git a/.changeset/light-avocados-worry.md b/.changeset/light-avocados-worry.md deleted file mode 100644 index a3605a1451..0000000000 --- a/.changeset/light-avocados-worry.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-bitbucket-cloud': patch -'@backstage/plugin-bitbucket-cloud-common': patch ---- - -Add support for `autocomplete` handler to provide autocomplete options for `RepoUrlPicker` diff --git a/.changeset/little-games-fail.md b/.changeset/little-games-fail.md deleted file mode 100644 index 199f983be8..0000000000 --- a/.changeset/little-games-fail.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/plugin-org': patch ---- - -Added `relationType` property to EntityMembersListCard component that allows for display users related to a group via some other relationship aside from `memberOf`. - -Also, as a side effect, the `relationsType` property has been deprecated in favor of a more accurately named `relationAggregation` property. diff --git a/.changeset/lucky-wolves-pull.md b/.changeset/lucky-wolves-pull.md deleted file mode 100644 index 17ed4572b6..0000000000 --- a/.changeset/lucky-wolves-pull.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-defaults': patch ---- - -Refactor of `rootHttpRouterServiceFactory` to allow it to be constructed with options, but without declaring options via `createServiceFactory`. diff --git a/.changeset/metal-jokes-add.md b/.changeset/metal-jokes-add.md deleted file mode 100644 index faef714d87..0000000000 --- a/.changeset/metal-jokes-add.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-react': patch ---- - -Make EntityOwnerPicker display metadata.title or spec.profile.displayName for mode=only-owners instead of metadata.name diff --git a/.changeset/metal-parents-brush.md b/.changeset/metal-parents-brush.md deleted file mode 100644 index f73b0040fd..0000000000 --- a/.changeset/metal-parents-brush.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-techdocs': patch ---- - -Fix double scrollbar bug in reader diff --git a/.changeset/metal-suits-drum.md b/.changeset/metal-suits-drum.md deleted file mode 100644 index 4cc7e18ced..0000000000 --- a/.changeset/metal-suits-drum.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-notifications': patch ---- - -The toolbar on the Notifications page is hidden when there are no listed notifications. diff --git a/.changeset/mighty-keys-bow.md b/.changeset/mighty-keys-bow.md deleted file mode 100644 index 5f1bb408c9..0000000000 --- a/.changeset/mighty-keys-bow.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-aws': patch ---- - -Export `defaultEksClusterEntityTransformer` to allow library consumers to layer additional changes on top of the default transformer. diff --git a/.changeset/moody-llamas-breathe.md b/.changeset/moody-llamas-breathe.md deleted file mode 100644 index 418cf7480e..0000000000 --- a/.changeset/moody-llamas-breathe.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-common': patch ---- - -Add dependencies that are needed by cross-imports from backend-defaults diff --git a/.changeset/neat-dingos-tickle.md b/.changeset/neat-dingos-tickle.md deleted file mode 100644 index 43929e532f..0000000000 --- a/.changeset/neat-dingos-tickle.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-techdocs-node': patch ---- - -Bumps default version of techdocs docker image to latest diff --git a/.changeset/new-sheep-arrive.md b/.changeset/new-sheep-arrive.md deleted file mode 100644 index 00e759a187..0000000000 --- a/.changeset/new-sheep-arrive.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-components': patch ---- - -Modified the `Select` component to take in a `data-testid` parameter ensuring backwards compatibility with default value corresponding to previously hardcoded `data-testid` of "select". diff --git a/.changeset/nice-cats-nail.md b/.changeset/nice-cats-nail.md deleted file mode 100644 index 0e9b1603b8..0000000000 --- a/.changeset/nice-cats-nail.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-app-api': patch ---- - -Internal refactor that avoids the use of service factory options. diff --git a/.changeset/poor-cheetahs-raise.md b/.changeset/poor-cheetahs-raise.md deleted file mode 100644 index 0ee2162a22..0000000000 --- a/.changeset/poor-cheetahs-raise.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-github': patch ---- - -Adds support for `repository` events. - -The provider adds a subscription to the topic `github.repository`. - -Hereby, it supports events of type `repository` with actions - -- `archived` -- `deleted` -- `edited` -- `renamed` -- `transferred` -- `unarchived` - -Actions skipped as they don't require entity changes: - -- `created` -- `privatized` -- `publicized` - -If the config option `validateLocationsExist` is enabled, an API request -is necessary and will be executed. -This affects the actions `renamed`, `transferred`, and `unarchive` -of event type `repository`. - -Catalog entities related to the `GithubEntityProvider` instance will be adjusted -according to action and its meaning for them. diff --git a/.changeset/pre.json b/.changeset/pre.json deleted file mode 100644 index cebbc6e919..0000000000 --- a/.changeset/pre.json +++ /dev/null @@ -1,258 +0,0 @@ -{ - "mode": "exit", - "tag": "next", - "initialVersions": { - "example-app": "0.2.98", - "@backstage/app-defaults": "1.5.6", - "example-app-next": "0.0.12", - "app-next-example-plugin": "0.0.12", - "example-backend": "0.0.27", - "@backstage/backend-app-api": "0.7.6", - "@backstage/backend-common": "0.23.0", - "@backstage/backend-defaults": "0.3.0", - "@backstage/backend-dev-utils": "0.1.4", - "@backstage/backend-dynamic-feature-service": "0.2.11", - "example-backend-legacy": "0.2.99", - "@backstage/backend-openapi-utils": "0.1.12", - "@backstage/backend-plugin-api": "0.6.19", - "@backstage/backend-tasks": "0.5.24", - "@backstage/backend-test-utils": "0.4.0", - "@backstage/catalog-client": "1.6.5", - "@backstage/catalog-model": "1.5.0", - "@backstage/cli": "0.26.7", - "@backstage/cli-common": "0.1.14", - "@backstage/cli-node": "0.2.6", - "@backstage/codemods": "0.1.49", - "@backstage/config": "1.2.0", - "@backstage/config-loader": "1.8.1", - "@backstage/core-app-api": "1.12.6", - "@backstage/core-compat-api": "0.2.6", - "@backstage/core-components": "0.14.8", - "@backstage/core-plugin-api": "1.9.3", - "@backstage/create-app": "0.5.16", - "@backstage/dev-utils": "1.0.33", - "e2e-test": "0.2.17", - "@backstage/e2e-test-utils": "0.1.1", - "@backstage/errors": "1.2.4", - "@backstage/eslint-plugin": "0.1.8", - "@backstage/frontend-app-api": "0.7.1", - "@backstage/frontend-plugin-api": "0.6.6", - "@backstage/frontend-test-utils": "0.1.8", - "@backstage/integration": "1.12.0", - "@backstage/integration-aws-node": "0.1.12", - "@backstage/integration-react": "1.1.28", - "@backstage/release-manifests": "0.0.11", - "@backstage/repo-tools": "0.9.1", - "@techdocs/cli": "1.8.12", - "techdocs-cli-embedded-app": "0.2.97", - "@backstage/test-utils": "1.5.6", - "@backstage/theme": "0.5.6", - "@backstage/types": "1.1.1", - "@backstage/version-bridge": "1.0.8", - "yarn-plugin-backstage": "0.0.1", - "@backstage/plugin-api-docs": "0.11.6", - "@backstage/plugin-api-docs-module-protoc-gen-doc": "0.1.7", - "@backstage/plugin-app-backend": "0.3.68", - "@backstage/plugin-app-node": "0.1.19", - "@backstage/plugin-app-visualizer": "0.1.7", - "@backstage/plugin-auth-backend": "0.22.6", - "@backstage/plugin-auth-backend-module-atlassian-provider": "0.2.0", - "@backstage/plugin-auth-backend-module-aws-alb-provider": "0.1.11", - "@backstage/plugin-auth-backend-module-azure-easyauth-provider": "0.1.2", - "@backstage/plugin-auth-backend-module-bitbucket-provider": "0.1.2", - "@backstage/plugin-auth-backend-module-cloudflare-access-provider": "0.1.2", - "@backstage/plugin-auth-backend-module-gcp-iap-provider": "0.2.14", - "@backstage/plugin-auth-backend-module-github-provider": "0.1.16", - "@backstage/plugin-auth-backend-module-gitlab-provider": "0.1.16", - "@backstage/plugin-auth-backend-module-google-provider": "0.1.16", - "@backstage/plugin-auth-backend-module-guest-provider": "0.1.5", - "@backstage/plugin-auth-backend-module-microsoft-provider": "0.1.14", - "@backstage/plugin-auth-backend-module-oauth2-provider": "0.2.0", - "@backstage/plugin-auth-backend-module-oauth2-proxy-provider": "0.1.12", - "@backstage/plugin-auth-backend-module-oidc-provider": "0.2.0", - "@backstage/plugin-auth-backend-module-okta-provider": "0.0.12", - "@backstage/plugin-auth-backend-module-onelogin-provider": "0.1.0", - "@backstage/plugin-auth-backend-module-pinniped-provider": "0.1.13", - "@backstage/plugin-auth-backend-module-vmware-cloud-provider": "0.2.0", - "@backstage/plugin-auth-node": "0.4.14", - "@backstage/plugin-auth-react": "0.1.3", - "@backstage/plugin-bitbucket-cloud-common": "0.2.20", - "@backstage/plugin-catalog": "1.21.0", - "@backstage/plugin-catalog-backend": "1.23.0", - "@backstage/plugin-catalog-backend-module-aws": "0.3.14", - "@backstage/plugin-catalog-backend-module-azure": "0.1.39", - "@backstage/plugin-catalog-backend-module-backstage-openapi": "0.2.2", - "@backstage/plugin-catalog-backend-module-bitbucket-cloud": "0.2.6", - "@backstage/plugin-catalog-backend-module-bitbucket-server": "0.1.33", - "@backstage/plugin-catalog-backend-module-gcp": "0.1.20", - "@backstage/plugin-catalog-backend-module-gerrit": "0.1.36", - "@backstage/plugin-catalog-backend-module-github": "0.6.2", - "@backstage/plugin-catalog-backend-module-github-org": "0.1.14", - "@backstage/plugin-catalog-backend-module-gitlab": "0.3.18", - "@backstage/plugin-catalog-backend-module-gitlab-org": "0.0.2", - "@backstage/plugin-catalog-backend-module-incremental-ingestion": "0.4.24", - "@backstage/plugin-catalog-backend-module-ldap": "0.6.0", - "@backstage/plugin-catalog-backend-module-msgraph": "0.5.27", - "@backstage/plugin-catalog-backend-module-openapi": "0.1.37", - "@backstage/plugin-catalog-backend-module-puppetdb": "0.1.25", - "@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "0.1.17", - "@backstage/plugin-catalog-backend-module-unprocessed": "0.4.6", - "@backstage/plugin-catalog-common": "1.0.24", - "@backstage/plugin-catalog-graph": "0.4.6", - "@backstage/plugin-catalog-import": "0.12.0", - "@backstage/plugin-catalog-node": "1.12.1", - "@backstage/plugin-catalog-react": "1.12.1", - "@backstage/plugin-catalog-unprocessed-entities": "0.2.5", - "@backstage/plugin-catalog-unprocessed-entities-common": "0.0.2", - "@backstage/plugin-config-schema": "0.1.56", - "@backstage/plugin-devtools": "0.1.15", - "@backstage/plugin-devtools-backend": "0.3.5", - "@backstage/plugin-devtools-common": "0.1.10", - "@backstage/plugin-events-backend": "0.3.6", - "@backstage/plugin-events-backend-module-aws-sqs": "0.3.5", - "@backstage/plugin-events-backend-module-azure": "0.2.5", - "@backstage/plugin-events-backend-module-bitbucket-cloud": "0.2.5", - "@backstage/plugin-events-backend-module-gerrit": "0.2.5", - "@backstage/plugin-events-backend-module-github": "0.2.5", - "@backstage/plugin-events-backend-module-gitlab": "0.2.5", - "@backstage/plugin-events-backend-test-utils": "0.1.29", - "@backstage/plugin-events-node": "0.3.5", - "@internal/plugin-todo-list": "1.0.28", - "@internal/plugin-todo-list-backend": "1.0.28", - "@internal/plugin-todo-list-common": "1.0.19", - "@backstage/plugin-home": "0.7.5", - "@backstage/plugin-home-react": "0.1.14", - "@backstage/plugin-kubernetes": "0.11.11", - "@backstage/plugin-kubernetes-backend": "0.18.0", - "@backstage/plugin-kubernetes-cluster": "0.0.12", - "@backstage/plugin-kubernetes-common": "0.8.0", - "@backstage/plugin-kubernetes-node": "0.1.13", - "@backstage/plugin-kubernetes-react": "0.4.0", - "@backstage/plugin-notifications": "0.2.2", - "@backstage/plugin-notifications-backend": "0.3.0", - "@backstage/plugin-notifications-backend-module-email": "0.1.0", - "@backstage/plugin-notifications-common": "0.0.4", - "@backstage/plugin-notifications-node": "0.2.0", - "@backstage/plugin-org": "0.6.26", - "@backstage/plugin-org-react": "0.1.25", - "@backstage/plugin-permission-backend": "0.5.43", - "@backstage/plugin-permission-backend-module-allow-all-policy": "0.1.16", - "@backstage/plugin-permission-common": "0.7.14", - "@backstage/plugin-permission-node": "0.7.30", - "@backstage/plugin-permission-react": "0.4.23", - "@backstage/plugin-proxy-backend": "0.5.0", - "@backstage/plugin-scaffolder": "1.21.0", - "@backstage/plugin-scaffolder-backend": "1.22.9", - "@backstage/plugin-scaffolder-backend-module-azure": "0.1.11", - "@backstage/plugin-scaffolder-backend-module-bitbucket": "0.2.9", - "@backstage/plugin-scaffolder-backend-module-bitbucket-cloud": "0.1.9", - "@backstage/plugin-scaffolder-backend-module-bitbucket-server": "0.1.9", - "@backstage/plugin-scaffolder-backend-module-confluence-to-markdown": "0.2.20", - "@backstage/plugin-scaffolder-backend-module-cookiecutter": "0.2.43", - "@backstage/plugin-scaffolder-backend-module-gerrit": "0.1.11", - "@backstage/plugin-scaffolder-backend-module-gitea": "0.1.9", - "@backstage/plugin-scaffolder-backend-module-github": "0.3.0", - "@backstage/plugin-scaffolder-backend-module-gitlab": "0.4.1", - "@backstage/plugin-scaffolder-backend-module-notifications": "0.0.2", - "@backstage/plugin-scaffolder-backend-module-rails": "0.4.36", - "@backstage/plugin-scaffolder-backend-module-sentry": "0.1.27", - "@backstage/plugin-scaffolder-backend-module-yeoman": "0.3.2", - "@backstage/plugin-scaffolder-common": "1.5.3", - "@backstage/plugin-scaffolder-node": "0.4.5", - "@backstage/plugin-scaffolder-node-test-utils": "0.1.5", - "@backstage/plugin-scaffolder-react": "1.9.0", - "@backstage/plugin-search": "1.4.12", - "@backstage/plugin-search-backend": "1.5.10", - "@backstage/plugin-search-backend-module-catalog": "0.1.25", - "@backstage/plugin-search-backend-module-elasticsearch": "1.5.0", - "@backstage/plugin-search-backend-module-explore": "0.1.25", - "@backstage/plugin-search-backend-module-pg": "0.5.28", - "@backstage/plugin-search-backend-module-stack-overflow-collator": "0.1.12", - "@backstage/plugin-search-backend-module-techdocs": "0.1.24", - "@backstage/plugin-search-backend-node": "1.2.24", - "@backstage/plugin-search-common": "1.2.12", - "@backstage/plugin-search-react": "1.7.12", - "@backstage/plugin-signals": "0.0.7", - "@backstage/plugin-signals-backend": "0.1.5", - "@backstage/plugin-signals-node": "0.1.5", - "@backstage/plugin-signals-react": "0.0.4", - "@backstage/plugin-techdocs": "1.10.6", - "@backstage/plugin-techdocs-addons-test-utils": "1.0.33", - "@backstage/plugin-techdocs-backend": "1.10.6", - "@backstage/plugin-techdocs-module-addons-contrib": "1.1.11", - "@backstage/plugin-techdocs-node": "1.12.5", - "@backstage/plugin-techdocs-react": "1.2.5", - "@backstage/plugin-user-settings": "0.8.7", - "@backstage/plugin-user-settings-backend": "0.2.18", - "@backstage/plugin-user-settings-common": "0.0.1", - "@backstage/plugin-catalog-backend-module-logs": "0.0.0", - "@backstage/plugin-scaffolder-backend-module-gcp": "0.0.1-next.1" - }, - "changesets": [ - "bright-fireants-sit", - "bright-panthers-leave", - "calm-jeans-ring", - "chilly-roses-trade", - "clever-waves-judge", - "create-app-1719320674", - "curvy-teachers-smell", - "eighty-games-wink", - "eleven-radios-begin", - "fair-fans-flow", - "fair-pillows-know", - "fair-rockets-leave", - "fair-spoons-work", - "famous-dodos-crash", - "fast-pens-smell", - "fifty-pumpkins-smell", - "friendly-bulldogs-pay", - "friendly-experts-fail", - "friendly-masks-type", - "friendly-oranges-greet", - "friendly-stingrays-occur", - "funny-laws-tease", - "gentle-avocados-obey", - "grumpy-wolves-hang", - "heavy-moose-pull", - "honest-pears-run", - "khaki-rivers-obey", - "kind-dancers-boil", - "light-avocados-worry", - "little-games-fail", - "metal-jokes-add", - "metal-parents-brush", - "metal-suits-drum", - "moody-llamas-breathe", - "neat-dingos-tickle", - "new-sheep-arrive", - "poor-cheetahs-raise", - "rare-peas-dream", - "renovate-7b61228", - "renovate-ced359b", - "rich-bears-march", - "selfish-turtles-jog", - "serious-kings-trade", - "sharp-rice-tickle", - "short-flowers-cry", - "shy-hounds-battle", - "silent-experts-move", - "silent-lobsters-tease", - "silent-moose-eat", - "soft-clocks-bake", - "sour-jokes-sneeze", - "spotty-crabs-shop", - "swift-dots-cough", - "ten-dancers-drum", - "ten-nails-hear", - "ten-pots-walk", - "thick-lizards-divide", - "thick-moose-decide", - "three-carpets-smoke", - "tough-lies-mate", - "weak-boats-float", - "yellow-cows-kick", - "young-donuts-swim", - "young-fishes-lie", - "young-houses-unite" - ] -} diff --git a/.changeset/rare-peas-dream.md b/.changeset/rare-peas-dream.md deleted file mode 100644 index 443f8c566d..0000000000 --- a/.changeset/rare-peas-dream.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-defaults': patch ---- - -Repack the package to fix issues with typescript with named exports diff --git a/.changeset/renovate-7b61228.md b/.changeset/renovate-7b61228.md deleted file mode 100644 index 74794c2155..0000000000 --- a/.changeset/renovate-7b61228.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/cli': patch -'@backstage/plugin-scaffolder-backend': patch ---- - -Updated dependency `esbuild` to `^0.21.0`. diff --git a/.changeset/renovate-ced359b.md b/.changeset/renovate-ced359b.md deleted file mode 100644 index 2c100b6e23..0000000000 --- a/.changeset/renovate-ced359b.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -'@backstage/plugin-home-react': patch -'@backstage/plugin-home': patch -'@backstage/plugin-scaffolder-react': patch -'@backstage/plugin-scaffolder': patch ---- - -Updated dependency `@rjsf/utils` to `5.18.5`. -Updated dependency `@rjsf/core` to `5.18.5`. -Updated dependency `@rjsf/material-ui` to `5.18.5`. -Updated dependency `@rjsf/validator-ajv8` to `5.18.5`. diff --git a/.changeset/rich-bears-march.md b/.changeset/rich-bears-march.md deleted file mode 100644 index ec4a4a9404..0000000000 --- a/.changeset/rich-bears-march.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@techdocs/cli': patch ---- - -Import discovery from backend-defaults instead of backend-common diff --git a/.changeset/selfish-turtles-jog.md b/.changeset/selfish-turtles-jog.md deleted file mode 100644 index 02506ec068..0000000000 --- a/.changeset/selfish-turtles-jog.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': minor -'@backstage/plugin-scaffolder-node': patch ---- - -Add support for `autocomplete` extension point to provide additional `autocomplete` handlers diff --git a/.changeset/serious-kings-trade.md b/.changeset/serious-kings-trade.md deleted file mode 100644 index 826392bf98..0000000000 --- a/.changeset/serious-kings-trade.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-test-utils': patch ---- - -Added mock for the Root Health Service in `mockServices`. diff --git a/.changeset/sharp-rice-tickle.md b/.changeset/sharp-rice-tickle.md deleted file mode 100644 index 6104e11e75..0000000000 --- a/.changeset/sharp-rice-tickle.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-kubernetes-react': patch ---- - -Add a namespace label to RolloutDrawer diff --git a/.changeset/short-flowers-cry.md b/.changeset/short-flowers-cry.md deleted file mode 100644 index bf2c354465..0000000000 --- a/.changeset/short-flowers-cry.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-github': minor ---- - -Adds support for custom tag policies when creating GitHub environments. diff --git a/.changeset/short-impalas-suffer.md b/.changeset/short-impalas-suffer.md deleted file mode 100644 index 34bc31e85d..0000000000 --- a/.changeset/short-impalas-suffer.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-kubernetes-react': patch ---- - -Fix the `HTML` markup of the `FixDialog` component, `ul` and `li` are not allowed inside a `p` tag. diff --git a/.changeset/shy-hounds-battle.md b/.changeset/shy-hounds-battle.md deleted file mode 100644 index bfcf46c076..0000000000 --- a/.changeset/shy-hounds-battle.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Fix a few minor issues with the backend template that were causing failing linting checks in the main repo. diff --git a/.changeset/silent-experts-move.md b/.changeset/silent-experts-move.md deleted file mode 100644 index 06441a62c6..0000000000 --- a/.changeset/silent-experts-move.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Subpath export `package.json` should be of a unique name to avoid typescript resolution issues diff --git a/.changeset/silent-lobsters-tease.md b/.changeset/silent-lobsters-tease.md deleted file mode 100644 index 2dea26d8ff..0000000000 --- a/.changeset/silent-lobsters-tease.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -The `backendPlugin` and `backendModule` factory now includes a step for automatically adding the new backend plugin/module to the `index.ts` file of the backend. diff --git a/.changeset/silent-moose-eat.md b/.changeset/silent-moose-eat.md deleted file mode 100644 index bc66f55181..0000000000 --- a/.changeset/silent-moose-eat.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder': patch ---- - -Support `catalogFilter` array on `OwnedEntityPicker` diff --git a/.changeset/smooth-pianos-argue.md b/.changeset/smooth-pianos-argue.md deleted file mode 100644 index e7fc66dee4..0000000000 --- a/.changeset/smooth-pianos-argue.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-test-utils': patch ---- - -Updated `startTestBackend` and `ServiceFactoryTester` to only accept plain service factory or backend feature objects, no longer supporting the callback form. This lines up with the changes to `@backstage/backend-plugin-api` and should not require any code changes. diff --git a/.changeset/soft-clocks-bake.md b/.changeset/soft-clocks-bake.md deleted file mode 100644 index 29d7658869..0000000000 --- a/.changeset/soft-clocks-bake.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog': patch ---- - -Added small notes to AboutCard to discourage customizability PRs diff --git a/.changeset/sour-jokes-sneeze.md b/.changeset/sour-jokes-sneeze.md deleted file mode 100644 index 5cafaea595..0000000000 --- a/.changeset/sour-jokes-sneeze.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-notifications-backend': patch ---- - -Added an option to filter notifications by topic diff --git a/.changeset/spotty-apricots-tan.md b/.changeset/spotty-apricots-tan.md deleted file mode 100644 index a2be38d775..0000000000 --- a/.changeset/spotty-apricots-tan.md +++ /dev/null @@ -1,77 +0,0 @@ ---- -'@backstage/backend-plugin-api': patch ---- - -Deprecated the ability to define options for service factories through `createServiceFactory`. In the future all service factories will return a plain `ServiceFactory` object, rather than allowing users to pass options to the factory. To allow for customization of a service implementation one can instead export one or a few building blocks that allows for simple re-implementation of the service instead. - -For example, instead of: - -```ts -export const fooServiceFactory = createServiceFactory<FooService>( - (options?: { bar: string }) => ({ - service: fooServiceRef, - deps: { logger: coreServices.logger }, - factory({ logger }) { - return { - // Implementation of the foo service using the `bar` option. - }; - }, - }), -); -``` - -We instead encourage service implementations to provide an easy to use API for re-implementing the service for advanced use-cases: - -```ts -/** @public */ -export class DefaultFooService implements FooService { - static create(options: { bar: string; logger: LoggerService }) { - return new DefaultFooService(options.logger, options.bar ?? 'default'); - } - - private constructor( - private readonly logger: string, - private readonly bar: string, - ) {} - - // The rest of the implementation -} -``` - -A user that wishes to customize the service can then easily do so by defining their own factory: - -```ts -export const customFooServiceFactory = createServiceFactory<FooService>({ - service: fooServiceRef, - deps: { logger: coreServices.logger }, - factory({ logger }) { - return DefaultFooService.create({ logger, bar: 'baz' }); - }, -}); -``` - -This is of course more verbose than the previous solution where the factory could be customized through `fooServiceFactory({ bar: 'baz' })`, but this is a simplified which in practice should be using static configuration instead. - -In cases where the old options patterns significantly improves the usability of the service factory, the old pattern can still be implemented like this: - -```ts -const fooServiceFactoryWithOptions = (options?: { bar: string }) => - createServiceFactory<FooService>({ - service: fooServiceRef, - deps: { logger: coreServices.logger }, - factory({ logger }) { - return { - // Implementation of the foo service using the `bar` option. - }; - }, - }); - -export const fooServiceFactory = Object.assign( - fooServiceFactoryWithOptions, - fooServiceFactoryWithOptions(), -); -``` - -This change is being made because the ability to define an options callback encourages bad design of services factories. When possible, a service should be configurable through static configuration, and the existence of options may discourage that. More importantly though, the existing options do not work well with the dependency injection system of services, which is a problem for callbacks an other more advanced options. This lead to a bad pattern where only a few explicit dependencies where made available in callbacks, rather than providing an API that allowed simple re-implementation of the service with full access to dependency injection. - -A separate benefit of this change is that it simplifies the TypeScript types in a way that allows TypeScript to provide a much better error message when a service factory doesn't properly implement the service interface. diff --git a/.changeset/spotty-crabs-shop.md b/.changeset/spotty-crabs-shop.md deleted file mode 100644 index 6bc1bcfe0c..0000000000 --- a/.changeset/spotty-crabs-shop.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-github': patch ---- - -Added action to enable GitHub Pages on a repo diff --git a/.changeset/stale-beds-sneeze.md b/.changeset/stale-beds-sneeze.md deleted file mode 100644 index 695e09a624..0000000000 --- a/.changeset/stale-beds-sneeze.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-auth-node': patch ---- - -Fix issues with Atlassian OAuth provider: retrieve the email and photo that were not in arrays but rather in single props. diff --git a/.changeset/swift-dots-cough.md b/.changeset/swift-dots-cough.md deleted file mode 100644 index 255ee192a0..0000000000 --- a/.changeset/swift-dots-cough.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-react': minor ---- - -Improve validation error display text in scaffolder diff --git a/.changeset/swift-seals-drive.md b/.changeset/swift-seals-drive.md deleted file mode 100644 index a03f490d3f..0000000000 --- a/.changeset/swift-seals-drive.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-plugin-api': minor ---- - -**BREAKING**: The `PermissionsService` no longer supports passing the deprecated `token` option, and the request options are now required. diff --git a/.changeset/tall-walls-learn.md b/.changeset/tall-walls-learn.md deleted file mode 100644 index d79c439221..0000000000 --- a/.changeset/tall-walls-learn.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'@backstage/backend-plugin-api': patch ---- - -All service config types were renamed to option types in order to standardize frontend and backend `create*` function signatures: - -- The `ServiceRefConfig` type was renamed to`ServiceRefOptions`; -- The `RootServiceFactoryConfig` type was renamed to `RootServiceFactoryOptions`; -- The `PluginServiceFactoryConfig` type was renamed to `PluginServiceFactoryOptions` diff --git a/.changeset/ten-dancers-drum.md b/.changeset/ten-dancers-drum.md deleted file mode 100644 index 3f54a7a6b3..0000000000 --- a/.changeset/ten-dancers-drum.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-github': patch ---- - -Fixed issue with octokit call missing owner and repo when creating environment variables and secrets using github:environment:create action diff --git a/.changeset/ten-nails-hear.md b/.changeset/ten-nails-hear.md deleted file mode 100644 index 8d3c4d59c3..0000000000 --- a/.changeset/ten-nails-hear.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-github': patch ---- - -Adds `requireLastPushApproval` input property to configure Branch Protection Settings in `github:publish` action - -Adds `requireLastPushApproval` input property to configure Branch Protection Settings in `github:repo:push` action diff --git a/.changeset/ten-pots-walk.md b/.changeset/ten-pots-walk.md deleted file mode 100644 index cf540fd0e2..0000000000 --- a/.changeset/ten-pots-walk.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-logs': patch ---- - -Creates a new module to make logging catalog errors simple. This module subscribes to catalog events and logs them. - -See [Backstage documentation](https://backstage.io/docs/features/software-catalog/configuration#subscribing-to-catalog-errors) for details on how to install -and configure the plugin. diff --git a/.changeset/tender-turkeys-begin.md b/.changeset/tender-turkeys-begin.md deleted file mode 100644 index 26e376cecf..0000000000 --- a/.changeset/tender-turkeys-begin.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-permission-react': patch ---- - -Improve API Reference documentation diff --git a/.changeset/thick-lizards-divide.md b/.changeset/thick-lizards-divide.md deleted file mode 100644 index 84c1ab311a..0000000000 --- a/.changeset/thick-lizards-divide.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/backend-app-api': patch -'@backstage/backend-common': patch ---- - -Fixing exporting of classes properly from new packages diff --git a/.changeset/thick-moose-decide.md b/.changeset/thick-moose-decide.md deleted file mode 100644 index 194932979d..0000000000 --- a/.changeset/thick-moose-decide.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-search': patch ---- - -Update deps in search api extension to include fetch api diff --git a/.changeset/three-carpets-smoke.md b/.changeset/three-carpets-smoke.md deleted file mode 100644 index ab6d857f7d..0000000000 --- a/.changeset/three-carpets-smoke.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-gitlab': patch ---- - -Added support for passing `variables` to `gitlab:pipeline:trigger` diff --git a/.changeset/three-lizards-crash.md b/.changeset/three-lizards-crash.md deleted file mode 100644 index 5dffed0f3b..0000000000 --- a/.changeset/three-lizards-crash.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-app-api': patch ---- - -The ability to install backend features in callback form (`() => BackendFeature`) has been deprecated. This typically means that you need to update the installed features to use the latest version of `@backstage/backend-plugin-api`. If the feature is from a third-party package, please reach out to the package maintainer to update it. diff --git a/.changeset/tiny-pianos-work.md b/.changeset/tiny-pianos-work.md deleted file mode 100644 index 033e8272e5..0000000000 --- a/.changeset/tiny-pianos-work.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-search-backend': patch ---- - -The `AuthorizedSearchEngine` will now ignore the deprecated `token` option, and treat it as an unauthorized request. This will not have any effect in practice, since credentials are always provided by the router. diff --git a/.changeset/tiny-schools-draw.md b/.changeset/tiny-schools-draw.md deleted file mode 100644 index 2042f13fac..0000000000 --- a/.changeset/tiny-schools-draw.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/backend-test-utils': patch -'@backstage/frontend-test-utils': patch -'@backstage/test-utils': patch ---- - -Rename frontend and backend `setupRequestMockHandlers` methods to `registerMswTestHooks`. diff --git a/.changeset/tough-lies-mate.md b/.changeset/tough-lies-mate.md deleted file mode 100644 index 99edcf3616..0000000000 --- a/.changeset/tough-lies-mate.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-gcp': minor -'@backstage/plugin-scaffolder-backend': minor -'@backstage/plugin-scaffolder-node': patch ---- - -Serialization of the scaffolder workspace into GCP bucket diff --git a/.changeset/twenty-buses-carry.md b/.changeset/twenty-buses-carry.md deleted file mode 100644 index 00347e60d8..0000000000 --- a/.changeset/twenty-buses-carry.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -Added the Postgres Search Engine to the `create-app` template diff --git a/.changeset/weak-boats-float.md b/.changeset/weak-boats-float.md deleted file mode 100644 index 4fe6fe73a0..0000000000 --- a/.changeset/weak-boats-float.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -'@backstage/plugin-catalog-backend': minor -'@backstage/backend-test-utils': patch -'@backstage/backend-defaults': patch -'@backstage/backend-common': patch ---- - -bumped better-sqlite3 from ^9.0.0 to ^11.0.0 diff --git a/.changeset/weak-emus-doubt.md b/.changeset/weak-emus-doubt.md deleted file mode 100644 index cd3b4a836b..0000000000 --- a/.changeset/weak-emus-doubt.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/plugin-notifications-backend-module-email': patch -'@backstage/plugin-notifications-common': patch -'@backstage/plugin-notifications-node': patch ---- - -Move notification processor filter parsing to common package diff --git a/.changeset/wet-rivers-travel.md b/.changeset/wet-rivers-travel.md deleted file mode 100644 index 1778a3db23..0000000000 --- a/.changeset/wet-rivers-travel.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-defaults': patch ---- - -Refactor of `rootConfigServiceFactory` to allow it to be constructed with options, but without declaring options via `createServiceFactory`. diff --git a/.changeset/wicked-impalas-explode.md b/.changeset/wicked-impalas-explode.md deleted file mode 100644 index f8a01bc36e..0000000000 --- a/.changeset/wicked-impalas-explode.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-test-utils': patch ---- - -Internal refactor of `mockServices.httpAuth.factory` to allow it to still be constructed with options, but without declaring options via `createServiceFactory`. diff --git a/.changeset/witty-keys-share.md b/.changeset/witty-keys-share.md deleted file mode 100644 index 0ef89e56e2..0000000000 --- a/.changeset/witty-keys-share.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-react': patch ---- - -disables rendering of output box if no output is returned diff --git a/.changeset/yellow-cows-kick.md b/.changeset/yellow-cows-kick.md deleted file mode 100644 index 93c7e1cff1..0000000000 --- a/.changeset/yellow-cows-kick.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-node-test-utils': patch ---- - -Filename and imports correction for mockActionContext.ts diff --git a/.changeset/young-donuts-swim.md b/.changeset/young-donuts-swim.md deleted file mode 100644 index edd854f6dc..0000000000 --- a/.changeset/young-donuts-swim.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-scaffolder-react': minor -'@backstage/plugin-scaffolder': minor ---- - -Add support for `bitbucketCloud` autocomplete in `RepoUrlPicker` diff --git a/.changeset/young-fishes-lie.md b/.changeset/young-fishes-lie.md deleted file mode 100644 index 769d046375..0000000000 --- a/.changeset/young-fishes-lie.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': patch ---- - -Fix user entity not being fetched for scaffolder dry runner diff --git a/.changeset/young-houses-unite.md b/.changeset/young-houses-unite.md deleted file mode 100644 index 47ffe43c21..0000000000 --- a/.changeset/young-houses-unite.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-app-api': patch ---- - -Fixing issue with `MiddlewareFactory` deprecation wrapping diff --git a/docs/releases/v1.29.0-changelog.md b/docs/releases/v1.29.0-changelog.md new file mode 100644 index 0000000000..86cb84d1f1 --- /dev/null +++ b/docs/releases/v1.29.0-changelog.md @@ -0,0 +1,2495 @@ +# Release v1.29.0 + +Upgrade Helper: [https://backstage.github.io/upgrade-helper/?to=1.29.0](https://backstage.github.io/upgrade-helper/?to=1.29.0) + +## @backstage/backend-app-api@0.8.0 + +### Minor Changes + +- 1cb84d7: **BREAKING**: Removed the depreacted `getPath` option from `httpRouterServiceFactory`, as well as the `HttpRouterFactoryOptions` type. +- f691c9b: **BREAKING**: Removed the ability to pass callback-form service factories through the `defaultServiceFactories` option of `createSpecializedBackend`. This is an immediate breaking change as usage of this function is expected to be very rare. + +### Patch Changes + +- 2f99178: The `ServiceFactoryTest.get` method was deprecated and the `ServiceFactoryTest.getSubject` should be used instead. The `getSubject` method has the same behavior, but has a better method name to indicate that the service instance returned is the subject currently being tested. +- b05e1e1: Service factories exported by this package have been updated to use the new service factory format that doesn't use a callback. +- 617a7d2: Internal refactor that avoids the use of service factory options. +- b60db08: Fixing exporting of classes properly from new packages +- 18b96b1: The ability to install backend features in callback form (`() => BackendFeature`) has been deprecated. This typically means that you need to update the installed features to use the latest version of `@backstage/backend-plugin-api`. If the feature is from a third-party package, please reach out to the package maintainer to update it. +- a63c4b6: Fixing issue with `MiddlewareFactory` deprecation wrapping +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/cli-node@0.2.7 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-permission-node@0.8.0 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/config-loader@1.8.1 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/backend-defaults@0.4.0 + +### Minor Changes + +- 1cb84d7: **BREAKING**: Removed the depreacted `getPath` option from `httpRouterServiceFactory`, as well as the `HttpRouterFactoryOptions` type. + +### Patch Changes + +- 53ced70: Added a new Root Health Service which adds new endpoints for health checks. +- 2f99178: The `ServiceFactoryTest.get` method was deprecated and the `ServiceFactoryTest.getSubject` should be used instead. The `getSubject` method has the same behavior, but has a better method name to indicate that the service instance returned is the subject currently being tested. +- 083eaf9: Fix bug where ISO durations could no longer be used for schedules +- b05e1e1: Service factories exported by this package have been updated to use the new service factory format that doesn't use a callback. +- 419f387: Refactor of `rootHttpRouterServiceFactory` to allow it to be constructed with options, but without declaring options via `createServiceFactory`. +- cb14a05: Repack the package to fix issues with typescript with named exports +- b9ed1bb: bumped better-sqlite3 from ^9.0.0 to ^11.0.0 +- e28af58: Refactor of `rootConfigServiceFactory` to allow it to be constructed with options, but without declaring options via `createServiceFactory`. +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-app-api@0.8.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-permission-node@0.8.0 + - @backstage/integration@1.13.0 + - @backstage/plugin-events-node@0.3.8 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/config-loader@1.8.1 + - @backstage/backend-dev-utils@0.1.4 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration-aws-node@0.1.12 + - @backstage/types@1.1.1 + +## @backstage/backend-plugin-api@0.7.0 + +### Minor Changes + +- 36f91e8: **BREAKING**: The `PermissionsService` no longer supports passing the deprecated `token` option, and the request options are now required. + +### Patch Changes + +- 53ced70: Added a new Root Health Service which adds new endpoints for health checks. + +- 083eaf9: Fix bug where ISO durations could no longer be used for schedules + +- 062c01c: Deprecated the ability to define options for service factories through `createServiceFactory`. In the future all service factories will return a plain `ServiceFactory` object, rather than allowing users to pass options to the factory. To allow for customization of a service implementation one can instead export one or a few building blocks that allows for simple re-implementation of the service instead. + + For example, instead of: + + ```ts + export const fooServiceFactory = createServiceFactory<FooService>( + (options?: { bar: string }) => ({ + service: fooServiceRef, + deps: { logger: coreServices.logger }, + factory({ logger }) { + return { + // Implementation of the foo service using the `bar` option. + }; + }, + }), + ); + ``` + + We instead encourage service implementations to provide an easy to use API for re-implementing the service for advanced use-cases: + + ```ts + /** @public */ + export class DefaultFooService implements FooService { + static create(options: { bar: string; logger: LoggerService }) { + return new DefaultFooService(options.logger, options.bar ?? 'default'); + } + + private constructor( + private readonly logger: string, + private readonly bar: string, + ) {} + + // The rest of the implementation + } + ``` + + A user that wishes to customize the service can then easily do so by defining their own factory: + + ```ts + export const customFooServiceFactory = createServiceFactory<FooService>({ + service: fooServiceRef, + deps: { logger: coreServices.logger }, + factory({ logger }) { + return DefaultFooService.create({ logger, bar: 'baz' }); + }, + }); + ``` + + This is of course more verbose than the previous solution where the factory could be customized through `fooServiceFactory({ bar: 'baz' })`, but this is a simplified which in practice should be using static configuration instead. + + In cases where the old options patterns significantly improves the usability of the service factory, the old pattern can still be implemented like this: + + ```ts + const fooServiceFactoryWithOptions = (options?: { bar: string }) => + createServiceFactory<FooService>({ + service: fooServiceRef, + deps: { logger: coreServices.logger }, + factory({ logger }) { + return { + // Implementation of the foo service using the `bar` option. + }; + }, + }); + + export const fooServiceFactory = Object.assign( + fooServiceFactoryWithOptions, + fooServiceFactoryWithOptions(), + ); + ``` + + This change is being made because the ability to define an options callback encourages bad design of services factories. When possible, a service should be configurable through static configuration, and the existence of options may discourage that. More importantly though, the existing options do not work well with the dependency injection system of services, which is a problem for callbacks an other more advanced options. This lead to a bad pattern where only a few explicit dependencies where made available in callbacks, rather than providing an API that allowed simple re-implementation of the service with full access to dependency injection. + + A separate benefit of this change is that it simplifies the TypeScript types in a way that allows TypeScript to provide a much better error message when a service factory doesn't properly implement the service interface. + +- fe47a3e: All service config types were renamed to option types in order to standardize frontend and backend `create*` function signatures: + + - The `ServiceRefConfig` type was renamed to`ServiceRefOptions`; + - The `RootServiceFactoryConfig` type was renamed to `RootServiceFactoryOptions`; + - The `PluginServiceFactoryConfig` type was renamed to `PluginServiceFactoryOptions` + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/core-app-api@1.14.0 + +### Minor Changes + +- d3c39fc: Allow for the disabling of external routes through config, which was rendered impossible after the introduction of default targets. + + ```yaml + app: + routes: + bindings: + # This has the effect of removing the button for registering new + # catalog entities in the scaffolder template list view + scaffolder.registerComponent: false + ``` + +### Patch Changes + +- db2e2d5: Updated config schema to support app.routes.bindings +- Updated dependencies + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + +## @backstage/integration@1.13.0 + +### Minor Changes + +- b5deed0: Add support for `token` for `bitbucketCloud` integration + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-catalog-backend@1.24.0 + +### Minor Changes + +- b9ed1bb: bumped better-sqlite3 from ^9.0.0 to ^11.0.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.0 + - @backstage/integration@1.13.0 + - @backstage/plugin-events-node@0.3.8 + - @backstage/backend-openapi-utils@0.1.15 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-search-backend-module-catalog@0.1.28 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog-backend-module-ldap@0.7.0 + +### Minor Changes + +- cb32ca7: **BREAKING**: `readLdapOrg` and the `LdapProviderConfig` type now always accept arrays of user and group configs, not just single items. + + Added support for single ldap catalog provider to provide list and undefined user and group bindings next to standard single one. + +### Patch Changes + +- 083eaf9: Fix bug where ISO durations could no longer be used for schedules +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-permission-common@0.8.0 + +### Minor Changes + +- f4085b8: **BREAKING**: Removed the deprecated and unused `token` option from `EvaluatorRequestOptions`. The `PermissionsClient` now has its own `PermissionClientRequestOptions` type that declares the `token` option instead. + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-permission-node@0.8.0 + +### Minor Changes + +- 36f91e8: **BREAKING**: Updated the `ServerPermissionClient` to match the new `PermissionsService` interface, where the deprecated `token` option has been removed and the options are now required. + +### Patch Changes + +- ed10fd2: The `PermissionPolicy` interface has been updated to align with the recent changes to the Backstage auth system. The second argument to the `handle` method is now of the new `PolicyQueryUser` type. This type maintains the old fields from the `BackstageIdentityResponse`, which are now all deprecated. Instead, two new fields have been added, which allows access to the same information: + + - `credentials` - A `BackstageCredentials` object, which is useful for making requests to other services on behalf of the user as part of evaluating the policy. This replaces the deprecated `token` field. See the [Auth Service documentation](https://backstage.io/docs/backend-system/core-services/auth#creating-request-tokens) for information about how to create a token using these credentials. + - `info` - A `BackstageUserInfo` object, which contains the same information as the deprecated `identity`, except for the `type` field that was redundant. + + Most existing policies can be updated by replacing the `BackstageIdentityResponse` type with `PolicyQueryUser`, which is exported from `@backstage/plugin-permission-node`, as well as replacing any occurrences of `user?.identity` with `user?.info`. + +- 28b2cfb: Fix invalid cross-reference in API Reference docs + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-scaffolder@1.23.0 + +### Minor Changes + +- 52b6db0: Use virtualization with `EntityPicker` as done earlier with `MultiEntityPicker` to fix performance issues with large data sets. `VirtualizedListbox` extracted into reusable component. +- 3583ce5: Use virtualization with `MultiEntityPicker`. Fixes performance issues with large data sets. +- b5deed0: Add support for `bitbucketCloud` autocomplete in `RepoUrlPicker` + +### Patch Changes + +- 4d7e11f: enable resizing of the task log stream viewer +- 661b354: Fixed a bug where the `RepoUrlPicker` would still require the `owner` field for `azure` +- cc81579: Updated dependency `@rjsf/utils` to `5.18.5`. + Updated dependency `@rjsf/core` to `5.18.5`. + Updated dependency `@rjsf/material-ui` to `5.18.5`. + Updated dependency `@rjsf/validator-ajv8` to `5.18.5`. +- 89c44b3: Support `catalogFilter` array on `OwnedEntityPicker` +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/integration@1.13.0 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/plugin-scaffolder-react@1.10.0 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-scaffolder-common@1.5.4 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/integration-react@1.1.29 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-compat-api@0.2.7 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-backend@1.23.0 + +### Minor Changes + +- b5deed0: Add support for `autocomplete` extension point to provide additional `autocomplete` handlers +- 0b52438: Serialization of the scaffolder workspace into GCP bucket + +### Patch Changes + +- b9451dd: Updated `catalog:write` scaffolder action to show correct file path location in log message +- ff1bb4c: Added a documentation how to use checkpoints +- da90cce: Updated dependency `esbuild` to `^0.21.0`. +- 62d1fe3: Fix user entity not being fetched for scaffolder dry runner +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-scaffolder-backend-module-github@0.4.0 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.0 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.4.4 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.1.12 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-backend-module-azure@0.1.14 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.1.12 + - @backstage/plugin-bitbucket-cloud-common@0.2.21 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.20 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.2.12 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.1.14 + - @backstage/plugin-scaffolder-backend-module-gitea@0.1.12 + - @backstage/plugin-scaffolder-common@1.5.4 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-backend-module-gcp@0.1.0 + +### Minor Changes + +- 0b52438: Serialization of the scaffolder workspace into GCP bucket + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-scaffolder-backend-module-github@0.4.0 + +### Minor Changes + +- 70c4b36: Adds support for custom tag policies when creating GitHub environments. + +### Patch Changes + +- ccfc9d1: Fixed bug resulting from missing required owner and repo arguments in `getEnvironmentPublicKey` in action `github:environment:create`. + + Adding environment secrets now works as expected. + +- 141f366: Added action to enable GitHub Pages on a repo + +- 4410fed: Fixed issue with octokit call missing owner and repo when creating environment variables and secrets using github:environment:create action + +- dfaa28d: Adds `requireLastPushApproval` input property to configure Branch Protection Settings in `github:publish` action + + Adds `requireLastPushApproval` input property to configure Branch Protection Settings in `github:repo:push` action + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-scaffolder-react@1.10.0 + +### Minor Changes + +- 354e68c: Improve validation error display text in scaffolder +- b5deed0: Add support for `bitbucketCloud` autocomplete in `RepoUrlPicker` + +### Patch Changes + +- cc81579: Updated dependency `@rjsf/utils` to `5.18.5`. + Updated dependency `@rjsf/core` to `5.18.5`. + Updated dependency `@rjsf/material-ui` to `5.18.5`. + Updated dependency `@rjsf/validator-ajv8` to `5.18.5`. +- 4d7e11f: disables rendering of output box if no output is returned +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/plugin-scaffolder-common@1.5.4 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + +## @backstage/app-defaults@1.5.8 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/core-app-api@1.14.0 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + +## @backstage/backend-common@0.23.3 + +### Patch Changes + +- 8c09c97: Deprecate legacy status check factory, handler and types. +- d228862: Update default backend plugin created by the cli to use non-deprecated error handling middleware +- c964a3d: Add dependencies that are needed by cross-imports from backend-defaults +- b60db08: Fixing exporting of classes properly from new packages +- b9ed1bb: bumped better-sqlite3 from ^9.0.0 to ^11.0.0 +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/integration@1.13.0 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/config-loader@1.8.1 + - @backstage/backend-dev-utils@0.1.4 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration-aws-node@0.1.12 + - @backstage/types@1.1.1 + +## @backstage/backend-dynamic-feature-service@0.2.15 + +### Patch Changes + +- b05e1e1: Service factories exported by this package have been updated to use the new service factory format that doesn't use a callback. +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-app-api@0.8.0 + - @backstage/backend-common@0.23.3 + - @backstage/cli-node@0.2.7 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/plugin-events-node@0.3.8 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/plugin-catalog-backend@1.24.0 + - @backstage/plugin-app-node@0.1.22 + - @backstage/plugin-events-backend@0.3.9 + - @backstage/plugin-search-backend-node@1.2.27 + - @backstage/config-loader@1.8.1 + - @backstage/plugin-search-common@1.2.13 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/backend-openapi-utils@0.1.15 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/errors@1.2.4 + +## @backstage/backend-tasks@0.5.27 + +### Patch Changes + +- 083eaf9: Fix bug where ISO durations could no longer be used for schedules +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/backend-test-utils@0.4.4 + +### Patch Changes + +- 2f99178: The `ServiceFactoryTest.get` method was deprecated and the `ServiceFactoryTest.getSubject` should be used instead. The `getSubject` method has the same behavior, but has a better method name to indicate that the service instance returned is the subject currently being tested. +- edf5cc3: The function `isDockerDisabledForTests` is deprecated and will no longer be exported in the near future as it should only be used internally. +- b05e1e1: Service factories exported by this package have been updated to use the new service factory format that doesn't use a callback. +- fce7887: Added mock for the Root Health Service in `mockServices`. +- 906c817: Updated `startTestBackend` and `ServiceFactoryTester` to only accept plain service factory or backend feature objects, no longer supporting the callback form. This lines up with the changes to `@backstage/backend-plugin-api` and should not require any code changes. +- 95a3a0b: Rename frontend and backend `setupRequestMockHandlers` methods to `registerMswTestHooks`. +- b9ed1bb: bumped better-sqlite3 from ^9.0.0 to ^11.0.0 +- 98ccf00: Internal refactor of `mockServices.httpAuth.factory` to allow it to still be constructed with options, but without declaring options via `createServiceFactory`. +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-defaults@0.4.0 + - @backstage/backend-app-api@0.8.0 + - @backstage/plugin-events-node@0.3.8 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/cli@0.26.11 + +### Patch Changes + +- 133464c: Added experimental support for dynamic frontend plugin builds, enabled via setting `EXPERIMENTAL_MODULE_FEDERATION` for the app build, and using the `frontend-dynamic-container` package role to create a container. Both of these are experimental and will change in the future. +- e2e320c: - remove unused dependencies `winston` and `yn` from the template of backend plugins; + - update `msw` to version `2.3.1` in the template of backend plugins; + starting with v1 and switching later to v2 is tedious and not straight forward; it's easier to start with v2; +- 0540c5a: Updated the scaffolding output message for `plugin-common` in `backstage-cli`. Now, when executing `backstage-cli new` to create a new `plugin-common` package, the output message accurately reflects the action by displaying `Creating common plugin package...` instead of the previous, less accurate `Creating backend plugin...`. +- 7652db4: Only bootstrap global-agent if it's actually being used +- f0c0039: Fix issue with CLI that was preventing upgrading from 1.28 +- d228862: Update default backend plugin created by the cli to use non-deprecated error handling middleware +- da90cce: Updated dependency `esbuild` to `^0.21.0`. +- a60d73b: Fix a few minor issues with the backend template that were causing failing linting checks in the main repo. +- 0510d98: Subpath export `package.json` should be of a unique name to avoid typescript resolution issues +- 4baac0c: The `backendPlugin` and `backendModule` factory now includes a step for automatically adding the new backend plugin/module to the `index.ts` file of the backend. +- Updated dependencies + - @backstage/cli-node@0.2.7 + - @backstage/integration@1.13.0 + - @backstage/config-loader@1.8.1 + - @backstage/catalog-model@1.5.0 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/eslint-plugin@0.1.8 + - @backstage/release-manifests@0.0.11 + - @backstage/types@1.1.1 + +## @backstage/cli-node@0.2.7 + +### Patch Changes + +- 133464c: Added internal metadata for the new experimental `frontend-dynamic-container` role. +- Updated dependencies + - @backstage/cli-common@0.1.14 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/core-compat-api@0.2.7 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/core-plugin-api@1.9.3 + - @backstage/version-bridge@1.0.8 + +## @backstage/core-components@0.14.9 + +### Patch Changes + +- d4ffdbb: Fixed bug where `<Select>` component with empty string as placeholder gave an error +- 99d672d: Modified the `Select` component to take in a `data-testid` parameter ensuring backwards compatibility with default value corresponding to previously hardcoded `data-testid` of "select". +- Updated dependencies + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/theme@0.5.6 + - @backstage/version-bridge@1.0.8 + +## @backstage/create-app@0.5.17 + +### Patch Changes + +- 780d994: Added `MyGroupsSidebarItem` to the sidebar in the `create-app` template +- f03d12a: Bumped create-app version. +- e90a2cd: Added the Catalog logs module to the `create-app` template +- 3ac2a6a: Added the Postgres Search Engine to the `create-app` template +- Updated dependencies + - @backstage/cli-common@0.1.14 + +## @backstage/dev-utils@1.0.35 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/core-app-api@1.14.0 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/app-defaults@1.5.8 + - @backstage/integration-react@1.1.29 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + +## @backstage/frontend-app-api@0.7.3 + +### Patch Changes + +- d3c39fc: Allow for the disabling of external routes through config, which was rendered impossible after the introduction of default targets. + + ```yaml + app: + routes: + bindings: + # This has the effect of removing the button for registering new + # catalog entities in the scaffolder template list view + scaffolder.registerComponent: false + ``` + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/core-app-api@1.14.0 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + +## @backstage/frontend-plugin-api@0.6.7 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/core-plugin-api@1.9.3 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + +## @backstage/frontend-test-utils@0.1.10 + +### Patch Changes + +- 95a3a0b: Rename frontend and backend `setupRequestMockHandlers` methods to `registerMswTestHooks`. +- Updated dependencies + - @backstage/frontend-app-api@0.7.3 + - @backstage/test-utils@1.5.8 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/types@1.1.1 + +## @backstage/integration-react@1.1.29 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.13.0 + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + +## @backstage/repo-tools@0.9.4 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/cli-node@0.2.7 + - @backstage/config-loader@1.8.1 + - @backstage/catalog-model@1.5.0 + - @backstage/cli-common@0.1.14 + - @backstage/errors@1.2.4 + +## @techdocs/cli@1.8.16 + +### Patch Changes + +- c964a3d: Import discovery from backend-defaults instead of backend-common +- Updated dependencies + - @backstage/backend-defaults@0.4.0 + - @backstage/plugin-techdocs-node@1.12.8 + - @backstage/catalog-model@1.5.0 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + +## @backstage/test-utils@1.5.8 + +### Patch Changes + +- 95a3a0b: Rename frontend and backend `setupRequestMockHandlers` methods to `registerMswTestHooks`. +- Updated dependencies + - @backstage/plugin-permission-common@0.8.0 + - @backstage/core-app-api@1.14.0 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + +## @backstage/plugin-api-docs@0.11.7 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/plugin-catalog@1.21.1 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/catalog-model@1.5.0 + - @backstage/core-compat-api@0.2.7 + - @backstage/core-plugin-api@1.9.3 + +## @backstage/plugin-app-backend@0.3.71 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/plugin-app-node@0.1.22 + - @backstage/config-loader@1.8.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-app-node@0.1.22 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/config-loader@1.8.1 + +## @backstage/plugin-app-visualizer@0.1.8 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/core-plugin-api@1.9.3 + +## @backstage/plugin-auth-backend@0.22.9 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-auth-backend-module-atlassian-provider@0.2.3 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/plugin-auth-backend-module-aws-alb-provider@0.1.14 + - @backstage/plugin-auth-backend-module-azure-easyauth-provider@0.1.5 + - @backstage/plugin-auth-backend-module-bitbucket-provider@0.1.5 + - @backstage/plugin-auth-backend-module-cloudflare-access-provider@0.1.5 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.17 + - @backstage/plugin-auth-backend-module-github-provider@0.1.19 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.1.19 + - @backstage/plugin-auth-backend-module-google-provider@0.1.19 + - @backstage/plugin-auth-backend-module-microsoft-provider@0.1.17 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.2.3 + - @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.15 + - @backstage/plugin-auth-backend-module-oidc-provider@0.2.3 + - @backstage/plugin-auth-backend-module-okta-provider@0.0.15 + - @backstage/plugin-auth-backend-module-onelogin-provider@0.1.3 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-auth-backend-module-atlassian-provider@0.2.3 + +### Patch Changes + +- b9832ae: Fix several issues with the Atlassian auth provider (type definition, profile url, profile transformation, scopes) +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-auth-node@0.4.17 + +## @backstage/plugin-auth-backend-module-aws-alb-provider@0.1.14 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/plugin-auth-backend@0.22.9 + - @backstage/errors@1.2.4 + +## @backstage/plugin-auth-backend-module-azure-easyauth-provider@0.1.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-auth-backend-module-bitbucket-provider@0.1.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-auth-node@0.4.17 + +## @backstage/plugin-auth-backend-module-cloudflare-access-provider@0.1.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.17 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-auth-backend-module-github-provider@0.1.19 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-auth-node@0.4.17 + +## @backstage/plugin-auth-backend-module-gitlab-provider@0.1.19 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-auth-node@0.4.17 + +## @backstage/plugin-auth-backend-module-google-provider@0.1.19 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-auth-node@0.4.17 + +## @backstage/plugin-auth-backend-module-guest-provider@0.1.8 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-auth-backend-module-microsoft-provider@0.1.17 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-auth-node@0.4.17 + +## @backstage/plugin-auth-backend-module-oauth2-provider@0.2.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-auth-node@0.4.17 + +## @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.15 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/errors@1.2.4 + +## @backstage/plugin-auth-backend-module-oidc-provider@0.2.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/plugin-auth-backend@0.22.9 + +## @backstage/plugin-auth-backend-module-okta-provider@0.0.15 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-auth-node@0.4.17 + +## @backstage/plugin-auth-backend-module-onelogin-provider@0.1.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-auth-node@0.4.17 + +## @backstage/plugin-auth-backend-module-pinniped-provider@0.1.16 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/config@1.2.0 + +## @backstage/plugin-auth-backend-module-vmware-cloud-provider@0.2.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/catalog-model@1.5.0 + +## @backstage/plugin-auth-node@0.4.17 + +### Patch Changes + +- 55c1a72: Fix issues with Atlassian OAuth provider: retrieve the email and photo that were not in arrays but rather in single props. +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-auth-react@0.1.4 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + +## @backstage/plugin-bitbucket-cloud-common@0.2.21 + +### Patch Changes + +- b5deed0: Add support for `autocomplete` handler to provide autocomplete options for `RepoUrlPicker` +- Updated dependencies + - @backstage/integration@1.13.0 + +## @backstage/plugin-catalog@1.21.1 + +### Patch Changes + +- 06c0956: Support i18n for catalog and catalog-react plugins +- d133eaa: Added small notes to AboutCard to discourage customizability PRs +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-scaffolder-common@1.5.4 + - @backstage/plugin-search-common@1.2.13 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/integration-react@1.1.29 + - @backstage/plugin-search-react@1.7.13 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-compat-api@0.2.7 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog-backend-module-aws@0.3.17 + +### Patch Changes + +- 4afa050: Export `defaultEksClusterEntityTransformer` to allow library consumers to layer additional changes on top of the default transformer. +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/integration@1.13.0 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-kubernetes-common@0.8.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration-aws-node@0.1.12 + +## @backstage/plugin-catalog-backend-module-azure@0.1.42 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/integration@1.13.0 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/config@1.2.0 + +## @backstage/plugin-catalog-backend-module-backstage-openapi@0.2.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-tasks@0.5.27 + - @backstage/backend-openapi-utils@0.1.15 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-catalog-backend-module-bitbucket-cloud@0.2.9 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/integration@1.13.0 + - @backstage/plugin-events-node@0.3.8 + - @backstage/plugin-bitbucket-cloud-common@0.2.21 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + +## @backstage/plugin-catalog-backend-module-bitbucket-server@0.1.36 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/integration@1.13.0 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-catalog-backend-module-gcp@0.1.23 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-kubernetes-common@0.8.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + +## @backstage/plugin-catalog-backend-module-gerrit@0.1.39 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/integration@1.13.0 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-catalog-backend-module-github@0.6.5 + +### Patch Changes + +- 9112efc: Adds support for `repository` events. + + The provider adds a subscription to the topic `github.repository`. + + Hereby, it supports events of type `repository` with actions + + - `archived` + - `deleted` + - `edited` + - `renamed` + - `transferred` + - `unarchived` + + Actions skipped as they don't require entity changes: + + - `created` + - `privatized` + - `publicized` + + If the config option `validateLocationsExist` is enabled, an API request + is necessary and will be executed. + This affects the actions `renamed`, `transferred`, and `unarchive` + of event type `repository`. + + Catalog entities related to the `GithubEntityProvider` instance will be adjusted + according to action and its meaning for them. + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/integration@1.13.0 + - @backstage/plugin-events-node@0.3.8 + - @backstage/plugin-catalog-backend@1.24.0 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + +## @backstage/plugin-catalog-backend-module-github-org@0.1.17 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-events-node@0.3.8 + - @backstage/plugin-catalog-backend-module-github@0.6.5 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/config@1.2.0 + +## @backstage/plugin-catalog-backend-module-gitlab@0.3.21 + +### Patch Changes + +- 8db30ad: The Gitlab configuration supports an additional optional boolean key `catalog.providers.gitlab.<your-org>.restrictUsersToGroup`. Setting this to `true` will make Backstage only import users from the group defined in the `group` key, instead of all users in the organisation (self-hosted) or of the root group (SaaS). It will default to false, keeping the original implementation intact, when not explicitly set. +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/integration@1.13.0 + - @backstage/plugin-events-node@0.3.8 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + +## @backstage/plugin-catalog-backend-module-gitlab-org@0.0.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-catalog-backend-module-gitlab@0.3.21 + - @backstage/plugin-events-node@0.3.8 + - @backstage/plugin-catalog-node@1.12.4 + +## @backstage/plugin-catalog-backend-module-incremental-ingestion@0.4.27 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-events-node@0.3.8 + - @backstage/plugin-catalog-backend@1.24.0 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-catalog-backend-module-logs@0.0.1 + +### Patch Changes + +- 97caf55: Creates a new module to make logging catalog errors simple. This module subscribes to catalog events and logs them. + + See [Backstage documentation](https://backstage.io/docs/features/software-catalog/configuration#subscribing-to-catalog-errors) for details on how to install + and configure the plugin. + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-events-node@0.3.8 + - @backstage/plugin-catalog-backend@1.24.0 + +## @backstage/plugin-catalog-backend-module-msgraph@0.5.30 + +### Patch Changes + +- f7bdcea: Adds a dynamic provider for the plugin-catalog-backend-module-msgraph. Configuration is now runtime configurable through the ProviderConfigTransformer. +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + +## @backstage/plugin-catalog-backend-module-openapi@0.1.40 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/integration@1.13.0 + - @backstage/plugin-catalog-backend@1.24.0 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog-backend-module-puppetdb@0.1.28 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.20 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-scaffolder-common@1.5.4 + - @backstage/catalog-model@1.5.0 + +## @backstage/plugin-catalog-backend-module-unprocessed@0.4.9 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-catalog-unprocessed-entities-common@0.0.3 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-catalog-common@1.0.25 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-search-common@1.2.13 + - @backstage/catalog-model@1.5.0 + +## @backstage/plugin-catalog-graph@0.4.7 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-compat-api@0.2.7 + - @backstage/core-plugin-api@1.9.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog-import@0.12.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/integration@1.13.0 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/integration-react@1.1.29 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-compat-api@0.2.7 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + +## @backstage/plugin-catalog-node@1.12.4 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.0 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog-react@1.12.2 + +### Patch Changes + +- 06c0956: Support i18n for catalog and catalog-react plugins +- 2030962: Make EntityOwnerPicker display metadata.title or spec.profile.displayName for mode=only-owners instead of metadata.name +- Updated dependencies + - @backstage/plugin-permission-common@0.8.0 + - @backstage/core-components@0.14.9 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/integration-react@1.1.29 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + +## @backstage/plugin-catalog-unprocessed-entities@0.2.6 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + +## @backstage/plugin-catalog-unprocessed-entities-common@0.0.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.0 + +## @backstage/plugin-config-schema@0.1.57 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-devtools@0.1.16 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/plugin-devtools-common@0.1.11 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/core-compat-api@0.2.7 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + +## @backstage/plugin-devtools-backend@0.3.8 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.0 + - @backstage/config-loader@1.8.1 + - @backstage/plugin-devtools-common@0.1.11 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-devtools-common@0.1.11 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-events-backend@0.3.9 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-events-node@0.3.8 + - @backstage/config@1.2.0 + +## @backstage/plugin-events-backend-module-aws-sqs@0.3.8 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-events-node@0.3.8 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-events-backend-module-azure@0.2.8 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-events-node@0.3.8 + +## @backstage/plugin-events-backend-module-bitbucket-cloud@0.2.8 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-events-node@0.3.8 + +## @backstage/plugin-events-backend-module-gerrit@0.2.8 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-events-node@0.3.8 + +## @backstage/plugin-events-backend-module-github@0.2.8 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-events-node@0.3.8 + - @backstage/config@1.2.0 + +## @backstage/plugin-events-backend-module-gitlab@0.2.8 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-events-node@0.3.8 + - @backstage/config@1.2.0 + +## @backstage/plugin-events-backend-test-utils@0.1.32 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.3.8 + +## @backstage/plugin-events-node@0.3.8 + +### Patch Changes + +- b05e1e1: Service factories exported by this package have been updated to use the new service factory format that doesn't use a callback. +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + +## @backstage/plugin-home@0.7.7 + +### Patch Changes + +- cc81579: Updated dependency `@rjsf/utils` to `5.18.5`. + Updated dependency `@rjsf/core` to `5.18.5`. + Updated dependency `@rjsf/material-ui` to `5.18.5`. + Updated dependency `@rjsf/validator-ajv8` to `5.18.5`. +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/core-app-api@1.14.0 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/plugin-home-react@0.1.15 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-compat-api@0.2.7 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + +## @backstage/plugin-home-react@0.1.15 + +### Patch Changes + +- cc81579: Updated dependency `@rjsf/utils` to `5.18.5`. + Updated dependency `@rjsf/core` to `5.18.5`. + Updated dependency `@rjsf/material-ui` to `5.18.5`. + Updated dependency `@rjsf/validator-ajv8` to `5.18.5`. +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/core-plugin-api@1.9.3 + +## @backstage/plugin-kubernetes@0.11.12 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/plugin-kubernetes-react@0.4.1 + - @backstage/plugin-kubernetes-common@0.8.1 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + +## @backstage/plugin-kubernetes-backend@0.18.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.0 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-kubernetes-node@0.1.16 + - @backstage/plugin-kubernetes-common@0.8.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration-aws-node@0.1.12 + - @backstage/types@1.1.1 + +## @backstage/plugin-kubernetes-cluster@0.0.13 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/plugin-kubernetes-react@0.4.1 + - @backstage/plugin-kubernetes-common@0.8.1 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + +## @backstage/plugin-kubernetes-common@0.8.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.0 + - @backstage/catalog-model@1.5.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-kubernetes-node@0.1.16 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-kubernetes-common@0.8.1 + - @backstage/catalog-model@1.5.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-kubernetes-react@0.4.1 + +### Patch Changes + +- e3cb6ab: Add a namespace label to RolloutDrawer +- 2414d86: Fix the `HTML` markup of the `FixDialog` component, `ul` and `li` are not allowed inside a `p` tag. +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/plugin-kubernetes-common@0.8.1 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-notifications@0.2.3 + +### Patch Changes + +- 3bf0697: The toolbar on the Notifications page is hidden when there are no listed notifications. +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/plugin-notifications-common@0.0.5 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/plugin-signals-react@0.0.4 + +## @backstage/plugin-notifications-backend@0.3.3 + +### Patch Changes + +- d7b8ca5: Added an option to filter notifications by topic +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-events-node@0.3.8 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/plugin-notifications-common@0.0.5 + - @backstage/plugin-notifications-node@0.2.3 + - @backstage/plugin-signals-node@0.1.8 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-notifications-backend-module-email@0.1.3 + +### Patch Changes + +- 4e4ef2b: Move notification processor filter parsing to common package +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-notifications-common@0.0.5 + - @backstage/plugin-notifications-node@0.2.3 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/integration-aws-node@0.1.12 + - @backstage/types@1.1.1 + +## @backstage/plugin-notifications-common@0.0.5 + +### Patch Changes + +- 4e4ef2b: Move notification processor filter parsing to common package +- Updated dependencies + - @backstage/config@1.2.0 + +## @backstage/plugin-notifications-node@0.2.3 + +### Patch Changes + +- 4e4ef2b: Move notification processor filter parsing to common package +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-notifications-common@0.0.5 + - @backstage/plugin-signals-node@0.1.8 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + +## @backstage/plugin-org@0.6.27 + +### Patch Changes + +- 5132d28: The `useGetEntities` hook could result in requests to `/api/catalog/entities` where the headers exceed the default maximum Node.js header size of 16KB. The hook logic has been adjusted to batch the requests. + +- c307ef4: Added `relationType` property to EntityMembersListCard component that allows for display users related to a group via some other relationship aside from `memberOf`. + + Also, as a side effect, the `relationsType` property has been deprecated in favor of a more accurately named `relationAggregation` property. + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/catalog-model@1.5.0 + - @backstage/core-compat-api@0.2.7 + - @backstage/core-plugin-api@1.9.3 + +## @backstage/plugin-org-react@0.1.26 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + +## @backstage/plugin-permission-backend@0.5.46 + +### Patch Changes + +- ed10fd2: The `PermissionPolicy` interface has been updated to align with the recent changes to the Backstage auth system. The second argument to the `handle` method is now of the new `PolicyQueryUser` type. This type maintains the old fields from the `BackstageIdentityResponse`, which are now all deprecated. Instead, two new fields have been added, which allows access to the same information: + + - `credentials` - A `BackstageCredentials` object, which is useful for making requests to other services on behalf of the user as part of evaluating the policy. This replaces the deprecated `token` field. See the [Auth Service documentation](https://backstage.io/docs/backend-system/core-services/auth#creating-request-tokens) for information about how to create a token using these credentials. + - `info` - A `BackstageUserInfo` object, which contains the same information as the deprecated `identity`, except for the `type` field that was redundant. + + Most existing policies can be updated by replacing the `BackstageIdentityResponse` type with `PolicyQueryUser`, which is exported from `@backstage/plugin-permission-node`, as well as replacing any occurrences of `user?.identity` with `user?.info`. + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.0 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-permission-backend-module-allow-all-policy@0.1.19 + +### Patch Changes + +- ed10fd2: Internal refactor to use new `PolicyQueryUser` type. +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.0 + - @backstage/plugin-auth-node@0.4.17 + +## @backstage/plugin-permission-react@0.4.24 + +### Patch Changes + +- 28b2cfb: Improve API Reference documentation +- Updated dependencies + - @backstage/plugin-permission-common@0.8.0 + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + +## @backstage/plugin-proxy-backend@0.5.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-backend-module-azure@0.1.14 + +### Patch Changes + +- 661b354: Fixed a bug where the `RepoUrlPicker` would still require the `owner` field for `azure` +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-scaffolder-backend-module-bitbucket@0.2.12 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.1.12 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.1.12 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.1.12 + +### Patch Changes + +- b5deed0: Add support for `autocomplete` handler to provide autocomplete options for `RepoUrlPicker` +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/plugin-bitbucket-cloud-common@0.2.21 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.1.12 + +### Patch Changes + +- 6a4ad4e: Instead of using hardcoded `targetBranch` now fetch the default branch from Bitbucket repository. + This prevents from errors when no `targetBranch` is provided and the default repository branch is different from `master`, for example: `main`. +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.23 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-scaffolder-backend-module-cookiecutter@0.2.46 + +### Patch Changes + +- 0ac124b: Updated configuration instructions +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-backend-module-gerrit@0.1.14 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-scaffolder-backend-module-gitea@0.1.12 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-scaffolder-backend-module-gitlab@0.4.4 + +### Patch Changes + +- 0ac124b: Updated configuration instructions +- 2fb0eb8: Added support for passing `variables` to `gitlab:pipeline:trigger` +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-scaffolder-backend-module-notifications@0.0.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/plugin-notifications-common@0.0.5 + - @backstage/plugin-notifications-node@0.2.3 + +## @backstage/plugin-scaffolder-backend-module-rails@0.4.39 + +### Patch Changes + +- 0ac124b: Updated configuration instructions +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-backend-module-sentry@0.1.30 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-scaffolder-backend-module-yeoman@0.3.6 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/plugin-scaffolder-node-test-utils@0.1.9 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-common@1.5.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.0 + - @backstage/catalog-model@1.5.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-node@0.4.8 + +### Patch Changes + +- 661b354: Fixed a bug where the `RepoUrlPicker` would still require the `owner` field for `azure` +- b5deed0: Add support for `autocomplete` extension point to provide additional `autocomplete` handlers +- 0b52438: Serialization of the scaffolder workspace into GCP bucket +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-common@1.5.4 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-node-test-utils@0.1.9 + +### Patch Changes + +- 54429b5: Filename and imports correction for mockActionContext.ts +- Updated dependencies + - @backstage/backend-test-utils@0.4.4 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/types@1.1.1 + +## @backstage/plugin-search@1.4.14 + +### Patch Changes + +- 1117aba: Update deps in search api extension to include fetch api +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/plugin-search-common@1.2.13 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/plugin-search-react@1.7.13 + - @backstage/core-compat-api@0.2.7 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + +## @backstage/plugin-search-backend@1.5.14 + +### Patch Changes + +- 343f656: The `AuthorizedSearchEngine` will now ignore the deprecated `token` option, and treat it as an unauthorized request. This will not have any effect in practice, since credentials are always provided by the router. +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-defaults@0.4.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.0 + - @backstage/backend-openapi-utils@0.1.15 + - @backstage/plugin-search-backend-node@1.2.27 + - @backstage/plugin-search-common@1.2.13 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-search-backend-module-catalog@0.1.28 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-search-backend-node@1.2.27 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-search-common@1.2.13 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-search-backend-module-elasticsearch@1.5.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-search-backend-node@1.2.27 + - @backstage/plugin-search-common@1.2.13 + - @backstage/config@1.2.0 + - @backstage/integration-aws-node@0.1.12 + +## @backstage/plugin-search-backend-module-explore@0.1.28 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-search-backend-node@1.2.27 + - @backstage/plugin-search-common@1.2.13 + - @backstage/config@1.2.0 + +## @backstage/plugin-search-backend-module-pg@0.5.32 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-app-api@0.8.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-search-backend-node@1.2.27 + - @backstage/plugin-search-common@1.2.13 + - @backstage/config@1.2.0 + +## @backstage/plugin-search-backend-module-stack-overflow-collator@0.1.15 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-search-backend-node@1.2.27 + - @backstage/plugin-search-common@1.2.13 + - @backstage/config@1.2.0 + +## @backstage/plugin-search-backend-module-techdocs@0.1.27 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-techdocs-node@1.12.8 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-search-backend-node@1.2.27 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-search-common@1.2.13 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + +## @backstage/plugin-search-backend-node@1.2.27 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-search-common@1.2.13 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-search-common@1.2.13 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-search-react@1.7.13 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/plugin-search-common@1.2.13 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + +## @backstage/plugin-signals@0.0.8 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/plugin-signals-react@0.0.4 + +## @backstage/plugin-signals-backend@0.1.8 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-events-node@0.3.8 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/plugin-signals-node@0.1.8 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-signals-node@0.1.8 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-events-node@0.3.8 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-techdocs@1.10.7 + +### Patch Changes + +- 8fc2622: Fixed an issue that was causing techdocs pages unnecessarily re-render on navigate. +- 6fa652c: Improve default sorting of docs table +- 605b691: Allow for searching TechDocs by entity title +- 60caa92: Fix double scrollbar bug in reader +- Updated dependencies + - @backstage/plugin-techdocs-react@1.2.6 + - @backstage/core-components@0.14.9 + - @backstage/integration@1.13.0 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/plugin-search-common@1.2.13 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/integration-react@1.1.29 + - @backstage/plugin-auth-react@0.1.4 + - @backstage/plugin-search-react@1.7.13 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-compat-api@0.2.7 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/theme@0.5.6 + +## @backstage/plugin-techdocs-addons-test-utils@1.0.35 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs@1.10.7 + - @backstage/plugin-techdocs-react@1.2.6 + - @backstage/core-app-api@1.14.0 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/plugin-catalog@1.21.1 + - @backstage/test-utils@1.5.8 + - @backstage/integration-react@1.1.29 + - @backstage/plugin-search-react@1.7.13 + - @backstage/core-plugin-api@1.9.3 + +## @backstage/plugin-techdocs-backend@1.10.9 + +### Patch Changes + +- 9ecf5fd: Adds extension point for publishers to the techdocs backend +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-techdocs-node@1.12.8 + - @backstage/integration@1.13.0 + - @backstage/plugin-search-backend-module-techdocs@0.1.27 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-techdocs-module-addons-contrib@1.1.12 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs-react@1.2.6 + - @backstage/core-components@0.14.9 + - @backstage/integration@1.13.0 + - @backstage/integration-react@1.1.29 + - @backstage/core-plugin-api@1.9.3 + +## @backstage/plugin-techdocs-node@1.12.8 + +### Patch Changes + +- 9ecf5fd: Adds extension point for publishers to the techdocs backend +- 4c4d077: Bumps default version of techdocs docker image to latest +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/integration@1.13.0 + - @backstage/plugin-search-common@1.2.13 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration-aws-node@0.1.12 + +## @backstage/plugin-techdocs-react@1.2.6 + +### Patch Changes + +- 8ac9ce5: Resolved the issue where changes in TechDoc add-ons, including the TextSize add-on, were not reapplying during navigation +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/version-bridge@1.0.8 + +## @backstage/plugin-user-settings@0.8.9 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/core-app-api@1.14.0 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/core-compat-api@0.2.7 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/plugin-signals-react@0.0.4 + - @backstage/plugin-user-settings-common@0.0.1 + +## @backstage/plugin-user-settings-backend@0.2.21 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/plugin-signals-node@0.1.8 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-user-settings-common@0.0.1 + +## example-app@0.2.99 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder@1.23.0 + - @backstage/plugin-techdocs@1.10.7 + - @backstage/plugin-techdocs-react@1.2.6 + - @backstage/core-components@0.14.9 + - @backstage/cli@0.26.11 + - @backstage/core-app-api@1.14.0 + - @backstage/frontend-app-api@0.7.3 + - @backstage/plugin-org@0.6.27 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/plugin-catalog@1.21.1 + - @backstage/plugin-notifications@0.2.3 + - @backstage/plugin-home@0.7.7 + - @backstage/plugin-scaffolder-react@1.10.0 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/plugin-search@1.4.14 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.12 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-search-common@1.2.13 + - @backstage/app-defaults@1.5.8 + - @backstage/integration-react@1.1.29 + - @backstage/plugin-api-docs@0.11.7 + - @backstage/plugin-auth-react@0.1.4 + - @backstage/plugin-catalog-graph@0.4.7 + - @backstage/plugin-catalog-import@0.12.1 + - @backstage/plugin-catalog-unprocessed-entities@0.2.6 + - @backstage/plugin-devtools@0.1.16 + - @backstage/plugin-kubernetes@0.11.12 + - @backstage/plugin-kubernetes-cluster@0.0.13 + - @backstage/plugin-search-react@1.7.13 + - @backstage/plugin-signals@0.0.8 + - @backstage/plugin-user-settings@0.8.9 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + +## example-app-next@0.0.13 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder@1.23.0 + - @backstage/plugin-techdocs@1.10.7 + - @backstage/plugin-techdocs-react@1.2.6 + - @backstage/core-components@0.14.9 + - @backstage/cli@0.26.11 + - @backstage/core-app-api@1.14.0 + - @backstage/frontend-app-api@0.7.3 + - @backstage/plugin-org@0.6.27 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/plugin-catalog@1.21.1 + - @backstage/plugin-notifications@0.2.3 + - @backstage/plugin-home@0.7.7 + - @backstage/plugin-scaffolder-react@1.10.0 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/plugin-search@1.4.14 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.12 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-search-common@1.2.13 + - @backstage/app-defaults@1.5.8 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/integration-react@1.1.29 + - @backstage/plugin-api-docs@0.11.7 + - @backstage/plugin-app-visualizer@0.1.8 + - @backstage/plugin-auth-react@0.1.4 + - @backstage/plugin-catalog-graph@0.4.7 + - @backstage/plugin-catalog-import@0.12.1 + - @backstage/plugin-catalog-unprocessed-entities@0.2.6 + - @backstage/plugin-kubernetes@0.11.12 + - @backstage/plugin-kubernetes-cluster@0.0.13 + - @backstage/plugin-search-react@1.7.13 + - @backstage/plugin-signals@0.0.8 + - @backstage/plugin-user-settings@0.8.9 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-compat-api@0.2.7 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + +## app-next-example-plugin@0.0.13 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/frontend-plugin-api@0.6.7 + +## example-backend@0.0.28 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-defaults@0.4.0 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.19 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-scaffolder-backend@1.23.0 + - @backstage/plugin-scaffolder-backend-module-github@0.4.0 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-backend@0.5.46 + - @backstage/plugin-permission-node@0.8.0 + - @backstage/plugin-techdocs-backend@1.10.9 + - @backstage/plugin-notifications-backend@0.3.3 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/plugin-search-backend@1.5.14 + - @backstage/plugin-catalog-backend@1.24.0 + - @backstage/plugin-app-backend@0.3.71 + - @backstage/plugin-auth-backend@0.22.9 + - @backstage/plugin-auth-backend-module-github-provider@0.1.19 + - @backstage/plugin-auth-backend-module-guest-provider@0.1.8 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.2.5 + - @backstage/plugin-catalog-backend-module-openapi@0.1.40 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.20 + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.9 + - @backstage/plugin-devtools-backend@0.3.8 + - @backstage/plugin-kubernetes-backend@0.18.3 + - @backstage/plugin-proxy-backend@0.5.3 + - @backstage/plugin-search-backend-module-catalog@0.1.28 + - @backstage/plugin-search-backend-module-explore@0.1.28 + - @backstage/plugin-search-backend-module-techdocs@0.1.27 + - @backstage/plugin-search-backend-node@1.2.27 + - @backstage/plugin-signals-backend@0.1.8 + - @backstage/catalog-model@1.5.0 + +## example-backend-legacy@0.2.100 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-scaffolder-backend@1.23.0 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-backend@0.5.46 + - @backstage/plugin-permission-node@0.8.0 + - @backstage/plugin-techdocs-backend@1.10.9 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.4.4 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.39 + - @backstage/integration@1.13.0 + - @backstage/plugin-events-node@0.3.8 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/plugin-search-backend@1.5.14 + - @backstage/plugin-catalog-backend@1.24.0 + - @backstage/plugin-app-backend@0.3.71 + - @backstage/plugin-auth-backend@0.22.9 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.20 + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.9 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-devtools-backend@0.3.8 + - @backstage/plugin-events-backend@0.3.9 + - @backstage/plugin-kubernetes-backend@0.18.3 + - @backstage/plugin-proxy-backend@0.5.3 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.23 + - @backstage/plugin-search-backend-module-catalog@0.1.28 + - @backstage/plugin-search-backend-module-elasticsearch@1.5.3 + - @backstage/plugin-search-backend-module-explore@0.1.28 + - @backstage/plugin-search-backend-module-pg@0.5.32 + - @backstage/plugin-search-backend-module-techdocs@0.1.27 + - @backstage/plugin-search-backend-node@1.2.27 + - @backstage/plugin-signals-backend@0.1.8 + - @backstage/plugin-signals-node@0.1.8 + - example-app@0.2.99 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + +## e2e-test@0.2.18 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.17 + - @backstage/cli-common@0.1.14 + - @backstage/errors@1.2.4 + +## techdocs-cli-embedded-app@0.2.98 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs@1.10.7 + - @backstage/plugin-techdocs-react@1.2.6 + - @backstage/core-components@0.14.9 + - @backstage/cli@0.26.11 + - @backstage/core-app-api@1.14.0 + - @backstage/plugin-catalog@1.21.1 + - @backstage/test-utils@1.5.8 + - @backstage/app-defaults@1.5.8 + - @backstage/integration-react@1.1.29 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + +## @internal/plugin-todo-list@1.0.29 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/core-plugin-api@1.9.3 + +## @internal/plugin-todo-list-backend@1.0.29 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/errors@1.2.4 + +## @internal/plugin-todo-list-common@1.0.20 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.0 diff --git a/package.json b/package.json index d3d042c2f5..07c9b2917b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "root", - "version": "1.29.0-next.2", + "version": "1.29.0", "private": true, "repository": { "type": "git", diff --git a/packages/app-defaults/CHANGELOG.md b/packages/app-defaults/CHANGELOG.md index 21fe959edb..a03034112c 100644 --- a/packages/app-defaults/CHANGELOG.md +++ b/packages/app-defaults/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/app-defaults +## 1.5.8 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/core-app-api@1.14.0 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + ## 1.5.8-next.2 ### Patch Changes diff --git a/packages/app-defaults/package.json b/packages/app-defaults/package.json index 4393164fcd..8997ba860f 100644 --- a/packages/app-defaults/package.json +++ b/packages/app-defaults/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/app-defaults", - "version": "1.5.8-next.2", + "version": "1.5.8", "description": "Provides the default wiring of a Backstage App", "backstage": { "role": "web-library" diff --git a/packages/app-next-example-plugin/CHANGELOG.md b/packages/app-next-example-plugin/CHANGELOG.md index 5456da237c..fb61388f22 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.13 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/frontend-plugin-api@0.6.7 + ## 0.0.13-next.1 ### Patch Changes diff --git a/packages/app-next-example-plugin/package.json b/packages/app-next-example-plugin/package.json index c3faec66d6..c48d5a92be 100644 --- a/packages/app-next-example-plugin/package.json +++ b/packages/app-next-example-plugin/package.json @@ -1,6 +1,6 @@ { "name": "app-next-example-plugin", - "version": "0.0.13-next.1", + "version": "0.0.13", "description": "Backstage internal example plugin", "backstage": { "role": "frontend-plugin", diff --git a/packages/app-next/CHANGELOG.md b/packages/app-next/CHANGELOG.md index 22d53e4c78..3bbf698ebd 100644 --- a/packages/app-next/CHANGELOG.md +++ b/packages/app-next/CHANGELOG.md @@ -1,5 +1,48 @@ # example-app-next +## 0.0.13 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder@1.23.0 + - @backstage/plugin-techdocs@1.10.7 + - @backstage/plugin-techdocs-react@1.2.6 + - @backstage/core-components@0.14.9 + - @backstage/cli@0.26.11 + - @backstage/core-app-api@1.14.0 + - @backstage/frontend-app-api@0.7.3 + - @backstage/plugin-org@0.6.27 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/plugin-catalog@1.21.1 + - @backstage/plugin-notifications@0.2.3 + - @backstage/plugin-home@0.7.7 + - @backstage/plugin-scaffolder-react@1.10.0 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/plugin-search@1.4.14 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.12 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-search-common@1.2.13 + - @backstage/app-defaults@1.5.8 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/integration-react@1.1.29 + - @backstage/plugin-api-docs@0.11.7 + - @backstage/plugin-app-visualizer@0.1.8 + - @backstage/plugin-auth-react@0.1.4 + - @backstage/plugin-catalog-graph@0.4.7 + - @backstage/plugin-catalog-import@0.12.1 + - @backstage/plugin-catalog-unprocessed-entities@0.2.6 + - @backstage/plugin-kubernetes@0.11.12 + - @backstage/plugin-kubernetes-cluster@0.0.13 + - @backstage/plugin-search-react@1.7.13 + - @backstage/plugin-signals@0.0.8 + - @backstage/plugin-user-settings@0.8.9 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-compat-api@0.2.7 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + ## 0.0.13-next.2 ### Patch Changes diff --git a/packages/app-next/package.json b/packages/app-next/package.json index c38eacfcd5..c0c19bc40c 100644 --- a/packages/app-next/package.json +++ b/packages/app-next/package.json @@ -1,6 +1,6 @@ { "name": "example-app-next", - "version": "0.0.13-next.2", + "version": "0.0.13", "private": true, "repository": { "type": "git", diff --git a/packages/app/CHANGELOG.md b/packages/app/CHANGELOG.md index 4977cc1d6d..a75cf24a07 100644 --- a/packages/app/CHANGELOG.md +++ b/packages/app/CHANGELOG.md @@ -1,5 +1,46 @@ # example-app +## 0.2.99 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder@1.23.0 + - @backstage/plugin-techdocs@1.10.7 + - @backstage/plugin-techdocs-react@1.2.6 + - @backstage/core-components@0.14.9 + - @backstage/cli@0.26.11 + - @backstage/core-app-api@1.14.0 + - @backstage/frontend-app-api@0.7.3 + - @backstage/plugin-org@0.6.27 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/plugin-catalog@1.21.1 + - @backstage/plugin-notifications@0.2.3 + - @backstage/plugin-home@0.7.7 + - @backstage/plugin-scaffolder-react@1.10.0 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/plugin-search@1.4.14 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.12 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-search-common@1.2.13 + - @backstage/app-defaults@1.5.8 + - @backstage/integration-react@1.1.29 + - @backstage/plugin-api-docs@0.11.7 + - @backstage/plugin-auth-react@0.1.4 + - @backstage/plugin-catalog-graph@0.4.7 + - @backstage/plugin-catalog-import@0.12.1 + - @backstage/plugin-catalog-unprocessed-entities@0.2.6 + - @backstage/plugin-devtools@0.1.16 + - @backstage/plugin-kubernetes@0.11.12 + - @backstage/plugin-kubernetes-cluster@0.0.13 + - @backstage/plugin-search-react@1.7.13 + - @backstage/plugin-signals@0.0.8 + - @backstage/plugin-user-settings@0.8.9 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + ## 0.2.99-next.2 ### Patch Changes diff --git a/packages/app/package.json b/packages/app/package.json index f15dbac9db..29cfbf0357 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,6 +1,6 @@ { "name": "example-app", - "version": "0.2.99-next.2", + "version": "0.2.99", "backstage": { "role": "frontend" }, diff --git a/packages/backend-app-api/CHANGELOG.md b/packages/backend-app-api/CHANGELOG.md index 4456d8438b..70a163ee34 100644 --- a/packages/backend-app-api/CHANGELOG.md +++ b/packages/backend-app-api/CHANGELOG.md @@ -1,5 +1,33 @@ # @backstage/backend-app-api +## 0.8.0 + +### Minor Changes + +- 1cb84d7: **BREAKING**: Removed the depreacted `getPath` option from `httpRouterServiceFactory`, as well as the `HttpRouterFactoryOptions` type. +- f691c9b: **BREAKING**: Removed the ability to pass callback-form service factories through the `defaultServiceFactories` option of `createSpecializedBackend`. This is an immediate breaking change as usage of this function is expected to be very rare. + +### Patch Changes + +- 2f99178: The `ServiceFactoryTest.get` method was deprecated and the `ServiceFactoryTest.getSubject` should be used instead. The `getSubject` method has the same behavior, but has a better method name to indicate that the service instance returned is the subject currently being tested. +- b05e1e1: Service factories exported by this package have been updated to use the new service factory format that doesn't use a callback. +- 617a7d2: Internal refactor that avoids the use of service factory options. +- b60db08: Fixing exporting of classes properly from new packages +- 18b96b1: The ability to install backend features in callback form (`() => BackendFeature`) has been deprecated. This typically means that you need to update the installed features to use the latest version of `@backstage/backend-plugin-api`. If the feature is from a third-party package, please reach out to the package maintainer to update it. +- a63c4b6: Fixing issue with `MiddlewareFactory` deprecation wrapping +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/cli-node@0.2.7 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-permission-node@0.8.0 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/config-loader@1.8.1 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 0.7.10-next.1 ### Patch Changes diff --git a/packages/backend-app-api/package.json b/packages/backend-app-api/package.json index 4d3ffd874f..8bd156c3a4 100644 --- a/packages/backend-app-api/package.json +++ b/packages/backend-app-api/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/backend-app-api", - "version": "0.7.10-next.1", + "version": "0.8.0", "description": "Core API used by Backstage backend apps", "backstage": { "role": "node-library" diff --git a/packages/backend-common/CHANGELOG.md b/packages/backend-common/CHANGELOG.md index d144d461b8..6d3218e0ed 100644 --- a/packages/backend-common/CHANGELOG.md +++ b/packages/backend-common/CHANGELOG.md @@ -1,5 +1,26 @@ # @backstage/backend-common +## 0.23.3 + +### Patch Changes + +- 8c09c97: Deprecate legacy status check factory, handler and types. +- d228862: Update default backend plugin created by the cli to use non-deprecated error handling middleware +- c964a3d: Add dependencies that are needed by cross-imports from backend-defaults +- b60db08: Fixing exporting of classes properly from new packages +- b9ed1bb: bumped better-sqlite3 from ^9.0.0 to ^11.0.0 +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/integration@1.13.0 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/config-loader@1.8.1 + - @backstage/backend-dev-utils@0.1.4 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration-aws-node@0.1.12 + - @backstage/types@1.1.1 + ## 0.23.3-next.1 ### Patch Changes diff --git a/packages/backend-common/package.json b/packages/backend-common/package.json index f23f0d2ce9..553c800ea5 100644 --- a/packages/backend-common/package.json +++ b/packages/backend-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/backend-common", - "version": "0.23.3-next.1", + "version": "0.23.3", "description": "Common functionality library for Backstage backends", "backstage": { "role": "node-library" diff --git a/packages/backend-defaults/CHANGELOG.md b/packages/backend-defaults/CHANGELOG.md index a9b20bfbea..7d2ad7d6b7 100644 --- a/packages/backend-defaults/CHANGELOG.md +++ b/packages/backend-defaults/CHANGELOG.md @@ -1,5 +1,37 @@ # @backstage/backend-defaults +## 0.4.0 + +### Minor Changes + +- 1cb84d7: **BREAKING**: Removed the depreacted `getPath` option from `httpRouterServiceFactory`, as well as the `HttpRouterFactoryOptions` type. + +### Patch Changes + +- 53ced70: Added a new Root Health Service which adds new endpoints for health checks. +- 2f99178: The `ServiceFactoryTest.get` method was deprecated and the `ServiceFactoryTest.getSubject` should be used instead. The `getSubject` method has the same behavior, but has a better method name to indicate that the service instance returned is the subject currently being tested. +- 083eaf9: Fix bug where ISO durations could no longer be used for schedules +- b05e1e1: Service factories exported by this package have been updated to use the new service factory format that doesn't use a callback. +- 419f387: Refactor of `rootHttpRouterServiceFactory` to allow it to be constructed with options, but without declaring options via `createServiceFactory`. +- cb14a05: Repack the package to fix issues with typescript with named exports +- b9ed1bb: bumped better-sqlite3 from ^9.0.0 to ^11.0.0 +- e28af58: Refactor of `rootConfigServiceFactory` to allow it to be constructed with options, but without declaring options via `createServiceFactory`. +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-app-api@0.8.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-permission-node@0.8.0 + - @backstage/integration@1.13.0 + - @backstage/plugin-events-node@0.3.8 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/config-loader@1.8.1 + - @backstage/backend-dev-utils@0.1.4 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration-aws-node@0.1.12 + - @backstage/types@1.1.1 + ## 0.3.4-next.1 ### Patch Changes diff --git a/packages/backend-defaults/package.json b/packages/backend-defaults/package.json index 0606d942ff..87da6e0017 100644 --- a/packages/backend-defaults/package.json +++ b/packages/backend-defaults/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/backend-defaults", - "version": "0.3.4-next.1", + "version": "0.4.0", "description": "Backend defaults used by Backstage backend apps", "backstage": { "role": "node-library" diff --git a/packages/backend-dynamic-feature-service/CHANGELOG.md b/packages/backend-dynamic-feature-service/CHANGELOG.md index 02f47ef7b4..3003a8e177 100644 --- a/packages/backend-dynamic-feature-service/CHANGELOG.md +++ b/packages/backend-dynamic-feature-service/CHANGELOG.md @@ -1,5 +1,32 @@ # @backstage/backend-dynamic-feature-service +## 0.2.15 + +### Patch Changes + +- b05e1e1: Service factories exported by this package have been updated to use the new service factory format that doesn't use a callback. +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-app-api@0.8.0 + - @backstage/backend-common@0.23.3 + - @backstage/cli-node@0.2.7 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/plugin-events-node@0.3.8 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/plugin-catalog-backend@1.24.0 + - @backstage/plugin-app-node@0.1.22 + - @backstage/plugin-events-backend@0.3.9 + - @backstage/plugin-search-backend-node@1.2.27 + - @backstage/config-loader@1.8.1 + - @backstage/plugin-search-common@1.2.13 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 0.2.15-next.1 ### Patch Changes diff --git a/packages/backend-dynamic-feature-service/package.json b/packages/backend-dynamic-feature-service/package.json index 3e3e566879..0d05b97bd9 100644 --- a/packages/backend-dynamic-feature-service/package.json +++ b/packages/backend-dynamic-feature-service/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-dynamic-feature-service", "description": "Backstage dynamic feature service", - "version": "0.2.15-next.1", + "version": "0.2.15", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/packages/backend-legacy/CHANGELOG.md b/packages/backend-legacy/CHANGELOG.md index 35ed7a6c93..04538ca02e 100644 --- a/packages/backend-legacy/CHANGELOG.md +++ b/packages/backend-legacy/CHANGELOG.md @@ -1,5 +1,47 @@ # example-backend-legacy +## 0.2.100 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-scaffolder-backend@1.23.0 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-backend@0.5.46 + - @backstage/plugin-permission-node@0.8.0 + - @backstage/plugin-techdocs-backend@1.10.9 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.4.4 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.39 + - @backstage/integration@1.13.0 + - @backstage/plugin-events-node@0.3.8 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/plugin-search-backend@1.5.14 + - @backstage/plugin-catalog-backend@1.24.0 + - @backstage/plugin-app-backend@0.3.71 + - @backstage/plugin-auth-backend@0.22.9 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.20 + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.9 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-devtools-backend@0.3.8 + - @backstage/plugin-events-backend@0.3.9 + - @backstage/plugin-kubernetes-backend@0.18.3 + - @backstage/plugin-proxy-backend@0.5.3 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.23 + - @backstage/plugin-search-backend-module-catalog@0.1.28 + - @backstage/plugin-search-backend-module-elasticsearch@1.5.3 + - @backstage/plugin-search-backend-module-explore@0.1.28 + - @backstage/plugin-search-backend-module-pg@0.5.32 + - @backstage/plugin-search-backend-module-techdocs@0.1.27 + - @backstage/plugin-search-backend-node@1.2.27 + - @backstage/plugin-signals-backend@0.1.8 + - @backstage/plugin-signals-node@0.1.8 + - example-app@0.2.99 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + ## 0.2.100-next.2 ### Patch Changes diff --git a/packages/backend-legacy/package.json b/packages/backend-legacy/package.json index a537361746..5861719455 100644 --- a/packages/backend-legacy/package.json +++ b/packages/backend-legacy/package.json @@ -1,6 +1,6 @@ { "name": "example-backend-legacy", - "version": "0.2.100-next.2", + "version": "0.2.100", "backstage": { "role": "backend" }, diff --git a/packages/backend-openapi-utils/CHANGELOG.md b/packages/backend-openapi-utils/CHANGELOG.md index 43a57f7d8c..540a239ad6 100644 --- a/packages/backend-openapi-utils/CHANGELOG.md +++ b/packages/backend-openapi-utils/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/backend-openapi-utils +## 0.1.15 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/errors@1.2.4 + ## 0.1.15-next.1 ### Patch Changes diff --git a/packages/backend-openapi-utils/package.json b/packages/backend-openapi-utils/package.json index f35863c6e3..3059af5ffe 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.15-next.1", + "version": "0.1.15", "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 cb341b218e..3f47354561 100644 --- a/packages/backend-plugin-api/CHANGELOG.md +++ b/packages/backend-plugin-api/CHANGELOG.md @@ -1,5 +1,103 @@ # @backstage/backend-plugin-api +## 0.7.0 + +### Minor Changes + +- 36f91e8: **BREAKING**: The `PermissionsService` no longer supports passing the deprecated `token` option, and the request options are now required. + +### Patch Changes + +- 53ced70: Added a new Root Health Service which adds new endpoints for health checks. +- 083eaf9: Fix bug where ISO durations could no longer be used for schedules +- 062c01c: Deprecated the ability to define options for service factories through `createServiceFactory`. In the future all service factories will return a plain `ServiceFactory` object, rather than allowing users to pass options to the factory. To allow for customization of a service implementation one can instead export one or a few building blocks that allows for simple re-implementation of the service instead. + + For example, instead of: + + ```ts + export const fooServiceFactory = createServiceFactory<FooService>( + (options?: { bar: string }) => ({ + service: fooServiceRef, + deps: { logger: coreServices.logger }, + factory({ logger }) { + return { + // Implementation of the foo service using the `bar` option. + }; + }, + }), + ); + ``` + + We instead encourage service implementations to provide an easy to use API for re-implementing the service for advanced use-cases: + + ```ts + /** @public */ + export class DefaultFooService implements FooService { + static create(options: { bar: string; logger: LoggerService }) { + return new DefaultFooService(options.logger, options.bar ?? 'default'); + } + + private constructor( + private readonly logger: string, + private readonly bar: string, + ) {} + + // The rest of the implementation + } + ``` + + A user that wishes to customize the service can then easily do so by defining their own factory: + + ```ts + export const customFooServiceFactory = createServiceFactory<FooService>({ + service: fooServiceRef, + deps: { logger: coreServices.logger }, + factory({ logger }) { + return DefaultFooService.create({ logger, bar: 'baz' }); + }, + }); + ``` + + This is of course more verbose than the previous solution where the factory could be customized through `fooServiceFactory({ bar: 'baz' })`, but this is a simplified which in practice should be using static configuration instead. + + In cases where the old options patterns significantly improves the usability of the service factory, the old pattern can still be implemented like this: + + ```ts + const fooServiceFactoryWithOptions = (options?: { bar: string }) => + createServiceFactory<FooService>({ + service: fooServiceRef, + deps: { logger: coreServices.logger }, + factory({ logger }) { + return { + // Implementation of the foo service using the `bar` option. + }; + }, + }); + + export const fooServiceFactory = Object.assign( + fooServiceFactoryWithOptions, + fooServiceFactoryWithOptions(), + ); + ``` + + This change is being made because the ability to define an options callback encourages bad design of services factories. When possible, a service should be configurable through static configuration, and the existence of options may discourage that. More importantly though, the existing options do not work well with the dependency injection system of services, which is a problem for callbacks an other more advanced options. This lead to a bad pattern where only a few explicit dependencies where made available in callbacks, rather than providing an API that allowed simple re-implementation of the service with full access to dependency injection. + + A separate benefit of this change is that it simplifies the TypeScript types in a way that allows TypeScript to provide a much better error message when a service factory doesn't properly implement the service interface. + +- fe47a3e: All service config types were renamed to option types in order to standardize frontend and backend `create*` function signatures: + + - The `ServiceRefConfig` type was renamed to`ServiceRefOptions`; + - The `RootServiceFactoryConfig` type was renamed to `RootServiceFactoryOptions`; + - The `PluginServiceFactoryConfig` type was renamed to `PluginServiceFactoryOptions` + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 0.6.22-next.1 ### Patch Changes diff --git a/packages/backend-plugin-api/package.json b/packages/backend-plugin-api/package.json index 631141a57f..52fbfb5806 100644 --- a/packages/backend-plugin-api/package.json +++ b/packages/backend-plugin-api/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/backend-plugin-api", - "version": "0.6.22-next.1", + "version": "0.7.0", "description": "Core API used by Backstage backend plugins", "backstage": { "role": "node-library" diff --git a/packages/backend-tasks/CHANGELOG.md b/packages/backend-tasks/CHANGELOG.md index 590d824635..fef4fd56a9 100644 --- a/packages/backend-tasks/CHANGELOG.md +++ b/packages/backend-tasks/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/backend-tasks +## 0.5.27 + +### Patch Changes + +- 083eaf9: Fix bug where ISO durations could no longer be used for schedules +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 0.5.27-next.1 ### Patch Changes diff --git a/packages/backend-tasks/package.json b/packages/backend-tasks/package.json index df10190443..998e1d0650 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.27-next.1", + "version": "0.5.27", "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 9f3d84a906..9bee6fae55 100644 --- a/packages/backend-test-utils/CHANGELOG.md +++ b/packages/backend-test-utils/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/backend-test-utils +## 0.4.4 + +### Patch Changes + +- 2f99178: The `ServiceFactoryTest.get` method was deprecated and the `ServiceFactoryTest.getSubject` should be used instead. The `getSubject` method has the same behavior, but has a better method name to indicate that the service instance returned is the subject currently being tested. +- edf5cc3: The function `isDockerDisabledForTests` is deprecated and will no longer be exported in the near future as it should only be used internally. +- b05e1e1: Service factories exported by this package have been updated to use the new service factory format that doesn't use a callback. +- fce7887: Added mock for the Root Health Service in `mockServices`. +- 906c817: Updated `startTestBackend` and `ServiceFactoryTester` to only accept plain service factory or backend feature objects, no longer supporting the callback form. This lines up with the changes to `@backstage/backend-plugin-api` and should not require any code changes. +- 95a3a0b: Rename frontend and backend `setupRequestMockHandlers` methods to `registerMswTestHooks`. +- b9ed1bb: bumped better-sqlite3 from ^9.0.0 to ^11.0.0 +- 98ccf00: Internal refactor of `mockServices.httpAuth.factory` to allow it to still be constructed with options, but without declaring options via `createServiceFactory`. +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-defaults@0.4.0 + - @backstage/backend-app-api@0.8.0 + - @backstage/plugin-events-node@0.3.8 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 0.4.4-next.1 ### Patch Changes diff --git a/packages/backend-test-utils/package.json b/packages/backend-test-utils/package.json index e975dc01d9..875949c0a0 100644 --- a/packages/backend-test-utils/package.json +++ b/packages/backend-test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/backend-test-utils", - "version": "0.4.4-next.1", + "version": "0.4.4", "description": "Test helpers library for Backstage backends", "backstage": { "role": "node-library" diff --git a/packages/backend/CHANGELOG.md b/packages/backend/CHANGELOG.md index 4ceb786f2a..854993119c 100644 --- a/packages/backend/CHANGELOG.md +++ b/packages/backend/CHANGELOG.md @@ -1,5 +1,42 @@ # example-backend +## 0.0.28 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-defaults@0.4.0 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.19 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-scaffolder-backend@1.23.0 + - @backstage/plugin-scaffolder-backend-module-github@0.4.0 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-backend@0.5.46 + - @backstage/plugin-permission-node@0.8.0 + - @backstage/plugin-techdocs-backend@1.10.9 + - @backstage/plugin-notifications-backend@0.3.3 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/plugin-search-backend@1.5.14 + - @backstage/plugin-catalog-backend@1.24.0 + - @backstage/plugin-app-backend@0.3.71 + - @backstage/plugin-auth-backend@0.22.9 + - @backstage/plugin-auth-backend-module-github-provider@0.1.19 + - @backstage/plugin-auth-backend-module-guest-provider@0.1.8 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.2.5 + - @backstage/plugin-catalog-backend-module-openapi@0.1.40 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.20 + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.9 + - @backstage/plugin-devtools-backend@0.3.8 + - @backstage/plugin-kubernetes-backend@0.18.3 + - @backstage/plugin-proxy-backend@0.5.3 + - @backstage/plugin-search-backend-module-catalog@0.1.28 + - @backstage/plugin-search-backend-module-explore@0.1.28 + - @backstage/plugin-search-backend-module-techdocs@0.1.27 + - @backstage/plugin-search-backend-node@1.2.27 + - @backstage/plugin-signals-backend@0.1.8 + - @backstage/catalog-model@1.5.0 + ## 0.0.28-next.2 ### Patch Changes diff --git a/packages/backend/package.json b/packages/backend/package.json index 459db3c317..ae47716326 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -1,6 +1,6 @@ { "name": "example-backend", - "version": "0.0.28-next.2", + "version": "0.0.28", "main": "dist/index.cjs.js", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/packages/cli-node/CHANGELOG.md b/packages/cli-node/CHANGELOG.md index dcf9073277..21995e4812 100644 --- a/packages/cli-node/CHANGELOG.md +++ b/packages/cli-node/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/cli-node +## 0.2.7 + +### Patch Changes + +- 133464c: Added internal metadata for the new experimental `frontend-dynamic-container` role. +- Updated dependencies + - @backstage/cli-common@0.1.14 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 0.2.6 ### Patch Changes diff --git a/packages/cli-node/package.json b/packages/cli-node/package.json index 56cf50a096..c727918510 100644 --- a/packages/cli-node/package.json +++ b/packages/cli-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/cli-node", - "version": "0.2.6", + "version": "0.2.7", "description": "Node.js library for Backstage CLIs", "backstage": { "role": "node-library" diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index a2fae6e3c0..c062324abb 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -1,5 +1,33 @@ # @backstage/cli +## 0.26.11 + +### Patch Changes + +- 133464c: Added experimental support for dynamic frontend plugin builds, enabled via setting `EXPERIMENTAL_MODULE_FEDERATION` for the app build, and using the `frontend-dynamic-container` package role to create a container. Both of these are experimental and will change in the future. +- e2e320c: - remove unused dependencies `winston` and `yn` from the template of backend plugins; + - update `msw` to version `2.3.1` in the template of backend plugins; + starting with v1 and switching later to v2 is tedious and not straight forward; it's easier to start with v2; +- 0540c5a: Updated the scaffolding output message for `plugin-common` in `backstage-cli`. Now, when executing `backstage-cli new` to create a new `plugin-common` package, the output message accurately reflects the action by displaying `Creating common plugin package...` instead of the previous, less accurate `Creating backend plugin...`. +- 7652db4: Only bootstrap global-agent if it's actually being used +- f0c0039: Fix issue with CLI that was preventing upgrading from 1.28 +- d228862: Update default backend plugin created by the cli to use non-deprecated error handling middleware +- da90cce: Updated dependency `esbuild` to `^0.21.0`. +- a60d73b: Fix a few minor issues with the backend template that were causing failing linting checks in the main repo. +- 0510d98: Subpath export `package.json` should be of a unique name to avoid typescript resolution issues +- 4baac0c: The `backendPlugin` and `backendModule` factory now includes a step for automatically adding the new backend plugin/module to the `index.ts` file of the backend. +- Updated dependencies + - @backstage/cli-node@0.2.7 + - @backstage/integration@1.13.0 + - @backstage/config-loader@1.8.1 + - @backstage/catalog-model@1.5.0 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/eslint-plugin@0.1.8 + - @backstage/release-manifests@0.0.11 + - @backstage/types@1.1.1 + ## 0.26.11-next.1 ### Patch Changes diff --git a/packages/cli/package.json b/packages/cli/package.json index 97c15b16f2..ccc4818331 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/cli", - "version": "0.26.11-next.1", + "version": "0.26.11", "description": "CLI for developing Backstage plugins and apps", "backstage": { "role": "cli" diff --git a/packages/core-app-api/CHANGELOG.md b/packages/core-app-api/CHANGELOG.md index d80ed2fdcb..ff09befd63 100644 --- a/packages/core-app-api/CHANGELOG.md +++ b/packages/core-app-api/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/core-app-api +## 1.14.0 + +### Minor Changes + +- d3c39fc: Allow for the disabling of external routes through config, which was rendered impossible after the introduction of default targets. + + ```yaml + app: + routes: + bindings: + # This has the effect of removing the button for registering new + # catalog entities in the scaffolder template list view + scaffolder.registerComponent: false + ``` + +### Patch Changes + +- db2e2d5: Updated config schema to support app.routes.bindings +- Updated dependencies + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + ## 1.13.1-next.1 ### Patch Changes diff --git a/packages/core-app-api/package.json b/packages/core-app-api/package.json index 35e32f9726..5f297b16d5 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.13.1-next.1", + "version": "1.14.0", "publishConfig": { "access": "public" }, diff --git a/packages/core-compat-api/CHANGELOG.md b/packages/core-compat-api/CHANGELOG.md index 3ad2bd654e..829c6f41ff 100644 --- a/packages/core-compat-api/CHANGELOG.md +++ b/packages/core-compat-api/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/core-compat-api +## 0.2.7 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/core-plugin-api@1.9.3 + - @backstage/version-bridge@1.0.8 + ## 0.2.7-next.1 ### Patch Changes diff --git a/packages/core-compat-api/package.json b/packages/core-compat-api/package.json index 0f164a6187..bbf131c761 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.2.7-next.1", + "version": "0.2.7", "backstage": { "role": "web-library" }, diff --git a/packages/core-components/CHANGELOG.md b/packages/core-components/CHANGELOG.md index 163406bbca..3d46390597 100644 --- a/packages/core-components/CHANGELOG.md +++ b/packages/core-components/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/core-components +## 0.14.9 + +### Patch Changes + +- d4ffdbb: Fixed bug where `<Select>` component with empty string as placeholder gave an error +- 99d672d: Modified the `Select` component to take in a `data-testid` parameter ensuring backwards compatibility with default value corresponding to previously hardcoded `data-testid` of "select". +- Updated dependencies + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/theme@0.5.6 + - @backstage/version-bridge@1.0.8 + ## 0.14.9-next.1 ### Patch Changes diff --git a/packages/core-components/package.json b/packages/core-components/package.json index 21c4a19dbf..55faac9dba 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.14.9-next.1", + "version": "0.14.9", "publishConfig": { "access": "public" }, diff --git a/packages/create-app/CHANGELOG.md b/packages/create-app/CHANGELOG.md index 708a9b33f8..d7ad8037e6 100644 --- a/packages/create-app/CHANGELOG.md +++ b/packages/create-app/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/create-app +## 0.5.17 + +### Patch Changes + +- 780d994: Added `MyGroupsSidebarItem` to the sidebar in the `create-app` template +- f03d12a: Bumped create-app version. +- e90a2cd: Added the Catalog logs module to the `create-app` template +- 3ac2a6a: Added the Postgres Search Engine to the `create-app` template +- Updated dependencies + - @backstage/cli-common@0.1.14 + ## 0.5.17-next.2 ### Patch Changes diff --git a/packages/create-app/package.json b/packages/create-app/package.json index c1ca92f87b..7d33d03a4b 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.17-next.2", + "version": "0.5.17", "publishConfig": { "access": "public" }, diff --git a/packages/dev-utils/CHANGELOG.md b/packages/dev-utils/CHANGELOG.md index ee9f56dec7..f46a65827a 100644 --- a/packages/dev-utils/CHANGELOG.md +++ b/packages/dev-utils/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/dev-utils +## 1.0.35 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/core-app-api@1.14.0 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/app-defaults@1.5.8 + - @backstage/integration-react@1.1.29 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + ## 1.0.35-next.2 ### Patch Changes diff --git a/packages/dev-utils/package.json b/packages/dev-utils/package.json index 50220c36e1..0902d7c322 100644 --- a/packages/dev-utils/package.json +++ b/packages/dev-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/dev-utils", - "version": "1.0.35-next.2", + "version": "1.0.35", "description": "Utilities for developing Backstage plugins.", "backstage": { "role": "web-library" diff --git a/packages/e2e-test/CHANGELOG.md b/packages/e2e-test/CHANGELOG.md index 5144d9fd86..ad76bf8b75 100644 --- a/packages/e2e-test/CHANGELOG.md +++ b/packages/e2e-test/CHANGELOG.md @@ -1,5 +1,14 @@ # e2e-test +## 0.2.18 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.17 + - @backstage/cli-common@0.1.14 + - @backstage/errors@1.2.4 + ## 0.2.18-next.2 ### Patch Changes diff --git a/packages/e2e-test/package.json b/packages/e2e-test/package.json index 1d65314e83..7fa0349a46 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.18-next.2", + "version": "0.2.18", "private": true, "backstage": { "role": "cli" diff --git a/packages/frontend-app-api/CHANGELOG.md b/packages/frontend-app-api/CHANGELOG.md index dde282a831..7203efb8d8 100644 --- a/packages/frontend-app-api/CHANGELOG.md +++ b/packages/frontend-app-api/CHANGELOG.md @@ -1,5 +1,31 @@ # @backstage/frontend-app-api +## 0.7.3 + +### Patch Changes + +- d3c39fc: Allow for the disabling of external routes through config, which was rendered impossible after the introduction of default targets. + + ```yaml + app: + routes: + bindings: + # This has the effect of removing the button for registering new + # catalog entities in the scaffolder template list view + scaffolder.registerComponent: false + ``` + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/core-app-api@1.14.0 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + ## 0.7.3-next.2 ### Patch Changes diff --git a/packages/frontend-app-api/package.json b/packages/frontend-app-api/package.json index 68c2fd8fab..a55284ff68 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.7.3-next.2", + "version": "0.7.3", "backstage": { "role": "web-library" }, diff --git a/packages/frontend-plugin-api/CHANGELOG.md b/packages/frontend-plugin-api/CHANGELOG.md index dda46968a4..4c0e6fe9f8 100644 --- a/packages/frontend-plugin-api/CHANGELOG.md +++ b/packages/frontend-plugin-api/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/frontend-plugin-api +## 0.6.7 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/core-plugin-api@1.9.3 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + ## 0.6.7-next.1 ### Patch Changes diff --git a/packages/frontend-plugin-api/package.json b/packages/frontend-plugin-api/package.json index b62fe36059..f02f3fdedf 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.6.7-next.1", + "version": "0.6.7", "backstage": { "role": "web-library" }, diff --git a/packages/frontend-test-utils/CHANGELOG.md b/packages/frontend-test-utils/CHANGELOG.md index 34d9b28143..de21194f4e 100644 --- a/packages/frontend-test-utils/CHANGELOG.md +++ b/packages/frontend-test-utils/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/frontend-test-utils +## 0.1.10 + +### Patch Changes + +- 95a3a0b: Rename frontend and backend `setupRequestMockHandlers` methods to `registerMswTestHooks`. +- Updated dependencies + - @backstage/frontend-app-api@0.7.3 + - @backstage/test-utils@1.5.8 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/types@1.1.1 + ## 0.1.10-next.2 ### Patch Changes diff --git a/packages/frontend-test-utils/package.json b/packages/frontend-test-utils/package.json index 2a366fa152..0816a25443 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.10-next.2", + "version": "0.1.10", "backstage": { "role": "web-library" }, diff --git a/packages/integration-react/CHANGELOG.md b/packages/integration-react/CHANGELOG.md index e5e5759f1e..ed54a92f5c 100644 --- a/packages/integration-react/CHANGELOG.md +++ b/packages/integration-react/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/integration-react +## 1.1.29 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.13.0 + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + ## 1.1.29-next.0 ### Patch Changes diff --git a/packages/integration-react/package.json b/packages/integration-react/package.json index 375f99fba6..b04b603327 100644 --- a/packages/integration-react/package.json +++ b/packages/integration-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/integration-react", - "version": "1.1.29-next.0", + "version": "1.1.29", "description": "Frontend package for managing integrations towards external systems", "backstage": { "role": "web-library" diff --git a/packages/integration/CHANGELOG.md b/packages/integration/CHANGELOG.md index a76d031e35..3fb630ccfc 100644 --- a/packages/integration/CHANGELOG.md +++ b/packages/integration/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/integration +## 1.13.0 + +### Minor Changes + +- b5deed0: Add support for `token` for `bitbucketCloud` integration + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 1.13.0-next.0 ### Minor Changes diff --git a/packages/integration/package.json b/packages/integration/package.json index 6f4743fd13..810150cf2d 100644 --- a/packages/integration/package.json +++ b/packages/integration/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/integration", - "version": "1.13.0-next.0", + "version": "1.13.0", "description": "Helpers for managing integrations towards external systems", "backstage": { "role": "common-library" diff --git a/packages/repo-tools/CHANGELOG.md b/packages/repo-tools/CHANGELOG.md index daa0684e41..18c696a51c 100644 --- a/packages/repo-tools/CHANGELOG.md +++ b/packages/repo-tools/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/repo-tools +## 0.9.4 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/cli-node@0.2.7 + - @backstage/config-loader@1.8.1 + - @backstage/catalog-model@1.5.0 + - @backstage/cli-common@0.1.14 + - @backstage/errors@1.2.4 + ## 0.9.4-next.1 ### Patch Changes diff --git a/packages/repo-tools/package.json b/packages/repo-tools/package.json index cd1658b417..9f3a177b4f 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.9.4-next.1", + "version": "0.9.4", "publishConfig": { "access": "public" }, diff --git a/packages/techdocs-cli-embedded-app/CHANGELOG.md b/packages/techdocs-cli-embedded-app/CHANGELOG.md index 123e82edf7..6c8cc3f4ac 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.98 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs@1.10.7 + - @backstage/plugin-techdocs-react@1.2.6 + - @backstage/core-components@0.14.9 + - @backstage/cli@0.26.11 + - @backstage/core-app-api@1.14.0 + - @backstage/plugin-catalog@1.21.1 + - @backstage/test-utils@1.5.8 + - @backstage/app-defaults@1.5.8 + - @backstage/integration-react@1.1.29 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + ## 0.2.98-next.2 ### Patch Changes diff --git a/packages/techdocs-cli-embedded-app/package.json b/packages/techdocs-cli-embedded-app/package.json index 979d18620f..6c395636b1 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.98-next.2", + "version": "0.2.98", "private": true, "backstage": { "role": "frontend" diff --git a/packages/techdocs-cli/CHANGELOG.md b/packages/techdocs-cli/CHANGELOG.md index 0097d35ef6..34f612932c 100644 --- a/packages/techdocs-cli/CHANGELOG.md +++ b/packages/techdocs-cli/CHANGELOG.md @@ -1,5 +1,17 @@ # @techdocs/cli +## 1.8.16 + +### Patch Changes + +- c964a3d: Import discovery from backend-defaults instead of backend-common +- Updated dependencies + - @backstage/backend-defaults@0.4.0 + - @backstage/plugin-techdocs-node@1.12.8 + - @backstage/catalog-model@1.5.0 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + ## 1.8.16-next.1 ### Patch Changes diff --git a/packages/techdocs-cli/package.json b/packages/techdocs-cli/package.json index d947af0ee8..a44213abb7 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.16-next.1", + "version": "1.8.16", "publishConfig": { "access": "public" }, diff --git a/packages/test-utils/CHANGELOG.md b/packages/test-utils/CHANGELOG.md index 6a038fd0d8..3f40af6299 100644 --- a/packages/test-utils/CHANGELOG.md +++ b/packages/test-utils/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/test-utils +## 1.5.8 + +### Patch Changes + +- 95a3a0b: Rename frontend and backend `setupRequestMockHandlers` methods to `registerMswTestHooks`. +- Updated dependencies + - @backstage/plugin-permission-common@0.8.0 + - @backstage/core-app-api@1.14.0 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + ## 1.5.8-next.1 ### Patch Changes diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index 9cf0c7a6a7..9d36217b46 100644 --- a/packages/test-utils/package.json +++ b/packages/test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/test-utils", - "version": "1.5.8-next.1", + "version": "1.5.8", "description": "Utilities to test Backstage plugins and apps.", "backstage": { "role": "web-library" diff --git a/plugins/api-docs/CHANGELOG.md b/plugins/api-docs/CHANGELOG.md index 58d69f516d..b6d585c0f0 100644 --- a/plugins/api-docs/CHANGELOG.md +++ b/plugins/api-docs/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-api-docs +## 0.11.7 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/plugin-catalog@1.21.1 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/catalog-model@1.5.0 + - @backstage/core-compat-api@0.2.7 + - @backstage/core-plugin-api@1.9.3 + ## 0.11.7-next.2 ### Patch Changes diff --git a/plugins/api-docs/package.json b/plugins/api-docs/package.json index 5a6d97b7ce..7cda749423 100644 --- a/plugins/api-docs/package.json +++ b/plugins/api-docs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-api-docs", - "version": "0.11.7-next.2", + "version": "0.11.7", "description": "A Backstage plugin that helps represent API entities in the frontend", "backstage": { "role": "frontend-plugin", diff --git a/plugins/app-backend/CHANGELOG.md b/plugins/app-backend/CHANGELOG.md index b472d51f0f..63265e33d9 100644 --- a/plugins/app-backend/CHANGELOG.md +++ b/plugins/app-backend/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-app-backend +## 0.3.71 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/plugin-app-node@0.1.22 + - @backstage/config-loader@1.8.1 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 0.3.71-next.1 ### Patch Changes diff --git a/plugins/app-backend/package.json b/plugins/app-backend/package.json index 0d44e3dc61..e6661f9d73 100644 --- a/plugins/app-backend/package.json +++ b/plugins/app-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-app-backend", - "version": "0.3.71-next.1", + "version": "0.3.71", "description": "A Backstage backend plugin that serves the Backstage frontend app", "backstage": { "role": "backend-plugin", diff --git a/plugins/app-node/CHANGELOG.md b/plugins/app-node/CHANGELOG.md index e5ff0eb99f..4dce17870a 100644 --- a/plugins/app-node/CHANGELOG.md +++ b/plugins/app-node/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-app-node +## 0.1.22 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/config-loader@1.8.1 + ## 0.1.22-next.1 ### Patch Changes diff --git a/plugins/app-node/package.json b/plugins/app-node/package.json index 11ddf46cf8..a846190f31 100644 --- a/plugins/app-node/package.json +++ b/plugins/app-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-app-node", - "version": "0.1.22-next.1", + "version": "0.1.22", "description": "Node.js library for the app plugin", "backstage": { "role": "node-library", diff --git a/plugins/app-visualizer/CHANGELOG.md b/plugins/app-visualizer/CHANGELOG.md index cdb8bab69e..ec24e1cc8b 100644 --- a/plugins/app-visualizer/CHANGELOG.md +++ b/plugins/app-visualizer/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-app-visualizer +## 0.1.8 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/core-plugin-api@1.9.3 + ## 0.1.8-next.1 ### Patch Changes diff --git a/plugins/app-visualizer/package.json b/plugins/app-visualizer/package.json index 95df128040..6b10ffc220 100644 --- a/plugins/app-visualizer/package.json +++ b/plugins/app-visualizer/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-app-visualizer", - "version": "0.1.8-next.1", + "version": "0.1.8", "description": "Visualizes the Backstage app structure", "backstage": { "role": "frontend-plugin", diff --git a/plugins/auth-backend-module-atlassian-provider/CHANGELOG.md b/plugins/auth-backend-module-atlassian-provider/CHANGELOG.md index 0449bc6933..55287ebd46 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.2.3 + +### Patch Changes + +- b9832ae: Fix several issues with the Atlassian auth provider (type definition, profile url, profile transformation, scopes) +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-auth-node@0.4.17 + ## 0.2.3-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-atlassian-provider/package.json b/plugins/auth-backend-module-atlassian-provider/package.json index d938144603..309dff7f50 100644 --- a/plugins/auth-backend-module-atlassian-provider/package.json +++ b/plugins/auth-backend-module-atlassian-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-atlassian-provider", - "version": "0.2.3-next.1", + "version": "0.2.3", "description": "The atlassian-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-aws-alb-provider/CHANGELOG.md b/plugins/auth-backend-module-aws-alb-provider/CHANGELOG.md index f1ae8a4981..cc2db5e210 100644 --- a/plugins/auth-backend-module-aws-alb-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-aws-alb-provider/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-auth-backend-module-aws-alb-provider +## 0.1.14 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/plugin-auth-backend@0.22.9 + - @backstage/errors@1.2.4 + ## 0.1.14-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-aws-alb-provider/package.json b/plugins/auth-backend-module-aws-alb-provider/package.json index 6ee5c274c1..9d15f0ea09 100644 --- a/plugins/auth-backend-module-aws-alb-provider/package.json +++ b/plugins/auth-backend-module-aws-alb-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-aws-alb-provider", - "version": "0.1.14-next.1", + "version": "0.1.14", "description": "The aws-alb provider module for the Backstage auth backend.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-azure-easyauth-provider/CHANGELOG.md b/plugins/auth-backend-module-azure-easyauth-provider/CHANGELOG.md index 5e78ec6abb..26eb0d17b4 100644 --- a/plugins/auth-backend-module-azure-easyauth-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-azure-easyauth-provider/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-auth-backend-module-azure-easyauth-provider +## 0.1.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + ## 0.1.5-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-azure-easyauth-provider/package.json b/plugins/auth-backend-module-azure-easyauth-provider/package.json index 287059eb8f..52293f2480 100644 --- a/plugins/auth-backend-module-azure-easyauth-provider/package.json +++ b/plugins/auth-backend-module-azure-easyauth-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-azure-easyauth-provider", - "version": "0.1.5-next.1", + "version": "0.1.5", "description": "The azure-easyauth-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-bitbucket-provider/CHANGELOG.md b/plugins/auth-backend-module-bitbucket-provider/CHANGELOG.md index 33b434f86e..86ec768727 100644 --- a/plugins/auth-backend-module-bitbucket-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-bitbucket-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-auth-backend-module-bitbucket-provider +## 0.1.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-auth-node@0.4.17 + ## 0.1.5-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-bitbucket-provider/package.json b/plugins/auth-backend-module-bitbucket-provider/package.json index 95189d2cea..8ddb0f8acd 100644 --- a/plugins/auth-backend-module-bitbucket-provider/package.json +++ b/plugins/auth-backend-module-bitbucket-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-bitbucket-provider", - "version": "0.1.5-next.1", + "version": "0.1.5", "description": "The bitbucket-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-cloudflare-access-provider/CHANGELOG.md b/plugins/auth-backend-module-cloudflare-access-provider/CHANGELOG.md index 9754e9a73a..2910ffccce 100644 --- a/plugins/auth-backend-module-cloudflare-access-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-cloudflare-access-provider/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-auth-backend-module-cloudflare-access-provider +## 0.1.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.1.5-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-cloudflare-access-provider/package.json b/plugins/auth-backend-module-cloudflare-access-provider/package.json index b0cd52d022..30c60ed6a4 100644 --- a/plugins/auth-backend-module-cloudflare-access-provider/package.json +++ b/plugins/auth-backend-module-cloudflare-access-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-cloudflare-access-provider", - "version": "0.1.5-next.1", + "version": "0.1.5", "description": "The cloudflare-access-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-gcp-iap-provider/CHANGELOG.md b/plugins/auth-backend-module-gcp-iap-provider/CHANGELOG.md index 8fe2c331a4..19549dc23a 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.17 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 0.2.17-next.1 ### 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 8e00b9e935..d0059e7a69 100644 --- a/plugins/auth-backend-module-gcp-iap-provider/package.json +++ b/plugins/auth-backend-module-gcp-iap-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-gcp-iap-provider", - "version": "0.2.17-next.1", + "version": "0.2.17", "description": "A GCP IAP auth provider module for the Backstage auth backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-github-provider/CHANGELOG.md b/plugins/auth-backend-module-github-provider/CHANGELOG.md index f73e6adf3c..5d9704a86b 100644 --- a/plugins/auth-backend-module-github-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-github-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-auth-backend-module-github-provider +## 0.1.19 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-auth-node@0.4.17 + ## 0.1.19-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-github-provider/package.json b/plugins/auth-backend-module-github-provider/package.json index 138aaa4e02..42ef2ccd4e 100644 --- a/plugins/auth-backend-module-github-provider/package.json +++ b/plugins/auth-backend-module-github-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-github-provider", - "version": "0.1.19-next.1", + "version": "0.1.19", "description": "The github-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-gitlab-provider/CHANGELOG.md b/plugins/auth-backend-module-gitlab-provider/CHANGELOG.md index a8d5844847..57a6aa189b 100644 --- a/plugins/auth-backend-module-gitlab-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-gitlab-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-auth-backend-module-gitlab-provider +## 0.1.19 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-auth-node@0.4.17 + ## 0.1.19-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-gitlab-provider/package.json b/plugins/auth-backend-module-gitlab-provider/package.json index 97e680237c..b0e0d2e647 100644 --- a/plugins/auth-backend-module-gitlab-provider/package.json +++ b/plugins/auth-backend-module-gitlab-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-gitlab-provider", - "version": "0.1.19-next.1", + "version": "0.1.19", "description": "The gitlab-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-google-provider/CHANGELOG.md b/plugins/auth-backend-module-google-provider/CHANGELOG.md index e7eeb2779c..17efe0d1a5 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.19 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-auth-node@0.4.17 + ## 0.1.19-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-google-provider/package.json b/plugins/auth-backend-module-google-provider/package.json index 55b2616502..1153cbb37a 100644 --- a/plugins/auth-backend-module-google-provider/package.json +++ b/plugins/auth-backend-module-google-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-google-provider", - "version": "0.1.19-next.1", + "version": "0.1.19", "description": "A Google auth provider module for the Backstage auth backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-guest-provider/CHANGELOG.md b/plugins/auth-backend-module-guest-provider/CHANGELOG.md index fd046e8dca..7c9e48041d 100644 --- a/plugins/auth-backend-module-guest-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-guest-provider/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-auth-backend-module-guest-provider +## 0.1.8 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + ## 0.1.8-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-guest-provider/package.json b/plugins/auth-backend-module-guest-provider/package.json index 78fbd098f6..1648ebea6a 100644 --- a/plugins/auth-backend-module-guest-provider/package.json +++ b/plugins/auth-backend-module-guest-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-guest-provider", - "version": "0.1.8-next.1", + "version": "0.1.8", "description": "The guest-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-microsoft-provider/CHANGELOG.md b/plugins/auth-backend-module-microsoft-provider/CHANGELOG.md index 668047c816..c4df7007f3 100644 --- a/plugins/auth-backend-module-microsoft-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-microsoft-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-auth-backend-module-microsoft-provider +## 0.1.17 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-auth-node@0.4.17 + ## 0.1.17-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-microsoft-provider/package.json b/plugins/auth-backend-module-microsoft-provider/package.json index 76d3236f8b..67a898cf80 100644 --- a/plugins/auth-backend-module-microsoft-provider/package.json +++ b/plugins/auth-backend-module-microsoft-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-microsoft-provider", - "version": "0.1.17-next.1", + "version": "0.1.17", "description": "The microsoft-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md b/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md index 9872a64385..edfcfa0bcb 100644 --- a/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-auth-backend-module-oauth2-provider +## 0.2.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-auth-node@0.4.17 + ## 0.2.3-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-oauth2-provider/package.json b/plugins/auth-backend-module-oauth2-provider/package.json index 71934913fe..c98a36d104 100644 --- a/plugins/auth-backend-module-oauth2-provider/package.json +++ b/plugins/auth-backend-module-oauth2-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-oauth2-provider", - "version": "0.2.3-next.1", + "version": "0.2.3", "description": "The oauth2-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-oauth2-proxy-provider/CHANGELOG.md b/plugins/auth-backend-module-oauth2-proxy-provider/CHANGELOG.md index 895ada0e6e..554468bcfe 100644 --- a/plugins/auth-backend-module-oauth2-proxy-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-oauth2-proxy-provider/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-auth-backend-module-oauth2-proxy-provider +## 0.1.15 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/errors@1.2.4 + ## 0.1.15-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-oauth2-proxy-provider/package.json b/plugins/auth-backend-module-oauth2-proxy-provider/package.json index 4123403eb2..16b4126781 100644 --- a/plugins/auth-backend-module-oauth2-proxy-provider/package.json +++ b/plugins/auth-backend-module-oauth2-proxy-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-oauth2-proxy-provider", - "version": "0.1.15-next.1", + "version": "0.1.15", "description": "The oauth2-proxy-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-oidc-provider/CHANGELOG.md b/plugins/auth-backend-module-oidc-provider/CHANGELOG.md index b9f8ffc98d..5e0d6aeb5c 100644 --- a/plugins/auth-backend-module-oidc-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-oidc-provider/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-auth-backend-module-oidc-provider +## 0.2.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/plugin-auth-backend@0.22.9 + ## 0.2.3-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-oidc-provider/package.json b/plugins/auth-backend-module-oidc-provider/package.json index 34e6c6f296..d825bd2986 100644 --- a/plugins/auth-backend-module-oidc-provider/package.json +++ b/plugins/auth-backend-module-oidc-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-oidc-provider", - "version": "0.2.3-next.1", + "version": "0.2.3", "description": "The oidc-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-okta-provider/CHANGELOG.md b/plugins/auth-backend-module-okta-provider/CHANGELOG.md index dfb5f638bf..029892a34a 100644 --- a/plugins/auth-backend-module-okta-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-okta-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-auth-backend-module-okta-provider +## 0.0.15 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-auth-node@0.4.17 + ## 0.0.15-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-okta-provider/package.json b/plugins/auth-backend-module-okta-provider/package.json index cf099d40ee..4070ffd31f 100644 --- a/plugins/auth-backend-module-okta-provider/package.json +++ b/plugins/auth-backend-module-okta-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-okta-provider", - "version": "0.0.15-next.1", + "version": "0.0.15", "description": "The okta-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-onelogin-provider/CHANGELOG.md b/plugins/auth-backend-module-onelogin-provider/CHANGELOG.md index 8e21a1868e..896f6b7e0c 100644 --- a/plugins/auth-backend-module-onelogin-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-onelogin-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-auth-backend-module-onelogin-provider +## 0.1.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-auth-node@0.4.17 + ## 0.1.3-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-onelogin-provider/package.json b/plugins/auth-backend-module-onelogin-provider/package.json index ac6a38a4f5..045dce0392 100644 --- a/plugins/auth-backend-module-onelogin-provider/package.json +++ b/plugins/auth-backend-module-onelogin-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-onelogin-provider", - "version": "0.1.3-next.1", + "version": "0.1.3", "description": "The onelogin-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-pinniped-provider/CHANGELOG.md b/plugins/auth-backend-module-pinniped-provider/CHANGELOG.md index 4435efc501..c3ea4665e8 100644 --- a/plugins/auth-backend-module-pinniped-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-pinniped-provider/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-auth-backend-module-pinniped-provider +## 0.1.16 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/config@1.2.0 + ## 0.1.16-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-pinniped-provider/package.json b/plugins/auth-backend-module-pinniped-provider/package.json index 2698a56a2e..e6f50e4008 100644 --- a/plugins/auth-backend-module-pinniped-provider/package.json +++ b/plugins/auth-backend-module-pinniped-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-pinniped-provider", - "version": "0.1.16-next.1", + "version": "0.1.16", "description": "The pinniped-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-vmware-cloud-provider/CHANGELOG.md b/plugins/auth-backend-module-vmware-cloud-provider/CHANGELOG.md index edfc30c099..f652d6135c 100644 --- a/plugins/auth-backend-module-vmware-cloud-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-vmware-cloud-provider/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-auth-backend-module-vmware-cloud-provider +## 0.2.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/catalog-model@1.5.0 + ## 0.2.3-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-vmware-cloud-provider/package.json b/plugins/auth-backend-module-vmware-cloud-provider/package.json index d6b7eaf263..77dafe38e1 100644 --- a/plugins/auth-backend-module-vmware-cloud-provider/package.json +++ b/plugins/auth-backend-module-vmware-cloud-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-vmware-cloud-provider", - "version": "0.2.3-next.1", + "version": "0.2.3", "description": "The vmware-cloud-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend/CHANGELOG.md b/plugins/auth-backend/CHANGELOG.md index 2bb083ed66..393820ec27 100644 --- a/plugins/auth-backend/CHANGELOG.md +++ b/plugins/auth-backend/CHANGELOG.md @@ -1,5 +1,35 @@ # @backstage/plugin-auth-backend +## 0.22.9 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-auth-backend-module-atlassian-provider@0.2.3 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/plugin-auth-backend-module-aws-alb-provider@0.1.14 + - @backstage/plugin-auth-backend-module-azure-easyauth-provider@0.1.5 + - @backstage/plugin-auth-backend-module-bitbucket-provider@0.1.5 + - @backstage/plugin-auth-backend-module-cloudflare-access-provider@0.1.5 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.17 + - @backstage/plugin-auth-backend-module-github-provider@0.1.19 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.1.19 + - @backstage/plugin-auth-backend-module-google-provider@0.1.19 + - @backstage/plugin-auth-backend-module-microsoft-provider@0.1.17 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.2.3 + - @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.15 + - @backstage/plugin-auth-backend-module-oidc-provider@0.2.3 + - @backstage/plugin-auth-backend-module-okta-provider@0.0.15 + - @backstage/plugin-auth-backend-module-onelogin-provider@0.1.3 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 0.22.9-next.1 ### Patch Changes diff --git a/plugins/auth-backend/package.json b/plugins/auth-backend/package.json index cd31a18064..c9d437ceba 100644 --- a/plugins/auth-backend/package.json +++ b/plugins/auth-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend", - "version": "0.22.9-next.1", + "version": "0.22.9", "description": "A Backstage backend plugin that handles authentication", "backstage": { "role": "backend-plugin", diff --git a/plugins/auth-node/CHANGELOG.md b/plugins/auth-node/CHANGELOG.md index e931a1c26a..298f0e4472 100644 --- a/plugins/auth-node/CHANGELOG.md +++ b/plugins/auth-node/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-auth-node +## 0.4.17 + +### Patch Changes + +- 55c1a72: Fix issues with Atlassian OAuth provider: retrieve the email and photo that were not in arrays but rather in single props. +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 0.4.17-next.1 ### Patch Changes diff --git a/plugins/auth-node/package.json b/plugins/auth-node/package.json index ab84eb7fe6..0f4b0f5a77 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.17-next.1", + "version": "0.4.17", "backstage": { "role": "node-library", "pluginId": "auth", diff --git a/plugins/auth-react/CHANGELOG.md b/plugins/auth-react/CHANGELOG.md index 84bfadc98c..4651cf7eae 100644 --- a/plugins/auth-react/CHANGELOG.md +++ b/plugins/auth-react/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-auth-react +## 0.1.4 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + ## 0.1.4-next.1 ### Patch Changes diff --git a/plugins/auth-react/package.json b/plugins/auth-react/package.json index 8af97a0b04..44a4ce9fd0 100644 --- a/plugins/auth-react/package.json +++ b/plugins/auth-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-react", - "version": "0.1.4-next.1", + "version": "0.1.4", "description": "Web library for the auth plugin", "backstage": { "role": "web-library", diff --git a/plugins/bitbucket-cloud-common/CHANGELOG.md b/plugins/bitbucket-cloud-common/CHANGELOG.md index 73060ebd4a..7b2b8a936b 100644 --- a/plugins/bitbucket-cloud-common/CHANGELOG.md +++ b/plugins/bitbucket-cloud-common/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-bitbucket-cloud-common +## 0.2.21 + +### Patch Changes + +- b5deed0: Add support for `autocomplete` handler to provide autocomplete options for `RepoUrlPicker` +- Updated dependencies + - @backstage/integration@1.13.0 + ## 0.2.21-next.0 ### Patch Changes diff --git a/plugins/bitbucket-cloud-common/package.json b/plugins/bitbucket-cloud-common/package.json index 0e98fcc505..d52122f995 100644 --- a/plugins/bitbucket-cloud-common/package.json +++ b/plugins/bitbucket-cloud-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-bitbucket-cloud-common", - "version": "0.2.21-next.0", + "version": "0.2.21", "description": "Common functionalities for bitbucket-cloud plugins", "backstage": { "role": "common-library", diff --git a/plugins/catalog-backend-module-aws/CHANGELOG.md b/plugins/catalog-backend-module-aws/CHANGELOG.md index 15f944de19..f2dd32b7f2 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.17 + +### Patch Changes + +- 4afa050: Export `defaultEksClusterEntityTransformer` to allow library consumers to layer additional changes on top of the default transformer. +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/integration@1.13.0 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-kubernetes-common@0.8.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration-aws-node@0.1.12 + ## 0.3.17-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-aws/package.json b/plugins/catalog-backend-module-aws/package.json index 7081b09d2b..91ac7c4eae 100644 --- a/plugins/catalog-backend-module-aws/package.json +++ b/plugins/catalog-backend-module-aws/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-aws", - "version": "0.3.17-next.1", + "version": "0.3.17", "description": "A Backstage catalog backend module that helps integrate towards AWS", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-azure/CHANGELOG.md b/plugins/catalog-backend-module-azure/CHANGELOG.md index 1f672302ac..e96ca2d650 100644 --- a/plugins/catalog-backend-module-azure/CHANGELOG.md +++ b/plugins/catalog-backend-module-azure/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-catalog-backend-module-azure +## 0.1.42 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/integration@1.13.0 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/config@1.2.0 + ## 0.1.42-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-azure/package.json b/plugins/catalog-backend-module-azure/package.json index 1159aff6db..05b920bcb0 100644 --- a/plugins/catalog-backend-module-azure/package.json +++ b/plugins/catalog-backend-module-azure/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-azure", - "version": "0.1.42-next.1", + "version": "0.1.42", "description": "A Backstage catalog backend module that helps integrate towards Azure", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-backstage-openapi/CHANGELOG.md b/plugins/catalog-backend-module-backstage-openapi/CHANGELOG.md index 125778b4b6..620ab36c40 100644 --- a/plugins/catalog-backend-module-backstage-openapi/CHANGELOG.md +++ b/plugins/catalog-backend-module-backstage-openapi/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-catalog-backend-module-backstage-openapi +## 0.2.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-tasks@0.5.27 + - @backstage/backend-openapi-utils@0.1.15 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.2.5-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-backstage-openapi/package.json b/plugins/catalog-backend-module-backstage-openapi/package.json index fad1dc47c9..de6c2a8410 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.2.5-next.1", + "version": "0.2.5", "backstage": { "role": "backend-plugin-module", "pluginId": "catalog", diff --git a/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md b/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md index 4ad56f2aa3..920d2bc111 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.2.9 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/integration@1.13.0 + - @backstage/plugin-events-node@0.3.8 + - @backstage/plugin-bitbucket-cloud-common@0.2.21 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + ## 0.2.9-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-bitbucket-cloud/package.json b/plugins/catalog-backend-module-bitbucket-cloud/package.json index e691c2a3c3..9faa941fd6 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/package.json +++ b/plugins/catalog-backend-module-bitbucket-cloud/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-bitbucket-cloud", - "version": "0.2.9-next.1", + "version": "0.2.9", "description": "A Backstage catalog backend module that helps integrate towards Bitbucket Cloud", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md b/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md index a5901702ff..857d9a33d9 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.36 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/integration@1.13.0 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.1.36-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-bitbucket-server/package.json b/plugins/catalog-backend-module-bitbucket-server/package.json index 4e47fcbdcc..793a4213f2 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.36-next.1", + "version": "0.1.36", "backstage": { "role": "backend-plugin-module", "pluginId": "catalog", diff --git a/plugins/catalog-backend-module-gcp/CHANGELOG.md b/plugins/catalog-backend-module-gcp/CHANGELOG.md index b76bc9d7a9..779039f858 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.23 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-kubernetes-common@0.8.1 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + ## 0.1.23-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-gcp/package.json b/plugins/catalog-backend-module-gcp/package.json index 0888a9eb03..7ebe7cbefc 100644 --- a/plugins/catalog-backend-module-gcp/package.json +++ b/plugins/catalog-backend-module-gcp/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-gcp", - "version": "0.1.23-next.1", + "version": "0.1.23", "description": "A Backstage catalog backend module that helps integrate towards GCP", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-gerrit/CHANGELOG.md b/plugins/catalog-backend-module-gerrit/CHANGELOG.md index 6492e65ffa..159c9bb550 100644 --- a/plugins/catalog-backend-module-gerrit/CHANGELOG.md +++ b/plugins/catalog-backend-module-gerrit/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-catalog-backend-module-gerrit +## 0.1.39 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/integration@1.13.0 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.1.39-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-gerrit/package.json b/plugins/catalog-backend-module-gerrit/package.json index b99347e6f5..0732db4465 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.39-next.1", + "version": "0.1.39", "backstage": { "role": "backend-plugin-module", "pluginId": "catalog", diff --git a/plugins/catalog-backend-module-github-org/CHANGELOG.md b/plugins/catalog-backend-module-github-org/CHANGELOG.md index 0236b1d30c..424465d813 100644 --- a/plugins/catalog-backend-module-github-org/CHANGELOG.md +++ b/plugins/catalog-backend-module-github-org/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-catalog-backend-module-github-org +## 0.1.17 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-events-node@0.3.8 + - @backstage/plugin-catalog-backend-module-github@0.6.5 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/config@1.2.0 + ## 0.1.17-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-github-org/package.json b/plugins/catalog-backend-module-github-org/package.json index abd92889a0..3fdcc2fedf 100644 --- a/plugins/catalog-backend-module-github-org/package.json +++ b/plugins/catalog-backend-module-github-org/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-github-org", - "version": "0.1.17-next.1", + "version": "0.1.17", "description": "The github-org backend module for the catalog plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-github/CHANGELOG.md b/plugins/catalog-backend-module-github/CHANGELOG.md index 02975d2b68..661712456b 100644 --- a/plugins/catalog-backend-module-github/CHANGELOG.md +++ b/plugins/catalog-backend-module-github/CHANGELOG.md @@ -1,5 +1,49 @@ # @backstage/plugin-catalog-backend-module-github +## 0.6.5 + +### Patch Changes + +- 9112efc: Adds support for `repository` events. + + The provider adds a subscription to the topic `github.repository`. + + Hereby, it supports events of type `repository` with actions + + - `archived` + - `deleted` + - `edited` + - `renamed` + - `transferred` + - `unarchived` + + Actions skipped as they don't require entity changes: + + - `created` + - `privatized` + - `publicized` + + If the config option `validateLocationsExist` is enabled, an API request + is necessary and will be executed. + This affects the actions `renamed`, `transferred`, and `unarchive` + of event type `repository`. + + Catalog entities related to the `GithubEntityProvider` instance will be adjusted + according to action and its meaning for them. + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/integration@1.13.0 + - @backstage/plugin-events-node@0.3.8 + - @backstage/plugin-catalog-backend@1.24.0 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + ## 0.6.5-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-github/package.json b/plugins/catalog-backend-module-github/package.json index c8b78c5e92..50b838be1d 100644 --- a/plugins/catalog-backend-module-github/package.json +++ b/plugins/catalog-backend-module-github/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-github", - "version": "0.6.5-next.1", + "version": "0.6.5", "description": "A Backstage catalog backend module that helps integrate towards GitHub", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-gitlab-org/CHANGELOG.md b/plugins/catalog-backend-module-gitlab-org/CHANGELOG.md index d86cb76c24..b36bcb4d71 100644 --- a/plugins/catalog-backend-module-gitlab-org/CHANGELOG.md +++ b/plugins/catalog-backend-module-gitlab-org/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-catalog-backend-module-gitlab-org +## 0.0.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-catalog-backend-module-gitlab@0.3.21 + - @backstage/plugin-events-node@0.3.8 + - @backstage/plugin-catalog-node@1.12.4 + ## 0.0.5-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-gitlab-org/package.json b/plugins/catalog-backend-module-gitlab-org/package.json index a08a42d1f3..9c4c1f725f 100644 --- a/plugins/catalog-backend-module-gitlab-org/package.json +++ b/plugins/catalog-backend-module-gitlab-org/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-gitlab-org", - "version": "0.0.5-next.1", + "version": "0.0.5", "description": "The gitlab-org backend module for the catalog plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-gitlab/CHANGELOG.md b/plugins/catalog-backend-module-gitlab/CHANGELOG.md index 8d6eb4bfef..97ed683942 100644 --- a/plugins/catalog-backend-module-gitlab/CHANGELOG.md +++ b/plugins/catalog-backend-module-gitlab/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-catalog-backend-module-gitlab +## 0.3.21 + +### Patch Changes + +- 8db30ad: The Gitlab configuration supports an additional optional boolean key `catalog.providers.gitlab.<your-org>.restrictUsersToGroup`. Setting this to `true` will make Backstage only import users from the group defined in the `group` key, instead of all users in the organisation (self-hosted) or of the root group (SaaS). It will default to false, keeping the original implementation intact, when not explicitly set. +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/integration@1.13.0 + - @backstage/plugin-events-node@0.3.8 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + ## 0.3.21-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-gitlab/package.json b/plugins/catalog-backend-module-gitlab/package.json index 0780ccdd6a..fa21798a62 100644 --- a/plugins/catalog-backend-module-gitlab/package.json +++ b/plugins/catalog-backend-module-gitlab/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-gitlab", - "version": "0.3.21-next.1", + "version": "0.3.21", "description": "A Backstage catalog backend module that helps integrate towards GitLab", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md b/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md index 9cd19e259e..0d04145063 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md +++ b/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-catalog-backend-module-incremental-ingestion +## 0.4.27 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-events-node@0.3.8 + - @backstage/plugin-catalog-backend@1.24.0 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.4.27-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-incremental-ingestion/package.json b/plugins/catalog-backend-module-incremental-ingestion/package.json index c9cf1f5a82..0180f36d03 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/package.json +++ b/plugins/catalog-backend-module-incremental-ingestion/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-incremental-ingestion", - "version": "0.4.27-next.1", + "version": "0.4.27", "description": "An entity provider for streaming large asset sources into the catalog", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-ldap/CHANGELOG.md b/plugins/catalog-backend-module-ldap/CHANGELOG.md index 6842b99282..9168ce0991 100644 --- a/plugins/catalog-backend-module-ldap/CHANGELOG.md +++ b/plugins/catalog-backend-module-ldap/CHANGELOG.md @@ -1,5 +1,26 @@ # @backstage/plugin-catalog-backend-module-ldap +## 0.7.0 + +### Minor Changes + +- cb32ca7: **BREAKING**: `readLdapOrg` and the `LdapProviderConfig` type now always accept arrays of user and group configs, not just single items. + + Added support for single ldap catalog provider to provide list and undefined user and group bindings next to standard single one. + +### Patch Changes + +- 083eaf9: Fix bug where ISO durations could no longer be used for schedules +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 0.7.0-next.1 ### Minor Changes diff --git a/plugins/catalog-backend-module-ldap/package.json b/plugins/catalog-backend-module-ldap/package.json index 411f168fd8..62b3328de7 100644 --- a/plugins/catalog-backend-module-ldap/package.json +++ b/plugins/catalog-backend-module-ldap/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-ldap", - "version": "0.7.0-next.1", + "version": "0.7.0", "description": "A Backstage catalog backend module that helps integrate towards LDAP", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-logs/CHANGELOG.md b/plugins/catalog-backend-module-logs/CHANGELOG.md index c609fc369d..2712f4a134 100644 --- a/plugins/catalog-backend-module-logs/CHANGELOG.md +++ b/plugins/catalog-backend-module-logs/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-catalog-backend-module-logs +## 0.0.1 + +### Patch Changes + +- 97caf55: Creates a new module to make logging catalog errors simple. This module subscribes to catalog events and logs them. + + See [Backstage documentation](https://backstage.io/docs/features/software-catalog/configuration#subscribing-to-catalog-errors) for details on how to install + and configure the plugin. + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-events-node@0.3.8 + - @backstage/plugin-catalog-backend@1.24.0 + ## 0.0.1-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-logs/package.json b/plugins/catalog-backend-module-logs/package.json index fe3f09c29c..560b93737e 100644 --- a/plugins/catalog-backend-module-logs/package.json +++ b/plugins/catalog-backend-module-logs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-logs", - "version": "0.0.1-next.1", + "version": "0.0.1", "description": "A module that subscribes to catalog releated events and logs them.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-msgraph/CHANGELOG.md b/plugins/catalog-backend-module-msgraph/CHANGELOG.md index eb3591241f..a33bea94b8 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.30 + +### Patch Changes + +- f7bdcea: Adds a dynamic provider for the plugin-catalog-backend-module-msgraph. Configuration is now runtime configurable through the ProviderConfigTransformer. +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + ## 0.5.30-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-msgraph/package.json b/plugins/catalog-backend-module-msgraph/package.json index b04cd8788c..3f5fa722a8 100644 --- a/plugins/catalog-backend-module-msgraph/package.json +++ b/plugins/catalog-backend-module-msgraph/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-msgraph", - "version": "0.5.30-next.1", + "version": "0.5.30", "description": "A Backstage catalog backend module that helps integrate towards Microsoft Graph", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-openapi/CHANGELOG.md b/plugins/catalog-backend-module-openapi/CHANGELOG.md index bf35045dcc..6cc947ee17 100644 --- a/plugins/catalog-backend-module-openapi/CHANGELOG.md +++ b/plugins/catalog-backend-module-openapi/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-catalog-backend-module-openapi +## 0.1.40 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/integration@1.13.0 + - @backstage/plugin-catalog-backend@1.24.0 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + ## 0.1.40-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-openapi/package.json b/plugins/catalog-backend-module-openapi/package.json index b37cb09b15..2dbe6612ac 100644 --- a/plugins/catalog-backend-module-openapi/package.json +++ b/plugins/catalog-backend-module-openapi/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-openapi", - "version": "0.1.40-next.1", + "version": "0.1.40", "description": "A Backstage catalog backend module that helps with OpenAPI specifications", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-puppetdb/CHANGELOG.md b/plugins/catalog-backend-module-puppetdb/CHANGELOG.md index ead44a56aa..cb4cd9664b 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.28 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 0.1.28-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-puppetdb/package.json b/plugins/catalog-backend-module-puppetdb/package.json index 114daa45e8..cf2a739380 100644 --- a/plugins/catalog-backend-module-puppetdb/package.json +++ b/plugins/catalog-backend-module-puppetdb/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-puppetdb", - "version": "0.1.28-next.1", + "version": "0.1.28", "description": "A Backstage catalog backend module that helps integrate towards PuppetDB", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md b/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md index 758d59c7c0..87299358b7 100644 --- a/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md +++ b/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-catalog-backend-module-scaffolder-entity-model +## 0.1.20 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-scaffolder-common@1.5.4 + - @backstage/catalog-model@1.5.0 + ## 0.1.20-next.1 ### 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 58bcdc6fb5..3aaa768f76 100644 --- a/plugins/catalog-backend-module-scaffolder-entity-model/package.json +++ b/plugins/catalog-backend-module-scaffolder-entity-model/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-scaffolder-entity-model", - "version": "0.1.20-next.1", + "version": "0.1.20", "description": "Adds support for the scaffolder specific entity model (e.g. the Template kind) to the catalog backend plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-unprocessed/CHANGELOG.md b/plugins/catalog-backend-module-unprocessed/CHANGELOG.md index afac0ebeed..a7d74143a1 100644 --- a/plugins/catalog-backend-module-unprocessed/CHANGELOG.md +++ b/plugins/catalog-backend-module-unprocessed/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-catalog-backend-module-unprocessed +## 0.4.9 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-catalog-unprocessed-entities-common@0.0.3 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + ## 0.4.9-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-unprocessed/package.json b/plugins/catalog-backend-module-unprocessed/package.json index c49a3d700d..6f1f4bb6bc 100644 --- a/plugins/catalog-backend-module-unprocessed/package.json +++ b/plugins/catalog-backend-module-unprocessed/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-unprocessed", - "version": "0.4.9-next.1", + "version": "0.4.9", "description": "Backstage Catalog module to view unprocessed entities", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend/CHANGELOG.md b/plugins/catalog-backend/CHANGELOG.md index 65ed28cb6d..8f99ab1f4c 100644 --- a/plugins/catalog-backend/CHANGELOG.md +++ b/plugins/catalog-backend/CHANGELOG.md @@ -1,5 +1,31 @@ # @backstage/plugin-catalog-backend +## 1.24.0 + +### Minor Changes + +- b9ed1bb: bumped better-sqlite3 from ^9.0.0 to ^11.0.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.0 + - @backstage/integration@1.13.0 + - @backstage/plugin-events-node@0.3.8 + - @backstage/backend-openapi-utils@0.1.15 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-search-backend-module-catalog@0.1.28 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 1.24.0-next.1 ### Minor Changes diff --git a/plugins/catalog-backend/package.json b/plugins/catalog-backend/package.json index e554f0a334..19d40bd34c 100644 --- a/plugins/catalog-backend/package.json +++ b/plugins/catalog-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend", - "version": "1.24.0-next.1", + "version": "1.24.0", "description": "The Backstage backend plugin that provides the Backstage catalog", "backstage": { "role": "backend-plugin", diff --git a/plugins/catalog-common/CHANGELOG.md b/plugins/catalog-common/CHANGELOG.md index fd3c714f97..e2859fcc83 100644 --- a/plugins/catalog-common/CHANGELOG.md +++ b/plugins/catalog-common/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-catalog-common +## 1.0.25 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-search-common@1.2.13 + - @backstage/catalog-model@1.5.0 + ## 1.0.24 ### Patch Changes diff --git a/plugins/catalog-common/package.json b/plugins/catalog-common/package.json index 0ea4ce5e3e..865dc02f4c 100644 --- a/plugins/catalog-common/package.json +++ b/plugins/catalog-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-common", - "version": "1.0.24", + "version": "1.0.25", "description": "Common functionalities for the catalog plugin", "backstage": { "role": "common-library", diff --git a/plugins/catalog-graph/CHANGELOG.md b/plugins/catalog-graph/CHANGELOG.md index f397955e1c..332ea17dd0 100644 --- a/plugins/catalog-graph/CHANGELOG.md +++ b/plugins/catalog-graph/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-catalog-graph +## 0.4.7 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-compat-api@0.2.7 + - @backstage/core-plugin-api@1.9.3 + - @backstage/types@1.1.1 + ## 0.4.7-next.2 ### Patch Changes diff --git a/plugins/catalog-graph/package.json b/plugins/catalog-graph/package.json index eb27725d45..1e7c376436 100644 --- a/plugins/catalog-graph/package.json +++ b/plugins/catalog-graph/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-graph", - "version": "0.4.7-next.2", + "version": "0.4.7", "backstage": { "role": "frontend-plugin", "pluginId": "catalog-graph", diff --git a/plugins/catalog-import/CHANGELOG.md b/plugins/catalog-import/CHANGELOG.md index 455f094a86..29ec3631b4 100644 --- a/plugins/catalog-import/CHANGELOG.md +++ b/plugins/catalog-import/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-catalog-import +## 0.12.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/integration@1.13.0 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/integration-react@1.1.29 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-compat-api@0.2.7 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + ## 0.12.1-next.2 ### Patch Changes diff --git a/plugins/catalog-import/package.json b/plugins/catalog-import/package.json index f41d239792..c3babc09a3 100644 --- a/plugins/catalog-import/package.json +++ b/plugins/catalog-import/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-import", - "version": "0.12.1-next.2", + "version": "0.12.1", "description": "A Backstage plugin the helps you import entities into your catalog", "backstage": { "role": "frontend-plugin", diff --git a/plugins/catalog-node/CHANGELOG.md b/plugins/catalog-node/CHANGELOG.md index 54f39e9e51..74982e481f 100644 --- a/plugins/catalog-node/CHANGELOG.md +++ b/plugins/catalog-node/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-catalog-node +## 1.12.4 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.0 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 1.12.4-next.1 ### Patch Changes diff --git a/plugins/catalog-node/package.json b/plugins/catalog-node/package.json index 575a1c65f5..ccd83cd129 100644 --- a/plugins/catalog-node/package.json +++ b/plugins/catalog-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-node", - "version": "1.12.4-next.1", + "version": "1.12.4", "description": "The plugin-catalog-node module for @backstage/plugin-catalog-backend", "backstage": { "role": "node-library", diff --git a/plugins/catalog-react/CHANGELOG.md b/plugins/catalog-react/CHANGELOG.md index b29a49e47d..38402e8824 100644 --- a/plugins/catalog-react/CHANGELOG.md +++ b/plugins/catalog-react/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-catalog-react +## 1.12.2 + +### Patch Changes + +- 06c0956: Support i18n for catalog and catalog-react plugins +- 2030962: Make EntityOwnerPicker display metadata.title or spec.profile.displayName for mode=only-owners instead of metadata.name +- Updated dependencies + - @backstage/plugin-permission-common@0.8.0 + - @backstage/core-components@0.14.9 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/integration-react@1.1.29 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + ## 1.12.2-next.2 ### Patch Changes diff --git a/plugins/catalog-react/package.json b/plugins/catalog-react/package.json index f522a4f111..c6a725ecb6 100644 --- a/plugins/catalog-react/package.json +++ b/plugins/catalog-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-react", - "version": "1.12.2-next.2", + "version": "1.12.2", "description": "A frontend library that helps other Backstage plugins interact with the catalog", "backstage": { "role": "web-library", diff --git a/plugins/catalog-unprocessed-entities-common/CHANGELOG.md b/plugins/catalog-unprocessed-entities-common/CHANGELOG.md index f2f489b6a0..ca38c923bd 100644 --- a/plugins/catalog-unprocessed-entities-common/CHANGELOG.md +++ b/plugins/catalog-unprocessed-entities-common/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-catalog-unprocessed-entities-common +## 0.0.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.0 + ## 0.0.2 ### Patch Changes diff --git a/plugins/catalog-unprocessed-entities-common/package.json b/plugins/catalog-unprocessed-entities-common/package.json index f491d27157..990f75bbea 100644 --- a/plugins/catalog-unprocessed-entities-common/package.json +++ b/plugins/catalog-unprocessed-entities-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-unprocessed-entities-common", - "version": "0.0.2", + "version": "0.0.3", "description": "Common functionalities for the catalog-unprocessed-entities plugin", "backstage": { "role": "common-library", diff --git a/plugins/catalog-unprocessed-entities/CHANGELOG.md b/plugins/catalog-unprocessed-entities/CHANGELOG.md index fefeffe9d2..e3fd1b6b76 100644 --- a/plugins/catalog-unprocessed-entities/CHANGELOG.md +++ b/plugins/catalog-unprocessed-entities/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-catalog-unprocessed-entities +## 0.2.6 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + ## 0.2.6-next.1 ### Patch Changes diff --git a/plugins/catalog-unprocessed-entities/package.json b/plugins/catalog-unprocessed-entities/package.json index 142b850bd3..872ce7b11b 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.2.6-next.1", + "version": "0.2.6", "backstage": { "role": "frontend-plugin", "pluginId": "catalog-unprocessed-entities", diff --git a/plugins/catalog/CHANGELOG.md b/plugins/catalog/CHANGELOG.md index 08a70d4956..2667fdf638 100644 --- a/plugins/catalog/CHANGELOG.md +++ b/plugins/catalog/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/plugin-catalog +## 1.21.1 + +### Patch Changes + +- 06c0956: Support i18n for catalog and catalog-react plugins +- d133eaa: Added small notes to AboutCard to discourage customizability PRs +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-scaffolder-common@1.5.4 + - @backstage/plugin-search-common@1.2.13 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/integration-react@1.1.29 + - @backstage/plugin-search-react@1.7.13 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-compat-api@0.2.7 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 1.21.1-next.2 ### Patch Changes diff --git a/plugins/catalog/package.json b/plugins/catalog/package.json index 0d101af3df..fc49a8c36b 100644 --- a/plugins/catalog/package.json +++ b/plugins/catalog/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog", - "version": "1.21.1-next.2", + "version": "1.21.1", "description": "The Backstage plugin for browsing the Backstage catalog", "backstage": { "role": "frontend-plugin", diff --git a/plugins/config-schema/CHANGELOG.md b/plugins/config-schema/CHANGELOG.md index 8458a50aa3..2344473925 100644 --- a/plugins/config-schema/CHANGELOG.md +++ b/plugins/config-schema/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-config-schema +## 0.1.57 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 0.1.57-next.1 ### Patch Changes diff --git a/plugins/config-schema/package.json b/plugins/config-schema/package.json index 9a1971d80b..6f91094e5f 100644 --- a/plugins/config-schema/package.json +++ b/plugins/config-schema/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-config-schema", - "version": "0.1.57-next.1", + "version": "0.1.57", "description": "A Backstage plugin that lets you browse the configuration schema of your app", "backstage": { "role": "frontend-plugin", diff --git a/plugins/devtools-backend/CHANGELOG.md b/plugins/devtools-backend/CHANGELOG.md index cc0dc806c8..f027384637 100644 --- a/plugins/devtools-backend/CHANGELOG.md +++ b/plugins/devtools-backend/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-devtools-backend +## 0.3.8 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.0 + - @backstage/config-loader@1.8.1 + - @backstage/plugin-devtools-common@0.1.11 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 0.3.8-next.1 ### Patch Changes diff --git a/plugins/devtools-backend/package.json b/plugins/devtools-backend/package.json index bd3b61f22d..ce5e143f24 100644 --- a/plugins/devtools-backend/package.json +++ b/plugins/devtools-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-devtools-backend", - "version": "0.3.8-next.1", + "version": "0.3.8", "backstage": { "role": "backend-plugin", "pluginId": "devtools", diff --git a/plugins/devtools-common/CHANGELOG.md b/plugins/devtools-common/CHANGELOG.md index 3e060571ad..37923e3fc7 100644 --- a/plugins/devtools-common/CHANGELOG.md +++ b/plugins/devtools-common/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-devtools-common +## 0.1.11 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.0 + - @backstage/types@1.1.1 + ## 0.1.10 ### Patch Changes diff --git a/plugins/devtools-common/package.json b/plugins/devtools-common/package.json index 24b17d6742..f476580ac0 100644 --- a/plugins/devtools-common/package.json +++ b/plugins/devtools-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-devtools-common", - "version": "0.1.10", + "version": "0.1.11", "description": "Common functionalities for the devtools plugin", "backstage": { "role": "common-library", diff --git a/plugins/devtools/CHANGELOG.md b/plugins/devtools/CHANGELOG.md index 5bc6220aa3..3403b7f2fa 100644 --- a/plugins/devtools/CHANGELOG.md +++ b/plugins/devtools/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-devtools +## 0.1.16 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/plugin-devtools-common@0.1.11 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/core-compat-api@0.2.7 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + ## 0.1.16-next.1 ### Patch Changes diff --git a/plugins/devtools/package.json b/plugins/devtools/package.json index 90d724692c..83d2a6b352 100644 --- a/plugins/devtools/package.json +++ b/plugins/devtools/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-devtools", - "version": "0.1.16-next.1", + "version": "0.1.16", "backstage": { "role": "frontend-plugin", "pluginId": "devtools", diff --git a/plugins/events-backend-module-aws-sqs/CHANGELOG.md b/plugins/events-backend-module-aws-sqs/CHANGELOG.md index 399ed2689d..e27fcefa6e 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.3.8 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-events-node@0.3.8 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + ## 0.3.8-next.1 ### Patch Changes diff --git a/plugins/events-backend-module-aws-sqs/package.json b/plugins/events-backend-module-aws-sqs/package.json index b2c09d3b8a..983e15567b 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.3.8-next.1", + "version": "0.3.8", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-module-azure/CHANGELOG.md b/plugins/events-backend-module-azure/CHANGELOG.md index 5e5ccffc2a..225ee30beb 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.2.8 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-events-node@0.3.8 + ## 0.2.8-next.1 ### Patch Changes diff --git a/plugins/events-backend-module-azure/package.json b/plugins/events-backend-module-azure/package.json index 8bb6ac4f6b..49c9b9439f 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.2.8-next.1", + "version": "0.2.8", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-module-bitbucket-cloud/CHANGELOG.md b/plugins/events-backend-module-bitbucket-cloud/CHANGELOG.md index 1a339c3807..4676feabbd 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.2.8 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-events-node@0.3.8 + ## 0.2.8-next.1 ### Patch Changes diff --git a/plugins/events-backend-module-bitbucket-cloud/package.json b/plugins/events-backend-module-bitbucket-cloud/package.json index 7efffdd361..6fd443a3b1 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.2.8-next.1", + "version": "0.2.8", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-module-gerrit/CHANGELOG.md b/plugins/events-backend-module-gerrit/CHANGELOG.md index 78963fbbaf..eddce5d6c5 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.2.8 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-events-node@0.3.8 + ## 0.2.8-next.1 ### Patch Changes diff --git a/plugins/events-backend-module-gerrit/package.json b/plugins/events-backend-module-gerrit/package.json index f1bea2868c..7d870063df 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.2.8-next.1", + "version": "0.2.8", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-module-github/CHANGELOG.md b/plugins/events-backend-module-github/CHANGELOG.md index a095cf4ab3..4597583ea8 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.2.8 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-events-node@0.3.8 + - @backstage/config@1.2.0 + ## 0.2.8-next.1 ### Patch Changes diff --git a/plugins/events-backend-module-github/package.json b/plugins/events-backend-module-github/package.json index 3b37f29022..955793ee6d 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.2.8-next.1", + "version": "0.2.8", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-module-gitlab/CHANGELOG.md b/plugins/events-backend-module-gitlab/CHANGELOG.md index dc8470bd7a..f22f90405e 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.2.8 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-events-node@0.3.8 + - @backstage/config@1.2.0 + ## 0.2.8-next.1 ### Patch Changes diff --git a/plugins/events-backend-module-gitlab/package.json b/plugins/events-backend-module-gitlab/package.json index 21c95448b1..c97a9e2f02 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.2.8-next.1", + "version": "0.2.8", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-test-utils/CHANGELOG.md b/plugins/events-backend-test-utils/CHANGELOG.md index 967ffc80da..4fcbcfc172 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.32 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.3.8 + ## 0.1.32-next.1 ### Patch Changes diff --git a/plugins/events-backend-test-utils/package.json b/plugins/events-backend-test-utils/package.json index 120c7f5fa6..09a36a7a1f 100644 --- a/plugins/events-backend-test-utils/package.json +++ b/plugins/events-backend-test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-test-utils", - "version": "0.1.32-next.1", + "version": "0.1.32", "description": "The plugin-events-backend-test-utils for @backstage/plugin-events-node", "backstage": { "role": "node-library", diff --git a/plugins/events-backend/CHANGELOG.md b/plugins/events-backend/CHANGELOG.md index a4b4b550bb..4840d9a623 100644 --- a/plugins/events-backend/CHANGELOG.md +++ b/plugins/events-backend/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-events-backend +## 0.3.9 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-events-node@0.3.8 + - @backstage/config@1.2.0 + ## 0.3.9-next.1 ### Patch Changes diff --git a/plugins/events-backend/package.json b/plugins/events-backend/package.json index 82066d5a91..f9f2a4b781 100644 --- a/plugins/events-backend/package.json +++ b/plugins/events-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend", - "version": "0.3.9-next.1", + "version": "0.3.9", "backstage": { "role": "backend-plugin", "pluginId": "events", diff --git a/plugins/events-node/CHANGELOG.md b/plugins/events-node/CHANGELOG.md index 022d50fdd1..d5b1c98372 100644 --- a/plugins/events-node/CHANGELOG.md +++ b/plugins/events-node/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-events-node +## 0.3.8 + +### Patch Changes + +- b05e1e1: Service factories exported by this package have been updated to use the new service factory format that doesn't use a callback. +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + ## 0.3.8-next.1 ### Patch Changes diff --git a/plugins/events-node/package.json b/plugins/events-node/package.json index f89617dd14..965f317357 100644 --- a/plugins/events-node/package.json +++ b/plugins/events-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-node", - "version": "0.3.8-next.1", + "version": "0.3.8", "description": "The plugin-events-node module for @backstage/plugin-events-backend", "backstage": { "role": "node-library", diff --git a/plugins/example-todo-list-backend/CHANGELOG.md b/plugins/example-todo-list-backend/CHANGELOG.md index d1553258ed..dd1a2087dc 100644 --- a/plugins/example-todo-list-backend/CHANGELOG.md +++ b/plugins/example-todo-list-backend/CHANGELOG.md @@ -1,5 +1,15 @@ # @internal/plugin-todo-list-backend +## 1.0.29 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/errors@1.2.4 + ## 1.0.29-next.1 ### Patch Changes diff --git a/plugins/example-todo-list-backend/package.json b/plugins/example-todo-list-backend/package.json index 3d46a9f5f7..0ca987d30b 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.29-next.1", + "version": "1.0.29", "backstage": { "role": "backend-plugin", "pluginId": "todo-list", diff --git a/plugins/example-todo-list-common/CHANGELOG.md b/plugins/example-todo-list-common/CHANGELOG.md index 3761ead6a3..e30cb653df 100644 --- a/plugins/example-todo-list-common/CHANGELOG.md +++ b/plugins/example-todo-list-common/CHANGELOG.md @@ -1,5 +1,12 @@ # @internal/plugin-todo-list-common +## 1.0.20 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.0 + ## 1.0.19 ### Patch Changes diff --git a/plugins/example-todo-list-common/package.json b/plugins/example-todo-list-common/package.json index 317cfa991d..efccce611f 100644 --- a/plugins/example-todo-list-common/package.json +++ b/plugins/example-todo-list-common/package.json @@ -1,6 +1,6 @@ { "name": "@internal/plugin-todo-list-common", - "version": "1.0.19", + "version": "1.0.20", "backstage": { "role": "common-library", "pluginId": "todo-list", diff --git a/plugins/example-todo-list/CHANGELOG.md b/plugins/example-todo-list/CHANGELOG.md index f61f8b8d0a..e55f882b0a 100644 --- a/plugins/example-todo-list/CHANGELOG.md +++ b/plugins/example-todo-list/CHANGELOG.md @@ -1,5 +1,13 @@ # @internal/plugin-todo-list +## 1.0.29 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/core-plugin-api@1.9.3 + ## 1.0.29-next.1 ### Patch Changes diff --git a/plugins/example-todo-list/package.json b/plugins/example-todo-list/package.json index d008b73538..c8c0a90312 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.29-next.1", + "version": "1.0.29", "backstage": { "role": "frontend-plugin", "pluginId": "todo-list", diff --git a/plugins/home-react/CHANGELOG.md b/plugins/home-react/CHANGELOG.md index 1f1c9a0e2e..c4db30307f 100644 --- a/plugins/home-react/CHANGELOG.md +++ b/plugins/home-react/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-home-react +## 0.1.15 + +### Patch Changes + +- cc81579: Updated dependency `@rjsf/utils` to `5.18.5`. + Updated dependency `@rjsf/core` to `5.18.5`. + Updated dependency `@rjsf/material-ui` to `5.18.5`. + Updated dependency `@rjsf/validator-ajv8` to `5.18.5`. +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/core-plugin-api@1.9.3 + ## 0.1.15-next.2 ### Patch Changes diff --git a/plugins/home-react/package.json b/plugins/home-react/package.json index ec05852818..433a91b475 100644 --- a/plugins/home-react/package.json +++ b/plugins/home-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-home-react", - "version": "0.1.15-next.2", + "version": "0.1.15", "description": "A Backstage plugin that contains react components helps you build a home page", "backstage": { "role": "web-library", diff --git a/plugins/home/CHANGELOG.md b/plugins/home/CHANGELOG.md index e65b3dec1c..eb49e3217b 100644 --- a/plugins/home/CHANGELOG.md +++ b/plugins/home/CHANGELOG.md @@ -1,5 +1,26 @@ # @backstage/plugin-home +## 0.7.7 + +### Patch Changes + +- cc81579: Updated dependency `@rjsf/utils` to `5.18.5`. + Updated dependency `@rjsf/core` to `5.18.5`. + Updated dependency `@rjsf/material-ui` to `5.18.5`. + Updated dependency `@rjsf/validator-ajv8` to `5.18.5`. +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/core-app-api@1.14.0 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/plugin-home-react@0.1.15 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-compat-api@0.2.7 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + ## 0.7.7-next.2 ### Patch Changes diff --git a/plugins/home/package.json b/plugins/home/package.json index 01dd27a295..189aeec2ac 100644 --- a/plugins/home/package.json +++ b/plugins/home/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-home", - "version": "0.7.7-next.2", + "version": "0.7.7", "description": "A Backstage plugin that helps you build a home page", "backstage": { "role": "frontend-plugin", diff --git a/plugins/kubernetes-backend/CHANGELOG.md b/plugins/kubernetes-backend/CHANGELOG.md index 7b8d3fb534..6a41d014f5 100644 --- a/plugins/kubernetes-backend/CHANGELOG.md +++ b/plugins/kubernetes-backend/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-kubernetes-backend +## 0.18.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.0 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-kubernetes-node@0.1.16 + - @backstage/plugin-kubernetes-common@0.8.1 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration-aws-node@0.1.12 + - @backstage/types@1.1.1 + ## 0.18.3-next.1 ### Patch Changes diff --git a/plugins/kubernetes-backend/package.json b/plugins/kubernetes-backend/package.json index c9d8733319..0e439ecd91 100644 --- a/plugins/kubernetes-backend/package.json +++ b/plugins/kubernetes-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes-backend", - "version": "0.18.3-next.1", + "version": "0.18.3", "description": "A Backstage backend plugin that integrates towards Kubernetes", "backstage": { "role": "backend-plugin", diff --git a/plugins/kubernetes-cluster/CHANGELOG.md b/plugins/kubernetes-cluster/CHANGELOG.md index 8932454b3c..a4b12a0556 100644 --- a/plugins/kubernetes-cluster/CHANGELOG.md +++ b/plugins/kubernetes-cluster/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-kubernetes-cluster +## 0.0.13 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/plugin-kubernetes-react@0.4.1 + - @backstage/plugin-kubernetes-common@0.8.1 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + ## 0.0.13-next.2 ### Patch Changes diff --git a/plugins/kubernetes-cluster/package.json b/plugins/kubernetes-cluster/package.json index 3c6e6c8f1b..af63bf4102 100644 --- a/plugins/kubernetes-cluster/package.json +++ b/plugins/kubernetes-cluster/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes-cluster", - "version": "0.0.13-next.2", + "version": "0.0.13", "description": "A Backstage plugin that shows details of Kubernetes clusters", "backstage": { "role": "frontend-plugin", diff --git a/plugins/kubernetes-common/CHANGELOG.md b/plugins/kubernetes-common/CHANGELOG.md index e4de39bfd9..a9cabafdd0 100644 --- a/plugins/kubernetes-common/CHANGELOG.md +++ b/plugins/kubernetes-common/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-kubernetes-common +## 0.8.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.0 + - @backstage/catalog-model@1.5.0 + - @backstage/types@1.1.1 + ## 0.8.0 ### Minor Changes diff --git a/plugins/kubernetes-common/package.json b/plugins/kubernetes-common/package.json index 9005c5ffe9..db94d165e4 100644 --- a/plugins/kubernetes-common/package.json +++ b/plugins/kubernetes-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes-common", - "version": "0.8.0", + "version": "0.8.1", "description": "Common functionalities for kubernetes, to be shared between kubernetes and kubernetes-backend plugin", "backstage": { "role": "common-library", diff --git a/plugins/kubernetes-node/CHANGELOG.md b/plugins/kubernetes-node/CHANGELOG.md index 4a6514a2d0..608fe97cd2 100644 --- a/plugins/kubernetes-node/CHANGELOG.md +++ b/plugins/kubernetes-node/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-kubernetes-node +## 0.1.16 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-kubernetes-common@0.8.1 + - @backstage/catalog-model@1.5.0 + - @backstage/types@1.1.1 + ## 0.1.16-next.1 ### Patch Changes diff --git a/plugins/kubernetes-node/package.json b/plugins/kubernetes-node/package.json index 461bf1bbbe..798978b5d2 100644 --- a/plugins/kubernetes-node/package.json +++ b/plugins/kubernetes-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes-node", - "version": "0.1.16-next.1", + "version": "0.1.16", "description": "Node.js library for the kubernetes plugin", "backstage": { "role": "node-library", diff --git a/plugins/kubernetes-react/CHANGELOG.md b/plugins/kubernetes-react/CHANGELOG.md index 3755d259a8..0fd0cfd07e 100644 --- a/plugins/kubernetes-react/CHANGELOG.md +++ b/plugins/kubernetes-react/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-kubernetes-react +## 0.4.1 + +### Patch Changes + +- e3cb6ab: Add a namespace label to RolloutDrawer +- 2414d86: Fix the `HTML` markup of the `FixDialog` component, `ul` and `li` are not allowed inside a `p` tag. +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/plugin-kubernetes-common@0.8.1 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 0.4.1-next.1 ### Patch Changes diff --git a/plugins/kubernetes-react/package.json b/plugins/kubernetes-react/package.json index fc6f382d3d..42ef4f7913 100644 --- a/plugins/kubernetes-react/package.json +++ b/plugins/kubernetes-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes-react", - "version": "0.4.1-next.1", + "version": "0.4.1", "description": "Web library for the kubernetes-react plugin", "backstage": { "role": "web-library", diff --git a/plugins/kubernetes/CHANGELOG.md b/plugins/kubernetes/CHANGELOG.md index a6d07dc706..fcb80b7b26 100644 --- a/plugins/kubernetes/CHANGELOG.md +++ b/plugins/kubernetes/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-kubernetes +## 0.11.12 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/plugin-kubernetes-react@0.4.1 + - @backstage/plugin-kubernetes-common@0.8.1 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + ## 0.11.12-next.2 ### Patch Changes diff --git a/plugins/kubernetes/package.json b/plugins/kubernetes/package.json index d0ee97a882..1ab92f5b3c 100644 --- a/plugins/kubernetes/package.json +++ b/plugins/kubernetes/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes", - "version": "0.11.12-next.2", + "version": "0.11.12", "description": "A Backstage plugin that integrates towards Kubernetes", "backstage": { "role": "frontend-plugin", diff --git a/plugins/notifications-backend-module-email/CHANGELOG.md b/plugins/notifications-backend-module-email/CHANGELOG.md index c536369352..4bfbfbd05d 100644 --- a/plugins/notifications-backend-module-email/CHANGELOG.md +++ b/plugins/notifications-backend-module-email/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-notifications-backend-module-email +## 0.1.3 + +### Patch Changes + +- 4e4ef2b: Move notification processor filter parsing to common package +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-notifications-common@0.0.5 + - @backstage/plugin-notifications-node@0.2.3 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/integration-aws-node@0.1.12 + - @backstage/types@1.1.1 + ## 0.1.3-next.1 ### Patch Changes diff --git a/plugins/notifications-backend-module-email/package.json b/plugins/notifications-backend-module-email/package.json index c47a65d4f4..b7107a4c6b 100644 --- a/plugins/notifications-backend-module-email/package.json +++ b/plugins/notifications-backend-module-email/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-notifications-backend-module-email", - "version": "0.1.3-next.1", + "version": "0.1.3", "description": "The email backend module for the notifications plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/notifications-backend/CHANGELOG.md b/plugins/notifications-backend/CHANGELOG.md index a4be935628..b4fe307f15 100644 --- a/plugins/notifications-backend/CHANGELOG.md +++ b/plugins/notifications-backend/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-notifications-backend +## 0.3.3 + +### Patch Changes + +- d7b8ca5: Added an option to filter notifications by topic +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-events-node@0.3.8 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/plugin-notifications-common@0.0.5 + - @backstage/plugin-notifications-node@0.2.3 + - @backstage/plugin-signals-node@0.1.8 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.3.3-next.1 ### Patch Changes diff --git a/plugins/notifications-backend/package.json b/plugins/notifications-backend/package.json index bfa1f2f0bd..abd0a1bbfe 100644 --- a/plugins/notifications-backend/package.json +++ b/plugins/notifications-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-notifications-backend", - "version": "0.3.3-next.1", + "version": "0.3.3", "backstage": { "role": "backend-plugin", "pluginId": "notifications", diff --git a/plugins/notifications-common/CHANGELOG.md b/plugins/notifications-common/CHANGELOG.md index 17231f0147..6e10272c36 100644 --- a/plugins/notifications-common/CHANGELOG.md +++ b/plugins/notifications-common/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-notifications-common +## 0.0.5 + +### Patch Changes + +- 4e4ef2b: Move notification processor filter parsing to common package +- Updated dependencies + - @backstage/config@1.2.0 + ## 0.0.4 ### Patch Changes diff --git a/plugins/notifications-common/package.json b/plugins/notifications-common/package.json index 3802d6535c..139681e6c6 100644 --- a/plugins/notifications-common/package.json +++ b/plugins/notifications-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-notifications-common", - "version": "0.0.4", + "version": "0.0.5", "description": "Common functionalities for the notifications plugin", "backstage": { "role": "common-library", diff --git a/plugins/notifications-node/CHANGELOG.md b/plugins/notifications-node/CHANGELOG.md index 69e594b513..764ee3affb 100644 --- a/plugins/notifications-node/CHANGELOG.md +++ b/plugins/notifications-node/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-notifications-node +## 0.2.3 + +### Patch Changes + +- 4e4ef2b: Move notification processor filter parsing to common package +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-notifications-common@0.0.5 + - @backstage/plugin-signals-node@0.1.8 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + ## 0.2.3-next.1 ### Patch Changes diff --git a/plugins/notifications-node/package.json b/plugins/notifications-node/package.json index f18ce420f7..04564da21e 100644 --- a/plugins/notifications-node/package.json +++ b/plugins/notifications-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-notifications-node", - "version": "0.2.3-next.1", + "version": "0.2.3", "description": "Node.js library for the notifications plugin", "backstage": { "role": "node-library", diff --git a/plugins/notifications/CHANGELOG.md b/plugins/notifications/CHANGELOG.md index 97e6c50b44..263bd9ba70 100644 --- a/plugins/notifications/CHANGELOG.md +++ b/plugins/notifications/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-notifications +## 0.2.3 + +### Patch Changes + +- 3bf0697: The toolbar on the Notifications page is hidden when there are no listed notifications. +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/plugin-notifications-common@0.0.5 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/plugin-signals-react@0.0.4 + ## 0.2.3-next.2 ### Patch Changes diff --git a/plugins/notifications/package.json b/plugins/notifications/package.json index 4ef28f9508..1575c48c5e 100644 --- a/plugins/notifications/package.json +++ b/plugins/notifications/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-notifications", - "version": "0.2.3-next.2", + "version": "0.2.3", "backstage": { "role": "frontend-plugin", "pluginId": "notifications", diff --git a/plugins/org-react/CHANGELOG.md b/plugins/org-react/CHANGELOG.md index d13578fd32..d6e117d579 100644 --- a/plugins/org-react/CHANGELOG.md +++ b/plugins/org-react/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-org-react +## 0.1.26 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + ## 0.1.26-next.2 ### Patch Changes diff --git a/plugins/org-react/package.json b/plugins/org-react/package.json index e6494eaa28..9405b38b59 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.26-next.2", + "version": "0.1.26", "backstage": { "role": "web-library", "pluginId": "org", diff --git a/plugins/org/CHANGELOG.md b/plugins/org/CHANGELOG.md index aa4bd9a93f..6d1fb352f8 100644 --- a/plugins/org/CHANGELOG.md +++ b/plugins/org/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-org +## 0.6.27 + +### Patch Changes + +- 5132d28: The `useGetEntities` hook could result in requests to `/api/catalog/entities` where the headers exceed the default maximum Node.js header size of 16KB. The hook logic has been adjusted to batch the requests. +- c307ef4: Added `relationType` property to EntityMembersListCard component that allows for display users related to a group via some other relationship aside from `memberOf`. + + Also, as a side effect, the `relationsType` property has been deprecated in favor of a more accurately named `relationAggregation` property. + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/catalog-model@1.5.0 + - @backstage/core-compat-api@0.2.7 + - @backstage/core-plugin-api@1.9.3 + ## 0.6.27-next.2 ### Patch Changes diff --git a/plugins/org/package.json b/plugins/org/package.json index c2d43bc5ed..2530ca2ea1 100644 --- a/plugins/org/package.json +++ b/plugins/org/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-org", - "version": "0.6.27-next.2", + "version": "0.6.27", "description": "A Backstage plugin that helps you create entity pages for your organization", "backstage": { "role": "frontend-plugin", diff --git a/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md b/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md index 616c6acda2..e06db25a91 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.19 + +### Patch Changes + +- ed10fd2: Internal refactor to use new `PolicyQueryUser` type. +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.0 + - @backstage/plugin-auth-node@0.4.17 + ## 0.1.19-next.1 ### 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 60e11825f4..27303483f7 100644 --- a/plugins/permission-backend-module-policy-allow-all/package.json +++ b/plugins/permission-backend-module-policy-allow-all/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-permission-backend-module-allow-all-policy", - "version": "0.1.19-next.1", + "version": "0.1.19", "description": "Allow all policy backend module for the permission plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/permission-backend/CHANGELOG.md b/plugins/permission-backend/CHANGELOG.md index 39ae10e557..e5a826f67a 100644 --- a/plugins/permission-backend/CHANGELOG.md +++ b/plugins/permission-backend/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-permission-backend +## 0.5.46 + +### Patch Changes + +- ed10fd2: The `PermissionPolicy` interface has been updated to align with the recent changes to the Backstage auth system. The second argument to the `handle` method is now of the new `PolicyQueryUser` type. This type maintains the old fields from the `BackstageIdentityResponse`, which are now all deprecated. Instead, two new fields have been added, which allows access to the same information: + + - `credentials` - A `BackstageCredentials` object, which is useful for making requests to other services on behalf of the user as part of evaluating the policy. This replaces the deprecated `token` field. See the [Auth Service documentation](https://backstage.io/docs/backend-system/core-services/auth#creating-request-tokens) for information about how to create a token using these credentials. + - `info` - A `BackstageUserInfo` object, which contains the same information as the deprecated `identity`, except for the `type` field that was redundant. + + Most existing policies can be updated by replacing the `BackstageIdentityResponse` type with `PolicyQueryUser`, which is exported from `@backstage/plugin-permission-node`, as well as replacing any occurrences of `user?.identity` with `user?.info`. + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.0 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.5.46-next.1 ### Patch Changes diff --git a/plugins/permission-backend/package.json b/plugins/permission-backend/package.json index 43a57407e1..95647ba82b 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.46-next.1", + "version": "0.5.46", "backstage": { "role": "backend-plugin", "pluginId": "permission", diff --git a/plugins/permission-common/CHANGELOG.md b/plugins/permission-common/CHANGELOG.md index e6b637a092..92a33afea2 100644 --- a/plugins/permission-common/CHANGELOG.md +++ b/plugins/permission-common/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-permission-common +## 0.8.0 + +### Minor Changes + +- f4085b8: **BREAKING**: Removed the deprecated and unused `token` option from `EvaluatorRequestOptions`. The `PermissionsClient` now has its own `PermissionClientRequestOptions` type that declares the `token` option instead. + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 0.7.14 ### Patch Changes diff --git a/plugins/permission-common/package.json b/plugins/permission-common/package.json index ee54459589..8d6f54fac0 100644 --- a/plugins/permission-common/package.json +++ b/plugins/permission-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-permission-common", - "version": "0.7.14", + "version": "0.8.0", "description": "Isomorphic types and client for Backstage permissions and authorization", "backstage": { "role": "common-library", diff --git a/plugins/permission-node/CHANGELOG.md b/plugins/permission-node/CHANGELOG.md index a63abb1d95..326dfb99d3 100644 --- a/plugins/permission-node/CHANGELOG.md +++ b/plugins/permission-node/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-permission-node +## 0.8.0 + +### Minor Changes + +- 36f91e8: **BREAKING**: Updated the `ServerPermissionClient` to match the new `PermissionsService` interface, where the deprecated `token` option has been removed and the options are now required. + +### Patch Changes + +- ed10fd2: The `PermissionPolicy` interface has been updated to align with the recent changes to the Backstage auth system. The second argument to the `handle` method is now of the new `PolicyQueryUser` type. This type maintains the old fields from the `BackstageIdentityResponse`, which are now all deprecated. Instead, two new fields have been added, which allows access to the same information: + + - `credentials` - A `BackstageCredentials` object, which is useful for making requests to other services on behalf of the user as part of evaluating the policy. This replaces the deprecated `token` field. See the [Auth Service documentation](https://backstage.io/docs/backend-system/core-services/auth#creating-request-tokens) for information about how to create a token using these credentials. + - `info` - A `BackstageUserInfo` object, which contains the same information as the deprecated `identity`, except for the `type` field that was redundant. + + Most existing policies can be updated by replacing the `BackstageIdentityResponse` type with `PolicyQueryUser`, which is exported from `@backstage/plugin-permission-node`, as well as replacing any occurrences of `user?.identity` with `user?.info`. + +- 28b2cfb: Fix invalid cross-reference in API Reference docs +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.7.33-next.1 ### Patch Changes diff --git a/plugins/permission-node/package.json b/plugins/permission-node/package.json index db3c067088..4bbf4d5faf 100644 --- a/plugins/permission-node/package.json +++ b/plugins/permission-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-permission-node", - "version": "0.7.33-next.1", + "version": "0.8.0", "description": "Common permission and authorization utilities for backend plugins", "backstage": { "role": "node-library", diff --git a/plugins/permission-react/CHANGELOG.md b/plugins/permission-react/CHANGELOG.md index 1eb951e625..2b19b7e849 100644 --- a/plugins/permission-react/CHANGELOG.md +++ b/plugins/permission-react/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-permission-react +## 0.4.24 + +### Patch Changes + +- 28b2cfb: Improve API Reference documentation +- Updated dependencies + - @backstage/plugin-permission-common@0.8.0 + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + ## 0.4.23 ### Patch Changes diff --git a/plugins/permission-react/package.json b/plugins/permission-react/package.json index 9ebb13e633..c119be8eb9 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.23", + "version": "0.4.24", "backstage": { "role": "web-library", "pluginId": "permission", diff --git a/plugins/proxy-backend/CHANGELOG.md b/plugins/proxy-backend/CHANGELOG.md index a6c1ef02d2..30cacb1d02 100644 --- a/plugins/proxy-backend/CHANGELOG.md +++ b/plugins/proxy-backend/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-proxy-backend +## 0.5.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + ## 0.5.3-next.1 ### Patch Changes diff --git a/plugins/proxy-backend/package.json b/plugins/proxy-backend/package.json index 23acc935f3..2e7bd08550 100644 --- a/plugins/proxy-backend/package.json +++ b/plugins/proxy-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-proxy-backend", - "version": "0.5.3-next.1", + "version": "0.5.3", "description": "A Backstage backend plugin that helps you set up proxy endpoints in the backend", "backstage": { "role": "backend-plugin", diff --git a/plugins/scaffolder-backend-module-azure/CHANGELOG.md b/plugins/scaffolder-backend-module-azure/CHANGELOG.md index c634d8c8ca..e386b5d9b8 100644 --- a/plugins/scaffolder-backend-module-azure/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-azure/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-scaffolder-backend-module-azure +## 0.1.14 + +### Patch Changes + +- 661b354: Fixed a bug where the `RepoUrlPicker` would still require the `owner` field for `azure` +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.1.14-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-azure/package.json b/plugins/scaffolder-backend-module-azure/package.json index c0e00e8ffe..205beae578 100644 --- a/plugins/scaffolder-backend-module-azure/package.json +++ b/plugins/scaffolder-backend-module-azure/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-azure", - "version": "0.1.14-next.1", + "version": "0.1.14", "description": "The azure module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/CHANGELOG.md b/plugins/scaffolder-backend-module-bitbucket-cloud/CHANGELOG.md index 4e1e2b9531..c8c79a302b 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-scaffolder-backend-module-bitbucket-cloud +## 0.1.12 + +### Patch Changes + +- b5deed0: Add support for `autocomplete` handler to provide autocomplete options for `RepoUrlPicker` +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/plugin-bitbucket-cloud-common@0.2.21 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.1.12-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/package.json b/plugins/scaffolder-backend-module-bitbucket-cloud/package.json index 5ce826ff1a..67f275462b 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/package.json +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-bitbucket-cloud", - "version": "0.1.12-next.1", + "version": "0.1.12", "description": "The Bitbucket Cloud module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-bitbucket-server/CHANGELOG.md b/plugins/scaffolder-backend-module-bitbucket-server/CHANGELOG.md index 3443242e91..5d2a0754cd 100644 --- a/plugins/scaffolder-backend-module-bitbucket-server/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-bitbucket-server/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-scaffolder-backend-module-bitbucket-server +## 0.1.12 + +### Patch Changes + +- 6a4ad4e: Instead of using hardcoded `targetBranch` now fetch the default branch from Bitbucket repository. + This prevents from errors when no `targetBranch` is provided and the default repository branch is different from `master`, for example: `main`. +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.1.12-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-bitbucket-server/package.json b/plugins/scaffolder-backend-module-bitbucket-server/package.json index b396faa5e5..a33bf90040 100644 --- a/plugins/scaffolder-backend-module-bitbucket-server/package.json +++ b/plugins/scaffolder-backend-module-bitbucket-server/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-bitbucket-server", - "version": "0.1.12-next.1", + "version": "0.1.12", "description": "The Bitbucket Server module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-bitbucket/CHANGELOG.md b/plugins/scaffolder-backend-module-bitbucket/CHANGELOG.md index 35f5382652..414f8b7bd8 100644 --- a/plugins/scaffolder-backend-module-bitbucket/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-bitbucket/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-scaffolder-backend-module-bitbucket +## 0.2.12 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.1.12 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.1.12 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.2.12-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-bitbucket/package.json b/plugins/scaffolder-backend-module-bitbucket/package.json index bca6e94878..95d92c39b8 100644 --- a/plugins/scaffolder-backend-module-bitbucket/package.json +++ b/plugins/scaffolder-backend-module-bitbucket/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-bitbucket", - "version": "0.2.12-next.1", + "version": "0.2.12", "description": "The bitbucket module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md b/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md index b3c7bfbe36..1613f1881c 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.23 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.2.23-next.1 ### 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 f607696136..9fe6781eff 100644 --- a/plugins/scaffolder-backend-module-confluence-to-markdown/package.json +++ b/plugins/scaffolder-backend-module-confluence-to-markdown/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-confluence-to-markdown", - "version": "0.2.23-next.1", + "version": "0.2.23", "description": "The confluence-to-markdown module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md b/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md index 5854e9ff47..f2dc2a822d 100644 --- a/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-scaffolder-backend-module-cookiecutter +## 0.2.46 + +### Patch Changes + +- 0ac124b: Updated configuration instructions +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 0.2.46-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-cookiecutter/package.json b/plugins/scaffolder-backend-module-cookiecutter/package.json index 43a7e348a4..0b0036ee5a 100644 --- a/plugins/scaffolder-backend-module-cookiecutter/package.json +++ b/plugins/scaffolder-backend-module-cookiecutter/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-cookiecutter", - "version": "0.2.46-next.1", + "version": "0.2.46", "description": "A module for the scaffolder backend that lets you template projects using cookiecutter", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-gcp/CHANGELOG.md b/plugins/scaffolder-backend-module-gcp/CHANGELOG.md index e32c2ef08f..51dd92b2cf 100644 --- a/plugins/scaffolder-backend-module-gcp/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-gcp/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-scaffolder-backend-module-gcp +## 0.1.0 + +### Minor Changes + +- 0b52438: Serialization of the scaffolder workspace into GCP bucket + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.1.0-next.3 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-gcp/package.json b/plugins/scaffolder-backend-module-gcp/package.json index c441acb21a..ae64d1de61 100644 --- a/plugins/scaffolder-backend-module-gcp/package.json +++ b/plugins/scaffolder-backend-module-gcp/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-gcp", - "version": "0.1.0-next.3", + "version": "0.1.0", "description": "The GCP Bucket module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-gerrit/CHANGELOG.md b/plugins/scaffolder-backend-module-gerrit/CHANGELOG.md index dd26e1d5a8..7b95a80811 100644 --- a/plugins/scaffolder-backend-module-gerrit/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-gerrit/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-scaffolder-backend-module-gerrit +## 0.1.14 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.1.14-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-gerrit/package.json b/plugins/scaffolder-backend-module-gerrit/package.json index 31a30c3f7e..96c069ea97 100644 --- a/plugins/scaffolder-backend-module-gerrit/package.json +++ b/plugins/scaffolder-backend-module-gerrit/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-gerrit", - "version": "0.1.14-next.1", + "version": "0.1.14", "description": "The gerrit module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-gitea/CHANGELOG.md b/plugins/scaffolder-backend-module-gitea/CHANGELOG.md index f3ceb7ce8c..4c03220562 100644 --- a/plugins/scaffolder-backend-module-gitea/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-gitea/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-scaffolder-backend-module-gitea +## 0.1.12 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.1.12-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-gitea/package.json b/plugins/scaffolder-backend-module-gitea/package.json index 3cacbc66db..69a84f43e7 100644 --- a/plugins/scaffolder-backend-module-gitea/package.json +++ b/plugins/scaffolder-backend-module-gitea/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-gitea", - "version": "0.1.12-next.1", + "version": "0.1.12", "description": "The gitea module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-github/CHANGELOG.md b/plugins/scaffolder-backend-module-github/CHANGELOG.md index 2d3c6ff0f2..680cb0469d 100644 --- a/plugins/scaffolder-backend-module-github/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-github/CHANGELOG.md @@ -1,5 +1,31 @@ # @backstage/plugin-scaffolder-backend-module-github +## 0.4.0 + +### Minor Changes + +- 70c4b36: Adds support for custom tag policies when creating GitHub environments. + +### Patch Changes + +- ccfc9d1: Fixed bug resulting from missing required owner and repo arguments in `getEnvironmentPublicKey` in action `github:environment:create`. + + Adding environment secrets now works as expected. + +- 141f366: Added action to enable GitHub Pages on a repo +- 4410fed: Fixed issue with octokit call missing owner and repo when creating environment variables and secrets using github:environment:create action +- dfaa28d: Adds `requireLastPushApproval` input property to configure Branch Protection Settings in `github:publish` action + + Adds `requireLastPushApproval` input property to configure Branch Protection Settings in `github:repo:push` action + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.4.0-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-github/package.json b/plugins/scaffolder-backend-module-github/package.json index 500ec86f9f..7732c7c11a 100644 --- a/plugins/scaffolder-backend-module-github/package.json +++ b/plugins/scaffolder-backend-module-github/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-github", - "version": "0.4.0-next.1", + "version": "0.4.0", "description": "The github module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md b/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md index 0c8f0529a6..60e7f1bccf 100644 --- a/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-scaffolder-backend-module-gitlab +## 0.4.4 + +### Patch Changes + +- 0ac124b: Updated configuration instructions +- 2fb0eb8: Added support for passing `variables` to `gitlab:pipeline:trigger` +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.4.4-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-gitlab/package.json b/plugins/scaffolder-backend-module-gitlab/package.json index 499cfd6872..8228a3ec0f 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.4.4-next.1", + "version": "0.4.4", "backstage": { "role": "backend-plugin-module", "pluginId": "scaffolder", diff --git a/plugins/scaffolder-backend-module-notifications/CHANGELOG.md b/plugins/scaffolder-backend-module-notifications/CHANGELOG.md index 6371124957..db52ded0c8 100644 --- a/plugins/scaffolder-backend-module-notifications/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-notifications/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-scaffolder-backend-module-notifications +## 0.0.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/plugin-notifications-common@0.0.5 + - @backstage/plugin-notifications-node@0.2.3 + ## 0.0.5-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-notifications/package.json b/plugins/scaffolder-backend-module-notifications/package.json index 7c983c36ce..68e177abfa 100644 --- a/plugins/scaffolder-backend-module-notifications/package.json +++ b/plugins/scaffolder-backend-module-notifications/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-notifications", - "version": "0.0.5-next.1", + "version": "0.0.5", "description": "The notifications backend module for the scaffolder plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-rails/CHANGELOG.md b/plugins/scaffolder-backend-module-rails/CHANGELOG.md index 0db7584509..cd34152910 100644 --- a/plugins/scaffolder-backend-module-rails/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-rails/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-scaffolder-backend-module-rails +## 0.4.39 + +### Patch Changes + +- 0ac124b: Updated configuration instructions +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 0.4.39-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-rails/package.json b/plugins/scaffolder-backend-module-rails/package.json index c15815d2fa..496174d510 100644 --- a/plugins/scaffolder-backend-module-rails/package.json +++ b/plugins/scaffolder-backend-module-rails/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-rails", - "version": "0.4.39-next.1", + "version": "0.4.39", "description": "A module for the scaffolder backend that lets you template projects using Rails", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-sentry/CHANGELOG.md b/plugins/scaffolder-backend-module-sentry/CHANGELOG.md index 29e8c17b04..113a63222f 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.30 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.1.30-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-sentry/package.json b/plugins/scaffolder-backend-module-sentry/package.json index c0866f979d..264736692a 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.30-next.1", + "version": "0.1.30", "backstage": { "role": "backend-plugin-module", "pluginId": "scaffolder", diff --git a/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md b/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md index 4e99b51284..53d2369d85 100644 --- a/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-scaffolder-backend-module-yeoman +## 0.3.6 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/plugin-scaffolder-node-test-utils@0.1.9 + - @backstage/types@1.1.1 + ## 0.3.6-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-yeoman/package.json b/plugins/scaffolder-backend-module-yeoman/package.json index 76158fdc01..5c65315e22 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.3.6-next.1", + "version": "0.3.6", "backstage": { "role": "backend-plugin-module", "pluginId": "scaffolder", diff --git a/plugins/scaffolder-backend/CHANGELOG.md b/plugins/scaffolder-backend/CHANGELOG.md index a4df9e72e9..27e4b4465e 100644 --- a/plugins/scaffolder-backend/CHANGELOG.md +++ b/plugins/scaffolder-backend/CHANGELOG.md @@ -1,5 +1,45 @@ # @backstage/plugin-scaffolder-backend +## 1.23.0 + +### Minor Changes + +- b5deed0: Add support for `autocomplete` extension point to provide additional `autocomplete` handlers +- 0b52438: Serialization of the scaffolder workspace into GCP bucket + +### Patch Changes + +- b9451dd: Updated `catalog:write` scaffolder action to show correct file path location in log message +- ff1bb4c: Added a documentation how to use checkpoints +- da90cce: Updated dependency `esbuild` to `^0.21.0`. +- 62d1fe3: Fix user entity not being fetched for scaffolder dry runner +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-scaffolder-backend-module-github@0.4.0 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.0 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.4.4 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.1.12 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-backend-module-azure@0.1.14 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.1.12 + - @backstage/plugin-bitbucket-cloud-common@0.2.21 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.20 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.2.12 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.1.14 + - @backstage/plugin-scaffolder-backend-module-gitea@0.1.12 + - @backstage/plugin-scaffolder-common@1.5.4 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 1.23.0-next.2 ### Patch Changes diff --git a/plugins/scaffolder-backend/package.json b/plugins/scaffolder-backend/package.json index 10d827762e..c86a048d46 100644 --- a/plugins/scaffolder-backend/package.json +++ b/plugins/scaffolder-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend", - "version": "1.23.0-next.2", + "version": "1.23.0", "description": "The Backstage backend plugin that helps you create new things", "backstage": { "role": "backend-plugin", diff --git a/plugins/scaffolder-common/CHANGELOG.md b/plugins/scaffolder-common/CHANGELOG.md index 12f3f9e235..914faf70f3 100644 --- a/plugins/scaffolder-common/CHANGELOG.md +++ b/plugins/scaffolder-common/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-scaffolder-common +## 1.5.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.0 + - @backstage/catalog-model@1.5.0 + - @backstage/types@1.1.1 + ## 1.5.3 ### Patch Changes diff --git a/plugins/scaffolder-common/package.json b/plugins/scaffolder-common/package.json index 3e56510daf..d86f0d67c0 100644 --- a/plugins/scaffolder-common/package.json +++ b/plugins/scaffolder-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-common", - "version": "1.5.3", + "version": "1.5.4", "description": "Common functionalities for the scaffolder, to be shared between scaffolder and scaffolder-backend plugin", "backstage": { "role": "common-library", diff --git a/plugins/scaffolder-node-test-utils/CHANGELOG.md b/plugins/scaffolder-node-test-utils/CHANGELOG.md index 9104fbcb26..7d578a2b14 100644 --- a/plugins/scaffolder-node-test-utils/CHANGELOG.md +++ b/plugins/scaffolder-node-test-utils/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-scaffolder-node-test-utils +## 0.1.9 + +### Patch Changes + +- 54429b5: Filename and imports correction for mockActionContext.ts +- Updated dependencies + - @backstage/backend-test-utils@0.4.4 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-scaffolder-node@0.4.8 + - @backstage/types@1.1.1 + ## 0.1.9-next.1 ### Patch Changes diff --git a/plugins/scaffolder-node-test-utils/package.json b/plugins/scaffolder-node-test-utils/package.json index d361d0ae1d..827b654b4e 100644 --- a/plugins/scaffolder-node-test-utils/package.json +++ b/plugins/scaffolder-node-test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-node-test-utils", - "version": "0.1.9-next.1", + "version": "0.1.9", "backstage": { "role": "node-library", "pluginId": "scaffolder", diff --git a/plugins/scaffolder-node/CHANGELOG.md b/plugins/scaffolder-node/CHANGELOG.md index f67c8c8cda..59658dcb11 100644 --- a/plugins/scaffolder-node/CHANGELOG.md +++ b/plugins/scaffolder-node/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-scaffolder-node +## 0.4.8 + +### Patch Changes + +- 661b354: Fixed a bug where the `RepoUrlPicker` would still require the `owner` field for `azure` +- b5deed0: Add support for `autocomplete` extension point to provide additional `autocomplete` handlers +- 0b52438: Serialization of the scaffolder workspace into GCP bucket +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/integration@1.13.0 + - @backstage/plugin-scaffolder-common@1.5.4 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 0.4.8-next.1 ### Patch Changes diff --git a/plugins/scaffolder-node/package.json b/plugins/scaffolder-node/package.json index 079eebfb00..07e468620b 100644 --- a/plugins/scaffolder-node/package.json +++ b/plugins/scaffolder-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-node", - "version": "0.4.8-next.1", + "version": "0.4.8", "description": "The plugin-scaffolder-node module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "node-library", diff --git a/plugins/scaffolder-react/CHANGELOG.md b/plugins/scaffolder-react/CHANGELOG.md index a1ed542bd5..68f94ac3fd 100644 --- a/plugins/scaffolder-react/CHANGELOG.md +++ b/plugins/scaffolder-react/CHANGELOG.md @@ -1,5 +1,31 @@ # @backstage/plugin-scaffolder-react +## 1.10.0 + +### Minor Changes + +- 354e68c: Improve validation error display text in scaffolder +- b5deed0: Add support for `bitbucketCloud` autocomplete in `RepoUrlPicker` + +### Patch Changes + +- cc81579: Updated dependency `@rjsf/utils` to `5.18.5`. + Updated dependency `@rjsf/core` to `5.18.5`. + Updated dependency `@rjsf/material-ui` to `5.18.5`. + Updated dependency `@rjsf/validator-ajv8` to `5.18.5`. +- 4d7e11f: disables rendering of output box if no output is returned +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/plugin-scaffolder-common@1.5.4 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + ## 1.10.0-next.2 ### Patch Changes diff --git a/plugins/scaffolder-react/package.json b/plugins/scaffolder-react/package.json index 36ee0870fc..f2d7d44a01 100644 --- a/plugins/scaffolder-react/package.json +++ b/plugins/scaffolder-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-react", - "version": "1.10.0-next.2", + "version": "1.10.0", "description": "A frontend library that helps other Backstage plugins interact with the Scaffolder", "backstage": { "role": "web-library", diff --git a/plugins/scaffolder/CHANGELOG.md b/plugins/scaffolder/CHANGELOG.md index 3c4cfe54ab..2da2802808 100644 --- a/plugins/scaffolder/CHANGELOG.md +++ b/plugins/scaffolder/CHANGELOG.md @@ -1,5 +1,39 @@ # @backstage/plugin-scaffolder +## 1.23.0 + +### Minor Changes + +- 52b6db0: Use virtualization with `EntityPicker` as done earlier with `MultiEntityPicker` to fix performance issues with large data sets. `VirtualizedListbox` extracted into reusable component. +- 3583ce5: Use virtualization with `MultiEntityPicker`. Fixes performance issues with large data sets. +- b5deed0: Add support for `bitbucketCloud` autocomplete in `RepoUrlPicker` + +### Patch Changes + +- 4d7e11f: enable resizing of the task log stream viewer +- 661b354: Fixed a bug where the `RepoUrlPicker` would still require the `owner` field for `azure` +- cc81579: Updated dependency `@rjsf/utils` to `5.18.5`. + Updated dependency `@rjsf/core` to `5.18.5`. + Updated dependency `@rjsf/material-ui` to `5.18.5`. + Updated dependency `@rjsf/validator-ajv8` to `5.18.5`. +- 89c44b3: Support `catalogFilter` array on `OwnedEntityPicker` +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/integration@1.13.0 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/plugin-scaffolder-react@1.10.0 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-scaffolder-common@1.5.4 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/integration-react@1.1.29 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-compat-api@0.2.7 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 1.22.1-next.2 ### Patch Changes diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index aaa681d174..5cc587fe4d 100644 --- a/plugins/scaffolder/package.json +++ b/plugins/scaffolder/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder", - "version": "1.22.1-next.2", + "version": "1.23.0", "description": "The Backstage plugin that helps you create new things", "backstage": { "role": "frontend-plugin", diff --git a/plugins/search-backend-module-catalog/CHANGELOG.md b/plugins/search-backend-module-catalog/CHANGELOG.md index d064814ecb..29304c6cfd 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.28 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-search-backend-node@1.2.27 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-search-common@1.2.13 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.1.28-next.1 ### Patch Changes diff --git a/plugins/search-backend-module-catalog/package.json b/plugins/search-backend-module-catalog/package.json index 0f45f3ce43..6ec054f10d 100644 --- a/plugins/search-backend-module-catalog/package.json +++ b/plugins/search-backend-module-catalog/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-backend-module-catalog", - "version": "0.1.28-next.1", + "version": "0.1.28", "description": "A module for the search backend that exports catalog modules", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/search-backend-module-elasticsearch/CHANGELOG.md b/plugins/search-backend-module-elasticsearch/CHANGELOG.md index f0628d0254..d561b1127a 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.5.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-search-backend-node@1.2.27 + - @backstage/plugin-search-common@1.2.13 + - @backstage/config@1.2.0 + - @backstage/integration-aws-node@0.1.12 + ## 1.5.3-next.1 ### Patch Changes diff --git a/plugins/search-backend-module-elasticsearch/package.json b/plugins/search-backend-module-elasticsearch/package.json index 9cb61ee97b..d96b4c924d 100644 --- a/plugins/search-backend-module-elasticsearch/package.json +++ b/plugins/search-backend-module-elasticsearch/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-backend-module-elasticsearch", - "version": "1.5.3-next.1", + "version": "1.5.3", "description": "A module for the search backend that implements search using ElasticSearch", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/search-backend-module-explore/CHANGELOG.md b/plugins/search-backend-module-explore/CHANGELOG.md index 888be119be..f5b60fa87e 100644 --- a/plugins/search-backend-module-explore/CHANGELOG.md +++ b/plugins/search-backend-module-explore/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-search-backend-module-explore +## 0.1.28 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-search-backend-node@1.2.27 + - @backstage/plugin-search-common@1.2.13 + - @backstage/config@1.2.0 + ## 0.1.28-next.1 ### Patch Changes diff --git a/plugins/search-backend-module-explore/package.json b/plugins/search-backend-module-explore/package.json index f37c4d55d3..9fd252df66 100644 --- a/plugins/search-backend-module-explore/package.json +++ b/plugins/search-backend-module-explore/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-backend-module-explore", - "version": "0.1.28-next.1", + "version": "0.1.28", "description": "A module for the search backend that exports explore modules", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/search-backend-module-pg/CHANGELOG.md b/plugins/search-backend-module-pg/CHANGELOG.md index 3fe18213bb..c19c797bde 100644 --- a/plugins/search-backend-module-pg/CHANGELOG.md +++ b/plugins/search-backend-module-pg/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-search-backend-module-pg +## 0.5.32 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-app-api@0.8.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-search-backend-node@1.2.27 + - @backstage/plugin-search-common@1.2.13 + - @backstage/config@1.2.0 + ## 0.5.32-next.1 ### Patch Changes diff --git a/plugins/search-backend-module-pg/package.json b/plugins/search-backend-module-pg/package.json index ec6782535f..8bdcf14306 100644 --- a/plugins/search-backend-module-pg/package.json +++ b/plugins/search-backend-module-pg/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-backend-module-pg", - "version": "0.5.32-next.1", + "version": "0.5.32", "description": "A module for the search backend that implements search using PostgreSQL", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/search-backend-module-stack-overflow-collator/CHANGELOG.md b/plugins/search-backend-module-stack-overflow-collator/CHANGELOG.md index 96214102b7..6c86337062 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.15 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-search-backend-node@1.2.27 + - @backstage/plugin-search-common@1.2.13 + - @backstage/config@1.2.0 + ## 0.1.15-next.1 ### 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 dd09d75b11..4d06f928a0 100644 --- a/plugins/search-backend-module-stack-overflow-collator/package.json +++ b/plugins/search-backend-module-stack-overflow-collator/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-backend-module-stack-overflow-collator", - "version": "0.1.15-next.1", + "version": "0.1.15", "description": "A module for the search backend that exports stack overflow modules", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/search-backend-module-techdocs/CHANGELOG.md b/plugins/search-backend-module-techdocs/CHANGELOG.md index 706d178601..2c41ecda1f 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.27 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-techdocs-node@1.12.8 + - @backstage/plugin-catalog-node@1.12.4 + - @backstage/plugin-search-backend-node@1.2.27 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-search-common@1.2.13 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + ## 0.1.27-next.1 ### Patch Changes diff --git a/plugins/search-backend-module-techdocs/package.json b/plugins/search-backend-module-techdocs/package.json index b26065cc60..a04f64756b 100644 --- a/plugins/search-backend-module-techdocs/package.json +++ b/plugins/search-backend-module-techdocs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-backend-module-techdocs", - "version": "0.1.27-next.1", + "version": "0.1.27", "description": "A module for the search backend that exports techdocs modules", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/search-backend-node/CHANGELOG.md b/plugins/search-backend-node/CHANGELOG.md index 26cd8e91eb..f43f3c4009 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.27 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/backend-tasks@0.5.27 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-search-common@1.2.13 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 1.2.27-next.1 ### Patch Changes diff --git a/plugins/search-backend-node/package.json b/plugins/search-backend-node/package.json index e8cc89d117..a236eff6c0 100644 --- a/plugins/search-backend-node/package.json +++ b/plugins/search-backend-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-backend-node", - "version": "1.2.27-next.1", + "version": "1.2.27", "description": "A library for Backstage backend plugins that want to interact with the search backend plugin", "backstage": { "role": "node-library", diff --git a/plugins/search-backend/CHANGELOG.md b/plugins/search-backend/CHANGELOG.md index 2de90e3960..eb391c6bba 100644 --- a/plugins/search-backend/CHANGELOG.md +++ b/plugins/search-backend/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-search-backend +## 1.5.14 + +### Patch Changes + +- 343f656: The `AuthorizedSearchEngine` will now ignore the deprecated `token` option, and treat it as an unauthorized request. This will not have any effect in practice, since credentials are always provided by the router. +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-defaults@0.4.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.0 + - @backstage/backend-openapi-utils@0.1.15 + - @backstage/plugin-search-backend-node@1.2.27 + - @backstage/plugin-search-common@1.2.13 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 1.5.14-next.1 ### Patch Changes diff --git a/plugins/search-backend/package.json b/plugins/search-backend/package.json index 8d266c63a8..a0e7b48f5b 100644 --- a/plugins/search-backend/package.json +++ b/plugins/search-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-backend", - "version": "1.5.14-next.1", + "version": "1.5.14", "description": "The Backstage backend plugin that provides your backstage app with search", "backstage": { "role": "backend-plugin", diff --git a/plugins/search-common/CHANGELOG.md b/plugins/search-common/CHANGELOG.md index e034c62315..5b163eab0d 100644 --- a/plugins/search-common/CHANGELOG.md +++ b/plugins/search-common/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-search-common +## 1.2.13 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.0 + - @backstage/types@1.1.1 + ## 1.2.12 ### Patch Changes diff --git a/plugins/search-common/package.json b/plugins/search-common/package.json index 61edfd13f3..8d0f4e9585 100644 --- a/plugins/search-common/package.json +++ b/plugins/search-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-common", - "version": "1.2.12", + "version": "1.2.13", "description": "Common functionalities for Search, to be shared between various search-enabled plugins", "backstage": { "role": "common-library", diff --git a/plugins/search-react/CHANGELOG.md b/plugins/search-react/CHANGELOG.md index 494ce07772..04d8bf312a 100644 --- a/plugins/search-react/CHANGELOG.md +++ b/plugins/search-react/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-search-react +## 1.7.13 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/plugin-search-common@1.2.13 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + ## 1.7.13-next.1 ### Patch Changes diff --git a/plugins/search-react/package.json b/plugins/search-react/package.json index a0701e1f3b..b5c17c369a 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.13-next.1", + "version": "1.7.13", "backstage": { "role": "web-library", "pluginId": "search", diff --git a/plugins/search/CHANGELOG.md b/plugins/search/CHANGELOG.md index a6cab671b5..bce322e95a 100644 --- a/plugins/search/CHANGELOG.md +++ b/plugins/search/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-search +## 1.4.14 + +### Patch Changes + +- 1117aba: Update deps in search api extension to include fetch api +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/plugin-search-common@1.2.13 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/plugin-search-react@1.7.13 + - @backstage/core-compat-api@0.2.7 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + ## 1.4.14-next.2 ### Patch Changes diff --git a/plugins/search/package.json b/plugins/search/package.json index ad8210df4c..56271eca58 100644 --- a/plugins/search/package.json +++ b/plugins/search/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search", - "version": "1.4.14-next.2", + "version": "1.4.14", "description": "The Backstage plugin that provides your backstage app with search", "backstage": { "role": "frontend-plugin", diff --git a/plugins/signals-backend/CHANGELOG.md b/plugins/signals-backend/CHANGELOG.md index aaf4a0c15f..e0525a0e78 100644 --- a/plugins/signals-backend/CHANGELOG.md +++ b/plugins/signals-backend/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-signals-backend +## 0.1.8 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-events-node@0.3.8 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/plugin-signals-node@0.1.8 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + ## 0.1.8-next.1 ### Patch Changes diff --git a/plugins/signals-backend/package.json b/plugins/signals-backend/package.json index 0bded11c2e..1e0ac41fcb 100644 --- a/plugins/signals-backend/package.json +++ b/plugins/signals-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-signals-backend", - "version": "0.1.8-next.1", + "version": "0.1.8", "backstage": { "role": "backend-plugin", "pluginId": "signals", diff --git a/plugins/signals-node/CHANGELOG.md b/plugins/signals-node/CHANGELOG.md index cbcdea7a98..0353548fe5 100644 --- a/plugins/signals-node/CHANGELOG.md +++ b/plugins/signals-node/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-signals-node +## 0.1.8 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-events-node@0.3.8 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + ## 0.1.8-next.1 ### Patch Changes diff --git a/plugins/signals-node/package.json b/plugins/signals-node/package.json index 033dcb8246..1cea62c21b 100644 --- a/plugins/signals-node/package.json +++ b/plugins/signals-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-signals-node", - "version": "0.1.8-next.1", + "version": "0.1.8", "description": "Node.js library for the signals plugin", "backstage": { "role": "node-library", diff --git a/plugins/signals/CHANGELOG.md b/plugins/signals/CHANGELOG.md index 9ccdff8b97..a4a7daec35 100644 --- a/plugins/signals/CHANGELOG.md +++ b/plugins/signals/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-signals +## 0.0.8 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/plugin-signals-react@0.0.4 + ## 0.0.8-next.1 ### Patch Changes diff --git a/plugins/signals/package.json b/plugins/signals/package.json index 58b82fab7a..88ca252c1f 100644 --- a/plugins/signals/package.json +++ b/plugins/signals/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-signals", - "version": "0.0.8-next.1", + "version": "0.0.8", "backstage": { "role": "frontend-plugin", "pluginId": "signals", diff --git a/plugins/techdocs-addons-test-utils/CHANGELOG.md b/plugins/techdocs-addons-test-utils/CHANGELOG.md index 5b247addab..3135cc5ffd 100644 --- a/plugins/techdocs-addons-test-utils/CHANGELOG.md +++ b/plugins/techdocs-addons-test-utils/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-techdocs-addons-test-utils +## 1.0.35 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs@1.10.7 + - @backstage/plugin-techdocs-react@1.2.6 + - @backstage/core-app-api@1.14.0 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/plugin-catalog@1.21.1 + - @backstage/test-utils@1.5.8 + - @backstage/integration-react@1.1.29 + - @backstage/plugin-search-react@1.7.13 + - @backstage/core-plugin-api@1.9.3 + ## 1.0.35-next.2 ### Patch Changes diff --git a/plugins/techdocs-addons-test-utils/package.json b/plugins/techdocs-addons-test-utils/package.json index 966308ee94..57cd4d06a6 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.35-next.2", + "version": "1.0.35", "backstage": { "role": "web-library", "pluginId": "techdocs-addons", diff --git a/plugins/techdocs-backend/CHANGELOG.md b/plugins/techdocs-backend/CHANGELOG.md index d50062c744..571b0d68fc 100644 --- a/plugins/techdocs-backend/CHANGELOG.md +++ b/plugins/techdocs-backend/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-techdocs-backend +## 1.10.9 + +### Patch Changes + +- 9ecf5fd: Adds extension point for publishers to the techdocs backend +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-techdocs-node@1.12.8 + - @backstage/integration@1.13.0 + - @backstage/plugin-search-backend-module-techdocs@0.1.27 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 1.10.9-next.1 ### Patch Changes diff --git a/plugins/techdocs-backend/package.json b/plugins/techdocs-backend/package.json index 1533cdc3fe..ce0df2ca78 100644 --- a/plugins/techdocs-backend/package.json +++ b/plugins/techdocs-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs-backend", - "version": "1.10.9-next.1", + "version": "1.10.9", "description": "The Backstage backend plugin that renders technical documentation for your components", "backstage": { "role": "backend-plugin", diff --git a/plugins/techdocs-module-addons-contrib/CHANGELOG.md b/plugins/techdocs-module-addons-contrib/CHANGELOG.md index 2cc99a8158..4072d96d9f 100644 --- a/plugins/techdocs-module-addons-contrib/CHANGELOG.md +++ b/plugins/techdocs-module-addons-contrib/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-techdocs-module-addons-contrib +## 1.1.12 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs-react@1.2.6 + - @backstage/core-components@0.14.9 + - @backstage/integration@1.13.0 + - @backstage/integration-react@1.1.29 + - @backstage/core-plugin-api@1.9.3 + ## 1.1.12-next.1 ### Patch Changes diff --git a/plugins/techdocs-module-addons-contrib/package.json b/plugins/techdocs-module-addons-contrib/package.json index f68df2a883..3c226f6a50 100644 --- a/plugins/techdocs-module-addons-contrib/package.json +++ b/plugins/techdocs-module-addons-contrib/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs-module-addons-contrib", - "version": "1.1.12-next.1", + "version": "1.1.12", "description": "Plugin module for contributed TechDocs Addons", "backstage": { "role": "frontend-plugin-module", diff --git a/plugins/techdocs-node/CHANGELOG.md b/plugins/techdocs-node/CHANGELOG.md index 99240bd9d4..d392e3e662 100644 --- a/plugins/techdocs-node/CHANGELOG.md +++ b/plugins/techdocs-node/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-techdocs-node +## 1.12.8 + +### Patch Changes + +- 9ecf5fd: Adds extension point for publishers to the techdocs backend +- 4c4d077: Bumps default version of techdocs docker image to latest +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/integration@1.13.0 + - @backstage/plugin-search-common@1.2.13 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration-aws-node@0.1.12 + ## 1.12.8-next.1 ### Patch Changes diff --git a/plugins/techdocs-node/package.json b/plugins/techdocs-node/package.json index 70d10aeed4..572b76e052 100644 --- a/plugins/techdocs-node/package.json +++ b/plugins/techdocs-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs-node", - "version": "1.12.8-next.1", + "version": "1.12.8", "description": "Common node.js functionalities for TechDocs, to be shared between techdocs-backend plugin and techdocs-cli", "backstage": { "role": "node-library", diff --git a/plugins/techdocs-react/CHANGELOG.md b/plugins/techdocs-react/CHANGELOG.md index 97677352df..5c9bd0004f 100644 --- a/plugins/techdocs-react/CHANGELOG.md +++ b/plugins/techdocs-react/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-techdocs-react +## 1.2.6 + +### Patch Changes + +- 8ac9ce5: Resolved the issue where changes in TechDoc add-ons, including the TextSize add-on, were not reapplying during navigation +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/version-bridge@1.0.8 + ## 1.2.6-next.1 ### Patch Changes diff --git a/plugins/techdocs-react/package.json b/plugins/techdocs-react/package.json index 1686b176ca..e65079b212 100644 --- a/plugins/techdocs-react/package.json +++ b/plugins/techdocs-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs-react", - "version": "1.2.6-next.1", + "version": "1.2.6", "description": "Shared frontend utilities for TechDocs and Addons", "backstage": { "role": "web-library", diff --git a/plugins/techdocs/CHANGELOG.md b/plugins/techdocs/CHANGELOG.md index 34dc9a310f..08a841f25c 100644 --- a/plugins/techdocs/CHANGELOG.md +++ b/plugins/techdocs/CHANGELOG.md @@ -1,5 +1,30 @@ # @backstage/plugin-techdocs +## 1.10.7 + +### Patch Changes + +- 8fc2622: Fixed an issue that was causing techdocs pages unnecessarily re-render on navigate. +- 6fa652c: Improve default sorting of docs table +- 605b691: Allow for searching TechDocs by entity title +- 60caa92: Fix double scrollbar bug in reader +- Updated dependencies + - @backstage/plugin-techdocs-react@1.2.6 + - @backstage/core-components@0.14.9 + - @backstage/integration@1.13.0 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/plugin-search-common@1.2.13 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/integration-react@1.1.29 + - @backstage/plugin-auth-react@0.1.4 + - @backstage/plugin-search-react@1.7.13 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-compat-api@0.2.7 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/theme@0.5.6 + ## 1.10.7-next.2 ### Patch Changes diff --git a/plugins/techdocs/package.json b/plugins/techdocs/package.json index cbf1f828ce..3a90078c72 100644 --- a/plugins/techdocs/package.json +++ b/plugins/techdocs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs", - "version": "1.10.7-next.2", + "version": "1.10.7", "description": "The Backstage plugin that renders technical documentation for your components", "backstage": { "role": "frontend-plugin", diff --git a/plugins/user-settings-backend/CHANGELOG.md b/plugins/user-settings-backend/CHANGELOG.md index c830df43e5..6a945081e8 100644 --- a/plugins/user-settings-backend/CHANGELOG.md +++ b/plugins/user-settings-backend/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-user-settings-backend +## 0.2.21 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.0 + - @backstage/backend-common@0.23.3 + - @backstage/plugin-auth-node@0.4.17 + - @backstage/plugin-signals-node@0.1.8 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-user-settings-common@0.0.1 + ## 0.2.21-next.1 ### Patch Changes diff --git a/plugins/user-settings-backend/package.json b/plugins/user-settings-backend/package.json index e975b38c08..e33bf0bd4b 100644 --- a/plugins/user-settings-backend/package.json +++ b/plugins/user-settings-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-user-settings-backend", - "version": "0.2.21-next.1", + "version": "0.2.21", "description": "The Backstage backend plugin to manage user settings", "backstage": { "role": "backend-plugin", diff --git a/plugins/user-settings/CHANGELOG.md b/plugins/user-settings/CHANGELOG.md index 8d886aee80..f10a4c0ea3 100644 --- a/plugins/user-settings/CHANGELOG.md +++ b/plugins/user-settings/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-user-settings +## 0.8.9 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.9 + - @backstage/core-app-api@1.14.0 + - @backstage/plugin-catalog-react@1.12.2 + - @backstage/frontend-plugin-api@0.6.7 + - @backstage/core-compat-api@0.2.7 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/plugin-signals-react@0.0.4 + - @backstage/plugin-user-settings-common@0.0.1 + ## 0.8.9-next.2 ### Patch Changes diff --git a/plugins/user-settings/package.json b/plugins/user-settings/package.json index 34c719d9df..5ae95e0e45 100644 --- a/plugins/user-settings/package.json +++ b/plugins/user-settings/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-user-settings", - "version": "0.8.9-next.2", + "version": "0.8.9", "description": "A Backstage plugin that provides a settings page", "backstage": { "role": "frontend-plugin", diff --git a/yarn.lock b/yarn.lock index c7d871b1d9..c6a1d2139a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3839,7 +3839,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/catalog-client@^1.6.5, @backstage/catalog-client@workspace:^, @backstage/catalog-client@workspace:packages/catalog-client": +"@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: @@ -3852,7 +3852,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/catalog-model@^1.4.3, @backstage/catalog-model@^1.4.5, @backstage/catalog-model@^1.5.0, @backstage/catalog-model@workspace:^, @backstage/catalog-model@workspace:packages/catalog-model": +"@backstage/catalog-model@^1.4.3, @backstage/catalog-model@^1.4.5, @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: @@ -4105,7 +4105,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/config@^1.1.1, @backstage/config@^1.2.0, @backstage/config@workspace:^, @backstage/config@workspace:packages/config": +"@backstage/config@^1.1.1, @backstage/config@workspace:^, @backstage/config@workspace:packages/config": version: 0.0.0-use.local resolution: "@backstage/config@workspace:packages/config" dependencies: @@ -4177,107 +4177,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/core-components@npm:^0.13.10": - version: 0.13.10 - resolution: "@backstage/core-components@npm:0.13.10" - dependencies: - "@backstage/config": ^1.1.1 - "@backstage/core-plugin-api": ^1.8.2 - "@backstage/errors": ^1.2.3 - "@backstage/theme": ^0.5.0 - "@backstage/version-bridge": ^1.0.7 - "@date-io/core": ^1.3.13 - "@material-table/core": ^3.1.0 - "@material-ui/core": ^4.12.2 - "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.61 - "@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 - ansi-regex: ^6.0.1 - classnames: ^2.2.6 - d3-selection: ^3.0.0 - d3-shape: ^3.0.0 - d3-zoom: ^3.0.0 - dagre: ^0.8.5 - linkify-react: 4.1.3 - linkifyjs: 4.1.3 - lodash: ^4.17.21 - pluralize: ^8.0.0 - qs: ^6.9.4 - rc-progress: 3.5.1 - react-helmet: 6.1.0 - react-hook-form: ^7.12.2 - react-idle-timer: 5.6.2 - react-markdown: ^8.0.0 - react-sparklines: ^1.7.0 - react-syntax-highlighter: ^15.4.5 - react-text-truncate: ^0.19.0 - react-use: ^17.3.2 - react-virtualized-auto-sizer: ^1.0.11 - react-window: ^1.8.6 - remark-gfm: ^3.0.1 - zen-observable: ^0.10.0 - zod: ^3.22.4 - peerDependencies: - 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 - checksum: ec2a0d0a27bc4d6b9d4da97f0b4df600148529ee51bf2c8e7d3adc45c3950adac662535d3beabc451db346f2c7e3c412ceaa756fc774012b43dff5e2695f2271 - languageName: node - linkType: hard - -"@backstage/core-components@npm:^0.14.4, @backstage/core-components@npm:^0.14.8": - version: 0.14.8 - resolution: "@backstage/core-components@npm:0.14.8" - dependencies: - "@backstage/config": ^1.2.0 - "@backstage/core-plugin-api": ^1.9.3 - "@backstage/errors": ^1.2.4 - "@backstage/theme": ^0.5.6 - "@backstage/version-bridge": ^1.0.8 - "@date-io/core": ^1.3.13 - "@material-table/core": ^3.1.0 - "@material-ui/core": ^4.12.2 - "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.61 - "@react-hookz/web": ^24.0.0 - "@types/react": ^16.13.1 || ^17.0.0 || ^18.0.0 - "@types/react-sparklines": ^1.7.0 - ansi-regex: ^6.0.1 - classnames: ^2.2.6 - d3-selection: ^3.0.0 - d3-shape: ^3.0.0 - d3-zoom: ^3.0.0 - dagre: ^0.8.5 - linkify-react: 4.1.3 - linkifyjs: 4.1.3 - lodash: ^4.17.21 - pluralize: ^8.0.0 - qs: ^6.9.4 - rc-progress: 3.5.1 - react-helmet: 6.1.0 - react-hook-form: ^7.12.2 - react-idle-timer: 5.7.2 - react-markdown: ^8.0.0 - react-sparklines: ^1.7.0 - react-syntax-highlighter: ^15.4.5 - react-use: ^17.3.2 - react-virtualized-auto-sizer: ^1.0.11 - react-window: ^1.8.6 - remark-gfm: ^3.0.1 - zen-observable: ^0.10.0 - zod: ^3.22.4 - peerDependencies: - 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 - checksum: b833e833c83f72e0cc695fe2726cbf01b58819ad062ed9ab1e604514bb398ade20e1abb208d2e39ab1f746fdbd4547486e3935bacb44b457a47070f9c77895dc - languageName: node - linkType: hard - -"@backstage/core-components@workspace:^, @backstage/core-components@workspace:packages/core-components": +"@backstage/core-components@^0.14.4, @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: @@ -4348,7 +4248,58 @@ __metadata: languageName: unknown linkType: soft -"@backstage/core-plugin-api@^1.8.2, @backstage/core-plugin-api@^1.9.2, @backstage/core-plugin-api@^1.9.3, @backstage/core-plugin-api@workspace:^, @backstage/core-plugin-api@workspace:packages/core-plugin-api": +"@backstage/core-components@npm:^0.13.10": + version: 0.13.10 + resolution: "@backstage/core-components@npm:0.13.10" + dependencies: + "@backstage/config": ^1.1.1 + "@backstage/core-plugin-api": ^1.8.2 + "@backstage/errors": ^1.2.3 + "@backstage/theme": ^0.5.0 + "@backstage/version-bridge": ^1.0.7 + "@date-io/core": ^1.3.13 + "@material-table/core": ^3.1.0 + "@material-ui/core": ^4.12.2 + "@material-ui/icons": ^4.9.1 + "@material-ui/lab": 4.0.0-alpha.61 + "@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 + ansi-regex: ^6.0.1 + classnames: ^2.2.6 + d3-selection: ^3.0.0 + d3-shape: ^3.0.0 + d3-zoom: ^3.0.0 + dagre: ^0.8.5 + linkify-react: 4.1.3 + linkifyjs: 4.1.3 + lodash: ^4.17.21 + pluralize: ^8.0.0 + qs: ^6.9.4 + rc-progress: 3.5.1 + react-helmet: 6.1.0 + react-hook-form: ^7.12.2 + react-idle-timer: 5.6.2 + react-markdown: ^8.0.0 + react-sparklines: ^1.7.0 + react-syntax-highlighter: ^15.4.5 + react-text-truncate: ^0.19.0 + react-use: ^17.3.2 + react-virtualized-auto-sizer: ^1.0.11 + react-window: ^1.8.6 + remark-gfm: ^3.0.1 + zen-observable: ^0.10.0 + zod: ^3.22.4 + peerDependencies: + 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 + checksum: ec2a0d0a27bc4d6b9d4da97f0b4df600148529ee51bf2c8e7d3adc45c3950adac662535d3beabc451db346f2c7e3c412ceaa756fc774012b43dff5e2695f2271 + languageName: node + linkType: hard + +"@backstage/core-plugin-api@^1.8.2, @backstage/core-plugin-api@^1.9.2, @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: @@ -4495,26 +4446,6 @@ __metadata: languageName: unknown linkType: soft -"@backstage/frontend-plugin-api@npm:^0.6.6": - version: 0.6.6 - resolution: "@backstage/frontend-plugin-api@npm:0.6.6" - dependencies: - "@backstage/core-components": ^0.14.8 - "@backstage/core-plugin-api": ^1.9.3 - "@backstage/types": ^1.1.1 - "@backstage/version-bridge": ^1.0.8 - "@material-ui/core": ^4.12.4 - "@types/react": ^16.13.1 || ^17.0.0 || ^18.0.0 - lodash: ^4.17.21 - zod: ^3.22.4 - zod-to-json-schema: ^3.21.4 - peerDependencies: - react: ^16.13.1 || ^17.0.0 || ^18.0.0 - react-router-dom: 6.0.0-beta.0 || ^6.3.0 - checksum: c2af07bb73751f050937ba0f34941cc21639defdf13c6e219069ff4143324404229113874caef28f41b9a92a00121991da2a88782595e5221b48910e2f8be7c7 - languageName: node - linkType: hard - "@backstage/frontend-plugin-api@workspace:^, @backstage/frontend-plugin-api@workspace:packages/frontend-plugin-api": version: 0.0.0-use.local resolution: "@backstage/frontend-plugin-api@workspace:packages/frontend-plugin-api" @@ -4578,24 +4509,6 @@ __metadata: languageName: unknown linkType: soft -"@backstage/integration-react@npm:^1.1.28": - version: 1.1.28 - resolution: "@backstage/integration-react@npm:1.1.28" - dependencies: - "@backstage/config": ^1.2.0 - "@backstage/core-plugin-api": ^1.9.3 - "@backstage/integration": ^1.12.0 - "@material-ui/core": ^4.12.2 - "@material-ui/icons": ^4.9.1 - "@types/react": ^16.13.1 || ^17.0.0 - peerDependencies: - 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 - checksum: 15443a7ebc457114715651e652a40472085ca18ec10da078bad1e71e3aa9cac33d10704b164d09108f6195a9cb4d2eae11751d853598ef0dd0e4c160858f782d - languageName: node - linkType: hard - "@backstage/integration-react@workspace:^, @backstage/integration-react@workspace:packages/integration-react": version: 0.0.0-use.local resolution: "@backstage/integration-react@workspace:packages/integration-react" @@ -4620,23 +4533,6 @@ __metadata: languageName: unknown linkType: soft -"@backstage/integration@npm:^1.12.0": - version: 1.12.0 - resolution: "@backstage/integration@npm:1.12.0" - dependencies: - "@azure/identity": ^4.0.0 - "@backstage/config": ^1.2.0 - "@backstage/errors": ^1.2.4 - "@octokit/auth-app": ^4.0.0 - "@octokit/rest": ^19.0.3 - cross-fetch: ^4.0.0 - git-url-parse: ^14.0.0 - lodash: ^4.17.21 - luxon: ^3.0.0 - checksum: 603c08058dadfe54b5d1788db87bab951b53ea4d1b19f609873717e0ab514859cc8608d0d60755c91eaea000ad71f817c5dd50892a3215443d7eed5a1d24a849 - languageName: node - linkType: hard - "@backstage/integration@workspace:^, @backstage/integration@workspace:packages/integration": version: 0.0.0-use.local resolution: "@backstage/integration@workspace:packages/integration" @@ -5722,7 +5618,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-catalog-common@^1.0.20, @backstage/plugin-catalog-common@^1.0.24, @backstage/plugin-catalog-common@workspace:^, @backstage/plugin-catalog-common@workspace:plugins/catalog-common": +"@backstage/plugin-catalog-common@^1.0.20, @backstage/plugin-catalog-common@workspace:^, @backstage/plugin-catalog-common@workspace:plugins/catalog-common": version: 0.0.0-use.local resolution: "@backstage/plugin-catalog-common@workspace:plugins/catalog-common" dependencies: @@ -5831,43 +5727,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-catalog-react@npm:^1.11.3, @backstage/plugin-catalog-react@npm:^1.9.3": - version: 1.12.1 - resolution: "@backstage/plugin-catalog-react@npm:1.12.1" - dependencies: - "@backstage/catalog-client": ^1.6.5 - "@backstage/catalog-model": ^1.5.0 - "@backstage/core-components": ^0.14.8 - "@backstage/core-plugin-api": ^1.9.3 - "@backstage/errors": ^1.2.4 - "@backstage/frontend-plugin-api": ^0.6.6 - "@backstage/integration-react": ^1.1.28 - "@backstage/plugin-catalog-common": ^1.0.24 - "@backstage/plugin-permission-common": ^0.7.14 - "@backstage/plugin-permission-react": ^0.4.23 - "@backstage/types": ^1.1.1 - "@backstage/version-bridge": ^1.0.8 - "@material-ui/core": ^4.12.2 - "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.61 - "@react-hookz/web": ^24.0.0 - "@types/react": ^16.13.1 || ^17.0.0 || ^18.0.0 - classnames: ^2.2.6 - lodash: ^4.17.21 - material-ui-popup-state: ^1.9.3 - qs: ^6.9.4 - react-use: ^17.2.4 - yaml: ^2.0.0 - zen-observable: ^0.10.0 - peerDependencies: - 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 - checksum: adbf967e978fa6bb4798d0620853e41f64cc08c39dd0056fc01b2146ca427d1bfab401b8972d7b551d4188b90f80f69db9254799bca095608b7079cec73da9c5 - languageName: node - linkType: hard - -"@backstage/plugin-catalog-react@workspace:^, @backstage/plugin-catalog-react@workspace:plugins/catalog-react": +"@backstage/plugin-catalog-react@^1.11.3, @backstage/plugin-catalog-react@^1.9.3, @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: @@ -6711,7 +6571,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-permission-common@^0.7.14, @backstage/plugin-permission-common@workspace:^, @backstage/plugin-permission-common@workspace:plugins/permission-common": +"@backstage/plugin-permission-common@workspace:^, @backstage/plugin-permission-common@workspace:plugins/permission-common": version: 0.0.0-use.local resolution: "@backstage/plugin-permission-common@workspace:plugins/permission-common" dependencies: @@ -6749,7 +6609,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-permission-react@^0.4.23, @backstage/plugin-permission-react@workspace:^, @backstage/plugin-permission-react@workspace:plugins/permission-react": +"@backstage/plugin-permission-react@workspace:^, @backstage/plugin-permission-react@workspace:plugins/permission-react": version: 0.0.0-use.local resolution: "@backstage/plugin-permission-react@workspace:plugins/permission-react" dependencies: @@ -8072,7 +7932,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/theme@^0.5.0, @backstage/theme@^0.5.6, @backstage/theme@workspace:^, @backstage/theme@workspace:packages/theme": +"@backstage/theme@^0.5.0, @backstage/theme@workspace:^, @backstage/theme@workspace:packages/theme": version: 0.0.0-use.local resolution: "@backstage/theme@workspace:packages/theme" dependencies: @@ -8103,7 +7963,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/version-bridge@^1.0.7, @backstage/version-bridge@^1.0.8, @backstage/version-bridge@workspace:^, @backstage/version-bridge@workspace:packages/version-bridge": +"@backstage/version-bridge@^1.0.7, @backstage/version-bridge@workspace:^, @backstage/version-bridge@workspace:packages/version-bridge": version: 0.0.0-use.local resolution: "@backstage/version-bridge@workspace:packages/version-bridge" dependencies: From 392b26a0ed848730e5c332136d391a6726763d41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Pi=C4=85tkiewicz?= <piatkiewicz.piotr@gmail.com> Date: Tue, 16 Jul 2024 15:17:07 +0200 Subject: [PATCH 284/416] Update writing-custom-actions.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Piotr Piątkiewicz <piatkiewicz.piotr@gmail.com> --- docs/features/software-templates/writing-custom-actions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/features/software-templates/writing-custom-actions.md b/docs/features/software-templates/writing-custom-actions.md index 6c1ea573db..98457d2e8d 100644 --- a/docs/features/software-templates/writing-custom-actions.md +++ b/docs/features/software-templates/writing-custom-actions.md @@ -195,7 +195,7 @@ const scaffolderModuleCustomExtensions = createBackendModule({ const backend = createBackend(); backend.add(import('@backstage/plugin-scaffolder-backend/alpha')); /* highlight-add-next-line */ -backend.add(scaffolderModuleCustomExtensions()); +backend.add(scaffolderModuleCustomExtensions); ``` If your custom action requires core services such as `config` or `cache` they can be imported in the dependencies and passed to the custom action function. From 5e6eccc84ca26e4dffe516f1eacc7d49da6d868f Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg <poldsberg@gmail.com> Date: Tue, 16 Jul 2024 16:26:15 +0200 Subject: [PATCH 285/416] docs: sidebar label fix for root health Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com> --- docs/backend-system/core-services/root-health.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/backend-system/core-services/root-health.md b/docs/backend-system/core-services/root-health.md index fc73ba9546..663dd699ae 100644 --- a/docs/backend-system/core-services/root-health.md +++ b/docs/backend-system/core-services/root-health.md @@ -1,7 +1,7 @@ --- id: root-health title: Root Health Service -sidebar_label: Health +sidebar_label: Root Health description: Documentation for the Health service --- From d5e567efff47e2756c6e17a85df9ea52812c4cf0 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg <poldsberg@gmail.com> Date: Tue, 16 Jul 2024 17:27:24 +0200 Subject: [PATCH 286/416] docs: update threat model and auth docs to mention public entry point Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com> --- docs/auth/index.md | 7 +------ docs/overview/threat-model.md | 2 ++ 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/docs/auth/index.md b/docs/auth/index.md index 4a0e56a36e..5188d7e2a4 100644 --- a/docs/auth/index.md +++ b/docs/auth/index.md @@ -12,12 +12,7 @@ access to external resources. :::note Note -Identity management and the Sign-In page in Backstage is NOT a method for blocking -access for unauthorized users. The identity system only serves to provide a personalized -experience and access to a Backstage Identity Token, which can be passed to backend plugins. -This also means that your Backstage backend APIs are by default unauthenticated. -Thus, if your Backstage instance is exposed to the Internet, anyone can access -information in the Backstage. You can learn more [here](../overview/threat-model.md#integrator-responsibilities). +Identity management and the Sign-In page in Backstage will only block external access when using the new backend system, without setting `backend.auth.dangerouslyDisableDefaultAuthPolicy` in configuration. Even so, the frontend bundle is not protected from external access, protecting it requires the use of the [experimental public entry point](https://backstage.io/docs/tutorials/enable-public-entry/). You can learn more about this in the [Threat Model](../overview/threat-model.md#operator-responsibilities). ::: diff --git a/docs/overview/threat-model.md b/docs/overview/threat-model.md index da97f3fc83..c0e2d61e25 100644 --- a/docs/overview/threat-model.md +++ b/docs/overview/threat-model.md @@ -37,6 +37,8 @@ The operator is ultimately responsible for auditing usage of internal and extern The operator is also responsible for maintaining the resolved NPM dependencies of their Backstage project. This involves ensuring that `yarn.lock` receives updated versions of packages that have vulnerabilities, when those fixed versions are in range of what the Backstage packages request in their respective `package.json` files. This is commonly done by employing automated tooling such as [Dependabot](https://dependabot.com/), [Snyk](https://snyk.io/), and/or [Renovate](https://docs.renovatebot.com/) on your own repository. When fixed versions exist that are _not_ in range of what Backstage packages request, or when larger operations such as switching out an entire dependency for another one is required, maintainers collaborate with contributors to try to address those dependency declarations in the main project as soon as possible. +The built-in protection against unauthorized access does not by default include protection of the frontend bundle. The frontend bundle includes all the code of your frontend plugins and code in minified form, as well as any other frontend resources like images, fonts, etc. If this is a concern, you can use the [experimental public entry point](https://backstage.io/docs/tutorials/enable-public-entry/) to create two separate frontend builds, where authenticated users only have access to the full one. + ## Common Backend Configuration There are many common facilities that are configured centrally and available to all Backstage backend plugins. For example there is a `DatabaseManager` that provides access to a SQL database, `TaskScheduler` for scheduling long-running tasks, `Logger` as a general logging facility, and `UrlReader` for reading content from external sources. These are all configured either directly in code, or within the `backend` block of the static configuration. The appropriate care needs to be taken to ensure that any secrets remain confidential and no malicious configuration is injected. From 7e13b7af04b24105619e34b17ea2b2547b1a6e12 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg <poldsberg@gmail.com> Date: Tue, 16 Jul 2024 15:30:50 +0200 Subject: [PATCH 287/416] backend-common: deprecate remaining methods Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com> --- .changeset/nine-cherries-decide.md | 14 ++++++++++++++ packages/backend-common/api-report.md | 12 ++++++------ .../src/compat/auth/createLegacyAuthAdapters.ts | 1 + .../src/compat/cache/cacheToPluginCacheManager.ts | 1 + .../backend-common/src/compat/legacy/legacy.ts | 3 +++ .../src/compat/logging/loggerToWinstonLogger.ts | 5 ++++- 6 files changed, 29 insertions(+), 7 deletions(-) create mode 100644 .changeset/nine-cherries-decide.md diff --git a/.changeset/nine-cherries-decide.md b/.changeset/nine-cherries-decide.md new file mode 100644 index 0000000000..b20c24aa85 --- /dev/null +++ b/.changeset/nine-cherries-decide.md @@ -0,0 +1,14 @@ +--- +'@backstage/backend-common': patch +--- + +The remaining exports in the package have now been deprecated: + +- `cacheToPluginCacheManager` +- `createLegacyAuthAdapters` +- `LegacyCreateRouter` +- `legacyPlugin` +- `loggerToWinstonLogger` +- `makeLegacyPlugin` + +Users of these export should fully [migrate to the new backend system](https://backstage.io/docs/backend-system/building-backends/migrating). diff --git a/packages/backend-common/api-report.md b/packages/backend-common/api-report.md index 52b661bcaf..23ed13b62c 100644 --- a/packages/backend-common/api-report.md +++ b/packages/backend-common/api-report.md @@ -129,7 +129,7 @@ export class CacheManager extends CacheManager_2 {} // @public @deprecated (undocumented) export type CacheManagerOptions = CacheManagerOptions_2; -// @public +// @public @deprecated export function cacheToPluginCacheManager(cache: CacheService): { getClient(options?: CacheServiceOptions): CacheService; }; @@ -142,7 +142,7 @@ export interface ContainerRunner { runContainer(opts: RunContainerOptions): Promise<void>; } -// @public +// @public @deprecated export function createLegacyAuthAdapters< TOptions extends { auth?: AuthService; @@ -401,10 +401,10 @@ export type KubernetesContainerRunnerOptions = { timeoutMs?: number; }; -// @public (undocumented) +// @public @deprecated (undocumented) export type LegacyCreateRouter<TEnv> = (deps: TEnv) => Promise<RequestHandler>; -// @public +// @public @deprecated export const legacyPlugin: ( name: string, createRouterImport: Promise<{ @@ -447,13 +447,13 @@ export function loadBackendConfig(options: { watch?: boolean; }): Promise<Config>; -// @public (undocumented) +// @public @deprecated (undocumented) export function loggerToWinstonLogger( logger: LoggerService, opts?: TransportStreamOptions, ): Logger; -// @public +// @public @deprecated export function makeLegacyPlugin< TEnv extends Record<string, unknown>, TEnvTransforms extends { diff --git a/packages/backend-common/src/compat/auth/createLegacyAuthAdapters.ts b/packages/backend-common/src/compat/auth/createLegacyAuthAdapters.ts index 0f591eac6c..15cd881649 100644 --- a/packages/backend-common/src/compat/auth/createLegacyAuthAdapters.ts +++ b/packages/backend-common/src/compat/auth/createLegacyAuthAdapters.ts @@ -292,6 +292,7 @@ export class UserInfoCompat implements UserInfoService { /** * An adapter that ensures presence of the auth and/or httpAuth services. * @public + * @deprecated Migrate to use the new backend system and auth services instead. */ export function createLegacyAuthAdapters< TOptions extends { diff --git a/packages/backend-common/src/compat/cache/cacheToPluginCacheManager.ts b/packages/backend-common/src/compat/cache/cacheToPluginCacheManager.ts index 2654934804..2ae55b016f 100644 --- a/packages/backend-common/src/compat/cache/cacheToPluginCacheManager.ts +++ b/packages/backend-common/src/compat/cache/cacheToPluginCacheManager.ts @@ -24,6 +24,7 @@ import { * old-backend plugin cache manager. * * @public + * @deprecated Migrate to use the new CacheService instead. */ export function cacheToPluginCacheManager(cache: CacheService): { getClient(options?: CacheServiceOptions): CacheService; diff --git a/packages/backend-common/src/compat/legacy/legacy.ts b/packages/backend-common/src/compat/legacy/legacy.ts index 57220a8430..c779daacd2 100644 --- a/packages/backend-common/src/compat/legacy/legacy.ts +++ b/packages/backend-common/src/compat/legacy/legacy.ts @@ -27,6 +27,7 @@ import { TokenManager } from '../../deprecated'; /** * @public + * @deprecated Fully use the new backend system instead. */ export type LegacyCreateRouter<TEnv> = (deps: TEnv) => Promise<RequestHandler>; @@ -69,6 +70,7 @@ function wrapTokenManager(tokenManager: TokenManager, auth: AuthService) { * Creates a new custom plugin compatibility wrapper. * * @public + * @deprecated Fully use the new backend system instead. * @remarks * * Usually you can use {@link legacyPlugin} directly instead, but you might @@ -128,6 +130,7 @@ export function makeLegacyPlugin< * register it with the http router based on the plugin id. * * @public + * @deprecated Fully use the new backend system instead. * @remarks * * This is intended to be used by plugin authors to ease the transition to the diff --git a/packages/backend-common/src/compat/logging/loggerToWinstonLogger.ts b/packages/backend-common/src/compat/logging/loggerToWinstonLogger.ts index 4ba88358d2..83871f48e3 100644 --- a/packages/backend-common/src/compat/logging/loggerToWinstonLogger.ts +++ b/packages/backend-common/src/compat/logging/loggerToWinstonLogger.ts @@ -53,7 +53,10 @@ class BackstageLoggerTransport extends Transport { } } -/** @public */ +/** + * @public + * @deprecated Migrate to use the new LoggerService instead. + */ export function loggerToWinstonLogger( logger: LoggerService, opts?: TransportStreamOptions, From b3769f14b3f3fa767546d0d806e0a1967fc0a940 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg <poldsberg@gmail.com> Date: Tue, 16 Jul 2024 18:37:01 +0200 Subject: [PATCH 288/416] changesets: enter prerelease Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com> --- .changeset/pre.json | 192 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 192 insertions(+) create mode 100644 .changeset/pre.json diff --git a/.changeset/pre.json b/.changeset/pre.json new file mode 100644 index 0000000000..be1b694c9e --- /dev/null +++ b/.changeset/pre.json @@ -0,0 +1,192 @@ +{ + "mode": "pre", + "tag": "next", + "initialVersions": { + "example-app": "0.2.99", + "@backstage/app-defaults": "1.5.8", + "example-app-next": "0.0.13", + "app-next-example-plugin": "0.0.13", + "example-backend": "0.0.28", + "@backstage/backend-app-api": "0.8.0", + "@backstage/backend-common": "0.23.3", + "@backstage/backend-defaults": "0.4.0", + "@backstage/backend-dev-utils": "0.1.4", + "@backstage/backend-dynamic-feature-service": "0.2.15", + "example-backend-legacy": "0.2.100", + "@backstage/backend-openapi-utils": "0.1.15", + "@backstage/backend-plugin-api": "0.7.0", + "@backstage/backend-tasks": "0.5.27", + "@backstage/backend-test-utils": "0.4.4", + "@backstage/catalog-client": "1.6.5", + "@backstage/catalog-model": "1.5.0", + "@backstage/cli": "0.26.11", + "@backstage/cli-common": "0.1.14", + "@backstage/cli-node": "0.2.7", + "@backstage/codemods": "0.1.49", + "@backstage/config": "1.2.0", + "@backstage/config-loader": "1.8.1", + "@backstage/core-app-api": "1.14.0", + "@backstage/core-compat-api": "0.2.7", + "@backstage/core-components": "0.14.9", + "@backstage/core-plugin-api": "1.9.3", + "@backstage/create-app": "0.5.17", + "@backstage/dev-utils": "1.0.35", + "e2e-test": "0.2.18", + "@backstage/e2e-test-utils": "0.1.1", + "@backstage/errors": "1.2.4", + "@backstage/eslint-plugin": "0.1.8", + "@backstage/frontend-app-api": "0.7.3", + "@backstage/frontend-plugin-api": "0.6.7", + "@backstage/frontend-test-utils": "0.1.10", + "@backstage/integration": "1.13.0", + "@backstage/integration-aws-node": "0.1.12", + "@backstage/integration-react": "1.1.29", + "@backstage/release-manifests": "0.0.11", + "@backstage/repo-tools": "0.9.4", + "@techdocs/cli": "1.8.16", + "techdocs-cli-embedded-app": "0.2.98", + "@backstage/test-utils": "1.5.8", + "@backstage/theme": "0.5.6", + "@backstage/types": "1.1.1", + "@backstage/version-bridge": "1.0.8", + "yarn-plugin-backstage": "0.0.1", + "@backstage/plugin-api-docs": "0.11.7", + "@backstage/plugin-api-docs-module-protoc-gen-doc": "0.1.7", + "@backstage/plugin-app-backend": "0.3.71", + "@backstage/plugin-app-node": "0.1.22", + "@backstage/plugin-app-visualizer": "0.1.8", + "@backstage/plugin-auth-backend": "0.22.9", + "@backstage/plugin-auth-backend-module-atlassian-provider": "0.2.3", + "@backstage/plugin-auth-backend-module-aws-alb-provider": "0.1.14", + "@backstage/plugin-auth-backend-module-azure-easyauth-provider": "0.1.5", + "@backstage/plugin-auth-backend-module-bitbucket-provider": "0.1.5", + "@backstage/plugin-auth-backend-module-cloudflare-access-provider": "0.1.5", + "@backstage/plugin-auth-backend-module-gcp-iap-provider": "0.2.17", + "@backstage/plugin-auth-backend-module-github-provider": "0.1.19", + "@backstage/plugin-auth-backend-module-gitlab-provider": "0.1.19", + "@backstage/plugin-auth-backend-module-google-provider": "0.1.19", + "@backstage/plugin-auth-backend-module-guest-provider": "0.1.8", + "@backstage/plugin-auth-backend-module-microsoft-provider": "0.1.17", + "@backstage/plugin-auth-backend-module-oauth2-provider": "0.2.3", + "@backstage/plugin-auth-backend-module-oauth2-proxy-provider": "0.1.15", + "@backstage/plugin-auth-backend-module-oidc-provider": "0.2.3", + "@backstage/plugin-auth-backend-module-okta-provider": "0.0.15", + "@backstage/plugin-auth-backend-module-onelogin-provider": "0.1.3", + "@backstage/plugin-auth-backend-module-pinniped-provider": "0.1.16", + "@backstage/plugin-auth-backend-module-vmware-cloud-provider": "0.2.3", + "@backstage/plugin-auth-node": "0.4.17", + "@backstage/plugin-auth-react": "0.1.4", + "@backstage/plugin-bitbucket-cloud-common": "0.2.21", + "@backstage/plugin-catalog": "1.21.1", + "@backstage/plugin-catalog-backend": "1.24.0", + "@backstage/plugin-catalog-backend-module-aws": "0.3.17", + "@backstage/plugin-catalog-backend-module-azure": "0.1.42", + "@backstage/plugin-catalog-backend-module-backstage-openapi": "0.2.5", + "@backstage/plugin-catalog-backend-module-bitbucket-cloud": "0.2.9", + "@backstage/plugin-catalog-backend-module-bitbucket-server": "0.1.36", + "@backstage/plugin-catalog-backend-module-gcp": "0.1.23", + "@backstage/plugin-catalog-backend-module-gerrit": "0.1.39", + "@backstage/plugin-catalog-backend-module-github": "0.6.5", + "@backstage/plugin-catalog-backend-module-github-org": "0.1.17", + "@backstage/plugin-catalog-backend-module-gitlab": "0.3.21", + "@backstage/plugin-catalog-backend-module-gitlab-org": "0.0.5", + "@backstage/plugin-catalog-backend-module-incremental-ingestion": "0.4.27", + "@backstage/plugin-catalog-backend-module-ldap": "0.7.0", + "@backstage/plugin-catalog-backend-module-logs": "0.0.1", + "@backstage/plugin-catalog-backend-module-msgraph": "0.5.30", + "@backstage/plugin-catalog-backend-module-openapi": "0.1.40", + "@backstage/plugin-catalog-backend-module-puppetdb": "0.1.28", + "@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "0.1.20", + "@backstage/plugin-catalog-backend-module-unprocessed": "0.4.9", + "@backstage/plugin-catalog-common": "1.0.25", + "@backstage/plugin-catalog-graph": "0.4.7", + "@backstage/plugin-catalog-import": "0.12.1", + "@backstage/plugin-catalog-node": "1.12.4", + "@backstage/plugin-catalog-react": "1.12.2", + "@backstage/plugin-catalog-unprocessed-entities": "0.2.6", + "@backstage/plugin-catalog-unprocessed-entities-common": "0.0.3", + "@backstage/plugin-config-schema": "0.1.57", + "@backstage/plugin-devtools": "0.1.16", + "@backstage/plugin-devtools-backend": "0.3.8", + "@backstage/plugin-devtools-common": "0.1.11", + "@backstage/plugin-events-backend": "0.3.9", + "@backstage/plugin-events-backend-module-aws-sqs": "0.3.8", + "@backstage/plugin-events-backend-module-azure": "0.2.8", + "@backstage/plugin-events-backend-module-bitbucket-cloud": "0.2.8", + "@backstage/plugin-events-backend-module-gerrit": "0.2.8", + "@backstage/plugin-events-backend-module-github": "0.2.8", + "@backstage/plugin-events-backend-module-gitlab": "0.2.8", + "@backstage/plugin-events-backend-test-utils": "0.1.32", + "@backstage/plugin-events-node": "0.3.8", + "@internal/plugin-todo-list": "1.0.29", + "@internal/plugin-todo-list-backend": "1.0.29", + "@internal/plugin-todo-list-common": "1.0.20", + "@backstage/plugin-home": "0.7.7", + "@backstage/plugin-home-react": "0.1.15", + "@backstage/plugin-kubernetes": "0.11.12", + "@backstage/plugin-kubernetes-backend": "0.18.3", + "@backstage/plugin-kubernetes-cluster": "0.0.13", + "@backstage/plugin-kubernetes-common": "0.8.1", + "@backstage/plugin-kubernetes-node": "0.1.16", + "@backstage/plugin-kubernetes-react": "0.4.1", + "@backstage/plugin-notifications": "0.2.3", + "@backstage/plugin-notifications-backend": "0.3.3", + "@backstage/plugin-notifications-backend-module-email": "0.1.3", + "@backstage/plugin-notifications-common": "0.0.5", + "@backstage/plugin-notifications-node": "0.2.3", + "@backstage/plugin-org": "0.6.27", + "@backstage/plugin-org-react": "0.1.26", + "@backstage/plugin-permission-backend": "0.5.46", + "@backstage/plugin-permission-backend-module-allow-all-policy": "0.1.19", + "@backstage/plugin-permission-common": "0.8.0", + "@backstage/plugin-permission-node": "0.8.0", + "@backstage/plugin-permission-react": "0.4.24", + "@backstage/plugin-proxy-backend": "0.5.3", + "@backstage/plugin-scaffolder": "1.23.0", + "@backstage/plugin-scaffolder-backend": "1.23.0", + "@backstage/plugin-scaffolder-backend-module-azure": "0.1.14", + "@backstage/plugin-scaffolder-backend-module-bitbucket": "0.2.12", + "@backstage/plugin-scaffolder-backend-module-bitbucket-cloud": "0.1.12", + "@backstage/plugin-scaffolder-backend-module-bitbucket-server": "0.1.12", + "@backstage/plugin-scaffolder-backend-module-confluence-to-markdown": "0.2.23", + "@backstage/plugin-scaffolder-backend-module-cookiecutter": "0.2.46", + "@backstage/plugin-scaffolder-backend-module-gcp": "0.1.0", + "@backstage/plugin-scaffolder-backend-module-gerrit": "0.1.14", + "@backstage/plugin-scaffolder-backend-module-gitea": "0.1.12", + "@backstage/plugin-scaffolder-backend-module-github": "0.4.0", + "@backstage/plugin-scaffolder-backend-module-gitlab": "0.4.4", + "@backstage/plugin-scaffolder-backend-module-notifications": "0.0.5", + "@backstage/plugin-scaffolder-backend-module-rails": "0.4.39", + "@backstage/plugin-scaffolder-backend-module-sentry": "0.1.30", + "@backstage/plugin-scaffolder-backend-module-yeoman": "0.3.6", + "@backstage/plugin-scaffolder-common": "1.5.4", + "@backstage/plugin-scaffolder-node": "0.4.8", + "@backstage/plugin-scaffolder-node-test-utils": "0.1.9", + "@backstage/plugin-scaffolder-react": "1.10.0", + "@backstage/plugin-search": "1.4.14", + "@backstage/plugin-search-backend": "1.5.14", + "@backstage/plugin-search-backend-module-catalog": "0.1.28", + "@backstage/plugin-search-backend-module-elasticsearch": "1.5.3", + "@backstage/plugin-search-backend-module-explore": "0.1.28", + "@backstage/plugin-search-backend-module-pg": "0.5.32", + "@backstage/plugin-search-backend-module-stack-overflow-collator": "0.1.15", + "@backstage/plugin-search-backend-module-techdocs": "0.1.27", + "@backstage/plugin-search-backend-node": "1.2.27", + "@backstage/plugin-search-common": "1.2.13", + "@backstage/plugin-search-react": "1.7.13", + "@backstage/plugin-signals": "0.0.8", + "@backstage/plugin-signals-backend": "0.1.8", + "@backstage/plugin-signals-node": "0.1.8", + "@backstage/plugin-signals-react": "0.0.4", + "@backstage/plugin-techdocs": "1.10.7", + "@backstage/plugin-techdocs-addons-test-utils": "1.0.35", + "@backstage/plugin-techdocs-backend": "1.10.9", + "@backstage/plugin-techdocs-module-addons-contrib": "1.1.12", + "@backstage/plugin-techdocs-node": "1.12.8", + "@backstage/plugin-techdocs-react": "1.2.6", + "@backstage/plugin-user-settings": "0.8.9", + "@backstage/plugin-user-settings-backend": "0.2.21", + "@backstage/plugin-user-settings-common": "0.0.1" + }, + "changesets": [] +} From 669d742d38359fed15ab03bad494ed73e3e3c7ce Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg <poldsberg@gmail.com> Date: Tue, 16 Jul 2024 19:32:32 +0200 Subject: [PATCH 289/416] create-app: remove unnecessary yarn.lock seeds Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com> --- packages/create-app/seed-yarn.lock | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/packages/create-app/seed-yarn.lock b/packages/create-app/seed-yarn.lock index b09a0ce1a7..00a86105cc 100644 --- a/packages/create-app/seed-yarn.lock +++ b/packages/create-app/seed-yarn.lock @@ -16,13 +16,3 @@ // package: the name of the package, e.g. @testing-library/react // query: the version query to pin the version for, e.g. ^14.0.0 // version: the version to pin to, must be in range of the query, e.g. 14.11.0 - -ajv@^8.0.0, ajv@^8.10.0, ajv@^8.11.0, ajv@^8.12.0, ajv@^8.14.0, ajv@^8.6.0, ajv@^8.6.3, ajv@^8.8.2, ajv@^8.9.0: - version "8.14.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.14.0.tgz#f514ddfd4756abb200e1704414963620a625ebbb" - integrity sha512-oYs1UUtO97ZO2lJ4bwnWeQW8/zvOIQLGKcvPTsWmvc2SYgBb+upuNS5NxoLaMU4h8Ju3Nbj6Cq8mD2LQoqVKFA== - -"@mui/material@^5.12.2": - version "5.16.1" - resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.16.1.tgz#6fcef9b5709df5864cf0b0bc0ea7b453a9d9e420" - integrity sha512-BGTgJRb0d/hX9tus5CEb6N/Fo8pE4tYA+s9r4/S0PCrtZ3urCLXlTH4qrAvggQbiF1cYRAbHCkVHoQ+4Pdxl+w== From 8e967da7a0c9cf380f458672340c6fe2e1399621 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg <poldsberg@gmail.com> Date: Tue, 16 Jul 2024 21:28:51 +0200 Subject: [PATCH 290/416] backend-defaults: fixed routing of health endpoints Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com> --- .changeset/selfish-bees-think.md | 5 +++++ .../src/entrypoints/rootHttpRouter/createHealthRouter.ts | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 .changeset/selfish-bees-think.md diff --git a/.changeset/selfish-bees-think.md b/.changeset/selfish-bees-think.md new file mode 100644 index 0000000000..15598ea551 --- /dev/null +++ b/.changeset/selfish-bees-think.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-defaults': patch +--- + +Fixed the routing of the new health check service, the health endpoints should now properly be available at `/.backstage/health/v1/readiness` and `/.backstage/health/v1/liveness`. diff --git a/packages/backend-defaults/src/entrypoints/rootHttpRouter/createHealthRouter.ts b/packages/backend-defaults/src/entrypoints/rootHttpRouter/createHealthRouter.ts index 13691ede28..007d1dd9cd 100644 --- a/packages/backend-defaults/src/entrypoints/rootHttpRouter/createHealthRouter.ts +++ b/packages/backend-defaults/src/entrypoints/rootHttpRouter/createHealthRouter.ts @@ -23,7 +23,7 @@ export function createHealthRouter(options: { health: RootHealthService }) { const router = Router(); router.get( - '.backstage/health/v1/readiness', + '/.backstage/health/v1/readiness', async (_request: Request, response: Response) => { const { status, payload } = await options.health.getReadiness(); response.status(status).json(payload); @@ -31,7 +31,7 @@ export function createHealthRouter(options: { health: RootHealthService }) { ); router.get( - '.backstage/health/v1/liveness', + '/.backstage/health/v1/liveness', async (_request: Request, response: Response) => { const { status, payload } = await options.health.getLiveness(); response.status(status).json(payload); From 4670f06f72877aa20faf7f24021a977b22598754 Mon Sep 17 00:00:00 2001 From: Matt Benson <gudnabrsam@gmail.com> Date: Wed, 6 Mar 2024 17:31:38 -0600 Subject: [PATCH 291/416] support ajv-errors for scaffolder validation Signed-off-by: Matt Benson <gudnabrsam@gmail.com> --- .changeset/modern-parrots-protect.md | 5 +++++ .../config/vocabularies/Backstage/accept.txt | 1 + .../software-templates/input-examples.md | 19 +++++++++++++++++++ .../software-templates/writing-templates.md | 5 +++++ plugins/scaffolder-react/package.json | 1 + .../src/next/components/Stepper/Stepper.tsx | 6 +++++- yarn.lock | 1 + 7 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 .changeset/modern-parrots-protect.md diff --git a/.changeset/modern-parrots-protect.md b/.changeset/modern-parrots-protect.md new file mode 100644 index 0000000000..7fccff1bef --- /dev/null +++ b/.changeset/modern-parrots-protect.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-react': patch +--- + +support ajv-errors for scaffolder validation diff --git a/.github/vale/config/vocabularies/Backstage/accept.txt b/.github/vale/config/vocabularies/Backstage/accept.txt index 6ff0ef56da..1092947245 100644 --- a/.github/vale/config/vocabularies/Backstage/accept.txt +++ b/.github/vale/config/vocabularies/Backstage/accept.txt @@ -7,6 +7,7 @@ ADRs airbrake Airbrake Airbrakes +ajv Alaria Alef allowlisted diff --git a/docs/features/software-templates/input-examples.md b/docs/features/software-templates/input-examples.md index f49e76e469..dd1228290f 100644 --- a/docs/features/software-templates/input-examples.md +++ b/docs/features/software-templates/input-examples.md @@ -26,6 +26,25 @@ parameters: ui:help: 'Hint: additional description...' ``` +#### Custom validation error message + +```yaml +parameters: + - title: Fill in some steps + properties: + name: + title: Simple text input + type: string + description: Description about input + maxLength: 8 + pattern: '^([a-zA-Z][a-zA-Z0-9]*)(-[a-zA-Z0-9]+)*$' + ui:autofocus: true + ui:help: 'Hint: additional description...' + errorMessage: + properties: + name: '1-8 alphanumeric tokens (first starts with letter) delimited by -' +``` + ### Multi line text input ```yaml diff --git a/docs/features/software-templates/writing-templates.md b/docs/features/software-templates/writing-templates.md index 15591eeb67..075fe0bb08 100644 --- a/docs/features/software-templates/writing-templates.md +++ b/docs/features/software-templates/writing-templates.md @@ -533,6 +533,11 @@ catalogFilter: metadata.annotations.github.com/team-slug: { exists: true } ``` +#### Custom validation messages + +You may specify custom JSON Schema validation messages as supported by the +[ajv-errors](https://github.com/ajv-validator/ajv-errors) plugin library to [ajv](https://github.com/ajv-validator/ajv). + ## `spec.steps` - `Action[]` The `steps` is an array of the things that you want to happen part of this diff --git a/plugins/scaffolder-react/package.json b/plugins/scaffolder-react/package.json index f2d7d44a01..9c50900c05 100644 --- a/plugins/scaffolder-react/package.json +++ b/plugins/scaffolder-react/package.json @@ -78,6 +78,7 @@ "@rjsf/validator-ajv8": "5.18.5", "@types/json-schema": "^7.0.9", "@types/react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "ajv-errors": "^3.0.0", "classnames": "^2.2.6", "flatted": "3.3.1", "humanize-duration": "^3.25.1", diff --git a/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx b/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx index 269b6a11d5..788c7cd715 100644 --- a/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx +++ b/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx @@ -35,7 +35,7 @@ import { } from './createAsyncValidators'; import { ReviewState, type ReviewStateProps } from '../ReviewState'; import { useTemplateSchema, useFormDataFromQuery } from '../../hooks'; -import validator from '@rjsf/validator-ajv8'; +import { customizeValidator } from '@rjsf/validator-ajv8'; import { useTransformSchemaToProps } from '../../hooks/useTransformSchemaToProps'; import { hasErrors } from './utils'; import * as FieldOverrides from './FieldOverrides'; @@ -50,6 +50,10 @@ import { ReviewStepProps } from '@backstage/plugin-scaffolder-react'; import { ErrorListTemplate } from './ErrorListTemplate'; import { makeStyles } from '@material-ui/core/styles'; import { PasswordWidget } from '../PasswordWidget/PasswordWidget'; +import ajvErrors from 'ajv-errors'; + +const validator = customizeValidator(); +ajvErrors(validator.ajv); const useStyles = makeStyles(theme => ({ backButton: { diff --git a/yarn.lock b/yarn.lock index c6a1d2139a..fe7bc4b2c8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7110,6 +7110,7 @@ __metadata: "@types/json-schema": ^7.0.9 "@types/luxon": ^3.0.0 "@types/react": ^16.13.1 || ^17.0.0 || ^18.0.0 + ajv-errors: ^3.0.0 classnames: ^2.2.6 flatted: 3.3.1 humanize-duration: ^3.25.1 From 8b808fd1a92389395668596a18942502816610aa Mon Sep 17 00:00:00 2001 From: Matt Benson <gudnabrsam@gmail.com> Date: Mon, 15 Jul 2024 10:48:22 -0500 Subject: [PATCH 292/416] add errorMessage test Signed-off-by: Matt Benson <gudnabrsam@gmail.com> --- .../next/components/Stepper/Stepper.test.tsx | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/plugins/scaffolder-react/src/next/components/Stepper/Stepper.test.tsx b/plugins/scaffolder-react/src/next/components/Stepper/Stepper.test.tsx index d7e271f8b3..df58d971fb 100644 --- a/plugins/scaffolder-react/src/next/components/Stepper/Stepper.test.tsx +++ b/plugins/scaffolder-react/src/next/components/Stepper/Stepper.test.tsx @@ -392,6 +392,46 @@ describe('Stepper', () => { expect(getByText('invalid postcode')).toBeInTheDocument(); }); + it('should render ajv-errors message', async () => { + const manifest: TemplateParameterSchema = { + steps: [ + { + title: 'Step 1', + schema: { + properties: { + postcode: { + type: 'string', + pattern: '[A-Z][0-9][A-Z] [0-9][A-Z][0-9]', + }, + }, + errorMessage: { + properties: { + postcode: 'invalid postcode', + }, + }, + }, + }, + ], + title: 'transformErrors Form Test', + }; + + const { getByText, getByRole } = await renderInTestApp( + <SecretsContextProvider> + <Stepper manifest={manifest} extensions={[]} onCreate={jest.fn()} /> + </SecretsContextProvider>, + ); + + await fireEvent.change(getByRole('textbox', { name: 'postcode' }), { + target: { value: 'invalid' }, + }); + + await act(async () => { + await fireEvent.click(getByRole('button', { name: 'Review' })); + }); + + expect(getByText('invalid postcode')).toBeInTheDocument(); + }); + it('should grab the initial formData from the query', async () => { const manifest: TemplateParameterSchema = { steps: [ From 7ab4983ed28943636a913eaf7992e437a1e2ade4 Mon Sep 17 00:00:00 2001 From: parmar-abhinav <abhinav.parmar@infosys.com> Date: Wed, 17 Jul 2024 15:00:39 +0530 Subject: [PATCH 293/416] Chore:Add error handling for YAML parsing to improve robustness Signed-off-by: parmar-abhinav <abhinav.parmar@infosys.com> --- .../fetch/rails/index.examples.test.ts | 70 ++++++++++++++++--- 1 file changed, 60 insertions(+), 10 deletions(-) diff --git a/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/index.examples.test.ts b/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/index.examples.test.ts index a80985321e..37e678ab6a 100644 --- a/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/index.examples.test.ts +++ b/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/index.examples.test.ts @@ -90,7 +90,12 @@ describe('fetch:rails', () => { }); it(`should ${examples[0].description}`, async () => { - const input = yaml.parse(examples[0].example).steps[0].input; + let input; + try { + input = yaml.parse(examples[0].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } await action.handler({ ...mockContext, @@ -110,7 +115,12 @@ describe('fetch:rails', () => { }); it(`should ${examples[1].description}`, async () => { - const input = yaml.parse(examples[1].example).steps[0].input; + let input; + try { + input = yaml.parse(examples[1].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } await action.handler({ ...mockContext, @@ -130,7 +140,12 @@ describe('fetch:rails', () => { }); it(`should ${examples[2].description}`, async () => { - const input = yaml.parse(examples[2].example).steps[0].input; + let input; + try { + input = yaml.parse(examples[2].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } await action.handler({ ...mockContext, @@ -150,7 +165,12 @@ describe('fetch:rails', () => { }); it(`should ${examples[3].description}`, async () => { - const input = yaml.parse(examples[3].example).steps[0].input; + let input; + try { + input = yaml.parse(examples[3].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } await action.handler({ ...mockContext, @@ -170,7 +190,12 @@ describe('fetch:rails', () => { }); it(`should ${examples[4].description}`, async () => { - const input = yaml.parse(examples[4].example).steps[0].input; + let input; + try { + input = yaml.parse(examples[4].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } await action.handler({ ...mockContext, @@ -190,7 +215,12 @@ describe('fetch:rails', () => { }); it(`should ${examples[5].description}`, async () => { - const input = yaml.parse(examples[5].example).steps[0].input; + let input; + try { + input = yaml.parse(examples[5].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } await action.handler({ ...mockContext, @@ -210,7 +240,12 @@ describe('fetch:rails', () => { }); it(`should ${examples[6].description}`, async () => { - const input = yaml.parse(examples[6].example).steps[0].input; + let input; + try { + input = yaml.parse(examples[6].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } await action.handler({ ...mockContext, @@ -230,7 +265,12 @@ describe('fetch:rails', () => { }); it(`should ${examples[7].description}`, async () => { - const input = yaml.parse(examples[7].example).steps[0].input; + let input; + try { + input = yaml.parse(examples[7].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } await action.handler({ ...mockContext, @@ -250,7 +290,12 @@ describe('fetch:rails', () => { }); it(`should ${examples[8].description}`, async () => { - const input = yaml.parse(examples[8].example).steps[0].input; + let input; + try { + input = yaml.parse(examples[8].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } await action.handler({ ...mockContext, @@ -270,7 +315,12 @@ describe('fetch:rails', () => { }); it(`should ${examples[9].description}`, async () => { - const input = yaml.parse(examples[9].example).steps[0].input; + let input; + try { + input = yaml.parse(examples[9].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } await action.handler({ ...mockContext, From 31fd39b4dce1c39d258ed72c43dabe8de38e1c38 Mon Sep 17 00:00:00 2001 From: blam <ben@blam.sh> Date: Wed, 17 Jul 2024 12:22:36 +0200 Subject: [PATCH 294/416] chore: fixing discord link Signed-off-by: blam <ben@blam.sh> --- microsite/blog/2022-12-19-backstage-wrapped-2022.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/microsite/blog/2022-12-19-backstage-wrapped-2022.mdx b/microsite/blog/2022-12-19-backstage-wrapped-2022.mdx index e92c9f2265..c15b9fe208 100644 --- a/microsite/blog/2022-12-19-backstage-wrapped-2022.mdx +++ b/microsite/blog/2022-12-19-backstage-wrapped-2022.mdx @@ -20,7 +20,7 @@ Last year we celebrated 75 [public adopters](https://github.com/backstage/backst ![Accelerated growth of Public Backstage Adopters, from January 2021–December 2022.](assets/2022-12-19/public-backstage-adopters-2022.png) -Not only are our adopters growing at an exponential rate, but so too are our contributors. Our [Discord server](https://discord.gg/backstage-687207715902193673-687207715902193673) is a perfect example of the worlds of our adopters and contributors melding. On average, at any given hour of the day or night, there are more than 500 people online available to talk and provide support on any Backstage topic. Discord discussions run a full gamut of topics – from technical support questions to best practices for onboarding engineers to Backstage – basically, anything and everything an adopter may be interested to know and learn. At the very beginning of 2022, we “only” had 4k Discord members. Today, we have a growing membership of 8.2k. +Not only are our adopters growing at an exponential rate, but so too are our contributors. Our [Discord server](https://discord.gg/backstage-687207715902193673) is a perfect example of the worlds of our adopters and contributors melding. On average, at any given hour of the day or night, there are more than 500 people online available to talk and provide support on any Backstage topic. Discord discussions run a full gamut of topics – from technical support questions to best practices for onboarding engineers to Backstage – basically, anything and everything an adopter may be interested to know and learn. At the very beginning of 2022, we “only” had 4k Discord members. Today, we have a growing membership of 8.2k. Isn’t it what we can call a great and vibrant community of enthusiasts? From c8f1cae0efb32b4b859bd7fa12d65e85c6dd5dbd Mon Sep 17 00:00:00 2001 From: Boris Bera <bbera@coveo.com> Date: Wed, 17 Jul 2024 11:31:12 -0400 Subject: [PATCH 295/416] Add `signIn.resolvers` to auth providers config schema Signed-off-by: Boris Bera <bbera@coveo.com> --- .changeset/breezy-jeans-tie.md | 18 ++++++++++++++++++ .../config.d.ts | 7 +++++++ .../config.d.ts | 6 ++++++ .../config.d.ts | 7 +++++++ .../config.d.ts | 6 ++++++ .../config.d.ts | 9 +++++++++ .../config.d.ts | 7 +++++++ .../config.d.ts | 7 +++++++ .../config.d.ts | 7 +++++++ .../config.d.ts | 7 +++++++ .../config.d.ts | 7 +++++++ .../config.d.ts | 6 ++++++ .../config.d.ts | 7 +++++++ .../config.d.ts | 7 +++++++ .../config.d.ts | 7 +++++++ 15 files changed, 115 insertions(+) create mode 100644 .changeset/breezy-jeans-tie.md diff --git a/.changeset/breezy-jeans-tie.md b/.changeset/breezy-jeans-tie.md new file mode 100644 index 0000000000..4601389a4c --- /dev/null +++ b/.changeset/breezy-jeans-tie.md @@ -0,0 +1,18 @@ +--- +'@backstage/plugin-auth-backend-module-cloudflare-access-provider': patch +'@backstage/plugin-auth-backend-module-vmware-cloud-provider': patch +'@backstage/plugin-auth-backend-module-atlassian-provider': patch +'@backstage/plugin-auth-backend-module-bitbucket-provider': patch +'@backstage/plugin-auth-backend-module-microsoft-provider': patch +'@backstage/plugin-auth-backend-module-onelogin-provider': patch +'@backstage/plugin-auth-backend-module-aws-alb-provider': patch +'@backstage/plugin-auth-backend-module-gcp-iap-provider': patch +'@backstage/plugin-auth-backend-module-github-provider': patch +'@backstage/plugin-auth-backend-module-gitlab-provider': patch +'@backstage/plugin-auth-backend-module-google-provider': patch +'@backstage/plugin-auth-backend-module-oauth2-provider': patch +'@backstage/plugin-auth-backend-module-oidc-provider': patch +'@backstage/plugin-auth-backend-module-okta-provider': patch +--- + +Add `signIn` to authentication provider configuration schema diff --git a/plugins/auth-backend-module-atlassian-provider/config.d.ts b/plugins/auth-backend-module-atlassian-provider/config.d.ts index d2c8a249c1..b6ca96d62f 100644 --- a/plugins/auth-backend-module-atlassian-provider/config.d.ts +++ b/plugins/auth-backend-module-atlassian-provider/config.d.ts @@ -28,6 +28,13 @@ export interface Config { audience?: string; callbackUrl?: string; additionalScopes?: string | string[]; + signIn?: { + resolvers: Array< + | { resolver: 'usernameMatchingUserEntityName' } + | { resolver: 'emailLocalPartMatchingUserEntityName' } + | { resolver: 'emailMatchingUserEntityProfileEmail' } + >; + }; }; }; }; diff --git a/plugins/auth-backend-module-aws-alb-provider/config.d.ts b/plugins/auth-backend-module-aws-alb-provider/config.d.ts index 1978e5a4df..5a3e90cf6b 100644 --- a/plugins/auth-backend-module-aws-alb-provider/config.d.ts +++ b/plugins/auth-backend-module-aws-alb-provider/config.d.ts @@ -21,6 +21,12 @@ export interface Config { awsalb?: { issuer?: string; region: string; + signIn?: { + resolvers: Array< + | { resolver: 'emailLocalPartMatchingUserEntityName' } + | { resolver: 'emailMatchingUserEntityProfileEmail' } + >; + }; }; }; }; diff --git a/plugins/auth-backend-module-bitbucket-provider/config.d.ts b/plugins/auth-backend-module-bitbucket-provider/config.d.ts index 17cac1c194..df68209469 100644 --- a/plugins/auth-backend-module-bitbucket-provider/config.d.ts +++ b/plugins/auth-backend-module-bitbucket-provider/config.d.ts @@ -26,6 +26,13 @@ export interface Config { */ clientSecret: string; additionalScopes?: string | string[]; + signIn?: { + resolvers: Array< + | { resolver: 'userIdMatchingUserEntityAnnotation' } + | { resolver: 'emailLocalPartMatchingUserEntityName' } + | { resolver: 'emailMatchingUserEntityProfileEmail' } + >; + }; }; }; }; diff --git a/plugins/auth-backend-module-cloudflare-access-provider/config.d.ts b/plugins/auth-backend-module-cloudflare-access-provider/config.d.ts index ff7d722d48..1300eb8c57 100644 --- a/plugins/auth-backend-module-cloudflare-access-provider/config.d.ts +++ b/plugins/auth-backend-module-cloudflare-access-provider/config.d.ts @@ -27,6 +27,12 @@ export interface Config { token: string; subject: string; }>; + signIn?: { + resolvers: Array< + | { resolver: 'emailLocalPartMatchingUserEntityName' } + | { resolver: 'emailMatchingUserEntityProfileEmail' } + >; + }; }; /** * The backstage token expiration. diff --git a/plugins/auth-backend-module-gcp-iap-provider/config.d.ts b/plugins/auth-backend-module-gcp-iap-provider/config.d.ts index 945378ada6..452f9819c3 100644 --- a/plugins/auth-backend-module-gcp-iap-provider/config.d.ts +++ b/plugins/auth-backend-module-gcp-iap-provider/config.d.ts @@ -32,6 +32,15 @@ export interface Config { * The name of the header to read the JWT token from, defaults to `'x-goog-iap-jwt-assertion'`. */ jwtHeader?: string; + + signIn?: { + resolvers: Array< + | { resolver: 'emailMatchingUserEntityAnnotation' } + | { resolver: 'idMatchingUserEntityAnnotation' } + | { resolver: 'emailLocalPartMatchingUserEntityName' } + | { resolver: 'emailMatchingUserEntityProfileEmail' } + >; + }; }; }; }; diff --git a/plugins/auth-backend-module-github-provider/config.d.ts b/plugins/auth-backend-module-github-provider/config.d.ts index f60d4c239d..2ca17998f0 100644 --- a/plugins/auth-backend-module-github-provider/config.d.ts +++ b/plugins/auth-backend-module-github-provider/config.d.ts @@ -28,6 +28,13 @@ export interface Config { callbackUrl?: string; enterpriseInstanceUrl?: string; additionalScopes?: string | string[]; + signIn?: { + resolvers: Array< + | { resolver: 'usernameMatchingUserEntityName' } + | { resolver: 'emailLocalPartMatchingUserEntityName' } + | { resolver: 'emailMatchingUserEntityProfileEmail' } + >; + }; }; }; }; diff --git a/plugins/auth-backend-module-gitlab-provider/config.d.ts b/plugins/auth-backend-module-gitlab-provider/config.d.ts index 18f7cb5005..d21c2bd62a 100644 --- a/plugins/auth-backend-module-gitlab-provider/config.d.ts +++ b/plugins/auth-backend-module-gitlab-provider/config.d.ts @@ -28,6 +28,13 @@ export interface Config { audience?: string; callbackUrl?: string; additionalScopes?: string | string[]; + signIn?: { + resolvers: Array< + | { resolver: 'usernameMatchingUserEntityName' } + | { resolver: 'emailLocalPartMatchingUserEntityName' } + | { resolver: 'emailMatchingUserEntityProfileEmail' } + >; + }; }; }; }; diff --git a/plugins/auth-backend-module-google-provider/config.d.ts b/plugins/auth-backend-module-google-provider/config.d.ts index 08a0e08f2b..3abab05cfe 100644 --- a/plugins/auth-backend-module-google-provider/config.d.ts +++ b/plugins/auth-backend-module-google-provider/config.d.ts @@ -27,6 +27,13 @@ export interface Config { clientSecret: string; callbackUrl?: string; additionalScopes?: string | string[]; + signIn?: { + resolvers: Array< + | { resolver: 'emailMatchingUserEntityAnnotation' } + | { resolver: 'emailLocalPartMatchingUserEntityName' } + | { resolver: 'emailMatchingUserEntityProfileEmail' } + >; + }; }; }; }; diff --git a/plugins/auth-backend-module-microsoft-provider/config.d.ts b/plugins/auth-backend-module-microsoft-provider/config.d.ts index a7ec027083..b1ed2d5766 100644 --- a/plugins/auth-backend-module-microsoft-provider/config.d.ts +++ b/plugins/auth-backend-module-microsoft-provider/config.d.ts @@ -29,6 +29,13 @@ export interface Config { domainHint?: string; callbackUrl?: string; additionalScopes?: string | string[]; + signIn?: { + resolvers: Array< + | { resolver: 'emailMatchingUserEntityAnnotation' } + | { resolver: 'emailLocalPartMatchingUserEntityName' } + | { resolver: 'emailMatchingUserEntityProfileEmail' } + >; + }; }; }; }; diff --git a/plugins/auth-backend-module-oauth2-provider/config.d.ts b/plugins/auth-backend-module-oauth2-provider/config.d.ts index 9b1ee18f1b..fa9dec7ce1 100644 --- a/plugins/auth-backend-module-oauth2-provider/config.d.ts +++ b/plugins/auth-backend-module-oauth2-provider/config.d.ts @@ -32,6 +32,13 @@ export interface Config { additionalScopes?: string | string[]; disableRefresh?: boolean; includeBasicAuth?: boolean; + signIn?: { + resolvers: Array< + | { resolver: 'usernameMatchingUserEntityName' } + | { resolver: 'emailLocalPartMatchingUserEntityName' } + | { resolver: 'emailMatchingUserEntityProfileEmail' } + >; + }; }; }; }; diff --git a/plugins/auth-backend-module-oidc-provider/config.d.ts b/plugins/auth-backend-module-oidc-provider/config.d.ts index 398e63c466..dbc06e51bb 100644 --- a/plugins/auth-backend-module-oidc-provider/config.d.ts +++ b/plugins/auth-backend-module-oidc-provider/config.d.ts @@ -31,6 +31,12 @@ export interface Config { tokenSignedResponseAlg?: string; additionalScopes?: string | string[]; prompt?: string; + signIn?: { + resolvers: Array< + | { resolver: 'emailLocalPartMatchingUserEntityName' } + | { resolver: 'emailMatchingUserEntityProfileEmail' } + >; + }; }; }; }; diff --git a/plugins/auth-backend-module-okta-provider/config.d.ts b/plugins/auth-backend-module-okta-provider/config.d.ts index aaf6ec1f91..0689171153 100644 --- a/plugins/auth-backend-module-okta-provider/config.d.ts +++ b/plugins/auth-backend-module-okta-provider/config.d.ts @@ -30,6 +30,13 @@ export interface Config { idp?: string; callbackUrl?: string; additionalScopes?: string | string[]; + signIn?: { + resolvers: Array< + | { resolver: 'emailMatchingUserEntityAnnotation' } + | { resolver: 'emailLocalPartMatchingUserEntityName' } + | { resolver: 'emailMatchingUserEntityProfileEmail' } + >; + }; }; }; }; diff --git a/plugins/auth-backend-module-onelogin-provider/config.d.ts b/plugins/auth-backend-module-onelogin-provider/config.d.ts index d4f1457461..8257e2ac71 100644 --- a/plugins/auth-backend-module-onelogin-provider/config.d.ts +++ b/plugins/auth-backend-module-onelogin-provider/config.d.ts @@ -27,6 +27,13 @@ export interface Config { clientSecret: string; issuer: string; callbackUrl?: string; + signIn?: { + resolvers: Array< + | { resolver: 'usernameMatchingUserEntityName' } + | { resolver: 'emailLocalPartMatchingUserEntityName' } + | { resolver: 'emailMatchingUserEntityProfileEmail' } + >; + }; }; }; }; diff --git a/plugins/auth-backend-module-vmware-cloud-provider/config.d.ts b/plugins/auth-backend-module-vmware-cloud-provider/config.d.ts index 6ea07f1936..a08451cff3 100644 --- a/plugins/auth-backend-module-vmware-cloud-provider/config.d.ts +++ b/plugins/auth-backend-module-vmware-cloud-provider/config.d.ts @@ -25,6 +25,13 @@ export interface Config { scope?: string; consoleEndpoint?: string; additionalScopes?: string | string[]; + signIn?: { + resolvers: Array< + | { resolver: 'profileEmailMatchingUserEntityEmail' } + | { resolver: 'emailLocalPartMatchingUserEntityName' } + | { resolver: 'emailMatchingUserEntityProfileEmail' } + >; + }; }; }; }; From ee2b0e54330409df51f9ed2ac78090c77afd8f53 Mon Sep 17 00:00:00 2001 From: MT Lewis <mtlewis@users.noreply.github.com> Date: Wed, 17 Jul 2024 17:08:02 +0100 Subject: [PATCH 296/416] cli: add support for forcing use of react development when building Signed-off-by: MT Lewis <mtlewis@users.noreply.github.com> --- .changeset/little-bulldogs-guess.md | 8 +++++ packages/cli/src/lib/bundler/config.ts | 44 +++++++++++++++++++++++--- 2 files changed, 48 insertions(+), 4 deletions(-) create mode 100644 .changeset/little-bulldogs-guess.md diff --git a/.changeset/little-bulldogs-guess.md b/.changeset/little-bulldogs-guess.md new file mode 100644 index 0000000000..8d247a182b --- /dev/null +++ b/.changeset/little-bulldogs-guess.md @@ -0,0 +1,8 @@ +--- +'@backstage/cli': patch +--- + +Add ability to force use of the development versions of `react` and `react-dom` +by setting the `FORCE_REACT_DEVELOPMENT` environment variable to `true` when +building, for example by using a command like `FORCE_REACT_DEVELOPMENT=true yarn +build:all`. diff --git a/packages/cli/src/lib/bundler/config.ts b/packages/cli/src/lib/bundler/config.ts index 60c8a7be66..44cdc4a475 100644 --- a/packages/cli/src/lib/bundler/config.ts +++ b/packages/cli/src/lib/bundler/config.ts @@ -15,7 +15,8 @@ */ import { BackendBundlingOptions, BundlingOptions } from './types'; -import { posix as posixPath, resolve as resolvePath } from 'path'; +import { posix as posixPath, resolve as resolvePath, dirname } from 'path'; +import chalk from 'chalk'; import webpack, { ProvidePlugin } from 'webpack'; import { BackstagePackage } from '@backstage/cli-node'; @@ -33,7 +34,7 @@ import fs from 'fs-extra'; import { getPackages } from '@manypkg/get-packages'; import { isChildPath } from '@backstage/cli-common'; import nodeExternals from 'webpack-node-externals'; -import { optimization } from './optimization'; +import { optimization as optimizationConfig } from './optimization'; import pickBy from 'lodash/pickBy'; import { readEntryPoints } from '../entryPoints'; import { runPlain } from '../run'; @@ -232,12 +233,47 @@ export async function createConfig( require.resolve('react-refresh'), ]; + const mode = isDev ? 'development' : 'production'; + const optimization = optimizationConfig(options); + + if (process.env.FORCE_REACT_DEVELOPMENT === 'true') { + console.log( + chalk.yellow( + `⚠️ WARNING: Forcing react and react-dom into development mode. This build should not be used in production.`, + ), + ); + + const reactPackageDirs = [ + `${dirname(require.resolve('react/package.json'))}/`, + `${dirname(require.resolve('react-dom/package.json'))}/`, + ]; + + // Don't define process.env.NODE_ENV with value matching config.mode. + optimization.nodeEnv = false; + + // Instead, provide a custom definition which always uses "development" if + // the module is part of `react` or `react-dom`, and `config.mode` otherwise. + plugins.push( + new webpack.DefinePlugin({ + 'process.env.NODE_ENV': webpack.DefinePlugin.runtimeValue( + ({ module }) => { + if (reactPackageDirs.some(val => module.resource.startsWith(val))) { + return '"development"'; + } + + return `"${mode}"`; + }, + ), + }), + ); + } + const withCache = yn(process.env[BUILD_CACHE_ENV_VAR], { default: false }); return { - mode: isDev ? 'development' : 'production', + mode, profile: false, - optimization: optimization(options), + optimization, bail: false, performance: { hints: false, // we check the gzip size instead From 7eb08a69dd0cdc11fdf363a07149a8ca9438eadd Mon Sep 17 00:00:00 2001 From: MT Lewis <mtlewis@users.noreply.github.com> Date: Wed, 17 Jul 2024 20:53:55 +0100 Subject: [PATCH 297/416] cli: allow linting packages with role dynamic-frontend-container Signed-off-by: MT Lewis <mtlewis@users.noreply.github.com> --- .changeset/bright-trainers-brake.md | 5 +++++ packages/cli/config/eslint-factory.js | 1 + 2 files changed, 6 insertions(+) create mode 100644 .changeset/bright-trainers-brake.md diff --git a/.changeset/bright-trainers-brake.md b/.changeset/bright-trainers-brake.md new file mode 100644 index 0000000000..2299d83a32 --- /dev/null +++ b/.changeset/bright-trainers-brake.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Add frontend-dynamic-container role to eslint config factory diff --git a/packages/cli/config/eslint-factory.js b/packages/cli/config/eslint-factory.js index 6bc200cade..96d8478ec0 100644 --- a/packages/cli/config/eslint-factory.js +++ b/packages/cli/config/eslint-factory.js @@ -201,6 +201,7 @@ function createConfigForRole(dir, role, extraConfig = {}) { case 'frontend': case 'frontend-plugin': case 'frontend-plugin-module': + case 'frontend-dynamic-container': return createConfig(dir, { ...extraConfig, extends: [ From 46e949f5ed570aefcc6917f4e771f633aef714e3 Mon Sep 17 00:00:00 2001 From: Francisco Meneses <fmeneses@redhat.com> Date: Wed, 17 Jul 2024 17:16:29 -0400 Subject: [PATCH 298/416] fix Spanish welcomeTitle message Signed-off-by: Francisco Meneses <fmeneses@redhat.com> --- .../WelcomeTitle/locales/goodAfternoon.locales.json | 1 + .../WelcomeTitle/locales/goodEvening.locales.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/home/src/homePageComponents/WelcomeTitle/locales/goodAfternoon.locales.json b/plugins/home/src/homePageComponents/WelcomeTitle/locales/goodAfternoon.locales.json index 9010ba4359..ddb51654fa 100644 --- a/plugins/home/src/homePageComponents/WelcomeTitle/locales/goodAfternoon.locales.json +++ b/plugins/home/src/homePageComponents/WelcomeTitle/locales/goodAfternoon.locales.json @@ -103,6 +103,7 @@ "Sinhala": "සුභ දවාලක්", "Slovenian": "Dober dan", "Somali": "Galab wanaagsan", + "Spanish": "Buenas tardes", "Southern Sámi": "Buerie biejjie", "Sumerian": "𒄭𒌓𒁀", "Swahili": "Habari ya mchana", diff --git a/plugins/home/src/homePageComponents/WelcomeTitle/locales/goodEvening.locales.json b/plugins/home/src/homePageComponents/WelcomeTitle/locales/goodEvening.locales.json index 5a98abafaa..c8d8c7334e 100644 --- a/plugins/home/src/homePageComponents/WelcomeTitle/locales/goodEvening.locales.json +++ b/plugins/home/src/homePageComponents/WelcomeTitle/locales/goodEvening.locales.json @@ -85,7 +85,7 @@ "Slovak": "Dober vecher", "Slovenian": "Dober vecher", "Somali": "Habeen wanaagsan", - "Spanish": "Buenas tardes", + "Spanish": "Buenas noches", "Sumerian": "𒄭𒈪", "Swedish": "God afton", "Tagalog": "Magandang gabi", From fdcc05947fc7447a28d3090235d882896e37d10a Mon Sep 17 00:00:00 2001 From: Francisco Meneses <fmeneses@redhat.com> Date: Wed, 17 Jul 2024 17:34:17 -0400 Subject: [PATCH 299/416] add changeset Signed-off-by: Francisco Meneses <fmeneses@redhat.com> --- .changeset/slow-toes-jog.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/slow-toes-jog.md diff --git a/.changeset/slow-toes-jog.md b/.changeset/slow-toes-jog.md new file mode 100644 index 0000000000..245feab544 --- /dev/null +++ b/.changeset/slow-toes-jog.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-home': patch +--- + +Fixed a bug on the WelcomeTitle component where the welcome message wasn't correct when the language was set to Spanish From 644d4696c28ca675efc0f240c428b5f43547f734 Mon Sep 17 00:00:00 2001 From: MT Lewis <mtlewis@users.noreply.github.com> Date: Thu, 18 Jul 2024 10:35:40 +0100 Subject: [PATCH 300/416] cli: only allow forcing react development mode when module federation is enabled Signed-off-by: MT Lewis <mtlewis@users.noreply.github.com> --- .changeset/little-bulldogs-guess.md | 15 ++++++++++++--- packages/cli/src/lib/bundler/config.ts | 5 ++++- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/.changeset/little-bulldogs-guess.md b/.changeset/little-bulldogs-guess.md index 8d247a182b..1f86f0a67f 100644 --- a/.changeset/little-bulldogs-guess.md +++ b/.changeset/little-bulldogs-guess.md @@ -3,6 +3,15 @@ --- Add ability to force use of the development versions of `react` and `react-dom` -by setting the `FORCE_REACT_DEVELOPMENT` environment variable to `true` when -building, for example by using a command like `FORCE_REACT_DEVELOPMENT=true yarn -build:all`. +to allow for detailed error messages and use of fast-refresh. Note that builds +with the development versions of `react` and `react-dom` should not be +deployed in production. + +This feature can be used by setting the `FORCE_REACT_DEVELOPMENT` environment +variable to `true`: + +```bash +EXPERIMENTAL_MODULE_FEDERATION=true \ +FORCE_REACT_DEVELOPMENT=true \ +yarn build:all +``` diff --git a/packages/cli/src/lib/bundler/config.ts b/packages/cli/src/lib/bundler/config.ts index 44cdc4a475..8e3d7eee19 100644 --- a/packages/cli/src/lib/bundler/config.ts +++ b/packages/cli/src/lib/bundler/config.ts @@ -236,7 +236,10 @@ export async function createConfig( const mode = isDev ? 'development' : 'production'; const optimization = optimizationConfig(options); - if (process.env.FORCE_REACT_DEVELOPMENT === 'true') { + if ( + process.env.EXPERIMENTAL_MODULE_FEDERATION === 'true' && + process.env.FORCE_REACT_DEVELOPMENT === 'true' + ) { console.log( chalk.yellow( `⚠️ WARNING: Forcing react and react-dom into development mode. This build should not be used in production.`, From ec950c58caac142a311225af4463e50982f7ee11 Mon Sep 17 00:00:00 2001 From: blam <ben@blam.sh> Date: Thu, 18 Jul 2024 12:35:16 +0200 Subject: [PATCH 301/416] chore: remove app-api dependency Signed-off-by: blam <ben@blam.sh> --- plugins/search-backend-module-pg/package.json | 1 - yarn.lock | 1 - 2 files changed, 2 deletions(-) diff --git a/plugins/search-backend-module-pg/package.json b/plugins/search-backend-module-pg/package.json index 8bdcf14306..1693c14c8a 100644 --- a/plugins/search-backend-module-pg/package.json +++ b/plugins/search-backend-module-pg/package.json @@ -49,7 +49,6 @@ "test": "backstage-cli package test" }, "dependencies": { - "@backstage/backend-app-api": "workspace:^", "@backstage/backend-common": "workspace:^", "@backstage/backend-plugin-api": "workspace:^", "@backstage/config": "workspace:^", diff --git a/yarn.lock b/yarn.lock index c6a1d2139a..9261d70f21 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7271,7 +7271,6 @@ __metadata: version: 0.0.0-use.local resolution: "@backstage/plugin-search-backend-module-pg@workspace:plugins/search-backend-module-pg" dependencies: - "@backstage/backend-app-api": "workspace:^" "@backstage/backend-common": "workspace:^" "@backstage/backend-plugin-api": "workspace:^" "@backstage/backend-test-utils": "workspace:^" From d3d6f5e9ec07a34dc9d6c66c84493629d75ea0a4 Mon Sep 17 00:00:00 2001 From: blam <ben@blam.sh> Date: Thu, 18 Jul 2024 12:42:16 +0200 Subject: [PATCH 302/416] chore: remove app-api dep Signed-off-by: blam <ben@blam.sh> --- packages/backend-dynamic-feature-service/package.json | 3 ++- .../src/schemas/rootLoggerServiceFactory.ts | 4 ++-- yarn.lock | 1 + 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/backend-dynamic-feature-service/package.json b/packages/backend-dynamic-feature-service/package.json index 0d05b97bd9..c693135f30 100644 --- a/packages/backend-dynamic-feature-service/package.json +++ b/packages/backend-dynamic-feature-service/package.json @@ -41,8 +41,8 @@ "start": "backstage-cli package start" }, "dependencies": { - "@backstage/backend-app-api": "workspace:^", "@backstage/backend-common": "workspace:^", + "@backstage/backend-defaults": "workspace:^", "@backstage/backend-plugin-api": "workspace:^", "@backstage/backend-tasks": "workspace:^", "@backstage/cli-common": "workspace:^", @@ -70,6 +70,7 @@ "winston": "^3.2.1" }, "devDependencies": { + "@backstage/backend-app-api": "workspace:^", "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", "wait-for-expect": "^3.0.2" diff --git a/packages/backend-dynamic-feature-service/src/schemas/rootLoggerServiceFactory.ts b/packages/backend-dynamic-feature-service/src/schemas/rootLoggerServiceFactory.ts index 6681a65a75..bf3df3ffe7 100644 --- a/packages/backend-dynamic-feature-service/src/schemas/rootLoggerServiceFactory.ts +++ b/packages/backend-dynamic-feature-service/src/schemas/rootLoggerServiceFactory.ts @@ -18,9 +18,9 @@ import { createServiceFactory, coreServices, } from '@backstage/backend-plugin-api'; -import { WinstonLogger } from '@backstage/backend-app-api'; +import { WinstonLogger } from '@backstage/backend-defaults/rootLogger'; import { transports, format } from 'winston'; -import { createConfigSecretEnumerator } from '@backstage/backend-app-api'; +import { createConfigSecretEnumerator } from '@backstage/backend-defaults/rootLogger'; import { loadConfigSchema } from '@backstage/config-loader'; import { getPackages } from '@manypkg/get-packages'; import { dynamicPluginsSchemasServiceRef } from './schemas'; diff --git a/yarn.lock b/yarn.lock index 9261d70f21..53bef5284a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3708,6 +3708,7 @@ __metadata: dependencies: "@backstage/backend-app-api": "workspace:^" "@backstage/backend-common": "workspace:^" + "@backstage/backend-defaults": "workspace:^" "@backstage/backend-plugin-api": "workspace:^" "@backstage/backend-tasks": "workspace:^" "@backstage/backend-test-utils": "workspace:^" From 7251567926578e77bddd0f87ec668b91209826e8 Mon Sep 17 00:00:00 2001 From: blam <ben@blam.sh> Date: Thu, 18 Jul 2024 12:43:24 +0200 Subject: [PATCH 303/416] chore: changeset Signed-off-by: blam <ben@blam.sh> --- .changeset/nine-glasses-nail.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/nine-glasses-nail.md diff --git a/.changeset/nine-glasses-nail.md b/.changeset/nine-glasses-nail.md new file mode 100644 index 0000000000..0d68da9f2b --- /dev/null +++ b/.changeset/nine-glasses-nail.md @@ -0,0 +1,6 @@ +--- +'@backstage/backend-dynamic-feature-service': patch +'@backstage/plugin-search-backend-module-pg': patch +--- + +Removing `@backstage/backend-app-api` dependency From 0a40f13580e9b6af226ab6bdbd49e2505d988a2c Mon Sep 17 00:00:00 2001 From: blam <ben@blam.sh> Date: Thu, 18 Jul 2024 13:05:32 +0200 Subject: [PATCH 304/416] chore: wip Signed-off-by: blam <ben@blam.sh> --- .../src/components/TabbedLayout/RoutedTabs.tsx | 3 +++ .../src/layout/HeaderTabs/HeaderTabs.test.tsx | 9 --------- .../core-components/src/layout/HeaderTabs/HeaderTabs.tsx | 7 +------ 3 files changed, 4 insertions(+), 15 deletions(-) diff --git a/packages/core-components/src/components/TabbedLayout/RoutedTabs.tsx b/packages/core-components/src/components/TabbedLayout/RoutedTabs.tsx index 2c727efe1b..6a5bf2970f 100644 --- a/packages/core-components/src/components/TabbedLayout/RoutedTabs.tsx +++ b/packages/core-components/src/components/TabbedLayout/RoutedTabs.tsx @@ -96,6 +96,9 @@ export function RoutedTabs(props: { routes: SubRoute[] }) { tabs={headerTabs} selectedIndex={index} onChange={onTabChange} + tabProps={{ + component: Link, + }} /> <Content> <Helmet title={route?.title} /> diff --git a/packages/core-components/src/layout/HeaderTabs/HeaderTabs.test.tsx b/packages/core-components/src/layout/HeaderTabs/HeaderTabs.test.tsx index dad40c4615..5aec83bc2b 100644 --- a/packages/core-components/src/layout/HeaderTabs/HeaderTabs.test.tsx +++ b/packages/core-components/src/layout/HeaderTabs/HeaderTabs.test.tsx @@ -95,13 +95,4 @@ describe('<HeaderTabs />', () => { await user.click(rendered.getByText('Docs')); expect(mockOnChange).toHaveBeenCalledTimes(1); }); - - it('should render 2 nav tabs', async () => { - const rendered = await renderInTestApp(<HeaderTabs tabs={mockTabs} />); - const tabs = rendered.queryAllByTestId(id => id.startsWith('header-tab')); - expect(tabs).toHaveLength(2); - tabs.forEach(tab => { - expect(tab.tagName.toLocaleLowerCase('en-US')).toBe('a'); - }); - }); }); diff --git a/packages/core-components/src/layout/HeaderTabs/HeaderTabs.tsx b/packages/core-components/src/layout/HeaderTabs/HeaderTabs.tsx index 9ee9c5525f..002c9fe1ea 100644 --- a/packages/core-components/src/layout/HeaderTabs/HeaderTabs.tsx +++ b/packages/core-components/src/layout/HeaderTabs/HeaderTabs.tsx @@ -18,7 +18,6 @@ import { makeStyles } from '@material-ui/core/styles'; import TabUI, { TabProps } from '@material-ui/core/Tab'; import Tabs from '@material-ui/core/Tabs'; import React, { useCallback, useEffect, useState } from 'react'; -import { Link } from '../../components/Link'; // TODO(blam): Remove this implementation when the Tabs are ready // This is just a temporary solution to implementing tabs for now @@ -96,9 +95,7 @@ export function HeaderTabs(props: HeaderTabsProps) { setSelectedTab(selectedIndex); } }, [selectedIndex]); - function removeLeadingSlash(path: string) { - return path.replace(/^\//, ''); - } + return ( <Box className={styles.tabsWrapper}> <Tabs @@ -115,8 +112,6 @@ export function HeaderTabs(props: HeaderTabsProps) { data-testid={`header-tab-${index}`} label={tab.label} key={tab.id} - component={Link} - to={removeLeadingSlash(tab.id)} value={index} className={styles.defaultTab} classes={{ selected: styles.selected, root: styles.tabRoot }} From 1f5094f1b70495aba6ee8d54bb86ed5dcea6b410 Mon Sep 17 00:00:00 2001 From: Ben Lambert <blam@spotify.com> Date: Wed, 26 Jun 2024 16:20:47 +0200 Subject: [PATCH 305/416] Update dry-squids-tap.md Signed-off-by: Ben Lambert <blam@spotify.com> Signed-off-by: blam <ben@blam.sh> --- .changeset/dry-squids-tap.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.changeset/dry-squids-tap.md b/.changeset/dry-squids-tap.md index 5193e1f204..9bd835d371 100644 --- a/.changeset/dry-squids-tap.md +++ b/.changeset/dry-squids-tap.md @@ -14,9 +14,9 @@ const TestExtensionKind = createExtensionKind({ output: { element: coreExtensionData.reactElement, }, - factory(_, props: { text: string }) { + factory(_, options: { text: string }) { return { - element: <h1>{props.text}</h1>, + element: <h1>{options.text}</h1>, }; }, }); From f749bb8fa989e5f4c29608a903cc9119cd745390 Mon Sep 17 00:00:00 2001 From: blam <ben@blam.sh> Date: Tue, 25 Jun 2024 14:25:22 +0200 Subject: [PATCH 306/416] chore: extension overrides spike Signed-off-by: blam <ben@blam.sh> --- .../core-compat-api/src/convertLegacyApp.ts | 72 ++++++++++- .../src/wiring/createExtension.test.ts | 33 +++++ .../src/wiring/createExtension.ts | 121 ++++++++++++++---- .../src/wiring/createExtensionKind.ts | 4 +- 4 files changed, 194 insertions(+), 36 deletions(-) diff --git a/packages/core-compat-api/src/convertLegacyApp.ts b/packages/core-compat-api/src/convertLegacyApp.ts index 72ce4b5e61..567e5efcad 100644 --- a/packages/core-compat-api/src/convertLegacyApp.ts +++ b/packages/core-compat-api/src/convertLegacyApp.ts @@ -26,6 +26,7 @@ import { coreExtensionData, createExtension, createExtensionInput, + createExtensionKind, createExtensionOverrides, } from '@backstage/frontend-plugin-api'; import { getComponentData } from '@backstage/core-plugin-api'; @@ -128,21 +129,80 @@ export function convertLegacyApp( }; }, }); - const CoreNavOverride = createExtension({ - namespace: 'app', - name: 'nav', - attachTo: { id: 'app/layout', input: 'nav' }, - output: {}, + + const CoreNavOverride = CurrentCoreNav.override({ + // namespace: 'app', + // name: 'nav', + // attachTo: { id: 'app/layout', input: 'nav' }, + // output: {}, factory: () => ({}), disabled: true, }); + createExtensionOverride({ + extension: CurrentCoreNav, + factory: () => null, + }); + const collectedRoutes = collectLegacyRoutes(routesEl); return [ ...collectedRoutes, createExtensionOverrides({ - extensions: [CoreLayoutOverride, CoreNavOverride], + extensions: [CoreNavOverride, CoreNavOverride], }), ]; } + +const EntityCardExtension = createExtensionKind({ + kind: 'entity-card', + attachTo: { id: 'entity-card', input: 'default' }, + inputs: { + loader: createExtensionInput({ + element: coreExtensionData.reactElement, + }), + }, + output: { + element: coreExtensionData.reactElement, + }, + factory({ inputs }, props: { title: string }) { + console.log(inputs.loader); + return { + element: React.createElement('h1'), + }; + }, +}); + +const GithubCard = EntityCardExtension.new({ + props: { + title: 'GitHub Card', + }, + factory({ inputs: { loader } }) { + console.log(loader); + return { + element: React.createElement('h2'), + }; + }, +}); + +GithubCard.override({ + attachTo: { id: 'entity-card', input: 'github' }, + inputs: { + loader: createExtensionInput( + { + element: coreExtensionData.reactElement, + }, + { singleton: false }, + ), + loader2: createExtensionInput({ + element: coreExtensionData.reactElement, + }), + }, + factory({ originalFactory, inputs }) { + inputs.loader2; + inputs.loader; + return originalFactory({ + inputsOverride: inputs, + }); + }, +}); diff --git a/packages/frontend-plugin-api/src/wiring/createExtension.test.ts b/packages/frontend-plugin-api/src/wiring/createExtension.test.ts index 42ab21db80..cfef69b0fe 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtension.test.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtension.test.ts @@ -291,4 +291,37 @@ describe('createExtension', () => { 'ExtensionDefinition{namespace=test,attachTo=root@default}', ); }); + + describe('override', () => { + it('should create an extension override', () => { + const extension = createExtension({ + namespace: 'test', + attachTo: { id: 'root', input: 'default' }, + output: { + foo: stringData, + }, + factory() { + return { + foo: 'bar', + }; + }, + }); + + const override = extension.override({ + attachTo: { + id: 'root', + input: 'default2', + }, + factory() { + return { + foo: 'baz', + }; + }, + }); + + expect(String(override)).toBe( + 'ExtensionDefinition{namespace=test,attachTo=root@default2}', + ); + }); + }); }); diff --git a/packages/frontend-plugin-api/src/wiring/createExtension.ts b/packages/frontend-plugin-api/src/wiring/createExtension.ts index 28dc6a4e29..b56cc39fc9 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtension.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtension.ts @@ -99,7 +99,33 @@ export interface CreateExtensionOptions< } /** @public */ -export interface ExtensionDefinition<TConfig> { +export interface ExtensionDefinitionOverrides< + TOriginalConfig, + TOriginalInputs extends AnyExtensionInputMap, + TOverrideInputs extends AnyExtensionInputMap, +> { + readonly disabled?: boolean; + readonly attachTo?: { id: string; input: string }; + // TODO: inputs (only adding to the list? or redefine arity and superset of old type on existing input?) + // TODO: config (any merging needed on there?) + inputs?: TOverrideInputs; + factory?(options: { + node: AppNode; + config: TOriginalConfig; + inputs: Expand<ResolvedExtensionInputs<TOriginalInputs & TOverrideInputs>>; + originalFactory: (originalFactoryOptions?: { + inputsOverride?: ResolvedExtensionInputs< + TOriginalInputs & TOverrideInputs + >; + }) => ExtensionDataValues<any>; + }): ExtensionDataValues<any>; +} + +/** @public */ +export interface ExtensionDefinition< + TConfig, + TInputs extends AnyExtensionInputMap, +> { $$type: '@backstage/ExtensionDefinition'; readonly kind?: string; readonly namespace?: string; @@ -107,13 +133,18 @@ export interface ExtensionDefinition<TConfig> { readonly attachTo: { id: string; input: string }; readonly disabled: boolean; readonly configSchema?: PortableSchema<TConfig>; + override<TOverrideInputs extends AnyExtensionInputMap>( + overrides: ExtensionDefinitionOverrides<TConfig, TInputs, TOverrideInputs>, + ): ExtensionDefinition<TConfig, TInputs>; } /** @internal */ -export interface InternalExtensionDefinition<TConfig> - extends ExtensionDefinition<TConfig> { +export interface InternalExtensionDefinition< + TConfig, + TInputs extends AnyExtensionInputMap, +> extends ExtensionDefinition<TConfig, TInputs> { readonly version: 'v1'; - readonly inputs: AnyExtensionInputMap; + readonly inputs: TInputs; readonly output: AnyExtensionDataMap; factory(context: { node: AppNode; @@ -123,10 +154,13 @@ export interface InternalExtensionDefinition<TConfig> } /** @internal */ -export function toInternalExtensionDefinition<TConfig>( - overrides: ExtensionDefinition<TConfig>, -): InternalExtensionDefinition<TConfig> { - const internal = overrides as InternalExtensionDefinition<TConfig>; +export function toInternalExtensionDefinition< + TConfig, + TInputs extends AnyExtensionInputMap, +>( + overrides: ExtensionDefinition<TConfig, TInputs>, +): InternalExtensionDefinition<TConfig, TInputs> { + const internal = overrides as InternalExtensionDefinition<TConfig, TInputs>; if (internal.$$type !== '@backstage/ExtensionDefinition') { throw new Error( `Invalid extension definition instance, bad type '${internal.$$type}'`, @@ -147,38 +181,69 @@ export function createExtension< TConfig = never, >( options: CreateExtensionOptions<TOutput, TInputs, TConfig>, -): ExtensionDefinition<TConfig> { +): ExtensionDefinition<TConfig, TInputs> { + const { + kind, + namespace, + name, + attachTo, + disabled = false, + inputs = {} as TInputs, + output, + configSchema, + factory, + } = options; + return { $$type: '@backstage/ExtensionDefinition', version: 'v1', - 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 }) { + kind, + namespace, + name, + attachTo, + disabled, + inputs, + output, + configSchema, + factory({ inputs: factoryInputs, ...rest }) { // TODO: Simplify this, but TS wouldn't infer the input type for some reason - return options.factory({ - inputs: inputs as Expand<ResolvedExtensionInputs<TInputs>>, + return factory({ + inputs: factoryInputs as Expand<ResolvedExtensionInputs<TInputs>>, ...rest, }); }, toString() { const parts: string[] = []; - if (options.kind) { - parts.push(`kind=${options.kind}`); + if (kind) { + parts.push(`kind=${kind}`); } - if (options.namespace) { - parts.push(`namespace=${options.namespace}`); + if (namespace) { + parts.push(`namespace=${namespace}`); } - if (options.name) { - parts.push(`name=${options.name}`); + if (name) { + parts.push(`name=${name}`); } - parts.push(`attachTo=${options.attachTo.id}@${options.attachTo.input}`); + parts.push(`attachTo=${attachTo.id}@${attachTo.input}`); return `ExtensionDefinition{${parts.join(',')}}`; }, - } as InternalExtensionDefinition<TConfig>; + override<TOverrideInputs extends AnyExtensionInputMap>( + overrides: ExtensionDefinitionOverrides< + TConfig, + TInputs, + TOverrideInputs + >, + ): ExtensionDefinition<TConfig, TInputs> { + return createExtension({ + kind, + namespace, + name, + attachTo: overrides.attachTo ?? attachTo, + disabled: overrides.disabled ?? disabled, + inputs: { ...inputs, ...overrides.inputs }, + output, + configSchema, + factory, + }); + }, + } as InternalExtensionDefinition<TConfig, TInputs>; } diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionKind.ts b/packages/frontend-plugin-api/src/wiring/createExtensionKind.ts index 52bf711822..353fb8ab70 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtensionKind.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtensionKind.ts @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - import { AppNode } from '../apis'; import { PortableSchema } from '../schema'; import { Expand } from '../types'; @@ -21,6 +20,7 @@ import { AnyExtensionDataMap, AnyExtensionInputMap, ExtensionDataValues, + ExtensionDefinition, ResolvedExtensionInputs, createExtension, } from './createExtension'; @@ -107,7 +107,7 @@ export class ExtensionKind< }, options: TOptions, ): Expand<ExtensionDataValues<TOutput>>; - }) { + }): ExtensionDefinition<TConfig, TInputs> { return createExtension({ kind: this.options.kind, namespace: args.namespace ?? this.options.namespace, From 966cca176bc0506034499ce2cb622ebdffe2ca1b Mon Sep 17 00:00:00 2001 From: blam <ben@blam.sh> Date: Wed, 26 Jun 2024 16:31:25 +0200 Subject: [PATCH 307/416] chore: tidying up Signed-off-by: blam <ben@blam.sh> Signed-off-by: blam <ben@blam.sh> --- .../core-compat-api/src/convertLegacyApp.ts | 72 +---- packages/frontend-plugin-api/api-report.md | 214 ++++++++++----- .../src/wiring/createExtension.test.ts | 33 --- .../src/wiring/createExtension.ts | 125 +++------ .../src/wiring/createExtensionKind.test.tsx | 164 ++++++++++++ .../src/wiring/createExtensionKind.ts | 245 ++++++++++++++---- .../frontend-plugin-api/src/wiring/index.ts | 4 +- 7 files changed, 550 insertions(+), 307 deletions(-) diff --git a/packages/core-compat-api/src/convertLegacyApp.ts b/packages/core-compat-api/src/convertLegacyApp.ts index 567e5efcad..72ce4b5e61 100644 --- a/packages/core-compat-api/src/convertLegacyApp.ts +++ b/packages/core-compat-api/src/convertLegacyApp.ts @@ -26,7 +26,6 @@ import { coreExtensionData, createExtension, createExtensionInput, - createExtensionKind, createExtensionOverrides, } from '@backstage/frontend-plugin-api'; import { getComponentData } from '@backstage/core-plugin-api'; @@ -129,80 +128,21 @@ export function convertLegacyApp( }; }, }); - - const CoreNavOverride = CurrentCoreNav.override({ - // namespace: 'app', - // name: 'nav', - // attachTo: { id: 'app/layout', input: 'nav' }, - // output: {}, + const CoreNavOverride = createExtension({ + namespace: 'app', + name: 'nav', + attachTo: { id: 'app/layout', input: 'nav' }, + output: {}, factory: () => ({}), disabled: true, }); - createExtensionOverride({ - extension: CurrentCoreNav, - factory: () => null, - }); - const collectedRoutes = collectLegacyRoutes(routesEl); return [ ...collectedRoutes, createExtensionOverrides({ - extensions: [CoreNavOverride, CoreNavOverride], + extensions: [CoreLayoutOverride, CoreNavOverride], }), ]; } - -const EntityCardExtension = createExtensionKind({ - kind: 'entity-card', - attachTo: { id: 'entity-card', input: 'default' }, - inputs: { - loader: createExtensionInput({ - element: coreExtensionData.reactElement, - }), - }, - output: { - element: coreExtensionData.reactElement, - }, - factory({ inputs }, props: { title: string }) { - console.log(inputs.loader); - return { - element: React.createElement('h1'), - }; - }, -}); - -const GithubCard = EntityCardExtension.new({ - props: { - title: 'GitHub Card', - }, - factory({ inputs: { loader } }) { - console.log(loader); - return { - element: React.createElement('h2'), - }; - }, -}); - -GithubCard.override({ - attachTo: { id: 'entity-card', input: 'github' }, - inputs: { - loader: createExtensionInput( - { - element: coreExtensionData.reactElement, - }, - { singleton: false }, - ), - loader2: createExtensionInput({ - element: coreExtensionData.reactElement, - }), - }, - factory({ originalFactory, inputs }) { - inputs.loader2; - inputs.loader; - return originalFactory({ - inputsOverride: inputs, - }); - }, -}); diff --git a/packages/frontend-plugin-api/api-report.md b/packages/frontend-plugin-api/api-report.md index 48718f5375..6a04d04cd6 100644 --- a/packages/frontend-plugin-api/api-report.md +++ b/packages/frontend-plugin-api/api-report.md @@ -529,9 +529,91 @@ export function createExtensionKind< TOutput extends AnyExtensionDataMap, TConfig, >( - options: ExtensionKindOptions<TOptions, TInputs, TOutput, TConfig>, + options: CreateExtensionKindOptions<TOptions, TInputs, TOutput, TConfig>, ): ExtensionKind<TOptions, TInputs, TOutput, TConfig>; +// @public (undocumented) +export interface CreateExtensionKindInstanceOptions< + TOptions, + TInputs extends AnyExtensionInputMap, + TOutput extends AnyExtensionDataMap, + TConfig, +> { + // (undocumented) + attachTo?: { + id: string; + input: string; + }; + // (undocumented) + configSchema?: PortableSchema<TConfig>; + // (undocumented) + disabled?: boolean; + // (undocumented) + factory?( + context: { + node: AppNode; + config: TConfig; + inputs: Expand<ResolvedExtensionInputs<TInputs>>; + originalFactory( + context?: { + node?: AppNode; + config?: TConfig; + inputs?: Expand<ResolvedExtensionInputs<TInputs>>; + }, + options?: TOptions, + ): Expand<ExtensionDataValues<TOutput>>; + }, + options: TOptions, + ): Expand<ExtensionDataValues<TOutput>>; + // (undocumented) + inputs?: TInputs; + // (undocumented) + name?: string; + // (undocumented) + namespace?: string; + // (undocumented) + options: TOptions; + // (undocumented) + output?: TOutput; +} + +// @public (undocumented) +export interface CreateExtensionKindOptions< + TOptions, + TInputs extends AnyExtensionInputMap, + TOutput extends AnyExtensionDataMap, + TConfig, +> { + // (undocumented) + attachTo: { + id: string; + input: string; + }; + // (undocumented) + configSchema?: PortableSchema<TConfig>; + // (undocumented) + disabled?: boolean; + // (undocumented) + factory( + context: { + node: AppNode; + config: TConfig; + inputs: Expand<ResolvedExtensionInputs<TInputs>>; + }, + options: TOptions, + ): Expand<ExtensionDataValues<TOutput>>; + // (undocumented) + inputs?: TInputs; + // (undocumented) + kind: string; + // (undocumented) + name?: string; + // (undocumented) + namespace?: string; + // (undocumented) + output: TOutput; +} + // @public (undocumented) export interface CreateExtensionOptions< TOutput extends AnyExtensionDataMap, @@ -548,7 +630,7 @@ export interface CreateExtensionOptions< // (undocumented) disabled?: boolean; // (undocumented) - factory(context: { + factory(options: { node: AppNode; config: TConfig; inputs: Expand<ResolvedExtensionInputs<TInputs>>; @@ -565,6 +647,51 @@ export interface CreateExtensionOptions< output: TOutput; } +// @public (undocumented) +export interface CreateExtensionOverrideKindInstanceOptions< + TOptions, + TInputs extends AnyExtensionInputMap, + TOutput extends AnyExtensionDataMap, + TConfig, +> { + // (undocumented) + attachTo?: { + id: string; + input: string; + }; + // (undocumented) + configSchema?: PortableSchema<TConfig>; + // (undocumented) + disabled?: boolean; + // (undocumented) + factory?( + context: { + node: AppNode; + config: TConfig; + inputs: Expand<ResolvedExtensionInputs<TInputs>>; + originalFactory( + context?: { + node?: AppNode; + config?: TConfig; + inputs?: Expand<ResolvedExtensionInputs<TInputs>>; + }, + options?: TOptions, + ): Expand<ExtensionDataValues<TOutput>>; + }, + options: TOptions, + ): Expand<ExtensionDataValues<TOutput>>; + // (undocumented) + inputs?: TInputs; + // (undocumented) + name?: string; + // (undocumented) + namespace?: string; + // (undocumented) + options?: TOptions; + // (undocumented) + output?: TOutput; +} + // @public (undocumented) export function createExtensionOverrides( options: ExtensionOverridesOptions, @@ -937,75 +1064,26 @@ export class ExtensionKind< TOutput extends AnyExtensionDataMap, TConfig, >( - options: ExtensionKindOptions<TOptions, TInputs, TOutput, TConfig>, + options: CreateExtensionKindOptions<TOptions, TInputs, TOutput, TConfig>, ): ExtensionKind<TOptions, TInputs, TOutput, TConfig>; // (undocumented) - new(args: { - namespace?: string; - name?: string; - attachTo?: { - id: string; - input: string; - }; - disabled?: boolean; - inputs?: TInputs; - output?: TOutput; - configSchema?: PortableSchema<TConfig>; - options: TOptions; - factory?( - context: { - node: AppNode; - config: TConfig; - inputs: Expand<ResolvedExtensionInputs<TInputs>>; - orignalFactory( - context?: { - node?: AppNode; - config?: TConfig; - inputs?: Expand<ResolvedExtensionInputs<TInputs>>; - }, - options?: TOptions, - ): Expand<ExtensionDataValues<TOutput>>; - }, - options: TOptions, - ): Expand<ExtensionDataValues<TOutput>>; - }): ExtensionDefinition<TConfig>; -} - -// @public (undocumented) -export interface ExtensionKindOptions< - TOptions, - TInputs extends AnyExtensionInputMap, - TOutput extends AnyExtensionDataMap, - TConfig, -> { - // (undocumented) - attachTo: { - id: string; - input: string; + new( + instanceProperties: CreateExtensionKindInstanceOptions< + TOptions, + TInputs, + TOutput, + TConfig + >, + ): ExtensionDefinition<TConfig> & { + override: ( + overrides: CreateExtensionOverrideKindInstanceOptions< + TOptions, + TInputs, + TOutput, + TConfig + >, + ) => ExtensionDefinition<TConfig>; }; - // (undocumented) - configSchema?: PortableSchema<TConfig>; - // (undocumented) - disabled?: boolean; - // (undocumented) - factory( - context: { - node: AppNode; - config: TConfig; - inputs: Expand<ResolvedExtensionInputs<TInputs>>; - }, - options: TOptions, - ): Expand<ExtensionDataValues<TOutput>>; - // (undocumented) - inputs?: TInputs; - // (undocumented) - kind: string; - // (undocumented) - name?: string; - // (undocumented) - namespace?: string; - // (undocumented) - output: TOutput; } // @public (undocumented) diff --git a/packages/frontend-plugin-api/src/wiring/createExtension.test.ts b/packages/frontend-plugin-api/src/wiring/createExtension.test.ts index cfef69b0fe..42ab21db80 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtension.test.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtension.test.ts @@ -291,37 +291,4 @@ describe('createExtension', () => { 'ExtensionDefinition{namespace=test,attachTo=root@default}', ); }); - - describe('override', () => { - it('should create an extension override', () => { - const extension = createExtension({ - namespace: 'test', - attachTo: { id: 'root', input: 'default' }, - output: { - foo: stringData, - }, - factory() { - return { - foo: 'bar', - }; - }, - }); - - const override = extension.override({ - attachTo: { - id: 'root', - input: 'default2', - }, - factory() { - return { - foo: 'baz', - }; - }, - }); - - expect(String(override)).toBe( - 'ExtensionDefinition{namespace=test,attachTo=root@default2}', - ); - }); - }); }); diff --git a/packages/frontend-plugin-api/src/wiring/createExtension.ts b/packages/frontend-plugin-api/src/wiring/createExtension.ts index b56cc39fc9..be76fbc069 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtension.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtension.ts @@ -91,7 +91,7 @@ export interface CreateExtensionOptions< inputs?: TInputs; output: TOutput; configSchema?: PortableSchema<TConfig>; - factory(context: { + factory(options: { node: AppNode; config: TConfig; inputs: Expand<ResolvedExtensionInputs<TInputs>>; @@ -99,33 +99,7 @@ export interface CreateExtensionOptions< } /** @public */ -export interface ExtensionDefinitionOverrides< - TOriginalConfig, - TOriginalInputs extends AnyExtensionInputMap, - TOverrideInputs extends AnyExtensionInputMap, -> { - readonly disabled?: boolean; - readonly attachTo?: { id: string; input: string }; - // TODO: inputs (only adding to the list? or redefine arity and superset of old type on existing input?) - // TODO: config (any merging needed on there?) - inputs?: TOverrideInputs; - factory?(options: { - node: AppNode; - config: TOriginalConfig; - inputs: Expand<ResolvedExtensionInputs<TOriginalInputs & TOverrideInputs>>; - originalFactory: (originalFactoryOptions?: { - inputsOverride?: ResolvedExtensionInputs< - TOriginalInputs & TOverrideInputs - >; - }) => ExtensionDataValues<any>; - }): ExtensionDataValues<any>; -} - -/** @public */ -export interface ExtensionDefinition< - TConfig, - TInputs extends AnyExtensionInputMap, -> { +export interface ExtensionDefinition<TConfig> { $$type: '@backstage/ExtensionDefinition'; readonly kind?: string; readonly namespace?: string; @@ -133,20 +107,15 @@ export interface ExtensionDefinition< readonly attachTo: { id: string; input: string }; readonly disabled: boolean; readonly configSchema?: PortableSchema<TConfig>; - override<TOverrideInputs extends AnyExtensionInputMap>( - overrides: ExtensionDefinitionOverrides<TConfig, TInputs, TOverrideInputs>, - ): ExtensionDefinition<TConfig, TInputs>; } /** @internal */ -export interface InternalExtensionDefinition< - TConfig, - TInputs extends AnyExtensionInputMap, -> extends ExtensionDefinition<TConfig, TInputs> { +export interface InternalExtensionDefinition<TConfig> + extends ExtensionDefinition<TConfig> { readonly version: 'v1'; - readonly inputs: TInputs; + readonly inputs: AnyExtensionInputMap; readonly output: AnyExtensionDataMap; - factory(context: { + factory(options: { node: AppNode; config: TConfig; inputs: ResolvedExtensionInputs<any>; @@ -154,13 +123,10 @@ export interface InternalExtensionDefinition< } /** @internal */ -export function toInternalExtensionDefinition< - TConfig, - TInputs extends AnyExtensionInputMap, ->( - overrides: ExtensionDefinition<TConfig, TInputs>, -): InternalExtensionDefinition<TConfig, TInputs> { - const internal = overrides as InternalExtensionDefinition<TConfig, TInputs>; +export function toInternalExtensionDefinition<TConfig>( + overrides: ExtensionDefinition<TConfig>, +): InternalExtensionDefinition<TConfig> { + const internal = overrides as InternalExtensionDefinition<TConfig>; if (internal.$$type !== '@backstage/ExtensionDefinition') { throw new Error( `Invalid extension definition instance, bad type '${internal.$$type}'`, @@ -181,69 +147,38 @@ export function createExtension< TConfig = never, >( options: CreateExtensionOptions<TOutput, TInputs, TConfig>, -): ExtensionDefinition<TConfig, TInputs> { - const { - kind, - namespace, - name, - attachTo, - disabled = false, - inputs = {} as TInputs, - output, - configSchema, - factory, - } = options; - +): ExtensionDefinition<TConfig> { return { $$type: '@backstage/ExtensionDefinition', version: 'v1', - kind, - namespace, - name, - attachTo, - disabled, - inputs, - output, - configSchema, - factory({ inputs: factoryInputs, ...rest }) { + 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 factory({ - inputs: factoryInputs as Expand<ResolvedExtensionInputs<TInputs>>, + return options.factory({ + inputs: inputs as Expand<ResolvedExtensionInputs<TInputs>>, ...rest, }); }, toString() { const parts: string[] = []; - if (kind) { - parts.push(`kind=${kind}`); + if (options.kind) { + parts.push(`kind=${options.kind}`); } - if (namespace) { - parts.push(`namespace=${namespace}`); + if (options.namespace) { + parts.push(`namespace=${options.namespace}`); } - if (name) { - parts.push(`name=${name}`); + if (options.name) { + parts.push(`name=${options.name}`); } - parts.push(`attachTo=${attachTo.id}@${attachTo.input}`); + parts.push(`attachTo=${options.attachTo.id}@${options.attachTo.input}`); return `ExtensionDefinition{${parts.join(',')}}`; }, - override<TOverrideInputs extends AnyExtensionInputMap>( - overrides: ExtensionDefinitionOverrides< - TConfig, - TInputs, - TOverrideInputs - >, - ): ExtensionDefinition<TConfig, TInputs> { - return createExtension({ - kind, - namespace, - name, - attachTo: overrides.attachTo ?? attachTo, - disabled: overrides.disabled ?? disabled, - inputs: { ...inputs, ...overrides.inputs }, - output, - configSchema, - factory, - }); - }, - } as InternalExtensionDefinition<TConfig, TInputs>; + } as InternalExtensionDefinition<TConfig>; } diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionKind.test.tsx b/packages/frontend-plugin-api/src/wiring/createExtensionKind.test.tsx index 3bdcd3a7cc..30c3e6ca44 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtensionKind.test.tsx +++ b/packages/frontend-plugin-api/src/wiring/createExtensionKind.test.tsx @@ -64,6 +64,7 @@ describe('createExtensionKind', () => { }, factory: expect.any(Function), toString: expect.any(Function), + override: expect.any(Function), version: 'v1', }); @@ -102,4 +103,167 @@ describe('createExtensionKind', () => { const { container } = createExtensionTester(extension).render(); expect(container.querySelector('h2')).toHaveTextContent('Hello, world!'); }); + + it('should allow calling of the default value from override', () => { + const TestExtension = createExtensionKind({ + kind: 'test-extension', + attachTo: { id: 'test', input: 'default' }, + output: { + element: coreExtensionData.reactElement, + }, + factory(_, options: { text: string }) { + return { + element: <h1>{options.text}</h1>, + }; + }, + }); + + const extension = TestExtension.new({ + name: 'my-extension', + options: { + text: 'Hello, world!', + }, + factory({ originalFactory }, options: { text: string }) { + const { element } = originalFactory(); + return { + element: ( + <h2> + {options.text} + {element} + </h2> + ), + }; + }, + }); + + expect(extension).toBeDefined(); + + const { container } = createExtensionTester(extension).render(); + + expect(container.querySelector('h2 h1')).toHaveTextContent('Hello, world!'); + }); + + it('should allow overriding options of the default value from override', () => { + const TestExtension = createExtensionKind({ + kind: 'test-extension', + attachTo: { id: 'test', input: 'default' }, + output: { + element: coreExtensionData.reactElement, + }, + factory(_, options: { text: string }) { + return { + element: <h1>{options.text}</h1>, + }; + }, + }); + + const extension = TestExtension.new({ + name: 'my-extension', + options: { + text: 'Hello, world!', + }, + factory({ originalFactory }, options: { text: string }) { + const { element } = originalFactory(undefined, { text: 'nothing!' }); + return { + element: ( + <h2> + {options.text} + {element} + </h2> + ), + }; + }, + }); + + expect(extension).toBeDefined(); + + const { container } = createExtensionTester(extension).render(); + + expect(container.querySelector('h2 h1')).toHaveTextContent('nothing!'); + }); + + describe('override', () => { + it('should allow overriding of the default factory', () => { + const TestExtension = createExtensionKind({ + kind: 'test-extension', + attachTo: { id: 'test', input: 'default' }, + output: { + element: coreExtensionData.reactElement, + }, + factory(_, options: { text: string }) { + return { + element: <h1>{options.text}</h1>, + }; + }, + }); + + const extension = TestExtension.new({ + name: 'my-extension', + options: { + text: 'Hello, world!', + }, + factory(_, options: { text: string }) { + return { + element: <h2>{options.text}</h2>, + }; + }, + }); + + const overridden = extension.override({ + factory({ originalFactory }, { text }) { + return { + element: ( + <div> + {originalFactory().element} + <h3>{text}</h3> + </div> + ), + }; + }, + }); + + const { container } = createExtensionTester(overridden).render(); + expect(container.querySelector('h2')).toHaveTextContent('Hello, world!'); + expect(container.querySelector('h3')).toHaveTextContent('Hello, world!'); + }); + }); + + it('should allow calling the kind factory if another factory is not defined in the instance', () => { + const TestExtension = createExtensionKind({ + kind: 'test-extension', + attachTo: { id: 'test', input: 'default' }, + output: { + element: coreExtensionData.reactElement, + }, + factory(_, options: { text: string }) { + return { + element: <h1>{options.text}</h1>, + }; + }, + }); + + const extension = TestExtension.new({ + name: 'my-extension', + options: { + text: 'Hello, world!', + }, + }); + + const overridden = extension.override({ + factory({ originalFactory }, { text }) { + return { + element: ( + <div> + {originalFactory().element} + <h3>{text}</h3> + </div> + ), + }; + }, + }); + + const { container } = createExtensionTester(overridden).render(); + expect(container.querySelector('h1')).toHaveTextContent('Hello, world!'); + expect(container.querySelector('h3')).toHaveTextContent('Hello, world!'); + }); }); diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionKind.ts b/packages/frontend-plugin-api/src/wiring/createExtensionKind.ts index 353fb8ab70..9813c9e50c 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtensionKind.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtensionKind.ts @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import { AppNode } from '../apis'; import { PortableSchema } from '../schema'; import { Expand } from '../types'; @@ -52,6 +53,76 @@ export interface CreateExtensionKindOptions< ): Expand<ExtensionDataValues<TOutput>>; } +/** + * @public + */ +export interface CreateExtensionKindInstanceOptions< + TOptions, + TInputs extends AnyExtensionInputMap, + TOutput extends AnyExtensionDataMap, + TConfig, +> { + namespace?: string; + name?: string; + attachTo?: { id: string; input: string }; + disabled?: boolean; + inputs?: TInputs; + output?: TOutput; + configSchema?: PortableSchema<TConfig>; + options: TOptions; + factory?( + context: { + node: AppNode; + config: TConfig; + inputs: Expand<ResolvedExtensionInputs<TInputs>>; + originalFactory( + context?: { + node?: AppNode; + config?: TConfig; + inputs?: Expand<ResolvedExtensionInputs<TInputs>>; + }, + options?: TOptions, + ): Expand<ExtensionDataValues<TOutput>>; + }, + options: TOptions, + ): Expand<ExtensionDataValues<TOutput>>; +} + +/** + * @public + */ +export interface CreateExtensionOverrideKindInstanceOptions< + TOptions, + TInputs extends AnyExtensionInputMap, + TOutput extends AnyExtensionDataMap, + TConfig, +> { + namespace?: string; + name?: string; + attachTo?: { id: string; input: string }; + disabled?: boolean; + inputs?: TInputs; + output?: TOutput; + configSchema?: PortableSchema<TConfig>; + options?: TOptions; + factory?( + context: { + node: AppNode; + config: TConfig; + inputs: Expand<ResolvedExtensionInputs<TInputs>>; + originalFactory( + context?: { + node?: AppNode; + config?: TConfig; + inputs?: Expand<ResolvedExtensionInputs<TInputs>>; + }, + options?: TOptions, + ): Expand<ExtensionDataValues<TOutput>>; + }, + options: TOptions, + ): Expand<ExtensionDataValues<TOutput>>; +} + /** * TODO: should we export an interface instead of a concrete class? * @public @@ -74,7 +145,7 @@ export class ExtensionKind< } private constructor( - private readonly options: CreateExtensionKindOptions< + private readonly kindProperties: CreateExtensionKindOptions< TOptions, TInputs, TOutput, @@ -82,49 +153,41 @@ export class ExtensionKind< >, ) {} - public new(args: { - namespace?: string; - name?: string; - attachTo?: { id: string; input: string }; - disabled?: boolean; - inputs?: TInputs; - output?: TOutput; - configSchema?: PortableSchema<TConfig>; - options: TOptions; - factory?( - context: { - node: AppNode; - config: TConfig; - inputs: Expand<ResolvedExtensionInputs<TInputs>>; - orignalFactory( - context?: { - node?: AppNode; - config?: TConfig; - inputs?: Expand<ResolvedExtensionInputs<TInputs>>; - }, - options?: TOptions, - ): Expand<ExtensionDataValues<TOutput>>; - }, - options: TOptions, - ): Expand<ExtensionDataValues<TOutput>>; - }): ExtensionDefinition<TConfig, TInputs> { - return createExtension({ - kind: this.options.kind, - namespace: args.namespace ?? this.options.namespace, - name: args.name ?? this.options.name, - attachTo: args.attachTo ?? this.options.attachTo, - disabled: args.disabled ?? this.options.disabled, - inputs: args.inputs ?? this.options.inputs, - output: args.output ?? this.options.output, - configSchema: args.configSchema ?? this.options.configSchema, // TODO: some config merging or smth + public new( + instanceProperties: CreateExtensionKindInstanceOptions< + TOptions, + TInputs, + TOutput, + TConfig + >, + ): ExtensionDefinition<TConfig> & { + override: ( + overrides: CreateExtensionOverrideKindInstanceOptions< + TOptions, + TInputs, + TOutput, + TConfig + >, + ) => ExtensionDefinition<TConfig>; + } { + const extension = createExtension({ + kind: this.kindProperties.kind, + namespace: instanceProperties.namespace ?? this.kindProperties.namespace, + name: instanceProperties.name ?? this.kindProperties.name, + attachTo: instanceProperties.attachTo ?? this.kindProperties.attachTo, + disabled: instanceProperties.disabled ?? this.kindProperties.disabled, + inputs: instanceProperties.inputs ?? this.kindProperties.inputs, + output: instanceProperties.output ?? this.kindProperties.output, + configSchema: + instanceProperties.configSchema ?? this.kindProperties.configSchema, // TODO: some config merging or smth factory: ({ node, config, inputs }) => { - if (args.factory) { - return args.factory( + if (instanceProperties.factory) { + return instanceProperties.factory( { node, config, inputs, - orignalFactory: ( + originalFactory: ( innerContext?: { node?: AppNode; config?: TConfig; @@ -132,29 +195,123 @@ export class ExtensionKind< }, innerOptions?: TOptions, ) => - this.options.factory( + this.kindProperties.factory( { node: innerContext?.node ?? node, config: innerContext?.config ?? config, inputs: innerContext?.inputs ?? inputs, }, - innerOptions ?? args.options, + innerOptions ?? instanceProperties.options, ), }, - args.options, + instanceProperties.options, ); } - return this.options.factory( + return this.kindProperties.factory( { node, config, inputs, }, - args.options, + instanceProperties.options, ); }, }); + + return { + ...extension, + override: overrides => { + return createExtension({ + kind: this.kindProperties.kind, + namespace: + overrides.namespace ?? + instanceProperties.namespace ?? + this.kindProperties.namespace, + name: + overrides.name ?? + instanceProperties.name ?? + this.kindProperties.name, + attachTo: + overrides.attachTo ?? + instanceProperties.attachTo ?? + this.kindProperties.attachTo, + disabled: + overrides.disabled ?? + instanceProperties.disabled ?? + this.kindProperties.disabled, + inputs: + overrides.inputs ?? + instanceProperties.inputs ?? + this.kindProperties.inputs, + output: + overrides.output ?? + instanceProperties.output ?? + this.kindProperties.output, + configSchema: + overrides.configSchema ?? + instanceProperties.configSchema ?? + this.kindProperties.configSchema, // TODO: some config merging or smth + factory: ({ node, config, inputs }) => { + if (overrides.factory) { + return overrides.factory( + { + node, + config, + inputs, + originalFactory: ( + innerContext?: { + node?: AppNode; + config?: TConfig; + inputs?: Expand<ResolvedExtensionInputs<TInputs>>; + }, + innerOptions?: TOptions, + ) => + instanceProperties.factory?.( + { + node: innerContext?.node ?? node, + config: innerContext?.config ?? config, + inputs: innerContext?.inputs ?? inputs, + originalFactory: this.kindProperties.factory, + }, + innerOptions ?? instanceProperties.options, + ) ?? + this.kindProperties.factory( + { + node, + config, + inputs, + }, + innerOptions ?? instanceProperties.options, + ), + }, + instanceProperties.options, + ); + } + + return ( + instanceProperties.factory?.( + { + node, + config, + inputs, + originalFactory: this.kindProperties.factory, + }, + instanceProperties.options, + ) ?? + this.kindProperties.factory( + { + node, + config, + inputs, + }, + instanceProperties.options, + ) + ); + }, + }); + }, + }; } } diff --git a/packages/frontend-plugin-api/src/wiring/index.ts b/packages/frontend-plugin-api/src/wiring/index.ts index 8fe9dc3a54..a312c0f06f 100644 --- a/packages/frontend-plugin-api/src/wiring/index.ts +++ b/packages/frontend-plugin-api/src/wiring/index.ts @@ -49,7 +49,9 @@ export { type FrontendFeature, } from './types'; export { - type CreateExtensionKindOptions as ExtensionKindOptions, + type CreateExtensionKindOptions, + type CreateExtensionKindInstanceOptions, + type CreateExtensionOverrideKindInstanceOptions, ExtensionKind, createExtensionKind, } from './createExtensionKind'; From 6b6cbdaac5cf05702210e9c24ccb4272c3ba3e88 Mon Sep 17 00:00:00 2001 From: Ben Lambert <ben@blam.sh> Date: Thu, 18 Jul 2024 13:07:02 +0200 Subject: [PATCH 308/416] Revert "NFE: Make it possible to override existing extension instances" Signed-off-by: blam <ben@blam.sh> --- packages/frontend-plugin-api/api-report.md | 214 +++++---------- .../src/wiring/createExtension.ts | 4 +- .../src/wiring/createExtensionKind.test.tsx | 164 ------------ .../src/wiring/createExtensionKind.ts | 245 ++++-------------- .../frontend-plugin-api/src/wiring/index.ts | 4 +- 5 files changed, 115 insertions(+), 516 deletions(-) diff --git a/packages/frontend-plugin-api/api-report.md b/packages/frontend-plugin-api/api-report.md index 6a04d04cd6..48718f5375 100644 --- a/packages/frontend-plugin-api/api-report.md +++ b/packages/frontend-plugin-api/api-report.md @@ -529,91 +529,9 @@ export function createExtensionKind< TOutput extends AnyExtensionDataMap, TConfig, >( - options: CreateExtensionKindOptions<TOptions, TInputs, TOutput, TConfig>, + options: ExtensionKindOptions<TOptions, TInputs, TOutput, TConfig>, ): ExtensionKind<TOptions, TInputs, TOutput, TConfig>; -// @public (undocumented) -export interface CreateExtensionKindInstanceOptions< - TOptions, - TInputs extends AnyExtensionInputMap, - TOutput extends AnyExtensionDataMap, - TConfig, -> { - // (undocumented) - attachTo?: { - id: string; - input: string; - }; - // (undocumented) - configSchema?: PortableSchema<TConfig>; - // (undocumented) - disabled?: boolean; - // (undocumented) - factory?( - context: { - node: AppNode; - config: TConfig; - inputs: Expand<ResolvedExtensionInputs<TInputs>>; - originalFactory( - context?: { - node?: AppNode; - config?: TConfig; - inputs?: Expand<ResolvedExtensionInputs<TInputs>>; - }, - options?: TOptions, - ): Expand<ExtensionDataValues<TOutput>>; - }, - options: TOptions, - ): Expand<ExtensionDataValues<TOutput>>; - // (undocumented) - inputs?: TInputs; - // (undocumented) - name?: string; - // (undocumented) - namespace?: string; - // (undocumented) - options: TOptions; - // (undocumented) - output?: TOutput; -} - -// @public (undocumented) -export interface CreateExtensionKindOptions< - TOptions, - TInputs extends AnyExtensionInputMap, - TOutput extends AnyExtensionDataMap, - TConfig, -> { - // (undocumented) - attachTo: { - id: string; - input: string; - }; - // (undocumented) - configSchema?: PortableSchema<TConfig>; - // (undocumented) - disabled?: boolean; - // (undocumented) - factory( - context: { - node: AppNode; - config: TConfig; - inputs: Expand<ResolvedExtensionInputs<TInputs>>; - }, - options: TOptions, - ): Expand<ExtensionDataValues<TOutput>>; - // (undocumented) - inputs?: TInputs; - // (undocumented) - kind: string; - // (undocumented) - name?: string; - // (undocumented) - namespace?: string; - // (undocumented) - output: TOutput; -} - // @public (undocumented) export interface CreateExtensionOptions< TOutput extends AnyExtensionDataMap, @@ -630,7 +548,7 @@ export interface CreateExtensionOptions< // (undocumented) disabled?: boolean; // (undocumented) - factory(options: { + factory(context: { node: AppNode; config: TConfig; inputs: Expand<ResolvedExtensionInputs<TInputs>>; @@ -647,51 +565,6 @@ export interface CreateExtensionOptions< output: TOutput; } -// @public (undocumented) -export interface CreateExtensionOverrideKindInstanceOptions< - TOptions, - TInputs extends AnyExtensionInputMap, - TOutput extends AnyExtensionDataMap, - TConfig, -> { - // (undocumented) - attachTo?: { - id: string; - input: string; - }; - // (undocumented) - configSchema?: PortableSchema<TConfig>; - // (undocumented) - disabled?: boolean; - // (undocumented) - factory?( - context: { - node: AppNode; - config: TConfig; - inputs: Expand<ResolvedExtensionInputs<TInputs>>; - originalFactory( - context?: { - node?: AppNode; - config?: TConfig; - inputs?: Expand<ResolvedExtensionInputs<TInputs>>; - }, - options?: TOptions, - ): Expand<ExtensionDataValues<TOutput>>; - }, - options: TOptions, - ): Expand<ExtensionDataValues<TOutput>>; - // (undocumented) - inputs?: TInputs; - // (undocumented) - name?: string; - // (undocumented) - namespace?: string; - // (undocumented) - options?: TOptions; - // (undocumented) - output?: TOutput; -} - // @public (undocumented) export function createExtensionOverrides( options: ExtensionOverridesOptions, @@ -1064,26 +937,75 @@ export class ExtensionKind< TOutput extends AnyExtensionDataMap, TConfig, >( - options: CreateExtensionKindOptions<TOptions, TInputs, TOutput, TConfig>, + options: ExtensionKindOptions<TOptions, TInputs, TOutput, TConfig>, ): ExtensionKind<TOptions, TInputs, TOutput, TConfig>; // (undocumented) - new( - instanceProperties: CreateExtensionKindInstanceOptions< - TOptions, - TInputs, - TOutput, - TConfig - >, - ): ExtensionDefinition<TConfig> & { - override: ( - overrides: CreateExtensionOverrideKindInstanceOptions< - TOptions, - TInputs, - TOutput, - TConfig - >, - ) => ExtensionDefinition<TConfig>; + new(args: { + namespace?: string; + name?: string; + attachTo?: { + id: string; + input: string; + }; + disabled?: boolean; + inputs?: TInputs; + output?: TOutput; + configSchema?: PortableSchema<TConfig>; + options: TOptions; + factory?( + context: { + node: AppNode; + config: TConfig; + inputs: Expand<ResolvedExtensionInputs<TInputs>>; + orignalFactory( + context?: { + node?: AppNode; + config?: TConfig; + inputs?: Expand<ResolvedExtensionInputs<TInputs>>; + }, + options?: TOptions, + ): Expand<ExtensionDataValues<TOutput>>; + }, + options: TOptions, + ): Expand<ExtensionDataValues<TOutput>>; + }): ExtensionDefinition<TConfig>; +} + +// @public (undocumented) +export interface ExtensionKindOptions< + TOptions, + TInputs extends AnyExtensionInputMap, + TOutput extends AnyExtensionDataMap, + TConfig, +> { + // (undocumented) + attachTo: { + id: string; + input: string; }; + // (undocumented) + configSchema?: PortableSchema<TConfig>; + // (undocumented) + disabled?: boolean; + // (undocumented) + factory( + context: { + node: AppNode; + config: TConfig; + inputs: Expand<ResolvedExtensionInputs<TInputs>>; + }, + options: TOptions, + ): Expand<ExtensionDataValues<TOutput>>; + // (undocumented) + inputs?: TInputs; + // (undocumented) + kind: string; + // (undocumented) + name?: string; + // (undocumented) + namespace?: string; + // (undocumented) + output: TOutput; } // @public (undocumented) diff --git a/packages/frontend-plugin-api/src/wiring/createExtension.ts b/packages/frontend-plugin-api/src/wiring/createExtension.ts index be76fbc069..28dc6a4e29 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtension.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtension.ts @@ -91,7 +91,7 @@ export interface CreateExtensionOptions< inputs?: TInputs; output: TOutput; configSchema?: PortableSchema<TConfig>; - factory(options: { + factory(context: { node: AppNode; config: TConfig; inputs: Expand<ResolvedExtensionInputs<TInputs>>; @@ -115,7 +115,7 @@ export interface InternalExtensionDefinition<TConfig> readonly version: 'v1'; readonly inputs: AnyExtensionInputMap; readonly output: AnyExtensionDataMap; - factory(options: { + factory(context: { node: AppNode; config: TConfig; inputs: ResolvedExtensionInputs<any>; diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionKind.test.tsx b/packages/frontend-plugin-api/src/wiring/createExtensionKind.test.tsx index 30c3e6ca44..3bdcd3a7cc 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtensionKind.test.tsx +++ b/packages/frontend-plugin-api/src/wiring/createExtensionKind.test.tsx @@ -64,7 +64,6 @@ describe('createExtensionKind', () => { }, factory: expect.any(Function), toString: expect.any(Function), - override: expect.any(Function), version: 'v1', }); @@ -103,167 +102,4 @@ describe('createExtensionKind', () => { const { container } = createExtensionTester(extension).render(); expect(container.querySelector('h2')).toHaveTextContent('Hello, world!'); }); - - it('should allow calling of the default value from override', () => { - const TestExtension = createExtensionKind({ - kind: 'test-extension', - attachTo: { id: 'test', input: 'default' }, - output: { - element: coreExtensionData.reactElement, - }, - factory(_, options: { text: string }) { - return { - element: <h1>{options.text}</h1>, - }; - }, - }); - - const extension = TestExtension.new({ - name: 'my-extension', - options: { - text: 'Hello, world!', - }, - factory({ originalFactory }, options: { text: string }) { - const { element } = originalFactory(); - return { - element: ( - <h2> - {options.text} - {element} - </h2> - ), - }; - }, - }); - - expect(extension).toBeDefined(); - - const { container } = createExtensionTester(extension).render(); - - expect(container.querySelector('h2 h1')).toHaveTextContent('Hello, world!'); - }); - - it('should allow overriding options of the default value from override', () => { - const TestExtension = createExtensionKind({ - kind: 'test-extension', - attachTo: { id: 'test', input: 'default' }, - output: { - element: coreExtensionData.reactElement, - }, - factory(_, options: { text: string }) { - return { - element: <h1>{options.text}</h1>, - }; - }, - }); - - const extension = TestExtension.new({ - name: 'my-extension', - options: { - text: 'Hello, world!', - }, - factory({ originalFactory }, options: { text: string }) { - const { element } = originalFactory(undefined, { text: 'nothing!' }); - return { - element: ( - <h2> - {options.text} - {element} - </h2> - ), - }; - }, - }); - - expect(extension).toBeDefined(); - - const { container } = createExtensionTester(extension).render(); - - expect(container.querySelector('h2 h1')).toHaveTextContent('nothing!'); - }); - - describe('override', () => { - it('should allow overriding of the default factory', () => { - const TestExtension = createExtensionKind({ - kind: 'test-extension', - attachTo: { id: 'test', input: 'default' }, - output: { - element: coreExtensionData.reactElement, - }, - factory(_, options: { text: string }) { - return { - element: <h1>{options.text}</h1>, - }; - }, - }); - - const extension = TestExtension.new({ - name: 'my-extension', - options: { - text: 'Hello, world!', - }, - factory(_, options: { text: string }) { - return { - element: <h2>{options.text}</h2>, - }; - }, - }); - - const overridden = extension.override({ - factory({ originalFactory }, { text }) { - return { - element: ( - <div> - {originalFactory().element} - <h3>{text}</h3> - </div> - ), - }; - }, - }); - - const { container } = createExtensionTester(overridden).render(); - expect(container.querySelector('h2')).toHaveTextContent('Hello, world!'); - expect(container.querySelector('h3')).toHaveTextContent('Hello, world!'); - }); - }); - - it('should allow calling the kind factory if another factory is not defined in the instance', () => { - const TestExtension = createExtensionKind({ - kind: 'test-extension', - attachTo: { id: 'test', input: 'default' }, - output: { - element: coreExtensionData.reactElement, - }, - factory(_, options: { text: string }) { - return { - element: <h1>{options.text}</h1>, - }; - }, - }); - - const extension = TestExtension.new({ - name: 'my-extension', - options: { - text: 'Hello, world!', - }, - }); - - const overridden = extension.override({ - factory({ originalFactory }, { text }) { - return { - element: ( - <div> - {originalFactory().element} - <h3>{text}</h3> - </div> - ), - }; - }, - }); - - const { container } = createExtensionTester(overridden).render(); - expect(container.querySelector('h1')).toHaveTextContent('Hello, world!'); - expect(container.querySelector('h3')).toHaveTextContent('Hello, world!'); - }); }); diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionKind.ts b/packages/frontend-plugin-api/src/wiring/createExtensionKind.ts index 9813c9e50c..52bf711822 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtensionKind.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtensionKind.ts @@ -21,7 +21,6 @@ import { AnyExtensionDataMap, AnyExtensionInputMap, ExtensionDataValues, - ExtensionDefinition, ResolvedExtensionInputs, createExtension, } from './createExtension'; @@ -53,76 +52,6 @@ export interface CreateExtensionKindOptions< ): Expand<ExtensionDataValues<TOutput>>; } -/** - * @public - */ -export interface CreateExtensionKindInstanceOptions< - TOptions, - TInputs extends AnyExtensionInputMap, - TOutput extends AnyExtensionDataMap, - TConfig, -> { - namespace?: string; - name?: string; - attachTo?: { id: string; input: string }; - disabled?: boolean; - inputs?: TInputs; - output?: TOutput; - configSchema?: PortableSchema<TConfig>; - options: TOptions; - factory?( - context: { - node: AppNode; - config: TConfig; - inputs: Expand<ResolvedExtensionInputs<TInputs>>; - originalFactory( - context?: { - node?: AppNode; - config?: TConfig; - inputs?: Expand<ResolvedExtensionInputs<TInputs>>; - }, - options?: TOptions, - ): Expand<ExtensionDataValues<TOutput>>; - }, - options: TOptions, - ): Expand<ExtensionDataValues<TOutput>>; -} - -/** - * @public - */ -export interface CreateExtensionOverrideKindInstanceOptions< - TOptions, - TInputs extends AnyExtensionInputMap, - TOutput extends AnyExtensionDataMap, - TConfig, -> { - namespace?: string; - name?: string; - attachTo?: { id: string; input: string }; - disabled?: boolean; - inputs?: TInputs; - output?: TOutput; - configSchema?: PortableSchema<TConfig>; - options?: TOptions; - factory?( - context: { - node: AppNode; - config: TConfig; - inputs: Expand<ResolvedExtensionInputs<TInputs>>; - originalFactory( - context?: { - node?: AppNode; - config?: TConfig; - inputs?: Expand<ResolvedExtensionInputs<TInputs>>; - }, - options?: TOptions, - ): Expand<ExtensionDataValues<TOutput>>; - }, - options: TOptions, - ): Expand<ExtensionDataValues<TOutput>>; -} - /** * TODO: should we export an interface instead of a concrete class? * @public @@ -145,7 +74,7 @@ export class ExtensionKind< } private constructor( - private readonly kindProperties: CreateExtensionKindOptions< + private readonly options: CreateExtensionKindOptions< TOptions, TInputs, TOutput, @@ -153,41 +82,49 @@ export class ExtensionKind< >, ) {} - public new( - instanceProperties: CreateExtensionKindInstanceOptions< - TOptions, - TInputs, - TOutput, - TConfig - >, - ): ExtensionDefinition<TConfig> & { - override: ( - overrides: CreateExtensionOverrideKindInstanceOptions< - TOptions, - TInputs, - TOutput, - TConfig - >, - ) => ExtensionDefinition<TConfig>; - } { - const extension = createExtension({ - kind: this.kindProperties.kind, - namespace: instanceProperties.namespace ?? this.kindProperties.namespace, - name: instanceProperties.name ?? this.kindProperties.name, - attachTo: instanceProperties.attachTo ?? this.kindProperties.attachTo, - disabled: instanceProperties.disabled ?? this.kindProperties.disabled, - inputs: instanceProperties.inputs ?? this.kindProperties.inputs, - output: instanceProperties.output ?? this.kindProperties.output, - configSchema: - instanceProperties.configSchema ?? this.kindProperties.configSchema, // TODO: some config merging or smth + public new(args: { + namespace?: string; + name?: string; + attachTo?: { id: string; input: string }; + disabled?: boolean; + inputs?: TInputs; + output?: TOutput; + configSchema?: PortableSchema<TConfig>; + options: TOptions; + factory?( + context: { + node: AppNode; + config: TConfig; + inputs: Expand<ResolvedExtensionInputs<TInputs>>; + orignalFactory( + context?: { + node?: AppNode; + config?: TConfig; + inputs?: Expand<ResolvedExtensionInputs<TInputs>>; + }, + options?: TOptions, + ): Expand<ExtensionDataValues<TOutput>>; + }, + options: TOptions, + ): Expand<ExtensionDataValues<TOutput>>; + }) { + return createExtension({ + kind: this.options.kind, + namespace: args.namespace ?? this.options.namespace, + name: args.name ?? this.options.name, + attachTo: args.attachTo ?? this.options.attachTo, + disabled: args.disabled ?? this.options.disabled, + inputs: args.inputs ?? this.options.inputs, + output: args.output ?? this.options.output, + configSchema: args.configSchema ?? this.options.configSchema, // TODO: some config merging or smth factory: ({ node, config, inputs }) => { - if (instanceProperties.factory) { - return instanceProperties.factory( + if (args.factory) { + return args.factory( { node, config, inputs, - originalFactory: ( + orignalFactory: ( innerContext?: { node?: AppNode; config?: TConfig; @@ -195,123 +132,29 @@ export class ExtensionKind< }, innerOptions?: TOptions, ) => - this.kindProperties.factory( + this.options.factory( { node: innerContext?.node ?? node, config: innerContext?.config ?? config, inputs: innerContext?.inputs ?? inputs, }, - innerOptions ?? instanceProperties.options, + innerOptions ?? args.options, ), }, - instanceProperties.options, + args.options, ); } - return this.kindProperties.factory( + return this.options.factory( { node, config, inputs, }, - instanceProperties.options, + args.options, ); }, }); - - return { - ...extension, - override: overrides => { - return createExtension({ - kind: this.kindProperties.kind, - namespace: - overrides.namespace ?? - instanceProperties.namespace ?? - this.kindProperties.namespace, - name: - overrides.name ?? - instanceProperties.name ?? - this.kindProperties.name, - attachTo: - overrides.attachTo ?? - instanceProperties.attachTo ?? - this.kindProperties.attachTo, - disabled: - overrides.disabled ?? - instanceProperties.disabled ?? - this.kindProperties.disabled, - inputs: - overrides.inputs ?? - instanceProperties.inputs ?? - this.kindProperties.inputs, - output: - overrides.output ?? - instanceProperties.output ?? - this.kindProperties.output, - configSchema: - overrides.configSchema ?? - instanceProperties.configSchema ?? - this.kindProperties.configSchema, // TODO: some config merging or smth - factory: ({ node, config, inputs }) => { - if (overrides.factory) { - return overrides.factory( - { - node, - config, - inputs, - originalFactory: ( - innerContext?: { - node?: AppNode; - config?: TConfig; - inputs?: Expand<ResolvedExtensionInputs<TInputs>>; - }, - innerOptions?: TOptions, - ) => - instanceProperties.factory?.( - { - node: innerContext?.node ?? node, - config: innerContext?.config ?? config, - inputs: innerContext?.inputs ?? inputs, - originalFactory: this.kindProperties.factory, - }, - innerOptions ?? instanceProperties.options, - ) ?? - this.kindProperties.factory( - { - node, - config, - inputs, - }, - innerOptions ?? instanceProperties.options, - ), - }, - instanceProperties.options, - ); - } - - return ( - instanceProperties.factory?.( - { - node, - config, - inputs, - originalFactory: this.kindProperties.factory, - }, - instanceProperties.options, - ) ?? - this.kindProperties.factory( - { - node, - config, - inputs, - }, - instanceProperties.options, - ) - ); - }, - }); - }, - }; } } diff --git a/packages/frontend-plugin-api/src/wiring/index.ts b/packages/frontend-plugin-api/src/wiring/index.ts index a312c0f06f..8fe9dc3a54 100644 --- a/packages/frontend-plugin-api/src/wiring/index.ts +++ b/packages/frontend-plugin-api/src/wiring/index.ts @@ -49,9 +49,7 @@ export { type FrontendFeature, } from './types'; export { - type CreateExtensionKindOptions, - type CreateExtensionKindInstanceOptions, - type CreateExtensionOverrideKindInstanceOptions, + type CreateExtensionKindOptions as ExtensionKindOptions, ExtensionKind, createExtensionKind, } from './createExtensionKind'; From b20c067c61abcfff3f158b7f4b6c5857dfbf347a Mon Sep 17 00:00:00 2001 From: blam <ben@blam.sh> Date: Thu, 18 Jul 2024 13:27:09 +0200 Subject: [PATCH 309/416] chore: fixing some code review comments Signed-off-by: blam <ben@blam.sh> --- .changeset/dry-squids-tap.md | 8 +- .../src/wiring/createExtensionKind.ts | 108 +++++++++++------- 2 files changed, 70 insertions(+), 46 deletions(-) diff --git a/.changeset/dry-squids-tap.md b/.changeset/dry-squids-tap.md index 9bd835d371..5a865395c0 100644 --- a/.changeset/dry-squids-tap.md +++ b/.changeset/dry-squids-tap.md @@ -14,17 +14,17 @@ const TestExtensionKind = createExtensionKind({ output: { element: coreExtensionData.reactElement, }, - factory(_, options: { text: string }) { + factory(_, params: { text: string }) { return { - element: <h1>{options.text}</h1>, + element: <h1>{params.text}</h1>, }; }, }); // create an instance of the extension kind with props -const testExtension = TestExtensionKind.new({ +const testExtension = TestExtensionKind.create({ name: 'foo', - options: { + params: { text: 'Hello World', }, }); diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionKind.ts b/packages/frontend-plugin-api/src/wiring/createExtensionKind.ts index 52bf711822..1212365712 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtensionKind.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtensionKind.ts @@ -21,6 +21,7 @@ import { AnyExtensionDataMap, AnyExtensionInputMap, ExtensionDataValues, + ExtensionDefinition, ResolvedExtensionInputs, createExtension, } from './createExtension'; @@ -29,14 +30,13 @@ import { * @public */ export interface CreateExtensionKindOptions< - TOptions, + TParams, TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, TConfig, > { kind: string; namespace?: string; - name?: string; attachTo: { id: string; input: string }; disabled?: boolean; inputs?: TInputs; @@ -48,41 +48,20 @@ export interface CreateExtensionKindOptions< config: TConfig; inputs: Expand<ResolvedExtensionInputs<TInputs>>; }, - options: TOptions, + params: TParams, ): Expand<ExtensionDataValues<TOutput>>; } /** - * TODO: should we export an interface instead of a concrete class? * @public */ -export class ExtensionKind< - TOptions, +export interface ExtensionKind< + TParams, TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, TConfig, > { - static create< - TOptions, - TInputs extends AnyExtensionInputMap, - TOutput extends AnyExtensionDataMap, - TConfig, - >( - options: CreateExtensionKindOptions<TOptions, TInputs, TOutput, TConfig>, - ): ExtensionKind<TOptions, TInputs, TOutput, TConfig> { - return new ExtensionKind(options); - } - - private constructor( - private readonly options: CreateExtensionKindOptions< - TOptions, - TInputs, - TOutput, - TConfig - >, - ) {} - - public new(args: { + create(args: { namespace?: string; name?: string; attachTo?: { id: string; input: string }; @@ -90,7 +69,7 @@ export class ExtensionKind< inputs?: TInputs; output?: TOutput; configSchema?: PortableSchema<TConfig>; - options: TOptions; + params: TParams; factory?( context: { node: AppNode; @@ -98,20 +77,64 @@ export class ExtensionKind< inputs: Expand<ResolvedExtensionInputs<TInputs>>; orignalFactory( context?: { - node?: AppNode; config?: TConfig; inputs?: Expand<ResolvedExtensionInputs<TInputs>>; }, - options?: TOptions, + params?: TParams, ): Expand<ExtensionDataValues<TOutput>>; }, - options: TOptions, + params: TParams, ): Expand<ExtensionDataValues<TOutput>>; - }) { + }): ExtensionDefinition<TConfig>; +} + +/** + * @internal + */ +class ExtensionKindImpl< + TParams, + TInputs extends AnyExtensionInputMap, + TOutput extends AnyExtensionDataMap, + TConfig, +> { + constructor( + private readonly options: CreateExtensionKindOptions< + TParams, + TInputs, + TOutput, + TConfig + >, + ) {} + + public create(args: { + namespace?: string; + name?: string; + attachTo?: { id: string; input: string }; + disabled?: boolean; + inputs?: TInputs; + output?: TOutput; + configSchema?: PortableSchema<TConfig>; + params: TParams; + factory?( + context: { + node: AppNode; + config: TConfig; + inputs: Expand<ResolvedExtensionInputs<TInputs>>; + orignalFactory( + context?: { + config?: TConfig; + inputs?: Expand<ResolvedExtensionInputs<TInputs>>; + }, + params?: TParams, + ): Expand<ExtensionDataValues<TOutput>>; + }, + params: TParams, + ): Expand<ExtensionDataValues<TOutput>>; + }): ExtensionDefinition<TConfig> { return createExtension({ kind: this.options.kind, namespace: args.namespace ?? this.options.namespace, - name: args.name ?? this.options.name, + name: args.name, attachTo: args.attachTo ?? this.options.attachTo, disabled: args.disabled ?? this.options.disabled, inputs: args.inputs ?? this.options.inputs, @@ -126,22 +149,21 @@ export class ExtensionKind< inputs, orignalFactory: ( innerContext?: { - node?: AppNode; config?: TConfig; inputs?: Expand<ResolvedExtensionInputs<TInputs>>; }, - innerOptions?: TOptions, + innerParams?: TParams, ) => this.options.factory( { - node: innerContext?.node ?? node, + node, config: innerContext?.config ?? config, inputs: innerContext?.inputs ?? inputs, }, - innerOptions ?? args.options, + innerParams ?? args.params, ), }, - args.options, + args.params, ); } @@ -151,7 +173,7 @@ export class ExtensionKind< config, inputs, }, - args.options, + args.params, ); }, }); @@ -165,10 +187,12 @@ export class ExtensionKind< * @public */ export function createExtensionKind< - TOptions, + TParams, TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, TConfig, ->(options: CreateExtensionKindOptions<TOptions, TInputs, TOutput, TConfig>) { - return ExtensionKind.create(options); +>( + options: CreateExtensionKindOptions<TParams, TInputs, TOutput, TConfig>, +): ExtensionKind<TParams, TInputs, TOutput, TConfig> { + return new ExtensionKindImpl(options); } From 4e42e5112cd692ab40696b3970e016cba94b4456 Mon Sep 17 00:00:00 2001 From: blam <ben@blam.sh> Date: Thu, 18 Jul 2024 13:50:26 +0200 Subject: [PATCH 310/416] chore: smaller renames and code review Signed-off-by: blam <ben@blam.sh> --- .changeset/dry-squids-tap.md | 6 ++-- .../architecture/08-naming-patterns.md | 20 ++++++------- ....tsx => createExtensionBlueprint.test.tsx} | 30 +++++++++---------- ...ionKind.ts => createExtensionBlueprint.ts} | 22 +++++++------- .../frontend-plugin-api/src/wiring/index.ts | 8 ++--- 5 files changed, 43 insertions(+), 43 deletions(-) rename packages/frontend-plugin-api/src/wiring/{createExtensionKind.test.tsx => createExtensionBlueprint.test.tsx} (77%) rename packages/frontend-plugin-api/src/wiring/{createExtensionKind.ts => createExtensionBlueprint.ts} (90%) diff --git a/.changeset/dry-squids-tap.md b/.changeset/dry-squids-tap.md index 5a865395c0..879ecb5d14 100644 --- a/.changeset/dry-squids-tap.md +++ b/.changeset/dry-squids-tap.md @@ -8,8 +8,8 @@ This allows the creation of extension with the following pattern: ```tsx // create the extension kind -const TestExtensionKind = createExtensionKind({ - kind: 'test-extension', +const EntityCardBlueprint = createExtensionBlueprint({ + kind: 'entity-card', attachTo: { id: 'test', input: 'default' }, output: { element: coreExtensionData.reactElement, @@ -22,7 +22,7 @@ const TestExtensionKind = createExtensionKind({ }); // create an instance of the extension kind with props -const testExtension = TestExtensionKind.create({ +const testExtension = EntityCardBlueprint.make({ name: 'foo', params: { text: 'Hello World', diff --git a/docs/frontend-system/architecture/08-naming-patterns.md b/docs/frontend-system/architecture/08-naming-patterns.md index 0916d9fd51..a17525f3ce 100644 --- a/docs/frontend-system/architecture/08-naming-patterns.md +++ b/docs/frontend-system/architecture/08-naming-patterns.md @@ -38,33 +38,31 @@ Note that while we use this naming pattern for the plugin instance this is only | Description | Pattern | Examples | | ----------- | ------------------------------- | ------------------------------------------------------------------- | -| Creator | `create<Kind>Extension` | `createPageExtension`, `createEntityCardExtension` | +| Blueprint | `<Kind>Blueprint` | `PageBlueprint`, `EntityCardBlueprint` | | ID | `[<kind>:]<namespace>[/<name>]` | `'core.nav'`, `'page:user-settings'`, `'entity-card:catalog/about'` | | Symbol | `<namespace>[<Name>][<Kind>]` | `coreNav`, `userSettingsPage`, `catalogAboutEntityCard` | -When you create a new extension you never provide the ID directly. Instead, you indirectly or directly provide the kind, namespace, and name parts that make up the ID. The kind is always provided by the extension creator function used to create the extension, the only exception is if you use `createExtension` directly. Any extension that is provided by a plugin will by default have its namespace set to the plugin ID, so you generally only need to provide an explicit namespace if you want to override an existing extension. The name is also optional, and primarily used to distinguish between multiple extensions of the same kind and namespace. If a plugin doesn't need to distinguish between different extensions of the same kind, the name can be omitted. +When you create a new extension you never provide the ID directly. Instead, you indirectly or directly provide the kind, namespace, and name parts that make up the ID. The kind is always provided by the blueprint creator, the only exception is if you use `createExtension` directly. Any extension that is provided by a plugin will by default have its namespace set to the plugin ID, so you generally only need to provide an explicit namespace if you want to override an existing extension. The name is also optional, and primarily used to distinguish between multiple extensions of the same kind and namespace. If a plugin doesn't need to distinguish between different extensions of the same kind, the name can be omitted. Example: ```ts -// This is an extension creator that is used to create an extension of the 'page' kind. -export function createPageExtension(options) { - return createExtension({ - kind: 'page', // Kinds are kebab-case - // ...options - }); -} +// This is an extension blueprint that is used to create an extension of the 'page' kind. +export const PageBlueprint = createExtensionBlueprint({ + kind: 'page', + // ... +}); // The namespace is inferred from the plugin ID, in this case 'catalog' // The final ID for this extension will be 'page:catalog/entity' -const catalogEntityPage = createPageExtension({ +const catalogEntityPage = PageBlueprint.make({ name: 'entity', // ... }); // The name is omitted, because the catalog plugin only provides a single extension of this kind // The final ID for this extension will be 'search-result-list-item:catalog' -const catalogSearchResultListItem = createSearchResultListItemExtension({ +const catalogSearchResultListItem = SearchResultListItemBlueprint.make({ // ... }); diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionKind.test.tsx b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.test.tsx similarity index 77% rename from packages/frontend-plugin-api/src/wiring/createExtensionKind.test.tsx rename to packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.test.tsx index 3bdcd3a7cc..b3e926e57c 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtensionKind.test.tsx +++ b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.test.tsx @@ -16,27 +16,27 @@ import React from 'react'; import { coreExtensionData } from './coreExtensionData'; -import { createExtensionKind } from './createExtensionKind'; +import { createExtensionBlueprint } from './createExtensionBlueprint'; import { createExtensionTester } from '@backstage/frontend-test-utils'; -describe('createExtensionKind', () => { - it('should allow creation of extension kinds', () => { - const TestExtension = createExtensionKind({ +describe('createExtensionBlueprint', () => { + it('should allow creation of extension blueprints', () => { + const TestExtensionBlueprint = createExtensionBlueprint({ kind: 'test-extension', attachTo: { id: 'test', input: 'default' }, output: { element: coreExtensionData.reactElement, }, - factory(_, options: { text: string }) { + factory(_, params: { text: string }) { return { - element: <h1>{options.text}</h1>, + element: <h1>{params.text}</h1>, }; }, }); - const extension = TestExtension.new({ + const extension = TestExtensionBlueprint.make({ name: 'my-extension', - options: { + params: { text: 'Hello, world!', }, }); @@ -72,27 +72,27 @@ describe('createExtensionKind', () => { }); it('should allow overriding of the default factory', () => { - const TestExtension = createExtensionKind({ + const TestExtensionBlueprint = createExtensionBlueprint({ kind: 'test-extension', attachTo: { id: 'test', input: 'default' }, output: { element: coreExtensionData.reactElement, }, - factory(_, options: { text: string }) { + factory(_, params: { text: string }) { return { - element: <h1>{options.text}</h1>, + element: <h1>{params.text}</h1>, }; }, }); - const extension = TestExtension.new({ + const extension = TestExtensionBlueprint.make({ name: 'my-extension', - options: { + params: { text: 'Hello, world!', }, - factory(_, options: { text: string }) { + factory(_, params: { text: string }) { return { - element: <h2>{options.text}</h2>, + element: <h2>{params.text}</h2>, }; }, }); diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionKind.ts b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts similarity index 90% rename from packages/frontend-plugin-api/src/wiring/createExtensionKind.ts rename to packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts index 1212365712..74d2eeadf1 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtensionKind.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts @@ -29,7 +29,7 @@ import { /** * @public */ -export interface CreateExtensionKindOptions< +export interface CreateExtensionBlueprintOptions< TParams, TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, @@ -55,13 +55,13 @@ export interface CreateExtensionKindOptions< /** * @public */ -export interface ExtensionKind< +export interface ExtensionBlueprint< TParams, TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, TConfig, > { - create(args: { + make(args: { namespace?: string; name?: string; attachTo?: { id: string; input: string }; @@ -77,6 +77,7 @@ export interface ExtensionKind< inputs: Expand<ResolvedExtensionInputs<TInputs>>; orignalFactory( context?: { + node?: AppNode; config?: TConfig; inputs?: Expand<ResolvedExtensionInputs<TInputs>>; }, @@ -91,14 +92,14 @@ export interface ExtensionKind< /** * @internal */ -class ExtensionKindImpl< +class ExtensionBlueprintImpl< TParams, TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, TConfig, > { constructor( - private readonly options: CreateExtensionKindOptions< + private readonly options: CreateExtensionBlueprintOptions< TParams, TInputs, TOutput, @@ -106,7 +107,7 @@ class ExtensionKindImpl< >, ) {} - public create(args: { + public make(args: { namespace?: string; name?: string; attachTo?: { id: string; input: string }; @@ -122,6 +123,7 @@ class ExtensionKindImpl< inputs: Expand<ResolvedExtensionInputs<TInputs>>; orignalFactory( context?: { + node?: AppNode; config?: TConfig; inputs?: Expand<ResolvedExtensionInputs<TInputs>>; }, @@ -186,13 +188,13 @@ class ExtensionKindImpl< * * @public */ -export function createExtensionKind< +export function createExtensionBlueprint< TParams, TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, TConfig, >( - options: CreateExtensionKindOptions<TParams, TInputs, TOutput, TConfig>, -): ExtensionKind<TParams, TInputs, TOutput, TConfig> { - return new ExtensionKindImpl(options); + options: CreateExtensionBlueprintOptions<TParams, TInputs, TOutput, TConfig>, +): ExtensionBlueprint<TParams, TInputs, TOutput, TConfig> { + return new ExtensionBlueprintImpl(options); } diff --git a/packages/frontend-plugin-api/src/wiring/index.ts b/packages/frontend-plugin-api/src/wiring/index.ts index 8fe9dc3a54..6d20368225 100644 --- a/packages/frontend-plugin-api/src/wiring/index.ts +++ b/packages/frontend-plugin-api/src/wiring/index.ts @@ -49,7 +49,7 @@ export { type FrontendFeature, } from './types'; export { - type CreateExtensionKindOptions as ExtensionKindOptions, - ExtensionKind, - createExtensionKind, -} from './createExtensionKind'; + type CreateExtensionBlueprintOptions, + type ExtensionBlueprint, + createExtensionBlueprint, +} from './createExtensionBlueprint'; From 9b89b82f66b500dabc5493a51d2fd1144e4828a4 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg <poldsberg@gmail.com> Date: Thu, 18 Jul 2024 12:08:15 +0200 Subject: [PATCH 311/416] frontend-plugin-api: infer ExtensionBoundary routable prop from outputs Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com> --- .changeset/early-trees-dance.md | 5 ++ .changeset/mighty-dolls-retire.md | 5 ++ .../architecture/03-extensions.md | 4 +- packages/frontend-plugin-api/api-report.md | 1 - .../src/components/ExtensionBoundary.test.tsx | 72 ++++++++++++++++--- .../src/components/ExtensionBoundary.tsx | 14 +++- .../src/extensions/createPageExtension.tsx | 2 +- plugins/catalog-react/src/alpha.tsx | 2 +- 8 files changed, 91 insertions(+), 14 deletions(-) create mode 100644 .changeset/early-trees-dance.md create mode 100644 .changeset/mighty-dolls-retire.md diff --git a/.changeset/early-trees-dance.md b/.changeset/early-trees-dance.md new file mode 100644 index 0000000000..5422bd2872 --- /dev/null +++ b/.changeset/early-trees-dance.md @@ -0,0 +1,5 @@ +--- +'@backstage/frontend-plugin-api': patch +--- + +The `ExtensionBoundary` now by default infers whether its routable from whether it outputs a route path. diff --git a/.changeset/mighty-dolls-retire.md b/.changeset/mighty-dolls-retire.md new file mode 100644 index 0000000000..b31c443a38 --- /dev/null +++ b/.changeset/mighty-dolls-retire.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-react': patch +--- + +Internal refactor to remove unnecessary `routable` prop in the implementation of the `createEntityContentExtension` alpha export. diff --git a/docs/frontend-system/architecture/03-extensions.md b/docs/frontend-system/architecture/03-extensions.md index 19345e0b26..cdc73a17ec 100644 --- a/docs/frontend-system/architecture/03-extensions.md +++ b/docs/frontend-system/architecture/03-extensions.md @@ -337,7 +337,7 @@ Similar to plugins the `ErrorBoundary` for extension allows to pass in a fallbac ### Analytics -Analytics information are provided through the `AnalyticsContext`, which will give `extensionId` & `pluginId` as context to analytics event fired inside of the extension. Additionally `RouteTracker` will capture an analytics event for routable extension to inform which extension metadata gets associated with a navigation event when the route navigated to is a gathered `mountPoint`. +Analytics information are provided through the `AnalyticsContext`, which will give `extensionId` & `pluginId` as context to analytics event fired inside of the extension. Additionally `RouteTracker` will capture an analytics event for routable extension to inform which extension metadata gets associated with a navigation event when the route navigated to is a gathered `mountPoint`. Whether an extension is routable is inferred from its outputs, but you can also explicitly control this behavior by passing the `routable` prop to `ExtensionBoundary`. The `ExtensionBoundary` can be used like the following in an extension creator: @@ -359,7 +359,7 @@ export function createSomeExtension< path: config.path, routeRef: options.routeRef, element: ( - <ExtensionBoundary node={node} routable> + <ExtensionBoundary node={node}> <ExtensionComponent /> </ExtensionBoundary> ), diff --git a/packages/frontend-plugin-api/api-report.md b/packages/frontend-plugin-api/api-report.md index 3e19573d95..d50ef0dd03 100644 --- a/packages/frontend-plugin-api/api-report.md +++ b/packages/frontend-plugin-api/api-report.md @@ -844,7 +844,6 @@ export interface ExtensionBoundaryProps { children: ReactNode; // (undocumented) node: AppNode; - // (undocumented) routable?: boolean; } diff --git a/packages/frontend-plugin-api/src/components/ExtensionBoundary.test.tsx b/packages/frontend-plugin-api/src/components/ExtensionBoundary.test.tsx index 66fb3901fc..1f12f127e8 100644 --- a/packages/frontend-plugin-api/src/components/ExtensionBoundary.test.tsx +++ b/packages/frontend-plugin-api/src/components/ExtensionBoundary.test.tsx @@ -15,15 +15,24 @@ */ import React, { useEffect } from 'react'; -import { screen, waitFor } from '@testing-library/react'; -import { MockAnalyticsApi, TestApiProvider } from '@backstage/test-utils'; +import { act, screen, waitFor } from '@testing-library/react'; +import { + MockAnalyticsApi, + TestApiProvider, + withLogCollector, +} from '@backstage/test-utils'; import { ExtensionBoundary } from './ExtensionBoundary'; import { coreExtensionData, createExtension } from '../wiring'; -import { analyticsApiRef, useAnalytics } from '@backstage/core-plugin-api'; +import { + analyticsApiRef, + createApiFactory, + useAnalytics, +} from '@backstage/core-plugin-api'; import { createRouteRef } from '../routing'; import { createExtensionTester } from '@backstage/frontend-test-utils'; +import { createApiExtension } from '../extensions'; -const wrapInBoundaryExtension = (element: JSX.Element) => { +const wrapInBoundaryExtension = (element?: JSX.Element) => { const routeRef = createRouteRef(); return createExtension({ name: 'test', @@ -54,12 +63,25 @@ describe('ExtensionBoundary', () => { }); it('should show app error component when an error is thrown', async () => { - const error = 'Something went wrong'; + const errorMsg = 'Something went wrong'; const ErrorComponent = () => { - throw new Error(error); + throw new Error(errorMsg); }; - createExtensionTester(wrapInBoundaryExtension(<ErrorComponent />)).render(); - await waitFor(() => expect(screen.getByText(error)).toBeInTheDocument()); + const { error } = await withLogCollector(['error'], async () => { + createExtensionTester( + wrapInBoundaryExtension(<ErrorComponent />), + ).render(); + await waitFor(() => + expect(screen.getByText(errorMsg)).toBeInTheDocument(), + ); + }); + expect(error).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + message: expect.stringContaining(errorMsg), + }), + ]), + ); }); it('should wrap children with analytics context', async () => { @@ -97,4 +119,38 @@ describe('ExtensionBoundary', () => { }); }); }); + + // TODO(Rugvip): It's annoying to test the inverse of this currently, because the extension tester overrides the subject to always output a path + it('should emit analytics events if routable', async () => { + const Emitter = () => { + const analytics = useAnalytics(); + useEffect(() => { + analytics.captureEvent('dummy', 'dummy'); + }); + return null; + }; + const analyticsApiMock = new MockAnalyticsApi(); + + await act(async () => { + createExtensionTester(wrapInBoundaryExtension(<Emitter />)) + .add( + createApiExtension({ + factory: createApiFactory(analyticsApiRef, analyticsApiMock), + }), + ) + .render(); + }); + + expect(analyticsApiMock.getEvents()).toEqual([ + expect.objectContaining({ + action: 'navigate', + subject: '/', + context: expect.objectContaining({ + pluginId: 'root', + extensionId: 'test', + }), + }), + expect.objectContaining({ action: 'dummy' }), + ]); + }); }); diff --git a/packages/frontend-plugin-api/src/components/ExtensionBoundary.tsx b/packages/frontend-plugin-api/src/components/ExtensionBoundary.tsx index 768352b76e..b6269484b0 100644 --- a/packages/frontend-plugin-api/src/components/ExtensionBoundary.tsx +++ b/packages/frontend-plugin-api/src/components/ExtensionBoundary.tsx @@ -26,6 +26,7 @@ import { ErrorBoundary } from './ErrorBoundary'; import { routableExtensionRenderedEvent } from '../../../core-plugin-api/src/analytics/Tracker'; import { AppNode, useComponentRef } from '../apis'; import { coreComponentRefs } from './coreComponentRefs'; +import { coreExtensionData } from '../wiring'; type RouteTrackerProps = PropsWithChildren<{ disableTracking?: boolean; @@ -50,6 +51,11 @@ const RouteTracker = (props: RouteTrackerProps) => { /** @public */ export interface ExtensionBoundaryProps { node: AppNode; + /** + * This explicitly marks the extension as routable for the purpose of + * capturing analytics events. If not provided, the extension boundary will be + * marked as routable if it outputs a routePath. + */ routable?: boolean; children: ReactNode; } @@ -58,6 +64,10 @@ export interface ExtensionBoundaryProps { export function ExtensionBoundary(props: ExtensionBoundaryProps) { const { node, routable, children } = props; + const doesOutputRoutePath = Boolean( + node.instance?.getData(coreExtensionData.routePath), + ); + const plugin = node.spec.source; const Progress = useComponentRef(coreComponentRefs.progress); const fallback = useComponentRef(coreComponentRefs.errorBoundaryFallback); @@ -72,7 +82,9 @@ export function ExtensionBoundary(props: ExtensionBoundaryProps) { <Suspense fallback={<Progress />}> <ErrorBoundary plugin={plugin} Fallback={fallback}> <AnalyticsContext attributes={attributes}> - <RouteTracker disableTracking={!routable}>{children}</RouteTracker> + <RouteTracker disableTracking={!(routable ?? doesOutputRoutePath)}> + {children} + </RouteTracker> </AnalyticsContext> </ErrorBoundary> </Suspense> diff --git a/packages/frontend-plugin-api/src/extensions/createPageExtension.tsx b/packages/frontend-plugin-api/src/extensions/createPageExtension.tsx index dfe549f32b..cd434a3ffc 100644 --- a/packages/frontend-plugin-api/src/extensions/createPageExtension.tsx +++ b/packages/frontend-plugin-api/src/extensions/createPageExtension.tsx @@ -87,7 +87,7 @@ export function createPageExtension< path: config.path, routeRef: options.routeRef, element: ( - <ExtensionBoundary node={node} routable> + <ExtensionBoundary node={node}> <ExtensionComponent /> </ExtensionBoundary> ), diff --git a/plugins/catalog-react/src/alpha.tsx b/plugins/catalog-react/src/alpha.tsx index b1650d1f5b..85712b358a 100644 --- a/plugins/catalog-react/src/alpha.tsx +++ b/plugins/catalog-react/src/alpha.tsx @@ -166,7 +166,7 @@ export function createEntityContentExtension< title: config.title, routeRef: options.routeRef, element: ( - <ExtensionBoundary node={node} routable> + <ExtensionBoundary node={node}> <ExtensionComponent /> </ExtensionBoundary> ), From 5eaaf807fade6caae1a874744140ea469a46dbcc Mon Sep 17 00:00:00 2001 From: blam <ben@blam.sh> Date: Thu, 18 Jul 2024 14:15:03 +0200 Subject: [PATCH 312/416] chore: fixing api-reports and changeset Signed-off-by: blam <ben@blam.sh> --- .changeset/dry-squids-tap.md | 8 +- packages/frontend-plugin-api/api-report.md | 179 ++++++++++----------- 2 files changed, 88 insertions(+), 99 deletions(-) diff --git a/.changeset/dry-squids-tap.md b/.changeset/dry-squids-tap.md index 879ecb5d14..d0a737f4af 100644 --- a/.changeset/dry-squids-tap.md +++ b/.changeset/dry-squids-tap.md @@ -2,12 +2,12 @@ '@backstage/frontend-plugin-api': patch --- -Introduce a new way to create extension types and kinds, with `createExtensionKind`. +Introduce a new way to encapsulate extension kinds that replaces the extension creator pattern with `createExtensionBlueprint` -This allows the creation of extension with the following pattern: +This allows the creation of extension instances with the following pattern: ```tsx -// create the extension kind +// create the extension blueprint which is used to create instances const EntityCardBlueprint = createExtensionBlueprint({ kind: 'entity-card', attachTo: { id: 'test', input: 'default' }, @@ -21,7 +21,7 @@ const EntityCardBlueprint = createExtensionBlueprint({ }, }); -// create an instance of the extension kind with props +// create an instance of the extension blueprint with params const testExtension = EntityCardBlueprint.make({ name: 'foo', params: { diff --git a/packages/frontend-plugin-api/api-report.md b/packages/frontend-plugin-api/api-report.md index 48718f5375..858350044c 100644 --- a/packages/frontend-plugin-api/api-report.md +++ b/packages/frontend-plugin-api/api-report.md @@ -499,6 +499,51 @@ export function createExtension< options: CreateExtensionOptions<TOutput, TInputs, TConfig>, ): ExtensionDefinition<TConfig>; +// @public +export function createExtensionBlueprint< + TParams, + TInputs extends AnyExtensionInputMap, + TOutput extends AnyExtensionDataMap, + TConfig, +>( + options: CreateExtensionBlueprintOptions<TParams, TInputs, TOutput, TConfig>, +): ExtensionBlueprint<TParams, TInputs, TOutput, TConfig>; + +// @public (undocumented) +export interface CreateExtensionBlueprintOptions< + TParams, + TInputs extends AnyExtensionInputMap, + TOutput extends AnyExtensionDataMap, + TConfig, +> { + // (undocumented) + attachTo: { + id: string; + input: string; + }; + // (undocumented) + configSchema?: PortableSchema<TConfig>; + // (undocumented) + disabled?: boolean; + // (undocumented) + factory( + context: { + node: AppNode; + config: TConfig; + inputs: Expand<ResolvedExtensionInputs<TInputs>>; + }, + params: TParams, + ): Expand<ExtensionDataValues<TOutput>>; + // (undocumented) + inputs?: TInputs; + // (undocumented) + kind: string; + // (undocumented) + namespace?: string; + // (undocumented) + output: TOutput; +} + // @public (undocumented) export function createExtensionDataRef<TData>( id: string, @@ -522,16 +567,6 @@ export function createExtensionInput< } >; -// @public -export function createExtensionKind< - TOptions, - TInputs extends AnyExtensionInputMap, - TOutput extends AnyExtensionDataMap, - TConfig, ->( - options: ExtensionKindOptions<TOptions, TInputs, TOutput, TConfig>, -): ExtensionKind<TOptions, TInputs, TOutput, TConfig>; - // @public (undocumented) export interface CreateExtensionOptions< TOutput extends AnyExtensionDataMap, @@ -843,6 +878,45 @@ export interface Extension<TConfig> { readonly id: string; } +// @public (undocumented) +export interface ExtensionBlueprint< + TParams, + TInputs extends AnyExtensionInputMap, + TOutput extends AnyExtensionDataMap, + TConfig, +> { + // (undocumented) + make(args: { + namespace?: string; + name?: string; + attachTo?: { + id: string; + input: string; + }; + disabled?: boolean; + inputs?: TInputs; + output?: TOutput; + configSchema?: PortableSchema<TConfig>; + params: TParams; + factory?( + context: { + node: AppNode; + config: TConfig; + inputs: Expand<ResolvedExtensionInputs<TInputs>>; + orignalFactory( + context?: { + node?: AppNode; + config?: TConfig; + inputs?: Expand<ResolvedExtensionInputs<TInputs>>; + }, + params?: TParams, + ): Expand<ExtensionDataValues<TOutput>>; + }, + params: TParams, + ): Expand<ExtensionDataValues<TOutput>>; + }): ExtensionDefinition<TConfig>; +} + // @public (undocumented) export function ExtensionBoundary( props: ExtensionBoundaryProps, @@ -923,91 +997,6 @@ export interface ExtensionInput< extensionData: TExtensionData; } -// @public -export class ExtensionKind< - TOptions, - TInputs extends AnyExtensionInputMap, - TOutput extends AnyExtensionDataMap, - TConfig, -> { - // (undocumented) - static create< - TOptions, - TInputs extends AnyExtensionInputMap, - TOutput extends AnyExtensionDataMap, - TConfig, - >( - options: ExtensionKindOptions<TOptions, TInputs, TOutput, TConfig>, - ): ExtensionKind<TOptions, TInputs, TOutput, TConfig>; - // (undocumented) - new(args: { - namespace?: string; - name?: string; - attachTo?: { - id: string; - input: string; - }; - disabled?: boolean; - inputs?: TInputs; - output?: TOutput; - configSchema?: PortableSchema<TConfig>; - options: TOptions; - factory?( - context: { - node: AppNode; - config: TConfig; - inputs: Expand<ResolvedExtensionInputs<TInputs>>; - orignalFactory( - context?: { - node?: AppNode; - config?: TConfig; - inputs?: Expand<ResolvedExtensionInputs<TInputs>>; - }, - options?: TOptions, - ): Expand<ExtensionDataValues<TOutput>>; - }, - options: TOptions, - ): Expand<ExtensionDataValues<TOutput>>; - }): ExtensionDefinition<TConfig>; -} - -// @public (undocumented) -export interface ExtensionKindOptions< - TOptions, - TInputs extends AnyExtensionInputMap, - TOutput extends AnyExtensionDataMap, - TConfig, -> { - // (undocumented) - attachTo: { - id: string; - input: string; - }; - // (undocumented) - configSchema?: PortableSchema<TConfig>; - // (undocumented) - disabled?: boolean; - // (undocumented) - factory( - context: { - node: AppNode; - config: TConfig; - inputs: Expand<ResolvedExtensionInputs<TInputs>>; - }, - options: TOptions, - ): Expand<ExtensionDataValues<TOutput>>; - // (undocumented) - inputs?: TInputs; - // (undocumented) - kind: string; - // (undocumented) - name?: string; - // (undocumented) - namespace?: string; - // (undocumented) - output: TOutput; -} - // @public (undocumented) export interface ExtensionOverrides { // (undocumented) From 3f257d25e26c51f21f6d63c3feecec59862eadb8 Mon Sep 17 00:00:00 2001 From: blam <ben@blam.sh> Date: Thu, 18 Jul 2024 14:59:02 +0200 Subject: [PATCH 313/416] chore: switch around the params to the factories Signed-off-by: blam <ben@blam.sh> --- .changeset/dry-squids-tap.md | 2 +- packages/frontend-plugin-api/api-report.md | 6 +- .../wiring/createExtensionBlueprint.test.tsx | 6 +- .../src/wiring/createExtensionBlueprint.ts | 61 ++++++++----------- 4 files changed, 33 insertions(+), 42 deletions(-) diff --git a/.changeset/dry-squids-tap.md b/.changeset/dry-squids-tap.md index d0a737f4af..613ec4b7cb 100644 --- a/.changeset/dry-squids-tap.md +++ b/.changeset/dry-squids-tap.md @@ -14,7 +14,7 @@ const EntityCardBlueprint = createExtensionBlueprint({ output: { element: coreExtensionData.reactElement, }, - factory(_, params: { text: string }) { + factory(params: { text: string }) { return { element: <h1>{params.text}</h1>, }; diff --git a/packages/frontend-plugin-api/api-report.md b/packages/frontend-plugin-api/api-report.md index 858350044c..342907e096 100644 --- a/packages/frontend-plugin-api/api-report.md +++ b/packages/frontend-plugin-api/api-report.md @@ -527,12 +527,12 @@ export interface CreateExtensionBlueprintOptions< disabled?: boolean; // (undocumented) factory( + params: TParams, context: { node: AppNode; config: TConfig; inputs: Expand<ResolvedExtensionInputs<TInputs>>; }, - params: TParams, ): Expand<ExtensionDataValues<TOutput>>; // (undocumented) inputs?: TInputs; @@ -899,20 +899,20 @@ export interface ExtensionBlueprint< configSchema?: PortableSchema<TConfig>; params: TParams; factory?( + params: TParams, context: { node: AppNode; config: TConfig; inputs: Expand<ResolvedExtensionInputs<TInputs>>; orignalFactory( + params?: TParams, context?: { node?: AppNode; config?: TConfig; inputs?: Expand<ResolvedExtensionInputs<TInputs>>; }, - params?: TParams, ): Expand<ExtensionDataValues<TOutput>>; }, - params: TParams, ): Expand<ExtensionDataValues<TOutput>>; }): ExtensionDefinition<TConfig>; } diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.test.tsx b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.test.tsx index b3e926e57c..c7b077bdbd 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.test.tsx +++ b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.test.tsx @@ -27,7 +27,7 @@ describe('createExtensionBlueprint', () => { output: { element: coreExtensionData.reactElement, }, - factory(_, params: { text: string }) { + factory(params: { text: string }) { return { element: <h1>{params.text}</h1>, }; @@ -78,7 +78,7 @@ describe('createExtensionBlueprint', () => { output: { element: coreExtensionData.reactElement, }, - factory(_, params: { text: string }) { + factory(params: { text: string }) { return { element: <h1>{params.text}</h1>, }; @@ -90,7 +90,7 @@ describe('createExtensionBlueprint', () => { params: { text: 'Hello, world!', }, - factory(_, params: { text: string }) { + factory(params: { text: string }) { return { element: <h2>{params.text}</h2>, }; diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts index 74d2eeadf1..6c79017a0a 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts @@ -43,12 +43,12 @@ export interface CreateExtensionBlueprintOptions< output: TOutput; configSchema?: PortableSchema<TConfig>; factory( + params: TParams, context: { node: AppNode; config: TConfig; inputs: Expand<ResolvedExtensionInputs<TInputs>>; }, - params: TParams, ): Expand<ExtensionDataValues<TOutput>>; } @@ -71,20 +71,20 @@ export interface ExtensionBlueprint< configSchema?: PortableSchema<TConfig>; params: TParams; factory?( + params: TParams, context: { node: AppNode; config: TConfig; inputs: Expand<ResolvedExtensionInputs<TInputs>>; orignalFactory( + params?: TParams, context?: { node?: AppNode; config?: TConfig; inputs?: Expand<ResolvedExtensionInputs<TInputs>>; }, - params?: TParams, ): Expand<ExtensionDataValues<TOutput>>; }, - params: TParams, ): Expand<ExtensionDataValues<TOutput>>; }): ExtensionDefinition<TConfig>; } @@ -117,20 +117,20 @@ class ExtensionBlueprintImpl< configSchema?: PortableSchema<TConfig>; params: TParams; factory?( + params: TParams, context: { node: AppNode; config: TConfig; inputs: Expand<ResolvedExtensionInputs<TInputs>>; orignalFactory( + params?: TParams, context?: { node?: AppNode; config?: TConfig; inputs?: Expand<ResolvedExtensionInputs<TInputs>>; }, - params?: TParams, ): Expand<ExtensionDataValues<TOutput>>; }, - params: TParams, ): Expand<ExtensionDataValues<TOutput>>; }): ExtensionDefinition<TConfig> { return createExtension({ @@ -144,39 +144,30 @@ class ExtensionBlueprintImpl< configSchema: args.configSchema ?? this.options.configSchema, // TODO: some config merging or smth factory: ({ node, config, inputs }) => { if (args.factory) { - return args.factory( - { - node, - config, - inputs, - orignalFactory: ( - innerContext?: { - config?: TConfig; - inputs?: Expand<ResolvedExtensionInputs<TInputs>>; - }, - innerParams?: TParams, - ) => - this.options.factory( - { - node, - config: innerContext?.config ?? config, - inputs: innerContext?.inputs ?? inputs, - }, - innerParams ?? args.params, - ), - }, - args.params, - ); - } - - return this.options.factory( - { + return args.factory(args.params, { node, config, inputs, - }, - args.params, - ); + orignalFactory: ( + innerParams?: TParams, + innerContext?: { + config?: TConfig; + inputs?: Expand<ResolvedExtensionInputs<TInputs>>; + }, + ) => + this.options.factory(innerParams ?? args.params, { + node, + config: innerContext?.config ?? config, + inputs: innerContext?.inputs ?? inputs, + }), + }); + } + + return this.options.factory(args.params, { + node, + config, + inputs, + }); }, }); } From b1104f9bd5c8516e7d85a70660f394608d0057a2 Mon Sep 17 00:00:00 2001 From: blam <ben@blam.sh> Date: Thu, 18 Jul 2024 16:58:03 +0200 Subject: [PATCH 314/416] chore: skip backend dynamic Signed-off-by: blam <ben@blam.sh> --- .changeset/nine-glasses-nail.md | 1 - packages/backend-dynamic-feature-service/package.json | 3 +-- .../src/schemas/rootLoggerServiceFactory.ts | 4 ++-- yarn.lock | 1 - 4 files changed, 3 insertions(+), 6 deletions(-) diff --git a/.changeset/nine-glasses-nail.md b/.changeset/nine-glasses-nail.md index 0d68da9f2b..138acce3dd 100644 --- a/.changeset/nine-glasses-nail.md +++ b/.changeset/nine-glasses-nail.md @@ -1,5 +1,4 @@ --- -'@backstage/backend-dynamic-feature-service': patch '@backstage/plugin-search-backend-module-pg': patch --- diff --git a/packages/backend-dynamic-feature-service/package.json b/packages/backend-dynamic-feature-service/package.json index c693135f30..0d05b97bd9 100644 --- a/packages/backend-dynamic-feature-service/package.json +++ b/packages/backend-dynamic-feature-service/package.json @@ -41,8 +41,8 @@ "start": "backstage-cli package start" }, "dependencies": { + "@backstage/backend-app-api": "workspace:^", "@backstage/backend-common": "workspace:^", - "@backstage/backend-defaults": "workspace:^", "@backstage/backend-plugin-api": "workspace:^", "@backstage/backend-tasks": "workspace:^", "@backstage/cli-common": "workspace:^", @@ -70,7 +70,6 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/backend-app-api": "workspace:^", "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", "wait-for-expect": "^3.0.2" diff --git a/packages/backend-dynamic-feature-service/src/schemas/rootLoggerServiceFactory.ts b/packages/backend-dynamic-feature-service/src/schemas/rootLoggerServiceFactory.ts index bf3df3ffe7..6681a65a75 100644 --- a/packages/backend-dynamic-feature-service/src/schemas/rootLoggerServiceFactory.ts +++ b/packages/backend-dynamic-feature-service/src/schemas/rootLoggerServiceFactory.ts @@ -18,9 +18,9 @@ import { createServiceFactory, coreServices, } from '@backstage/backend-plugin-api'; -import { WinstonLogger } from '@backstage/backend-defaults/rootLogger'; +import { WinstonLogger } from '@backstage/backend-app-api'; import { transports, format } from 'winston'; -import { createConfigSecretEnumerator } from '@backstage/backend-defaults/rootLogger'; +import { createConfigSecretEnumerator } from '@backstage/backend-app-api'; import { loadConfigSchema } from '@backstage/config-loader'; import { getPackages } from '@manypkg/get-packages'; import { dynamicPluginsSchemasServiceRef } from './schemas'; diff --git a/yarn.lock b/yarn.lock index 53bef5284a..9261d70f21 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3708,7 +3708,6 @@ __metadata: dependencies: "@backstage/backend-app-api": "workspace:^" "@backstage/backend-common": "workspace:^" - "@backstage/backend-defaults": "workspace:^" "@backstage/backend-plugin-api": "workspace:^" "@backstage/backend-tasks": "workspace:^" "@backstage/backend-test-utils": "workspace:^" From 73184b37beea314d63196229f28c11bb14c89315 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg <poldsberg@gmail.com> Date: Thu, 18 Jul 2024 18:46:25 +0200 Subject: [PATCH 315/416] ' Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com> --- .changeset/early-trees-dance.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/early-trees-dance.md b/.changeset/early-trees-dance.md index 5422bd2872..55b2c08f89 100644 --- a/.changeset/early-trees-dance.md +++ b/.changeset/early-trees-dance.md @@ -2,4 +2,4 @@ '@backstage/frontend-plugin-api': patch --- -The `ExtensionBoundary` now by default infers whether its routable from whether it outputs a route path. +The `ExtensionBoundary` now by default infers whether it's routable from whether it outputs a route path. From 6ecedfafbcdeedc529868b615d2597a6121a7f5c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 18 Jul 2024 17:03:48 +0000 Subject: [PATCH 316/416] fix(deps): update dependency stream-buffers to v3.0.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 6db9d6b8f4..b63d8d7d63 100644 --- a/yarn.lock +++ b/yarn.lock @@ -41326,9 +41326,9 @@ __metadata: linkType: hard "stream-buffers@npm:^3.0.2": - version: 3.0.2 - resolution: "stream-buffers@npm:3.0.2" - checksum: b09fdeea606e3113ebd0e07010ed0cf038608fa396130add9e45deaff5cc3ba845dc25c31ad24f8341f85907846344cb7c85f75ea52c6572e2ac646e9b6072d0 + version: 3.0.3 + resolution: "stream-buffers@npm:3.0.3" + checksum: 3f0bdc4b1fd3ff370cef5a2103dd930b8981d42d97741eeb087a660771e27f0fc35fa8a351bb36e15bbbbce0eea00fefed60d6cdff4c6c3f527580529f183807 languageName: node linkType: hard From ba8571efe953a343e08195cb586c2e1bd3b6adaa Mon Sep 17 00:00:00 2001 From: Yayun Feng <yayfen@amazon.com> Date: Sat, 1 Jun 2024 00:09:56 +0200 Subject: [PATCH 317/416] Setup user agent header for AWS sdk client Signed-off-by: Yayun Feng <yervant.feng@gmail.com> --- .changeset/chilly-trains-sleep.md | 7 +++++++ .../entrypoints/urlReader/lib/AwsCodeCommitUrlReader.ts | 1 + .../src/entrypoints/urlReader/lib/AwsS3UrlReader.ts | 1 + .../src/processors/AwsEKSClusterProcessor.ts | 1 + .../src/providers/AwsS3EntityProvider.ts | 1 + .../src/publisher/AwsSqsConsumingEventPublisher.ts | 1 + 6 files changed, 12 insertions(+) create mode 100644 .changeset/chilly-trains-sleep.md diff --git a/.changeset/chilly-trains-sleep.md b/.changeset/chilly-trains-sleep.md new file mode 100644 index 0000000000..cde7600c8b --- /dev/null +++ b/.changeset/chilly-trains-sleep.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-events-backend-module-aws-sqs': patch +'@backstage/plugin-catalog-backend-module-aws': patch +'@backstage/backend-common': patch +--- + +Setup user agent header for AWS sdk clients, this enables users to better track API calls made from Backstage to AWS APIs through things like CloudTrail. diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/AwsCodeCommitUrlReader.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/AwsCodeCommitUrlReader.ts index 7f02f1468f..5a2655ad1c 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/AwsCodeCommitUrlReader.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/AwsCodeCommitUrlReader.ts @@ -213,6 +213,7 @@ export class AwsCodeCommitUrlReader implements UrlReaderService { ); const codeCommit = new CodeCommitClient({ + customUserAgent: 'backstage-aws-codecommit-url-reader', region: region, credentials: credentials, }); diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/AwsS3UrlReader.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/AwsS3UrlReader.ts index 27f60f5b77..324538add4 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/AwsS3UrlReader.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/AwsS3UrlReader.ts @@ -222,6 +222,7 @@ export class AwsS3UrlReader implements UrlReaderService { ); const s3 = new S3Client({ + customUserAgent: 'backstage-aws-s3-url-reader', region: region, credentials: credentials, endpoint: integration.config.endpoint, diff --git a/plugins/catalog-backend-module-aws/src/processors/AwsEKSClusterProcessor.ts b/plugins/catalog-backend-module-aws/src/processors/AwsEKSClusterProcessor.ts index a491dbab7d..a5f5ce2f6c 100644 --- a/plugins/catalog-backend-module-aws/src/processors/AwsEKSClusterProcessor.ts +++ b/plugins/catalog-backend-module-aws/src/processors/AwsEKSClusterProcessor.ts @@ -106,6 +106,7 @@ export class AwsEKSClusterProcessor implements CatalogProcessor { } const eksClient = new EKS({ + customUserAgent: 'backstage-aws-catalog-eks-cluster-processor', credentials, credentialDefaultProvider: providerFunction, region, diff --git a/plugins/catalog-backend-module-aws/src/providers/AwsS3EntityProvider.ts b/plugins/catalog-backend-module-aws/src/providers/AwsS3EntityProvider.ts index 91ba76b695..0c58fe3f3a 100644 --- a/plugins/catalog-backend-module-aws/src/providers/AwsS3EntityProvider.ts +++ b/plugins/catalog-backend-module-aws/src/providers/AwsS3EntityProvider.ts @@ -154,6 +154,7 @@ export class AwsS3EntityProvider implements EntityProvider { accountId ? { accountId } : undefined, ); this.s3 = new S3({ + customUserAgent: 'backstage-aws-catalog-s3-entity-provider', apiVersion: '2006-03-01', credentialDefaultProvider: () => credProvider.sdkCredentialProvider, endpoint: this.integration.config.endpoint, diff --git a/plugins/events-backend-module-aws-sqs/src/publisher/AwsSqsConsumingEventPublisher.ts b/plugins/events-backend-module-aws-sqs/src/publisher/AwsSqsConsumingEventPublisher.ts index 26eba88c18..de55dee017 100644 --- a/plugins/events-backend-module-aws-sqs/src/publisher/AwsSqsConsumingEventPublisher.ts +++ b/plugins/events-backend-module-aws-sqs/src/publisher/AwsSqsConsumingEventPublisher.ts @@ -76,6 +76,7 @@ export class AwsSqsConsumingEventPublisher { }; this.sqs = new SQSClient({ + customUserAgent: 'backstage-aws-events-sqs-publisher', region: config.region, endpoint: config.endpoint, }); From 1eb5e9f686bd52bf99af3f611415ce2ad8bd7dc7 Mon Sep 17 00:00:00 2001 From: blam <ben@blam.sh> Date: Fri, 19 Jul 2024 14:06:17 +0200 Subject: [PATCH 318/416] chore: attempt to fix the tabs Signed-off-by: blam <ben@blam.sh> --- .../TabbedLayout/RoutedTabs.test.tsx | 12 +++++ .../components/TabbedLayout/RoutedTabs.tsx | 51 ++++++++----------- 2 files changed, 33 insertions(+), 30 deletions(-) diff --git a/packages/core-components/src/components/TabbedLayout/RoutedTabs.test.tsx b/packages/core-components/src/components/TabbedLayout/RoutedTabs.test.tsx index ec91208eee..991276c5d3 100644 --- a/packages/core-components/src/components/TabbedLayout/RoutedTabs.test.tsx +++ b/packages/core-components/src/components/TabbedLayout/RoutedTabs.test.tsx @@ -160,4 +160,16 @@ describe('RoutedTabs', () => { rendered.queryByText('tabbed-test-content-2'), ).not.toBeInTheDocument(); }); + + it('should render the tabs as <a> links', async () => { + const routes = [testRoute2, testRoute1, testRoute3]; + const rendered = await renderInTestApp(<RoutedTabs routes={routes} />); + + const tabs = rendered.queryAllByRole('tab'); + + for (const [k, v] of Object.entries(tabs)) { + expect(v.tagName).toBe('A'); + expect(v).toHaveAttribute('href', routes[Number(k)].path); + } + }); }); diff --git a/packages/core-components/src/components/TabbedLayout/RoutedTabs.tsx b/packages/core-components/src/components/TabbedLayout/RoutedTabs.tsx index 6a5bf2970f..d6f6eab144 100644 --- a/packages/core-components/src/components/TabbedLayout/RoutedTabs.tsx +++ b/packages/core-components/src/components/TabbedLayout/RoutedTabs.tsx @@ -15,15 +15,11 @@ */ import React, { useMemo } from 'react'; import { Helmet } from 'react-helmet'; -import { - matchRoutes, - useNavigate, - useParams, - useRoutes, -} from 'react-router-dom'; +import { matchRoutes, useParams, useRoutes } from 'react-router-dom'; import { Content } from '../../layout/Content'; import { HeaderTabs } from '../../layout/HeaderTabs'; import { SubRoute } from './types'; +import { Link } from '../Link'; export function useSelectedSubRoute(subRoutes: SubRoute[]): { index: number; @@ -68,38 +64,33 @@ export function useSelectedSubRoute(subRoutes: SubRoute[]): { export function RoutedTabs(props: { routes: SubRoute[] }) { const { routes } = props; - const navigate = useNavigate(); + const { index, route, element } = useSelectedSubRoute(routes); const headerTabs = useMemo( () => - routes.map(t => ({ - id: t.path, - label: t.title, - tabProps: t.tabProps, - })), + routes.map(t => { + const { path, title, tabProps } = t; + let to = path; + // Remove trailing /* + to = to.replace(/\/\*$/, ''); + // And remove leading / for relative navigation + to = to.replace(/^\//, ''); + return { + id: path, + label: title, + tabProps: { + ...tabProps, + component: Link, + to, + }, + }; + }), [routes], ); - const onTabChange = (tabIndex: number) => { - let { path } = routes[tabIndex]; - // Remove trailing /* - path = path.replace(/\/\*$/, ''); - // And remove leading / for relative navigation - path = path.replace(/^\//, ''); - // Note! route resolves relative to the position in the React tree, - // not relative to current location - navigate(path); - }; return ( <> - <HeaderTabs - tabs={headerTabs} - selectedIndex={index} - onChange={onTabChange} - tabProps={{ - component: Link, - }} - /> + <HeaderTabs tabs={headerTabs} selectedIndex={index} /> <Content> <Helmet title={route?.title} /> {element} From 678971ad41380d5b958ed4b9f72e9372385d9380 Mon Sep 17 00:00:00 2001 From: blam <ben@blam.sh> Date: Fri, 19 Jul 2024 14:07:17 +0200 Subject: [PATCH 319/416] chore: added changeset Signed-off-by: blam <ben@blam.sh> --- .changeset/eighty-mirrors-flow.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/eighty-mirrors-flow.md diff --git a/.changeset/eighty-mirrors-flow.md b/.changeset/eighty-mirrors-flow.md new file mode 100644 index 0000000000..57e978a78c --- /dev/null +++ b/.changeset/eighty-mirrors-flow.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-components': patch +--- + +Move the `Link` component to the `RoutedTabs` instead of the `HeaderTabs` component From de4cd433c15a6cc2ba63448ff31542decedaf2bf Mon Sep 17 00:00:00 2001 From: MT Lewis <mtlewis@users.noreply.github.com> Date: Fri, 19 Jul 2024 13:31:28 +0100 Subject: [PATCH 320/416] cli: simplify changeset Co-authored-by: Patrik Oldsberg <poldsberg@gmail.com> Signed-off-by: MT Lewis <mtlewis@users.noreply.github.com> --- .changeset/little-bulldogs-guess.md | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/.changeset/little-bulldogs-guess.md b/.changeset/little-bulldogs-guess.md index 1f86f0a67f..3e646a033f 100644 --- a/.changeset/little-bulldogs-guess.md +++ b/.changeset/little-bulldogs-guess.md @@ -2,16 +2,4 @@ '@backstage/cli': patch --- -Add ability to force use of the development versions of `react` and `react-dom` -to allow for detailed error messages and use of fast-refresh. Note that builds -with the development versions of `react` and `react-dom` should not be -deployed in production. - -This feature can be used by setting the `FORCE_REACT_DEVELOPMENT` environment -variable to `true`: - -```bash -EXPERIMENTAL_MODULE_FEDERATION=true \ -FORCE_REACT_DEVELOPMENT=true \ -yarn build:all -``` +The experimental module federation build now has the ability to force the use of development versions of `react` and `react-dom` by setting the `FORCE_REACT_DEVELOPMENT` flag. From 2e1a7f10e5f29af3e4f253ad62b7d61148c5f995 Mon Sep 17 00:00:00 2001 From: MT Lewis <mtlewis@users.noreply.github.com> Date: Fri, 19 Jul 2024 13:48:20 +0100 Subject: [PATCH 321/416] cli: only check for truthiness of environment variables when forcing react mode Signed-off-by: MT Lewis <mtlewis@users.noreply.github.com> --- 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 8e3d7eee19..3d3be4f485 100644 --- a/packages/cli/src/lib/bundler/config.ts +++ b/packages/cli/src/lib/bundler/config.ts @@ -237,8 +237,8 @@ export async function createConfig( const optimization = optimizationConfig(options); if ( - process.env.EXPERIMENTAL_MODULE_FEDERATION === 'true' && - process.env.FORCE_REACT_DEVELOPMENT === 'true' + !!process.env.EXPERIMENTAL_MODULE_FEDERATION && + !!process.env.FORCE_REACT_DEVELOPMENT ) { console.log( chalk.yellow( From 0983429447db996138e90c6168f82e47b405223e Mon Sep 17 00:00:00 2001 From: MT Lewis <mtlewis@users.noreply.github.com> Date: Fri, 19 Jul 2024 14:05:28 +0100 Subject: [PATCH 322/416] cli: expand comment Signed-off-by: MT Lewis <mtlewis@users.noreply.github.com> --- packages/cli/src/lib/bundler/config.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/cli/src/lib/bundler/config.ts b/packages/cli/src/lib/bundler/config.ts index 3d3be4f485..e10ac0253e 100644 --- a/packages/cli/src/lib/bundler/config.ts +++ b/packages/cli/src/lib/bundler/config.ts @@ -251,7 +251,9 @@ export async function createConfig( `${dirname(require.resolve('react-dom/package.json'))}/`, ]; - // Don't define process.env.NODE_ENV with value matching config.mode. + // Don't define process.env.NODE_ENV with value matching config.mode. If we + // don't set this to false, webpack will define the value of + // process.env.NODE_ENV for us, and the definition below will be ignored. optimization.nodeEnv = false; // Instead, provide a custom definition which always uses "development" if From 232b134606d193c262d38892e86e41bc979305fd Mon Sep 17 00:00:00 2001 From: MT Lewis <mtlewis@users.noreply.github.com> Date: Fri, 19 Jul 2024 14:07:35 +0100 Subject: [PATCH 323/416] cli: skip forcing react to development mode if mode is development anyway Signed-off-by: MT Lewis <mtlewis@users.noreply.github.com> --- packages/cli/src/lib/bundler/config.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/cli/src/lib/bundler/config.ts b/packages/cli/src/lib/bundler/config.ts index e10ac0253e..1f29277676 100644 --- a/packages/cli/src/lib/bundler/config.ts +++ b/packages/cli/src/lib/bundler/config.ts @@ -237,6 +237,7 @@ export async function createConfig( const optimization = optimizationConfig(options); if ( + mode === 'production' && !!process.env.EXPERIMENTAL_MODULE_FEDERATION && !!process.env.FORCE_REACT_DEVELOPMENT ) { From 6c94522688dc49b850db6d23c57b1a794c4b0602 Mon Sep 17 00:00:00 2001 From: MT Lewis <mtlewis@users.noreply.github.com> Date: Fri, 19 Jul 2024 14:08:54 +0100 Subject: [PATCH 324/416] cli: remove explicit boolean coercions when forcing react mode Signed-off-by: MT Lewis <mtlewis@users.noreply.github.com> --- 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 1f29277676..9a611a5954 100644 --- a/packages/cli/src/lib/bundler/config.ts +++ b/packages/cli/src/lib/bundler/config.ts @@ -238,8 +238,8 @@ export async function createConfig( if ( mode === 'production' && - !!process.env.EXPERIMENTAL_MODULE_FEDERATION && - !!process.env.FORCE_REACT_DEVELOPMENT + process.env.EXPERIMENTAL_MODULE_FEDERATION && + process.env.FORCE_REACT_DEVELOPMENT ) { console.log( chalk.yellow( From 0e706b3484998631a591b8a07a23b075781ffb25 Mon Sep 17 00:00:00 2001 From: Ben Lambert <blam@spotify.com> Date: Fri, 19 Jul 2024 15:40:42 +0200 Subject: [PATCH 325/416] Update modern-parrots-protect.md Signed-off-by: Ben Lambert <blam@spotify.com> --- .changeset/modern-parrots-protect.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/modern-parrots-protect.md b/.changeset/modern-parrots-protect.md index 7fccff1bef..bb4df2c248 100644 --- a/.changeset/modern-parrots-protect.md +++ b/.changeset/modern-parrots-protect.md @@ -2,4 +2,4 @@ '@backstage/plugin-scaffolder-react': patch --- -support ajv-errors for scaffolder validation +support `ajv-errors` for scaffolder validation to allow for customizing the error messages From b8600fe1650507c7b0e443ba58d8183e4a7413a8 Mon Sep 17 00:00:00 2001 From: Adam Letizia <LetiziaAdam@JohnDeere.com> Date: Fri, 19 Jul 2024 09:48:20 -0500 Subject: [PATCH 326/416] fix(scaffolder): refetch user credentials when selected host is changed in RepoUrlPicker Signed-off-by: Adam Letizia <LetiziaAdam@JohnDeere.com> --- .changeset/tough-lies-repair.md | 5 ++ .../RepoUrlPicker/RepoUrlPicker.test.tsx | 56 +++++++++++++++---- .../fields/RepoUrlPicker/RepoUrlPicker.tsx | 11 +++- 3 files changed, 58 insertions(+), 14 deletions(-) create mode 100644 .changeset/tough-lies-repair.md diff --git a/.changeset/tough-lies-repair.md b/.changeset/tough-lies-repair.md new file mode 100644 index 0000000000..25b1884bbc --- /dev/null +++ b/.changeset/tough-lies-repair.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder': patch +--- + +RepoUrlPicker: refetch user credentials when a new host is selected diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.test.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.test.tsx index 002652cfab..fce9d9517c 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.test.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.test.tsx @@ -33,6 +33,7 @@ import { ScaffolderRJSFField, } from '@backstage/plugin-scaffolder-react'; import { act, fireEvent } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; describe('RepoUrlPicker', () => { const mockScaffolderApi: Partial<ScaffolderApi> = { @@ -323,14 +324,29 @@ describe('RepoUrlPicker', () => { }); }); - it('should not call the scmAuthApi if secret is available in the state', async () => { + it('should call the scmAuthApi with the new host when the host is changed', async () => { const SecretsComponent = () => { const { secrets } = useTemplateSecrets(); return ( <div data-testid="current-secrets">{JSON.stringify({ secrets })}</div> ); }; - const { getByTestId } = await renderInTestApp( + const allowedHosts = ['github.com', 'gitlab.example.com']; + + (mockScmAuthApi.getCredentials as jest.Mock).mockImplementation( + ({ url }) => { + let token = ''; + if (url === `https://${allowedHosts[0]}`) { + token = 'abc123'; + } else if (url === `https://${allowedHosts[1]}`) { + token = 'def456'; + } + return Promise.resolve({ token }); + }, + ); + const secondHost = allowedHosts[1]; + + const { getAllByRole, getByTestId } = await renderInTestApp( <TestApiProvider apis={[ [scmIntegrationsApiRef, mockIntegrationsApi], @@ -338,16 +354,16 @@ describe('RepoUrlPicker', () => { [scaffolderApiRef, mockScaffolderApi], ]} > - <SecretsContextProvider initialSecrets={{ testKey: 'abc123' }}> + <SecretsContextProvider> <Form validator={validator} schema={{ type: 'string' }} uiSchema={{ 'ui:field': 'RepoUrlPicker', 'ui:options': { + allowedHosts, requestUserCredentials: { secretsKey: 'testKey', - additionalScopes: { github: ['workflow'] }, }, }, }} @@ -361,19 +377,35 @@ describe('RepoUrlPicker', () => { ); await act(async () => { + // need to wait for the debounce to finish to fetch credentials for the first selected host + await new Promise(resolve => setTimeout(resolve, 600)); + }); + const firstHostSecrets = JSON.parse( + getByTestId('current-secrets').textContent!, + ); + expect(firstHostSecrets).toEqual({ + secrets: { testKey: 'abc123' }, + }); + + await act(async () => { + // Select the second host + const hostInput = getAllByRole('combobox')[0]; + await userEvent.selectOptions(hostInput, secondHost); + // need to wait for the debounce to finish await new Promise(resolve => setTimeout(resolve, 600)); }); - - // as we already have a secret in the state, getCredentials should not be called again. - expect(mockScmAuthApi.getCredentials).toHaveBeenCalledTimes(0); - - const currentSecrets = JSON.parse( + const secondHostSecrets = JSON.parse( getByTestId('current-secrets').textContent!, ); - - expect(currentSecrets).toEqual({ - secrets: { testKey: 'abc123' }, + expect(secondHostSecrets).toEqual({ + secrets: { testKey: 'def456' }, + }); + expect(mockScmAuthApi.getCredentials).toHaveBeenCalledWith({ + url: `https://${secondHost}`, + additionalScope: { + repoWrite: true, + }, }); }); }); diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.tsx index e0d714ffda..e653be9178 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.tsx @@ -49,6 +49,9 @@ export const RepoUrlPicker = (props: RepoUrlPickerProps) => { const [state, setState] = useState<RepoUrlPickerState>( parseRepoPickerUrl(formData), ); + const [credentialsHost, setCredentialsHost] = useState<string | undefined>( + undefined, + ); const integrationApi = useApi(scmIntegrationsApiRef); const scmAuthApi = useApi(scmAuthApiRef); const { secrets, setSecrets } = useTemplateSecrets(); @@ -128,8 +131,11 @@ export const RepoUrlPicker = (props: RepoUrlPickerProps) => { return; } - // don't show login prompt if secret value is already in state - if (secrets[requestUserCredentials.secretsKey]) { + // don't show login prompt if secret value is already in state for selected host + if ( + secrets[requestUserCredentials.secretsKey] && + credentialsHost === state.host + ) { return; } @@ -147,6 +153,7 @@ export const RepoUrlPicker = (props: RepoUrlPickerProps) => { // set the secret using the key provided in the ui:options for use // in the templating the manifest with ${{ secrets[secretsKey] }} setSecrets({ [requestUserCredentials.secretsKey]: token }); + setCredentialsHost(state.host); }, 500, [state, uiSchema], From 924c0a6379fa9a2c521622259126125b0bc2ddc0 Mon Sep 17 00:00:00 2001 From: rghara <ramin.g01@infosys.com> Date: Fri, 19 Jul 2024 12:53:18 -0400 Subject: [PATCH 327/416] Updated document getting-started/logging-in with missing login screen screenshot Signed-off-by: rghara <ramin.g01@infosys.com> --- docs/assets/getting-started/login-screen.png | Bin 0 -> 108521 bytes docs/getting-started/logging-in.md | 2 ++ 2 files changed, 2 insertions(+) create mode 100755 docs/assets/getting-started/login-screen.png diff --git a/docs/assets/getting-started/login-screen.png b/docs/assets/getting-started/login-screen.png new file mode 100755 index 0000000000000000000000000000000000000000..70b56f399a22d19ad863f77db22739f67a352501 GIT binary patch literal 108521 zcmZs?1yCIAwk{k(aCd?Rw_pkG?(V?{BDe)-fCQHS!3pj%1PksmNN~3xgS)$Pn|%A* z=iL9lT?JHkO*2*fu3qc0H&jhU76X+8_1Uv$81iyb8qb~~20wcS{~j3;xZ+}UdIkJ} z`>Y`=@vL-+Y#TUv@kv}+{MoaLD6~5e0&tGvAouR`vuC)@Pd{*rA1U2|i{_SEdd`}5 zmJZ4voI&qF&LH60vu9q^<~EiNYW9|P&Y!6T47{k_sRcM*Q+oivy<h)5<K*Gx{C{8I z<Kh3$Xa2e4>D<U$a#Mi#*|SF;c`0!%cjLV@v`j+j>qknq;LmWF&yghgt-cb8DRU8M zJhx9m)uW~l+bF?jMIm5+nMD7Ckv^MA50x;P(2Us_SCNy8Ls1EVdpR-eK{+z|OWSfP z{G*5KrpIv8>CnND@#5verSR~l;m<9%doCYcU0q>mX|t}9KHynQ<V+*MFXU!Sq;$@$ zBUgb1X~Z?*DEnP6jNC%R(^P##;*d{Vnrc3cagAY)6JUh|fJv2Uh+pG0y<TWBTFbZ~ zKG@q15NRe>*c#skj}+wO<D{InDaM+uPO+BD>*=>ai@S&V+4FJ5MKnFP)~gdul<54x z`DbmbwH^jE;Ke!u9$p@S>9;}hct*vLtOm`zGvXle&UGRPvw(cD1ODN3PNwnUs^PRF zH+muj#Bu+CENOO(9pnab)b_Poc`zQp%*e2VwHV!r*k!Ee;BuuMooGi$%&$r;9dNos zf~Y8uLnSBNu^m@e-3)EO=huO-Q*?v8P5wg9rtGZ?a_ZLbcC;|wtbBh8*sB^ITYuKM z8u8DH;gy7TlRma@t-#r)3W*$@@>m4(B{R)Ajv;9j3PRbPvJtYWSDg_^(QA&OxEXcZ z^0WyQoVEVeq3?fdkk&kIIPw!xn6G0~d~<sKRyMhOu+S3CjqIqCk*II~j!}Bd-EK*l zSO<4mnRqo~KQIDxB0f(loL^-z+p<vfs-usZOXNYRqG(SKZox`Gkv;9mn=KZRS-^Qf z3s>81CoT*YBX1}fQ-?0?y_FXuXPDbf^@B^9noT}HG7|rXlLA(xA`fWQk3j0`n}oMW zw3t>*sG>q7s|KWJ`b7_2%KMJ!7+bk>8kKc5ucCKfyVQSDU21f$rQj!qLf(t}d|x(z zhb)_(*m8xo6S|PMeod%Wm$*E|*kGSL8bo2I6o=(<wPGve-}0fH^1i%Q=Ze_q=1nF< zjrN>^XDwq+9}W>oJJKIkJ?^oN8Zyet|D~bQwLKb-etfDpNF0s%2W54gNVC`PPUCI< zIUk;}4`=-A-&k+JpQ{wL3HA)<Fm}Ao0@95d1h8Jd%-35IelEPKQcS&a2KvAX;i=|= z2C*8LE_4qs`KyweE(8q+w7#t2<`wK82{(h7)t9lD6<^(=t9z5#bANI|WH-@Xu)+4~ zQ+Fv3T*+eofl(C)fy|oy5q(E&aa}lvt+>gE!820Yq}8R>Vy5RJoejAGzhFHTlJ1s` zN)%bh<(hfrADsu8&F)sL<xs0rpKK@mlLmRuqvo!yJxGZ979tV=cNu!wbS0s%*~eTv znV$LyKJcCP8`8U}0!yBdytfc6P^MA#&PRU|ER9LO%p(W{3-~@Y<&WXILKdFb_{Q3k zRLFlKAPuu(w^j?EFHF(83{=sQDPFJ^K&-?^a3MPh_CFiqSw3y~8DWkLI`W&Ix+V?E z>sZtUY6<lA)Ki6d@F$?P<oS!57U710V(25*DaTzI&+me<h|;E{A|gg+=4lJwDEYJp zztwx!%b_Gxu8kvdCIwBbJi7(AdN~`!)D6)&7AYwk<`Sm7k5t6nj+WwElSAiYo6V(T zlmG7Qx%4@db!Cw#Lo>ibMqOo-EJjRC1CJ7@u-*U~y1DNpgqr<XwkxTRdzHhcryGMK zV`I<B1)RSmCzEVVm5@4X7$@8CUL`By@u4qgwp`j&scqe!o~WO<$oBFUC9x(z&!H?h zYr$RCzC6h?sl3om)0}_<B2sRlq_U&IjEns^kssVZwawh{C~Wy8x0!}6y(^*|WSs-8 zP7Rh<Gu>lR_(w+hkfCKseIJgaa85-rX#KA6;#z6@t85v!8z?bT`9~NvSThZD0w*$X zFq#(*v={lX$bCUE0v&vQ81v5B-2-Nab92=5QZ}Ad3w)(kU1(-EjSAR-RjE2;^tUN$ zl<t+%={Bj<mN^U3WUcy5^H0e3Wov1Gr4N}@xm2BDgdbBnNRC;=aaCL@0tts##7gMw zD&Uy&?yN~wR0K4^(we+tS<GXa*smuZaM=<<Qp(tAlz~i&MLyq*ERzr<9wGblOl?Ko z?mvxcoZHS5_&{5=)SLH~_)Q&^<`2}ep~@*d?F<=U>SjaNMUPKg)V>+`xlYLN25f6I z%s8jojD1_!e1YQi--ABWD71HPRtcxn*txVwcP52;f<7eCF5UGME@6GRX&-<^na8{@ zNFGvqr%ojt^z>Lv^QNQ<$^U%v9J!<m^@1x?4!BN>?qrppM{<{=-lpQl>?KR2U5WWy z7h|}Iw2TF3jFWXs-fWAfc9wtW3uy5p<H(3|wW1<W{--REP=odP16YHmN{v{A?RR!} z(+H)=cY=M-_4!%Rlx)taniB1Es+tm4{67}t&u0?L$Cgn9yb_gnsB8!oM(v6=rE?Zl z4q3xnt{ewv*~8Y%Pku}cvh&643tm4zO(Av`4Z{_0p{z?48F2>Y(ap7NOGG{bIu?ce z3;)TRkKbo6$NRz}M~Wn6H(Ap*_F0{TKi@$aan|1EA(4OT_;(&Hjam=dE&?40`2@P+ zs;z|rjG#0pQW$y{<*;K-F9$cZDnE?G$;pDnwre_`aSA+jqJ8Hb@PS9?Xtn>{j4k70 zr8!;nX)^}&9vxEIq9u`Wz=k#CBCegPyu+4Q%$4Ee3t`@<Lqp}b!^hG_8NcHz+{Q*g zZ3gBTdDK%Cgrt<#dEtC}jp1+NnOP>$Qi>cz$)cb=c^VtBa&SBs0VzX-PU&)^`)uPN zaz8kRkYG{UfzMWnxkajcxxkhPhu)lwAd@f!RqzTq5w(?2NZqmeDh{29V^pw8Ob?v~ zIPSg&O;%zX=d)m4f?N>rJq^CC4u*mo&isf+u*Zk#qF1QTYbWbJZ>||&O7mN|m-izG zsjW*e$si0zzY%x=w#&tCwQ!Fc#njufvzlMI)BBJFUUG?T<G9XG{cPOtdO4`D=Nj3t zWJ+vMC|K{*kYS#r@uD%k7*gn<PvEjMqplJmgL`QpKmSYGTQC2AW)<zR{6^jHXkyyW zHvDYNmZ6HcTieUvsJCmieB(}r*h8OY<FpNNQDhZrfco=URx`kCzFhPg;tld^v&Y`A z=%E+^O@sW)x?n6rn6J4awz$K5fF7Y9Hx&iB!X`IR_yLx>JVl^5VGNS(>}4lRmN{B( z#S=og=CKNIX-bR=>&2H{xRbbMG)TLnLyQGViM1|rP^@2ORN{-}&IkHbXTrDY$I54@ z$Nu=R0Y@0&YfOBK|5w@k81wIY+0oC?1qb`tnLug8T%7ubEc}%XN*{-~b8(SlOQ^)s zJ?aJ%b!nOA-Zgrx&e0-iD`zmfB`8qThZMiksRy&~x+wm!5Y*On?38VVza^x}jasov zgFfu44aIhQ6mYCHSD5Cox)Elj4?hZtux9?aSy;q?`UxSFw9JMwkzwL$mjppm2>PY5 zYpIANu<rO(cDH{BDP`*_F1~20YEq;keqMTF>SmA%n8R!q5=3MW3UW&&$X4oXiujN( z0DH&&BHuw8&W*+O(1PrrTe&G5SMYc#q<{)i0I%dTMC*BW&SRF+#ZW0iGY>>n_|6g} zd6rrl+zv7KF`GAHEWB8$lRWwmgpTO5KL$yx5L{^FC}l5ypQy*Fc8HWP;LC6+53g4? zs68^+qKK2Y?ulbhy(K0E<~F~*-il;5hyA-Zw!v)L+9P?t^gYp`xi~h`0VSajf%=j# z=a@PM<&~P6@2!J(a<sxvP-itp$}k2wm@HJBzl#p#YUU#z9or2r-*`;E98*Ct=6?}R zgyf7vA#3o|&v!IEe%o`k>@{R0F{gu6;I`SDkN(BtK2!u5bU9<0w{@u|81;~@eC~-7 zcx8q&5^Ygs8u1=Y?T#r`3C=($W2vnD&6WtYA?LzNR=zre1rEJ8S6>w}qmJchcs9l7 zPsL4O{k%+rml^}?d_kgO6_2O+2_HB2$%IW1nf|sM3SsU`&+9HN>ffIfu$Vs~v$rMz zGwS+9E9mRGdm_ZDFkziPVLi}db}%=iFOp!Sq@nU@OtD;b5b7NHF3xNbFD9;j$n_sv z874GTH4Gw)@H-V0M>h_;VlsYAwI5*IaUtg}dhqJBe3|nly^)uQ9hR%k5%?C}ahhRb z6&nc{G(kD)Kv8J6P%~0`WDWH!n6cn#g+)O^BFwH9?A_M8S;7z(eASy!TF;REXPReP ziyhTg@qlU?9j~NW+;rVpvq3ZHp9^BK^Te%d<lBby^zhtC&7aY(0LAvVD^0j}hN=P= z%qU@XyJ&d5-}BT%8hqI&5+rx0%M#7o`B;N7e+cvvqoSMQ(h~G?&=Op5ePK|kSNjI6 z=L1XPot8|2bZ;t=^XMrW`vY<p8(R$zg751{P>0%8F*~$M<J)a3*B5(zyV(t&3}i}y zH?~+!_ItB=#iz|wK_CUZ9WxY@=VI0O!bzRg?4kXi=8^2>s2!t8g5QsEh1SvHq+HR) zh-$=8kR{rTC977PV=qpdg?kvppdxKX+w?KBh5iF)f~7j5o%^X?KtEVNO{ZpjrmS1b z=k^arZG}6N8et;^3`JLlvoe-#=MxE<4P{nTmKa%&V*P&@vu?X+KhM+N9G_{jpIsZb zWURnNW!H(U`)WG^rBjjmb_aWn0nToypF^)sbfI?C?2CPhp#6GCKnIq1K8~<Q)13tK zQ?X#hO9uQ)k}_A7+^=)5^7Br;vmwj{jnt`Ae)fia>pxBkY8tvN`ExhWbf&<}>ddF1 zT(^23SG}(j@@-YZsc(i-PlY3Y!X!&VCcDlI>6A`$zO;J9`kV@&))C66PI469MiE3N z?czC(6S%4NaEE!`FS@SAmv}b((6X1$=?Py^bialKiNBBxpfP}&hUwyG2bnPZ9WTd% z6!a$2=Z>u)141)vkEVhydk3>{3Gj6<yAV&vV95R_YhtD4Z;~@dyM@P$GT;>oEC~$X zIDmjb@py$p>UQz!YUConS6I*$UA@35ULR@K9AFK$!FFUOJ$jb+vTPvs!eP!2L8e}f zr$;JOCcUq;lj%IShcas>47v3~dzA+DY!s8`iOXqs75R}YS2cY{g0#}LA1k^mWSbhm zGkq9fF$LDJ@@z&n`FS%bZ{)(5&Sn+;g9O}AMe6^8+urf1DAo)26=x`uiH$O~@OKRr zJo5hmFTu1OAZnHVtP3Y0E_Vk`k@tH3N~_4%6S^gd3ccYm2-g-@9}!<tFvi;FT)$yg z>fe#+p9KowS|(t^Q*29_7<j+KEQ6P+Xfp6Qm1XJ1@6CueEO|}B-I>O53|P79=3eEj z+r)+J1Z(g4<;y0r4H;~Pq>{<^VvDxof9sVIZEd<UV}AGD1hxBpPC@8XHK3iKeV7qe z2Uy0|WHssDpJpWI!}+eO<<I$5?Y!2FS~`kRpd_akCTlk~rys9|KRx=pkn-}eyKo~p zQ!%r_zno-6UkQr=co0IFtg!++?+p`M35!J7h?ggi!YxDg4P>YPYPq^)pNDZ@TN}y1 z!mY3&upJ+3uI?57M{UdUudaE_KOzToUTRT7zlj7IX=}EeX`t7Z%8})@BZk#NAc4}# zNWTDzq@CwTI&r@$Y=h;<K3CoFXB(jl5w#THH<>~HTHFSV2aqvS_<aE3*c^u;Dc1&e zL_jcWMh>*-D!*RjK?G(bj;F@`^5-P_Wfu@xivY&9^B}LSNK>JY8Hmuo6PGXf>O?^E zWCWp-EM)ADTxyupPrf)sw4z^qvIyT4l1{K-zh|pl6qm46f-2}rc&U}<zMPt{O?<$q zVOFrN&Hg4VIO!a;qjJzsuC%QoQ(LD5*Z#Rx-zS4HgVvErdF9dpclwO>02Kfp)Q<Ah zWKOxi<1{@T41WPsD~kQzcd>5rnnFEkKT$Usz%Ks_p~we76ZBwYe?H8ZZl*}8d^rWb zwMn7%%m`SUvuJ7CFGg8gPr;|mHP5olkqB5hM%JPJt=qm0ikPY#mGHB)e!B$9zKht& zuS|QwutAjV;7Hc+REMzkH6jU1F&i)-&4^~0js<ZFJs&zQAK`P}8)@I3CaRUbPbES_ z_xBWWzYhF6Tqp$&faW3hS7B-2#WB7_W)}@}wTW5>%WmmwvsT59cOX|{8IS)Mdu|Z4 zOj_j=0^L;{JDp9WiD7KfPbKRAi*j`;SDJ4&Z0AxBBo~Mp|A-^0cklM&<nJe?V=cKJ zd5Z728FAi=;K#Jri;jW~(_fiPGS+1cPBC_3sLr3GaHp+)X(VcQ;6n8|t~lOa><Eq8 z*tHrmsWL7O>wTHJ(0dg+`;zW#8zR%rE^Ncm^%nKN%*kil@&tvfCqc@cGCZ8Cx+=tS z{X0cT54Q^VzhmbA4@W|;Xr+JJV|st+!y3augZuc)2~M>R92<3~8{$CpTu8kCD^~`d zF;RdMf7EzfFpvG*j<dn?gWUV?Rfb=F)SzsN(q}BWh1PJ@!x%aa2{^a&f0-kk?fuaP zfCvZMj1iXzSJ#x3dW&jYXNk-Nk~_2f{3)&DbX<a0+50h?&{b+#vo^<GdSJweGZo01 zYsQYp6slhbIq{R5{9g?PC)k}exP|9Rzqwmc`)NY>5O;m*;|c2@PvLAZ+vp4)A4<VC z^N=c=owx^oF}Qq#{<ZPZRGEhQN0;OG$S;8EhU)D_57SAzt2EkRQD$nDR;T`b34i)k z#I(j?Dk{^mZ5LcMTJ>d_>d5_LA7%6qy=dvm-1^n(ulhU${mvTODVitU?e9qW4-#n> zx;P0hlKP&ZQ@+k9qO_->y)UHJ>0nNWlfl0YZ{W4en|tIX2|NboD=$-n%G*r*M$E3n zrlVUjJ-b)#f&n?e5<1_9`)!M`q1O?1D`|H`RPYX+^gS#jRF#N8DpR8bc0<p!<MVqa z84G*p`i|Qd!WKSR;y*2B%J52e&tYBWVXy$q*-%T`2H#DUwZ-w&ksw1fl=IUq&sCl* z@x)cn*N(53lI~dHo39odYxs^)>FvNuJ#SI#3@W^2SFyP%q~@;*k3;aDB)Co$tPl4V z*HGa`EkFQtSWAhq=YOA)nRK=OJl%9%>?L_jjQ?=(8P0lAKy&62)<A?oty~mnCAx-` zB;OY2GFZmoxv#0YBJ~{wIdd##xfvr2Mhqg(2e-k5w6g~aA%$Od!ukg6x2xtO=^Twz zRu<ocuF27og?7?~Isok;cRjr|b<BS?CY*wB@BT%GNx(K-V3aaX5iod`<$8Gl=o;!k ztNb%Tvbhx~gKsezR5i&mXUWYRBm~~xu~Ea&97elfefq61hS!VEJ1w5nNY|jYYCrVL zB|Fike4OZ?D||DS6>ay$g)OlrYoug$d`7Tdb~C?TRS6V!m}{HO@=yD$KpBjJX|ew3 zvFlGcas`p(SrU5v7YS;-?*d<pQ%12YuM=s6zRF<oo;XD~K0yN(e>hG=FEzxB&Oeb- zhqG+yGV~~Cle?qb1!rj0ZZk|a5yIR<90cn4A`E9LE$W?td?<Z<D<z(Ez}``~ef>4* zbt#>DmSg-uxN=ylptA|x+-L8KS@gAH5+rW0`p7Dgt6;u!<nsfay~R;JV1ei;j1`hL z1h2)rX<|hgjgvLN_f_W}0hNkbeAFN17+V4o%dCj+R_x&qF#U6^{)HWd+o8j3M|32H zWUaFJya2mJ``TErDnSxdxSjPxRG#$R|64YRK~>EPopjo2qf{OUrK2~i|AO?3tPPJV zqz*wrq#VVKNsWG%v20Va1$Cgt88aAe*v%6!xYy*toS1aX{r<xr#2IazYQ_%7e2yiz zpq+*(g(wg)Jw^OXOrd7M&nYP%TF1GR&Spj2OPKt;I2~?e++Bj)|01+Zy=I}gNVq)8 zM<N6nMun_P{23o&lj~@K586mtk;MpnI#F)2$HX87mz<Tf-x6?J{?_F_{TRxVHd3&u zi6h$OFqXpJkU@B~mJ3G{^h5J9?F@5-D|=e))>7;2ycsOo^*tGXJpRP%J1S0C58CAp z?ivG%oi1;(U5;g^vaW)OFEBAIm2UB7fpt~g{js<wseMWV84oLz3?4Axt7?h(tH-N7 zym~?!e>n;vWj1l|5+KcnzG}s9YgstXG6T@YW;?a_ZIA)}I@VpcSQMMlwII+BXb}@; z4N{U*!+h>!f^TiJFVd&kN$(C?J4|oxu@MXnq-e|-e?dVv_t|DAljlk>+U#{d{BfM9 z2#BXZvBC@1U=qY{B8ZBU99ze-5fT$eyZ`8BK0WZ>1frB~yO*rgoidzv`*V$WzkA$q zYFZ%batBuj4*JdJiOB@y^Tui&^Tjvhl%yOtNkV|cUj)#Q{9=+QxnuPUN_H}oJlTQ$ zCH<sZZ9wjLq+QW`jcd=3PpEW9%d`fP6WHr|{?>v23xZ}vs0K$q)x11V3WYX9NCxGz z_xatd<@FWnDxf3_sb<diNwkckw?|rI6JvWK7V|Y2Bq=FtTJ$JKf|4`Ulu!<(mNwWM zy=4>a(O%0U;zZhmLmP?&gnLBAm9GZ4wWt82hz5uUCO@u!RVN)vACvGHE)gx|hu@nK z5h{w*dsgFwBA<TA)Bcxw<PQBX!#+)s3=Xp6&-Irl>OMl@qOUuM)lg28A4d*i9)Hsb zWe=eCQ3xs&3BrSh7oI97+jHm!kaNJz-{JiPbW^<MZjo=eH7yZlAuEjQ3`S4XBl=;e z(Ek9S9>Y@>9#1AulIacg)hf;{OHT?5gD(;GW?lbkxck5Kbl~8G%i-wnTmS@By+sZF zZveW`0b3Io;DhL7l=E&Qs9zr@*UmjY`{cB(uZ>|8z=;lBBi(!XtkL8TJ<C-^HFd&a z0PNllUuhaoVu9W4#1bf4<zXTRR(9?OAFYek0HjNr%~;$U=TFzjv^C_Mo%|wo2H(;l z07C`zEs@jksE9+Kx3dvQ-LmH{lTjJ+Y4&zZTgTZ~xW+yrV^BoRrfh8Bt&el4gVA)9 za?O2ckclLrm}kwS0cJ}+0}ijzYPalyZ<7OU+`p#G7(jVcsYNX5bo#TzbxjPvYqi6x zVaDmd-dakK-AU9GVUBgblA<YDx8;9N)q46Y<<n|yNR5s4TuDgw;xkSq+_>#~dQIx9 z`=$22ESZ8`>e^fCZVGUC>nEazA#5l|7aYs|u{g79e*l(tv)l>=ZRqV5Ekz5RqhP!o zA3!~DD?(MNuW9JE+Z}tcy5#VFqCXnmroREG=Myja?|8@!1!(fg)VrGW-*dJ0Zu!yC z_8R(&xpnB-x9V}Pf9qnvOh+-MIj(t<?P-)wo6svJCCmlr8>m!ntVCAUiS&<^3Eto+ z<k;tQQE-sE;Q2;U*L};tZOBmNu<*%emjqt>8Xv7L-aHQWANam}D=CA3za)5XNfXxs z8N*&n+!;y80!uuV!mn4YS|zNK)BI1O7eILOtbCkpVC~l;>cebCS#Grl<*{`-rv2ki z9@q3HrjJ*`0&au3_Ih+<Z!%0<tGv_9hCiL4J+yQn6=c}`LEaUG#a$N)QV>qs;OKsP z;tYLQ5XeU~)=-E6v01R>y9}-Yp3az-uo1LupRh(6=@_+1n_gMZLVwmOL9K-j)39J$ zLu}Ma2-l2Qqei@vY%86nH~QNf{ENb{;aKdm(bP>vr}-bHUH$#K+T?z}_hhYlF7~qw zlraDxH)(loSBW82dQjMFqYlkU!T5i=E|Y58%atO^r~V0Q+PtJq7pmP=8s!O+pi$r4 zgt4!yIvU$lMds>Tce<D!A$CrRX<TGs9J8tz_NT5k(p7;l%ui<Rm&!^NODPu}%RcA} z_aXr0SgEo{IP7&T-QUo{2Hug}P}EKM!?a9@Cd1YU+aIr1!Jm|s9<iO=G<$?fqN6c& zPIS15QUIoWLKAVChB2A*V>H6Yy^DxCKK54g$=f>PL9}DJKZh2C$PyW8WAl#ziekwy z#T)EO;TZx5TYY@u`iw_yMH@&D7SIniaU=H<{<pg7-snU%-`*5aWPq82ext<a*#i#C zCR#<Jn50rmDY3rMc*y>-G+omjUl<C$w4?W?GNFHzX<qEkCMnJv6X=(^Pm=C~yfb0H z?+Mkt3W{nPVJoX-c62vS&K>f}lK@KaUuD#k|7VNP6UM+9Fh~>7;lm;pbc6VXMUr=M z*%XDb#?SH0^g%QX6<-E{#t>`hJM3L-7HS5I)_QKJ?hu()v=@WBoPBW-3`xseA-E;F z;zY4!LGZq-e8Splb-82U*qvd`5r8-`SCM7etD1<sc8tP0pztrSB8~}DoxhU?=EzEE zB54Lk*f5c^G@~(Or-xN8=anB_M|24YU>fN1UH-_8zCW)H4Bs&gonNRV{+^Lk;Li;v zd0;$#wGzZ&=ZOtSW)8N|WK`y(3L3{uE@s}Jx4uyNw7%EG!1Cl*`|VEa5fdkQlPHVH zoMxW2(R%V*G!HMB(9wTx$^fT&)awO3UDafY7Cm|AHO_7oV+@Qj+s=Frbw--Sb+V7c zHuTMP=)%XM&M+Sv<u&J*%nS-Kj2$_~s#<`|sjy-d_fNA}{!SyEpE{N^A8CtwEbmut zDFM@3taGVMjZsRD(>7M7C1aWmn&8W&D<et<XlI8~E>=iy?P%fFuGckW1+ItW{*`nS zeqx38uUDc!mkn4Tqg9L~@8!+@h$M?dfk|1p>U6olGvccaQ6o@nBTK;J2i)0F4x#r+ z3F_Rie6!@J{9ziH3|a&-Xh{r^HkQ|W)c35iYZ?$6bSB?3S2NBkDG;tD#&CW-JMHOb z&wXkT@4vl_7H}Hq0#2V=$rv^PxLj|c2ybtq{w+Amz-?=>9&N%I;;f&WAb4d<|C2a7 zxcKK!Tj}kXE`1V(?@>nnJ~iu~EoQ3Vc<dHdoZm*A9$ltW-c<X6wa-7?WqMI+L+9~E zHGsAeZu$5gl)0W`C;2)phii+SEE)WV0CIrGv&qX8lm?cH3NI;xw0xr^wm15#TtKWq zqpLXdY{-EI+9b7KT??3hc%~|i982BB84sOnqF0v6;VSrJSk)b;SJpI;c)IM<AIP(G zaeYc4*l~46gAXLtCb!92C{p+czptqMWF?mrAOPA$LR15Wz6Rj-PTa>rx&sOp5`C|P zi{r-G)w*QJocK3X|8$TeF#l9ca|%J~%8Uz3Ir%NT9^)Gm>Ti3!DGg){#)H{gP=+`_ z%cN}iNu8{ZN$=atp0%n<v4$O$3^`?M_Cy{9+6l@7&@<n;-R?(u45b0COPtZrY)mIN zZ|H3|ZRwq3hj^<b-v1?S#ZGwJd62{QY)ujB=4cd>4sr76*qmq)ujR)7Z5rzm1NNBY zJK)cZ$Vzqw(9H~Yuro|%JmmCa5V6e!p|=M+W&B-X81LH|4Q4r%vq?Oq%N)PCa!&7e zKq>&XWZZEOIyNkWhH#*|r{=jR5{L%lddrlLP#PbAYur*oMGuoXjrcwK6<&sT-00H9 zWz0m=;7_f6#<o><QQkWhRx(fb=6}`BblsY1n8aV19E*@4Tki>i0u03jiSmt(jus!Q zP5B!HN-;AZ3{OGf{iWL1uG@=}Ps}_IBcb2DH3~-O<O{8b(RFMaU()bgEvN>=P2-BA z)?XUlb@;c0_3BPTVG1{{TCm(RL+Nwvv$H&B20)S|$3e%z)Xgys`}DVSxMQoYe&yR` zIu6Os-()iTMar(s)FMt2%(wkDY2_uN%OeOnS|N#4Sk$SrN1o~7RT-P0{@3mO+8Fg2 zJn`hQU7c~^xc%2;15oF<PRRLS)_vJ8YkvF}>Ce`mrHABUrVG{NZquUS9aL#xI*OqZ zgy%Y$@aK9~oM1lab&7zG&1-BiT6#^x<R?;mg5>?cguZjhDXG?|HLsbwto!YRch`sk z*y-WN9tyI~Rv~9zi+eA(vPd6#drHgZ_`mQbqvNPAtmgb|M1H4MtiFo@U5~TMv7d0$ zOA0^mSKp_9wQkxD^`TBH{xgLB1W9?nX=I^%h#gFY+izARi#<cNi(#;kFHA;+DX70V zKLZ#heh48jvHtHn+!K&|9Nvt&YZ^J*(ZtIW+qi^F4MWUUoV?o|R|}DBJEGBlBn+Hq zZjXTX#-T;+tfSB9;LB{>g2xtJx<e`pF>6QxSPZWngqfL)vJokJ`!5sq^f>$vK@~2) z!tRno{Kw7z_Ohwec}H&<oKo13ji=?jx0Tv>Md<P;wyZ@q?Q`l&`qxQ4_l#%Y3q|O3 z{O?Qf9;$Qr9xndjeg$3OwvW=JQa^DQQOs8#6YLtF2^c{gp`G&oXy8_!vT$xuy~WI5 zpXz0Gw8h)CA+w=>wwMAdj1siFJ6D0Q8r81OjqZ7;p7Vq|0k-LLEN;@ZR(zb9u(DRX z^V&WOACo#Vs${03gEZqS*SnUu_o%+aou!=*mE5T6mt~UMUr7*L?iuIW^NuYF0h4ao zVmCK?T}`jkQ6)}d{YNg;=yjnf+lTUUIkcKUo#YO(_+KIZ6B@yh(i%j{VCd~>cg<{A zNT|wu%DbRY_{Wco<VX6_C827^w{DitS%S(H`GY`7HHfYlVU(U_dls-5#?aeVS|2E_ zBkA`9r0>1Cvba6ck)2;wV<@k#KIR0Q_t)5#JMJc^!E{uVlQ*b@v%e2iM5rbYHEK`+ z2-!H8a<7U^ftn@=E~>I*ImeLK{Hpk7ME`R91tOZiZB9TUrL6QXX$>XapYgoca=6?u zo+S|*MExlllm&MBq!v37H!7G+PIj67Ne(lhX(((foZ138GUX*h13Xga+D}=35eO0Q zHxW}thnJ-LBa8Q@toa~K9Lhh-*9AJJUjMR@`?K?Zsfhc1+nc0+h>3m2wMw*&c7VNS zcGNn3OS7@kjq~BQA$(CP!wmaBPOE0A>C10enzj5e>IFCga)FOSNE3`#Mxr)tdB-+d ze^<pkOqDn<K^G!07tg6VK9~C=ohojd*{mi-4Q|QF?Crb1w(3)hm^fk}h~i6H!IRm( zf-uuJ9*=27@j@2yVk?{cNJTkmo^cDW<c0$&kPwo{Fii4Pdyv^KFF1WU)gI@f%)gO0 zub8z<0gL+J=0#~>z1$=tEdd36iXLn5MdL~K1O>tX?YdZzH2iSClbq*kXT`J=ex$wC z=ma!L{#@@=;-x|S8fw(jDP?}_%kF4UcE@F>5+~C|H4&xKilqFFu{sq?c%fMch&afx z{Xnc@&T<dJ6pB<VAKh8a9GV0u4pRR{H%@Mw=f`qVS2Vx9d0|j!&O&`hj}x8D^<OlR zhtA}(QblG}dl*l2Fk;Pd&&A&j&Ecg$^v)wn=(bgUrc7!&*kcck^?jfjFlrv!ztwop z3@!}k?u3{i)7jjc3M2ZQuf{HoFxOL8oRinBH@tJma0Wm`I&y~d3qT1csp!4*e5gG~ z%Ssw9`@w~#vP0*Vj!il(^xWijG9xdMEUq<l=`>S&{8?b|5n5TPJOJ{}hlMU>>T>O? z-!As~E@5ffec44{?qG918l;UidtGZ|9iVJbE6{(lE=m2nHvcj3X!_8bz%|hh(?F*~ zwX_arLoTtGa%Cj^j+*@IzqZ;D%OQ5P5K97}ftVv1zb*F*`Pu6cD=Z4wD#7EPp}?c; z%`->3<FPClxRgJ?_0`_K4u{;Fzk$fWO?NaR0KPmg*^{&C90`A5`~o`4_*5DZ*OJ{V zr843#6a!d18-TI#KUVy>BT7#9T~;6i#7wuFw8q9U-Fk*v2X9waRaa9e2S^)XI{p(K z{0~e0_Jc28a>&{#4ix=L87)4IIrG<NRpOCDj=H@@&7~-q@XHqZd~+Gea<MFQT}C<^ zZx?|;gK4g8>7HYzx_W)ARh0(x^ahJ2L8`z)glgM|+GEQ`58eAOxn$$lOYx86?jlJY zs`$)zHy1x^*r7$iM8fRS<&Vb)X^ngfkFSiczayX6@`Hb;FA_+~of~tU@bM3=5eR#E zTthT?SmOSZ<V;B{V~+nEr~!D|du?8fd!D7%+T3S*W0Ra@J(f4eQBXF)bB6|%4%=T9 zz_CtJv(lOV;^Fq1erA3Knf2tWNH&XzFICsAuOVe9L@srg(JpW*@>hJ_GT=M2Q#c87 zBHiRuDBwfw8s;63hi6sz2Ky+fg*lYuw4}2ihNL+3ob|HFD8h(hI*%jJ5RkaTeni?6 zLsu1cezLEAD7JbKb1-m>k3?G(z1Y!bIbg6(J1m}k#k-2l<jZ&*o~RoCrBh5fim@;& z<QKuXBWO(8ONh<lD!;DeDfw9CA{T?YHGXJub)8oLRda;;RS#I~EZ!k@>YT!*lQr-! zyLGQiFb_GqiLeFFFqg*0#Zb-kFuhdy)6$GY=62?`6kVj-j)irNdsZ~Ixp~8rtO^w( z>2ly;qNdBaes-D2ZZUTwa<=VAaLTZe#|SAayLsP`fdxIJpG|6c4TMxasGz<uH=Kr+ zH>UmBA?ZOKJs*lBHwi@XLf{T8{&IhlvGpzV6`>)JqO7sXL*MWqcuEuyuGMO@e2_w4 zO9}@nJ&)?Qs#P2Bv^6ses9-29OXaToP-lGhTEsYYSN+g#Ar0w8oQd8$;AkemU<sY_ zZRy?4M=@}&Nf@j5r!=0MW<}PQ&|bL9^e(je^~&O<xA3G5wqm!2=R+nlruZ<!-Nbuw zHSjr?+8|=Zdl_X(>?%@ims9_aB1o?vw&I5gdt^UX0_|gu<WfHNOOF&mm`w8kR)v(z zeb6fl(VG_S@$J_Kbgi!r9s%Pvrl={aOHFwra7HrH6T?T1@4S4M@C9p5SwS)-m#%iK zhxnZCWPg$~?v5^j&V_mxT|{w9#71nNad7+DX=HTz%hxZ?zUI$aWF0MJ$PKva4>pxR zxNB+@7|Kfn4lW;e-W@ekDhF=MVm+^RW0_BAFnaRe{o6+(fP0F>ufNAVsjgjgwEfcr zrx}T=TRvIscZwV9a~7QK9HuPU6lskDl(@qT`z@Ztd%7&-l+3$G?eP*!9w%8^P1}Fd zhFKZ*#y(V9tp_{PbAY@qe6|~(XoB3e%bpFS8#m#>l?08v9f<^hk}SY#a14dcJpWAy zP@t)Do=qwi;3zJ3�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 literal 0 HcmV?d00001 diff --git a/docs/getting-started/logging-in.md b/docs/getting-started/logging-in.md index fef8907e07..5386e98798 100644 --- a/docs/getting-started/logging-in.md +++ b/docs/getting-started/logging-in.md @@ -20,6 +20,8 @@ Run your Backstage app with `yarn dev`. Navigate to `http://localhost:3000`. If you're not already logged in, you should see a login screen like this, +![Screenshot of the the login screen](../assets/getting-started/login-screen.png) + To login, you should choose the "Github" provider and click the "Sign in" button. This will redirect you to a Github OAuth page. Verify that the scopes mentioned on that page match the setup you did in [the authentication tutorial](./config/authentication.md). Once you click "Confirm", you will be brought back to the Backstage interface and signed in! If you are already logged in, you will be automatically brought to your Backstage instance. From 708294012180f435dd61c87a827b752b6f3fb974 Mon Sep 17 00:00:00 2001 From: MT Lewis <mtlewis@users.noreply.github.com> Date: Wed, 17 Jul 2024 18:01:01 +0100 Subject: [PATCH 328/416] cli: add support for frontend-dynamic-container role in yarn start Signed-off-by: MT Lewis <mtlewis@users.noreply.github.com> --- .../cli/src/commands/build/buildFrontend.ts | 27 +----------- packages/cli/src/commands/start/command.ts | 8 ++++ .../cli/src/commands/start/startFrontend.ts | 11 ++++- packages/cli/src/lib/bundler/index.ts | 1 + .../cli/src/lib/bundler/moduleFederation.ts | 44 +++++++++++++++++++ packages/cli/src/lib/bundler/types.ts | 1 + 6 files changed, 65 insertions(+), 27 deletions(-) create mode 100644 packages/cli/src/lib/bundler/moduleFederation.ts diff --git a/packages/cli/src/commands/build/buildFrontend.ts b/packages/cli/src/commands/build/buildFrontend.ts index 62da74e6d3..f29e0bdd38 100644 --- a/packages/cli/src/commands/build/buildFrontend.ts +++ b/packages/cli/src/commands/build/buildFrontend.ts @@ -16,11 +16,9 @@ import fs from 'fs-extra'; import { resolve as resolvePath } from 'path'; -import { buildBundle } from '../../lib/bundler'; +import { buildBundle, getModuleFederationOptions } from '../../lib/bundler'; import { getEnvironmentParallelism } from '../../lib/parallel'; import { loadCliConfig } from '../../lib/config'; -import chalk from 'chalk'; -import { BuildOptions } from '../../lib/bundler/types'; interface BuildAppOptions { targetDir: string; @@ -29,29 +27,6 @@ interface BuildAppOptions { isModuleFederationRemote?: true; } -function getModuleFederationOptions( - name: string, - isRemote?: boolean, -): BuildOptions['moduleFederation'] { - if (!isRemote && !process.env.EXPERIMENTAL_MODULE_FEDERATION) { - return undefined; - } - - console.log( - chalk.yellow( - `⚠️ WARNING: Module federation is experimental and will receive immediate breaking changes in the future.`, - ), - ); - - return { - mode: isRemote ? 'remote' : 'host', - // The default output mode requires the name to be a usable as a code - // symbol, there might be better options here but for now we need to - // sanitize the name. - name: name.replaceAll('@', '').replaceAll('/', '__').replaceAll('-', '_'), - }; -} - export async function buildFrontend(options: BuildAppOptions) { const { targetDir, writeStats, configPaths } = options; const { name } = await fs.readJson(resolvePath(targetDir, 'package.json')); diff --git a/packages/cli/src/commands/start/command.ts b/packages/cli/src/commands/start/command.ts index 2f2af95d85..aa46b717bb 100644 --- a/packages/cli/src/commands/start/command.ts +++ b/packages/cli/src/commands/start/command.ts @@ -15,6 +15,7 @@ */ import { OptionValues } from 'commander'; +import { PackageRole } from '@backstage/cli-node'; import { findRoleFromCommand } from '../../lib/role'; import { startBackend, startBackendPlugin } from './startBackend'; import { startFrontend } from './startFrontend'; @@ -47,6 +48,13 @@ export async function command(opts: OptionValues): Promise<void> { case 'frontend-plugin': case 'frontend-plugin-module': return startFrontend({ entry: 'dev/index', ...options }); + case 'frontend-dynamic-container' as PackageRole: // experimental + return startFrontend({ + entry: 'src/index', + ...options, + skipOpenBrowser: true, + isModuleFederationRemote: true, + }); default: throw new Error( `Start command is not supported for package role '${role}'`, diff --git a/packages/cli/src/commands/start/startFrontend.ts b/packages/cli/src/commands/start/startFrontend.ts index a809473788..627da1bd1a 100644 --- a/packages/cli/src/commands/start/startFrontend.ts +++ b/packages/cli/src/commands/start/startFrontend.ts @@ -14,7 +14,9 @@ * limitations under the License. */ -import { serveBundle } from '../../lib/bundler'; +import { readJson } from 'fs-extra'; +import { getModuleFederationOptions, serveBundle } from '../../lib/bundler'; +import { paths } from '../../lib/paths'; interface StartAppOptions { verifyVersions?: boolean; @@ -22,14 +24,21 @@ interface StartAppOptions { checksEnabled: boolean; configPaths: string[]; + isModuleFederationRemote?: boolean; } export async function startFrontend(options: StartAppOptions) { + const { name } = await readJson(paths.resolveTarget('package.json')); + const waitForExit = await serveBundle({ entry: options.entry, checksEnabled: options.checksEnabled, configPaths: options.configPaths, verifyVersions: options.verifyVersions, + moduleFederation: getModuleFederationOptions( + name, + options.isModuleFederationRemote, + ), }); await waitForExit(); diff --git a/packages/cli/src/lib/bundler/index.ts b/packages/cli/src/lib/bundler/index.ts index a3b584efc4..2219784dc9 100644 --- a/packages/cli/src/lib/bundler/index.ts +++ b/packages/cli/src/lib/bundler/index.ts @@ -16,4 +16,5 @@ export { serveBackend } from './backend'; export { buildBundle } from './bundle'; +export { getModuleFederationOptions } from './moduleFederation'; export { serveBundle } from './server'; diff --git a/packages/cli/src/lib/bundler/moduleFederation.ts b/packages/cli/src/lib/bundler/moduleFederation.ts new file mode 100644 index 0000000000..ae3f9ab048 --- /dev/null +++ b/packages/cli/src/lib/bundler/moduleFederation.ts @@ -0,0 +1,44 @@ +/* + * Copyright 2024 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 { ModuleFederationOptions } from './types'; + +export function getModuleFederationOptions( + name: string, + isModuleFederationRemote?: boolean, +): ModuleFederationOptions | undefined { + if ( + !isModuleFederationRemote && + !process.env.EXPERIMENTAL_MODULE_FEDERATION + ) { + return undefined; + } + + console.log( + chalk.yellow( + `⚠️ WARNING: Module federation is experimental and will receive immediate breaking changes in the future.`, + ), + ); + + return { + mode: isModuleFederationRemote ? 'remote' : 'host', + // The default output mode requires the name to be a usable as a code + // symbol, there might be better options here but for now we need to + // sanitize the name. + name: name.replaceAll('@', '').replaceAll('/', '__').replaceAll('-', '_'), + }; +} diff --git a/packages/cli/src/lib/bundler/types.ts b/packages/cli/src/lib/bundler/types.ts index 7291ac0818..60c59f757b 100644 --- a/packages/cli/src/lib/bundler/types.ts +++ b/packages/cli/src/lib/bundler/types.ts @@ -43,6 +43,7 @@ export type ServeOptions = BundlingPathsOptions & { checksEnabled: boolean; configPaths: string[]; verifyVersions?: boolean; + moduleFederation?: ModuleFederationOptions; }; export type BuildOptions = BundlingPathsOptions & { From 94ab20ebfa48ae8197be8180dfa86b7ee4ea6bfa Mon Sep 17 00:00:00 2001 From: MT Lewis <mtlewis@users.noreply.github.com> Date: Wed, 17 Jul 2024 18:04:36 +0100 Subject: [PATCH 329/416] cli: skip opening browser when serving bundle for packages with frontend-dynamic-container role Signed-off-by: MT Lewis <mtlewis@users.noreply.github.com> --- packages/cli/src/commands/start/startFrontend.ts | 2 ++ packages/cli/src/lib/bundler/server.ts | 5 ++++- packages/cli/src/lib/bundler/types.ts | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/cli/src/commands/start/startFrontend.ts b/packages/cli/src/commands/start/startFrontend.ts index 627da1bd1a..20faf4a9ff 100644 --- a/packages/cli/src/commands/start/startFrontend.ts +++ b/packages/cli/src/commands/start/startFrontend.ts @@ -24,6 +24,7 @@ interface StartAppOptions { checksEnabled: boolean; configPaths: string[]; + skipOpenBrowser?: boolean; isModuleFederationRemote?: boolean; } @@ -35,6 +36,7 @@ export async function startFrontend(options: StartAppOptions) { checksEnabled: options.checksEnabled, configPaths: options.configPaths, verifyVersions: options.verifyVersions, + skipOpenBrowser: options.skipOpenBrowser, moduleFederation: getModuleFederationOptions( name, options.isModuleFederationRemote, diff --git a/packages/cli/src/lib/bundler/server.ts b/packages/cli/src/lib/bundler/server.ts index 1da15cd37e..cf35f65518 100644 --- a/packages/cli/src/lib/bundler/server.ts +++ b/packages/cli/src/lib/bundler/server.ts @@ -162,6 +162,7 @@ DEPRECATION WARNING: React Router Beta is deprecated and support for it will be const config = await createConfig(paths, { ...commonConfigOptions, additionalEntryPoints: detectedModulesEntryPoint, + moduleFederation: options.moduleFederation, }); if (process.env.EXPERIMENTAL_VITE) { @@ -278,7 +279,9 @@ DEPRECATION WARNING: React Router Beta is deprecated and support for it will be } }); - openBrowser(url.href); + if (!options.skipOpenBrowser) { + openBrowser(url.href); + } const waitForExit = async () => { for (const signal of ['SIGINT', 'SIGTERM'] as const) { diff --git a/packages/cli/src/lib/bundler/types.ts b/packages/cli/src/lib/bundler/types.ts index 60c59f757b..f8e228c5c4 100644 --- a/packages/cli/src/lib/bundler/types.ts +++ b/packages/cli/src/lib/bundler/types.ts @@ -43,6 +43,7 @@ export type ServeOptions = BundlingPathsOptions & { checksEnabled: boolean; configPaths: string[]; verifyVersions?: boolean; + skipOpenBrowser?: boolean; moduleFederation?: ModuleFederationOptions; }; From b7709255e8b3540176b7db675e9ad77e658920cc Mon Sep 17 00:00:00 2001 From: MT Lewis <mtlewis@users.noreply.github.com> Date: Wed, 17 Jul 2024 18:12:16 +0100 Subject: [PATCH 330/416] cli: pass websocket host and port explicitly in configuration When configuring the ReactRefreshPlugin and the WebpackDevServer, we previously inferred the host and port from the browser location. This is no longer sufficient, since dynamic plugin containers may be served from separate dev servers. https://webpack.js.org/configuration/dev-server/#websocketurl https://github.com/pmmmwh/react-refresh-webpack-plugin/blob/main/docs/API.md#sockhost Signed-off-by: MT Lewis <mtlewis@users.noreply.github.com> --- packages/cli/src/lib/bundler/config.ts | 30 ++++++++++++++++++++++ packages/cli/src/lib/bundler/server.ts | 12 +++------ packages/cli/src/lib/bundler/transforms.ts | 11 +------- 3 files changed, 34 insertions(+), 19 deletions(-) diff --git a/packages/cli/src/lib/bundler/config.ts b/packages/cli/src/lib/bundler/config.ts index 9a611a5954..1f08f74a85 100644 --- a/packages/cli/src/lib/bundler/config.ts +++ b/packages/cli/src/lib/bundler/config.ts @@ -29,6 +29,7 @@ import { ModuleFederationPlugin } from '@module-federation/enhanced/webpack'; import { LinkedPackageResolvePlugin } from './LinkedPackageResolvePlugin'; import ModuleScopePlugin from 'react-dev-utils/ModuleScopePlugin'; import { RunScriptWebpackPlugin } from 'run-script-webpack-plugin'; +import ReactRefreshPlugin from '@pmmmwh/react-refresh-webpack-plugin'; import { paths as cliPaths } from '../../lib/paths'; import fs from 'fs-extra'; import { getPackages } from '@manypkg/get-packages'; @@ -54,6 +55,21 @@ export function resolveBaseUrl(config: Config): URL { } } +export function resolveEndpoint(config: Config): { + host: string; + port: number; +} { + const url = resolveBaseUrl(config); + + return { + host: config.getOptionalString('app.listen.host') ?? url.hostname, + port: + config.getOptionalNumber('app.listen.port') ?? + Number(url.port) ?? + (url.protocol === 'https:' ? 443 : 80), + }; +} + async function readBuildInfo() { const timestamp = Date.now(); @@ -108,6 +124,20 @@ export async function createConfig( publicPath = `${publicPath}${publicSubPath}`.replace('//', '/'); } + if (isDev) { + const { host, port } = resolveEndpoint(options.frontendConfig); + + plugins.push( + new ReactRefreshPlugin({ + overlay: { + sockProtocol: 'ws', + sockHost: host, + sockPort: port, + }, + }), + ); + } + if (checksEnabled) { plugins.push( new ForkTsCheckerWebpackPlugin({ diff --git a/packages/cli/src/lib/bundler/server.ts b/packages/cli/src/lib/bundler/server.ts index cf35f65518..cbd76b4ead 100644 --- a/packages/cli/src/lib/bundler/server.ts +++ b/packages/cli/src/lib/bundler/server.ts @@ -30,7 +30,7 @@ import { import { paths as libPaths } from '../../lib/paths'; import { loadCliConfig } from '../config'; import { Lockfile } from '../versioning'; -import { createConfig, resolveBaseUrl } from './config'; +import { createConfig, resolveBaseUrl, resolveEndpoint } from './config'; import { createDetectedModulesEntryPoint } from './packageDetection'; import { resolveBundlingPaths, resolveOptionalBundlingPaths } from './paths'; import { ServeOptions } from './types'; @@ -131,13 +131,7 @@ DEPRECATION WARNING: React Router Beta is deprecated and support for it will be const { frontendConfig, fullConfig } = cliConfig; const url = resolveBaseUrl(frontendConfig); - - const host = - frontendConfig.getOptionalString('app.listen.host') || url.hostname; - const port = - frontendConfig.getOptionalNumber('app.listen.port') || - Number(url.port) || - (url.protocol === 'https:' ? 443 : 80); + const { host, port } = resolveEndpoint(frontendConfig); const detectedModulesEntryPoint = await createDetectedModulesEntryPoint({ config: fullConfig, @@ -257,7 +251,7 @@ DEPRECATION WARNING: React Router Beta is deprecated and support for it will be // When the dev server is behind a proxy, the host and public hostname differ allowedHosts: [url.hostname], client: { - webSocketURL: 'auto://0.0.0.0:0/ws', + webSocketURL: { hostname: host, port }, }, }, compiler, diff --git a/packages/cli/src/lib/bundler/transforms.ts b/packages/cli/src/lib/bundler/transforms.ts index da1eec4e11..0900b8e48e 100644 --- a/packages/cli/src/lib/bundler/transforms.ts +++ b/packages/cli/src/lib/bundler/transforms.ts @@ -17,7 +17,6 @@ import { ModuleOptions, WebpackPluginInstance } from 'webpack'; import MiniCssExtractPlugin from 'mini-css-extract-plugin'; import { svgrTemplate } from '../svgrTemplate'; -import ReactRefreshPlugin from '@pmmmwh/react-refresh-webpack-plugin'; type Transforms = { loaders: ModuleOptions['rules']; @@ -193,15 +192,7 @@ export const transforms = (options: TransformOptions): Transforms => { const plugins = new Array<WebpackPluginInstance>(); - if (isDev) { - if (!isBackend) { - plugins.push( - new ReactRefreshPlugin({ - overlay: { sockProtocol: 'ws' }, - }), - ); - } - } else { + if (!isDev) { plugins.push( new MiniCssExtractPlugin({ filename: 'static/[name].[contenthash:8].css', From be1ee471cf2b09d455256ad6edfa84031ca16489 Mon Sep 17 00:00:00 2001 From: MT Lewis <mtlewis@users.noreply.github.com> Date: Wed, 17 Jul 2024 18:18:20 +0100 Subject: [PATCH 331/416] cli: disable historyApiFallback for module federation remotes Module federation remotes only serve static assets, and aren't intended to be loaded directly in a browser. As such, the historyApiFallback isn't useful and should be disabled in this context. Signed-off-by: MT Lewis <mtlewis@users.noreply.github.com> --- packages/cli/src/lib/bundler/server.ts | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/packages/cli/src/lib/bundler/server.ts b/packages/cli/src/lib/bundler/server.ts index cbd76b4ead..a3cbaeacc7 100644 --- a/packages/cli/src/lib/bundler/server.ts +++ b/packages/cli/src/lib/bundler/server.ts @@ -227,14 +227,17 @@ DEPRECATION WARNING: React Router Beta is deprecated and support for it will be directory: paths.targetPublic, } : undefined, - historyApiFallback: { - // Paths with dots should still use the history fallback. - // See https://github.com/facebookincubator/create-react-app/issues/387. - disableDotRule: true, + historyApiFallback: + options.moduleFederation?.mode === 'remote' + ? false + : { + // Paths with dots should still use the history fallback. + // See https://github.com/facebookincubator/create-react-app/issues/387. + disableDotRule: true, - // The index needs to be rewritten relative to the new public path, including subroutes. - index: `${config.output?.publicPath}index.html`, - }, + // The index needs to be rewritten relative to the new public path, including subroutes. + index: `${config.output?.publicPath}index.html`, + }, server: url.protocol === 'https:' ? { From f93ae496ce956598c56254d5420438be92faf0c0 Mon Sep 17 00:00:00 2001 From: MT Lewis <mtlewis@users.noreply.github.com> Date: Wed, 17 Jul 2024 18:19:32 +0100 Subject: [PATCH 332/416] cli: add CORS headers for webpack-dev-server content This allows loading static assets from dev-servers for dynamic plugin containers. Signed-off-by: MT Lewis <mtlewis@users.noreply.github.com> --- packages/cli/src/lib/bundler/server.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/cli/src/lib/bundler/server.ts b/packages/cli/src/lib/bundler/server.ts index a3cbaeacc7..0421f4d019 100644 --- a/packages/cli/src/lib/bundler/server.ts +++ b/packages/cli/src/lib/bundler/server.ts @@ -256,6 +256,12 @@ DEPRECATION WARNING: React Router Beta is deprecated and support for it will be client: { webSocketURL: { hostname: host, port }, }, + headers: { + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': 'GET, OPTIONS', + 'Access-Control-Allow-Headers': + 'X-Requested-With, content-type, Authorization', + }, }, compiler, ); From e20fe546952f78e8f82faed76c03daf930d821ec Mon Sep 17 00:00:00 2001 From: Ramin G <rghara@outlook.com> Date: Fri, 19 Jul 2024 15:56:09 -0400 Subject: [PATCH 333/416] Corrected typo in logging-in.md Corrected typo in the description of the image Signed-off-by: Ramin G <rghara@outlook.com> --- docs/getting-started/logging-in.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started/logging-in.md b/docs/getting-started/logging-in.md index 5386e98798..7d6fb5d55b 100644 --- a/docs/getting-started/logging-in.md +++ b/docs/getting-started/logging-in.md @@ -20,7 +20,7 @@ Run your Backstage app with `yarn dev`. Navigate to `http://localhost:3000`. If you're not already logged in, you should see a login screen like this, -![Screenshot of the the login screen](../assets/getting-started/login-screen.png) +![Screenshot of the login screen](../assets/getting-started/login-screen.png) To login, you should choose the "Github" provider and click the "Sign in" button. This will redirect you to a Github OAuth page. Verify that the scopes mentioned on that page match the setup you did in [the authentication tutorial](./config/authentication.md). Once you click "Confirm", you will be brought back to the Backstage interface and signed in! From c761199ce774a272e303f4493ba4a9c505ee5131 Mon Sep 17 00:00:00 2001 From: rghara <ramin.g01@infosys.com> Date: Fri, 19 Jul 2024 18:51:44 -0400 Subject: [PATCH 334/416] Replaced login screen image Signed-off-by: rghara <ramin.g01@infosys.com> --- docs/assets/getting-started/login-screen.png | Bin 108521 -> 53116 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/assets/getting-started/login-screen.png b/docs/assets/getting-started/login-screen.png index 70b56f399a22d19ad863f77db22739f67a352501..1af52cb2c9b0b95cac2b6e715077bf9095ec038c 100755 GIT binary patch literal 53116 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 literal 108521 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�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 From aab708eb27b0a3809685d7d3e1057ac0f9ea8b54 Mon Sep 17 00:00:00 2001 From: parmar-abhinav <abhinav.parmar@infosys.com> Date: Sun, 21 Jul 2024 10:14:29 +0530 Subject: [PATCH 335/416] Added test cases for gitlab:issue:edit examples Signed-off-by: parmar-abhinav <abhinav.parmar@infosys.com> --- .changeset/plenty-tools-exist.md | 5 + .../actions/gitlabIssueEdit.examples.test.ts | 817 ++++++++++++++++++ .../src/actions/gitlabIssueEdit.examples.ts | 177 +++- 3 files changed, 997 insertions(+), 2 deletions(-) create mode 100644 .changeset/plenty-tools-exist.md create mode 100644 plugins/scaffolder-backend-module-gitlab/src/actions/gitlabIssueEdit.examples.test.ts diff --git a/.changeset/plenty-tools-exist.md b/.changeset/plenty-tools-exist.md new file mode 100644 index 0000000000..0ce22a74f2 --- /dev/null +++ b/.changeset/plenty-tools-exist.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend-module-gitlab': patch +--- + +Added test cases for gitlab:issue:edit examples diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabIssueEdit.examples.test.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabIssueEdit.examples.test.ts new file mode 100644 index 0000000000..7e50eac66c --- /dev/null +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabIssueEdit.examples.test.ts @@ -0,0 +1,817 @@ +/* + * Copyright 2024 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 { createMockActionContext } from '@backstage/plugin-scaffolder-node-test-utils'; +import { ConfigReader } from '@backstage/core-app-api'; +import { ScmIntegrations } from '@backstage/integration'; +import { editGitlabIssueAction } from './gitlabIssueEdit'; +import { examples } from './gitlabIssueEdit.examples'; +import yaml from 'yaml'; + +const mockGitlabClient = { + Issues: { + edit: jest.fn(), + }, +}; +jest.mock('@gitbeaker/rest', () => ({ + Gitlab: class { + constructor() { + return mockGitlabClient; + } + }, +})); + +describe('gitlab:issue:edit', () => { + beforeEach(() => { + jest.clearAllMocks(); + jest.useFakeTimers({ + now: new Date(1999, 6, 14, 12, 0, 0), + }); + }); + + afterEach(() => { + jest.useRealTimers(); + }); + + const config = new ConfigReader({ + integrations: { + gitlab: [ + { + host: 'gitlab.com', + token: 'myIntegrationsToken', + apiBaseUrl: 'https://gitlab.com/api/v4', + }, + ], + }, + }); + const integrations = ScmIntegrations.fromConfig(config); + + const action = editGitlabIssueAction({ integrations }); + + it(`Should ${examples[0].description}`, async () => { + const mockContext = createMockActionContext({ + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: 123, + issueIid: 42, + title: 'Computer banks to rule the world', + }, + workspacePath: 'seen2much', + }); + + mockGitlabClient.Issues.edit.mockResolvedValue({ + id: 123, + iid: 42, + web_url: 'https://gitlab.com/hangar18-/issues/42', + }); + + let input; + try { + input = yaml.parse(examples[0].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(mockGitlabClient.Issues.edit).toHaveBeenCalledWith(12, 42, { + title: input.title, + issueType: undefined, + addLabels: undefined, + removeLabels: undefined, + description: input.description, + assigneeIds: [], + confidential: false, + discussionLocked: false, + epicId: undefined, + labels: undefined, + updatedAt: new Date().toISOString(), + dueDate: undefined, + milestoneId: undefined, + weight: undefined, + stateEvent: undefined, + }); + + expect(mockContext.output).toHaveBeenCalledWith('issueId', 123); + expect(mockContext.output).toHaveBeenCalledWith('issueIid', 42); + expect(mockContext.output).toHaveBeenCalledWith( + 'issueUrl', + 'https://gitlab.com/hangar18-/issues/42', + ); + }); + + it(`Should ${examples[1].description}`, async () => { + const mockContext = createMockActionContext({ + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: 123, + issueIid: 42, + title: 'Computer banks to rule the world', + }, + workspacePath: 'seen2much', + }); + + mockGitlabClient.Issues.edit.mockResolvedValue({ + id: 123, + iid: 42, + web_url: 'https://gitlab.com/hangar18-/issues/42', + }); + + let input; + try { + input = yaml.parse(examples[1].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(mockGitlabClient.Issues.edit).toHaveBeenCalledWith(12, 42, { + title: input.title, + issueType: undefined, + addLabels: undefined, + removeLabels: undefined, + description: input.description, + assigneeIds: [18], + confidential: false, + discussionLocked: false, + epicId: undefined, + labels: undefined, + updatedAt: '2024-05-10T18:00:00.000Z', + dueDate: '2024-09-28', + milestoneId: undefined, + weight: undefined, + stateEvent: undefined, + }); + + expect(mockContext.output).toHaveBeenCalledWith('issueId', 123); + expect(mockContext.output).toHaveBeenCalledWith('issueIid', 42); + expect(mockContext.output).toHaveBeenCalledWith( + 'issueUrl', + 'https://gitlab.com/hangar18-/issues/42', + ); + }); + + it(`Should ${examples[2].description}`, async () => { + const mockContext = createMockActionContext({ + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: 123, + issueIid: 42, + title: 'Computer banks to rule the world', + }, + workspacePath: 'seen2much', + }); + + mockGitlabClient.Issues.edit.mockResolvedValue({ + id: 123, + iid: 42, + web_url: 'https://gitlab.com/hangar18-/issues/42', + }); + + let input; + try { + input = yaml.parse(examples[2].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + epicId: undefined, + }, + }); + + expect(mockGitlabClient.Issues.edit).toHaveBeenCalledWith(12, 42, { + title: input.title, + issueType: undefined, + addLabels: undefined, + removeLabels: undefined, + description: input.description, + assigneeIds: [18, 15], + confidential: false, + discussionLocked: true, + epicId: undefined, + labels: 'phase1:label1,phase2:label2', + updatedAt: '2024-05-10T18:00:00.000Z', + dueDate: '2024-09-28', + milestoneId: undefined, + weight: undefined, + stateEvent: undefined, + }); + + expect(mockContext.output).toHaveBeenCalledWith('issueId', 123); + expect(mockContext.output).toHaveBeenCalledWith('issueIid', 42); + expect(mockContext.output).toHaveBeenCalledWith( + 'issueUrl', + 'https://gitlab.com/hangar18-/issues/42', + ); + }); + + it(`Should ${examples[2].description}`, async () => { + const mockContext = createMockActionContext({ + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: 123, + issueIid: 42, + title: 'Computer banks to rule the world', + }, + workspacePath: 'seen2much', + }); + + mockGitlabClient.Issues.edit.mockResolvedValue({ + id: 123, + iid: 42, + web_url: 'https://gitlab.com/hangar18-/issues/42', + }); + + let input; + try { + input = yaml.parse(examples[2].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + epicId: undefined, + }, + }); + + expect(mockGitlabClient.Issues.edit).toHaveBeenCalledWith(12, 42, { + title: input.title, + issueType: undefined, + addLabels: undefined, + removeLabels: undefined, + description: input.description, + assigneeIds: [18, 15], + confidential: false, + discussionLocked: true, + epicId: undefined, + labels: 'phase1:label1,phase2:label2', + updatedAt: '2024-05-10T18:00:00.000Z', + dueDate: '2024-09-28', + milestoneId: undefined, + weight: undefined, + stateEvent: undefined, + }); + + expect(mockContext.output).toHaveBeenCalledWith('issueId', 123); + expect(mockContext.output).toHaveBeenCalledWith('issueIid', 42); + expect(mockContext.output).toHaveBeenCalledWith( + 'issueUrl', + 'https://gitlab.com/hangar18-/issues/42', + ); + }); + + it(`Should ${examples[3].description}`, async () => { + const mockContext = createMockActionContext({ + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: 123, + issueIid: 42, + title: 'Computer banks to rule the world', + }, + workspacePath: 'seen2much', + }); + + mockGitlabClient.Issues.edit.mockResolvedValue({ + id: 123, + iid: 42, + web_url: 'https://gitlab.com/hangar18-/issues/42', + }); + + let input; + try { + input = yaml.parse(examples[3].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(mockGitlabClient.Issues.edit).toHaveBeenCalledWith(12, 42, { + title: 'Computer banks to rule the world', + issueType: undefined, + addLabels: undefined, + removeLabels: undefined, + description: input.description, + assigneeIds: [], + confidential: false, + discussionLocked: false, + epicId: undefined, + labels: undefined, + updatedAt: new Date().toISOString(), + dueDate: undefined, + milestoneId: undefined, + weight: undefined, + stateEvent: 'close', + }); + + expect(mockContext.output).toHaveBeenCalledWith('issueId', 123); + expect(mockContext.output).toHaveBeenCalledWith('issueIid', 42); + expect(mockContext.output).toHaveBeenCalledWith( + 'issueUrl', + 'https://gitlab.com/hangar18-/issues/42', + ); + }); + + it(`Should ${examples[4].description}`, async () => { + const mockContext = createMockActionContext({ + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: 123, + issueIid: 42, + title: 'Computer banks to rule the world', + }, + workspacePath: 'seen2much', + }); + + mockGitlabClient.Issues.edit.mockResolvedValue({ + id: 123, + iid: 42, + web_url: 'https://gitlab.com/hangar18-/issues/42', + }); + + let input; + try { + input = yaml.parse(examples[4].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(mockGitlabClient.Issues.edit).toHaveBeenCalledWith(12, 42, { + title: 'Computer banks to rule the world', + issueType: undefined, + addLabels: undefined, + removeLabels: undefined, + description: input.description, + assigneeIds: [], + confidential: false, + discussionLocked: false, + epicId: undefined, + labels: undefined, + updatedAt: new Date().toISOString(), + dueDate: undefined, + milestoneId: undefined, + weight: undefined, + stateEvent: 'reopen', + }); + + expect(mockContext.output).toHaveBeenCalledWith('issueId', 123); + expect(mockContext.output).toHaveBeenCalledWith('issueIid', 42); + expect(mockContext.output).toHaveBeenCalledWith( + 'issueUrl', + 'https://gitlab.com/hangar18-/issues/42', + ); + }); + + it(`Should ${examples[5].description}`, async () => { + const mockContext = createMockActionContext({ + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: 123, + issueIid: 42, + title: 'Computer banks to rule the world', + }, + workspacePath: 'seen2much', + }); + + mockGitlabClient.Issues.edit.mockResolvedValue({ + id: 123, + iid: 42, + web_url: 'https://gitlab.com/hangar18-/issues/42', + }); + + let input; + try { + input = yaml.parse(examples[5].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(mockGitlabClient.Issues.edit).toHaveBeenCalledWith(12, 42, { + title: input.title, + issueType: undefined, + addLabels: undefined, + removeLabels: undefined, + description: input.description, + assigneeIds: [18, 20], + confidential: false, + discussionLocked: false, + epicId: undefined, + labels: undefined, + updatedAt: new Date().toISOString(), + dueDate: undefined, + milestoneId: input.milestoneId, + weight: undefined, + stateEvent: undefined, + }); + + expect(mockContext.output).toHaveBeenCalledWith('issueId', 123); + expect(mockContext.output).toHaveBeenCalledWith('issueIid', 42); + expect(mockContext.output).toHaveBeenCalledWith( + 'issueUrl', + 'https://gitlab.com/hangar18-/issues/42', + ); + }); + + it(`Should ${examples[6].description}`, async () => { + const mockContext = createMockActionContext({ + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: 123, + issueIid: 42, + title: 'Computer banks to rule the world', + }, + workspacePath: 'seen2much', + }); + + mockGitlabClient.Issues.edit.mockResolvedValue({ + id: 123, + iid: 42, + web_url: 'https://gitlab.com/hangar18-/issues/42', + }); + + let input; + try { + input = yaml.parse(examples[6].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(mockGitlabClient.Issues.edit).toHaveBeenCalledWith(12, 42, { + title: input.title, + issueType: undefined, + addLabels: undefined, + removeLabels: undefined, + description: input.description, + assigneeIds: [], + confidential: false, + discussionLocked: false, + epicId: undefined, + labels: input.labels, + updatedAt: new Date().toISOString(), + dueDate: undefined, + milestoneId: input.milestoneId, + weight: input.weight, + stateEvent: undefined, + }); + + expect(mockContext.output).toHaveBeenCalledWith('issueId', 123); + expect(mockContext.output).toHaveBeenCalledWith('issueIid', 42); + expect(mockContext.output).toHaveBeenCalledWith( + 'issueUrl', + 'https://gitlab.com/hangar18-/issues/42', + ); + }); + + it(`Should ${examples[7].description}`, async () => { + const mockContext = createMockActionContext({ + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: 123, + issueIid: 42, + title: 'Computer banks to rule the world', + }, + workspacePath: 'seen2much', + }); + + mockGitlabClient.Issues.edit.mockResolvedValue({ + id: 123, + iid: 42, + web_url: 'https://gitlab.com/hangar18-/issues/42', + }); + + let input; + try { + input = yaml.parse(examples[7].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(mockGitlabClient.Issues.edit).toHaveBeenCalledWith(12, 42, { + title: input.title, + issueType: undefined, + addLabels: undefined, + removeLabels: undefined, + description: input.description, + assigneeIds: [], + confidential: input.confidential, + discussionLocked: false, + epicId: undefined, + labels: input.labels, + updatedAt: new Date().toISOString(), + dueDate: undefined, + milestoneId: input.milestoneId, + weight: input.weight, + stateEvent: undefined, + }); + + expect(mockContext.output).toHaveBeenCalledWith('issueId', 123); + expect(mockContext.output).toHaveBeenCalledWith('issueIid', 42); + expect(mockContext.output).toHaveBeenCalledWith( + 'issueUrl', + 'https://gitlab.com/hangar18-/issues/42', + ); + }); + + it(`Should ${examples[8].description}`, async () => { + const mockContext = createMockActionContext({ + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: 123, + issueIid: 42, + title: 'Computer banks to rule the world', + }, + workspacePath: 'seen2much', + }); + + mockGitlabClient.Issues.edit.mockResolvedValue({ + id: 123, + iid: 42, + web_url: 'https://gitlab.com/hangar18-/issues/42', + }); + + let input; + try { + input = yaml.parse(examples[8].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(mockGitlabClient.Issues.edit).toHaveBeenCalledWith(12, 42, { + title: input.title, + issueType: undefined, + addLabels: undefined, + removeLabels: undefined, + description: input.description, + assigneeIds: [], + confidential: false, + discussionLocked: input.discussionLocked, + epicId: undefined, + labels: input.labels, + updatedAt: new Date().toISOString(), + dueDate: undefined, + milestoneId: input.milestoneId, + weight: input.weight, + stateEvent: undefined, + }); + + expect(mockContext.output).toHaveBeenCalledWith('issueId', 123); + expect(mockContext.output).toHaveBeenCalledWith('issueIid', 42); + expect(mockContext.output).toHaveBeenCalledWith( + 'issueUrl', + 'https://gitlab.com/hangar18-/issues/42', + ); + }); + + it(`Should ${examples[9].description}`, async () => { + const mockContext = createMockActionContext({ + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: 123, + issueIid: 42, + title: 'Computer banks to rule the world', + }, + workspacePath: 'seen2much', + }); + + mockGitlabClient.Issues.edit.mockResolvedValue({ + id: 123, + iid: 42, + web_url: 'https://gitlab.com/hangar18-/issues/42', + }); + + let input; + try { + input = yaml.parse(examples[9].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(mockGitlabClient.Issues.edit).toHaveBeenCalledWith(12, 42, { + title: input.title, + issueType: undefined, + addLabels: undefined, + removeLabels: input.removeLabels, + description: input.description, + assigneeIds: [], + confidential: false, + discussionLocked: false, + epicId: undefined, + labels: input.labels, + updatedAt: new Date().toISOString(), + dueDate: undefined, + milestoneId: input.milestoneId, + weight: input.weight, + stateEvent: undefined, + }); + + expect(mockContext.output).toHaveBeenCalledWith('issueId', 123); + expect(mockContext.output).toHaveBeenCalledWith('issueIid', 42); + expect(mockContext.output).toHaveBeenCalledWith( + 'issueUrl', + 'https://gitlab.com/hangar18-/issues/42', + ); + }); + it(`Should ${examples[10].description}`, async () => { + const mockContext = createMockActionContext({ + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: 123, + issueIid: 42, + title: 'Computer banks to rule the world', + }, + workspacePath: 'seen2much', + }); + + mockGitlabClient.Issues.edit.mockResolvedValue({ + id: 123, + iid: 42, + web_url: 'https://gitlab.com/hangar18-/issues/42', + }); + + let input; + try { + input = yaml.parse(examples[10].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(mockGitlabClient.Issues.edit).toHaveBeenCalledWith(12, 42, { + title: input.title, + issueType: undefined, + addLabels: undefined, + removeLabels: input.removeLabels, + description: input.description, + assigneeIds: [], + confidential: false, + discussionLocked: false, + epicId: undefined, + labels: input.labels, + updatedAt: new Date().toISOString(), + dueDate: undefined, + milestoneId: input.milestoneId, + weight: input.weight, + stateEvent: undefined, + }); + + expect(mockContext.output).toHaveBeenCalledWith('issueId', 123); + expect(mockContext.output).toHaveBeenCalledWith('issueIid', 42); + expect(mockContext.output).toHaveBeenCalledWith( + 'issueUrl', + 'https://gitlab.com/hangar18-/issues/42', + ); + }); + it(`Should ${examples[11].description}`, async () => { + const mockContext = createMockActionContext({ + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: 123, + issueIid: 42, + title: 'Computer banks to rule the world', + }, + workspacePath: 'seen2much', + }); + + mockGitlabClient.Issues.edit.mockResolvedValue({ + id: 123, + iid: 42, + web_url: 'https://gitlab.com/hangar18-/issues/42', + }); + + let input; + try { + input = yaml.parse(examples[11].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(mockGitlabClient.Issues.edit).toHaveBeenCalledWith(12, 42, { + title: input.title, + issueType: input.issueType, + addLabels: undefined, + removeLabels: input.removeLabels, + description: input.description, + assigneeIds: [], + confidential: false, + discussionLocked: false, + epicId: undefined, + labels: input.labels, + updatedAt: new Date().toISOString(), + dueDate: undefined, + milestoneId: input.milestoneId, + weight: input.weight, + stateEvent: undefined, + }); + + expect(mockContext.output).toHaveBeenCalledWith('issueId', 123); + expect(mockContext.output).toHaveBeenCalledWith('issueIid', 42); + expect(mockContext.output).toHaveBeenCalledWith( + 'issueUrl', + 'https://gitlab.com/hangar18-/issues/42', + ); + }); +}); diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabIssueEdit.examples.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabIssueEdit.examples.ts index 861c0736f0..8686a66250 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabIssueEdit.examples.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabIssueEdit.examples.ts @@ -50,7 +50,7 @@ export const examples: TemplateExample[] = [ title: 'Test Issue', assignees: [18], description: 'This is the edited description of the issue', - updatedAt: '2024-05-10 18:00:00.000', + updatedAt: '2024-05-10T18:00:00.000Z', dueDate: '2024-09-28', }, }, @@ -72,7 +72,7 @@ export const examples: TemplateExample[] = [ assignees: [18, 15], description: 'This is the description of the issue', confidential: false, - updatedAt: '2024-05-10 18:00:00.000', + updatedAt: '2024-05-10T18:00:00.000Z', dueDate: '2024-09-28', discussionLocked: true, epicId: 1, @@ -82,4 +82,177 @@ export const examples: TemplateExample[] = [ ], }), }, + { + description: 'Edit a gitlab issue to change its state to close', + example: yaml.stringify({ + steps: [ + { + id: 'gitlabIssue', + name: 'EditIssues', + action: 'gitlab:issue:edit', + input: { + ...commonGitlabConfigExample, + projectId: 12, + stateEvent: 'close', + }, + }, + ], + }), + }, + { + description: 'Edit a gitlab issue to change its state to reopened', + example: yaml.stringify({ + steps: [ + { + id: 'gitlabIssue', + name: 'EditIssues', + action: 'gitlab:issue:edit', + input: { + ...commonGitlabConfigExample, + projectId: 12, + stateEvent: 'reopen', + }, + }, + ], + }), + }, + { + description: + 'Edit a gitlab issue to assign it to multiple users and set milestone', + example: yaml.stringify({ + steps: [ + { + id: 'gitlabIssue', + name: 'EditIssues', + action: 'gitlab:issue:edit', + input: { + ...commonGitlabConfigExample, + projectId: 12, + title: 'Test issue with milestone', + assignees: [18, 20], + description: 'This issue has milestone set', + milestoneId: 5, + }, + }, + ], + }), + }, + { + description: 'Edit a gitlab issue to add weight and update labels', + example: yaml.stringify({ + steps: [ + { + id: 'gitlabIssue', + name: 'EditIssues', + action: 'gitlab:issue:edit', + input: { + ...commonGitlabConfigExample, + projectId: 12, + title: 'Issue with weight and labels', + description: 'This issue has weight and new labels', + weight: 3, + labels: 'bug,urgent', + }, + }, + ], + }), + }, + { + description: 'Edit a gitlab issue to make it confidential', + example: yaml.stringify({ + steps: [ + { + id: 'gitlabIssue', + name: 'EditIssues', + action: 'gitlab:issue:edit', + input: { + ...commonGitlabConfigExample, + projectId: 12, + title: 'Confidential Issue', + description: 'This issue is confidential', + confidential: true, + }, + }, + ], + }), + }, + { + description: 'Edit a gitlab issue to lock the discussion', + example: yaml.stringify({ + steps: [ + { + id: 'gitlabIssue', + name: 'EditIssues', + action: 'gitlab:issue:edit', + input: { + ...commonGitlabConfigExample, + projectId: 12, + title: 'Locked Discussion Issue', + description: 'This discussion on this issue is locked', + discussionLocked: true, + }, + }, + ], + }), + }, + { + description: 'Edit a gitlab issue to remove labels and update milestone', + example: yaml.stringify({ + steps: [ + { + id: 'gitlabIssue', + name: 'EditIssues', + action: 'gitlab:issue:edit', + input: { + ...commonGitlabConfigExample, + projectId: 12, + title: 'Issue with labels removed and milestone updated', + description: 'This issue has labels removed and milestone updated', + removeLabels: 'phase1:label1', + milestoneId: 6, + }, + }, + ], + }), + }, + { + description: 'Edit a gitlab issue to remove some labels and new ones', + example: yaml.stringify({ + steps: [ + { + id: 'gitlabIssue', + name: 'EditIssues', + action: 'gitlab:issue:edit', + input: { + ...commonGitlabConfigExample, + projectId: 12, + title: 'Issue with labels updated', + description: 'This issue has labels removed and new ones added', + removeLabels: 'bug,urgent', + labels: 'enhancement:documentation', + }, + }, + ], + }), + }, + { + description: 'Edit a gitlab issue to change issue type and add labels', + example: yaml.stringify({ + steps: [ + { + id: 'gitlabIssue', + name: 'EditIssues', + action: 'gitlab:issue:edit', + input: { + ...commonGitlabConfigExample, + projectId: 12, + title: 'Issue with type and labels', + description: 'This issue has been changes and new labels added', + labels: 'task,high-priority', + issueType: 'task', + }, + }, + ], + }), + }, ]; From 1ba4c2f6da8412660a236fa3588c4fa129cdf92e Mon Sep 17 00:00:00 2001 From: parmar-abhinav <abhinav.parmar@infosys.com> Date: Sun, 21 Jul 2024 10:59:49 +0530 Subject: [PATCH 336/416] Added test cases for gitlab:pipeline:trigger examples Signed-off-by: parmar-abhinav <abhinav.parmar@infosys.com> --- .changeset/strange-papayas-beg.md | 5 + .../gitlabPipelineTrigger.examples.test.ts | 320 ++++++++++++++++++ .../actions/gitlabPipelineTrigger.examples.ts | 63 ++++ 3 files changed, 388 insertions(+) create mode 100644 .changeset/strange-papayas-beg.md create mode 100644 plugins/scaffolder-backend-module-gitlab/src/actions/gitlabPipelineTrigger.examples.test.ts diff --git a/.changeset/strange-papayas-beg.md b/.changeset/strange-papayas-beg.md new file mode 100644 index 0000000000..6ce33fb029 --- /dev/null +++ b/.changeset/strange-papayas-beg.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend-module-gitlab': patch +--- + +Added test cases for gitlab:pipeline:trigger examples diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabPipelineTrigger.examples.test.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabPipelineTrigger.examples.test.ts new file mode 100644 index 0000000000..53cbfb0b87 --- /dev/null +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabPipelineTrigger.examples.test.ts @@ -0,0 +1,320 @@ +/* + * Copyright 2024 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/core-app-api'; +import { ScmIntegrations } from '@backstage/integration'; +import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test-utils'; +import { createTriggerGitlabPipelineAction } from './gitlabPipelineTrigger'; +import { examples } from './gitlabPipelineTrigger.examples'; +import yaml from 'yaml'; + +const mockGitlabClient = { + PipelineTriggerTokens: { + create: jest.fn(), + trigger: jest.fn(), + remove: jest.fn(), + }, +}; +jest.mock('@gitbeaker/rest', () => ({ + Gitlab: class { + constructor() { + return mockGitlabClient; + } + }, +})); + +describe('gitlab:pipeline:trigger', () => { + beforeEach(() => { + jest.resetModules(); + jest.clearAllMocks(); + jest.useFakeTimers({ + now: new Date(1988, 5, 3, 12, 0, 0), + }); + }); + + afterEach(() => { + jest.useRealTimers(); + }); + + const config = new ConfigReader({ + integrations: { + gitlab: [ + { + host: 'gitlab.com', + token: 'glpat-abcdef', + apiBaseUrl: 'https://gitlab.com/api/v4', + }, + ], + }, + }); + const integrations = ScmIntegrations.fromConfig(config); + + const action = createTriggerGitlabPipelineAction({ integrations }); + + it(`should ${examples[0].description}`, async () => { + const mockContext = createMockActionContext({ + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: 123, + tokenDescription: 'Gitlab sample pipeline', + branch: 'main', + }, + workspacePath: 'repository', + }); + + mockGitlabClient.PipelineTriggerTokens.create.mockResolvedValue({ + id: 42, + description: 'Gitlab sample pipeline', + createdAt: new Date().toISOString(), + last_used: null, + token: 'abcdd-ghijkl', + updated_at: new Date().toISOString(), + owner: null, + }); + + mockGitlabClient.PipelineTriggerTokens.trigger.mockResolvedValue({ + id: 99, + web_url: 'https://gitlab.com/hangar18-/pipelines/99', + }); + + let input; + try { + input = yaml.parse(examples[0].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(mockGitlabClient.PipelineTriggerTokens.create).toHaveBeenCalledWith( + input.projectId, + input.tokenDescription, + ); + + expect(mockGitlabClient.PipelineTriggerTokens.trigger).toHaveBeenCalledWith( + input.projectId, + 'main', + 'abcdd-ghijkl', + { variables: input.variables }, + ); + + expect(mockGitlabClient.PipelineTriggerTokens.remove).toHaveBeenCalledWith( + input.projectId, + 42, + ); + + expect(mockContext.output).toHaveBeenCalledWith( + 'pipelineUrl', + 'https://gitlab.com/hangar18-/pipelines/99', + ); + }); + + it(`should ${examples[1].description}`, async () => { + const mockContext = createMockActionContext({ + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: 123, + tokenDescription: 'Gitlab sample pipeline', + branch: 'main', + }, + workspacePath: 'repository', + }); + + mockGitlabClient.PipelineTriggerTokens.create.mockResolvedValue({ + id: 42, + description: 'Gitlab sample pipeline', + createdAt: new Date().toISOString(), + last_used: null, + token: 'abcdd-ghijkl', + updated_at: new Date().toISOString(), + owner: null, + }); + + mockGitlabClient.PipelineTriggerTokens.trigger.mockResolvedValue({ + id: 99, + web_url: 'https://gitlab.com/hangar18-/pipelines/99', + }); + + let input; + try { + input = yaml.parse(examples[1].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(mockGitlabClient.PipelineTriggerTokens.create).toHaveBeenCalledWith( + input.projectId, + input.tokenDescription, + ); + + expect(mockGitlabClient.PipelineTriggerTokens.trigger).toHaveBeenCalledWith( + input.projectId, + 'main', + 'abcdd-ghijkl', + { variables: input.variables }, + ); + + expect(mockGitlabClient.PipelineTriggerTokens.remove).toHaveBeenCalledWith( + input.projectId, + 42, + ); + + expect(mockContext.output).toHaveBeenCalledWith( + 'pipelineUrl', + 'https://gitlab.com/hangar18-/pipelines/99', + ); + }); + it(`should ${examples[2].description}`, async () => { + const mockContext = createMockActionContext({ + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: 123, + tokenDescription: 'Gitlab sample pipeline', + branch: 'main', + }, + workspacePath: 'repository', + }); + + mockGitlabClient.PipelineTriggerTokens.create.mockResolvedValue({ + id: 42, + description: 'Gitlab sample pipeline', + createdAt: new Date().toISOString(), + last_used: null, + token: 'abcdd-ghijkl', + updated_at: new Date().toISOString(), + owner: null, + }); + + mockGitlabClient.PipelineTriggerTokens.trigger.mockResolvedValue({ + id: 99, + web_url: 'https://gitlab.com/hangar18-/pipelines/99', + }); + + let input; + try { + input = yaml.parse(examples[2].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(mockGitlabClient.PipelineTriggerTokens.create).toHaveBeenCalledWith( + input.projectId, + input.tokenDescription, + ); + + expect(mockGitlabClient.PipelineTriggerTokens.trigger).toHaveBeenCalledWith( + input.projectId, + 'main', + 'abcdd-ghijkl', + { variables: input.variables }, + ); + + expect(mockGitlabClient.PipelineTriggerTokens.remove).toHaveBeenCalledWith( + input.projectId, + 42, + ); + + expect(mockContext.output).toHaveBeenCalledWith( + 'pipelineUrl', + 'https://gitlab.com/hangar18-/pipelines/99', + ); + }); + it(`should ${examples[3].description}`, async () => { + const mockContext = createMockActionContext({ + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: 123, + tokenDescription: 'Gitlab sample pipeline', + branch: 'main', + }, + workspacePath: 'repository', + }); + + mockGitlabClient.PipelineTriggerTokens.create.mockResolvedValue({ + id: 42, + description: 'Gitlab sample pipeline', + createdAt: new Date().toISOString(), + last_used: null, + token: 'abcdd-ghijkl', + updated_at: new Date().toISOString(), + owner: null, + }); + + mockGitlabClient.PipelineTriggerTokens.trigger.mockResolvedValue({ + id: 99, + web_url: 'https://gitlab.com/hangar18-/pipelines/99', + }); + + let input; + try { + input = yaml.parse(examples[3].example).steps[0].input; + } catch (error) { + console.error('Failed to parse YAML:', error); + } + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + ...input, + }, + }); + + expect(mockGitlabClient.PipelineTriggerTokens.create).toHaveBeenCalledWith( + input.projectId, + input.tokenDescription, + ); + + expect(mockGitlabClient.PipelineTriggerTokens.trigger).toHaveBeenCalledWith( + input.projectId, + 'main', + 'abcdd-ghijkl', + { variables: input.variables }, + ); + + expect(mockGitlabClient.PipelineTriggerTokens.remove).toHaveBeenCalledWith( + input.projectId, + 42, + ); + + expect(mockContext.output).toHaveBeenCalledWith( + 'pipelineUrl', + 'https://gitlab.com/hangar18-/pipelines/99', + ); + }); +}); diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabPipelineTrigger.examples.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabPipelineTrigger.examples.ts index d0840030df..f213fcd83f 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabPipelineTrigger.examples.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabPipelineTrigger.examples.ts @@ -39,4 +39,67 @@ export const examples: TemplateExample[] = [ ], }), }, + { + description: 'Trigger a GitLab Project Pipeline with No Variables', + example: yaml.stringify({ + steps: [ + { + id: 'triggerPipeline', + name: 'Trigger Project Pipeline', + action: 'gitlab:pipeline:trigger', + input: { + ...commonGitlabConfigExample, + projectId: 12, + tokenDescription: + 'This is the text that will appear in the pipeline token', + token: 'glpt-xxxxxxxxxxxx', + branch: 'main', + variables: {}, + }, + }, + ], + }), + }, + { + description: 'Trigger a GitLab Project Pipeline with Single Variables', + example: yaml.stringify({ + steps: [ + { + id: 'triggerPipeline', + name: 'Trigger Project Pipeline', + action: 'gitlab:pipeline:trigger', + input: { + ...commonGitlabConfigExample, + projectId: 12, + tokenDescription: + 'This is the text that will appear in the pipeline token', + token: 'glpt-xxxxxxxxxxxx', + branch: 'main', + variables: { var_one: 'one' }, + }, + }, + ], + }), + }, + { + description: 'Trigger a GitLab Project Pipeline with Multiple Variables', + example: yaml.stringify({ + steps: [ + { + id: 'triggerPipeline', + name: 'Trigger Project Pipeline', + action: 'gitlab:pipeline:trigger', + input: { + ...commonGitlabConfigExample, + projectId: 12, + tokenDescription: + 'This is the text that will appear in the pipeline token', + token: 'glpt-xxxxxxxxxxxx', + branch: 'main', + variables: { var_one: 'one', var_two: 'two', var_three: 'three' }, + }, + }, + ], + }), + }, ]; From e53074fb0ec07d93025beefa783f52de2ce21b4c Mon Sep 17 00:00:00 2001 From: Stephen Glass <stephen@stephen.glass> Date: Sun, 21 Jul 2024 01:44:13 -0400 Subject: [PATCH 337/416] Update default backend plugin to use RootConfigService Signed-off-by: Stephen Glass <stephen@stephen.glass> --- .changeset/heavy-numbers-love.md | 5 +++++ .../cli/templates/default-backend-plugin/package.json.hbs | 1 - .../templates/default-backend-plugin/src/service/router.ts | 5 ++--- 3 files changed, 7 insertions(+), 4 deletions(-) create mode 100644 .changeset/heavy-numbers-love.md diff --git a/.changeset/heavy-numbers-love.md b/.changeset/heavy-numbers-love.md new file mode 100644 index 0000000000..c18d144636 --- /dev/null +++ b/.changeset/heavy-numbers-love.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Updated default backend plugin to use `RootConfigService` instead of `Config`. This also removes the dependency on `@backstage/config` as it's no longer used. diff --git a/packages/cli/templates/default-backend-plugin/package.json.hbs b/packages/cli/templates/default-backend-plugin/package.json.hbs index 3b808fc5e5..8dd31cbc38 100644 --- a/packages/cli/templates/default-backend-plugin/package.json.hbs +++ b/packages/cli/templates/default-backend-plugin/package.json.hbs @@ -31,7 +31,6 @@ "@backstage/backend-common": "{{versionQuery '@backstage/backend-common'}}", "@backstage/backend-defaults": "{{versionQuery '@backstage/backend-defaults'}}", "@backstage/backend-plugin-api": "{{versionQuery '@backstage/backend-plugin-api'}}", - "@backstage/config": "{{versionQuery '@backstage/config'}}", "express": "{{versionQuery 'express' '4.17.1'}}", "express-promise-router": "{{versionQuery 'express-promise-router' '4.1.0'}}", "node-fetch": "{{versionQuery 'node-fetch' '2.6.7'}}" diff --git a/packages/cli/templates/default-backend-plugin/src/service/router.ts b/packages/cli/templates/default-backend-plugin/src/service/router.ts index 312d7e252e..ced654aa82 100644 --- a/packages/cli/templates/default-backend-plugin/src/service/router.ts +++ b/packages/cli/templates/default-backend-plugin/src/service/router.ts @@ -1,12 +1,11 @@ import { MiddlewareFactory } from '@backstage/backend-defaults/rootHttpRouter'; -import { LoggerService } from '@backstage/backend-plugin-api'; -import { Config } from '@backstage/config'; +import { LoggerService, RootConfigService } from '@backstage/backend-plugin-api'; import express from 'express'; import Router from 'express-promise-router'; export interface RouterOptions { logger: LoggerService; - config: Config; + config: RootConfigService; } export async function createRouter( From ef742dc56e889f254983cd1a0575c0880a104aa0 Mon Sep 17 00:00:00 2001 From: parmar-abhinav <abhinav.parmar@infosys.com> Date: Sun, 21 Jul 2024 12:29:54 +0530 Subject: [PATCH 338/416] Added test cases for gitlab:projectAccessToken:create example Signed-off-by: parmar-abhinav <abhinav.parmar@infosys.com> --- .changeset/six-rats-kick.md | 5 + ...bProjectAccessTokenCreate.examples.test.ts | 256 ++++++++++++++++++ ...gitlabProjectAccessTokenCreate.examples.ts | 158 +++++++++++ .../gitlabProjectAccessTokenCreate.test.ts | 221 +++++++++++++++ 4 files changed, 640 insertions(+) create mode 100644 .changeset/six-rats-kick.md create mode 100644 plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectAccessTokenCreate.test.ts diff --git a/.changeset/six-rats-kick.md b/.changeset/six-rats-kick.md new file mode 100644 index 0000000000..23958a2502 --- /dev/null +++ b/.changeset/six-rats-kick.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend-module-gitlab': patch +--- + +Added test cases for gitlab:projectAccessToken:create example diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectAccessTokenCreate.examples.test.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectAccessTokenCreate.examples.test.ts index 811926cc82..0762212809 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectAccessTokenCreate.examples.test.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectAccessTokenCreate.examples.test.ts @@ -51,6 +51,10 @@ describe('gitlab:projectAccessToken:create examples', () => { host: 'hosted.gitlab.com', apiBaseUrl: 'https://api.hosted.gitlab.com', }, + { + host: 'gitlab.example.com', + apiBaseUrl: 'https://api.gitlab.example.com', + }, ], }, }); @@ -192,4 +196,256 @@ describe('gitlab:projectAccessToken:create examples', () => { expect(mockContext.output).toHaveBeenCalledWith('access_token', 'TOKEN'); }); + + it(`should ${examples[5].description}`, async () => { + mockGitlabClient.ProjectAccessTokens.create.mockResolvedValue({ + token: 'personal-access-token', + username: 'gitlab-user', + }); + + const input = yaml.parse(examples[5].example).steps[0].input; + await action.handler({ + ...mockContext, + input, + }); + + expect(mockGitlabClient.ProjectAccessTokens.create).toHaveBeenCalledWith( + '456', + 'tokenname', + ['read_repository'], + { + accessLevel: 30, + expiresAt: '2025-07-21', + }, + ); + + expect(mockContext.output).toHaveBeenCalledWith( + 'access_token', + 'personal-access-token', + ); + }); + + it(`should ${examples[6].description}`, async () => { + mockGitlabClient.ProjectAccessTokens.create.mockResolvedValue({ + token: 'personal-access-token', + username: 'gitlab-user', + }); + + const input = yaml.parse(examples[6].example).steps[0].input; + await action.handler({ + ...mockContext, + input, + }); + + expect(mockGitlabClient.ProjectAccessTokens.create).toHaveBeenCalledWith( + '456', + 'full-access-token', + ['read_repository'], + { + accessLevel: 40, + expiresAt: '2024-12-31', + }, + ); + + expect(mockContext.output).toHaveBeenCalledWith( + 'access_token', + 'personal-access-token', + ); + }); + + it(`should ${examples[7].description}`, async () => { + mockGitlabClient.ProjectAccessTokens.create.mockResolvedValue({ + token: 'personal-access-token', + username: 'gitlab-user', + }); + + const input = yaml.parse(examples[7].example).steps[0].input; + await action.handler({ + ...mockContext, + input, + }); + + expect(mockGitlabClient.ProjectAccessTokens.create).toHaveBeenCalledWith( + '101112', + 'tokenname', + ['read_repository'], + { + accessLevel: 40, + expiresAt: '2025-07-21', + }, + ); + + expect(mockContext.output).toHaveBeenCalledWith( + 'access_token', + 'personal-access-token', + ); + }); + + it(`should ${examples[8].description}`, async () => { + mockGitlabClient.ProjectAccessTokens.create.mockResolvedValue({ + token: 'personal-access-token', + username: 'gitlab-user', + }); + + const input = yaml.parse(examples[8].example).steps[0].input; + await action.handler({ + ...mockContext, + input, + }); + + expect(mockGitlabClient.ProjectAccessTokens.create).toHaveBeenCalledWith( + '101112', + 'tokenname', + ['read_repository', 'read_api'], + { + accessLevel: 40, + expiresAt: '2025-07-21', + }, + ); + + expect(mockContext.output).toHaveBeenCalledWith( + 'access_token', + 'personal-access-token', + ); + }); + + it(`should ${examples[9].description}`, async () => { + mockGitlabClient.ProjectAccessTokens.create.mockResolvedValue({ + token: 'personal-access-token', + username: 'gitlab-user', + }); + + const input = yaml.parse(examples[9].example).steps[0].input; + await action.handler({ + ...mockContext, + input, + }); + + expect(mockGitlabClient.ProjectAccessTokens.create).toHaveBeenCalledWith( + '101112', + 'tokenname', + ['read_repository'], + { + accessLevel: 10, + expiresAt: '2025-07-21', + }, + ); + + expect(mockContext.output).toHaveBeenCalledWith( + 'access_token', + 'personal-access-token', + ); + }); + + it(`should ${examples[10].description}`, async () => { + mockGitlabClient.ProjectAccessTokens.create.mockResolvedValue({ + token: 'personal-access-token', + username: 'gitlab-user', + }); + + const input = yaml.parse(examples[10].example).steps[0].input; + await action.handler({ + ...mockContext, + input, + }); + + expect(mockGitlabClient.ProjectAccessTokens.create).toHaveBeenCalledWith( + '101112', + 'tokenname', + ['read_repository'], + { + accessLevel: 40, + expiresAt: '2025-07-21', + }, + ); + + expect(mockContext.output).toHaveBeenCalledWith( + 'access_token', + 'personal-access-token', + ); + }); + + it(`should ${examples[11].description}`, async () => { + mockGitlabClient.ProjectAccessTokens.create.mockResolvedValue({ + token: 'personal-access-token', + username: 'gitlab-user', + }); + + const input = yaml.parse(examples[11].example).steps[0].input; + await action.handler({ + ...mockContext, + input, + }); + + expect(mockGitlabClient.ProjectAccessTokens.create).toHaveBeenCalledWith( + '101112', + 'tokenname', + ['read_repository'], + { + accessLevel: 50, + expiresAt: '2025-07-21', + }, + ); + + expect(mockContext.output).toHaveBeenCalledWith( + 'access_token', + 'personal-access-token', + ); + }); + + it(`should ${examples[12].description}`, async () => { + mockGitlabClient.ProjectAccessTokens.create.mockResolvedValue({ + token: 'personal-access-token', + username: 'gitlab-user', + }); + + const input = yaml.parse(examples[12].example).steps[0].input; + await action.handler({ + ...mockContext, + input, + }); + + expect(mockGitlabClient.ProjectAccessTokens.create).toHaveBeenCalledWith( + '101112', + 'no-expiry-token', + ['read_repository'], + { + accessLevel: 40, + expiresAt: '2025-07-21', + }, + ); + + expect(mockContext.output).toHaveBeenCalledWith( + 'access_token', + 'personal-access-token', + ); + }); + + it(`should ${examples[13].description}`, async () => { + mockGitlabClient.ProjectAccessTokens.create.mockResolvedValue({ + token: 'personal-access-token', + username: 'gitlab-user', + }); + + const input = yaml.parse(examples[13].example).steps[0].input; + await action.handler({ + ...mockContext, + input, + }); + + expect(mockGitlabClient.ProjectAccessTokens.create).toHaveBeenCalledWith( + '101112', + 'tokenname', + ['read_repository'], + { + accessLevel: 40, + expiresAt: '2025-07-21', + }, + ); + + expect(mockContext.output).toHaveBeenCalledWith( + 'access_token', + 'personal-access-token', + ); + }); }); diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectAccessTokenCreate.examples.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectAccessTokenCreate.examples.ts index 8d4f335a46..89f8ae6269 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectAccessTokenCreate.examples.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectAccessTokenCreate.examples.ts @@ -102,4 +102,162 @@ export const examples: TemplateExample[] = [ ], }), }, + { + description: 'Create a GitLab project access token with an access level', + example: yaml.stringify({ + steps: [ + { + id: 'createAccessToken', + action: 'gitlab:projectAccessToken:create', + name: 'Create GitLab Project Access Token', + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: '456', + accessLevel: 30, + }, + }, + ], + }), + }, + { + description: 'Create a GitLab project access token with multiple options', + example: yaml.stringify({ + steps: [ + { + id: 'createAccessToken', + action: 'gitlab:projectAccessToken:create', + name: 'Create GitLab Project Access Token', + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: '456', + accessLevel: 40, + name: 'full-access-token', + expiresAt: '2024-12-31', + }, + }, + ], + }), + }, + { + description: + 'Create a GitLab project access token with a token for authorization', + example: yaml.stringify({ + steps: [ + { + id: 'createAccessToken', + action: 'gitlab:projectAccessToken:create', + name: 'Create GitLab Project Access Token', + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: '101112', + token: 'personal-access-token', + }, + }, + ], + }), + }, + { + description: 'Create a GitLab project access token with read-only scopes', + example: yaml.stringify({ + steps: [ + { + id: 'createAccessToken', + action: 'gitlab:projectAccessToken:create', + name: 'Create GitLab Project Access Token', + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: '101112', + scopes: ['read_repository', 'read_api'], + }, + }, + ], + }), + }, + { + description: 'Create a GitLab project access token with guest access level', + example: yaml.stringify({ + steps: [ + { + id: 'createAccessToken', + action: 'gitlab:projectAccessToken:create', + name: 'Create GitLab Project Access Token', + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: '101112', + accessLevel: 10, + }, + }, + ], + }), + }, + { + description: + 'Create a GitLab project access token with maintainer access level', + example: yaml.stringify({ + steps: [ + { + id: 'createAccessToken', + action: 'gitlab:projectAccessToken:create', + name: 'Create GitLab Project Access Token', + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: '101112', + accessLevel: 40, + }, + }, + ], + }), + }, + { + description: 'Create a GitLab project access token with owner access level', + example: yaml.stringify({ + steps: [ + { + id: 'createAccessToken', + action: 'gitlab:projectAccessToken:create', + name: 'Create GitLab Project Access Token', + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: '101112', + accessLevel: 50, + }, + }, + ], + }), + }, + { + description: + 'Create a GitLab project access token with a specified name and no expiration date', + example: yaml.stringify({ + steps: [ + { + id: 'createAccessToken', + action: 'gitlab:projectAccessToken:create', + name: 'Create GitLab Project Access Token', + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: '101112', + name: 'no-expiry-token', + }, + }, + ], + }), + }, + { + description: + 'Create a GitLab project access token for a specific gitlab instance', + example: yaml.stringify({ + steps: [ + { + id: 'createAccessToken', + action: 'gitlab:projectAccessToken:create', + name: 'Create GitLab Project Access Token', + input: { + repoUrl: 'gitlab.example.com?repo=repo&owner=owner', + projectId: '101112', + }, + }, + ], + }), + }, ]; diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectAccessTokenCreate.test.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectAccessTokenCreate.test.ts new file mode 100644 index 0000000000..34ce8878f2 --- /dev/null +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectAccessTokenCreate.test.ts @@ -0,0 +1,221 @@ +/* + * Copyright 2024 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 { ScmIntegrations } from '@backstage/integration'; +import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test-utils'; +import { createGitlabProjectAccessTokenAction } from './gitlabProjectAccessTokenCreate'; // Adjust the import based on your project structure + +import { DateTime } from 'luxon'; + +jest.mock('node-fetch'); + +const mockGitlabClient = { + ProjectAccessTokens: { + create: jest.fn(), + }, +}; + +jest.mock('@gitbeaker/rest', () => ({ + Gitlab: class { + constructor() { + return mockGitlabClient; + } + }, +})); + +describe('gitlab:projectAccessToken:create examples', () => { + const config = new ConfigReader({ + integrations: { + gitlab: [ + { + host: 'gitlab.com', + token: 'gitlab-token', + apiBaseUrl: 'https://api.gitlab.com', + }, + { + host: 'hosted.gitlab.com', + apiBaseUrl: 'https://api.hosted.gitlab.com', + }, + ], + }, + }); + + const integrations = ScmIntegrations.fromConfig(config); + const action = createGitlabProjectAccessTokenAction({ integrations }); + + const mockContext = createMockActionContext({ + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + }, + }); + + beforeEach(() => { + jest.resetAllMocks(); + }); + + it('should create a GitLab project access token with minimal options.', async () => { + mockGitlabClient.ProjectAccessTokens.create.mockResolvedValue({ + token: 'gitlab-token', + username: 'gitlab-user', + }); + + await action.handler({ + ...mockContext, + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: '987', + }, + }); + + expect(mockGitlabClient.ProjectAccessTokens.create).toHaveBeenCalledWith( + '987', + 'tokenname', + ['read_repository'], + { + accessLevel: 40, + expiresAt: DateTime.now().plus({ days: 365 }).toISODate()!, + }, + ); + + expect(mockContext.output).toHaveBeenCalledWith( + 'access_token', + 'gitlab-token', + ); + }); + + it('should create a GitLab project access token with custom scopes.', async () => { + mockGitlabClient.ProjectAccessTokens.create.mockResolvedValue({ + token: 'gitlab-token', + username: 'gitlab-user', + }); + + await action.handler({ + ...mockContext, + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: '987', + scopes: ['read_registry', 'write_repository'], + }, + }); + + expect(mockGitlabClient.ProjectAccessTokens.create).toHaveBeenCalledWith( + '987', + 'tokenname', + ['read_registry', 'write_repository'], + { + accessLevel: 40, + expiresAt: DateTime.now().plus({ days: 365 }).toISODate()!, + }, + ); + + expect(mockContext.output).toHaveBeenCalledWith( + 'access_token', + 'gitlab-token', + ); + }); + + it('should create a GitLab project access token with a specified name.', async () => { + mockGitlabClient.ProjectAccessTokens.create.mockResolvedValue({ + token: 'gitlab-token', + username: 'gitlab-user', + }); + + await action.handler({ + ...mockContext, + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: '2110', + name: 'token', + }, + }); + + expect(mockGitlabClient.ProjectAccessTokens.create).toHaveBeenCalledWith( + '2110', + 'token', + ['read_repository'], + { + accessLevel: 40, + expiresAt: DateTime.now().plus({ days: 365 }).toISODate()!, + }, + ); + + expect(mockContext.output).toHaveBeenCalledWith( + 'access_token', + 'gitlab-token', + ); + }); + + it('should create a GitLab project access token with a numeric project ID.', async () => { + mockGitlabClient.ProjectAccessTokens.create.mockResolvedValue({ + token: 'gitlab-token', + username: 'gitlab-user', + }); + + await action.handler({ + ...mockContext, + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: 23, + }, + }); + + expect(mockGitlabClient.ProjectAccessTokens.create).toHaveBeenCalledWith( + 23, + 'tokenname', + ['read_repository'], + { + accessLevel: 40, + expiresAt: DateTime.now().plus({ days: 365 }).toISODate()!, + }, + ); + + expect(mockContext.output).toHaveBeenCalledWith( + 'access_token', + 'gitlab-token', + ); + }); + + it('should create a GitLab project access token with a specified expired Date.', async () => { + mockGitlabClient.ProjectAccessTokens.create.mockResolvedValue({ + token: 'gitlab-token', + username: 'gitlab-user', + }); + + await action.handler({ + ...mockContext, + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: '123', + expiresAt: '1999-07-14', + }, + }); + + expect(mockGitlabClient.ProjectAccessTokens.create).toHaveBeenCalledWith( + '123', + 'tokenname', + ['read_repository'], + { + accessLevel: 40, + expiresAt: '1999-07-14', + }, + ); + + expect(mockContext.output).toHaveBeenCalledWith( + 'access_token', + 'gitlab-token', + ); + }); +}); From fba7537ad1fd83d9578d71ea546b36b3cf1be9f3 Mon Sep 17 00:00:00 2001 From: Jordan Slott <jordan.slott@twosigma.com> Date: Sun, 21 Jul 2024 15:31:35 -0400 Subject: [PATCH 339/416] Fixes #25709 Memoize filtered entity graph nodes Signed-off-by: Jordan Slott <jordan.slott@twosigma.com> --- .changeset/light-pianos-exercise.md | 5 +++++ .../EntityRelationsGraph/useEntityRelationGraph.ts | 12 ++++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) create mode 100644 .changeset/light-pianos-exercise.md diff --git a/.changeset/light-pianos-exercise.md b/.changeset/light-pianos-exercise.md new file mode 100644 index 0000000000..4bf161eb06 --- /dev/null +++ b/.changeset/light-pianos-exercise.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-graph': patch +--- + +Memoize entity graph nodes when applying an `entityFilter` to prevent repeated redraws diff --git a/plugins/catalog-graph/src/components/EntityRelationsGraph/useEntityRelationGraph.ts b/plugins/catalog-graph/src/components/EntityRelationsGraph/useEntityRelationGraph.ts index af2a491ada..07e3085f1f 100644 --- a/plugins/catalog-graph/src/components/EntityRelationsGraph/useEntityRelationGraph.ts +++ b/plugins/catalog-graph/src/components/EntityRelationsGraph/useEntityRelationGraph.ts @@ -14,7 +14,7 @@ * limitations under the License. */ import { Entity } from '@backstage/catalog-model'; -import { useEffect } from 'react'; +import { useEffect, useMemo } from 'react'; import { useEntityStore } from './useEntityStore'; import { pickBy } from 'lodash'; @@ -104,9 +104,13 @@ export function useEntityRelationGraph({ requestEntities, ]); - const filteredEntities = entityFilter - ? pickBy(entities, (value, _key) => entityFilter(value)) - : entities; + const filteredEntities = useMemo( + () => + entityFilter + ? pickBy(entities, (value, _key) => entityFilter(value)) + : entities, + [entities, entityFilter], + ); return { entities: filteredEntities, From 4e79d199ccb03c1b57dd4b889b83c058b13fd399 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg <poldsberg@gmail.com> Date: Wed, 17 Jul 2024 19:59:42 +0200 Subject: [PATCH 340/416] backend-defaults,test-utils: use, export, and test health service Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com> --- .changeset/gentle-dryers-smile.md | 5 ++ .changeset/soft-gorillas-refuse.md | 5 ++ .../api-report-rootHttpRouter.md | 8 ++ .../rootHttpRouter/createHealthRouter.ts | 6 +- .../src/entrypoints/rootHttpRouter/index.ts | 1 + .../rootHttpRouterServiceFactory.test.ts | 74 +++++++++++++++++++ .../src/next/wiring/TestBackend.test.ts | 9 +++ .../src/next/wiring/TestBackend.ts | 7 +- 8 files changed, 112 insertions(+), 3 deletions(-) create mode 100644 .changeset/gentle-dryers-smile.md create mode 100644 .changeset/soft-gorillas-refuse.md create mode 100644 packages/backend-defaults/src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.test.ts diff --git a/.changeset/gentle-dryers-smile.md b/.changeset/gentle-dryers-smile.md new file mode 100644 index 0000000000..b061461da1 --- /dev/null +++ b/.changeset/gentle-dryers-smile.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-defaults': patch +--- + +The `createHealthRouter` utility that allows you to create a health check router is now exported via `@backstage/backend-defaults/rootHttpRouter`. diff --git a/.changeset/soft-gorillas-refuse.md b/.changeset/soft-gorillas-refuse.md new file mode 100644 index 0000000000..323c4d20d2 --- /dev/null +++ b/.changeset/soft-gorillas-refuse.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-test-utils': patch +--- + +The default services for `startTestBackend` and `ServiceFactoryTester` now includes the Root Health Service. diff --git a/packages/backend-defaults/api-report-rootHttpRouter.md b/packages/backend-defaults/api-report-rootHttpRouter.md index 329398a7b8..36f3aa3ab6 100644 --- a/packages/backend-defaults/api-report-rootHttpRouter.md +++ b/packages/backend-defaults/api-report-rootHttpRouter.md @@ -3,6 +3,7 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +/// <reference types="express" /> /// <reference types="node" /> import { Config } from '@backstage/config'; @@ -17,10 +18,17 @@ import { LoggerService } from '@backstage/backend-plugin-api'; import { RequestHandler } from 'express'; import { RequestListener } from 'http'; import { RootConfigService } from '@backstage/backend-plugin-api'; +import { RootHealthService } from '@backstage/backend-plugin-api'; import { RootHttpRouterService } from '@backstage/backend-plugin-api'; +import { Router } from 'express'; import type { Server } from 'node:http'; import { ServiceFactory } from '@backstage/backend-plugin-api'; +// @public (undocumented) +export function createHealthRouter(options: { + health: RootHealthService; +}): Router; + // @public export function createHttpServer( listener: RequestListener, diff --git a/packages/backend-defaults/src/entrypoints/rootHttpRouter/createHealthRouter.ts b/packages/backend-defaults/src/entrypoints/rootHttpRouter/createHealthRouter.ts index 007d1dd9cd..3772ab0fab 100644 --- a/packages/backend-defaults/src/entrypoints/rootHttpRouter/createHealthRouter.ts +++ b/packages/backend-defaults/src/entrypoints/rootHttpRouter/createHealthRouter.ts @@ -1,5 +1,3 @@ -import { RootHealthService } from '@backstage/backend-plugin-api'; - /* * Copyright 2024 The Backstage Authors * @@ -16,9 +14,13 @@ import { RootHealthService } from '@backstage/backend-plugin-api'; * limitations under the License. */ +import { RootHealthService } from '@backstage/backend-plugin-api'; import Router from 'express-promise-router'; import { Request, Response } from 'express'; +/** + * @public + */ export function createHealthRouter(options: { health: RootHealthService }) { const router = Router(); diff --git a/packages/backend-defaults/src/entrypoints/rootHttpRouter/index.ts b/packages/backend-defaults/src/entrypoints/rootHttpRouter/index.ts index 9c2d96dab2..e9aee8a0e0 100644 --- a/packages/backend-defaults/src/entrypoints/rootHttpRouter/index.ts +++ b/packages/backend-defaults/src/entrypoints/rootHttpRouter/index.ts @@ -18,6 +18,7 @@ export { DefaultRootHttpRouter, type DefaultRootHttpRouterOptions, } from './DefaultRootHttpRouter'; +export { createHealthRouter } from './createHealthRouter'; export * from './http'; export { rootHttpRouterServiceFactory, diff --git a/packages/backend-defaults/src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.test.ts b/packages/backend-defaults/src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.test.ts new file mode 100644 index 0000000000..dea0159dff --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.test.ts @@ -0,0 +1,74 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + ServiceFactoryTester, + mockServices, +} from '@backstage/backend-test-utils'; +import { Express } from 'express'; +import request from 'supertest'; +import { rootHttpRouterServiceFactory } from './rootHttpRouterServiceFactory'; +import { coreServices } from '@backstage/backend-plugin-api'; + +describe('rootHttpRouterServiceFactory', () => { + it('should make the health endpoints available', async () => { + let app: Express | undefined = undefined; + + const tester = ServiceFactoryTester.from( + rootHttpRouterServiceFactory({ + configure(options) { + options.applyDefaults(); + app = options.app; + }, + }), + { + dependencies: [ + mockServices.rootConfig.factory({ + data: { + app: { baseUrl: 'http://localhost' }, + backend: { + baseUrl: 'http://localhost', + listen: { host: '', port: 0 }, + }, + }, + }), + ], + }, + ); + + // Trigger creation of the http service, accessing the app instance through the configure callback + await tester.getSubject(); + + await request(app!) + .get('/.backstage/health/v1/liveness') + .expect(200, { status: 'ok' }); + + await request(app!).get('/.backstage/health/v1/readiness').expect(503, { + message: 'Backend has not started yet', + status: 'error', + }); + + const lifecycle = await tester.getService(coreServices.rootLifecycle); + + await (lifecycle as any).startup(); // Trigger startup by calling the private startup method + + await request(app!).get('/.backstage/health/v1/readiness').expect(200, { + status: 'ok', + }); + + expect('test').toBe('test'); + }); +}); 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 ecba34290d..a01d4bebf5 100644 --- a/packages/backend-test-utils/src/next/wiring/TestBackend.test.ts +++ b/packages/backend-test-utils/src/next/wiring/TestBackend.test.ts @@ -242,6 +242,15 @@ describe('TestBackend', () => { expect(res.body).toEqual({ message: 'pong' }); }); + it('should expose health check endpoints', async () => { + const { server } = await startTestBackend({ features: [] }); + + const res = await request(server).get('/.backstage/health/v1/liveness'); + + expect(res.status).toEqual(200); + expect(res.body).toEqual({ status: 'ok' }); + }); + it('should provide extension point implementations', async () => { expect.assertions(3); diff --git a/packages/backend-test-utils/src/next/wiring/TestBackend.ts b/packages/backend-test-utils/src/next/wiring/TestBackend.ts index 16ee6b78d2..3d662a8c12 100644 --- a/packages/backend-test-utils/src/next/wiring/TestBackend.ts +++ b/packages/backend-test-utils/src/next/wiring/TestBackend.ts @@ -37,6 +37,7 @@ import express from 'express'; // Direct internal import to avoid duplication // eslint-disable-next-line @backstage/no-forbidden-package-imports import { InternalBackendFeature } from '@backstage/backend-plugin-api/src/wiring/types'; +import { createHealthRouter } from '@backstage/backend-defaults/rootHttpRouter'; /** @public */ export interface TestBackendOptions<TExtensionPoints extends any[]> { @@ -73,6 +74,7 @@ export const defaultServiceFactories = [ mockServices.lifecycle.factory(), mockServices.logger.factory(), mockServices.permissions.factory(), + mockServices.rootHealth.factory(), mockServices.rootLifecycle.factory(), mockServices.rootLogger.factory(), mockServices.scheduler.factory(), @@ -251,15 +253,18 @@ export async function startTestBackend<TExtensionPoints extends any[]>( config: coreServices.rootConfig, lifecycle: coreServices.rootLifecycle, rootLogger: coreServices.rootLogger, + health: coreServices.rootHealth, }, - async factory({ config, lifecycle, rootLogger }) { + async factory({ config, lifecycle, rootLogger, health }) { const router = DefaultRootHttpRouter.create(); const logger = rootLogger.child({ service: 'rootHttpRouter' }); const app = express(); const middleware = MiddlewareFactory.create({ config, logger }); + const healthRouter = createHealthRouter({ health }); + app.use(healthRouter); app.use(router.handler()); app.use(middleware.notFound()); app.use(middleware.error()); From 31bfc4417f7a4d04d5899ce1d638505c30f9f627 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg <poldsberg@gmail.com> Date: Sat, 20 Jul 2024 12:47:09 +0200 Subject: [PATCH 341/416] frontend-plugin-api: update extension data ref declaration to allow embedding of ID in type Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com> --- .changeset/dull-ghosts-double.md | 7 ++ .changeset/tiny-oranges-pretend.md | 19 ++++++ .../architecture/03-extensions.md | 4 +- .../architecture/08-naming-patterns.md | 20 +++--- .../src/tree/instantiateAppNodeTree.test.ts | 8 ++- packages/frontend-plugin-api/api-report.md | 52 +++++++++++--- .../src/extensions/createApiExtension.ts | 5 +- .../createAppRootWrapperExtension.tsx | 7 +- .../extensions/createComponentExtension.tsx | 2 +- .../src/extensions/createNavItemExtension.tsx | 2 +- .../src/extensions/createNavLogoExtension.tsx | 2 +- .../src/extensions/createRouterExtension.tsx | 7 +- .../extensions/createSignInPageExtension.tsx | 2 +- .../src/extensions/createThemeExtension.ts | 5 +- .../extensions/createTranslationExtension.ts | 2 +- .../src/wiring/coreExtensionData.ts | 8 ++- .../src/wiring/createExtension.test.ts | 2 +- .../src/wiring/createExtension.ts | 2 +- .../src/wiring/createExtensionDataRef.test.ts | 9 +++ .../src/wiring/createExtensionDataRef.ts | 68 +++++++++++++------ .../src/wiring/createPlugin.test.ts | 4 +- plugins/catalog-react/api-report-alpha.md | 13 +++- plugins/catalog-react/src/alpha.tsx | 18 ++--- plugins/home/api-report-alpha.md | 6 +- plugins/home/src/alpha.tsx | 4 +- plugins/search-react/api-report-alpha.md | 1 + plugins/search-react/src/alpha.tsx | 2 +- 27 files changed, 204 insertions(+), 77 deletions(-) create mode 100644 .changeset/dull-ghosts-double.md create mode 100644 .changeset/tiny-oranges-pretend.md diff --git a/.changeset/dull-ghosts-double.md b/.changeset/dull-ghosts-double.md new file mode 100644 index 0000000000..0bc5a09791 --- /dev/null +++ b/.changeset/dull-ghosts-double.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-catalog-react': patch +'@backstage/plugin-search-react': patch +'@backstage/plugin-home': patch +--- + +Updated alpha definitions of extension data references. diff --git a/.changeset/tiny-oranges-pretend.md b/.changeset/tiny-oranges-pretend.md new file mode 100644 index 0000000000..87227fb962 --- /dev/null +++ b/.changeset/tiny-oranges-pretend.md @@ -0,0 +1,19 @@ +--- +'@backstage/frontend-plugin-api': patch +--- + +Extension data references can now be defined in a way that encapsulates the ID string in the type, in addition to the data type itself. The old way of creating extension data references is deprecated and will be removed in a future release. + +For example, the following code: + +```ts +export const myExtension = createExtensionDataRef<MyType>('my-plugin.my-data'); +``` + +Should be updated to the following: + +```ts +export const myExtension = createExtensionDataRef<MyType>().with({ + id: 'my-plugin.my-data', +}); +``` diff --git a/docs/frontend-system/architecture/03-extensions.md b/docs/frontend-system/architecture/03-extensions.md index cdc73a17ec..2f3daba6f8 100644 --- a/docs/frontend-system/architecture/03-extensions.md +++ b/docs/frontend-system/architecture/03-extensions.md @@ -91,7 +91,9 @@ To create a new extension data reference to represent a type of shared extension ```ts export const reactElementExtensionDataRef = - createExtensionDataRef<React.JSX.Element>('my-plugin.reactElement'); + createExtensionDataRef<React.JSX.Element>().with({ + id: 'my-plugin.reactElement', + }); ``` The `ExtensionDataRef` can then be used to describe an output property of the extension. This will enforce typing on the return value of the extension factory: diff --git a/docs/frontend-system/architecture/08-naming-patterns.md b/docs/frontend-system/architecture/08-naming-patterns.md index a17525f3ce..f031b80d84 100644 --- a/docs/frontend-system/architecture/08-naming-patterns.md +++ b/docs/frontend-system/architecture/08-naming-patterns.md @@ -98,9 +98,9 @@ export interface SearchResultItemExtensionData { } export const searchResultItemExtensionDataRef = - createExtensionDataRef<SearchResultItemExtensionData>( - 'search.search-result-item', - ); + createExtensionDataRef<SearchResultItemExtensionData>().with({ + id: 'search.search-result-item', + }); ``` #### Grouped Extension Data @@ -109,8 +109,12 @@ This way of defining extension data is similar to the standalone way, but it use ```ts export const coreExtensionData = { - reactElement: createExtensionDataRef<ReactElement>('core.react-element'), - routePath: createExtensionDataRef<string>('core.route-path'), + reactElement: createExtensionDataRef<ReactElement>().with({ + id: 'core.react-element', + }), + routePath: createExtensionDataRef<string>().with({ + id: 'core.route-path', + }), }; ``` @@ -125,9 +129,9 @@ export function createGraphiQLEndpointExtension(options) { // Use a TypeScript namespace to merge the extension data references with the extension creator export namespace createGraphiQLEndpointExtension { - export const endpointDataRef = createExtensionDataRef</* ... */>( - 'graphiql.graphiql-endpoint.endpoint', - ); + export const endpointDataRef = createExtensionDataRef</* ... */>().with({ + id: 'graphiql.graphiql-endpoint.endpoint', + }); } ``` diff --git a/packages/frontend-app-api/src/tree/instantiateAppNodeTree.test.ts b/packages/frontend-app-api/src/tree/instantiateAppNodeTree.test.ts index 3330b9add8..c5c66e8319 100644 --- a/packages/frontend-app-api/src/tree/instantiateAppNodeTree.test.ts +++ b/packages/frontend-app-api/src/tree/instantiateAppNodeTree.test.ts @@ -32,9 +32,11 @@ import { resolveAppTree } from './resolveAppTree'; import { resolveExtensionDefinition } from '../../../frontend-plugin-api/src/wiring/resolveExtensionDefinition'; import { withLogCollector } from '@backstage/test-utils'; -const testDataRef = createExtensionDataRef<string>('test'); -const otherDataRef = createExtensionDataRef<number>('other'); -const inputMirrorDataRef = createExtensionDataRef<unknown>('mirror'); +const testDataRef = createExtensionDataRef<string>().with({ id: 'test' }); +const otherDataRef = createExtensionDataRef<number>().with({ id: 'other' }); +const inputMirrorDataRef = createExtensionDataRef<unknown>().with({ + id: 'mirror', +}); const simpleExtension = resolveExtensionDefinition( createExtension({ diff --git a/packages/frontend-plugin-api/api-report.md b/packages/frontend-plugin-api/api-report.md index 29c165aaaa..65445b5c4d 100644 --- a/packages/frontend-plugin-api/api-report.md +++ b/packages/frontend-plugin-api/api-report.md @@ -151,6 +151,7 @@ export { AnyApiRef }; export type AnyExtensionDataMap = { [name in string]: ExtensionDataRef< unknown, + string, { optional?: true; } @@ -317,13 +318,15 @@ export { configApiRef }; // @public (undocumented) export interface ConfigurableExtensionDataRef< + TId extends string, TData, TConfig extends { optional?: true; } = {}, -> extends ExtensionDataRef<TData, TConfig> { +> extends ExtensionDataRef<TData, TId, TConfig> { // (undocumented) optional(): ConfigurableExtensionDataRef< + TId, TData, TData & { optional: true; @@ -347,9 +350,17 @@ export type CoreErrorBoundaryFallbackProps = { // @public (undocumented) export const coreExtensionData: { - reactElement: ConfigurableExtensionDataRef<JSX_2.Element, {}>; - routePath: ConfigurableExtensionDataRef<string, {}>; - routeRef: ConfigurableExtensionDataRef<RouteRef<AnyRouteRefParams>, {}>; + reactElement: ConfigurableExtensionDataRef< + 'core.reactElement', + JSX_2.Element, + {} + >; + routePath: ConfigurableExtensionDataRef<'core.routing.path', string, {}>; + routeRef: ConfigurableExtensionDataRef< + 'core.routing.ref', + RouteRef<AnyRouteRefParams>, + {} + >; }; // @public (undocumented) @@ -385,7 +396,11 @@ export function createApiExtension< // @public (undocumented) export namespace createApiExtension { const // (undocumented) - factoryDataRef: ConfigurableExtensionDataRef<AnyApiFactory, {}>; + factoryDataRef: ConfigurableExtensionDataRef< + 'core.api.factory', + AnyApiFactory, + {} + >; } export { createApiFactory }; @@ -440,6 +455,7 @@ export function createAppRootWrapperExtension< export namespace createAppRootWrapperExtension { const // (undocumented) componentDataRef: ConfigurableExtensionDataRef< + 'app.root.wrapper', React_2.ComponentType<{ children?: React_2.ReactNode; }>, @@ -477,6 +493,7 @@ export function createComponentExtension< export namespace createComponentExtension { const // (undocumented) componentDataRef: ConfigurableExtensionDataRef< + 'core.component.component', { ref: ComponentRef; impl: ComponentType; @@ -544,10 +561,17 @@ export interface CreateExtensionBlueprintOptions< output: TOutput; } -// @public (undocumented) +// @public @deprecated (undocumented) export function createExtensionDataRef<TData>( id: string, -): ConfigurableExtensionDataRef<TData>; +): ConfigurableExtensionDataRef<string, TData>; + +// @public (undocumented) +export function createExtensionDataRef<TData>(): { + with<TId extends string>(options: { + id: TId; + }): ConfigurableExtensionDataRef<TId, TData>; +}; // @public (undocumented) export function createExtensionInput< @@ -646,6 +670,7 @@ export function createNavItemExtension(options: { export namespace createNavItemExtension { const // (undocumented) targetDataRef: ConfigurableExtensionDataRef< + 'core.nav-item.target', { title: string; icon: IconComponent_2; @@ -667,6 +692,7 @@ export function createNavLogoExtension(options: { export namespace createNavLogoExtension { const // (undocumented) logoElementsDataRef: ConfigurableExtensionDataRef< + 'core.nav-logo.logo-elements', { logoIcon?: JSX.Element | undefined; logoFull?: JSX.Element | undefined; @@ -760,6 +786,7 @@ export function createRouterExtension< export namespace createRouterExtension { const // (undocumented) componentDataRef: ConfigurableExtensionDataRef< + 'app.router.wrapper', React_2.ComponentType<{ children?: React_2.ReactNode; }>, @@ -796,6 +823,7 @@ export function createSignInPageExtension< export namespace createSignInPageExtension { const // (undocumented) componentDataRef: ConfigurableExtensionDataRef< + 'core.sign-in-page.component', React_2.ComponentType<SignInPageProps>, {} >; @@ -818,7 +846,11 @@ export function createThemeExtension( // @public (undocumented) export namespace createThemeExtension { const // (undocumented) - themeDataRef: ConfigurableExtensionDataRef<AppTheme, {}>; + themeDataRef: ConfigurableExtensionDataRef< + 'core.theme.theme', + AppTheme, + {} + >; } // @public (undocumented) @@ -831,6 +863,7 @@ export function createTranslationExtension(options: { export namespace createTranslationExtension { const // (undocumented) translationDataRef: ConfigurableExtensionDataRef< + 'core.translation.translation', | TranslationResource<string> | TranslationMessages< string, @@ -934,11 +967,12 @@ export interface ExtensionBoundaryProps { // @public (undocumented) export type ExtensionDataRef< TData, + TId extends string = string, TConfig extends { optional?: true; } = {}, > = { - id: string; + id: TId; T: TData; config: TConfig; $$type: '@backstage/ExtensionDataRef'; diff --git a/packages/frontend-plugin-api/src/extensions/createApiExtension.ts b/packages/frontend-plugin-api/src/extensions/createApiExtension.ts index 1680332960..93346f1ec9 100644 --- a/packages/frontend-plugin-api/src/extensions/createApiExtension.ts +++ b/packages/frontend-plugin-api/src/extensions/createApiExtension.ts @@ -72,6 +72,7 @@ export function createApiExtension< /** @public */ export namespace createApiExtension { - export const factoryDataRef = - createExtensionDataRef<AnyApiFactory>('core.api.factory'); + export const factoryDataRef = createExtensionDataRef<AnyApiFactory>().with({ + id: 'core.api.factory', + }); } diff --git a/packages/frontend-plugin-api/src/extensions/createAppRootWrapperExtension.tsx b/packages/frontend-plugin-api/src/extensions/createAppRootWrapperExtension.tsx index bbc51806af..ce2eb89f25 100644 --- a/packages/frontend-plugin-api/src/extensions/createAppRootWrapperExtension.tsx +++ b/packages/frontend-plugin-api/src/extensions/createAppRootWrapperExtension.tsx @@ -77,8 +77,7 @@ export function createAppRootWrapperExtension< /** @public */ export namespace createAppRootWrapperExtension { - export const componentDataRef = - createExtensionDataRef<ComponentType<PropsWithChildren<{}>>>( - 'app.root.wrapper', - ); + export const componentDataRef = createExtensionDataRef< + ComponentType<PropsWithChildren<{}>> + >().with({ id: 'app.root.wrapper' }); } diff --git a/packages/frontend-plugin-api/src/extensions/createComponentExtension.tsx b/packages/frontend-plugin-api/src/extensions/createComponentExtension.tsx index a1231d8353..a40ee3b069 100644 --- a/packages/frontend-plugin-api/src/extensions/createComponentExtension.tsx +++ b/packages/frontend-plugin-api/src/extensions/createComponentExtension.tsx @@ -92,5 +92,5 @@ export namespace createComponentExtension { export const componentDataRef = createExtensionDataRef<{ ref: ComponentRef; impl: ComponentType; - }>('core.component.component'); + }>().with({ id: 'core.component.component' }); } diff --git a/packages/frontend-plugin-api/src/extensions/createNavItemExtension.tsx b/packages/frontend-plugin-api/src/extensions/createNavItemExtension.tsx index 4b92d4dace..2a2c47835a 100644 --- a/packages/frontend-plugin-api/src/extensions/createNavItemExtension.tsx +++ b/packages/frontend-plugin-api/src/extensions/createNavItemExtension.tsx @@ -61,5 +61,5 @@ export namespace createNavItemExtension { title: string; icon: IconComponent; routeRef: RouteRef<undefined>; - }>('core.nav-item.target'); + }>().with({ id: 'core.nav-item.target' }); } diff --git a/packages/frontend-plugin-api/src/extensions/createNavLogoExtension.tsx b/packages/frontend-plugin-api/src/extensions/createNavLogoExtension.tsx index 3d66b26d6b..1f2419bd02 100644 --- a/packages/frontend-plugin-api/src/extensions/createNavLogoExtension.tsx +++ b/packages/frontend-plugin-api/src/extensions/createNavLogoExtension.tsx @@ -51,5 +51,5 @@ export namespace createNavLogoExtension { export const logoElementsDataRef = createExtensionDataRef<{ logoIcon?: JSX.Element; logoFull?: JSX.Element; - }>('core.nav-logo.logo-elements'); + }>().with({ id: 'core.nav-logo.logo-elements' }); } diff --git a/packages/frontend-plugin-api/src/extensions/createRouterExtension.tsx b/packages/frontend-plugin-api/src/extensions/createRouterExtension.tsx index 32d61f7e60..12f946e8a7 100644 --- a/packages/frontend-plugin-api/src/extensions/createRouterExtension.tsx +++ b/packages/frontend-plugin-api/src/extensions/createRouterExtension.tsx @@ -77,8 +77,7 @@ export function createRouterExtension< /** @public */ export namespace createRouterExtension { - export const componentDataRef = - createExtensionDataRef<ComponentType<PropsWithChildren<{}>>>( - 'app.router.wrapper', - ); + export const componentDataRef = createExtensionDataRef< + ComponentType<PropsWithChildren<{}>> + >().with({ id: 'app.router.wrapper' }); } diff --git a/packages/frontend-plugin-api/src/extensions/createSignInPageExtension.tsx b/packages/frontend-plugin-api/src/extensions/createSignInPageExtension.tsx index b525cc3a7b..312d30c78c 100644 --- a/packages/frontend-plugin-api/src/extensions/createSignInPageExtension.tsx +++ b/packages/frontend-plugin-api/src/extensions/createSignInPageExtension.tsx @@ -79,5 +79,5 @@ export function createSignInPageExtension< export namespace createSignInPageExtension { export const componentDataRef = createExtensionDataRef< ComponentType<SignInPageProps> - >('core.sign-in-page.component'); + >().with({ id: 'core.sign-in-page.component' }); } diff --git a/packages/frontend-plugin-api/src/extensions/createThemeExtension.ts b/packages/frontend-plugin-api/src/extensions/createThemeExtension.ts index cc6dbdabe9..1740f05a5a 100644 --- a/packages/frontend-plugin-api/src/extensions/createThemeExtension.ts +++ b/packages/frontend-plugin-api/src/extensions/createThemeExtension.ts @@ -33,6 +33,7 @@ export function createThemeExtension(theme: AppTheme) { /** @public */ export namespace createThemeExtension { - export const themeDataRef = - createExtensionDataRef<AppTheme>('core.theme.theme'); + export const themeDataRef = createExtensionDataRef<AppTheme>().with({ + id: 'core.theme.theme', + }); } diff --git a/packages/frontend-plugin-api/src/extensions/createTranslationExtension.ts b/packages/frontend-plugin-api/src/extensions/createTranslationExtension.ts index 8497a64b88..9445e32e24 100644 --- a/packages/frontend-plugin-api/src/extensions/createTranslationExtension.ts +++ b/packages/frontend-plugin-api/src/extensions/createTranslationExtension.ts @@ -38,5 +38,5 @@ export function createTranslationExtension(options: { export namespace createTranslationExtension { export const translationDataRef = createExtensionDataRef< TranslationResource | TranslationMessages - >('core.translation.translation'); + >().with({ id: 'core.translation.translation' }); } diff --git a/packages/frontend-plugin-api/src/wiring/coreExtensionData.ts b/packages/frontend-plugin-api/src/wiring/coreExtensionData.ts index a6ff41f6b0..cb48cb8df3 100644 --- a/packages/frontend-plugin-api/src/wiring/coreExtensionData.ts +++ b/packages/frontend-plugin-api/src/wiring/coreExtensionData.ts @@ -20,7 +20,9 @@ import { createExtensionDataRef } from './createExtensionDataRef'; /** @public */ export const coreExtensionData = { - reactElement: createExtensionDataRef<JSX.Element>('core.reactElement'), - routePath: createExtensionDataRef<string>('core.routing.path'), - routeRef: createExtensionDataRef<RouteRef>('core.routing.ref'), + reactElement: createExtensionDataRef<JSX.Element>().with({ + id: 'core.reactElement', + }), + routePath: createExtensionDataRef<string>().with({ id: 'core.routing.path' }), + routeRef: createExtensionDataRef<RouteRef>().with({ id: 'core.routing.ref' }), }; diff --git a/packages/frontend-plugin-api/src/wiring/createExtension.test.ts b/packages/frontend-plugin-api/src/wiring/createExtension.test.ts index 42ab21db80..4323737540 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtension.test.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtension.test.ts @@ -18,7 +18,7 @@ import { createExtension } from './createExtension'; import { createExtensionDataRef } from './createExtensionDataRef'; import { createExtensionInput } from './createExtensionInput'; -const stringData = createExtensionDataRef<string>('string'); +const stringData = createExtensionDataRef<string>().with({ id: 'string' }); function unused(..._any: any[]) {} diff --git a/packages/frontend-plugin-api/src/wiring/createExtension.ts b/packages/frontend-plugin-api/src/wiring/createExtension.ts index 28dc6a4e29..e87f3a638e 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtension.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtension.ts @@ -22,7 +22,7 @@ import { ExtensionInput } from './createExtensionInput'; /** @public */ export type AnyExtensionDataMap = { - [name in string]: ExtensionDataRef<unknown, { optional?: true }>; + [name in string]: ExtensionDataRef<unknown, string, { optional?: true }>; }; /** @public */ diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionDataRef.test.ts b/packages/frontend-plugin-api/src/wiring/createExtensionDataRef.test.ts index f7a0dc82d0..f979a7def0 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtensionDataRef.test.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtensionDataRef.test.ts @@ -18,6 +18,15 @@ import { createExtensionDataRef } from './createExtensionDataRef'; describe('createExtensionDataRef', () => { it('can be created and read', () => { + const ref = createExtensionDataRef().with({ id: 'foo' }); + expect(ref.id).toBe('foo'); + expect(String(ref)).toBe('ExtensionDataRef{id=foo,optional=false}'); + const refOptional = ref.optional(); + expect(refOptional.id).toBe('foo'); + expect(String(refOptional)).toBe('ExtensionDataRef{id=foo,optional=true}'); + }); + + it('can be created and read in the deprecated way', () => { const ref = createExtensionDataRef('foo'); expect(ref.id).toBe('foo'); expect(String(ref)).toBe('ExtensionDataRef{id=foo,optional=false}'); diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionDataRef.ts b/packages/frontend-plugin-api/src/wiring/createExtensionDataRef.ts index a7f4e4374e..a1c7b462f2 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtensionDataRef.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtensionDataRef.ts @@ -17,9 +17,10 @@ /** @public */ export type ExtensionDataRef< TData, + TId extends string = string, TConfig extends { optional?: true } = {}, > = { - id: string; + id: TId; T: TData; config: TConfig; $$type: '@backstage/ExtensionDataRef'; @@ -27,30 +28,59 @@ export type ExtensionDataRef< /** @public */ export interface ConfigurableExtensionDataRef< + TId extends string, TData, TConfig extends { optional?: true } = {}, -> extends ExtensionDataRef<TData, TConfig> { - optional(): ConfigurableExtensionDataRef<TData, TData & { optional: true }>; +> extends ExtensionDataRef<TData, TId, TConfig> { + optional(): ConfigurableExtensionDataRef< + TId, + TData, + TData & { optional: true } + >; } -// TODO: change to options object with ID. -/** @public */ +/** + * @public + * @deprecated Use the following form instead: `createExtensionDataRef<Type>().with({ id: 'core.foo' })` + */ export function createExtensionDataRef<TData>( id: string, -): ConfigurableExtensionDataRef<TData> { +): ConfigurableExtensionDataRef<string, TData>; +/** @public */ +export function createExtensionDataRef<TData>(): { + with<TId extends string>(options: { + id: TId; + }): ConfigurableExtensionDataRef<TId, TData>; +}; +export function createExtensionDataRef<TData>(id?: string): + | ConfigurableExtensionDataRef<string, TData> + | { + with<TId extends string>(options: { + id: TId; + }): ConfigurableExtensionDataRef<TId, TData>; + } { + const createRef = <TId extends string>(refId: TId) => + ({ + id: refId, + $$type: '@backstage/ExtensionDataRef', + config: {}, + optional() { + return { + ...this, + config: { ...this.config, optional: true }, + }; + }, + toString() { + const optional = Boolean(this.config.optional); + return `ExtensionDataRef{id=${refId},optional=${optional}}`; + }, + } as ConfigurableExtensionDataRef<TId, TData, { optional?: true }>); + if (id) { + return createRef(id); + } return { - id, - $$type: '@backstage/ExtensionDataRef', - config: {}, - optional() { - return { - ...this, - config: { ...this.config, optional: true }, - }; + with<TId extends string>(options: { id: TId }) { + return createRef(options.id); }, - toString() { - const optional = Boolean(this.config.optional); - return `ExtensionDataRef{id=${id},optional=${optional}}`; - }, - } as ConfigurableExtensionDataRef<TData, { optional?: true }>; + }; } diff --git a/packages/frontend-plugin-api/src/wiring/createPlugin.test.ts b/packages/frontend-plugin-api/src/wiring/createPlugin.test.ts index dab8a9778a..bb9bdc2107 100644 --- a/packages/frontend-plugin-api/src/wiring/createPlugin.test.ts +++ b/packages/frontend-plugin-api/src/wiring/createPlugin.test.ts @@ -27,7 +27,9 @@ import { MockConfigApi, renderWithEffects } from '@backstage/test-utils'; import { createExtensionInput } from './createExtensionInput'; import { BackstagePlugin } from './types'; -const nameExtensionDataRef = createExtensionDataRef<string>('name'); +const nameExtensionDataRef = createExtensionDataRef<string>().with({ + id: 'name', +}); const Extension1 = createExtension({ name: '1', diff --git a/plugins/catalog-react/api-report-alpha.md b/plugins/catalog-react/api-report-alpha.md index b82c7ae3e2..d2bfb29458 100644 --- a/plugins/catalog-react/api-report-alpha.md +++ b/plugins/catalog-react/api-report-alpha.md @@ -17,12 +17,21 @@ import { TranslationRef } from '@backstage/core-plugin-api/alpha'; // @alpha (undocumented) export const catalogExtensionData: { - entityContentTitle: ConfigurableExtensionDataRef<string, {}>; + entityContentTitle: ConfigurableExtensionDataRef< + 'catalog.entity-content-title', + string, + {} + >; entityFilterFunction: ConfigurableExtensionDataRef< + 'catalog.entity-filter-function', (entity: Entity) => boolean, {} >; - entityFilterExpression: ConfigurableExtensionDataRef<string, {}>; + entityFilterExpression: ConfigurableExtensionDataRef< + 'catalog.entity-filter-expression', + string, + {} + >; }; // @alpha (undocumented) diff --git a/plugins/catalog-react/src/alpha.tsx b/plugins/catalog-react/src/alpha.tsx index 85712b358a..e81b8e5ebf 100644 --- a/plugins/catalog-react/src/alpha.tsx +++ b/plugins/catalog-react/src/alpha.tsx @@ -36,15 +36,15 @@ export * from './translation'; /** @alpha */ export const catalogExtensionData = { - entityContentTitle: createExtensionDataRef<string>( - 'catalog.entity-content-title', - ), - entityFilterFunction: createExtensionDataRef<(entity: Entity) => boolean>( - 'catalog.entity-filter-function', - ), - entityFilterExpression: createExtensionDataRef<string>( - 'catalog.entity-filter-expression', - ), + entityContentTitle: createExtensionDataRef<string>().with({ + id: 'catalog.entity-content-title', + }), + entityFilterFunction: createExtensionDataRef< + (entity: Entity) => boolean + >().with({ id: 'catalog.entity-filter-function' }), + entityFilterExpression: createExtensionDataRef<string>().with({ + id: 'catalog.entity-filter-expression', + }), }; // TODO: Figure out how to merge with provided config schema diff --git a/plugins/home/api-report-alpha.md b/plugins/home/api-report-alpha.md index 35ce0bb86c..1dd3da96be 100644 --- a/plugins/home/api-report-alpha.md +++ b/plugins/home/api-report-alpha.md @@ -11,7 +11,11 @@ const _default: BackstagePlugin<{}, {}>; export default _default; // @alpha (undocumented) -export const titleExtensionDataRef: ConfigurableExtensionDataRef<string, {}>; +export const titleExtensionDataRef: ConfigurableExtensionDataRef< + 'title', + string, + {} +>; // (No @packageDocumentation comment for this package) ``` diff --git a/plugins/home/src/alpha.tsx b/plugins/home/src/alpha.tsx index e9ff26c9e1..b13c2a2e0e 100644 --- a/plugins/home/src/alpha.tsx +++ b/plugins/home/src/alpha.tsx @@ -31,7 +31,9 @@ const rootRouteRef = createRouteRef(); /** * @alpha */ -export const titleExtensionDataRef = createExtensionDataRef<string>('title'); +export const titleExtensionDataRef = createExtensionDataRef<string>().with({ + id: 'title', +}); const homePage = createPageExtension({ defaultPath: '/home', diff --git a/plugins/search-react/api-report-alpha.md b/plugins/search-react/api-report-alpha.md index 36f5f049c5..aea85d0f81 100644 --- a/plugins/search-react/api-report-alpha.md +++ b/plugins/search-react/api-report-alpha.md @@ -31,6 +31,7 @@ export function createSearchResultListItemExtension< export namespace createSearchResultListItemExtension { const // (undocumented) itemDataRef: ConfigurableExtensionDataRef< + 'search.search-result-list-item.item', { predicate?: SearchResultItemExtensionPredicate | undefined; component: SearchResultItemExtensionComponent; diff --git a/plugins/search-react/src/alpha.tsx b/plugins/search-react/src/alpha.tsx index db198fa99d..a22eaf4244 100644 --- a/plugins/search-react/src/alpha.tsx +++ b/plugins/search-react/src/alpha.tsx @@ -137,5 +137,5 @@ export namespace createSearchResultListItemExtension { export const itemDataRef = createExtensionDataRef<{ predicate?: SearchResultItemExtensionPredicate; component: SearchResultItemExtensionComponent; - }>('search.search-result-list-item.item'); + }>().with({ id: 'search.search-result-list-item.item' }); } From 0bfe7efa2284b31592c9966278f6d5ad5850c27a Mon Sep 17 00:00:00 2001 From: blam <ben@blam.sh> Date: Thu, 18 Jul 2024 14:54:24 +0200 Subject: [PATCH 342/416] chore: wip Signed-off-by: blam <ben@blam.sh> Signed-off-by: blam <ben@blam.sh> --- .../frontend-app-api/src/wiring/createApp.tsx | 1 + .../src/extensions/IconBundleBlueprint.ts | 31 +++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 packages/frontend-plugin-api/src/extensions/IconBundleBlueprint.ts diff --git a/packages/frontend-app-api/src/wiring/createApp.tsx b/packages/frontend-app-api/src/wiring/createApp.tsx index cf6ea6dab4..ae7283f301 100644 --- a/packages/frontend-app-api/src/wiring/createApp.tsx +++ b/packages/frontend-app-api/src/wiring/createApp.tsx @@ -171,6 +171,7 @@ export interface CreateAppFeatureLoader { /** @public */ export function createApp(options?: { + /** @deprecated - TODO */ icons?: { [key in string]: IconComponent }; features?: (FrontendFeature | CreateAppFeatureLoader)[]; configLoader?: () => Promise<{ config: ConfigApi }>; diff --git a/packages/frontend-plugin-api/src/extensions/IconBundleBlueprint.ts b/packages/frontend-plugin-api/src/extensions/IconBundleBlueprint.ts new file mode 100644 index 0000000000..7008dba5a1 --- /dev/null +++ b/packages/frontend-plugin-api/src/extensions/IconBundleBlueprint.ts @@ -0,0 +1,31 @@ +/* + * Copyright 2024 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 { IconComponent } from '../icons'; +import { createExtensionBlueprint, createExtensionDataRef } from '../wiring'; + +const iconsDataRef = + createExtensionDataRef<{ [key in string]: IconComponent }>('core.icons'); + +/** @public */ +export const IconBundleBlueprint = createExtensionBlueprint({ + kind: 'icon-bundle', + namespace: 'app', + attachTo: { id: 'app', input: 'icons' }, + output: { + icons: iconsDataRef, + }, + factory: (_, params: { icons: { [key in string]: IconComponent } }) => params, +}); From 39f36a944251d056362702622d82eacd6ff54bb6 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg <poldsberg@gmail.com> Date: Mon, 22 Jul 2024 14:06:27 +0200 Subject: [PATCH 343/416] auth-backend-module-microsoft-provider: update scope handling to define required scopes in backend Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com> --- .changeset/new-scissors-try.md | 5 ++ docs/auth/microsoft/provider.md | 4 +- .../src/authenticator.ts | 20 ++++-- .../src/module.test.ts | 65 ++++++++++++++++++- 4 files changed, 83 insertions(+), 11 deletions(-) create mode 100644 .changeset/new-scissors-try.md diff --git a/.changeset/new-scissors-try.md b/.changeset/new-scissors-try.md new file mode 100644 index 0000000000..a9e9a45ce7 --- /dev/null +++ b/.changeset/new-scissors-try.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-auth-backend-module-microsoft-provider': patch +--- + +Updated the Microsoft authenticator to accurately define required scopes, but to also omit the required and additional scopes when requesting resource scopes. diff --git a/docs/auth/microsoft/provider.md b/docs/auth/microsoft/provider.md index f799eeb627..60104b99b7 100644 --- a/docs/auth/microsoft/provider.md +++ b/docs/auth/microsoft/provider.md @@ -67,8 +67,6 @@ auth: clientSecret: ${AZURE_CLIENT_SECRET} tenantId: ${AZURE_TENANT_ID} domainHint: ${AZURE_TENANT_ID} - additionalScopes: - - Mail.Send signIn: resolvers: # typically you would pick one of these @@ -86,7 +84,7 @@ The Microsoft provider is a structure with three mandatory configuration keys: Leave blank if your app registration is multi tenant. When specified, this reduces login friction for users with accounts in multiple tenants by automatically filtering away accounts from other tenants. For more details, see [Home Realm Discovery](https://learn.microsoft.com/en-us/azure/active-directory/manage-apps/home-realm-discovery-policy) -- `additionalScopes` (optional): List of scopes for the App Registration. The default and mandatory value is ['user.read']. +- `additionalScopes` (optional): List of scopes for the App Registration, to be requested in addition to the required ones. ### Resolvers diff --git a/plugins/auth-backend-module-microsoft-provider/src/authenticator.ts b/plugins/auth-backend-module-microsoft-provider/src/authenticator.ts index 1b6eb87fae..fe7dc8f7e1 100644 --- a/plugins/auth-backend-module-microsoft-provider/src/authenticator.ts +++ b/plugins/auth-backend-module-microsoft-provider/src/authenticator.ts @@ -21,21 +21,30 @@ import { PassportProfile, } from '@backstage/plugin-auth-node'; import { ExtendedMicrosoftStrategy } from './strategy'; -import { union } from 'lodash'; /** @public */ export const microsoftAuthenticator = createOAuthAuthenticator({ defaultProfileTransform: PassportOAuthAuthenticatorHelper.defaultProfileTransform, + scopes: { + required: ['email', 'openid', 'offline_access', 'user.read'], + transform({ requested, granted, required, additional }) { + // Resources scopes are of the form `<resource>/<scope>`, and are handled + // separately from the normal scopes in the client. When request a + // resource scope we should only include forward the request scope along + // with offline_access. + const hasResourceScope = Array.from(requested).some(s => s.includes('/')); + if (hasResourceScope) { + return [...requested, 'offline_access']; + } + return [...requested, ...granted, ...required, ...additional]; + }, + }, initialize({ callbackUrl, config }) { const clientId = config.getString('clientId'); const clientSecret = config.getString('clientSecret'); const tenantId = config.getString('tenantId'); const domainHint = config.getOptionalString('domainHint'); - const scope = union( - ['user.read'], - config.getOptionalStringArray('additionalScopes'), - ); const helper = PassportOAuthAuthenticatorHelper.from( new ExtendedMicrosoftStrategy( @@ -44,7 +53,6 @@ export const microsoftAuthenticator = createOAuthAuthenticator({ clientSecret: clientSecret, callbackURL: callbackUrl, tenant: tenantId, - scope: scope, }, ( accessToken: string, diff --git a/plugins/auth-backend-module-microsoft-provider/src/module.test.ts b/plugins/auth-backend-module-microsoft-provider/src/module.test.ts index b50956b9eb..a072b99bde 100644 --- a/plugins/auth-backend-module-microsoft-provider/src/module.test.ts +++ b/plugins/auth-backend-module-microsoft-provider/src/module.test.ts @@ -67,7 +67,7 @@ describe('authModuleMicrosoftProvider', () => { expect(startUrl.pathname).toBe('/my-tenant-id/oauth2/v2.0/authorize'); expect(Object.fromEntries(startUrl.searchParams)).toEqual({ response_type: 'code', - scope: 'User.Read.All', + scope: 'email openid offline_access user.read User.Read.All', client_id: 'my-client-id', redirect_uri: `http://localhost:${server.port()}/api/auth/microsoft/handler/frame`, state: expect.any(String), @@ -97,6 +97,7 @@ describe('authModuleMicrosoftProvider', () => { clientSecret: 'another-client-secret', tenantId: 'another-tenant-id', domainHint: 'somedomain', + additionalScopes: ['some-extra-scope'], }, }, }, @@ -125,7 +126,7 @@ describe('authModuleMicrosoftProvider', () => { expect(startUrl.pathname).toBe('/another-tenant-id/oauth2/v2.0/authorize'); expect(Object.fromEntries(startUrl.searchParams)).toEqual({ response_type: 'code', - scope: 'user.read', + scope: 'email openid offline_access user.read some-extra-scope', client_id: 'another-client-id', redirect_uri: `http://localhost:${server.port()}/api/auth/microsoft/handler/frame`, state: expect.any(String), @@ -137,4 +138,64 @@ describe('authModuleMicrosoftProvider', () => { nonce: decodeURIComponent(nonceCookie.value), }); }); + + it('should not include required scopes for resources', async () => { + const { server } = await startTestBackend({ + features: [ + authPlugin, + authModuleMicrosoftProvider, + mockServices.rootConfig.factory({ + data: { + app: { + baseUrl: 'http://localhost:3000', + }, + auth: { + providers: { + microsoft: { + development: { + clientId: 'another-client-id', + clientSecret: 'another-client-secret', + tenantId: 'another-tenant-id', + additionalScopes: ['some-extra-scope'], + }, + }, + }, + }, + }, + }), + ], + }); + + const agent = request.agent(server); + + const res = await agent.get( + '/api/auth/microsoft/start?env=development&scope=some-resource/some-scope', + ); + + expect(res.status).toEqual(302); + + const nonceCookie = agent.jar.getCookie('microsoft-nonce', { + domain: 'localhost', + path: '/api/auth/microsoft/handler', + script: false, + secure: false, + }); + expect(nonceCookie).toBeDefined(); + + const startUrl = new URL(res.get('location')); + expect(startUrl.origin).toBe('https://login.microsoftonline.com'); + expect(startUrl.pathname).toBe('/another-tenant-id/oauth2/v2.0/authorize'); + expect(Object.fromEntries(startUrl.searchParams)).toEqual({ + response_type: 'code', + scope: 'some-resource/some-scope offline_access', + client_id: 'another-client-id', + redirect_uri: `http://localhost:${server.port()}/api/auth/microsoft/handler/frame`, + state: expect.any(String), + }); + + expect(decodeOAuthState(startUrl.searchParams.get('state')!)).toEqual({ + env: 'development', + nonce: decodeURIComponent(nonceCookie.value), + }); + }); }); From 09d1370799f92e7043ae0d1d5ebbd0798ab917d3 Mon Sep 17 00:00:00 2001 From: Calvin Lee <calvin.lee@harness.io> Date: Mon, 22 Jul 2024 22:29:47 +0900 Subject: [PATCH 344/416] Update .changeset/witty-bears-behave.md Co-authored-by: Ben Lambert <ben@blam.sh> Signed-off-by: Calvin Lee <calvin.lee@harness.io> --- .changeset/witty-bears-behave.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/witty-bears-behave.md b/.changeset/witty-bears-behave.md index 7514759189..174467b9eb 100644 --- a/.changeset/witty-bears-behave.md +++ b/.changeset/witty-bears-behave.md @@ -2,4 +2,4 @@ '@backstage/integration': patch --- -Updated functions for getHarnessEditContentsUrl, getHarnessFileContentsUrl, getHarnessArchiveUrl, getHarnessLatestCommitUrl and parseHarnessUrl to handle account and org level urls +Updated functions for `getHarnessEditContentsUrl`, `getHarnessFileContentsUrl`, `getHarnessArchiveUrl`, `getHarnessLatestCommitUrl` and `parseHarnessUrl` to handle account and org level urls From dc37210a290aa28ed4e12d4d22a3f4696c693af1 Mon Sep 17 00:00:00 2001 From: blam <ben@blam.sh> Date: Mon, 22 Jul 2024 15:38:22 +0200 Subject: [PATCH 345/416] feat: add support for collecting icons using the new extension blueprint Signed-off-by: blam <ben@blam.sh> --- packages/frontend-app-api/src/extensions/App.tsx | 4 ++++ packages/frontend-app-api/src/wiring/createApp.tsx | 10 +++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/frontend-app-api/src/extensions/App.tsx b/packages/frontend-app-api/src/extensions/App.tsx index 82e7600178..7794aceb79 100644 --- a/packages/frontend-app-api/src/extensions/App.tsx +++ b/packages/frontend-app-api/src/extensions/App.tsx @@ -24,6 +24,7 @@ import { createExtensionInput, createThemeExtension, createTranslationExtension, + IconBundleBlueprint, } from '@backstage/frontend-plugin-api'; export const App = createExtension({ @@ -42,6 +43,9 @@ export const App = createExtension({ translations: createExtensionInput({ translation: createTranslationExtension.translationDataRef, }), + icons: createExtensionInput({ + icon: IconBundleBlueprint.dataRefs.icons, + }), root: createExtensionInput( { element: coreExtensionData.reactElement, diff --git a/packages/frontend-app-api/src/wiring/createApp.tsx b/packages/frontend-app-api/src/wiring/createApp.tsx index ae7283f301..4d929b206f 100644 --- a/packages/frontend-app-api/src/wiring/createApp.tsx +++ b/packages/frontend-app-api/src/wiring/createApp.tsx @@ -25,6 +25,7 @@ import { createThemeExtension, createTranslationExtension, FrontendFeature, + IconBundleBlueprint, iconsApiRef, RouteResolutionApi, routeResolutionApiRef, @@ -247,6 +248,7 @@ export function createApp(options?: { * @public */ export function createSpecializedApp(options?: { + /** @deprecated - TODO */ icons?: { [key in string]: IconComponent }; features?: FrontendFeature[]; config?: ConfigApi; @@ -374,6 +376,11 @@ function createApiHolder( (x): x is typeof createTranslationExtension.translationDataRef.T => !!x, ) ?? []; + const extensionIcons = tree.root.edges.attachments + .get('icons') + ?.map(e => e.instance?.getData(IconBundleBlueprint.dataRefs.icons)) + .reduce((acc, bundle) => ({ ...acc, ...bundle }), {}); + for (const factory of pluginApis) { factoryRegistry.register('default', factory); } @@ -414,7 +421,8 @@ function createApiHolder( factoryRegistry.register('static', { api: iconsApiRef, deps: {}, - factory: () => new DefaultIconsApi({ ...defaultIcons, ...icons }), + factory: () => + new DefaultIconsApi({ ...defaultIcons, ...extensionIcons, ...icons }), }); factoryRegistry.register('static', { From 4a18c942be1d49700540005f9d6a1566d0268f98 Mon Sep 17 00:00:00 2001 From: blam <ben@blam.sh> Date: Mon, 22 Jul 2024 15:39:33 +0200 Subject: [PATCH 346/416] feat: support exporting of dataRefs through blueprints Signed-off-by: blam <ben@blam.sh> --- .../src/extensions/IconBundleBlueprint.ts | 10 ++++--- .../src/extensions/index.ts | 1 + .../src/wiring/createExtensionBlueprint.ts | 27 ++++++++++++++++--- 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/packages/frontend-plugin-api/src/extensions/IconBundleBlueprint.ts b/packages/frontend-plugin-api/src/extensions/IconBundleBlueprint.ts index 7008dba5a1..2ad1404102 100644 --- a/packages/frontend-plugin-api/src/extensions/IconBundleBlueprint.ts +++ b/packages/frontend-plugin-api/src/extensions/IconBundleBlueprint.ts @@ -16,8 +16,9 @@ import { IconComponent } from '../icons'; import { createExtensionBlueprint, createExtensionDataRef } from '../wiring'; -const iconsDataRef = - createExtensionDataRef<{ [key in string]: IconComponent }>('core.icons'); +const iconsDataRef = createExtensionDataRef<{ + [key in string]: IconComponent; +}>().with({ id: 'core.icons' }); /** @public */ export const IconBundleBlueprint = createExtensionBlueprint({ @@ -27,5 +28,8 @@ export const IconBundleBlueprint = createExtensionBlueprint({ output: { icons: iconsDataRef, }, - factory: (_, params: { icons: { [key in string]: IconComponent } }) => params, + factory: (params: { icons: { [key in string]: IconComponent } }) => params, + dataRefs: { + icons: iconsDataRef, + }, }); diff --git a/packages/frontend-plugin-api/src/extensions/index.ts b/packages/frontend-plugin-api/src/extensions/index.ts index 562cb728cb..267201db81 100644 --- a/packages/frontend-plugin-api/src/extensions/index.ts +++ b/packages/frontend-plugin-api/src/extensions/index.ts @@ -25,3 +25,4 @@ export { createSignInPageExtension } from './createSignInPageExtension'; export { createThemeExtension } from './createThemeExtension'; export { createComponentExtension } from './createComponentExtension'; export { createTranslationExtension } from './createTranslationExtension'; +export { IconBundleBlueprint } from './IconBundleBlueprint'; diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts index 6c79017a0a..b504db5f03 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts @@ -34,6 +34,7 @@ export interface CreateExtensionBlueprintOptions< TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, TConfig, + TDataRefs extends AnyExtensionDataMap, > { kind: string; namespace?: string; @@ -50,6 +51,8 @@ export interface CreateExtensionBlueprintOptions< inputs: Expand<ResolvedExtensionInputs<TInputs>>; }, ): Expand<ExtensionDataValues<TOutput>>; + + dataRefs?: TDataRefs; } /** @@ -60,7 +63,10 @@ export interface ExtensionBlueprint< TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, TConfig, + TDataRefs extends AnyExtensionDataMap, > { + dataRefs: TDataRefs; + make(args: { namespace?: string; name?: string; @@ -97,15 +103,21 @@ class ExtensionBlueprintImpl< TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, TConfig, + TDataRefs extends AnyExtensionDataMap, > { constructor( private readonly options: CreateExtensionBlueprintOptions< TParams, TInputs, TOutput, - TConfig + TConfig, + TDataRefs >, - ) {} + ) { + this.dataRefs = options.dataRefs!; + } + + dataRefs: TDataRefs; public make(args: { namespace?: string; @@ -184,8 +196,15 @@ export function createExtensionBlueprint< TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, TConfig, + TDataRefs extends AnyExtensionDataMap = never, >( - options: CreateExtensionBlueprintOptions<TParams, TInputs, TOutput, TConfig>, -): ExtensionBlueprint<TParams, TInputs, TOutput, TConfig> { + options: CreateExtensionBlueprintOptions< + TParams, + TInputs, + TOutput, + TConfig, + TDataRefs + >, +): ExtensionBlueprint<TParams, TInputs, TOutput, TConfig, TDataRefs> { return new ExtensionBlueprintImpl(options); } From 7777b5fb40b96fcefe6a418c0d3d657b3ae6b6a1 Mon Sep 17 00:00:00 2001 From: blam <ben@blam.sh> Date: Mon, 22 Jul 2024 15:45:01 +0200 Subject: [PATCH 347/416] chore: added changeset Signed-off-by: blam <ben@blam.sh> --- .changeset/forty-ties-agree.md | 18 ++++++++++++++++++ .changeset/forty-ties-disagree.md | 5 +++++ 2 files changed, 23 insertions(+) create mode 100644 .changeset/forty-ties-agree.md create mode 100644 .changeset/forty-ties-disagree.md diff --git a/.changeset/forty-ties-agree.md b/.changeset/forty-ties-agree.md new file mode 100644 index 0000000000..caa45841a2 --- /dev/null +++ b/.changeset/forty-ties-agree.md @@ -0,0 +1,18 @@ +--- +'@backstage/frontend-plugin-api': patch +--- + +Added a new `IconBundleBlueprint` that lets you create icon bundle extensions that can be installed in an App in order to override or add new app icons. + +```tsx +import { IconBundleBlueprint } from '@backstage/frontend-plugin-api'; + +const exampleIconBundle = IconBundleBlueprint.make({ + name: 'example-bundle', + params: { + icons: { + user: MyOwnUserIcon, + }, + }, +}); +``` diff --git a/.changeset/forty-ties-disagree.md b/.changeset/forty-ties-disagree.md new file mode 100644 index 0000000000..214097b35d --- /dev/null +++ b/.changeset/forty-ties-disagree.md @@ -0,0 +1,5 @@ +--- +'@backstage/frontend-app-api': patch +--- + +Support icon overriding with the new `IconBundleBlueprint` API. From be5cb5ea365f09044cc18788e7b5d9eaa6b3689e Mon Sep 17 00:00:00 2001 From: Devin Lauderdale <devinlauderdale2@gmail.com> Date: Mon, 22 Jul 2024 08:58:25 -0500 Subject: [PATCH 348/416] docs: remove unmaintained dora-metrics plugin Signed-off-by: Devin Lauderdale <devinlauderdale2@gmail.com> --- microsite/data/plugins/dora-metrics.yaml | 10 ---------- microsite/static/img/okay.png | Bin 46181 -> 0 bytes 2 files changed, 10 deletions(-) delete mode 100644 microsite/data/plugins/dora-metrics.yaml delete mode 100644 microsite/static/img/okay.png diff --git a/microsite/data/plugins/dora-metrics.yaml b/microsite/data/plugins/dora-metrics.yaml deleted file mode 100644 index 3f59902f46..0000000000 --- a/microsite/data/plugins/dora-metrics.yaml +++ /dev/null @@ -1,10 +0,0 @@ ---- -title: DORA Metrics -author: Okay -authorUrl: https://www.okayhq.com -category: Metrics -description: Embed dashboards (like DORA metrics) in your team or service pages from any dev tools (including Github, Gitlab, Jira, Argo, CircleCI, Buildkite, Pagerduty, Rollbar, Sentry, etc). -documentation: https://github.com/OkayHQ/backstage-plugin -iconUrl: /img/okay.png -npmPackageName: '@okayhq/backstage-plugin' -addedDate: '2022-06-16' diff --git a/microsite/static/img/okay.png b/microsite/static/img/okay.png deleted file mode 100644 index 357219d9d2c51e1d9a16f3f7a0c4fc476936d685..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 46181 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 From cf9da6dafbe6c2fd038d9b8176a2f28816b76e10 Mon Sep 17 00:00:00 2001 From: blam <ben@blam.sh> Date: Mon, 22 Jul 2024 16:10:05 +0200 Subject: [PATCH 349/416] chore: added test for dataRef exporting Signed-off-by: blam <ben@blam.sh> --- .../wiring/createExtensionBlueprint.test.tsx | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.test.tsx b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.test.tsx index c7b077bdbd..87b3cec152 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.test.tsx +++ b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.test.tsx @@ -18,6 +18,7 @@ import React from 'react'; import { coreExtensionData } from './coreExtensionData'; import { createExtensionBlueprint } from './createExtensionBlueprint'; import { createExtensionTester } from '@backstage/frontend-test-utils'; +import { createExtensionDataRef } from './createExtensionDataRef'; describe('createExtensionBlueprint', () => { it('should allow creation of extension blueprints', () => { @@ -102,4 +103,28 @@ describe('createExtensionBlueprint', () => { const { container } = createExtensionTester(extension).render(); expect(container.querySelector('h2')).toHaveTextContent('Hello, world!'); }); + + it('should allow exporting the dataRefs from the extension blueprint', () => { + const dataRef = createExtensionDataRef<string>().with({ id: 'test.data' }); + + const TestExtensionBlueprint = createExtensionBlueprint({ + kind: 'test-extension', + attachTo: { id: 'test', input: 'default' }, + output: { + element: coreExtensionData.reactElement, + }, + dataRefs: { + data: dataRef, + }, + factory(params: { text: string }) { + return { + element: <h1>{params.text}</h1>, + }; + }, + }); + + expect(TestExtensionBlueprint.dataRefs).toEqual({ + data: dataRef, + }); + }); }); From 493feaca4d4af19c4174a531d268f4d6e63c1a9e Mon Sep 17 00:00:00 2001 From: MT Lewis <mtlewis@users.noreply.github.com> Date: Thu, 18 Jul 2024 11:10:18 +0100 Subject: [PATCH 350/416] cli: allow running with no configuration files Co-authored-by: Patrik Oldsberg <poldsberg@gmail.com> Signed-off-by: MT Lewis <mtlewis@users.noreply.github.com> --- .changeset/rich-mugs-dress.md | 7 ++++++ packages/cli/src/lib/bundler/config.ts | 6 ++++- packages/cli/src/lib/config.ts | 8 ++++--- packages/config-loader/api-report.md | 1 + .../src/sources/ConfigSources.test.ts | 13 +++++++++- .../src/sources/ConfigSources.ts | 24 +++++++++++++------ 6 files changed, 47 insertions(+), 12 deletions(-) create mode 100644 .changeset/rich-mugs-dress.md diff --git a/.changeset/rich-mugs-dress.md b/.changeset/rich-mugs-dress.md new file mode 100644 index 0000000000..5008e33a70 --- /dev/null +++ b/.changeset/rich-mugs-dress.md @@ -0,0 +1,7 @@ +--- +'@backstage/config-loader': patch +--- + +Add boolean `allowMissingDefaultConfig` option to `ConfigSources.default` and +`ConfigSources.defaultForTargets`, which results in omission of a ConfigSource +for the default app-config.yaml configuration file if it's not present. diff --git a/packages/cli/src/lib/bundler/config.ts b/packages/cli/src/lib/bundler/config.ts index 1f08f74a85..042f74d1f3 100644 --- a/packages/cli/src/lib/bundler/config.ts +++ b/packages/cli/src/lib/bundler/config.ts @@ -48,8 +48,12 @@ const BUILD_CACHE_ENV_VAR = 'BACKSTAGE_CLI_EXPERIMENTAL_BUILD_CACHE'; export function resolveBaseUrl(config: Config): URL { const baseUrl = config.getOptionalString('app.baseUrl'); + try { - return new URL(baseUrl ?? '/', 'http://localhost:3000'); + return new URL( + baseUrl ?? '/', + `http://localhost:${process.env.PORT ?? '3000'}`, + ); } catch (error) { throw new Error(`Invalid app.baseUrl, ${error}`); } diff --git a/packages/cli/src/lib/config.ts b/packages/cli/src/lib/config.ts index 0c657b640e..0be20b0185 100644 --- a/packages/cli/src/lib/config.ts +++ b/packages/cli/src/lib/config.ts @@ -96,11 +96,13 @@ export async function loadCliConfig(options: Options) { }, }); + const configurationLoadedMessage = appConfigs.length + ? `Loaded config from ${appConfigs.map(c => c.context).join(', ')}` + : `No configuration files found, running without config`; + // printing to stderr to not clobber stdout in case the cli command // outputs structured data (e.g. as config:schema does) - process.stderr.write( - `Loaded config from ${appConfigs.map(c => c.context).join(', ')}\n`, - ); + process.stderr.write(`${configurationLoadedMessage}\n`); try { const frontendAppConfigs = schema.process(appConfigs, { diff --git a/packages/config-loader/api-report.md b/packages/config-loader/api-report.md index bc8f217bbb..835e53351d 100644 --- a/packages/config-loader/api-report.md +++ b/packages/config-loader/api-report.md @@ -21,6 +21,7 @@ export type AsyncConfigSourceGenerator = AsyncGenerator< // @public export interface BaseConfigSourcesOptions { + allowMissingDefaultConfig?: boolean; // (undocumented) remote?: Pick<RemoteConfigSourceOptions, 'reloadInterval'>; // (undocumented) diff --git a/packages/config-loader/src/sources/ConfigSources.test.ts b/packages/config-loader/src/sources/ConfigSources.test.ts index 4b14572666..e19ac1d51f 100644 --- a/packages/config-loader/src/sources/ConfigSources.test.ts +++ b/packages/config-loader/src/sources/ConfigSources.test.ts @@ -69,13 +69,18 @@ describe('ConfigSources', () => { }); it('should create default sources for targets', () => { + const fsSpy = jest.spyOn(fs, 'pathExistsSync').mockImplementation(path => { + return path === `${root}app-config.yaml`; + }); + expect( mergeSources( ConfigSources.defaultForTargets({ rootDir: '/', targets: [] }), ), ).toEqual([{ name: 'FileConfigSource', path: `${root}app-config.yaml` }]); - const fsSpy = jest.spyOn(fs, 'pathExistsSync').mockReturnValue(true); + fsSpy.mockReturnValue(true); + expect( mergeSources( ConfigSources.defaultForTargets({ rootDir: '/', targets: [] }), @@ -159,6 +164,10 @@ describe('ConfigSources', () => { }); it('should create a default source', () => { + const fsSpy = jest.spyOn(fs, 'pathExistsSync').mockImplementation(path => { + return path === `${root}app-config.yaml`; + }); + expect( mergeSources( ConfigSources.default({ @@ -184,6 +193,8 @@ describe('ConfigSources', () => { { name: 'FileConfigSource', path: resolvePath('b.yaml') }, { name: 'EnvConfigSource', env: { HOME: '/' } }, ]); + + fsSpy.mockRestore(); }); it('should merge sources', () => { diff --git a/packages/config-loader/src/sources/ConfigSources.ts b/packages/config-loader/src/sources/ConfigSources.ts index ecff39da2d..be8892f9a9 100644 --- a/packages/config-loader/src/sources/ConfigSources.ts +++ b/packages/config-loader/src/sources/ConfigSources.ts @@ -74,6 +74,11 @@ export interface BaseConfigSourcesOptions { watch?: boolean; rootDir?: string; remote?: Pick<RemoteConfigSourceOptions, 'reloadInterval'>; + /** + * Allow the default app-config.yaml to be missing, in which case the source + * will not be created. + */ + allowMissingDefaultConfig?: boolean; /** * A custom substitution function that overrides the default one. @@ -177,14 +182,19 @@ export class ConfigSources { if (argSources.length === 0) { const defaultPath = resolvePath(rootDir, 'app-config.yaml'); const localPath = resolvePath(rootDir, 'app-config.local.yaml'); + const alwaysIncludeDefaultConfigSource = + !options.allowMissingDefaultConfig; + + if (alwaysIncludeDefaultConfigSource || fs.pathExistsSync(defaultPath)) { + argSources.push( + FileConfigSource.create({ + watch: options.watch, + path: defaultPath, + substitutionFunc: options.substitutionFunc, + }), + ); + } - argSources.push( - FileConfigSource.create({ - watch: options.watch, - path: defaultPath, - substitutionFunc: options.substitutionFunc, - }), - ); if (fs.pathExistsSync(localPath)) { argSources.push( FileConfigSource.create({ From 0eedec304dbe8e4f8b1e982a1e29b081cbed3ddd Mon Sep 17 00:00:00 2001 From: MT Lewis <mtlewis@users.noreply.github.com> Date: Thu, 18 Jul 2024 11:18:07 +0100 Subject: [PATCH 351/416] cli: add changeset for module federation local development changes Signed-off-by: MT Lewis <mtlewis@users.noreply.github.com> --- .changeset/strong-otters-compete.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/strong-otters-compete.md diff --git a/.changeset/strong-otters-compete.md b/.changeset/strong-otters-compete.md new file mode 100644 index 0000000000..fdcb982b88 --- /dev/null +++ b/.changeset/strong-otters-compete.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Add support for dynamic plugins via the EXPERIMENTAL_MODULE_FEDERATION environment variable when running `yarn start`. From 9d661bb3807a534cf023dc84d816cee5d3c81472 Mon Sep 17 00:00:00 2001 From: MT Lewis <mtlewis@users.noreply.github.com> Date: Fri, 19 Jul 2024 14:28:13 +0100 Subject: [PATCH 352/416] cli: only consider PORT environment variable for module federation remotes Signed-off-by: MT Lewis <mtlewis@users.noreply.github.com> --- packages/cli/src/lib/bundler/config.ts | 43 +++++++++++++++++++------- packages/cli/src/lib/bundler/server.ts | 7 +++-- 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/packages/cli/src/lib/bundler/config.ts b/packages/cli/src/lib/bundler/config.ts index 042f74d1f3..42cdae24e3 100644 --- a/packages/cli/src/lib/bundler/config.ts +++ b/packages/cli/src/lib/bundler/config.ts @@ -14,7 +14,11 @@ * limitations under the License. */ -import { BackendBundlingOptions, BundlingOptions } from './types'; +import { + BackendBundlingOptions, + BundlingOptions, + ModuleFederationOptions, +} from './types'; import { posix as posixPath, resolve as resolvePath, dirname } from 'path'; import chalk from 'chalk'; import webpack, { ProvidePlugin } from 'webpack'; @@ -46,24 +50,32 @@ import { hasReactDomClient } from './hasReactDomClient'; const BUILD_CACHE_ENV_VAR = 'BACKSTAGE_CLI_EXPERIMENTAL_BUILD_CACHE'; -export function resolveBaseUrl(config: Config): URL { +export function resolveBaseUrl( + config: Config, + moduleFederation?: ModuleFederationOptions, +): URL { const baseUrl = config.getOptionalString('app.baseUrl'); + const defaultBaseUrl = + moduleFederation?.mode === 'remote' + ? `http://localhost:${process.env.PORT ?? '3000'}` + : 'http://localhost:3000'; + try { - return new URL( - baseUrl ?? '/', - `http://localhost:${process.env.PORT ?? '3000'}`, - ); + return new URL(baseUrl ?? '/', defaultBaseUrl); } catch (error) { throw new Error(`Invalid app.baseUrl, ${error}`); } } -export function resolveEndpoint(config: Config): { +export function resolveEndpoint( + config: Config, + moduleFederation?: ModuleFederationOptions, +): { host: string; port: number; } { - const url = resolveBaseUrl(config); + const url = resolveBaseUrl(config, moduleFederation); return { host: config.getOptionalString('app.listen.host') ?? url.hostname, @@ -114,7 +126,13 @@ export async function createConfig( paths: BundlingPaths, options: BundlingOptions, ): Promise<webpack.Configuration> { - const { checksEnabled, isDev, frontendConfig, publicSubPath = '' } = options; + const { + checksEnabled, + isDev, + frontendConfig, + moduleFederation, + publicSubPath = '', + } = options; const { plugins, loaders } = transforms(options); // Any package that is part of the monorepo but outside the monorepo root dir need @@ -122,14 +140,17 @@ export async function createConfig( const { packages } = await getPackages(cliPaths.targetDir); const externalPkgs = packages.filter(p => !isChildPath(paths.root, p.dir)); - const validBaseUrl = resolveBaseUrl(frontendConfig); + const validBaseUrl = resolveBaseUrl(frontendConfig, moduleFederation); let publicPath = validBaseUrl.pathname.replace(/\/$/, ''); if (publicSubPath) { publicPath = `${publicPath}${publicSubPath}`.replace('//', '/'); } if (isDev) { - const { host, port } = resolveEndpoint(options.frontendConfig); + const { host, port } = resolveEndpoint( + options.frontendConfig, + options.moduleFederation, + ); plugins.push( new ReactRefreshPlugin({ diff --git a/packages/cli/src/lib/bundler/server.ts b/packages/cli/src/lib/bundler/server.ts index 0421f4d019..6b89847fb6 100644 --- a/packages/cli/src/lib/bundler/server.ts +++ b/packages/cli/src/lib/bundler/server.ts @@ -130,8 +130,11 @@ DEPRECATION WARNING: React Router Beta is deprecated and support for it will be } const { frontendConfig, fullConfig } = cliConfig; - const url = resolveBaseUrl(frontendConfig); - const { host, port } = resolveEndpoint(frontendConfig); + const url = resolveBaseUrl(frontendConfig, options.moduleFederation); + const { host, port } = resolveEndpoint( + frontendConfig, + options.moduleFederation, + ); const detectedModulesEntryPoint = await createDetectedModulesEntryPoint({ config: fullConfig, From 239dffc970b4b040ffdf9aee24f6937c4994f5ba Mon Sep 17 00:00:00 2001 From: MT Lewis <mtlewis@users.noreply.github.com> Date: Mon, 22 Jul 2024 11:06:42 +0100 Subject: [PATCH 353/416] cli: remove usage of deprecated functionality from @backstage/config-loader Co-authored-by: Patrik Oldsberg <poldsberg@gmail.com> Signed-off-by: MT Lewis <mtlewis@users.noreply.github.com> --- .changeset/ninety-icons-smile.md | 5 +++ packages/cli/src/lib/config.ts | 76 +++++++++++++++++++------------- 2 files changed, 51 insertions(+), 30 deletions(-) create mode 100644 .changeset/ninety-icons-smile.md diff --git a/.changeset/ninety-icons-smile.md b/.changeset/ninety-icons-smile.md new file mode 100644 index 0000000000..f137879706 --- /dev/null +++ b/.changeset/ninety-icons-smile.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Remove usage of deprecated functionality from @backstage/config-loader diff --git a/packages/cli/src/lib/config.ts b/packages/cli/src/lib/config.ts index 0be20b0185..49cce1f1ed 100644 --- a/packages/cli/src/lib/config.ts +++ b/packages/cli/src/lib/config.ts @@ -14,14 +14,9 @@ * limitations under the License. */ -import { - ConfigTarget, - loadConfig, - loadConfigSchema, -} from '@backstage/config-loader'; +import { ConfigSources, loadConfigSchema } from '@backstage/config-loader'; import { AppConfig, ConfigReader } from '@backstage/config'; import { paths } from './paths'; -import { isValidUrl } from './urls'; import { getPackages } from '@manypkg/get-packages'; import { PackageGraph } from '@backstage/cli-node'; @@ -37,13 +32,6 @@ type Options = { }; export async function loadCliConfig(options: Options) { - const configTargets: ConfigTarget[] = []; - options.args.forEach(arg => { - if (!isValidUrl(arg)) { - configTargets.push({ path: paths.resolveTarget(arg) }); - } - }); - // Consider all packages in the monorepo when loading in config const { packages } = await getPackages(paths.targetDir); @@ -75,25 +63,53 @@ export async function loadCliConfig(options: Options) { noUndeclaredProperties: options.strict, }); - const { appConfigs } = await loadConfig({ - experimentalEnvFunc: options.mockEnv + const source = ConfigSources.default({ + allowMissingDefaultConfig: true, + substitutionFunc: options.mockEnv ? async name => process.env[name] || 'x' : undefined, - configRoot: paths.targetRoot, - configTargets: configTargets, - watch: options.watch && { - onChange(newAppConfigs) { - const newFrontendAppConfigs = schema.process(newAppConfigs, { - visibility: options.fullVisibility - ? ['frontend', 'backend', 'secret'] - : ['frontend'], - withFilteredKeys: options.withFilteredKeys, - withDeprecatedKeys: options.withDeprecatedKeys, - ignoreSchemaErrors: !options.strict, - }); - options.watch?.(newFrontendAppConfigs); - }, - }, + watch: Boolean(options.watch), + rootDir: paths.targetRoot, + argv: options.args, + }); + + const appConfigs = await new Promise<AppConfig[]>((resolve, reject) => { + async function loadConfigReaderLoop() { + let loaded = false; + + try { + const abortController = new AbortController(); + for await (const { configs } of source.readConfigData({ + signal: abortController.signal, + })) { + if (loaded) { + const newFrontendAppConfigs = schema.process(configs, { + visibility: options.fullVisibility + ? ['frontend', 'backend', 'secret'] + : ['frontend'], + withFilteredKeys: options.withFilteredKeys, + withDeprecatedKeys: options.withDeprecatedKeys, + ignoreSchemaErrors: !options.strict, + }); + options.watch?.(newFrontendAppConfigs); + } else { + resolve(configs); + loaded = true; + + if (!options.watch) { + abortController.abort(); + } + } + } + } catch (error) { + if (loaded) { + console.error(`Failed to reload configuration, ${error}`); + } else { + reject(error); + } + } + } + loadConfigReaderLoop(); }); const configurationLoadedMessage = appConfigs.length From 348087a09636d79e3a2894325b16afef79275ec9 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg <poldsberg@gmail.com> Date: Mon, 22 Jul 2024 16:22:29 +0200 Subject: [PATCH 354/416] auth-backend-module-microsoft-provider: cleanup deps Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com> --- plugins/auth-backend-module-microsoft-provider/package.json | 2 -- yarn.lock | 2 -- 2 files changed, 4 deletions(-) diff --git a/plugins/auth-backend-module-microsoft-provider/package.json b/plugins/auth-backend-module-microsoft-provider/package.json index 67a898cf80..b67fb8c447 100644 --- a/plugins/auth-backend-module-microsoft-provider/package.json +++ b/plugins/auth-backend-module-microsoft-provider/package.json @@ -38,9 +38,7 @@ "@backstage/plugin-auth-node": "workspace:^", "express": "^4.18.2", "jose": "^5.0.0", - "lodash": "^4.17.21", "node-fetch": "^2.6.7", - "passport": "^0.7.0", "passport-microsoft": "^1.0.0" }, "devDependencies": { diff --git a/yarn.lock b/yarn.lock index a8ed83a61a..ff5eac7b1f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4861,10 +4861,8 @@ __metadata: "@types/passport-microsoft": ^1.0.0 express: ^4.18.2 jose: ^5.0.0 - lodash: ^4.17.21 msw: ^1.0.0 node-fetch: ^2.6.7 - passport: ^0.7.0 passport-microsoft: ^1.0.0 supertest: ^6.3.3 languageName: unknown From b1f3c44e42a8f880698e2b4e5c59be133c000738 Mon Sep 17 00:00:00 2001 From: blam <ben@blam.sh> Date: Mon, 22 Jul 2024 16:31:09 +0200 Subject: [PATCH 355/416] chore: api-reports Signed-off-by: blam <ben@blam.sh> --- packages/frontend-plugin-api/api-report.md | 46 +++++++++++++++++++++- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/packages/frontend-plugin-api/api-report.md b/packages/frontend-plugin-api/api-report.md index 65445b5c4d..3c082a7694 100644 --- a/packages/frontend-plugin-api/api-report.md +++ b/packages/frontend-plugin-api/api-report.md @@ -522,9 +522,16 @@ export function createExtensionBlueprint< TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, TConfig, + TDataRefs extends AnyExtensionDataMap = never, >( - options: CreateExtensionBlueprintOptions<TParams, TInputs, TOutput, TConfig>, -): ExtensionBlueprint<TParams, TInputs, TOutput, TConfig>; + options: CreateExtensionBlueprintOptions< + TParams, + TInputs, + TOutput, + TConfig, + TDataRefs + >, +): ExtensionBlueprint<TParams, TInputs, TOutput, TConfig, TDataRefs>; // @public (undocumented) export interface CreateExtensionBlueprintOptions< @@ -532,6 +539,7 @@ export interface CreateExtensionBlueprintOptions< TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, TConfig, + TDataRefs extends AnyExtensionDataMap, > { // (undocumented) attachTo: { @@ -541,6 +549,8 @@ export interface CreateExtensionBlueprintOptions< // (undocumented) configSchema?: PortableSchema<TConfig>; // (undocumented) + dataRefs?: TDataRefs; + // (undocumented) disabled?: boolean; // (undocumented) factory( @@ -917,7 +927,10 @@ export interface ExtensionBlueprint< TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, TConfig, + TDataRefs extends AnyExtensionDataMap, > { + // (undocumented) + dataRefs: TDataRefs; // (undocumented) make(args: { namespace?: string; @@ -1085,6 +1098,35 @@ export { gitlabAuthApiRef }; export { googleAuthApiRef }; +// @public (undocumented) +export const IconBundleBlueprint: ExtensionBlueprint< + { + icons: { + [x: string]: IconComponent; + }; + }, + AnyExtensionInputMap, + { + icons: ConfigurableExtensionDataRef< + 'core.icons', + { + [x: string]: IconComponent; + }, + {} + >; + }, + unknown, + { + icons: ConfigurableExtensionDataRef< + 'core.icons', + { + [x: string]: IconComponent; + }, + {} + >; + } +>; + // @public export type IconComponent = ComponentType< | { From 98ea3e2ca9329f6b131e3d3f038ba5101b039beb Mon Sep 17 00:00:00 2001 From: Adam Letizia <43392371+koalaty-code@users.noreply.github.com> Date: Mon, 22 Jul 2024 09:40:18 -0500 Subject: [PATCH 356/416] chore(changeset): new change description Co-authored-by: Ben Lambert <ben@blam.sh> Signed-off-by: Adam Letizia <43392371+koalaty-code@users.noreply.github.com> --- .changeset/tough-lies-repair.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/tough-lies-repair.md b/.changeset/tough-lies-repair.md index 25b1884bbc..b2f848e292 100644 --- a/.changeset/tough-lies-repair.md +++ b/.changeset/tough-lies-repair.md @@ -2,4 +2,4 @@ '@backstage/plugin-scaffolder': patch --- -RepoUrlPicker: refetch user credentials when a new host is selected +Fix issue with `RepoUrlPicker` not refreshing the credentials for a different host From d0e95a70369cb81bf2c74850a5c3b80250388110 Mon Sep 17 00:00:00 2001 From: Rich Barton-Cooper <58304039+richcooper95@users.noreply.github.com> Date: Fri, 3 May 2024 16:01:05 +0100 Subject: [PATCH 357/416] feat: expose uiSchema and formContext in FormProps This commit exposes two extra fields in the FormProps: `uiSchema` and `formContext`. Signed-off-by: Rich Barton-Cooper <rich@syntasso.io> Co-authored-by: Chunyi Lyu <chunyineko@gmail.com> --- .changeset/flat-plums-grow.md | 6 ++++++ plugins/scaffolder-react/api-report.md | 2 +- plugins/scaffolder-react/src/components/types.ts | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 .changeset/flat-plums-grow.md diff --git a/.changeset/flat-plums-grow.md b/.changeset/flat-plums-grow.md new file mode 100644 index 0000000000..b62f3e65a9 --- /dev/null +++ b/.changeset/flat-plums-grow.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-scaffolder-react': patch +--- + +Add ability to customise form fields in the UI by exposing `uiSchema` and `formContext` in +`FormProps` diff --git a/plugins/scaffolder-react/api-report.md b/plugins/scaffolder-react/api-report.md index a14490b80c..a19a656d17 100644 --- a/plugins/scaffolder-react/api-report.md +++ b/plugins/scaffolder-react/api-report.md @@ -128,7 +128,7 @@ export interface FieldExtensionUiSchema<TFieldReturnValue, TUiOptions> // @public export type FormProps = Pick< FormProps_2, - 'transformErrors' | 'noHtml5Validate' + 'transformErrors' | 'noHtml5Validate' | 'uiSchema' | 'formContext' >; // @public diff --git a/plugins/scaffolder-react/src/components/types.ts b/plugins/scaffolder-react/src/components/types.ts index 597998bac4..d5d317015d 100644 --- a/plugins/scaffolder-react/src/components/types.ts +++ b/plugins/scaffolder-react/src/components/types.ts @@ -32,7 +32,7 @@ export type TemplateGroupFilter = { */ export type FormProps = Pick< SchemaFormProps, - 'transformErrors' | 'noHtml5Validate' + 'transformErrors' | 'noHtml5Validate' | 'uiSchema' | 'formContext' >; /** From 8cdd846abc49841100cdaf5273d4793a821b475e Mon Sep 17 00:00:00 2001 From: Rich Barton-Cooper <rich@syntasso.io> Date: Mon, 22 Jul 2024 15:55:23 +0100 Subject: [PATCH 358/416] fix: merge uiSchema and formContext in Stepper component This commit ensures that the uiSchema and formContext are merged in the Stepper component form, with the non-props values taking precedence over the props values. The uiSchemas are deep-merged using `lodash.merge` to ensure that nested values are correctly merged. Signed-off-by: Rich Barton-Cooper <rich@syntasso.io> --- .../next/components/Stepper/Stepper.test.tsx | 60 +++++++++++++++++++ .../src/next/components/Stepper/Stepper.tsx | 15 ++++- 2 files changed, 72 insertions(+), 3 deletions(-) diff --git a/plugins/scaffolder-react/src/next/components/Stepper/Stepper.test.tsx b/plugins/scaffolder-react/src/next/components/Stepper/Stepper.test.tsx index df58d971fb..78aef3428f 100644 --- a/plugins/scaffolder-react/src/next/components/Stepper/Stepper.test.tsx +++ b/plugins/scaffolder-react/src/next/components/Stepper/Stepper.test.tsx @@ -549,6 +549,66 @@ describe('Stepper', () => { }); }); + it('should allow overrides to the uiSchema and formContext correctly', async () => { + const manifest: TemplateParameterSchema = { + title: 'Custom Fields', + steps: [ + { + title: 'Test', + schema: { + properties: { + name: { + type: 'string', + 'ui:placeholder': 'Enter your name', + }, + age: { + type: 'number', + 'ui:placeholder': 'Enter your age', + }, + }, + }, + }, + ], + }; + + const uiSchema = { + name: { + 'ui:readonly': true, + 'ui:placeholder': 'Should be overwritten', + }, + }; + + const formContext = { + readOnlyAsDisabled: true, + }; + + const { getByRole } = await renderInTestApp( + <SecretsContextProvider> + <Stepper + manifest={manifest} + onCreate={jest.fn()} + extensions={[]} + formProps={{ uiSchema, formContext }} + initialState={{ name: 'Some Name', age: 40 }} + /> + </SecretsContextProvider>, + ); + + expect(getByRole('textbox', { name: 'name' })).toHaveValue('Some Name'); + expect(getByRole('textbox', { name: 'name' })).toBeDisabled(); + expect(getByRole('textbox', { name: 'name' })).toHaveAttribute( + 'placeholder', + 'Enter your name', + ); + + expect(getByRole('spinbutton', { name: 'age' })).toHaveValue(40); + expect(getByRole('spinbutton', { name: 'age' })).toBeEnabled(); + expect(getByRole('spinbutton', { name: 'age' })).toHaveAttribute( + 'placeholder', + 'Enter your age', + ); + }); + describe('Scaffolder Layouts', () => { it('should render the step in the scaffolder layout', async () => { const ScaffolderLayout: LayoutTemplate = ({ properties }) => ( diff --git a/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx b/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx index 788c7cd715..3a8858144b 100644 --- a/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx +++ b/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx @@ -51,6 +51,7 @@ import { ErrorListTemplate } from './ErrorListTemplate'; import { makeStyles } from '@material-ui/core/styles'; import { PasswordWidget } from '../PasswordWidget/PasswordWidget'; import ajvErrors from 'ajv-errors'; +import { merge } from 'lodash'; const validator = customizeValidator(); ajvErrors(validator.ajv); @@ -193,6 +194,14 @@ export const Stepper = (stepperProps: StepperProps) => { setFormState(current => ({ ...current, ...formData })); }; + const { + formContext: propFormContext, + uiSchema: propUiSchema, + ...restFormProps + } = props.formProps ?? {}; + + const mergedUiSchema = merge({}, propUiSchema, currentStep?.uiSchema); + return ( <> {isValidating && <LinearProgress variant="indeterminate" />} @@ -229,9 +238,9 @@ export const Stepper = (stepperProps: StepperProps) => { validator={validator} extraErrors={errors as unknown as ErrorSchema} formData={formState} - formContext={{ formData: formState }} + formContext={{ ...propFormContext, formData: formState }} schema={currentStep.schema} - uiSchema={currentStep.uiSchema} + uiSchema={mergedUiSchema} onSubmit={handleNext} fields={fields} showErrorList="top" @@ -241,7 +250,7 @@ export const Stepper = (stepperProps: StepperProps) => { experimental_defaultFormStateBehavior={{ allOf: 'populateDefaults', }} - {...(props.formProps ?? {})} + {...restFormProps} > <div className={styles.footer}> <Button From 3ca333b683d542cee92998256f0a4607f45be452 Mon Sep 17 00:00:00 2001 From: Thomas Cardonne <thomas.cardonne@adevinta.com> Date: Mon, 22 Jul 2024 22:19:06 +0200 Subject: [PATCH 359/416] test(scaffolder-backend-module-gitlab): fix tests for gitlabProjectAccessTokenCreate examples Fixes tests created in #25713 Signed-off-by: Thomas Cardonne <thomas.cardonne@adevinta.com> --- ...tlabProjectAccessTokenCreate.examples.test.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectAccessTokenCreate.examples.test.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectAccessTokenCreate.examples.test.ts index 0762212809..bdf14ce1c8 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectAccessTokenCreate.examples.test.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectAccessTokenCreate.examples.test.ts @@ -215,7 +215,7 @@ describe('gitlab:projectAccessToken:create examples', () => { ['read_repository'], { accessLevel: 30, - expiresAt: '2025-07-21', + expiresAt: DateTime.now().plus({ days: 365 }).toISODate()!, }, ); @@ -271,7 +271,7 @@ describe('gitlab:projectAccessToken:create examples', () => { ['read_repository'], { accessLevel: 40, - expiresAt: '2025-07-21', + expiresAt: DateTime.now().plus({ days: 365 }).toISODate()!, }, ); @@ -299,7 +299,7 @@ describe('gitlab:projectAccessToken:create examples', () => { ['read_repository', 'read_api'], { accessLevel: 40, - expiresAt: '2025-07-21', + expiresAt: DateTime.now().plus({ days: 365 }).toISODate()!, }, ); @@ -327,7 +327,7 @@ describe('gitlab:projectAccessToken:create examples', () => { ['read_repository'], { accessLevel: 10, - expiresAt: '2025-07-21', + expiresAt: DateTime.now().plus({ days: 365 }).toISODate()!, }, ); @@ -355,7 +355,7 @@ describe('gitlab:projectAccessToken:create examples', () => { ['read_repository'], { accessLevel: 40, - expiresAt: '2025-07-21', + expiresAt: DateTime.now().plus({ days: 365 }).toISODate()!, }, ); @@ -383,7 +383,7 @@ describe('gitlab:projectAccessToken:create examples', () => { ['read_repository'], { accessLevel: 50, - expiresAt: '2025-07-21', + expiresAt: DateTime.now().plus({ days: 365 }).toISODate()!, }, ); @@ -411,7 +411,7 @@ describe('gitlab:projectAccessToken:create examples', () => { ['read_repository'], { accessLevel: 40, - expiresAt: '2025-07-21', + expiresAt: DateTime.now().plus({ days: 365 }).toISODate()!, }, ); @@ -439,7 +439,7 @@ describe('gitlab:projectAccessToken:create examples', () => { ['read_repository'], { accessLevel: 40, - expiresAt: '2025-07-21', + expiresAt: DateTime.now().plus({ days: 365 }).toISODate()!, }, ); From 97abfa22b9e98ad3c8b950628e19b4240243cb52 Mon Sep 17 00:00:00 2001 From: blam <ben@blam.sh> Date: Tue, 23 Jul 2024 08:01:34 +0200 Subject: [PATCH 360/416] chore: added some docs and cleanup the todos Signed-off-by: blam <ben@blam.sh> --- .../building-apps/03-built-in-extensions.md | 1 + .../building-apps/08-migrating.md | 25 +++++++++++++++++++ .../building-plugins/03-extension-types.md | 4 +++ .../frontend-app-api/src/wiring/createApp.tsx | 4 +-- 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/docs/frontend-system/building-apps/03-built-in-extensions.md b/docs/frontend-system/building-apps/03-built-in-extensions.md index 4f8417f74f..a5e6476eb0 100644 --- a/docs/frontend-system/building-apps/03-built-in-extensions.md +++ b/docs/frontend-system/building-apps/03-built-in-extensions.md @@ -45,6 +45,7 @@ This extension is the first extension attached to the extension tree. It is resp | themes | The app themes list. | [createThemeExtension.themeDataRef](https://backstage.io/docs/reference/frontend-plugin-api.createthemeextension.themedataref) | false | See [default themes](#default-theme-extensions). | [createThemeExtension](https://backstage.io/docs/reference/frontend-plugin-api.createthemeextension) | | components | The app components list. | [createComponentExtension.componentDataRef](https://backstage.io/docs/reference/frontend-plugin-api.createcomponentextension.componentdataref) | false | See [default components](#default-components-extensions). | [createComponentExtension](https://backstage.io/docs/reference/frontend-plugin-api.createcomponentextension) | | translations | The app translations list. | [createTranslationExtension.translationDataRef](https://backstage.io/docs/reference/frontend-plugin-api.createtranslationextension.translationdataref) | false | - | [createTranslationExtension](https://backstage.io/docs/reference/frontend-plugin-api.createtranslationextension) | +| icons | The app icons list. | [IconBundleBlueprint.dataRefs.icons](https://backstage.io/docs/reference/frontend-plugin-api.iconbundleblueprint.dataRefs.icons) | true | - | [IconBundleBlueprint](https://backstage.io/docs/reference/frontend-plugin-api.iconbundleblueprint) | #### Default theme extensions diff --git a/docs/frontend-system/building-apps/08-migrating.md b/docs/frontend-system/building-apps/08-migrating.md index 0abdd2aac3..716e0da772 100644 --- a/docs/frontend-system/building-apps/08-migrating.md +++ b/docs/frontend-system/building-apps/08-migrating.md @@ -314,6 +314,31 @@ const app = createApp({ }); ``` +### `icons` + +Icons are now installed as extensions, using the `IconBundleBlueprint` to make new instances which can be added to the app. + +```ts +import { IconBundleBlueprint } from '@backstage/frontend-plugin-api'; + +const exampleIconBundle = IconBundleBlueprint.make({ + name: 'example-bundle', + params: { + icons: { + user: MyOwnUserIcon, + }, + }, +}); + +const app = createApp({ + features: [ + createExtensionOverrides({ + extensions: [exampleIconBundle], + }), + ], +}); +``` + ### `bindRoutes` Route bindings can still be done using this option, but you now also have the ability to bind routes using static configuration instead. See the section on [binding routes](../architecture/07-routes.md#binding-external-route-references) for more information. diff --git a/docs/frontend-system/building-plugins/03-extension-types.md b/docs/frontend-system/building-plugins/03-extension-types.md index 2bea073ed6..1f3baaa710 100644 --- a/docs/frontend-system/building-plugins/03-extension-types.md +++ b/docs/frontend-system/building-plugins/03-extension-types.md @@ -38,6 +38,10 @@ Sign-in page extension have a single purpose - to implement a custom sign-in pag Theme extensions provide custom themes for the app. They are always attached to the app extension and you can have any number of themes extensions installed in an app at once, letting the user choose which theme to use. +### Icons - [Reference](../../reference/frontend-plugin-api.iconbundleblueprint.md) + +Icon bundle extensions provide the ability to replace or provide new icons to the app. You can use the above blueprint to make new extension instances which can be installed into the app. + ### Translation - [Reference](../../reference/frontend-plugin-api.createtranslationextension.md) Translation extension provide custom translation messages for the app. They can be used both to override the default english messages to custom ones, as well as provide translations for additional languages. diff --git a/packages/frontend-app-api/src/wiring/createApp.tsx b/packages/frontend-app-api/src/wiring/createApp.tsx index 4d929b206f..8d39cb65aa 100644 --- a/packages/frontend-app-api/src/wiring/createApp.tsx +++ b/packages/frontend-app-api/src/wiring/createApp.tsx @@ -172,7 +172,7 @@ export interface CreateAppFeatureLoader { /** @public */ export function createApp(options?: { - /** @deprecated - TODO */ + /** @deprecated - Please use {@link @backstage/frontend-app-api#IconBundleBlueprint} to make new icon bundles which can be installed in the app seperately */ icons?: { [key in string]: IconComponent }; features?: (FrontendFeature | CreateAppFeatureLoader)[]; configLoader?: () => Promise<{ config: ConfigApi }>; @@ -248,7 +248,7 @@ export function createApp(options?: { * @public */ export function createSpecializedApp(options?: { - /** @deprecated - TODO */ + /** @deprecated - Please use {@link @backstage/frontend-app-api#IconBundleBlueprint} to make new icon bundles which can be installed in the app seperately */ icons?: { [key in string]: IconComponent }; features?: FrontendFeature[]; config?: ConfigApi; From 2b4358b04429c02b6108bc93b285006ebd1a1be3 Mon Sep 17 00:00:00 2001 From: Ben Lambert <blam@spotify.com> Date: Tue, 23 Jul 2024 08:07:57 +0200 Subject: [PATCH 361/416] Update flat-plums-grow.md Signed-off-by: Ben Lambert <blam@spotify.com> --- .changeset/flat-plums-grow.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.changeset/flat-plums-grow.md b/.changeset/flat-plums-grow.md index b62f3e65a9..7057216786 100644 --- a/.changeset/flat-plums-grow.md +++ b/.changeset/flat-plums-grow.md @@ -2,5 +2,4 @@ '@backstage/plugin-scaffolder-react': patch --- -Add ability to customise form fields in the UI by exposing `uiSchema` and `formContext` in -`FormProps` +Add ability to customise form fields in the UI by exposing `uiSchema` and `formContext` in `FormProps` From d4e33aca1adc461063130fa36e255498490785ec Mon Sep 17 00:00:00 2001 From: blam <ben@blam.sh> Date: Tue, 23 Jul 2024 08:19:53 +0200 Subject: [PATCH 362/416] chore: fixing tests Signed-off-by: blam <ben@blam.sh> --- .../src/components/TabbedLayout/RoutedTabs.test.tsx | 5 +++-- .../src/components/TabbedLayout/RoutedTabs.tsx | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/core-components/src/components/TabbedLayout/RoutedTabs.test.tsx b/packages/core-components/src/components/TabbedLayout/RoutedTabs.test.tsx index 991276c5d3..754ac2ec8d 100644 --- a/packages/core-components/src/components/TabbedLayout/RoutedTabs.test.tsx +++ b/packages/core-components/src/components/TabbedLayout/RoutedTabs.test.tsx @@ -162,14 +162,15 @@ describe('RoutedTabs', () => { }); it('should render the tabs as <a> links', async () => { - const routes = [testRoute2, testRoute1, testRoute3]; + const routes = [testRoute1, testRoute2, testRoute3]; + const expectedHrefs = ['/', '/some-other-path', '/some-other-path-similar']; const rendered = await renderInTestApp(<RoutedTabs routes={routes} />); const tabs = rendered.queryAllByRole('tab'); for (const [k, v] of Object.entries(tabs)) { expect(v.tagName).toBe('A'); - expect(v).toHaveAttribute('href', routes[Number(k)].path); + expect(v).toHaveAttribute('href', expectedHrefs[Number(k)]); } }); }); diff --git a/packages/core-components/src/components/TabbedLayout/RoutedTabs.tsx b/packages/core-components/src/components/TabbedLayout/RoutedTabs.tsx index d6f6eab144..b57a3782bb 100644 --- a/packages/core-components/src/components/TabbedLayout/RoutedTabs.tsx +++ b/packages/core-components/src/components/TabbedLayout/RoutedTabs.tsx @@ -79,9 +79,9 @@ export function RoutedTabs(props: { routes: SubRoute[] }) { id: path, label: title, tabProps: { - ...tabProps, component: Link, to, + ...tabProps, }, }; }), From 663568ebb6946f09a16458feca290059cb2ae79a Mon Sep 17 00:00:00 2001 From: blam <ben@blam.sh> Date: Tue, 23 Jul 2024 08:28:46 +0200 Subject: [PATCH 363/416] chore: fixing todo package Signed-off-by: blam <ben@blam.sh> --- packages/frontend-app-api/src/wiring/createApp.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/frontend-app-api/src/wiring/createApp.tsx b/packages/frontend-app-api/src/wiring/createApp.tsx index 8d39cb65aa..d82d0ca782 100644 --- a/packages/frontend-app-api/src/wiring/createApp.tsx +++ b/packages/frontend-app-api/src/wiring/createApp.tsx @@ -172,7 +172,7 @@ export interface CreateAppFeatureLoader { /** @public */ export function createApp(options?: { - /** @deprecated - Please use {@link @backstage/frontend-app-api#IconBundleBlueprint} to make new icon bundles which can be installed in the app seperately */ + /** @deprecated - Please use {@link @backstage/frontend-plugin-api#IconBundleBlueprint} to make new icon bundles which can be installed in the app seperately */ icons?: { [key in string]: IconComponent }; features?: (FrontendFeature | CreateAppFeatureLoader)[]; configLoader?: () => Promise<{ config: ConfigApi }>; @@ -248,7 +248,7 @@ export function createApp(options?: { * @public */ export function createSpecializedApp(options?: { - /** @deprecated - Please use {@link @backstage/frontend-app-api#IconBundleBlueprint} to make new icon bundles which can be installed in the app seperately */ + /** @deprecated - Please use {@link @backstage/frontend-plugin-api#IconBundleBlueprint} to make new icon bundles which can be installed in the app seperately */ icons?: { [key in string]: IconComponent }; features?: FrontendFeature[]; config?: ConfigApi; From fbc7819133216ada61e2782a91b96a5d7954a0b2 Mon Sep 17 00:00:00 2001 From: Heikki Hellgren <heikki.hellgren@op.fi> Date: Tue, 23 Jul 2024 10:17:41 +0300 Subject: [PATCH 364/416] fix: use es2022 in cli bundler and in storybook fixes #25737 Signed-off-by: Heikki Hellgren <heikki.hellgren@op.fi> --- .changeset/cuddly-zebras-crash.md | 5 +++++ packages/cli/src/lib/bundler/optimization.ts | 4 ++-- packages/cli/src/lib/bundler/transforms.ts | 6 +++--- storybook/.storybook/main.js | 4 ++-- 4 files changed, 12 insertions(+), 7 deletions(-) create mode 100644 .changeset/cuddly-zebras-crash.md diff --git a/.changeset/cuddly-zebras-crash.md b/.changeset/cuddly-zebras-crash.md new file mode 100644 index 0000000000..473ac4053f --- /dev/null +++ b/.changeset/cuddly-zebras-crash.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Use ES2022 in CLI bundler diff --git a/packages/cli/src/lib/bundler/optimization.ts b/packages/cli/src/lib/bundler/optimization.ts index 891e0793fe..cf240b4791 100644 --- a/packages/cli/src/lib/bundler/optimization.ts +++ b/packages/cli/src/lib/bundler/optimization.ts @@ -28,13 +28,13 @@ export const optimization = ( minimize: !isDev, minimizer: [ new EsbuildPlugin({ - target: 'es2019', + target: 'ES2022', format: 'iife', exclude: 'remoteEntry.js', }), // Avoid iife wrapping of module federation remote entry as it breaks the variable assignment new EsbuildPlugin({ - target: 'es2019', + target: 'ES2022', format: undefined, include: 'remoteEntry.js', }), diff --git a/packages/cli/src/lib/bundler/transforms.ts b/packages/cli/src/lib/bundler/transforms.ts index 0900b8e48e..1be54f7a73 100644 --- a/packages/cli/src/lib/bundler/transforms.ts +++ b/packages/cli/src/lib/bundler/transforms.ts @@ -57,7 +57,7 @@ export const transforms = (options: TransformOptions): Transforms => { loader: require.resolve('swc-loader'), options: { jsc: { - target: 'es2019', + target: 'ES2022', externalHelpers: !isBackend, parser: { syntax: 'typescript', @@ -85,7 +85,7 @@ export const transforms = (options: TransformOptions): Transforms => { loader: require.resolve('swc-loader'), options: { jsc: { - target: 'es2019', + target: 'ES2022', externalHelpers: !isBackend, parser: { syntax: 'ecmascript', @@ -118,7 +118,7 @@ export const transforms = (options: TransformOptions): Transforms => { loader: require.resolve('swc-loader'), options: { jsc: { - target: 'es2019', + target: 'es2022', externalHelpers: !isBackend, parser: { syntax: 'ecmascript', diff --git a/storybook/.storybook/main.js b/storybook/.storybook/main.js index cb5f364a32..799c6c7c85 100644 --- a/storybook/.storybook/main.js +++ b/storybook/.storybook/main.js @@ -69,7 +69,7 @@ module.exports = Object.assign(({ args }) => { loader: require.resolve('swc-loader'), options: { jsc: { - target: 'es2019', + target: 'ES2022', parser: { syntax: 'typescript', tsx: true, @@ -89,7 +89,7 @@ module.exports = Object.assign(({ args }) => { loader: require.resolve('swc-loader'), options: { jsc: { - target: 'es2019', + target: 'ES2022', parser: { syntax: 'ecmascript', jsx: true, From faa1b465e9d5fb64110ff3fe121959f4839fbe3e Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg <poldsberg@gmail.com> Date: Tue, 23 Jul 2024 09:52:28 +0200 Subject: [PATCH 365/416] app-next,docs: add example for public index entry point in new frontend system Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com> --- docs/tutorials/enable-public-entry.md | 43 ++++++++++++++++ packages/app-next/src/App.tsx | 17 ++----- .../src/index-public-experimental.tsx | 49 +++++++++++++++++++ .../app-next/src/overrides/SignInPage.tsx | 31 ++++++++++++ 4 files changed, 126 insertions(+), 14 deletions(-) create mode 100644 packages/app-next/src/index-public-experimental.tsx create mode 100644 packages/app-next/src/overrides/SignInPage.tsx diff --git a/docs/tutorials/enable-public-entry.md b/docs/tutorials/enable-public-entry.md index 6282f66418..d257753413 100644 --- a/docs/tutorials/enable-public-entry.md +++ b/docs/tutorials/enable-public-entry.md @@ -100,3 +100,46 @@ With that, Backstage's cli and backend will detect public entry point and serve 5. Finally, as soon as you log in, you will be redirected to the main app home page (inspect the page and see that the protected bundle was served from the app backend after the redirect). That's it! + +## New Frontend System + +If your app uses the new frontend system, you can still use the public entry point feature. The `index-public-experimental.tsx` file does end up looking a bit different in this case: + +```tsx title="in packages/app/src/index-public-experimental.tsx" +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import { CookieAuthRedirect } from '@backstage/plugin-auth-react'; +import { createApp } from '@backstage/frontend-app-api'; +import { + coreExtensionData, + createExtension, + createExtensionOverrides, +} from '@backstage/frontend-plugin-api'; + +const signInPage = createSignInPageExtension({ + name: 'guest', + loader: async () => props => <SignInPage {...props} providers={['guest']} />, +}); + +const authRedirectExtension = createExtension({ + namespace: 'app', + name: 'layout', + attachTo: { id: 'app/root', input: 'children' }, + output: { + element: coreExtensionData.reactElement, + }, + factory: () => ({ + element: <CookieAuthRedirect />, + }), +}); + +const app = createApp({ + features: [ + createExtensionOverrides({ + extensions: [signInPage, authRedirectExtension], + }), + ], +}); + +ReactDOM.createRoot(document.getElementById('root')!).render(app.createRoot()); +``` diff --git a/packages/app-next/src/App.tsx b/packages/app-next/src/App.tsx index c911a01258..14c4da8467 100644 --- a/packages/app-next/src/App.tsx +++ b/packages/app-next/src/App.tsx @@ -36,18 +36,13 @@ import { convertLegacyApp } from '@backstage/core-compat-api'; import { FlatRoutes } from '@backstage/core-app-api'; import { Route } from 'react-router'; import { CatalogImportPage } from '@backstage/plugin-catalog-import'; -import { - createApiFactory, - configApiRef, - SignInPageProps, -} from '@backstage/core-plugin-api'; +import { createApiFactory, configApiRef } from '@backstage/core-plugin-api'; import { ScmAuth, ScmIntegrationsApi, scmIntegrationsApiRef, } from '@backstage/integration-react'; -import { createSignInPageExtension } from '@backstage/frontend-plugin-api'; -import { SignInPage } from '@backstage/core-components'; +import { signInPageOverrides } from './overrides/SignInPage'; /* @@ -90,12 +85,6 @@ const homePageExtension = createExtension({ }, }); -const signInPage = createSignInPageExtension({ - name: 'guest', - loader: async () => (props: SignInPageProps) => - <SignInPage {...props} providers={['guest']} />, -}); - const scmAuthExtension = createApiExtension({ factory: ScmAuth.createDefaultApiFactory(), }); @@ -121,13 +110,13 @@ const app = createApp({ userSettingsPlugin, homePlugin, appVisualizerPlugin, + signInPageOverrides, ...collectedLegacyPlugins, createExtensionOverrides({ extensions: [ homePageExtension, scmAuthExtension, scmIntegrationApi, - signInPage, notFoundErrorPage, ], }), diff --git a/packages/app-next/src/index-public-experimental.tsx b/packages/app-next/src/index-public-experimental.tsx new file mode 100644 index 0000000000..56bc698ffd --- /dev/null +++ b/packages/app-next/src/index-public-experimental.tsx @@ -0,0 +1,49 @@ +/* + * 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 from 'react'; +import ReactDOM from 'react-dom/client'; +import { CookieAuthRedirect } from '@backstage/plugin-auth-react'; +import { createApp } from '@backstage/frontend-app-api'; +import { signInPageOverrides } from './overrides/SignInPage'; +import { + coreExtensionData, + createExtension, + createExtensionOverrides, +} from '@backstage/frontend-plugin-api'; + +const authRedirectExtension = createExtension({ + namespace: 'app', + name: 'layout', + attachTo: { id: 'app/root', input: 'children' }, + output: { + element: coreExtensionData.reactElement, + }, + factory: () => ({ + element: <CookieAuthRedirect />, + }), +}); + +const app = createApp({ + features: [ + signInPageOverrides, + createExtensionOverrides({ + extensions: [authRedirectExtension], + }), + ], +}); + +ReactDOM.createRoot(document.getElementById('root')!).render(app.createRoot()); diff --git a/packages/app-next/src/overrides/SignInPage.tsx b/packages/app-next/src/overrides/SignInPage.tsx new file mode 100644 index 0000000000..364a749293 --- /dev/null +++ b/packages/app-next/src/overrides/SignInPage.tsx @@ -0,0 +1,31 @@ +/* + * Copyright 2024 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 { SignInPage } from '@backstage/core-components'; +import { + createExtensionOverrides, + createSignInPageExtension, +} from '@backstage/frontend-plugin-api'; + +const signInPage = createSignInPageExtension({ + name: 'guest', + loader: async () => props => <SignInPage {...props} providers={['guest']} />, +}); + +export const signInPageOverrides = createExtensionOverrides({ + extensions: [signInPage], +}); From c79eac60653eefe154ea0d68ccd0a9a72785bbc4 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg <poldsberg@gmail.com> Date: Tue, 23 Jul 2024 10:04:38 +0200 Subject: [PATCH 366/416] scaffolder: fix deprecation comment formatting Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com> --- .../src/deprecated.ts | 12 +++-- .../src/scaffolder/actions/deprecated.ts | 54 ++++++++++++------- 2 files changed, 44 insertions(+), 22 deletions(-) diff --git a/plugins/scaffolder-backend-module-bitbucket/src/deprecated.ts b/plugins/scaffolder-backend-module-bitbucket/src/deprecated.ts index a17c88c3a4..a9daa771f0 100644 --- a/plugins/scaffolder-backend-module-bitbucket/src/deprecated.ts +++ b/plugins/scaffolder-backend-module-bitbucket/src/deprecated.ts @@ -19,25 +19,29 @@ import * as bitbucketServer from '@backstage/plugin-scaffolder-backend-module-bi export { createPublishBitbucketAction } from './actions/bitbucket'; /** - * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-bitbucket-cloud instead + * @public + * @deprecated use import from `@backstage/plugin-scaffolder-backend-module-bitbucket-cloud` instead */ export const createPublishBitbucketCloudAction = bitbucketCloud.createPublishBitbucketCloudAction; /** - * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-bitbucket-cloud instead + * @public + * @deprecated use import from `@backstage/plugin-scaffolder-backend-module-bitbucket-cloud` instead */ export const createBitbucketPipelinesRunAction = bitbucketCloud.createBitbucketPipelinesRunAction; /** - * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-bitbucket-server instead + * @public + * @deprecated use import from `@backstage/plugin-scaffolder-backend-module-bitbucket-server` instead */ export const createPublishBitbucketServerAction = bitbucketServer.createPublishBitbucketServerAction; /** - * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-bitbucket-server instead + * @public + * @deprecated use import from `@backstage/plugin-scaffolder-backend-module-bitbucket-server` instead */ export const createPublishBitbucketServerPullRequestAction = bitbucketServer.createPublishBitbucketServerPullRequestAction; diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/deprecated.ts b/plugins/scaffolder-backend/src/scaffolder/actions/deprecated.ts index fd5fdd49e8..5d037b44b6 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/deprecated.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/deprecated.ts @@ -22,56 +22,66 @@ import * as bitbucketServer from '@backstage/plugin-scaffolder-backend-module-bi import * as gerrit from '@backstage/plugin-scaffolder-backend-module-gerrit'; /** - * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-github instead + * @public + * @deprecated use import from `@backstage/plugin-scaffolder-backend-module-github` instead */ export const createGithubActionsDispatchAction = github.createGithubActionsDispatchAction; /** - * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-github instead + * @public + * @deprecated use import from `@backstage/plugin-scaffolder-backend-module-github` instead */ export const createGithubDeployKeyAction = github.createGithubDeployKeyAction; /** - * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-github instead + * @public + * @deprecated use import from `@backstage/plugin-scaffolder-backend-module-github` instead */ export const createGithubEnvironmentAction = github.createGithubEnvironmentAction; /** - * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-github instead + * @public + * @deprecated use import from `@backstage/plugin-scaffolder-backend-module-github` instead */ export const createGithubIssuesLabelAction = github.createGithubIssuesLabelAction; /** - * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-github instead + * @public + * @deprecated use import from `@backstage/plugin-scaffolder-backend-module-github` instead */ export type CreateGithubPullRequestActionOptions = github.CreateGithubPullRequestActionOptions; /** - * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-github instead + * @public + * @deprecated use import from `@backstage/plugin-scaffolder-backend-module-github` instead */ export const createGithubRepoCreateAction = github.createGithubRepoCreateAction; /** - * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-github instead + * @public + * @deprecated use import from `@backstage/plugin-scaffolder-backend-module-github` instead */ export const createGithubRepoPushAction = github.createGithubRepoPushAction; /** - * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-github instead + * @public + * @deprecated use import from `@backstage/plugin-scaffolder-backend-module-github` instead */ export const createGithubWebhookAction = github.createGithubWebhookAction; /** - * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-github instead + * @public + * @deprecated use import from `@backstage/plugin-scaffolder-backend-module-github` instead */ export const createPublishGithubAction = github.createPublishGithubAction; /** - * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-github instead + * @public + * @deprecated use import from `@backstage/plugin-scaffolder-backend-module-github` instead */ export const createPublishGithubPullRequestAction = github.createPublishGithubPullRequestAction; @@ -83,46 +93,54 @@ export const createPublishBitbucketAction = bitbucket.createPublishBitbucketAction; /** - * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-bitbucket-cloud instead + * @public + * @deprecated use import from `@backstage/plugin-scaffolder-backend-module-bitbucket-cloud` instead */ export const createPublishBitbucketCloudAction = bitbucketCloud.createPublishBitbucketCloudAction; /** - * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-bitbucket-server instead + * @public + * @deprecated use import from `@backstage/plugin-scaffolder-backend-module-bitbucket-server` instead */ export const createPublishBitbucketServerAction = bitbucketServer.createPublishBitbucketServerAction; /** - * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-bitbucket-server instead + * @public + * @deprecated use import from `@backstage/plugin-scaffolder-backend-module-bitbucket-server` instead */ export const createPublishBitbucketServerPullRequestAction = bitbucketServer.createPublishBitbucketServerPullRequestAction; /** - * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-azure instead + * @public + * @deprecated use import from `@backstage/plugin-scaffolder-backend-module-azure` instead */ export const createPublishAzureAction = azure.createPublishAzureAction; /** - * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-gerrit instead + * @public + * @deprecated use import from `@backstage/plugin-scaffolder-backend-module-gerrit` instead */ export const createPublishGerritAction = gerrit.createPublishGerritAction; /** - * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-gerrit instead + * @public + * @deprecated use import from `@backstage/plugin-scaffolder-backend-module-gerrit` instead */ export const createPublishGerritReviewAction = gerrit.createPublishGerritReviewAction; /** - * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-gitlab instead + * @public + * @deprecated use import from `@backstage/plugin-scaffolder-backend-module-gitlab` instead */ export const createPublishGitlabAction = gitlab.createPublishGitlabAction; /** - * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-gitlab instead + * @public + * @deprecated use import from `@backstage/plugin-scaffolder-backend-module-gitlab` instead */ export const createPublishGitlabMergeRequestAction = gitlab.createPublishGitlabMergeRequestAction; From a6603e4f34e1b6c2338ebfa3d8034e6744efcb21 Mon Sep 17 00:00:00 2001 From: Yghore <yhgore@gmail.com> Date: Mon, 8 Jul 2024 21:32:28 +0200 Subject: [PATCH 367/416] feat: add automatic commited action for merge-request gitlab Signed-off-by: Yghore <yhgore@gmail.com> --- .changeset/wild-eggs-exist.md | 10 ++++ .../src/actions/gitlabMergeRequest.ts | 53 ++++++++++++++----- 2 files changed, 50 insertions(+), 13 deletions(-) create mode 100644 .changeset/wild-eggs-exist.md diff --git a/.changeset/wild-eggs-exist.md b/.changeset/wild-eggs-exist.md new file mode 100644 index 0000000000..68c49e343b --- /dev/null +++ b/.changeset/wild-eggs-exist.md @@ -0,0 +1,10 @@ +--- +'@backstage/plugin-scaffolder-backend-module-gitlab': patch +--- + +Add custom action for merge request: **auto** + +The **Auto** action selects the committed action between _create_ and _update_. + +The **Auto** action fetches files using the **/projects/repository/tree endpoint**. +After fetching, it checks if the file exists locally and in the repository. If it does, it chooses **update**; otherwise, it chooses **create**. diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabMergeRequest.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabMergeRequest.ts index a549585426..6032b4ac28 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabMergeRequest.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabMergeRequest.ts @@ -17,6 +17,7 @@ import { createTemplateAction, parseRepoUrl, + SerializedFile, serializeDirectoryContents, } from '@backstage/plugin-scaffolder-node'; import { Types } from '@gitbeaker/core'; @@ -27,6 +28,20 @@ import { resolveSafeChildPath } from '@backstage/backend-plugin-api'; import { createGitlabApi } from './helpers'; import { examples } from './gitlabMergeRequest.examples'; +function getFileAction( + file: SerializedFile, + remoteFiles: Types.RepositoryTreeSchema[], + defaultCommitAction: 'create' | 'delete' | 'update' | 'auto' | undefined, +): 'create' | 'delete' | 'update' { + if (defaultCommitAction === 'auto') { + return remoteFiles && + remoteFiles.some(remoteFile => remoteFile.path === file.path) + ? 'update' + : 'create'; + } + return defaultCommitAction ?? 'create'; +} + /** * Create a new action that creates a gitlab merge request. * @@ -46,7 +61,7 @@ export const createPublishGitlabMergeRequestAction = (options: { sourcePath?: string; targetPath?: string; token?: string; - commitAction?: 'create' | 'delete' | 'update'; + commitAction?: 'create' | 'delete' | 'update' | 'auto'; /** @deprecated projectID passed as query parameters in the repoUrl */ projectid?: string; removeSourceBranch?: boolean; @@ -109,9 +124,9 @@ export const createPublishGitlabMergeRequestAction = (options: { commitAction: { title: 'Commit action', type: 'string', - enum: ['create', 'update', 'delete'], + enum: ['create', 'update', 'delete', 'auto'], description: - 'The action to be used for git commit. Defaults to create.', + 'The action to be used for git commit. Defaults to create. "auto" is custom action provide by backstage, (automatic assign create or update action) /!\\ Use more api calls /!\\ *', }, removeSourceBranch: { title: 'Delete source branch', @@ -199,16 +214,7 @@ export const createPublishGitlabMergeRequestAction = (options: { gitignore: true, }); - const actions: Types.CommitAction[] = fileContents.map(file => ({ - action: ctx.input.commitAction ?? 'create', - filePath: targetPath - ? path.posix.join(targetPath, file.path) - : file.path, - encoding: 'base64', - content: file.content.toString('base64'), - execute_filemode: file.executable, - })); - + let remoteFiles: Types.RepositoryTreeSchema[]; let targetBranch = targetBranchName; if (!targetBranch) { const projects = await api.Projects.show(repoID); @@ -216,6 +222,27 @@ export const createPublishGitlabMergeRequestAction = (options: { const { default_branch: defaultBranch } = projects; targetBranch = defaultBranch!; } + try { + remoteFiles = await api.Repositories.tree(repoID, { + ref: targetBranch, + recursive: true, + path: targetPath ?? undefined, + }); + } catch (e) { + ctx.logger.warn( + `Could not retrieve the list of files for ${repoID} (branch: ${targetBranch}) : ${e}`, + ); + } + + const actions: Types.CommitAction[] = fileContents.map(file => ({ + action: getFileAction(file, remoteFiles, ctx.input.commitAction), + filePath: targetPath + ? path.posix.join(targetPath, file.path) + : file.path, + encoding: 'base64', + content: file.content.toString('base64'), + execute_filemode: file.executable, + })); try { await api.Branches.create(repoID, branchName, String(targetBranch)); From 224958e95239ddf67176fbf4695635dfad70d80d Mon Sep 17 00:00:00 2001 From: Yghore <yhgore@gmail.com> Date: Mon, 8 Jul 2024 21:55:46 +0200 Subject: [PATCH 368/416] doc: add api report Signed-off-by: Yghore <yhgore@gmail.com> --- .../scaffolder-backend-module-gitlab/api-report.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/plugins/scaffolder-backend-module-gitlab/api-report.md b/plugins/scaffolder-backend-module-gitlab/api-report.md index b1f240029e..4b5dc491ca 100644 --- a/plugins/scaffolder-backend-module-gitlab/api-report.md +++ b/plugins/scaffolder-backend-module-gitlab/api-report.md @@ -33,11 +33,11 @@ export const createGitlabIssueAction: (options: { projectId: number; labels?: string | undefined; description?: string | undefined; - weight?: number | undefined; token?: string | undefined; + weight?: number | undefined; assignees?: number[] | undefined; - createdAt?: string | undefined; confidential?: boolean | undefined; + createdAt?: string | undefined; milestoneId?: number | undefined; epicId?: number | undefined; dueDate?: string | undefined; @@ -61,8 +61,8 @@ export const createGitlabProjectAccessTokenAction: (options: { projectId: string | number; name?: string | undefined; token?: string | undefined; - scopes?: string[] | undefined; expiresAt?: string | undefined; + scopes?: string[] | undefined; accessLevel?: number | undefined; }, { @@ -118,7 +118,7 @@ export const createGitlabRepoPushAction: (options: { sourcePath?: string | undefined; targetPath?: string | undefined; token?: string | undefined; - commitAction?: 'update' | 'delete' | 'create' | undefined; + commitAction?: 'update' | 'create' | 'delete' | undefined; }, JsonObject >; @@ -193,7 +193,7 @@ export const createPublishGitlabMergeRequestAction: (options: { sourcePath?: string | undefined; targetPath?: string | undefined; token?: string | undefined; - commitAction?: 'update' | 'delete' | 'create' | undefined; + commitAction?: 'auto' | 'update' | 'create' | 'delete' | undefined; projectid?: string | undefined; removeSourceBranch?: boolean | undefined; assignee?: string | undefined; @@ -206,8 +206,8 @@ export const createTriggerGitlabPipelineAction: (options: { integrations: ScmIntegrationRegistry; }) => TemplateAction< { - branch: string; repoUrl: string; + branch: string; projectId: number; tokenDescription: string; token?: string | undefined; @@ -229,8 +229,8 @@ export const editGitlabIssueAction: (options: { title?: string | undefined; labels?: string | undefined; description?: string | undefined; - weight?: number | undefined; token?: string | undefined; + weight?: number | undefined; assignees?: number[] | undefined; addLabels?: string | undefined; confidential?: boolean | undefined; From ed0bea5d93d4b2e1f52d04469eb6b288fc13abde Mon Sep 17 00:00:00 2001 From: Yghore <yhgore@gmail.com> Date: Sun, 14 Jul 2024 22:56:19 +0200 Subject: [PATCH 369/416] fix(default action) create -> auto Signed-off-by: Yghore <yhgore@gmail.com> --- .../scaffolder-backend-module-gitlab/api-report.md | 14 +++++++------- .../src/actions/gitlabMergeRequest.ts | 6 +++--- plugins/scaffolder-backend/api-report.md | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/plugins/scaffolder-backend-module-gitlab/api-report.md b/plugins/scaffolder-backend-module-gitlab/api-report.md index 4b5dc491ca..ab89669ede 100644 --- a/plugins/scaffolder-backend-module-gitlab/api-report.md +++ b/plugins/scaffolder-backend-module-gitlab/api-report.md @@ -33,11 +33,11 @@ export const createGitlabIssueAction: (options: { projectId: number; labels?: string | undefined; description?: string | undefined; - token?: string | undefined; weight?: number | undefined; + token?: string | undefined; assignees?: number[] | undefined; - confidential?: boolean | undefined; createdAt?: string | undefined; + confidential?: boolean | undefined; milestoneId?: number | undefined; epicId?: number | undefined; dueDate?: string | undefined; @@ -61,8 +61,8 @@ export const createGitlabProjectAccessTokenAction: (options: { projectId: string | number; name?: string | undefined; token?: string | undefined; - expiresAt?: string | undefined; scopes?: string[] | undefined; + expiresAt?: string | undefined; accessLevel?: number | undefined; }, { @@ -118,7 +118,7 @@ export const createGitlabRepoPushAction: (options: { sourcePath?: string | undefined; targetPath?: string | undefined; token?: string | undefined; - commitAction?: 'update' | 'create' | 'delete' | undefined; + commitAction?: 'update' | 'delete' | 'create' | undefined; }, JsonObject >; @@ -193,7 +193,7 @@ export const createPublishGitlabMergeRequestAction: (options: { sourcePath?: string | undefined; targetPath?: string | undefined; token?: string | undefined; - commitAction?: 'auto' | 'update' | 'create' | 'delete' | undefined; + commitAction?: 'auto' | 'update' | 'delete' | 'create' | undefined; projectid?: string | undefined; removeSourceBranch?: boolean | undefined; assignee?: string | undefined; @@ -206,8 +206,8 @@ export const createTriggerGitlabPipelineAction: (options: { integrations: ScmIntegrationRegistry; }) => TemplateAction< { - repoUrl: string; branch: string; + repoUrl: string; projectId: number; tokenDescription: string; token?: string | undefined; @@ -229,8 +229,8 @@ export const editGitlabIssueAction: (options: { title?: string | undefined; labels?: string | undefined; description?: string | undefined; - token?: string | undefined; weight?: number | undefined; + token?: string | undefined; assignees?: number[] | undefined; addLabels?: string | undefined; confidential?: boolean | undefined; diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabMergeRequest.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabMergeRequest.ts index 6032b4ac28..d256a2166b 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabMergeRequest.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabMergeRequest.ts @@ -33,13 +33,13 @@ function getFileAction( remoteFiles: Types.RepositoryTreeSchema[], defaultCommitAction: 'create' | 'delete' | 'update' | 'auto' | undefined, ): 'create' | 'delete' | 'update' { - if (defaultCommitAction === 'auto') { + if (!defaultCommitAction || defaultCommitAction === 'auto') { return remoteFiles && remoteFiles.some(remoteFile => remoteFile.path === file.path) ? 'update' : 'create'; } - return defaultCommitAction ?? 'create'; + return defaultCommitAction; } /** @@ -126,7 +126,7 @@ export const createPublishGitlabMergeRequestAction = (options: { type: 'string', enum: ['create', 'update', 'delete', 'auto'], description: - 'The action to be used for git commit. Defaults to create. "auto" is custom action provide by backstage, (automatic assign create or update action) /!\\ Use more api calls /!\\ *', + 'The action to be used for git commit. Defaults to auto. "auto" is custom action provide by backstage, (automatic assign create or update action) /!\\ Use more api calls /!\\ *', }, removeSourceBranch: { title: 'Delete source branch', diff --git a/plugins/scaffolder-backend/api-report.md b/plugins/scaffolder-backend/api-report.md index a3beee2b53..907a30b541 100644 --- a/plugins/scaffolder-backend/api-report.md +++ b/plugins/scaffolder-backend/api-report.md @@ -312,7 +312,7 @@ export const createPublishGitlabMergeRequestAction: (options: { sourcePath?: string | undefined; targetPath?: string | undefined; token?: string | undefined; - commitAction?: 'update' | 'delete' | 'create' | undefined; + commitAction?: 'auto' | 'update' | 'delete' | 'create' | undefined; projectid?: string | undefined; removeSourceBranch?: boolean | undefined; assignee?: string | undefined; From 3afa2966b2e2b2d90196e604fffa939450e145e8 Mon Sep 17 00:00:00 2001 From: Yghore <yhgore@gmail.com> Date: Tue, 9 Jul 2024 13:12:25 +0000 Subject: [PATCH 370/416] fix: remote file was always fetched even without auto commit action Signed-off-by: Yghore <yhgore@gmail.com> --- .../src/actions/gitlabMergeRequest.ts | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabMergeRequest.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabMergeRequest.ts index d256a2166b..0c6a6fad48 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabMergeRequest.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabMergeRequest.ts @@ -214,7 +214,6 @@ export const createPublishGitlabMergeRequestAction = (options: { gitignore: true, }); - let remoteFiles: Types.RepositoryTreeSchema[]; let targetBranch = targetBranchName; if (!targetBranch) { const projects = await api.Projects.show(repoID); @@ -222,16 +221,20 @@ export const createPublishGitlabMergeRequestAction = (options: { const { default_branch: defaultBranch } = projects; targetBranch = defaultBranch!; } - try { - remoteFiles = await api.Repositories.tree(repoID, { - ref: targetBranch, - recursive: true, - path: targetPath ?? undefined, - }); - } catch (e) { - ctx.logger.warn( - `Could not retrieve the list of files for ${repoID} (branch: ${targetBranch}) : ${e}`, - ); + + let remoteFiles: Types.RepositoryTreeSchema[] = []; + if (ctx.input.commitAction && ctx.input.commitAction === 'auto') { + try { + remoteFiles = await api.Repositories.tree(repoID, { + ref: targetBranch, + recursive: true, + path: targetPath ?? undefined, + }); + } catch (e) { + ctx.logger.warn( + `Could not retrieve the list of files for ${repoID} (branch: ${targetBranch}) : ${e}`, + ); + } } const actions: Types.CommitAction[] = fileContents.map(file => ({ From 9281a5e9bd60da001cc413dd58a7043a94232e72 Mon Sep 17 00:00:00 2001 From: Yghore <yhgore@gmail.com> Date: Mon, 15 Jul 2024 12:29:41 +0000 Subject: [PATCH 371/416] fix(filepath if targetPath is set), fix(default commitAction not retrieve repo files) Signed-off-by: Yghore <yhgore@gmail.com> --- .../src/actions/gitlabMergeRequest.ts | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabMergeRequest.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabMergeRequest.ts index 0c6a6fad48..733365c6df 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabMergeRequest.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabMergeRequest.ts @@ -29,13 +29,14 @@ import { createGitlabApi } from './helpers'; import { examples } from './gitlabMergeRequest.examples'; function getFileAction( - file: SerializedFile, + fileInfo: { file: SerializedFile; targetPath: string | undefined }, remoteFiles: Types.RepositoryTreeSchema[], defaultCommitAction: 'create' | 'delete' | 'update' | 'auto' | undefined, ): 'create' | 'delete' | 'update' { if (!defaultCommitAction || defaultCommitAction === 'auto') { + const filePath = path.join(fileInfo.targetPath ?? '', fileInfo.file.path); return remoteFiles && - remoteFiles.some(remoteFile => remoteFile.path === file.path) + remoteFiles.some(remoteFile => remoteFile.path === filePath) ? 'update' : 'create'; } @@ -223,7 +224,7 @@ export const createPublishGitlabMergeRequestAction = (options: { } let remoteFiles: Types.RepositoryTreeSchema[] = []; - if (ctx.input.commitAction && ctx.input.commitAction === 'auto') { + if (!ctx.input.commitAction || ctx.input.commitAction === 'auto') { try { remoteFiles = await api.Repositories.tree(repoID, { ref: targetBranch, @@ -238,7 +239,11 @@ export const createPublishGitlabMergeRequestAction = (options: { } const actions: Types.CommitAction[] = fileContents.map(file => ({ - action: getFileAction(file, remoteFiles, ctx.input.commitAction), + action: getFileAction( + { file, targetPath }, + remoteFiles, + ctx.input.commitAction, + ), filePath: targetPath ? path.posix.join(targetPath, file.path) : file.path, From 422f883e4e8a7b38452ba6f58e0af910d8894ae3 Mon Sep 17 00:00:00 2001 From: Yghore <yhgore@gmail.com> Date: Mon, 15 Jul 2024 12:33:00 +0000 Subject: [PATCH 372/416] add: test for auto commited action Signed-off-by: Yghore <yhgore@gmail.com> --- .../src/actions/gitlabMergeRequest.test.ts | 115 +++++++++++++++++- 1 file changed, 113 insertions(+), 2 deletions(-) diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabMergeRequest.test.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabMergeRequest.test.ts index befc2c01c9..3eda50a924 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabMergeRequest.test.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabMergeRequest.test.ts @@ -61,6 +61,28 @@ const mockGitlabClient = { ]; }), }, + Repositories: { + tree: jest.fn( + async ( + repoID: string | number, + options: { ref: string; recursive: boolean; path: string | undefined }, + ) => { + if (repoID !== 'owner/repo') throw new Error('repo does not exist'); + if (options.recursive === false) throw new Error('malformed options'); + else { + return [ + { + id: 'a1e8f8d745cc87e3a9248358d9352bb7f9a0aeba', + name: 'auto.txt', + type: 'blob', + path: 'source/auto.txt', + mode: '040000', + }, + ]; + } + }, + ), + }, }; jest.mock('@gitbeaker/node', () => ({ @@ -407,7 +429,7 @@ describe('createGitLabMergeRequest', () => { }); describe('createGitLabMergeRequestWithoutCommitAction', () => { - it('default commitAction is create', async () => { + it('default commitAction is auto', async () => { const input = { repoUrl: 'gitlab.com?repo=repo&owner=owner', title: 'Create my new MR', @@ -417,7 +439,7 @@ describe('createGitLabMergeRequest', () => { }; mockDir.setContent({ [workspacePath]: { - source: { 'foo.txt': 'Hello there!' }, + source: { 'foo.txt': 'Hello there!', 'auto.txt': 'File exist' }, irrelevant: { 'bar.txt': 'Nothing to see here' }, }, }); @@ -429,6 +451,13 @@ describe('createGitLabMergeRequest', () => { 'new-mr', 'Create my new MR', [ + { + action: 'update', + filePath: 'source/auto.txt', + content: 'RmlsZSBleGlzdA==', + encoding: 'base64', + execute_filemode: false, + }, { action: 'create', filePath: 'source/foo.txt', @@ -512,6 +541,88 @@ describe('createGitLabMergeRequest', () => { ); }); + it('commitAction is auto when auto is passed in options', async () => { + const input = { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + title: 'Create my new MR', + branchName: 'new-mr', + description: 'MR description', + commitAction: 'auto', + }; + mockDir.setContent({ + [workspacePath]: { + source: { 'foo.txt': 'Hello there!', 'auto.txt': 'File exist' }, + }, + }); + + const ctx = createMockActionContext({ input, workspacePath }); + await instance.handler(ctx); + + expect(mockGitlabClient.Commits.create).toHaveBeenCalledWith( + 'owner/repo', + 'new-mr', + 'Create my new MR', + [ + { + action: 'update', + filePath: 'source/auto.txt', + content: 'RmlsZSBleGlzdA==', + encoding: 'base64', + execute_filemode: false, + }, + { + action: 'create', + filePath: 'source/foo.txt', + content: 'SGVsbG8gdGhlcmUh', + encoding: 'base64', + execute_filemode: false, + }, + ], + ); + }); + + it('commitAction is auto when auto is passed in options with targetPath', async () => { + const input = { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + title: 'Create my new MR', + branchName: 'new-mr', + description: 'MR description', + commitAction: 'auto', + targetPath: 'source', + }; + mockDir.setContent({ + [workspacePath]: { + source: { 'foo.txt': 'Hello there!', 'auto.txt': 'File exist' }, + irrevelant: {}, + }, + }); + + const ctx = createMockActionContext({ input, workspacePath }); + await instance.handler(ctx); + + expect(mockGitlabClient.Commits.create).toHaveBeenCalledWith( + 'owner/repo', + 'new-mr', + 'Create my new MR', + [ + { + action: 'update', + filePath: 'source/auto.txt', + content: 'RmlsZSBleGlzdA==', + encoding: 'base64', + execute_filemode: false, + }, + { + action: 'create', + filePath: 'source/foo.txt', + content: 'SGVsbG8gdGhlcmUh', + encoding: 'base64', + execute_filemode: false, + }, + ], + ); + }); + it('commitAction is delete when delete is passed in options', async () => { const input = { repoUrl: 'gitlab.com?repo=repo&owner=owner', From 9999ce0937e33086ca2c8a601400f2967b4ebfb1 Mon Sep 17 00:00:00 2001 From: Yghore <yhgore@gmail.com> Date: Mon, 15 Jul 2024 12:47:17 +0000 Subject: [PATCH 373/416] fix: add api-report... Signed-off-by: Yghore <yhgore@gmail.com> --- plugins/scaffolder-backend/api-report.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/plugins/scaffolder-backend/api-report.md b/plugins/scaffolder-backend/api-report.md index 907a30b541..ca008c4280 100644 --- a/plugins/scaffolder-backend/api-report.md +++ b/plugins/scaffolder-backend/api-report.md @@ -312,7 +312,10 @@ export const createPublishGitlabMergeRequestAction: (options: { sourcePath?: string | undefined; targetPath?: string | undefined; token?: string | undefined; - commitAction?: 'auto' | 'update' | 'delete' | 'create' | undefined; + commitAction?: 'auto' | 'update' | 'delete' | 'create' | undefined + /** + * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-github instead + */; projectid?: string | undefined; removeSourceBranch?: boolean | undefined; assignee?: string | undefined; From 6bec6090a8bbfb11691118bf87c416afdd77eacc Mon Sep 17 00:00:00 2001 From: blam <ben@blam.sh> Date: Tue, 23 Jul 2024 10:21:26 +0200 Subject: [PATCH 374/416] chore: fix api-reports Signed-off-by: blam <ben@blam.sh> --- plugins/scaffolder-backend/api-report.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/plugins/scaffolder-backend/api-report.md b/plugins/scaffolder-backend/api-report.md index ca008c4280..907a30b541 100644 --- a/plugins/scaffolder-backend/api-report.md +++ b/plugins/scaffolder-backend/api-report.md @@ -312,10 +312,7 @@ export const createPublishGitlabMergeRequestAction: (options: { sourcePath?: string | undefined; targetPath?: string | undefined; token?: string | undefined; - commitAction?: 'auto' | 'update' | 'delete' | 'create' | undefined - /** - * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-github instead - */; + commitAction?: 'auto' | 'update' | 'delete' | 'create' | undefined; projectid?: string | undefined; removeSourceBranch?: boolean | undefined; assignee?: string | undefined; From c3f56507740906dddeeb6304216db9f77755dec6 Mon Sep 17 00:00:00 2001 From: blam <ben@blam.sh> Date: Tue, 23 Jul 2024 10:32:30 +0200 Subject: [PATCH 375/416] chore: migrate the EntityCardExtension to EntityCardBlueprint Signed-off-by: blam <ben@blam.sh> --- plugins/catalog-react/src/alpha.tsx | 39 +++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/plugins/catalog-react/src/alpha.tsx b/plugins/catalog-react/src/alpha.tsx index e81b8e5ebf..7f276b8ea6 100644 --- a/plugins/catalog-react/src/alpha.tsx +++ b/plugins/catalog-react/src/alpha.tsx @@ -22,6 +22,7 @@ import { RouteRef, coreExtensionData, createExtension, + createExtensionBlueprint, createExtensionDataRef, createSchemaFromZod, } from '@backstage/frontend-plugin-api'; @@ -47,6 +48,44 @@ export const catalogExtensionData = { }), }; +/** @alpha */ +export const EntityCardBlueprint = createExtensionBlueprint({ + kind: 'entity-card', + attachTo: { id: 'entity-content:catalog/overview', input: 'cards' }, + configSchema: createSchemaFromZod(z => + z.object({ + filter: z.string().optional(), + }), + ), + output: { + element: coreExtensionData.reactElement, + filterFunction: catalogExtensionData.entityFilterFunction.optional(), + filterExpression: catalogExtensionData.entityFilterExpression.optional(), + }, + factory( + params: { + filter?: + | typeof catalogExtensionData.entityFilterFunction.T + | typeof catalogExtensionData.entityFilterExpression.T; + loader: () => Promise<JSX.Element>; + }, + { node, config }, + ) { + const ExtensionComponent = lazy(() => + params.loader().then(element => ({ default: () => element })), + ); + + return { + element: ( + <ExtensionBoundary node={node}> + <ExtensionComponent /> + </ExtensionBoundary> + ), + ...mergeFilters({ config, options: params }), + }; + }, +}); + // TODO: Figure out how to merge with provided config schema /** @alpha */ export function createEntityCardExtension< From d5bf3b1f4b7dd3f1c2ba76141c3ba972e0dcfd20 Mon Sep 17 00:00:00 2001 From: blam <ben@blam.sh> Date: Tue, 23 Jul 2024 11:09:33 +0200 Subject: [PATCH 376/416] chore: rework how to define factory functions and params in blueprints Signed-off-by: blam <ben@blam.sh> --- .../wiring/createExtensionBlueprint.test.tsx | 13 +-- .../src/wiring/createExtensionBlueprint.ts | 110 ++++++++++-------- 2 files changed, 66 insertions(+), 57 deletions(-) diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.test.tsx b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.test.tsx index 87b3cec152..d2373518a3 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.test.tsx +++ b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.test.tsx @@ -88,20 +88,17 @@ describe('createExtensionBlueprint', () => { const extension = TestExtensionBlueprint.make({ name: 'my-extension', - params: { - text: 'Hello, world!', - }, - factory(params: { text: string }) { - return { - element: <h2>{params.text}</h2>, - }; + factory(origFactory) { + return origFactory({ + text: 'Hello, world!', + }); }, }); expect(extension).toBeDefined(); const { container } = createExtensionTester(extension).render(); - expect(container.querySelector('h2')).toHaveTextContent('Hello, world!'); + expect(container.querySelector('h1')).toHaveTextContent('Hello, world!'); }); it('should allow exporting the dataRefs from the extension blueprint', () => { diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts index b504db5f03..fb9081f7f8 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts @@ -67,32 +67,43 @@ export interface ExtensionBlueprint< > { dataRefs: TDataRefs; - make(args: { - namespace?: string; - name?: string; - attachTo?: { id: string; input: string }; - disabled?: boolean; - inputs?: TInputs; - output?: TOutput; - configSchema?: PortableSchema<TConfig>; - params: TParams; - factory?( - params: TParams, - context: { - node: AppNode; - config: TConfig; - inputs: Expand<ResolvedExtensionInputs<TInputs>>; - orignalFactory( - params?: TParams, - context?: { - node?: AppNode; - config?: TConfig; - inputs?: Expand<ResolvedExtensionInputs<TInputs>>; - }, - ): Expand<ExtensionDataValues<TOutput>>; - }, - ): Expand<ExtensionDataValues<TOutput>>; - }): ExtensionDefinition<TConfig>; + /** + * Creates a new extension from the blueprint. + * + * You must either pass `params` directly, or define a `factory` that can + * optionally call the original factory with the same params. + */ + make( + args: { + namespace?: string; + name?: string; + attachTo?: { id: string; input: string }; + disabled?: boolean; + inputs?: TInputs; + output?: TOutput; + configSchema?: PortableSchema<TConfig>; + } & ( + | { + factory( + originalFactory: ( + params: TParams, + context?: { + config?: TConfig; + inputs?: Expand<ResolvedExtensionInputs<TInputs>>; + }, + ) => Expand<ExtensionDataValues<TOutput>>, + context: { + node: AppNode; + config: TConfig; + inputs: Expand<ResolvedExtensionInputs<TInputs>>; + }, + ): Expand<ExtensionDataValues<TOutput>>; + } + | { + params: TParams; + } + ), + ): ExtensionDefinition<TConfig>; } /** @@ -127,21 +138,19 @@ class ExtensionBlueprintImpl< inputs?: TInputs; output?: TOutput; configSchema?: PortableSchema<TConfig>; - params: TParams; + params?: TParams; factory?( - params: TParams, + originalFactory: ( + params: TParams, + context?: { + config?: TConfig; + inputs?: Expand<ResolvedExtensionInputs<TInputs>>; + }, + ) => Expand<ExtensionDataValues<TOutput>>, context: { node: AppNode; config: TConfig; inputs: Expand<ResolvedExtensionInputs<TInputs>>; - orignalFactory( - params?: TParams, - context?: { - node?: AppNode; - config?: TConfig; - inputs?: Expand<ResolvedExtensionInputs<TInputs>>; - }, - ): Expand<ExtensionDataValues<TOutput>>; }, ): Expand<ExtensionDataValues<TOutput>>; }): ExtensionDefinition<TConfig> { @@ -156,30 +165,33 @@ class ExtensionBlueprintImpl< configSchema: args.configSchema ?? this.options.configSchema, // TODO: some config merging or smth factory: ({ node, config, inputs }) => { if (args.factory) { - return args.factory(args.params, { - node, - config, - inputs, - orignalFactory: ( - innerParams?: TParams, + return args.factory( + ( + innerParams: TParams, innerContext?: { config?: TConfig; inputs?: Expand<ResolvedExtensionInputs<TInputs>>; }, ) => - this.options.factory(innerParams ?? args.params, { + this.options.factory(innerParams, { node, config: innerContext?.config ?? config, inputs: innerContext?.inputs ?? inputs, }), + { + node, + config, + inputs, + }, + ); + } else if (args.params) { + return this.options.factory(args.params, { + node, + config, + inputs, }); } - - return this.options.factory(args.params, { - node, - config, - inputs, - }); + throw new Error('Either params or factory must be provided'); }, }); } From 32a38e1f37dd02476a17d78cfc3cc18cc7f08b24 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg <poldsberg@gmail.com> Date: Sun, 21 Jul 2024 13:21:43 +0200 Subject: [PATCH 377/416] cli: remove most lockfile analysis features Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com> --- .changeset/neat-gifts-join.md | 5 + .changeset/small-spoons-shout.md | 13 ++ .../config/vocabularies/Backstage/accept.txt | 2 + .../keeping-backstage-updated.md | 24 +- docs/tooling/cli/03-commands.md | 21 +- packages/cli/cli-report.md | 11 - packages/cli/src/commands/index.ts | 2 +- .../cli/src/commands/versions/bump.test.ts | 174 +------------- packages/cli/src/commands/versions/bump.ts | 98 +------- packages/cli/src/commands/versions/lint.ts | 114 +-------- packages/cli/src/lib/bundler/server.ts | 39 ---- .../cli/src/lib/versioning/Lockfile.test.ts | 219 ------------------ packages/cli/src/lib/versioning/Lockfile.ts | 211 ----------------- plugins/devtools-backend/src/util/Lockfile.ts | 189 +-------------- 14 files changed, 43 insertions(+), 1079 deletions(-) create mode 100644 .changeset/neat-gifts-join.md create mode 100644 .changeset/small-spoons-shout.md diff --git a/.changeset/neat-gifts-join.md b/.changeset/neat-gifts-join.md new file mode 100644 index 0000000000..cd140c4692 --- /dev/null +++ b/.changeset/neat-gifts-join.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-devtools-backend': patch +--- + +Removed unused code for lockfile analysis. diff --git a/.changeset/small-spoons-shout.md b/.changeset/small-spoons-shout.md new file mode 100644 index 0000000000..76c209edc6 --- /dev/null +++ b/.changeset/small-spoons-shout.md @@ -0,0 +1,13 @@ +--- +'@backstage/cli': minor +--- + +**BREAKING**: The lockfile (`yarn.lock`) dependency analysis and mutations have been removed from several commands. + +The `versions:bump` command will no longer attempt to bump and deduplicate dependencies by modifying the lockfile, it will only update `package.json` files. + +The `versions:check` command has been removed, since its only purpose was verification and mutation of the lockfile. We recommend using the `yarn dedupe` command instead, or the `yarn-deduplicate` package if you're using Yarn classic. + +The check that was built into the `package start` command has been removed, it will no longer warn about lockfile mismatches. + +The packages in the Backstage ecosystem handle package duplications much better now than when these CLI features were first introduced, so the need for these features has diminished. By removing them, we drastically reduce the integration between the Backstage CLI and Yarn, making it much easier to add support for other package managers in the future. diff --git a/.github/vale/config/vocabularies/Backstage/accept.txt b/.github/vale/config/vocabularies/Backstage/accept.txt index 1092947245..42b0e4895c 100644 --- a/.github/vale/config/vocabularies/Backstage/accept.txt +++ b/.github/vale/config/vocabularies/Backstage/accept.txt @@ -85,7 +85,9 @@ debounce Debounce debuggability declaratively +deduplicate deduplicated +deduplication deliverables denormalized dependabot diff --git a/docs/getting-started/keeping-backstage-updated.md b/docs/getting-started/keeping-backstage-updated.md index 1de8874d56..88e4a02ef2 100644 --- a/docs/getting-started/keeping-backstage-updated.md +++ b/docs/getting-started/keeping-backstage-updated.md @@ -63,18 +63,16 @@ When a given dependency version is the _same_ between different packages, the dependency is hoisted to the main `node_modules` folder in the monorepo root to be shared between packages. When _different_ versions of the same dependency are encountered, Yarn creates a `node_modules` folder within a particular package. +This can lead to multiple versions of the same package being installed and used +in the same app. -This can lead to confusing situations with type definitions, or anything with -global state. React [Context](https://reactjs.org/docs/context.html), for -example, depends on global referential equality. This can cause problems in -Backstage with API lookup, or config loading. +All Backstage core packages are implemented in such as way that package +duplication is **not** a problem. For example, duplicate installations of +packages like `@backstage/core-plugin-api`, `@backstage/core-components`, +`@backstage/plugin-catalog-react`, and `@backstage/backend-plugin-api` are all +acceptable. -To help resolve these situations, the Backstage CLI has -[versions:check](https://backstage.io/docs/tooling/cli/03-commands#versionscheck). This -will validate versions of `@backstage` packages in your app to check for -duplicate definitions: - -```bash -# Add --fix to attempt automatic resolution in yarn.lock -yarn backstage-cli versions:check -``` +While package duplication might be acceptable in many cases, you might want to +deduplicate packages for the purpose of optimizing bundle size and installation +speed. We recommend using deduplication utilities such as `yarn dedupe` to trim +down the number of duplicate packages. diff --git a/docs/tooling/cli/03-commands.md b/docs/tooling/cli/03-commands.md index 234d0d04b7..a6652bd036 100644 --- a/docs/tooling/cli/03-commands.md +++ b/docs/tooling/cli/03-commands.md @@ -26,7 +26,6 @@ repo [command] Command that run across an entire package [command] Lifecycle scripts for individual packages migrate [command] Migration utilities versions:bump [options] Bump Backstage packages to the latest versions -versions:check [options] Check Backstage package versioning clean Delete cache directories [DEPRECATED] build-workspace <workspace-dir> [packages...] Builds a temporary dist workspace from the provided packages @@ -327,8 +326,7 @@ Options: ## versions\:bump Bump all `@backstage` packages to the latest versions. This checks for updates -in the package registry, and will update entries both in `yarn.lock` and -`package.json` files when necessary. +in the package registry, and will update entries `package.json` files when necessary. ```text Usage: backstage-cli versions:bump [options] @@ -339,23 +337,6 @@ Options: --release <version|next|main> Bump to a specific Backstage release line or version (default: "main") ``` -## versions\:check - -Validate `@backstage` dependencies within the repo, making sure that there are -no duplicates of packages that might lead to breakages. - -By supplying the `--fix` flag the command will attempt to fix any conflict that -can be resolved by editing `yarn.lock`, but will not attempt to search for -remote updates or modify any `package.json` files. - -```text -Usage: backstage-cli versions:check [options] - -Options: - --fix Fix any auto-fixable versioning problems - -h, --help display help for command -``` - ## build-workspace Builds a mirror of the workspace using the packaged production version of each diff --git a/packages/cli/cli-report.md b/packages/cli/cli-report.md index 01b0f7ddec..907f0298f2 100644 --- a/packages/cli/cli-report.md +++ b/packages/cli/cli-report.md @@ -22,7 +22,6 @@ Commands: package [command] migrate [command] versions:bump [options] - versions:check [options] versions:migrate [options] clean build-workspace [options] <workspace-dir> [packages...] @@ -607,16 +606,6 @@ Options: -h, --help ``` -### `backstage-cli versions:check` - -``` -Usage: backstage-cli versions:check [options] - -Options: - --fix - -h, --help -``` - ### `backstage-cli versions:migrate` ``` diff --git a/packages/cli/src/commands/index.ts b/packages/cli/src/commands/index.ts index 25a3a4e26c..fa4bb05333 100644 --- a/packages/cli/src/commands/index.ts +++ b/packages/cli/src/commands/index.ts @@ -396,7 +396,7 @@ export function registerCommands(program: Command) { .action(lazy(() => import('./versions/bump').then(m => m.default))); program - .command('versions:check') + .command('versions:check', { hidden: true }) .option('--fix', 'Fix any auto-fixable versioning problems') .description('Check Backstage package versioning') .action(lazy(() => import('./versions/lint').then(m => m.default))); diff --git a/packages/cli/src/commands/versions/bump.test.ts b/packages/cli/src/commands/versions/bump.test.ts index b8677a48c5..cc48b91fd8 100644 --- a/packages/cli/src/commands/versions/bump.test.ts +++ b/packages/cli/src/commands/versions/bump.test.ts @@ -23,7 +23,6 @@ import { YarnInfoInspectData } from '../../lib/versioning/packages'; import { setupServer } from 'msw/node'; import { rest } from 'msw'; import { NotFoundError } from '@backstage/errors'; -import { Lockfile } from '../../lib/versioning/Lockfile'; import { MockDirectory, createMockDirectory, @@ -117,17 +116,6 @@ const lockfileMock = `${HEADER} version "1.0.3" `; -// This is the lockfile that we produce to unlock versions before we run yarn install -const lockfileMockResult = `${HEADER} -"@backstage/core@^1.0.5": - version "1.0.6" - dependencies: - "@backstage/core-api" "^1.0.6" - -"@backstage/theme@^1.0.0": - version "1.0.0" -`; - // Avoid flakes by comparing sorted log lines. File system access is async, which leads to the log line order being indeterministic const expectLogsToMatch = ( recievedLogs: String[], @@ -204,11 +192,7 @@ describe('bump', () => { 'Using default pattern glob @backstage/*', 'Checking for updates of @backstage/core', 'Checking for updates of @backstage/theme', - 'Checking for updates of @backstage/core-api', 'Some packages are outdated, updating', - 'unlocking @backstage/core@^1.0.3 ~> 1.0.6', - 'unlocking @backstage/core-api@^1.0.6 ~> 1.0.7', - 'unlocking @backstage/core-api@^1.0.3 ~> 1.0.7', 'bumping @backstage/core in a to ^1.0.6', 'bumping @backstage/core in b to ^1.0.6', 'bumping @backstage/theme in b to ^2.0.0', @@ -220,9 +204,8 @@ describe('bump', () => { 'Version bump complete!', ]); - expect(mockFetchPackageInfo).toHaveBeenCalledTimes(3); + expect(mockFetchPackageInfo).toHaveBeenCalledTimes(2); expect(mockFetchPackageInfo).toHaveBeenCalledWith('@backstage/core'); - expect(mockFetchPackageInfo).toHaveBeenCalledWith('@backstage/core-api'); expect(mockFetchPackageInfo).toHaveBeenCalledWith('@backstage/theme'); expect(runObj.run).toHaveBeenCalledTimes(1); @@ -232,12 +215,6 @@ describe('bump', () => { expect.any(Object), ); - const lockfileContents = await fs.readFile( - mockDir.resolve('yarn.lock'), - 'utf8', - ); - expect(lockfileContents).toBe(lockfileMockResult); - const packageA = await fs.readJson( mockDir.resolve('packages/a/package.json'), ); @@ -312,11 +289,7 @@ describe('bump', () => { 'Using default pattern glob @backstage/*', 'Checking for updates of @backstage/core', 'Checking for updates of @backstage/theme', - 'Checking for updates of @backstage/core-api', 'Some packages are outdated, updating', - 'unlocking @backstage/core@^1.0.3 ~> 1.0.6', - 'unlocking @backstage/core-api@^1.0.6 ~> 1.0.7', - 'unlocking @backstage/core-api@^1.0.3 ~> 1.0.7', 'bumping @backstage/core in a to ^1.0.6', 'bumping @backstage/core in b to ^1.0.6', 'bumping @backstage/theme in b to ^2.0.0', @@ -328,9 +301,8 @@ describe('bump', () => { 'Version bump complete!', ]); - expect(mockFetchPackageInfo).toHaveBeenCalledTimes(3); + expect(mockFetchPackageInfo).toHaveBeenCalledTimes(2); expect(mockFetchPackageInfo).toHaveBeenCalledWith('@backstage/core'); - expect(mockFetchPackageInfo).toHaveBeenCalledWith('@backstage/core-api'); expect(mockFetchPackageInfo).toHaveBeenCalledWith('@backstage/theme'); expect(runObj.run).not.toHaveBeenCalledWith( @@ -339,12 +311,6 @@ describe('bump', () => { expect.any(Object), ); - const lockfileContents = await fs.readFile( - mockDir.resolve('yarn.lock'), - 'utf8', - ); - expect(lockfileContents).toBe(lockfileMockResult); - const packageA = await fs.readJson( mockDir.resolve('packages/a/package.json'), ); @@ -425,12 +391,7 @@ describe('bump', () => { 'Using default pattern glob @backstage/*', 'Checking for updates of @backstage/core', 'Checking for updates of @backstage/theme', - 'Checking for updates of @backstage/theme', - 'Checking for updates of @backstage/core-api', 'Some packages are outdated, updating', - 'unlocking @backstage/core@^1.0.3 ~> 1.0.6', - 'unlocking @backstage/core-api@^1.0.6 ~> 1.0.7', - 'unlocking @backstage/core-api@^1.0.3 ~> 1.0.7', 'bumping @backstage/theme in b to ^5.0.0', 'bumping @backstage/core in b to ^1.0.6', 'bumping @backstage/core in a to ^1.0.6', @@ -443,9 +404,8 @@ describe('bump', () => { 'Version bump complete!', ]); - expect(mockFetchPackageInfo).toHaveBeenCalledTimes(2); + expect(mockFetchPackageInfo).toHaveBeenCalledTimes(1); expect(mockFetchPackageInfo).toHaveBeenCalledWith('@backstage/core'); - expect(mockFetchPackageInfo).not.toHaveBeenCalledWith('@backstage/theme'); expect(runObj.run).toHaveBeenCalledTimes(1); expect(runObj.run).toHaveBeenCalledWith( @@ -454,12 +414,6 @@ describe('bump', () => { expect.any(Object), ); - const lockfileContents = await fs.readFile( - mockDir.resolve('yarn.lock'), - 'utf8', - ); - expect(lockfileContents).toBe(lockfileMockResult); - const packageA = await fs.readJson( mockDir.resolve('packages/a/package.json'), ); @@ -629,12 +583,7 @@ describe('bump', () => { 'Using default pattern glob @backstage/*', 'Checking for updates of @backstage/core', 'Checking for updates of @backstage/theme', - 'Checking for updates of @backstage/theme', - 'Checking for updates of @backstage/core-api', 'Some packages are outdated, updating', - 'unlocking @backstage/core@^1.0.3 ~> 1.0.6', - 'unlocking @backstage/core-api@^1.0.6 ~> 1.0.7', - 'unlocking @backstage/core-api@^1.0.3 ~> 1.0.7', 'bumping @backstage/theme in b to ^5.0.0', 'bumping @backstage/core in b to ^1.0.6', 'bumping @backstage/core in a to ^1.0.6', @@ -658,21 +607,6 @@ describe('bump', () => { "@backstage-extra/custom-two@^1.0.0": version "1.0.0" -`; - const customLockfileMockResult = `${HEADER} -"@backstage-extra/custom-two@^1.0.0": - version "1.0.0" - -"@backstage-extra/custom@^1.1.0": - version "1.1.0" - -"@backstage/core@^1.0.5": - version "1.0.6" - dependencies: - "@backstage/core-api" "^1.0.6" - -"@backstage/theme@^1.0.0": - version "1.0.0" `; mockDir.setContent({ 'yarn.lock': customLockfileMock, @@ -731,12 +665,7 @@ describe('bump', () => { 'Checking for updates of @backstage-extra/custom', 'Checking for updates of @backstage-extra/custom-two', 'Checking for updates of @backstage/theme', - 'Checking for updates of @backstage/core-api', 'Some packages are outdated, updating', - 'unlocking @backstage/core@^1.0.3 ~> 1.0.6', - 'unlocking @backstage-extra/custom@^1.0.1 ~> 1.1.0', - 'unlocking @backstage/core-api@^1.0.6 ~> 1.0.7', - 'unlocking @backstage/core-api@^1.0.3 ~> 1.0.7', 'bumping @backstage/core in a to ^1.0.6', 'bumping @backstage-extra/custom in a to ^1.1.0', 'bumping @backstage-extra/custom-two in a to ^2.0.0', @@ -754,7 +683,7 @@ describe('bump', () => { 'Version bump complete!', ]); - expect(mockFetchPackageInfo).toHaveBeenCalledTimes(5); + expect(mockFetchPackageInfo).toHaveBeenCalledTimes(4); expect(mockFetchPackageInfo).toHaveBeenCalledWith('@backstage/core'); expect(mockFetchPackageInfo).toHaveBeenCalledWith('@backstage/theme'); @@ -765,12 +694,6 @@ describe('bump', () => { expect.any(Object), ); - const lockfileContents = await fs.readFile( - mockDir.resolve('yarn.lock'), - 'utf8', - ); - expect(lockfileContents).toEqual(customLockfileMockResult); - const packageA = await fs.readJson( mockDir.resolve('packages/a/package.json'), ); @@ -798,7 +721,7 @@ describe('bump', () => { it('should ignore not found packages', async () => { mockDir.setContent({ - 'yarn.lock': lockfileMockResult, + 'yarn.lock': lockfileMock, 'package.json': JSON.stringify({ workspaces: { packages: ['packages/*'], @@ -848,21 +771,11 @@ describe('bump', () => { 'Checking for updates of @backstage/theme', 'Package info not found, ignoring package @backstage/core', 'Package info not found, ignoring package @backstage/theme', - 'Checking for updates of @backstage/core', - 'Checking for updates of @backstage/theme', - 'Package info not found, ignoring package @backstage/core', - 'Package info not found, ignoring package @backstage/theme', 'All Backstage packages are up to date!', ]); expect(runObj.run).toHaveBeenCalledTimes(0); - const lockfileContents = await fs.readFile( - mockDir.resolve('yarn.lock'), - 'utf8', - ); - expect(lockfileContents).toBe(lockfileMockResult); - const packageA = await fs.readJson( mockDir.resolve('packages/a/package.json'), ); @@ -883,83 +796,6 @@ describe('bump', () => { }, }); }); - - // eslint-disable-next-line jest/expect-expect - it('should log duplicates', async () => { - jest.spyOn(Lockfile.prototype, 'analyze').mockReturnValue({ - invalidRanges: [], - newVersions: [], - newRanges: [ - { - name: '@backstage/backend-app-api', - oldRange: '^1.0.0', - newRange: '^2.0.0', - oldVersion: '1.0.0', - newVersion: '2.0.0', - }, - ], - }); - mockDir.setContent({ - 'yarn.lock': `${HEADER} -"@backstage/backend-app-api@^1.0.0": - version "1.0.0" -`, - 'package.json': JSON.stringify({ - workspaces: { - packages: ['packages/*'], - }, - }), - packages: { - a: { - 'package.json': JSON.stringify({ - name: 'a', - dependencies: { - '@backstage/backend-app-api': '^1.0.0', - }, - }), - }, - }, - }); - - jest.spyOn(runObj, 'run').mockResolvedValue(undefined); - worker.use( - rest.get( - 'https://versions.backstage.io/v1/tags/main/manifest.json', - (_, res, ctx) => - res( - ctx.status(200), - ctx.json({ - packages: [ - { - name: '@backstage/backend-app-api', - version: '2.0.0', - }, - ], - }), - ), - ), - ); - const { log: logs } = await withLogCollector(['log', 'warn'], async () => { - await bump({ pattern: null, release: 'main' } as unknown as Command); - }); - expectLogsToMatch(logs, [ - 'Using default pattern glob @backstage/*', - 'Checking for updates of @backstage/backend-app-api', - 'Checking for updates of @backstage/backend-app-api', - 'Some packages are outdated, updating', - 'bumping @backstage/backend-app-api in a to ^2.0.0', - 'Running yarn install to install new versions', - 'Checking for moved packages to the @backstage-community namespace...', - '⚠️ The following packages may have breaking changes:', - ' @backstage/backend-app-api : 1.0.0 ~> 2.0.0', - ' https://github.com/backstage/backstage/blob/master/packages/backend-app-api/CHANGELOG.md', - 'Version bump complete!', - ' ⚠️ Warning! ⚠️', - ' The below package(s) have incompatible duplicate installations, likely due to a bad dependency in a plugin.', - ' You can investigate this by running `yarn why <package-name>`, and report the issue to the plugin maintainers.', - ' @backstage/backend-app-api', - ]); - }); }); describe('bumpBackstageJsonVersion', () => { diff --git a/packages/cli/src/commands/versions/bump.ts b/packages/cli/src/commands/versions/bump.ts index d6d5f424ba..5b981d3890 100644 --- a/packages/cli/src/commands/versions/bump.ts +++ b/packages/cli/src/commands/versions/bump.ts @@ -24,7 +24,6 @@ import fs from 'fs-extra'; import chalk from 'chalk'; import ora from 'ora'; import semver from 'semver'; -import { minimatch } from 'minimatch'; import { OptionValues } from 'commander'; import { isError, NotFoundError } from '@backstage/errors'; import { resolve as resolvePath } from 'path'; @@ -36,7 +35,6 @@ import { Lockfile, YarnInfoInspectData, } from '../../lib/versioning'; -import { forbiddenDuplicatesFilter } from './lint'; import { BACKSTAGE_JSON } from '@backstage/cli-common'; import { runParallelWorkers } from '../../lib/parallel'; import { @@ -44,7 +42,6 @@ import { getManifestByVersion, ReleaseManifest, } from '@backstage/release-manifests'; -import { PackageGraph } from '@backstage/cli-node'; import { migrateMovedPackages } from './migrate'; function shouldUseGlobalAgent(): boolean { @@ -125,8 +122,6 @@ export default async (opts: OptionValues) => { // Next check with the package registry to see which dependency ranges we need to bump const versionBumps = new Map<string, PkgVersionInfo[]>(); - // Track package versions that we want to remove from yarn.lock in order to trigger a bump - const unlocked = Array<{ name: string; range: string; target: string }>(); await runParallelWorkers({ parallelismFactor: 4, @@ -157,72 +152,13 @@ export default async (opts: OptionValues) => { }, }); - const filter = (name: string) => minimatch(name, pattern); - - // Check for updates of transitive backstage dependencies - await runParallelWorkers({ - parallelismFactor: 4, - items: lockfile.keys(), - async worker(name) { - // Only check @backstage packages and friends, we don't want this to do a full update of all deps - if (!filter(name)) { - return; - } - - let target: string; - try { - target = await findTargetVersion(name); - } catch (error) { - if (isError(error) && error.name === 'NotFoundError') { - console.log(`Package info not found, ignoring package ${name}`); - return; - } - throw error; - } - - for (const entry of lockfile.get(name) ?? []) { - // Ignore lockfile entries that don't satisfy the version range, since - // these can't cause the package to be locked to an older version - if (!semver.satisfies(target, entry.range)) { - continue; - } - // Unlock all entries that are within range but on the old version - unlocked.push({ name, range: entry.range, target }); - } - }, - }); - - console.log(); - // Write all discovered version bumps to package.json in this repo - if (versionBumps.size === 0 && unlocked.length === 0) { + if (versionBumps.size === 0) { console.log(chalk.green('All Backstage packages are up to date!')); } else { console.log(chalk.yellow('Some packages are outdated, updating')); console.log(); - if (unlocked.length > 0) { - const removed = new Set<string>(); - for (const { name, range, target } of unlocked) { - // Don't bother removing lockfile entries if they're already on the correct version - const existingEntry = lockfile.get(name)?.find(e => e.range === range); - if (existingEntry?.version === target) { - continue; - } - const key = JSON.stringify({ name, range }); - if (!removed.has(key)) { - removed.add(key); - console.log( - `${chalk.magenta('unlocking')} ${name}@${chalk.yellow( - range, - )} ~> ${chalk.yellow(target)}`, - ); - lockfile.remove(name, range); - } - } - await lockfile.save(lockfilePath); - } - const breakingUpdates = new Map<string, { from: string; to: string }>(); await runParallelWorkers({ parallelismFactor: 4, @@ -334,38 +270,6 @@ export default async (opts: OptionValues) => { } console.log(); - - // Finally we make sure the new lockfile doesn't have any duplicates - const dedupLockfile = await Lockfile.load(lockfilePath); - - const result = dedupLockfile.analyze({ - filter, - localPackages: PackageGraph.fromPackages( - await PackageGraph.listTargetPackages(), - ), - }); - - const forbiddenNewRanges = result.newRanges.filter(({ name }) => - forbiddenDuplicatesFilter(name), - ); - if (forbiddenNewRanges.length > 0) { - console.log(chalk.yellow(' ⚠️ Warning! ⚠️')); - console.log(); - console.log( - chalk.yellow( - ' The below package(s) have incompatible duplicate installations, likely due to a bad dependency in a plugin.', - ), - ); - console.log( - chalk.yellow( - ' You can investigate this by running `yarn why <package-name>`, and report the issue to the plugin maintainers.', - ), - ); - console.log(); - for (const { name } of forbiddenNewRanges) { - console.log(chalk.yellow(` ${name}`)); - } - } }; export function createStrictVersionFinder(options: { diff --git a/packages/cli/src/commands/versions/lint.ts b/packages/cli/src/commands/versions/lint.ts index bfb2a752a0..66b5fc04c4 100644 --- a/packages/cli/src/commands/versions/lint.ts +++ b/packages/cli/src/commands/versions/lint.ts @@ -14,116 +14,8 @@ * limitations under the License. */ -import { OptionValues } from 'commander'; -import { Lockfile } from '../../lib/versioning'; -import { paths } from '../../lib/paths'; -import partition from 'lodash/partition'; -import { PackageGraph } from '@backstage/cli-node'; - -// Packages that we try to avoid duplicates for -const INCLUDED = [/^@backstage\//]; - -export const includedFilter = (name: string) => - INCLUDED.some(pattern => pattern.test(name)); - -// Packages that are not allowed to have any duplicates -const FORBID_DUPLICATES = [/^@backstage\/\w+-app-api$/, /^@backstage\/plugin-/]; - -// There are some packages that ARE explicitly allowed to have duplicates since -// they handle that appropriately. This takes precedence over FORBID_DUPLICATES -// above. -const ALLOW_DUPLICATES = [ - /^@backstage\/core-plugin-api$/, - // Duplicates of libraries are OK - // TODO(Rugvip): Check this using package role instead - /^@backstage\/plugin-.*-react$/, - /^@backstage\/plugin-.*-node$/, - /^@backstage\/plugin-.*-common$/, -]; - -export const forbiddenDuplicatesFilter = (name: string) => - FORBID_DUPLICATES.some(pattern => pattern.test(name)) && - !ALLOW_DUPLICATES.some(pattern => pattern.test(name)); - -export default async (cmd: OptionValues) => { - const fix = Boolean(cmd.fix); - - let success = true; - - const lockfilePath = paths.resolveTargetRoot('yarn.lock'); - const lockfile = await Lockfile.load(lockfilePath); - const result = lockfile.analyze({ - filter: includedFilter, - localPackages: PackageGraph.fromPackages( - await PackageGraph.listTargetPackages(), - ), - }); - - logArray( - result.invalidRanges, - "The following packages versions are invalid and can't be analyzed:", - e => ` ${e.name} @ ${e.range}`, +export default async () => { + throw new Error( + 'This command has been removed, please consider alternatives such as `yarn dedupe` instead.', ); - - if (fix) { - lockfile.replaceVersions(result.newVersions); - await lockfile.save(lockfilePath); - } else { - const [newVersionsForbidden, newVersionsAllowed] = partition( - result.newVersions, - ({ name }) => forbiddenDuplicatesFilter(name), - ); - if (newVersionsForbidden.length && !fix) { - success = false; - } - - logArray( - newVersionsForbidden, - 'The following packages must be deduplicated, this can be done automatically with --fix', - e => - ` ${e.name} @ ${e.range} bumped from ${e.oldVersion} to ${e.newVersion}`, - ); - logArray( - newVersionsAllowed, - 'The following packages can be deduplicated, this can be done automatically with --fix', - e => - ` ${e.name} @ ${e.range} bumped from ${e.oldVersion} to ${e.newVersion}`, - ); - } - - const [newRangesForbidden, newRangesAllowed] = partition( - result.newRanges, - ({ name }) => forbiddenDuplicatesFilter(name), - ); - if (newRangesForbidden.length) { - success = false; - } - - logArray( - newRangesForbidden, - 'The following packages must be deduplicated by updating dependencies in package.json', - e => ` ${e.name} @ ${e.oldRange} should be changed to ${e.newRange}`, - ); - logArray( - newRangesAllowed, - 'The following packages can be deduplicated by updating dependencies in package.json', - e => ` ${e.name} @ ${e.oldRange} should be changed to ${e.newRange}`, - ); - - if (!success) { - throw new Error('Failed versioning check'); - } }; - -function logArray<T>(arr: T[], header: string, each: (item: T) => string) { - if (arr.length === 0) { - return; - } - - console.log(header); - console.log(); - for (const e of arr) { - console.log(each(e)); - } - console.log(); -} diff --git a/packages/cli/src/lib/bundler/server.ts b/packages/cli/src/lib/bundler/server.ts index 6b89847fb6..259f3263eb 100644 --- a/packages/cli/src/lib/bundler/server.ts +++ b/packages/cli/src/lib/bundler/server.ts @@ -14,22 +14,15 @@ * limitations under the License. */ -import { PackageGraph } from '@backstage/cli-node'; import { AppConfig } from '@backstage/config'; import chalk from 'chalk'; import fs from 'fs-extra'; -import uniq from 'lodash/uniq'; import openBrowser from 'react-dev-utils/openBrowser'; import webpack from 'webpack'; import WebpackDevServer from 'webpack-dev-server'; -import { - forbiddenDuplicatesFilter, - includedFilter, -} from '../../commands/versions/lint'; import { paths as libPaths } from '../../lib/paths'; import { loadCliConfig } from '../config'; -import { Lockfile } from '../versioning'; import { createConfig, resolveBaseUrl, resolveEndpoint } from './config'; import { createDetectedModulesEntryPoint } from './packageDetection'; import { resolveBundlingPaths, resolveOptionalBundlingPaths } from './paths'; @@ -41,38 +34,6 @@ export async function serveBundle(options: ServeOptions) { const targetPkg = await fs.readJson(paths.targetPackageJson); if (options.verifyVersions) { - const lockfile = await Lockfile.load( - libPaths.resolveTargetRoot('yarn.lock'), - ); - const result = lockfile.analyze({ - filter: includedFilter, - localPackages: PackageGraph.fromPackages( - await PackageGraph.listTargetPackages(), - ), - }); - const problemPackages = [...result.newVersions, ...result.newRanges] - .map(({ name }) => name) - .filter(forbiddenDuplicatesFilter); - - if (problemPackages.length > 1) { - console.log( - chalk.yellow( - `⚠️ Some of the following packages may be outdated or have duplicate installations: - - ${uniq(problemPackages).join(', ')} - `, - ), - ); - console.log( - chalk.yellow( - `⚠️ This can be resolved using the following command: - - yarn backstage-cli versions:check --fix - `, - ), - ); - } - if ( targetPkg.dependencies?.['react-router']?.includes('beta') || targetPkg.dependencies?.['react-router-dom']?.includes('beta') diff --git a/packages/cli/src/lib/versioning/Lockfile.test.ts b/packages/cli/src/lib/versioning/Lockfile.test.ts index a4267acdb7..d6996b9143 100644 --- a/packages/cli/src/lib/versioning/Lockfile.test.ts +++ b/packages/cli/src/lib/versioning/Lockfile.test.ts @@ -14,8 +14,6 @@ * limitations under the License. */ -import fs from 'fs-extra'; -import { BackstagePackage } from '@backstage/cli-node'; import { Lockfile } from './Lockfile'; import { createMockDirectory } from '@backstage/backend-test-utils'; @@ -47,34 +45,6 @@ b@^2: version "2.0.0" `; -const mockADedup = `${LEGACY_HEADER} -a@^1: - version "1.0.1" - resolved "https://my-registry/a-1.0.01.tgz#abc123" - integrity sha512-xyz - dependencies: - b "^2" - -b@2.0.x, b@^2: - version "2.0.1" -`; - -const mockB = `${LEGACY_HEADER} -"@s/a@*", "@s/a@1 || 2", "@s/a@^1": - version "1.0.1" - -"@s/a@^2.0.x": - version "2.0.0" -`; - -const mockBDedup = `${LEGACY_HEADER} -"@s/a@*", "@s/a@1 || 2", "@s/a@^2.0.x": - version "2.0.0" - -"@s/a@^1": - version "1.0.1" -`; - describe('Lockfile', () => { const mockDir = createMockDirectory(); @@ -93,75 +63,6 @@ describe('Lockfile', () => { ]); expect(lockfile.toString()).toBe(mockA); }); - - it('should deduplicate and save mockA', async () => { - mockDir.setContent({ - 'yarn.lock': mockA, - }); - - const lockfilePath = mockDir.resolve('yarn.lock'); - const lockfile = await Lockfile.load(lockfilePath); - const result = lockfile.analyze({ localPackages: new Map() }); - expect(result).toEqual({ - invalidRanges: [], - newRanges: [], - newVersions: [ - { - name: 'b', - range: '^2', - oldVersion: '2.0.0', - newVersion: '2.0.1', - }, - ], - }); - - expect(lockfile.toString()).toBe(mockA); - lockfile.replaceVersions(result.newVersions); - expect(lockfile.toString()).toBe(mockADedup); - - await expect(fs.readFile(lockfilePath, 'utf8')).resolves.toBe(mockA); - await expect(lockfile.save(lockfilePath)).resolves.toBeUndefined(); - await expect(fs.readFile(lockfilePath, 'utf8')).resolves.toBe(mockADedup); - }); - - it('should deduplicate mockB', async () => { - mockDir.setContent({ - 'yarn.lock': mockB, - }); - - const lockfile = await Lockfile.load(mockDir.resolve('yarn.lock')); - const result = lockfile.analyze({ localPackages: new Map() }); - expect(result).toEqual({ - invalidRanges: [], - newRanges: [ - { - name: '@s/a', - oldRange: '^1', - newRange: '^2.0.x', - oldVersion: '1.0.1', - newVersion: '2.0.0', - }, - ], - newVersions: [ - { - name: '@s/a', - range: '*', - oldVersion: '1.0.1', - newVersion: '2.0.0', - }, - { - name: '@s/a', - range: '1 || 2', - oldVersion: '1.0.1', - newVersion: '2.0.0', - }, - ], - }); - - expect(lockfile.toString()).toBe(mockB); - lockfile.replaceVersions(result.newVersions); - expect(lockfile.toString()).toBe(mockBDedup); - }); }); const mockANew = `${MODERN_HEADER} @@ -179,51 +80,6 @@ b@^2: version: 2.0.0 `; -const mockANewDedup = `${MODERN_HEADER} -a@^1: - version: 1.0.1 - dependencies: - b: ^2 - integrity: sha512-xyz - resolved: "https://my-registry/a-1.0.01.tgz#abc123" - -"b@2.0.x, b@^2.0.1": - version: 2.0.1 - -b@^2: - version: 2.0.1 -`; - -const mockANewLocal = `${MODERN_HEADER} -a@^1: - version: 1.0.1 - dependencies: - b: ^2 - integrity: sha512-xyz - resolved: "https://my-registry/a-1.0.01.tgz#abc123" - -"b@2.0.x, b@^2.0.1": - version: 0.0.0-use.local - -b@^2: - version: 2.0.0 -`; - -const mockANewLocalDedup = `${MODERN_HEADER} -a@^1: - version: 1.0.1 - dependencies: - b: ^2 - integrity: sha512-xyz - resolved: "https://my-registry/a-1.0.01.tgz#abc123" - -"b@2.0.x, b@^2.0.1": - version: 0.0.0-use.local - -b@^2: - version: 0.0.0-use.local -`; - describe('New Lockfile', () => { const mockDir = createMockDirectory(); @@ -243,79 +99,4 @@ describe('New Lockfile', () => { ]); expect(lockfile.toString()).toBe(mockANew); }); - - it('should deduplicate and save mockANew', async () => { - mockDir.setContent({ - 'yarn.lock': mockANew, - }); - - const lockfilePath = mockDir.resolve('yarn.lock'); - const lockfile = await Lockfile.load(lockfilePath); - const result = lockfile.analyze({ localPackages: new Map() }); - expect(result).toEqual({ - invalidRanges: [], - newRanges: [], - newVersions: [ - { - name: 'b', - range: '^2', - oldVersion: '2.0.0', - newVersion: '2.0.1', - }, - ], - }); - - expect(lockfile.toString()).toBe(mockANew); - lockfile.replaceVersions(result.newVersions); - expect(lockfile.toString()).toBe(mockANewDedup); - - await expect(fs.readFile(lockfilePath, 'utf8')).resolves.toBe(mockANew); - await expect(lockfile.save(lockfilePath)).resolves.toBeUndefined(); - await expect(fs.readFile(lockfilePath, 'utf8')).resolves.toBe( - mockANewDedup, - ); - }); - - it('should deduplicate and save mockANewLocal', async () => { - mockDir.setContent({ - 'yarn.lock': mockANewLocal, - }); - - const lockfilePath = mockDir.resolve('yarn.lock'); - const lockfile = await Lockfile.load(lockfilePath); - const result = lockfile.analyze({ - localPackages: new Map([ - [ - 'b', - { - packageJson: { version: '2.0.1' }, - } as BackstagePackage, - ], - ]), - }); - expect(result).toEqual({ - invalidRanges: [], - newRanges: [], - newVersions: [ - { - name: 'b', - range: '^2', - oldVersion: '2.0.0', - newVersion: '0.0.0-use.local', - }, - ], - }); - - expect(lockfile.toString()).toBe(mockANewLocal); - lockfile.replaceVersions(result.newVersions); - expect(lockfile.toString()).toBe(mockANewLocalDedup); - - await expect(fs.readFile(lockfilePath, 'utf8')).resolves.toBe( - mockANewLocal, - ); - await expect(lockfile.save(lockfilePath)).resolves.toBeUndefined(); - await expect(fs.readFile(lockfilePath, 'utf8')).resolves.toBe( - mockANewLocalDedup, - ); - }); }); diff --git a/packages/cli/src/lib/versioning/Lockfile.ts b/packages/cli/src/lib/versioning/Lockfile.ts index 50d0a77cfd..047cf5aefc 100644 --- a/packages/cli/src/lib/versioning/Lockfile.ts +++ b/packages/cli/src/lib/versioning/Lockfile.ts @@ -15,10 +15,8 @@ */ import fs from 'fs-extra'; -import semver from 'semver'; import { parseSyml, stringifySyml } from '@yarnpkg/parsers'; import { stringify as legacyStringifyLockfile } from '@yarnpkg/lockfile'; -import { BackstagePackage } from '@backstage/cli-node'; const ENTRY_PATTERN = /^((?:@[^/]+\/)?[^@/]+)@(.+)$/; @@ -39,35 +37,6 @@ type LockfileQueryEntry = { dataKey: string; }; -/** Entries that have an invalid version range, for example an npm tag */ -type AnalyzeResultInvalidRange = { - name: string; - range: string; -}; - -/** Entries that can be deduplicated by bumping to an existing higher version */ -type AnalyzeResultNewVersion = { - name: string; - range: string; - oldVersion: string; - newVersion: string; -}; - -/** Entries that would need a dependency update in package.json to be deduplicated */ -type AnalyzeResultNewRange = { - name: string; - oldRange: string; - newRange: string; - oldVersion: string; - newVersion: string; -}; - -type AnalyzeResult = { - invalidRanges: AnalyzeResultInvalidRange[]; - newVersions: AnalyzeResultNewVersion[]; - newRanges: AnalyzeResultNewRange[]; -}; - // the new yarn header is handled out of band of the parsing // https://github.com/yarnpkg/berry/blob/0c5974f193a9397630e9aee2b3876cca62611149/packages/yarnpkg-core/sources/Project.ts#L1741-L1746 const NEW_HEADER = `${[ @@ -153,186 +122,6 @@ export class Lockfile { return this.packages.keys(); } - /** Analyzes the lockfile to identify possible actions and warnings for the entries */ - analyze(options: { - filter?: (name: string) => boolean; - localPackages: Map<string, BackstagePackage>; - }): AnalyzeResult { - const { filter, localPackages } = options; - const result: AnalyzeResult = { - invalidRanges: [], - newVersions: [], - newRanges: [], - }; - - for (const [name, allEntries] of this.packages) { - if (filter && !filter(name)) { - continue; - } - - // Get rid of and signal any invalid ranges upfront - const invalid = allEntries.filter( - e => !semver.validRange(e.range) && !e.range.startsWith('workspace:'), - ); - result.invalidRanges.push( - ...invalid.map(({ range }) => ({ name, range })), - ); - - // Grab all valid entries, if there aren't at least 2 different valid ones we're done - const entries = allEntries.filter(e => semver.validRange(e.range)); - if (entries.length < 2) { - continue; - } - - // Find all versions currently in use - const versions = Array.from(new Set(entries.map(e => e.version))) - .map(v => { - // Translate workspace:^ references to the actual version - if (v === '0.0.0-use.local') { - const local = localPackages.get(name); - if (!local) { - throw new Error(`No local package found for ${name}`); - } - if (!local.packageJson.version) { - throw new Error(`No version found for local package ${name}`); - } - return { - entryVersion: v, - actualVersion: local.packageJson.version, - }; - } - return { entryVersion: v, actualVersion: v }; - }) - .sort((v1, v2) => semver.rcompare(v1.actualVersion, v2.actualVersion)); - - // If we're not using at least 2 different versions we're done - if (versions.length < 2) { - continue; - } - - // TODO(Rugvip): Support bumping into workspace ranges too - const acceptedVersions = new Set<string>(); - for (const { version, range } of entries) { - // Finds the highest matching version from the the known versions - // TODO(Rugvip): We may want to select the version that satisfies the most ranges rather than the highest one - const acceptedVersion = versions.find(v => - semver.satisfies(v.actualVersion, range), - ); - if (!acceptedVersion) { - throw new Error( - `No existing version was accepted for range ${range}, searching through ${versions}, for package ${name}`, - ); - } - - if (acceptedVersion.entryVersion !== version) { - result.newVersions.push({ - name, - range, - newVersion: acceptedVersion.entryVersion, - oldVersion: version, - }); - } - - acceptedVersions.add(acceptedVersion.actualVersion); - } - - // If all ranges were able to accept the same version, we're done - if (acceptedVersions.size === 1) { - continue; - } - - // Find the max version that we may want bump older packages to - const maxVersion = Array.from(acceptedVersions).sort(semver.rcompare)[0]; - // Find all existing ranges that satisfy the new max version, and pick the one that - // results in the highest minimum allowed version, usually being the more specific one - const maxEntry = entries - .filter(e => semver.satisfies(maxVersion, e.range)) - .map(e => ({ e, min: semver.minVersion(e.range) })) - .filter(p => p.min) - .sort((a, b) => semver.rcompare(a.min!, b.min!))[0]?.e; - if (!maxEntry) { - throw new Error( - `No entry found that satisfies max version '${maxVersion}'`, - ); - } - - // Find all entries that don't satisfy the max version - for (const { version, range } of entries) { - if (semver.satisfies(maxVersion, range)) { - continue; - } - - result.newRanges.push({ - name, - oldRange: range, - newRange: maxEntry.range, - oldVersion: version, - newVersion: maxVersion, - }); - } - } - - return result; - } - - remove(name: string, range: string): boolean { - const query = `${name}@${range}`; - const existed = Boolean(this.data[query]); - delete this.data[query]; - - const newEntries = this.packages.get(name)?.filter(e => e.range !== range); - if (newEntries) { - this.packages.set(name, newEntries); - } - - return existed; - } - - /** Modifies the lockfile by bumping packages to the suggested versions */ - replaceVersions(results: AnalyzeResultNewVersion[]) { - for (const { name, range, oldVersion, newVersion } of results) { - const query = `${name}@${range}`; - - // Update the backing data - const entryData = this.data[query]; - if (!entryData) { - throw new Error(`No entry data for ${query}`); - } - if (entryData.version !== oldVersion) { - throw new Error( - `Expected existing version data for ${query} to be ${oldVersion}, was ${entryData.version}`, - ); - } - - // Modifying the data in the entry is not enough, we need to reference an existing version object - const matchingEntry = Object.entries(this.data).find( - ([q, e]) => q.startsWith(`${name}@`) && e.version === newVersion, - ); - if (!matchingEntry) { - throw new Error( - `No matching entry found for ${name} at version ${newVersion}`, - ); - } - this.data[query] = matchingEntry[1]; - - // Update our internal data structure - const entry = this.packages.get(name)?.find(e => e.range === range); - if (!entry) { - throw new Error(`No entry data for ${query}`); - } - if (entry.version !== oldVersion) { - throw new Error( - `Expected existing version data for ${query} to be ${oldVersion}, was ${entryData.version}`, - ); - } - entry.version = newVersion; - } - } - - async save(path: string) { - await fs.writeFile(path, this.toString(), 'utf8'); - } - toString() { return this.legacy ? legacyStringifyLockfile(this.data) diff --git a/plugins/devtools-backend/src/util/Lockfile.ts b/plugins/devtools-backend/src/util/Lockfile.ts index 52dbb847bc..7f5497e948 100644 --- a/plugins/devtools-backend/src/util/Lockfile.ts +++ b/plugins/devtools-backend/src/util/Lockfile.ts @@ -15,7 +15,6 @@ */ import fs from 'fs-extra'; -import semver from 'semver'; import { parseSyml, stringifySyml } from '@yarnpkg/parsers'; import { stringify as legacyStringifyLockfile } from '@yarnpkg/lockfile'; @@ -35,35 +34,6 @@ type LockfileQueryEntry = { version: string; }; -/** Entries that have an invalid version range, for example an npm tag */ -type AnalyzeResultInvalidRange = { - name: string; - range: string; -}; - -/** Entries that can be deduplicated by bumping to an existing higher version */ -type AnalyzeResultNewVersion = { - name: string; - range: string; - oldVersion: string; - newVersion: string; -}; - -/** Entries that would need a dependency update in package.json to be deduplicated */ -type AnalyzeResultNewRange = { - name: string; - oldRange: string; - newRange: string; - oldVersion: string; - newVersion: string; -}; - -type AnalyzeResult = { - invalidRanges: AnalyzeResultInvalidRange[]; - newVersions: AnalyzeResultNewVersion[]; - newRanges: AnalyzeResultNewRange[]; -}; - function parseLockfile(lockfileContents: string) { try { return { @@ -135,11 +105,10 @@ export class Lockfile { queries.push({ range, version: value.version }); } - return new Lockfile(path, packages, data, legacy); + return new Lockfile(packages, data, legacy); } private constructor( - private readonly path: string, private readonly packages: Map<string, LockfileQueryEntry[]>, private readonly data: LockfileData, private readonly legacy: boolean = false, @@ -155,162 +124,6 @@ export class Lockfile { return this.packages.keys(); } - /** Analyzes the lockfile to identify possible actions and warnings for the entries */ - analyze(options?: { filter?: (name: string) => boolean }): AnalyzeResult { - const { filter } = options ?? {}; - const result: AnalyzeResult = { - invalidRanges: [], - newVersions: [], - newRanges: [], - }; - - for (const [name, allEntries] of this.packages) { - if (filter && !filter(name)) { - continue; - } - - // Get rid of and signal any invalid ranges upfront - const invalid = allEntries.filter(e => !semver.validRange(e.range)); - result.invalidRanges.push( - ...invalid.map(({ range }) => ({ name, range })), - ); - - // Grab all valid entries, if there aren't at least 2 different valid ones we're done - const entries = allEntries.filter(e => semver.validRange(e.range)); - if (entries.length < 2) { - continue; - } - - // Find all versions currently in use - const versions = Array.from(new Set(entries.map(e => e.version))).sort( - (v1, v2) => semver.rcompare(v1, v2), - ); - - // If we're not using at least 2 different versions we're done - if (versions.length < 2) { - continue; - } - - const acceptedVersions = new Set<string>(); - for (const { version, range } of entries) { - // Finds the highest matching version from the the known versions - // TODO(Rugvip): We may want to select the version that satisfies the most ranges rather than the highest one - const acceptedVersion = versions.find(v => semver.satisfies(v, range)); - if (!acceptedVersion) { - throw new Error( - `No existing version was accepted for range ${range}, searching through ${versions}, for package ${name}`, - ); - } - - if (acceptedVersion !== version) { - result.newVersions.push({ - name, - range, - newVersion: acceptedVersion, - oldVersion: version, - }); - } - - acceptedVersions.add(acceptedVersion); - } - - // If all ranges were able to accept the same version, we're done - if (acceptedVersions.size === 1) { - continue; - } - - // Find the max version that we may want bump older packages to - const maxVersion = Array.from(acceptedVersions).sort(semver.rcompare)[0]; - // Find all existing ranges that satisfy the new max version, and pick the one that - // results in the highest minimum allowed version, usually being the more specific one - const maxEntry = entries - .filter(e => semver.satisfies(maxVersion, e.range)) - .map(e => ({ e, min: semver.minVersion(e.range) })) - .filter(p => p.min) - .sort((a, b) => semver.rcompare(a.min!, b.min!))[0]?.e; - if (!maxEntry) { - throw new Error( - `No entry found that satisfies max version '${maxVersion}'`, - ); - } - - // Find all entries that don't satisfy the max version - for (const { version, range } of entries) { - if (semver.satisfies(maxVersion, range)) { - continue; - } - - result.newRanges.push({ - name, - oldRange: range, - newRange: maxEntry.range, - oldVersion: version, - newVersion: maxVersion, - }); - } - } - - return result; - } - - remove(name: string, range: string): boolean { - const query = `${name}@${range}`; - const existed = Boolean(this.data[query]); - delete this.data[query]; - - const newEntries = this.packages.get(name)?.filter(e => e.range !== range); - if (newEntries) { - this.packages.set(name, newEntries); - } - - return existed; - } - - /** Modifies the lockfile by bumping packages to the suggested versions */ - replaceVersions(results: AnalyzeResultNewVersion[]) { - for (const { name, range, oldVersion, newVersion } of results) { - const query = `${name}@${range}`; - - // Update the backing data - const entryData = this.data[query]; - if (!entryData) { - throw new Error(`No entry data for ${query}`); - } - if (entryData.version !== oldVersion) { - throw new Error( - `Expected existing version data for ${query} to be ${oldVersion}, was ${entryData.version}`, - ); - } - - // Modifying the data in the entry is not enough, we need to reference an existing version object - const matchingEntry = Object.entries(this.data).find( - ([q, e]) => q.startsWith(`${name}@`) && e.version === newVersion, - ); - if (!matchingEntry) { - throw new Error( - `No matching entry found for ${name} at version ${newVersion}`, - ); - } - this.data[query] = matchingEntry[1]; - - // Update our internal data structure - const entry = this.packages.get(name)?.find(e => e.range === range); - if (!entry) { - throw new Error(`No entry data for ${query}`); - } - if (entry.version !== oldVersion) { - throw new Error( - `Expected existing version data for ${query} to be ${oldVersion}, was ${entryData.version}`, - ); - } - entry.version = newVersion; - } - } - - async save() { - await fs.writeFile(this.path, this.toString(), 'utf8'); - } - toString() { return stringifyLockfile(this.data, this.legacy); } From 81ea85028c0551474f390cb32b08d4096ebdc6cf Mon Sep 17 00:00:00 2001 From: blam <ben@blam.sh> Date: Tue, 23 Jul 2024 11:16:05 +0200 Subject: [PATCH 378/416] chore: fix api-reports Signed-off-by: blam <ben@blam.sh> --- packages/frontend-plugin-api/api-report.md | 64 ++++++++++++---------- plugins/catalog-react/src/alpha.tsx | 39 ------------- 2 files changed, 34 insertions(+), 69 deletions(-) diff --git a/packages/frontend-plugin-api/api-report.md b/packages/frontend-plugin-api/api-report.md index 3c082a7694..d6a91c0c99 100644 --- a/packages/frontend-plugin-api/api-report.md +++ b/packages/frontend-plugin-api/api-report.md @@ -931,36 +931,40 @@ export interface ExtensionBlueprint< > { // (undocumented) dataRefs: TDataRefs; - // (undocumented) - make(args: { - namespace?: string; - name?: string; - attachTo?: { - id: string; - input: string; - }; - disabled?: boolean; - inputs?: TInputs; - output?: TOutput; - configSchema?: PortableSchema<TConfig>; - params: TParams; - factory?( - params: TParams, - context: { - node: AppNode; - config: TConfig; - inputs: Expand<ResolvedExtensionInputs<TInputs>>; - orignalFactory( - params?: TParams, - context?: { - node?: AppNode; - config?: TConfig; - inputs?: Expand<ResolvedExtensionInputs<TInputs>>; - }, - ): Expand<ExtensionDataValues<TOutput>>; - }, - ): Expand<ExtensionDataValues<TOutput>>; - }): ExtensionDefinition<TConfig>; + make( + args: { + namespace?: string; + name?: string; + attachTo?: { + id: string; + input: string; + }; + disabled?: boolean; + inputs?: TInputs; + output?: TOutput; + configSchema?: PortableSchema<TConfig>; + } & ( + | { + factory( + originalFactory: ( + params: TParams, + context?: { + config?: TConfig; + inputs?: Expand<ResolvedExtensionInputs<TInputs>>; + }, + ) => Expand<ExtensionDataValues<TOutput>>, + context: { + node: AppNode; + config: TConfig; + inputs: Expand<ResolvedExtensionInputs<TInputs>>; + }, + ): Expand<ExtensionDataValues<TOutput>>; + } + | { + params: TParams; + } + ), + ): ExtensionDefinition<TConfig>; } // @public (undocumented) diff --git a/plugins/catalog-react/src/alpha.tsx b/plugins/catalog-react/src/alpha.tsx index 7f276b8ea6..e81b8e5ebf 100644 --- a/plugins/catalog-react/src/alpha.tsx +++ b/plugins/catalog-react/src/alpha.tsx @@ -22,7 +22,6 @@ import { RouteRef, coreExtensionData, createExtension, - createExtensionBlueprint, createExtensionDataRef, createSchemaFromZod, } from '@backstage/frontend-plugin-api'; @@ -48,44 +47,6 @@ export const catalogExtensionData = { }), }; -/** @alpha */ -export const EntityCardBlueprint = createExtensionBlueprint({ - kind: 'entity-card', - attachTo: { id: 'entity-content:catalog/overview', input: 'cards' }, - configSchema: createSchemaFromZod(z => - z.object({ - filter: z.string().optional(), - }), - ), - output: { - element: coreExtensionData.reactElement, - filterFunction: catalogExtensionData.entityFilterFunction.optional(), - filterExpression: catalogExtensionData.entityFilterExpression.optional(), - }, - factory( - params: { - filter?: - | typeof catalogExtensionData.entityFilterFunction.T - | typeof catalogExtensionData.entityFilterExpression.T; - loader: () => Promise<JSX.Element>; - }, - { node, config }, - ) { - const ExtensionComponent = lazy(() => - params.loader().then(element => ({ default: () => element })), - ); - - return { - element: ( - <ExtensionBoundary node={node}> - <ExtensionComponent /> - </ExtensionBoundary> - ), - ...mergeFilters({ config, options: params }), - }; - }, -}); - // TODO: Figure out how to merge with provided config schema /** @alpha */ export function createEntityCardExtension< From 9e8371b9e61c248636e29570aad72c4ed91c1429 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg <poldsberg@gmail.com> Date: Tue, 23 Jul 2024 12:00:24 +0200 Subject: [PATCH 379/416] Update docs/tutorials/enable-public-entry.md Co-authored-by: Jack Palmer <UsainBloot@users.noreply.github.com> Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com> --- docs/tutorials/enable-public-entry.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/tutorials/enable-public-entry.md b/docs/tutorials/enable-public-entry.md index d257753413..0174d43e3f 100644 --- a/docs/tutorials/enable-public-entry.md +++ b/docs/tutorials/enable-public-entry.md @@ -114,6 +114,7 @@ import { coreExtensionData, createExtension, createExtensionOverrides, + createSignInPageExtension } from '@backstage/frontend-plugin-api'; const signInPage = createSignInPageExtension({ From e3644bf16eac1b87ca85a633b029291adb2883a7 Mon Sep 17 00:00:00 2001 From: blam <ben@blam.sh> Date: Tue, 23 Jul 2024 12:38:10 +0200 Subject: [PATCH 380/416] chore: fixing prettier Signed-off-by: blam <ben@blam.sh> --- docs/tutorials/enable-public-entry.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/enable-public-entry.md b/docs/tutorials/enable-public-entry.md index 0174d43e3f..25d7382f13 100644 --- a/docs/tutorials/enable-public-entry.md +++ b/docs/tutorials/enable-public-entry.md @@ -114,7 +114,7 @@ import { coreExtensionData, createExtension, createExtensionOverrides, - createSignInPageExtension + createSignInPageExtension, } from '@backstage/frontend-plugin-api'; const signInPage = createSignInPageExtension({ From 9a46a81ece020408ce61f4eccd0aa922b712601d Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg <poldsberg@gmail.com> Date: Tue, 23 Jul 2024 12:40:11 +0200 Subject: [PATCH 381/416] core-app-api: fix immediate sign-in on sign-out Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com> --- .changeset/thirty-paws-hope.md | 5 ++++ .../IdentityApi/AppIdentityProxy.ts | 3 ++- .../core-app-api/src/app/AppManager.test.tsx | 26 ++++++++++++++----- 3 files changed, 26 insertions(+), 8 deletions(-) create mode 100644 .changeset/thirty-paws-hope.md diff --git a/.changeset/thirty-paws-hope.md b/.changeset/thirty-paws-hope.md new file mode 100644 index 0000000000..0de607f331 --- /dev/null +++ b/.changeset/thirty-paws-hope.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-app-api': patch +--- + +The request to delete the session cookie when running the app in protected mode is now done with a plain `fetch` rather than `FetchApi`. This fixes a bug where the app would immediately try to sign-in again when removing the cookie during logout. diff --git a/packages/core-app-api/src/apis/implementations/IdentityApi/AppIdentityProxy.ts b/packages/core-app-api/src/apis/implementations/IdentityApi/AppIdentityProxy.ts index 92e2abffb7..941ec90d66 100644 --- a/packages/core-app-api/src/apis/implementations/IdentityApi/AppIdentityProxy.ts +++ b/packages/core-app-api/src/apis/implementations/IdentityApi/AppIdentityProxy.ts @@ -153,8 +153,9 @@ export class AppIdentityProxy implements IdentityApi { // It is fine if we do NOT worry yet about deleting cookies for OTHER backends like techdocs const appBaseUrl = await ctx.discoveryApi.getBaseUrl('app'); try { - await ctx.fetchApi.fetch(`${appBaseUrl}/.backstage/auth/v1/cookie`, { + await fetch(`${appBaseUrl}/.backstage/auth/v1/cookie`, { method: 'DELETE', + credentials: 'include', }); } catch { // Ignore the error for those who use static serving of the frontend diff --git a/packages/core-app-api/src/app/AppManager.test.tsx b/packages/core-app-api/src/app/AppManager.test.tsx index 85b6bcd684..01277a09c7 100644 --- a/packages/core-app-api/src/app/AppManager.test.tsx +++ b/packages/core-app-api/src/app/AppManager.test.tsx @@ -19,9 +19,12 @@ import { MockAnalyticsApi, renderWithEffects, withLogCollector, + registerMswTestHooks, } from '@backstage/test-utils'; -import { screen, waitFor, act } from '@testing-library/react'; +import { screen, act } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; +import { setupServer } from 'msw/node'; +import { rest } from 'msw'; import React, { PropsWithChildren, ReactNode } from 'react'; import { BrowserRouter, Navigate, Route, Routes } from 'react-router-dom'; import { @@ -51,6 +54,9 @@ import { } from '@backstage/core-plugin-api/alpha'; describe('Integration Test', () => { + const server = setupServer(); + registerMswTestHooks(server); + const noOpAnalyticsApi = createApiFactory( analyticsApiRef, new NoOpAnalyticsApi(), @@ -847,6 +853,17 @@ describe('Integration Test', () => { }); it('should clear app cookie when the user logs out', async () => { + const logoutSignal = jest.fn(); + server.use( + rest.delete( + 'http://localhost:7007/app/.backstage/auth/v1/cookie', + (_req, res, ctx) => { + logoutSignal(); + return res(ctx.status(200)); + }, + ), + ); + const meta = global.document.createElement('meta'); meta.name = 'backstage-app-mode'; meta.content = 'protected'; @@ -901,12 +918,7 @@ describe('Integration Test', () => { await userEvent.click(screen.getByText('Sign Out')); }); - await waitFor(() => - expect(fetchApiMock.fetch).toHaveBeenCalledWith( - 'http://localhost:7007/app/.backstage/auth/v1/cookie', - { method: 'DELETE' }, - ), - ); + expect(logoutSignal).toHaveBeenCalled(); global.document.head.removeChild(meta); }); From 749b5efd22af01591e4bb8f4e1854dfcc169317c Mon Sep 17 00:00:00 2001 From: Jack Palmer <jackpalmer@spotify.com> Date: Tue, 23 Jul 2024 12:30:01 +0100 Subject: [PATCH 382/416] feat: Add visibility hidden to CookieAuthRedirect Signed-off-by: Jack Palmer <jackpalmer@spotify.com> --- .../src/components/CookieAuthRedirect/CookieAuthRedirect.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/auth-react/src/components/CookieAuthRedirect/CookieAuthRedirect.tsx b/plugins/auth-react/src/components/CookieAuthRedirect/CookieAuthRedirect.tsx index f719aebdae..c89aa6a54d 100644 --- a/plugins/auth-react/src/components/CookieAuthRedirect/CookieAuthRedirect.tsx +++ b/plugins/auth-react/src/components/CookieAuthRedirect/CookieAuthRedirect.tsx @@ -45,6 +45,7 @@ export function CookieAuthRedirect() { ref={form => form?.submit()} action={window.location.href} method="POST" + style={{ visibility: 'hidden' }} > <input type="hidden" name="type" value="sign-in" /> <input type="hidden" name="token" value={state.result} /> From aeac3e9efa0df730facf88617c6bc7882ee6e830 Mon Sep 17 00:00:00 2001 From: Jack Palmer <jackpalmer@spotify.com> Date: Tue, 23 Jul 2024 12:31:58 +0100 Subject: [PATCH 383/416] chore: changeset Signed-off-by: Jack Palmer <jackpalmer@spotify.com> --- .changeset/wicked-bobcats-teach.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/wicked-bobcats-teach.md diff --git a/.changeset/wicked-bobcats-teach.md b/.changeset/wicked-bobcats-teach.md new file mode 100644 index 0000000000..041e336f7d --- /dev/null +++ b/.changeset/wicked-bobcats-teach.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-auth-react': patch +--- + +feat: Hide visibility of CookieAuthRedirect From dc4fb4f6ac64bc53d38ff00e92eec000ac1911eb Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg <poldsberg@gmail.com> Date: Tue, 23 Jul 2024 15:08:07 +0200 Subject: [PATCH 384/416] cli: fix forwarding of target dir when resolving optional bundling paths Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com> --- .changeset/violet-jokes-wave.md | 5 +++++ packages/cli/src/lib/bundler/bundle.ts | 1 + 2 files changed, 6 insertions(+) create mode 100644 .changeset/violet-jokes-wave.md diff --git a/.changeset/violet-jokes-wave.md b/.changeset/violet-jokes-wave.md new file mode 100644 index 0000000000..623cff2583 --- /dev/null +++ b/.changeset/violet-jokes-wave.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Fix for `repo build --all` not properly detecting the experimental public entry point. diff --git a/packages/cli/src/lib/bundler/bundle.ts b/packages/cli/src/lib/bundler/bundle.ts index d24d4252f4..0aa91a90a6 100644 --- a/packages/cli/src/lib/bundler/bundle.ts +++ b/packages/cli/src/lib/bundler/bundle.ts @@ -42,6 +42,7 @@ export async function buildBundle(options: BuildOptions) { const paths = resolveBundlingPaths(options); const publicPaths = await resolveOptionalBundlingPaths({ + targetDir: options.targetDir, entry: 'src/index-public-experimental', dist: 'dist/public', }); From bf2984369d30ee9b1b18974b85d8edb9ae373834 Mon Sep 17 00:00:00 2001 From: Chap Ambrose <cambrose@salesforce.com> Date: Tue, 23 Jul 2024 08:34:14 -0500 Subject: [PATCH 385/416] cleanup heroku.md Signed-off-by: Chap Ambrose <cambrose@salesforce.com> --- docs/deployment/heroku.md | 42 +++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/docs/deployment/heroku.md b/docs/deployment/heroku.md index faf1c2106e..d285e4b397 100644 --- a/docs/deployment/heroku.md +++ b/docs/deployment/heroku.md @@ -7,8 +7,6 @@ description: How to deploy Backstage to Heroku Heroku is a Platform as a Service (PaaS) designed to simplify application deployment. -[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/chap/backstage-button) - ## Create App Starting with an existing Backstage app or follow the [getting started guide](https://backstage.io/docs/getting-started/) to create a new one. @@ -17,8 +15,8 @@ Install the [Heroku CLI](https://devcenter.heroku.com/articles/heroku-cli) and create a new Heroku app: ```shell -$ cd your-app/ -$ heroku apps:create <your-app> +cd your-app/ +heroku apps:create <your-app> ``` ## Domain @@ -26,7 +24,7 @@ $ heroku apps:create <your-app> Get Heroku app URL: ```shell -$ heroku domains -a <your-app> +heroku domains -a <your-app> <your-app-123>.herokuapp.com ``` @@ -59,7 +57,7 @@ Add a build script in `package.json` to compile frontend during deployment: Create a [Procfile](https://devcenter.heroku.com/articles/procfile) in the app's root: ```shell -$ echo "web: yarn workspace backend start --config ../../app-config.yaml --config ../../app-config.production.yaml" > Procfile +echo "web: yarn workspace backend start --config ../../app-config.yaml --config ../../app-config.production.yaml" > Procfile ``` ## Database @@ -67,7 +65,7 @@ $ echo "web: yarn workspace backend start --config ../../app-config.yaml --confi Provision a [Heroku Postgres](https://elements.heroku.com/addons/heroku-postgresql) database: ```shell -$ heroku addons:create heroku-postgresql -a <your-app> +heroku addons:create heroku-postgresql -a <your-app> ``` Update `database` in `app-config.production.yaml`: @@ -85,7 +83,7 @@ backend: Allow postgres self-signed certificates: ```shell -$ heroku config:set PGSSLMODE=no-verify -a <your-app> +heroku config:set PGSSLMODE=no-verify -a <your-app> ``` ## Deployment @@ -93,20 +91,20 @@ $ heroku config:set PGSSLMODE=no-verify -a <your-app> Commit changes and push to Heroku to build and deploy: ```shell -$ git add Procfile && git commit -am "configure heroku" -$ git push heroku main +git add Procfile && git commit -am "configure heroku" +git push heroku main ``` View the app in the browser: ```shell -$ heroku open -a <your-app> +heroku open -a <your-app> ``` View logs: ```shell -$ heroku heroku -a <your-app> +heroku heroku -a <your-app> ``` ## Docker @@ -116,27 +114,27 @@ As an alternative to git deploys, Heroku also [supports container images](https: Login to Heroku's container registry: ```shell -$ heroku container:login +heroku container:login ``` Configure the Heroku app to run a container image: ```shell -$ heroku stack:set container -a <your-app> +heroku stack:set container -a <your-app> ``` -Locally run the [host build command](https://backstage.io/docs/deployment/docker/#host-build): +Locally run the [host build commands](https://backstage.io/docs/deployment/docker/#host-build), they must be run whenever you are going to publish a new image: ```shell -$ yarn build:backend --config ../../app-config.yaml --config ../../app-config.production.yaml +yarn install --frozen-lockfile +yarn tsc +yarn build:backend --config ../../app-config.yaml --config ../../app-config.production.yaml ``` -Build, push, and release the container image: +Build, push, and release the container image to the `web` dyno: ```shell -$ docker image build . -f packages/backend/Dockerfile --tag registry.heroku.com/<your-app>/web - -$ docker push registry.heroku.com/<your-app>/web - -$ heroku container:release web -a <your-app> +docker image build . -f packages/backend/Dockerfile --tag registry.heroku.com/<your-app>/web +docker push registry.heroku.com/<your-app>/web +heroku container:release web -a <your-app> ``` From 4a8774820c5fd84262058a1e48361d5656b57601 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <github-actions[bot]@users.noreply.github.com> Date: Tue, 23 Jul 2024 14:02:37 +0000 Subject: [PATCH 386/416] Version Packages (next) --- .changeset/pre.json | 52 +- docs/releases/v1.30.0-next.0-changelog.md | 2214 +++++++++++++++++ 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 | 43 + packages/app-next/package.json | 2 +- packages/app/CHANGELOG.md | 41 + packages/app/package.json | 2 +- packages/backend-app-api/CHANGELOG.md | 17 + packages/backend-app-api/package.json | 2 +- packages/backend-common/CHANGELOG.md | 28 + packages/backend-common/package.json | 2 +- packages/backend-defaults/CHANGELOG.md | 23 + packages/backend-defaults/package.json | 2 +- .../CHANGELOG.md | 26 + .../package.json | 2 +- packages/backend-legacy/CHANGELOG.md | 42 + packages/backend-legacy/package.json | 2 +- packages/backend-openapi-utils/CHANGELOG.md | 8 + packages/backend-openapi-utils/package.json | 2 +- packages/backend-plugin-api/CHANGELOG.md | 12 + packages/backend-plugin-api/package.json | 2 +- packages/backend-tasks/CHANGELOG.md | 11 + packages/backend-tasks/package.json | 2 +- packages/backend-test-utils/CHANGELOG.md | 15 + packages/backend-test-utils/package.json | 2 +- packages/backend/CHANGELOG.md | 37 + packages/backend/package.json | 2 +- packages/cli/CHANGELOG.md | 35 + packages/cli/package.json | 2 +- packages/config-loader/CHANGELOG.md | 13 + packages/config-loader/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 | 12 + packages/core-components/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/frontend-app-api/CHANGELOG.md | 16 + packages/frontend-app-api/package.json | 2 +- packages/frontend-plugin-api/CHANGELOG.md | 71 + packages/frontend-plugin-api/package.json | 2 +- packages/frontend-test-utils/CHANGELOG.md | 10 + packages/frontend-test-utils/package.json | 2 +- packages/integration-react/CHANGELOG.md | 9 + packages/integration-react/package.json | 2 +- packages/integration/CHANGELOG.md | 13 + packages/integration/package.json | 2 +- packages/repo-tools/CHANGELOG.md | 12 + 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 | 11 + packages/techdocs-cli/package.json | 2 +- packages/test-utils/CHANGELOG.md | 13 + packages/test-utils/package.json | 2 +- plugins/api-docs/CHANGELOG.md | 15 + plugins/api-docs/package.json | 2 +- plugins/app-backend/CHANGELOG.md | 14 + plugins/app-backend/package.json | 2 +- plugins/app-node/CHANGELOG.md | 8 + plugins/app-node/package.json | 2 +- plugins/app-visualizer/CHANGELOG.md | 9 + plugins/app-visualizer/package.json | 2 +- .../CHANGELOG.md | 8 + .../package.json | 2 +- .../CHANGELOG.md | 11 + .../package.json | 2 +- .../CHANGELOG.md | 10 + .../package.json | 2 +- .../CHANGELOG.md | 8 + .../package.json | 2 +- .../CHANGELOG.md | 10 + .../package.json | 2 +- .../CHANGELOG.md | 10 + .../package.json | 2 +- .../CHANGELOG.md | 8 + .../package.json | 2 +- .../CHANGELOG.md | 8 + .../package.json | 2 +- .../CHANGELOG.md | 8 + .../package.json | 2 +- .../CHANGELOG.md | 11 + .../package.json | 2 +- .../CHANGELOG.md | 9 + .../package.json | 2 +- .../CHANGELOG.md | 8 + .../package.json | 2 +- .../CHANGELOG.md | 9 + .../package.json | 2 +- .../CHANGELOG.md | 10 + .../package.json | 2 +- .../CHANGELOG.md | 8 + .../package.json | 2 +- .../CHANGELOG.md | 8 + .../package.json | 2 +- .../CHANGELOG.md | 9 + .../package.json | 2 +- .../CHANGELOG.md | 9 + .../package.json | 2 +- plugins/auth-backend/CHANGELOG.md | 30 + plugins/auth-backend/package.json | 2 +- plugins/auth-node/CHANGELOG.md | 13 + plugins/auth-node/package.json | 2 +- plugins/auth-react/CHANGELOG.md | 10 + plugins/auth-react/package.json | 2 +- plugins/bitbucket-cloud-common/CHANGELOG.md | 7 + plugins/bitbucket-cloud-common/package.json | 2 +- .../catalog-backend-module-aws/CHANGELOG.md | 19 + .../catalog-backend-module-aws/package.json | 2 +- .../catalog-backend-module-azure/CHANGELOG.md | 13 + .../catalog-backend-module-azure/package.json | 2 +- .../CHANGELOG.md | 13 + .../package.json | 2 +- .../CHANGELOG.md | 17 + .../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 | 13 + .../package.json | 2 +- .../CHANGELOG.md | 13 + .../package.json | 2 +- .../CHANGELOG.md | 17 + .../package.json | 2 +- .../CHANGELOG.md | 11 + .../package.json | 2 +- .../CHANGELOG.md | 15 + .../package.json | 2 +- .../CHANGELOG.md | 16 + .../package.json | 2 +- .../catalog-backend-module-ldap/CHANGELOG.md | 14 + .../catalog-backend-module-ldap/package.json | 2 +- .../catalog-backend-module-logs/CHANGELOG.md | 9 + .../catalog-backend-module-logs/package.json | 2 +- .../CHANGELOG.md | 14 + .../package.json | 2 +- .../CHANGELOG.md | 15 + .../package.json | 2 +- .../CHANGELOG.md | 14 + .../package.json | 2 +- .../CHANGELOG.md | 11 + .../package.json | 2 +- .../CHANGELOG.md | 14 + .../package.json | 2 +- plugins/catalog-backend/CHANGELOG.md | 23 + plugins/catalog-backend/package.json | 2 +- plugins/catalog-graph/CHANGELOG.md | 15 + plugins/catalog-graph/package.json | 2 +- plugins/catalog-import/CHANGELOG.md | 18 + plugins/catalog-import/package.json | 2 +- plugins/catalog-node/CHANGELOG.md | 15 + plugins/catalog-node/package.json | 2 +- plugins/catalog-react/CHANGELOG.md | 21 + plugins/catalog-react/package.json | 2 +- .../catalog-unprocessed-entities/CHANGELOG.md | 10 + .../catalog-unprocessed-entities/package.json | 2 +- plugins/catalog/CHANGELOG.md | 21 + plugins/catalog/package.json | 2 +- plugins/config-schema/CHANGELOG.md | 10 + plugins/config-schema/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 +- .../CHANGELOG.md | 13 + .../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 | 10 + .../example-todo-list-backend/package.json | 2 +- plugins/example-todo-list/CHANGELOG.md | 8 + plugins/example-todo-list/package.json | 2 +- plugins/home-react/CHANGELOG.md | 8 + plugins/home-react/package.json | 2 +- plugins/home/CHANGELOG.md | 19 + plugins/home/package.json | 2 +- plugins/kubernetes-backend/CHANGELOG.md | 20 + plugins/kubernetes-backend/package.json | 2 +- plugins/kubernetes-cluster/CHANGELOG.md | 12 + plugins/kubernetes-cluster/package.json | 2 +- plugins/kubernetes-node/CHANGELOG.md | 10 + plugins/kubernetes-node/package.json | 2 +- plugins/kubernetes-react/CHANGELOG.md | 12 + plugins/kubernetes-react/package.json | 2 +- plugins/kubernetes/CHANGELOG.md | 12 + plugins/kubernetes/package.json | 2 +- .../CHANGELOG.md | 15 + .../package.json | 2 +- plugins/notifications-backend/CHANGELOG.md | 17 + plugins/notifications-backend/package.json | 2 +- plugins/notifications-node/CHANGELOG.md | 12 + plugins/notifications-node/package.json | 2 +- plugins/notifications/CHANGELOG.md | 13 + plugins/notifications/package.json | 2 +- plugins/org-react/CHANGELOG.md | 11 + plugins/org-react/package.json | 2 +- plugins/org/CHANGELOG.md | 13 + plugins/org/package.json | 2 +- .../CHANGELOG.md | 10 + .../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/proxy-backend/CHANGELOG.md | 10 + plugins/proxy-backend/package.json | 2 +- .../CHANGELOG.md | 11 + .../package.json | 2 +- .../CHANGELOG.md | 12 + .../package.json | 2 +- .../CHANGELOG.md | 11 + .../package.json | 2 +- .../CHANGELOG.md | 13 + .../package.json | 2 +- .../CHANGELOG.md | 12 + .../package.json | 2 +- .../CHANGELOG.md | 14 + .../package.json | 2 +- .../CHANGELOG.md | 11 + .../package.json | 2 +- .../CHANGELOG.md | 11 + .../package.json | 2 +- .../CHANGELOG.md | 11 + .../package.json | 2 +- .../CHANGELOG.md | 12 + .../package.json | 2 +- .../CHANGELOG.md | 23 + .../package.json | 2 +- .../CHANGELOG.md | 12 + .../package.json | 2 +- .../CHANGELOG.md | 14 + .../package.json | 2 +- .../CHANGELOG.md | 10 + .../package.json | 2 +- .../CHANGELOG.md | 10 + .../package.json | 2 +- plugins/scaffolder-backend/CHANGELOG.md | 31 + plugins/scaffolder-backend/package.json | 2 +- .../scaffolder-node-test-utils/CHANGELOG.md | 10 + .../scaffolder-node-test-utils/package.json | 2 +- plugins/scaffolder-node/CHANGELOG.md | 13 + plugins/scaffolder-node/package.json | 2 +- plugins/scaffolder-react/CHANGELOG.md | 22 + plugins/scaffolder-react/package.json | 2 +- plugins/scaffolder/CHANGELOG.md | 23 + plugins/scaffolder/package.json | 2 +- .../CHANGELOG.md | 18 + .../package.json | 2 +- .../CHANGELOG.md | 12 + .../package.json | 2 +- .../CHANGELOG.md | 12 + .../package.json | 2 +- plugins/search-backend-module-pg/CHANGELOG.md | 12 + 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 | 16 + plugins/search/package.json | 2 +- plugins/signals-backend/CHANGELOG.md | 13 + plugins/signals-backend/package.json | 2 +- plugins/signals-node/CHANGELOG.md | 12 + plugins/signals-node/package.json | 2 +- plugins/signals/CHANGELOG.md | 11 + plugins/signals/package.json | 2 +- .../techdocs-addons-test-utils/CHANGELOG.md | 15 + .../techdocs-addons-test-utils/package.json | 2 +- plugins/techdocs-backend/CHANGELOG.md | 17 + plugins/techdocs-backend/package.json | 2 +- .../CHANGELOG.md | 11 + .../package.json | 2 +- plugins/techdocs-node/CHANGELOG.md | 14 + plugins/techdocs-node/package.json | 2 +- plugins/techdocs-react/CHANGELOG.md | 11 + plugins/techdocs-react/package.json | 2 +- plugins/techdocs/CHANGELOG.md | 21 + plugins/techdocs/package.json | 2 +- plugins/user-settings-backend/CHANGELOG.md | 14 + plugins/user-settings-backend/package.json | 2 +- plugins/user-settings/CHANGELOG.md | 17 + plugins/user-settings/package.json | 2 +- yarn.lock | 264 +- 314 files changed, 4828 insertions(+), 219 deletions(-) create mode 100644 docs/releases/v1.30.0-next.0-changelog.md diff --git a/.changeset/pre.json b/.changeset/pre.json index be1b694c9e..7da5b582e1 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -188,5 +188,55 @@ "@backstage/plugin-user-settings-backend": "0.2.21", "@backstage/plugin-user-settings-common": "0.0.1" }, - "changesets": [] + "changesets": [ + "blue-pumas-cheer", + "bright-trainers-brake", + "chilly-trains-sleep", + "cool-insects-remember", + "cuddly-zebras-crash", + "dry-squids-tap", + "dull-ghosts-double", + "early-trees-dance", + "eighty-mirrors-flow", + "flat-plums-grow", + "forty-ties-agree", + "forty-ties-disagree", + "friendly-feet-refuse", + "gentle-dryers-smile", + "grumpy-owls-suffer", + "heavy-numbers-love", + "hip-hairs-exist", + "late-games-protect", + "light-pianos-exercise", + "little-bulldogs-guess", + "little-suns-fly", + "mighty-dolls-retire", + "modern-parrots-protect", + "neat-gifts-join", + "new-scissors-try", + "nice-peas-retire", + "nine-cherries-decide", + "nine-glasses-nail", + "ninety-icons-smile", + "pink-gorillas-brake", + "plenty-tools-exist", + "rich-mugs-dress", + "selfish-bees-think", + "six-rats-kick", + "slow-toes-jog", + "small-spoons-shout", + "soft-gorillas-refuse", + "spotty-planets-accept", + "strange-papayas-beg", + "strong-otters-compete", + "stupid-dots-relate", + "swift-kings-sparkle", + "thirty-paws-hope", + "tiny-oranges-pretend", + "tough-lies-repair", + "violet-jokes-wave", + "wicked-bobcats-teach", + "wild-eggs-exist", + "witty-bears-behave" + ] } diff --git a/docs/releases/v1.30.0-next.0-changelog.md b/docs/releases/v1.30.0-next.0-changelog.md new file mode 100644 index 0000000000..f3b7f2ef45 --- /dev/null +++ b/docs/releases/v1.30.0-next.0-changelog.md @@ -0,0 +1,2214 @@ +# Release v1.30.0-next.0 + +Upgrade Helper: [https://backstage.github.io/upgrade-helper/?to=1.30.0-next.0](https://backstage.github.io/upgrade-helper/?to=1.30.0-next.0) + +## @backstage/cli@0.27.0-next.0 + +### Minor Changes + +- 32a38e1: **BREAKING**: The lockfile (`yarn.lock`) dependency analysis and mutations have been removed from several commands. + + The `versions:bump` command will no longer attempt to bump and deduplicate dependencies by modifying the lockfile, it will only update `package.json` files. + + The `versions:check` command has been removed, since its only purpose was verification and mutation of the lockfile. We recommend using the `yarn dedupe` command instead, or the `yarn-deduplicate` package if you're using Yarn classic. + + The check that was built into the `package start` command has been removed, it will no longer warn about lockfile mismatches. + + The packages in the Backstage ecosystem handle package duplications much better now than when these CLI features were first introduced, so the need for these features has diminished. By removing them, we drastically reduce the integration between the Backstage CLI and Yarn, making it much easier to add support for other package managers in the future. + +### Patch Changes + +- 7eb08a6: Add frontend-dynamic-container role to eslint config factory +- fbc7819: Use ES2022 in CLI bundler +- e53074f: Updated default backend plugin to use `RootConfigService` instead of `Config`. This also removes the dependency on `@backstage/config` as it's no longer used. +- ee2b0e5: The experimental module federation build now has the ability to force the use of development versions of `react` and `react-dom` by setting the `FORCE_REACT_DEVELOPMENT` flag. +- 239dffc: Remove usage of deprecated functionality from @backstage/config-loader +- 0eedec3: Add support for dynamic plugins via the EXPERIMENTAL_MODULE_FEDERATION environment variable when running `yarn start`. +- dc4fb4f: Fix for `repo build --all` not properly detecting the experimental public entry point. +- Updated dependencies + - @backstage/integration@1.14.0-next.0 + - @backstage/config-loader@1.8.2-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/cli-common@0.1.14 + - @backstage/cli-node@0.2.7 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/eslint-plugin@0.1.8 + - @backstage/release-manifests@0.0.11 + - @backstage/types@1.1.1 + +## @backstage/integration@1.14.0-next.0 + +### Minor Changes + +- 78c1329: Updated `GitlabUrlReader.readUrl` and `GitlabUrlReader.readTree` to accept a user-provided token, supporting both bearer and private tokens. + +### Patch Changes + +- c591670: Updated functions for `getHarnessEditContentsUrl`, `getHarnessFileContentsUrl`, `getHarnessArchiveUrl`, `getHarnessLatestCommitUrl` and `parseHarnessUrl` to handle account and org level urls +- Updated dependencies + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-scaffolder-react@1.11.0-next.0 + +### Minor Changes + +- 8839381: Add scaffolder option to display object items in separate rows on review page + +### Patch Changes + +- d0e95a7: Add ability to customise form fields in the UI by exposing `uiSchema` and `formContext` in `FormProps` +- 4670f06: support `ajv-errors` for scaffolder validation to allow for customizing the error messages +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/plugin-scaffolder-common@1.5.4 + +## @backstage/app-defaults@1.5.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-app-api@1.14.1-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + - @backstage/plugin-permission-react@0.4.24 + +## @backstage/backend-app-api@0.8.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/config-loader@1.8.2-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/cli-common@0.1.14 + - @backstage/cli-node@0.2.7 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-permission-node@0.8.1-next.0 + +## @backstage/backend-common@0.23.4-next.0 + +### Patch Changes + +- ba8571e: Setup user agent header for AWS sdk clients, this enables users to better track API calls made from Backstage to AWS APIs through things like CloudTrail. + +- 7e13b7a: The remaining exports in the package have now been deprecated: + + - `cacheToPluginCacheManager` + - `createLegacyAuthAdapters` + - `LegacyCreateRouter` + - `legacyPlugin` + - `loggerToWinstonLogger` + - `makeLegacyPlugin` + + Users of these export should fully [migrate to the new backend system](https://backstage.io/docs/backend-system/building-backends/migrating). + +- Updated dependencies + - @backstage/integration@1.14.0-next.0 + - @backstage/config-loader@1.8.2-next.0 + - @backstage/backend-dev-utils@0.1.4 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration-aws-node@0.1.12 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.0 + +## @backstage/backend-defaults@0.4.2-next.0 + +### Patch Changes + +- 4e79d19: The `createHealthRouter` utility that allows you to create a health check router is now exported via `@backstage/backend-defaults/rootHttpRouter`. +- 78c1329: Updated `GitlabUrlReader.readUrl` and `GitlabUrlReader.readTree` to accept a user-provided token, supporting both bearer and private tokens. +- 8e967da: Fixed the routing of the new health check service, the health endpoints should now properly be available at `/.backstage/health/v1/readiness` and `/.backstage/health/v1/liveness`. +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/config-loader@1.8.2-next.0 + - @backstage/backend-app-api@0.8.1-next.0 + - @backstage/backend-dev-utils@0.1.4 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration-aws-node@0.1.12 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-events-node@0.3.9-next.0 + - @backstage/plugin-permission-node@0.8.1-next.0 + +## @backstage/backend-dynamic-feature-service@0.2.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-backend@1.24.1-next.0 + - @backstage/config-loader@1.8.2-next.0 + - @backstage/backend-app-api@0.8.1-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/cli-common@0.1.14 + - @backstage/cli-node@0.2.7 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-app-node@0.1.23-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-events-backend@0.3.10-next.0 + - @backstage/plugin-events-node@0.3.9-next.0 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.1-next.0 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + - @backstage/plugin-search-backend-node@1.2.28-next.0 + - @backstage/plugin-search-common@1.2.13 + +## @backstage/backend-openapi-utils@0.1.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/errors@1.2.4 + +## @backstage/backend-plugin-api@0.7.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-permission-common@0.8.0 + +## @backstage/backend-tasks@0.5.28-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/backend-test-utils@0.4.5-next.0 + +### Patch Changes + +- 4e79d19: The default services for `startTestBackend` and `ServiceFactoryTester` now includes the Root Health Service. +- Updated dependencies + - @backstage/backend-defaults@0.4.2-next.0 + - @backstage/backend-app-api@0.8.1-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-events-node@0.3.9-next.0 + +## @backstage/config-loader@1.8.2-next.0 + +### Patch Changes + +- 493feac: Add boolean `allowMissingDefaultConfig` option to `ConfigSources.default` and + `ConfigSources.defaultForTargets`, which results in omission of a ConfigSource + for the default app-config.yaml configuration file if it's not present. +- Updated dependencies + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/core-app-api@1.14.1-next.0 + +### Patch Changes + +- 9a46a81: The request to delete the session cookie when running the app in protected mode is now done with a plain `fetch` rather than `FetchApi`. This fixes a bug where the app would immediately try to sign-in again when removing the cookie during logout. +- Updated dependencies + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + +## @backstage/core-compat-api@0.2.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/version-bridge@1.0.8 + +## @backstage/core-components@0.14.10-next.0 + +### Patch Changes + +- 678971a: Move the `Link` component to the `RoutedTabs` instead of the `HeaderTabs` component +- Updated dependencies + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/theme@0.5.6 + - @backstage/version-bridge@1.0.8 + +## @backstage/create-app@0.5.18-next.0 + +### Patch Changes + +- c0a705d: Added the Kubernetes plugin to `create-app` +- Updated dependencies + - @backstage/cli-common@0.1.14 + +## @backstage/dev-utils@1.0.36-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-app-api@1.14.1-next.0 + - @backstage/app-defaults@1.5.9-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/theme@0.5.6 + +## @backstage/frontend-app-api@0.7.4-next.0 + +### Patch Changes + +- 7777b5f: Support icon overriding with the new `IconBundleBlueprint` API. +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-app-api@1.14.1-next.0 + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + +## @backstage/frontend-plugin-api@0.6.8-next.0 + +### Patch Changes + +- 4e53ad6: Introduce a new way to encapsulate extension kinds that replaces the extension creator pattern with `createExtensionBlueprint` + + This allows the creation of extension instances with the following pattern: + + ```tsx + // create the extension blueprint which is used to create instances + const EntityCardBlueprint = createExtensionBlueprint({ + kind: 'entity-card', + attachTo: { id: 'test', input: 'default' }, + output: { + element: coreExtensionData.reactElement, + }, + factory(params: { text: string }) { + return { + element: <h1>{params.text}</h1>, + }; + }, + }); + + // create an instance of the extension blueprint with params + const testExtension = EntityCardBlueprint.make({ + name: 'foo', + params: { + text: 'Hello World', + }, + }); + ``` + +- 9b89b82: The `ExtensionBoundary` now by default infers whether it's routable from whether it outputs a route path. + +- 7777b5f: Added a new `IconBundleBlueprint` that lets you create icon bundle extensions that can be installed in an App in order to override or add new app icons. + + ```tsx + import { IconBundleBlueprint } from '@backstage/frontend-plugin-api'; + + const exampleIconBundle = IconBundleBlueprint.make({ + name: 'example-bundle', + params: { + icons: { + user: MyOwnUserIcon, + }, + }, + }); + ``` + +- 31bfc44: Extension data references can now be defined in a way that encapsulates the ID string in the type, in addition to the data type itself. The old way of creating extension data references is deprecated and will be removed in a future release. + + For example, the following code: + + ```ts + export const myExtension = + createExtensionDataRef<MyType>('my-plugin.my-data'); + ``` + + Should be updated to the following: + + ```ts + export const myExtension = createExtensionDataRef<MyType>().with({ + id: 'my-plugin.my-data', + }); + ``` + +- Updated dependencies + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + +## @backstage/frontend-test-utils@0.1.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/frontend-app-api@0.7.4-next.0 + - @backstage/test-utils@1.5.9-next.0 + - @backstage/types@1.1.1 + +## @backstage/integration-react@1.1.30-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + +## @backstage/repo-tools@0.9.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.8.2-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/cli-common@0.1.14 + - @backstage/cli-node@0.2.7 + - @backstage/errors@1.2.4 + +## @techdocs/cli@1.8.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.4.2-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/plugin-techdocs-node@1.12.9-next.0 + +## @backstage/test-utils@1.5.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.14.1-next.0 + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-react@0.4.24 + +## @backstage/plugin-api-docs@0.11.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/core-compat-api@0.2.8-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/plugin-catalog@1.21.2-next.0 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-permission-react@0.4.24 + +## @backstage/plugin-app-backend@0.3.72-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/config-loader@1.8.2-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-app-node@0.1.23-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + +## @backstage/plugin-app-node@0.1.23-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.8.2-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + +## @backstage/plugin-app-visualizer@0.1.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + +## @backstage/plugin-auth-backend@0.22.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/plugin-auth-backend-module-microsoft-provider@0.1.18-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-backend-module-atlassian-provider@0.2.4-next.0 + - @backstage/plugin-auth-backend-module-aws-alb-provider@0.1.15-next.0 + - @backstage/plugin-auth-backend-module-azure-easyauth-provider@0.1.6-next.0 + - @backstage/plugin-auth-backend-module-bitbucket-provider@0.1.6-next.0 + - @backstage/plugin-auth-backend-module-cloudflare-access-provider@0.1.6-next.0 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.18-next.0 + - @backstage/plugin-auth-backend-module-github-provider@0.1.20-next.0 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.1.20-next.0 + - @backstage/plugin-auth-backend-module-google-provider@0.1.20-next.0 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.2.4-next.0 + - @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.16-next.0 + - @backstage/plugin-auth-backend-module-oidc-provider@0.2.4-next.0 + - @backstage/plugin-auth-backend-module-okta-provider@0.0.16-next.0 + - @backstage/plugin-auth-backend-module-onelogin-provider@0.1.4-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + +## @backstage/plugin-auth-backend-module-atlassian-provider@0.2.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + +## @backstage/plugin-auth-backend-module-aws-alb-provider@0.1.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-backend@0.22.10-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + +## @backstage/plugin-auth-backend-module-azure-easyauth-provider@0.1.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.18-next.0 + +## @backstage/plugin-auth-backend-module-bitbucket-provider@0.1.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + +## @backstage/plugin-auth-backend-module-cloudflare-access-provider@0.1.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.18-next.0 + +## @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.0 + +## @backstage/plugin-auth-backend-module-github-provider@0.1.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + +## @backstage/plugin-auth-backend-module-gitlab-provider@0.1.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + +## @backstage/plugin-auth-backend-module-google-provider@0.1.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + +## @backstage/plugin-auth-backend-module-guest-provider@0.1.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.18-next.0 + +## @backstage/plugin-auth-backend-module-microsoft-provider@0.1.18-next.0 + +### Patch Changes + +- 39f36a9: Updated the Microsoft authenticator to accurately define required scopes, but to also omit the required and additional scopes when requesting resource scopes. +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + +## @backstage/plugin-auth-backend-module-oauth2-provider@0.2.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + +## @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.18-next.0 + +## @backstage/plugin-auth-backend-module-oidc-provider@0.2.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-auth-backend@0.22.10-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + +## @backstage/plugin-auth-backend-module-okta-provider@0.0.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + +## @backstage/plugin-auth-backend-module-onelogin-provider@0.1.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + +## @backstage/plugin-auth-backend-module-pinniped-provider@0.1.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + +## @backstage/plugin-auth-backend-module-vmware-cloud-provider@0.2.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + +## @backstage/plugin-auth-node@0.4.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-auth-react@0.1.5-next.0 + +### Patch Changes + +- aeac3e9: feat: Hide visibility of CookieAuthRedirect +- Updated dependencies + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + +## @backstage/plugin-bitbucket-cloud-common@0.2.22-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.14.0-next.0 + +## @backstage/plugin-catalog@1.21.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/plugin-search-react@1.7.14-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-compat-api@0.2.8-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/plugin-scaffolder-common@1.5.4 + - @backstage/plugin-search-common@1.2.13 + +## @backstage/plugin-catalog-backend@1.24.1-next.0 + +### Patch Changes + +- a629fb2: Added setAllowedLocationTypes while introducing a new extension point called CatalogLocationsExtensionPoint +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-openapi-utils@0.1.16-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-events-node@0.3.9-next.0 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.1-next.0 + - @backstage/plugin-search-backend-module-catalog@0.1.29-next.0 + +## @backstage/plugin-catalog-backend-module-aws@0.3.18-next.0 + +### Patch Changes + +- ba8571e: Setup user agent header for AWS sdk clients, this enables users to better track API calls made from Backstage to AWS APIs through things like CloudTrail. +- 90a7340: `AwsOrganizationCloudAccountProcessor` configuration field `roleArn` is deprecated in favor of new field `accountId` +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration-aws-node@0.1.12 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-kubernetes-common@0.8.1 + +## @backstage/plugin-catalog-backend-module-azure@0.1.43-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/config@1.2.0 + - @backstage/plugin-catalog-common@1.0.25 + +## @backstage/plugin-catalog-backend-module-backstage-openapi@0.2.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/backend-openapi-utils@0.1.16-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-catalog-backend-module-bitbucket-cloud@0.2.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.22-next.0 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-events-node@0.3.9-next.0 + +## @backstage/plugin-catalog-backend-module-bitbucket-server@0.1.37-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-catalog-backend-module-gcp@0.1.24-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/plugin-kubernetes-common@0.8.1 + +## @backstage/plugin-catalog-backend-module-gerrit@0.1.40-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + +## @backstage/plugin-catalog-backend-module-github@0.6.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-backend@1.24.1-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-events-node@0.3.9-next.0 + +## @backstage/plugin-catalog-backend-module-github-org@0.1.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/config@1.2.0 + - @backstage/plugin-catalog-backend-module-github@0.6.6-next.0 + - @backstage/plugin-events-node@0.3.9-next.0 + +## @backstage/plugin-catalog-backend-module-gitlab@0.3.22-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-events-node@0.3.9-next.0 + +## @backstage/plugin-catalog-backend-module-gitlab-org@0.0.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-catalog-backend-module-gitlab@0.3.22-next.0 + - @backstage/plugin-events-node@0.3.9-next.0 + +## @backstage/plugin-catalog-backend-module-incremental-ingestion@0.4.28-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-backend@1.24.1-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-events-node@0.3.9-next.0 + - @backstage/plugin-permission-common@0.8.0 + +## @backstage/plugin-catalog-backend-module-ldap@0.7.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.25 + +## @backstage/plugin-catalog-backend-module-logs@0.0.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.24.1-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-events-node@0.3.9-next.0 + +## @backstage/plugin-catalog-backend-module-msgraph@0.5.31-next.0 + +### Patch Changes + +- 58dff4d: Added option to ingest groups based on their group membership in Azure Entra ID +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/plugin-catalog-common@1.0.25 + +## @backstage/plugin-catalog-backend-module-openapi@0.1.41-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-backend@1.24.1-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.25 + +## @backstage/plugin-catalog-backend-module-puppetdb@0.1.29-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.21-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-scaffolder-common@1.5.4 + +## @backstage/plugin-catalog-backend-module-unprocessed@0.4.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-catalog-unprocessed-entities-common@0.0.3 + - @backstage/plugin-permission-common@0.8.0 + +## @backstage/plugin-catalog-graph@0.4.8-next.0 + +### Patch Changes + +- fba7537: Memoize entity graph nodes when applying an `entityFilter` to prevent repeated redraws +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-compat-api@0.2.8-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog-import@0.12.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-compat-api@0.2.8-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/plugin-catalog-common@1.0.25 + +## @backstage/plugin-catalog-node@1.12.5-next.0 + +### Patch Changes + +- a629fb2: Added setAllowedLocationTypes while introducing a new extension point called CatalogLocationsExtensionPoint +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.1-next.0 + +## @backstage/plugin-catalog-react@1.12.3-next.0 + +### Patch Changes + +- 31bfc44: Updated alpha definitions of extension data references. +- 9b89b82: Internal refactor to remove unnecessary `routable` prop in the implementation of the `createEntityContentExtension` alpha export. +- bebd569: Fix extra divider displayed on user list picker component +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-react@0.4.24 + +## @backstage/plugin-catalog-unprocessed-entities@0.2.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.10-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + +## @backstage/plugin-config-schema@0.1.58-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-devtools@0.1.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-compat-api@0.2.8-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/plugin-devtools-common@0.1.11 + - @backstage/plugin-permission-react@0.4.24 + +## @backstage/plugin-devtools-backend@0.3.9-next.0 + +### Patch Changes + +- 32a38e1: Removed unused code for lockfile analysis. +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/config-loader@1.8.2-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-devtools-common@0.1.11 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.1-next.0 + +## @backstage/plugin-events-backend@0.3.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/plugin-events-node@0.3.9-next.0 + +## @backstage/plugin-events-backend-module-aws-sqs@0.3.9-next.0 + +### Patch Changes + +- ba8571e: Setup user agent header for AWS sdk clients, this enables users to better track API calls made from Backstage to AWS APIs through things like CloudTrail. +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + - @backstage/plugin-events-node@0.3.9-next.0 + +## @backstage/plugin-events-backend-module-azure@0.2.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-events-node@0.3.9-next.0 + +## @backstage/plugin-events-backend-module-bitbucket-cloud@0.2.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-events-node@0.3.9-next.0 + +## @backstage/plugin-events-backend-module-gerrit@0.2.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-events-node@0.3.9-next.0 + +## @backstage/plugin-events-backend-module-github@0.2.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/plugin-events-node@0.3.9-next.0 + +## @backstage/plugin-events-backend-module-gitlab@0.2.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/plugin-events-node@0.3.9-next.0 + +## @backstage/plugin-events-backend-test-utils@0.1.33-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.3.9-next.0 + +## @backstage/plugin-events-node@0.3.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + +## @backstage/plugin-home@0.7.8-next.0 + +### Patch Changes + +- 31bfc44: Updated alpha definitions of extension data references. +- fdcc059: Fixed a bug on the WelcomeTitle component where the welcome message wasn't correct when the language was set to Spanish +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-app-api@1.14.1-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-compat-api@0.2.8-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + - @backstage/plugin-home-react@0.1.16-next.0 + +## @backstage/plugin-home-react@0.1.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + +## @backstage/plugin-kubernetes@0.11.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/plugin-kubernetes-common@0.8.1 + - @backstage/plugin-kubernetes-react@0.4.2-next.0 + +## @backstage/plugin-kubernetes-backend@0.18.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration-aws-node@0.1.12 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-kubernetes-common@0.8.1 + - @backstage/plugin-kubernetes-node@0.1.17-next.0 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.1-next.0 + +## @backstage/plugin-kubernetes-cluster@0.0.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/plugin-kubernetes-common@0.8.1 + - @backstage/plugin-kubernetes-react@0.4.2-next.0 + +## @backstage/plugin-kubernetes-node@0.1.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/types@1.1.1 + - @backstage/plugin-kubernetes-common@0.8.1 + +## @backstage/plugin-kubernetes-react@0.4.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.10-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-kubernetes-common@0.8.1 + +## @backstage/plugin-notifications@0.2.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/plugin-notifications-common@0.0.5 + - @backstage/plugin-signals-react@0.0.4 + +## @backstage/plugin-notifications-backend@0.3.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-events-node@0.3.9-next.0 + - @backstage/plugin-notifications-common@0.0.5 + - @backstage/plugin-notifications-node@0.2.4-next.0 + - @backstage/plugin-signals-node@0.1.9-next.0 + +## @backstage/plugin-notifications-backend-module-email@0.1.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/integration-aws-node@0.1.12 + - @backstage/types@1.1.1 + - @backstage/plugin-notifications-common@0.0.5 + - @backstage/plugin-notifications-node@0.2.4-next.0 + +## @backstage/plugin-notifications-node@0.2.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-notifications-common@0.0.5 + - @backstage/plugin-signals-node@0.1.9-next.0 + +## @backstage/plugin-org@0.6.28-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/core-compat-api@0.2.8-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/plugin-catalog-common@1.0.25 + +## @backstage/plugin-org-react@0.1.27-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + +## @backstage/plugin-permission-backend@0.5.47-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.1-next.0 + +## @backstage/plugin-permission-backend-module-allow-all-policy@0.1.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.1-next.0 + +## @backstage/plugin-permission-node@0.8.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-permission-common@0.8.0 + +## @backstage/plugin-proxy-backend@0.5.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder@1.23.1-next.0 + +### Patch Changes + +- bbd9f56: Cleaned up codebase of RepoUrlPicker +- b8600fe: Fix issue with `RepoUrlPicker` not refreshing the credentials for a different host +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/plugin-scaffolder-react@1.11.0-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-compat-api@0.2.8-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/plugin-scaffolder-common@1.5.4 + +## @backstage/plugin-scaffolder-backend@1.23.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.4.5-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.22-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.21-next.0 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.1-next.0 + - @backstage/plugin-scaffolder-backend-module-azure@0.1.15-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.2.13-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.1.13-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.1.13-next.0 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.1.15-next.0 + - @backstage/plugin-scaffolder-backend-module-gitea@0.1.13-next.0 + - @backstage/plugin-scaffolder-backend-module-github@0.4.1-next.0 + - @backstage/plugin-scaffolder-common@1.5.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + +## @backstage/plugin-scaffolder-backend-module-azure@0.1.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + +## @backstage/plugin-scaffolder-backend-module-bitbucket@0.2.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.1.13-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.1.13-next.0 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + +## @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.1.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-bitbucket-cloud-common@0.2.22-next.0 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + +## @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.1.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + +## @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.24-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + +## @backstage/plugin-scaffolder-backend-module-cookiecutter@0.2.47-next.0 + +### Patch Changes + +- dae85df: Add examples for `fetch:cookiecutter` scaffolder action & improve related tests +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + +## @backstage/plugin-scaffolder-backend-module-gcp@0.1.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + +## @backstage/plugin-scaffolder-backend-module-gerrit@0.1.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + +## @backstage/plugin-scaffolder-backend-module-gitea@0.1.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + +## @backstage/plugin-scaffolder-backend-module-github@0.4.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + +## @backstage/plugin-scaffolder-backend-module-gitlab@0.4.5-next.0 + +### Patch Changes + +- fad1b90: Allow the `createGitlabProjectVariableAction` to use oauth tokens + +- aab708e: Added test cases for gitlab:issue:edit examples + +- ef742dc: Added test cases for gitlab:projectAccessToken:create example + +- 1ba4c2f: Added test cases for gitlab:pipeline:trigger examples + +- a6603e4: Add custom action for merge request: **auto** + + The **Auto** action selects the committed action between _create_ and _update_. + + The **Auto** action fetches files using the **/projects/repository/tree endpoint**. + After fetching, it checks if the file exists locally and in the repository. If it does, it chooses **update**; otherwise, it chooses **create**. + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + +## @backstage/plugin-scaffolder-backend-module-notifications@0.0.6-next.0 + +### Patch Changes + +- 6fc03c7: Add examples for notification:send scaffolder action & improve related tests +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-notifications-common@0.0.5 + - @backstage/plugin-notifications-node@0.2.4-next.0 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + +## @backstage/plugin-scaffolder-backend-module-rails@0.4.40-next.0 + +### Patch Changes + +- 449def7: Add examples for fetch:rails scaffolder action & improve related tests +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + +## @backstage/plugin-scaffolder-backend-module-sentry@0.1.31-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + +## @backstage/plugin-scaffolder-backend-module-yeoman@0.3.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + - @backstage/plugin-scaffolder-node-test-utils@0.1.10-next.0 + +## @backstage/plugin-scaffolder-node@0.4.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-common@1.5.4 + +## @backstage/plugin-scaffolder-node-test-utils@0.1.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-test-utils@0.4.5-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + +## @backstage/plugin-search@1.4.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/plugin-search-react@1.7.14-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-compat-api@0.2.8-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + - @backstage/plugin-search-common@1.2.13 + +## @backstage/plugin-search-backend@1.5.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-defaults@0.4.2-next.0 + - @backstage/backend-openapi-utils@0.1.16-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.1-next.0 + - @backstage/plugin-search-backend-node@1.2.28-next.0 + - @backstage/plugin-search-common@1.2.13 + +## @backstage/plugin-search-backend-module-catalog@0.1.29-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-search-backend-node@1.2.28-next.0 + - @backstage/plugin-search-common@1.2.13 + +## @backstage/plugin-search-backend-module-elasticsearch@1.5.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/integration-aws-node@0.1.12 + - @backstage/plugin-search-backend-node@1.2.28-next.0 + - @backstage/plugin-search-common@1.2.13 + +## @backstage/plugin-search-backend-module-explore@0.1.29-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/config@1.2.0 + - @backstage/plugin-search-backend-node@1.2.28-next.0 + - @backstage/plugin-search-common@1.2.13 + +## @backstage/plugin-search-backend-module-pg@0.5.33-next.0 + +### Patch Changes + +- 7251567: Removing `@backstage/backend-app-api` dependency +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/plugin-search-backend-node@1.2.28-next.0 + - @backstage/plugin-search-common@1.2.13 + +## @backstage/plugin-search-backend-module-stack-overflow-collator@0.1.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/config@1.2.0 + - @backstage/plugin-search-backend-node@1.2.28-next.0 + - @backstage/plugin-search-common@1.2.13 + +## @backstage/plugin-search-backend-module-techdocs@0.1.28-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-search-backend-node@1.2.28-next.0 + - @backstage/plugin-search-common@1.2.13 + - @backstage/plugin-techdocs-node@1.12.9-next.0 + +## @backstage/plugin-search-backend-node@1.2.28-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-search-common@1.2.13 + +## @backstage/plugin-search-react@1.7.14-next.0 + +### Patch Changes + +- 31bfc44: Updated alpha definitions of extension data references. +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + - @backstage/plugin-search-common@1.2.13 + +## @backstage/plugin-signals@0.0.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/plugin-signals-react@0.0.4 + +## @backstage/plugin-signals-backend@0.1.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-events-node@0.3.9-next.0 + - @backstage/plugin-signals-node@0.1.9-next.0 + +## @backstage/plugin-signals-node@0.1.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-events-node@0.3.9-next.0 + +## @backstage/plugin-techdocs@1.10.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/plugin-search-react@1.7.14-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/plugin-auth-react@0.1.5-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-compat-api@0.2.8-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/theme@0.5.6 + - @backstage/plugin-search-common@1.2.13 + - @backstage/plugin-techdocs-react@1.2.7-next.0 + +## @backstage/plugin-techdocs-addons-test-utils@1.0.36-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/plugin-search-react@1.7.14-next.0 + - @backstage/core-app-api@1.14.1-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/test-utils@1.5.9-next.0 + - @backstage/plugin-catalog@1.21.2-next.0 + - @backstage/plugin-techdocs@1.10.8-next.0 + - @backstage/plugin-techdocs-react@1.2.7-next.0 + +## @backstage/plugin-techdocs-backend@1.10.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-search-backend-module-techdocs@0.1.28-next.0 + - @backstage/plugin-techdocs-node@1.12.9-next.0 + +## @backstage/plugin-techdocs-module-addons-contrib@1.1.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.10-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/plugin-techdocs-react@1.2.7-next.0 + +## @backstage/plugin-techdocs-node@1.12.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration-aws-node@0.1.12 + - @backstage/plugin-search-common@1.2.13 + +## @backstage/plugin-techdocs-react@1.2.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.10-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/version-bridge@1.0.8 + +## @backstage/plugin-user-settings@0.8.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-app-api@1.14.1-next.0 + - @backstage/core-compat-api@0.2.8-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/plugin-signals-react@0.0.4 + - @backstage/plugin-user-settings-common@0.0.1 + +## @backstage/plugin-user-settings-backend@0.2.22-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-signals-node@0.1.9-next.0 + - @backstage/plugin-user-settings-common@0.0.1 + +## example-app@0.2.100-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.27.0-next.0 + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/plugin-search-react@1.7.14-next.0 + - @backstage/plugin-home@0.7.8-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/plugin-scaffolder-react@1.11.0-next.0 + - @backstage/frontend-app-api@0.7.4-next.0 + - @backstage/plugin-catalog-graph@0.4.8-next.0 + - @backstage/plugin-scaffolder@1.23.1-next.0 + - @backstage/core-app-api@1.14.1-next.0 + - @backstage/plugin-auth-react@0.1.5-next.0 + - @backstage/app-defaults@1.5.9-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/theme@0.5.6 + - @backstage/plugin-api-docs@0.11.8-next.0 + - @backstage/plugin-catalog@1.21.2-next.0 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-catalog-import@0.12.2-next.0 + - @backstage/plugin-catalog-unprocessed-entities@0.2.7-next.0 + - @backstage/plugin-devtools@0.1.17-next.0 + - @backstage/plugin-kubernetes@0.11.13-next.0 + - @backstage/plugin-kubernetes-cluster@0.0.14-next.0 + - @backstage/plugin-notifications@0.2.4-next.0 + - @backstage/plugin-org@0.6.28-next.0 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/plugin-search@1.4.15-next.0 + - @backstage/plugin-search-common@1.2.13 + - @backstage/plugin-signals@0.0.9-next.0 + - @backstage/plugin-techdocs@1.10.8-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.13-next.0 + - @backstage/plugin-techdocs-react@1.2.7-next.0 + - @backstage/plugin-user-settings@0.8.10-next.0 + +## example-app-next@0.0.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.27.0-next.0 + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/plugin-search-react@1.7.14-next.0 + - @backstage/plugin-home@0.7.8-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/plugin-scaffolder-react@1.11.0-next.0 + - @backstage/frontend-app-api@0.7.4-next.0 + - @backstage/plugin-catalog-graph@0.4.8-next.0 + - @backstage/plugin-scaffolder@1.23.1-next.0 + - @backstage/core-app-api@1.14.1-next.0 + - @backstage/plugin-auth-react@0.1.5-next.0 + - @backstage/app-defaults@1.5.9-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-compat-api@0.2.8-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/theme@0.5.6 + - @backstage/plugin-api-docs@0.11.8-next.0 + - @backstage/plugin-app-visualizer@0.1.9-next.0 + - @backstage/plugin-catalog@1.21.2-next.0 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-catalog-import@0.12.2-next.0 + - @backstage/plugin-catalog-unprocessed-entities@0.2.7-next.0 + - @backstage/plugin-kubernetes@0.11.13-next.0 + - @backstage/plugin-kubernetes-cluster@0.0.14-next.0 + - @backstage/plugin-notifications@0.2.4-next.0 + - @backstage/plugin-org@0.6.28-next.0 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/plugin-search@1.4.15-next.0 + - @backstage/plugin-search-common@1.2.13 + - @backstage/plugin-signals@0.0.9-next.0 + - @backstage/plugin-techdocs@1.10.8-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.13-next.0 + - @backstage/plugin-techdocs-react@1.2.7-next.0 + - @backstage/plugin-user-settings@0.8.10-next.0 + +## app-next-example-plugin@0.0.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/core-components@0.14.10-next.0 + +## example-backend@0.0.29-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.4.2-next.0 + - @backstage/plugin-catalog-backend@1.24.1-next.0 + - @backstage/plugin-devtools-backend@0.3.9-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-app-backend@0.3.72-next.0 + - @backstage/plugin-auth-backend@0.22.10-next.0 + - @backstage/plugin-auth-backend-module-github-provider@0.1.20-next.0 + - @backstage/plugin-auth-backend-module-guest-provider@0.1.9-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.2.6-next.0 + - @backstage/plugin-catalog-backend-module-openapi@0.1.41-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.21-next.0 + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.10-next.0 + - @backstage/plugin-kubernetes-backend@0.18.4-next.0 + - @backstage/plugin-notifications-backend@0.3.4-next.0 + - @backstage/plugin-permission-backend@0.5.47-next.0 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.20-next.0 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.1-next.0 + - @backstage/plugin-proxy-backend@0.5.4-next.0 + - @backstage/plugin-scaffolder-backend@1.23.1-next.0 + - @backstage/plugin-scaffolder-backend-module-github@0.4.1-next.0 + - @backstage/plugin-search-backend@1.5.15-next.0 + - @backstage/plugin-search-backend-module-catalog@0.1.29-next.0 + - @backstage/plugin-search-backend-module-explore@0.1.29-next.0 + - @backstage/plugin-search-backend-module-techdocs@0.1.28-next.0 + - @backstage/plugin-search-backend-node@1.2.28-next.0 + - @backstage/plugin-signals-backend@0.1.9-next.0 + - @backstage/plugin-techdocs-backend@1.10.10-next.0 + +## example-backend-legacy@0.2.101-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.40-next.0 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.4.5-next.0 + - @backstage/plugin-catalog-backend@1.24.1-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/plugin-devtools-backend@0.3.9-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/plugin-search-backend-module-pg@0.5.33-next.0 + - example-app@0.2.100-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/plugin-app-backend@0.3.72-next.0 + - @backstage/plugin-auth-backend@0.22.10-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.21-next.0 + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.10-next.0 + - @backstage/plugin-events-backend@0.3.10-next.0 + - @backstage/plugin-events-node@0.3.9-next.0 + - @backstage/plugin-kubernetes-backend@0.18.4-next.0 + - @backstage/plugin-permission-backend@0.5.47-next.0 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.1-next.0 + - @backstage/plugin-proxy-backend@0.5.4-next.0 + - @backstage/plugin-scaffolder-backend@1.23.1-next.0 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.24-next.0 + - @backstage/plugin-search-backend@1.5.15-next.0 + - @backstage/plugin-search-backend-module-catalog@0.1.29-next.0 + - @backstage/plugin-search-backend-module-elasticsearch@1.5.4-next.0 + - @backstage/plugin-search-backend-module-explore@0.1.29-next.0 + - @backstage/plugin-search-backend-module-techdocs@0.1.28-next.0 + - @backstage/plugin-search-backend-node@1.2.28-next.0 + - @backstage/plugin-signals-backend@0.1.9-next.0 + - @backstage/plugin-signals-node@0.1.9-next.0 + - @backstage/plugin-techdocs-backend@1.10.10-next.0 + +## e2e-test@0.2.19-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.18-next.0 + - @backstage/cli-common@0.1.14 + - @backstage/errors@1.2.4 + +## techdocs-cli-embedded-app@0.2.99-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.27.0-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-app-api@1.14.1-next.0 + - @backstage/app-defaults@1.5.9-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/test-utils@1.5.9-next.0 + - @backstage/theme@0.5.6 + - @backstage/plugin-catalog@1.21.2-next.0 + - @backstage/plugin-techdocs@1.10.8-next.0 + - @backstage/plugin-techdocs-react@1.2.7-next.0 + +## @internal/plugin-todo-list@1.0.30-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + +## @internal/plugin-todo-list-backend@1.0.30-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.18-next.0 diff --git a/package.json b/package.json index 07c9b2917b..73d0ca5b19 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "root", - "version": "1.29.0", + "version": "1.30.0-next.0", "private": true, "repository": { "type": "git", diff --git a/packages/app-defaults/CHANGELOG.md b/packages/app-defaults/CHANGELOG.md index a03034112c..a045f9a4f9 100644 --- a/packages/app-defaults/CHANGELOG.md +++ b/packages/app-defaults/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/app-defaults +## 1.5.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-app-api@1.14.1-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + - @backstage/plugin-permission-react@0.4.24 + ## 1.5.8 ### Patch Changes diff --git a/packages/app-defaults/package.json b/packages/app-defaults/package.json index 8997ba860f..2389c2cddc 100644 --- a/packages/app-defaults/package.json +++ b/packages/app-defaults/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/app-defaults", - "version": "1.5.8", + "version": "1.5.9-next.0", "description": "Provides the default wiring of a Backstage App", "backstage": { "role": "web-library" diff --git a/packages/app-next-example-plugin/CHANGELOG.md b/packages/app-next-example-plugin/CHANGELOG.md index fb61388f22..f05b81642f 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.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/core-components@0.14.10-next.0 + ## 0.0.13 ### Patch Changes diff --git a/packages/app-next-example-plugin/package.json b/packages/app-next-example-plugin/package.json index c48d5a92be..d397883063 100644 --- a/packages/app-next-example-plugin/package.json +++ b/packages/app-next-example-plugin/package.json @@ -1,6 +1,6 @@ { "name": "app-next-example-plugin", - "version": "0.0.13", + "version": "0.0.14-next.0", "description": "Backstage internal example plugin", "backstage": { "role": "frontend-plugin", diff --git a/packages/app-next/CHANGELOG.md b/packages/app-next/CHANGELOG.md index 3bbf698ebd..794484d2ce 100644 --- a/packages/app-next/CHANGELOG.md +++ b/packages/app-next/CHANGELOG.md @@ -1,5 +1,48 @@ # example-app-next +## 0.0.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.27.0-next.0 + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/plugin-search-react@1.7.14-next.0 + - @backstage/plugin-home@0.7.8-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/plugin-scaffolder-react@1.11.0-next.0 + - @backstage/frontend-app-api@0.7.4-next.0 + - @backstage/plugin-catalog-graph@0.4.8-next.0 + - @backstage/plugin-scaffolder@1.23.1-next.0 + - @backstage/core-app-api@1.14.1-next.0 + - @backstage/plugin-auth-react@0.1.5-next.0 + - @backstage/app-defaults@1.5.9-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-compat-api@0.2.8-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/theme@0.5.6 + - @backstage/plugin-api-docs@0.11.8-next.0 + - @backstage/plugin-app-visualizer@0.1.9-next.0 + - @backstage/plugin-catalog@1.21.2-next.0 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-catalog-import@0.12.2-next.0 + - @backstage/plugin-catalog-unprocessed-entities@0.2.7-next.0 + - @backstage/plugin-kubernetes@0.11.13-next.0 + - @backstage/plugin-kubernetes-cluster@0.0.14-next.0 + - @backstage/plugin-notifications@0.2.4-next.0 + - @backstage/plugin-org@0.6.28-next.0 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/plugin-search@1.4.15-next.0 + - @backstage/plugin-search-common@1.2.13 + - @backstage/plugin-signals@0.0.9-next.0 + - @backstage/plugin-techdocs@1.10.8-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.13-next.0 + - @backstage/plugin-techdocs-react@1.2.7-next.0 + - @backstage/plugin-user-settings@0.8.10-next.0 + ## 0.0.13 ### Patch Changes diff --git a/packages/app-next/package.json b/packages/app-next/package.json index c0c19bc40c..b4b9f69c51 100644 --- a/packages/app-next/package.json +++ b/packages/app-next/package.json @@ -1,6 +1,6 @@ { "name": "example-app-next", - "version": "0.0.13", + "version": "0.0.14-next.0", "private": true, "repository": { "type": "git", diff --git a/packages/app/CHANGELOG.md b/packages/app/CHANGELOG.md index a75cf24a07..4ba5430905 100644 --- a/packages/app/CHANGELOG.md +++ b/packages/app/CHANGELOG.md @@ -1,5 +1,46 @@ # example-app +## 0.2.100-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.27.0-next.0 + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/plugin-search-react@1.7.14-next.0 + - @backstage/plugin-home@0.7.8-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/plugin-scaffolder-react@1.11.0-next.0 + - @backstage/frontend-app-api@0.7.4-next.0 + - @backstage/plugin-catalog-graph@0.4.8-next.0 + - @backstage/plugin-scaffolder@1.23.1-next.0 + - @backstage/core-app-api@1.14.1-next.0 + - @backstage/plugin-auth-react@0.1.5-next.0 + - @backstage/app-defaults@1.5.9-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/theme@0.5.6 + - @backstage/plugin-api-docs@0.11.8-next.0 + - @backstage/plugin-catalog@1.21.2-next.0 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-catalog-import@0.12.2-next.0 + - @backstage/plugin-catalog-unprocessed-entities@0.2.7-next.0 + - @backstage/plugin-devtools@0.1.17-next.0 + - @backstage/plugin-kubernetes@0.11.13-next.0 + - @backstage/plugin-kubernetes-cluster@0.0.14-next.0 + - @backstage/plugin-notifications@0.2.4-next.0 + - @backstage/plugin-org@0.6.28-next.0 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/plugin-search@1.4.15-next.0 + - @backstage/plugin-search-common@1.2.13 + - @backstage/plugin-signals@0.0.9-next.0 + - @backstage/plugin-techdocs@1.10.8-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.13-next.0 + - @backstage/plugin-techdocs-react@1.2.7-next.0 + - @backstage/plugin-user-settings@0.8.10-next.0 + ## 0.2.99 ### Patch Changes diff --git a/packages/app/package.json b/packages/app/package.json index 29cfbf0357..0468a2f7a8 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,6 +1,6 @@ { "name": "example-app", - "version": "0.2.99", + "version": "0.2.100-next.0", "backstage": { "role": "frontend" }, diff --git a/packages/backend-app-api/CHANGELOG.md b/packages/backend-app-api/CHANGELOG.md index 70a163ee34..94ab9afb6f 100644 --- a/packages/backend-app-api/CHANGELOG.md +++ b/packages/backend-app-api/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/backend-app-api +## 0.8.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/config-loader@1.8.2-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/cli-common@0.1.14 + - @backstage/cli-node@0.2.7 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-permission-node@0.8.1-next.0 + ## 0.8.0 ### Minor Changes diff --git a/packages/backend-app-api/package.json b/packages/backend-app-api/package.json index 8bd156c3a4..9372b837e0 100644 --- a/packages/backend-app-api/package.json +++ b/packages/backend-app-api/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/backend-app-api", - "version": "0.8.0", + "version": "0.8.1-next.0", "description": "Core API used by Backstage backend apps", "backstage": { "role": "node-library" diff --git a/packages/backend-common/CHANGELOG.md b/packages/backend-common/CHANGELOG.md index 6d3218e0ed..01499c5d92 100644 --- a/packages/backend-common/CHANGELOG.md +++ b/packages/backend-common/CHANGELOG.md @@ -1,5 +1,33 @@ # @backstage/backend-common +## 0.23.4-next.0 + +### Patch Changes + +- ba8571e: Setup user agent header for AWS sdk clients, this enables users to better track API calls made from Backstage to AWS APIs through things like CloudTrail. +- 7e13b7a: The remaining exports in the package have now been deprecated: + + - `cacheToPluginCacheManager` + - `createLegacyAuthAdapters` + - `LegacyCreateRouter` + - `legacyPlugin` + - `loggerToWinstonLogger` + - `makeLegacyPlugin` + + Users of these export should fully [migrate to the new backend system](https://backstage.io/docs/backend-system/building-backends/migrating). + +- Updated dependencies + - @backstage/integration@1.14.0-next.0 + - @backstage/config-loader@1.8.2-next.0 + - @backstage/backend-dev-utils@0.1.4 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration-aws-node@0.1.12 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.0 + ## 0.23.3 ### Patch Changes diff --git a/packages/backend-common/package.json b/packages/backend-common/package.json index 553c800ea5..4ace5e950a 100644 --- a/packages/backend-common/package.json +++ b/packages/backend-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/backend-common", - "version": "0.23.3", + "version": "0.23.4-next.0", "description": "Common functionality library for Backstage backends", "backstage": { "role": "node-library" diff --git a/packages/backend-defaults/CHANGELOG.md b/packages/backend-defaults/CHANGELOG.md index 7d2ad7d6b7..a8cc588f1e 100644 --- a/packages/backend-defaults/CHANGELOG.md +++ b/packages/backend-defaults/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/backend-defaults +## 0.4.2-next.0 + +### Patch Changes + +- 4e79d19: The `createHealthRouter` utility that allows you to create a health check router is now exported via `@backstage/backend-defaults/rootHttpRouter`. +- 78c1329: Updated `GitlabUrlReader.readUrl` and `GitlabUrlReader.readTree` to accept a user-provided token, supporting both bearer and private tokens. +- 8e967da: Fixed the routing of the new health check service, the health endpoints should now properly be available at `/.backstage/health/v1/readiness` and `/.backstage/health/v1/liveness`. +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/config-loader@1.8.2-next.0 + - @backstage/backend-app-api@0.8.1-next.0 + - @backstage/backend-dev-utils@0.1.4 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration-aws-node@0.1.12 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-events-node@0.3.9-next.0 + - @backstage/plugin-permission-node@0.8.1-next.0 + ## 0.4.0 ### Minor Changes diff --git a/packages/backend-defaults/package.json b/packages/backend-defaults/package.json index 87da6e0017..9c04507003 100644 --- a/packages/backend-defaults/package.json +++ b/packages/backend-defaults/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/backend-defaults", - "version": "0.4.0", + "version": "0.4.2-next.0", "description": "Backend defaults used by Backstage backend apps", "backstage": { "role": "node-library" diff --git a/packages/backend-dynamic-feature-service/CHANGELOG.md b/packages/backend-dynamic-feature-service/CHANGELOG.md index 3003a8e177..ade7a7c0ec 100644 --- a/packages/backend-dynamic-feature-service/CHANGELOG.md +++ b/packages/backend-dynamic-feature-service/CHANGELOG.md @@ -1,5 +1,31 @@ # @backstage/backend-dynamic-feature-service +## 0.2.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-backend@1.24.1-next.0 + - @backstage/config-loader@1.8.2-next.0 + - @backstage/backend-app-api@0.8.1-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/cli-common@0.1.14 + - @backstage/cli-node@0.2.7 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-app-node@0.1.23-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-events-backend@0.3.10-next.0 + - @backstage/plugin-events-node@0.3.9-next.0 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.1-next.0 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + - @backstage/plugin-search-backend-node@1.2.28-next.0 + - @backstage/plugin-search-common@1.2.13 + ## 0.2.15 ### Patch Changes diff --git a/packages/backend-dynamic-feature-service/package.json b/packages/backend-dynamic-feature-service/package.json index 0d05b97bd9..cc7a8b390b 100644 --- a/packages/backend-dynamic-feature-service/package.json +++ b/packages/backend-dynamic-feature-service/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-dynamic-feature-service", "description": "Backstage dynamic feature service", - "version": "0.2.15", + "version": "0.2.16-next.0", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/packages/backend-legacy/CHANGELOG.md b/packages/backend-legacy/CHANGELOG.md index 04538ca02e..5acae66b6a 100644 --- a/packages/backend-legacy/CHANGELOG.md +++ b/packages/backend-legacy/CHANGELOG.md @@ -1,5 +1,47 @@ # example-backend-legacy +## 0.2.101-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.40-next.0 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.4.5-next.0 + - @backstage/plugin-catalog-backend@1.24.1-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/plugin-devtools-backend@0.3.9-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/plugin-search-backend-module-pg@0.5.33-next.0 + - example-app@0.2.100-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/plugin-app-backend@0.3.72-next.0 + - @backstage/plugin-auth-backend@0.22.10-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.21-next.0 + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.10-next.0 + - @backstage/plugin-events-backend@0.3.10-next.0 + - @backstage/plugin-events-node@0.3.9-next.0 + - @backstage/plugin-kubernetes-backend@0.18.4-next.0 + - @backstage/plugin-permission-backend@0.5.47-next.0 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.1-next.0 + - @backstage/plugin-proxy-backend@0.5.4-next.0 + - @backstage/plugin-scaffolder-backend@1.23.1-next.0 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.24-next.0 + - @backstage/plugin-search-backend@1.5.15-next.0 + - @backstage/plugin-search-backend-module-catalog@0.1.29-next.0 + - @backstage/plugin-search-backend-module-elasticsearch@1.5.4-next.0 + - @backstage/plugin-search-backend-module-explore@0.1.29-next.0 + - @backstage/plugin-search-backend-module-techdocs@0.1.28-next.0 + - @backstage/plugin-search-backend-node@1.2.28-next.0 + - @backstage/plugin-signals-backend@0.1.9-next.0 + - @backstage/plugin-signals-node@0.1.9-next.0 + - @backstage/plugin-techdocs-backend@1.10.10-next.0 + ## 0.2.100 ### Patch Changes diff --git a/packages/backend-legacy/package.json b/packages/backend-legacy/package.json index 5861719455..8b07afca38 100644 --- a/packages/backend-legacy/package.json +++ b/packages/backend-legacy/package.json @@ -1,6 +1,6 @@ { "name": "example-backend-legacy", - "version": "0.2.100", + "version": "0.2.101-next.0", "backstage": { "role": "backend" }, diff --git a/packages/backend-openapi-utils/CHANGELOG.md b/packages/backend-openapi-utils/CHANGELOG.md index 540a239ad6..1056cc4cc1 100644 --- a/packages/backend-openapi-utils/CHANGELOG.md +++ b/packages/backend-openapi-utils/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/backend-openapi-utils +## 0.1.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/errors@1.2.4 + ## 0.1.15 ### Patch Changes diff --git a/packages/backend-openapi-utils/package.json b/packages/backend-openapi-utils/package.json index 3059af5ffe..7b7778f9fe 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.15", + "version": "0.1.16-next.0", "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 3f47354561..9dd2e2587c 100644 --- a/packages/backend-plugin-api/CHANGELOG.md +++ b/packages/backend-plugin-api/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/backend-plugin-api +## 0.7.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-permission-common@0.8.0 + ## 0.7.0 ### Minor Changes diff --git a/packages/backend-plugin-api/package.json b/packages/backend-plugin-api/package.json index 52fbfb5806..4bad9325f1 100644 --- a/packages/backend-plugin-api/package.json +++ b/packages/backend-plugin-api/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/backend-plugin-api", - "version": "0.7.0", + "version": "0.7.1-next.0", "description": "Core API used by Backstage backend plugins", "backstage": { "role": "node-library" diff --git a/packages/backend-tasks/CHANGELOG.md b/packages/backend-tasks/CHANGELOG.md index fef4fd56a9..929a38084c 100644 --- a/packages/backend-tasks/CHANGELOG.md +++ b/packages/backend-tasks/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/backend-tasks +## 0.5.28-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 0.5.27 ### Patch Changes diff --git a/packages/backend-tasks/package.json b/packages/backend-tasks/package.json index 998e1d0650..51e8c4611e 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.27", + "version": "0.5.28-next.0", "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 9bee6fae55..72672bba7f 100644 --- a/packages/backend-test-utils/CHANGELOG.md +++ b/packages/backend-test-utils/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/backend-test-utils +## 0.4.5-next.0 + +### Patch Changes + +- 4e79d19: The default services for `startTestBackend` and `ServiceFactoryTester` now includes the Root Health Service. +- Updated dependencies + - @backstage/backend-defaults@0.4.2-next.0 + - @backstage/backend-app-api@0.8.1-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-events-node@0.3.9-next.0 + ## 0.4.4 ### Patch Changes diff --git a/packages/backend-test-utils/package.json b/packages/backend-test-utils/package.json index 875949c0a0..e562b89c84 100644 --- a/packages/backend-test-utils/package.json +++ b/packages/backend-test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/backend-test-utils", - "version": "0.4.4", + "version": "0.4.5-next.0", "description": "Test helpers library for Backstage backends", "backstage": { "role": "node-library" diff --git a/packages/backend/CHANGELOG.md b/packages/backend/CHANGELOG.md index 854993119c..6110ab5f99 100644 --- a/packages/backend/CHANGELOG.md +++ b/packages/backend/CHANGELOG.md @@ -1,5 +1,42 @@ # example-backend +## 0.0.29-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.4.2-next.0 + - @backstage/plugin-catalog-backend@1.24.1-next.0 + - @backstage/plugin-devtools-backend@0.3.9-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-app-backend@0.3.72-next.0 + - @backstage/plugin-auth-backend@0.22.10-next.0 + - @backstage/plugin-auth-backend-module-github-provider@0.1.20-next.0 + - @backstage/plugin-auth-backend-module-guest-provider@0.1.9-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.2.6-next.0 + - @backstage/plugin-catalog-backend-module-openapi@0.1.41-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.21-next.0 + - @backstage/plugin-catalog-backend-module-unprocessed@0.4.10-next.0 + - @backstage/plugin-kubernetes-backend@0.18.4-next.0 + - @backstage/plugin-notifications-backend@0.3.4-next.0 + - @backstage/plugin-permission-backend@0.5.47-next.0 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.20-next.0 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.1-next.0 + - @backstage/plugin-proxy-backend@0.5.4-next.0 + - @backstage/plugin-scaffolder-backend@1.23.1-next.0 + - @backstage/plugin-scaffolder-backend-module-github@0.4.1-next.0 + - @backstage/plugin-search-backend@1.5.15-next.0 + - @backstage/plugin-search-backend-module-catalog@0.1.29-next.0 + - @backstage/plugin-search-backend-module-explore@0.1.29-next.0 + - @backstage/plugin-search-backend-module-techdocs@0.1.28-next.0 + - @backstage/plugin-search-backend-node@1.2.28-next.0 + - @backstage/plugin-signals-backend@0.1.9-next.0 + - @backstage/plugin-techdocs-backend@1.10.10-next.0 + ## 0.0.28 ### Patch Changes diff --git a/packages/backend/package.json b/packages/backend/package.json index ae47716326..27c378e339 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -1,6 +1,6 @@ { "name": "example-backend", - "version": "0.0.28", + "version": "0.0.29-next.0", "main": "dist/index.cjs.js", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index c062324abb..cbeb8493eb 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -1,5 +1,40 @@ # @backstage/cli +## 0.27.0-next.0 + +### Minor Changes + +- 32a38e1: **BREAKING**: The lockfile (`yarn.lock`) dependency analysis and mutations have been removed from several commands. + + The `versions:bump` command will no longer attempt to bump and deduplicate dependencies by modifying the lockfile, it will only update `package.json` files. + + The `versions:check` command has been removed, since its only purpose was verification and mutation of the lockfile. We recommend using the `yarn dedupe` command instead, or the `yarn-deduplicate` package if you're using Yarn classic. + + The check that was built into the `package start` command has been removed, it will no longer warn about lockfile mismatches. + + The packages in the Backstage ecosystem handle package duplications much better now than when these CLI features were first introduced, so the need for these features has diminished. By removing them, we drastically reduce the integration between the Backstage CLI and Yarn, making it much easier to add support for other package managers in the future. + +### Patch Changes + +- 7eb08a6: Add frontend-dynamic-container role to eslint config factory +- fbc7819: Use ES2022 in CLI bundler +- e53074f: Updated default backend plugin to use `RootConfigService` instead of `Config`. This also removes the dependency on `@backstage/config` as it's no longer used. +- ee2b0e5: The experimental module federation build now has the ability to force the use of development versions of `react` and `react-dom` by setting the `FORCE_REACT_DEVELOPMENT` flag. +- 239dffc: Remove usage of deprecated functionality from @backstage/config-loader +- 0eedec3: Add support for dynamic plugins via the EXPERIMENTAL_MODULE_FEDERATION environment variable when running `yarn start`. +- dc4fb4f: Fix for `repo build --all` not properly detecting the experimental public entry point. +- Updated dependencies + - @backstage/integration@1.14.0-next.0 + - @backstage/config-loader@1.8.2-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/cli-common@0.1.14 + - @backstage/cli-node@0.2.7 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/eslint-plugin@0.1.8 + - @backstage/release-manifests@0.0.11 + - @backstage/types@1.1.1 + ## 0.26.11 ### Patch Changes diff --git a/packages/cli/package.json b/packages/cli/package.json index ccc4818331..0c999b8b9c 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/cli", - "version": "0.26.11", + "version": "0.27.0-next.0", "description": "CLI for developing Backstage plugins and apps", "backstage": { "role": "cli" diff --git a/packages/config-loader/CHANGELOG.md b/packages/config-loader/CHANGELOG.md index fb048e7237..f19fa29e29 100644 --- a/packages/config-loader/CHANGELOG.md +++ b/packages/config-loader/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/config-loader +## 1.8.2-next.0 + +### Patch Changes + +- 493feac: Add boolean `allowMissingDefaultConfig` option to `ConfigSources.default` and + `ConfigSources.defaultForTargets`, which results in omission of a ConfigSource + for the default app-config.yaml configuration file if it's not present. +- Updated dependencies + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 1.8.1 ### Patch Changes diff --git a/packages/config-loader/package.json b/packages/config-loader/package.json index 28718b8290..16ff3e4f0b 100644 --- a/packages/config-loader/package.json +++ b/packages/config-loader/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/config-loader", - "version": "1.8.1", + "version": "1.8.2-next.0", "description": "Config loading functionality used by Backstage backend, and CLI", "backstage": { "role": "node-library" diff --git a/packages/core-app-api/CHANGELOG.md b/packages/core-app-api/CHANGELOG.md index ff09befd63..26b9eb20fe 100644 --- a/packages/core-app-api/CHANGELOG.md +++ b/packages/core-app-api/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/core-app-api +## 1.14.1-next.0 + +### Patch Changes + +- 9a46a81: The request to delete the session cookie when running the app in protected mode is now done with a plain `fetch` rather than `FetchApi`. This fixes a bug where the app would immediately try to sign-in again when removing the cookie during logout. +- Updated dependencies + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + ## 1.14.0 ### Minor Changes diff --git a/packages/core-app-api/package.json b/packages/core-app-api/package.json index 5f297b16d5..0f78b11f98 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.14.0", + "version": "1.14.1-next.0", "publishConfig": { "access": "public" }, diff --git a/packages/core-compat-api/CHANGELOG.md b/packages/core-compat-api/CHANGELOG.md index 829c6f41ff..43acba43f0 100644 --- a/packages/core-compat-api/CHANGELOG.md +++ b/packages/core-compat-api/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/core-compat-api +## 0.2.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/version-bridge@1.0.8 + ## 0.2.7 ### Patch Changes diff --git a/packages/core-compat-api/package.json b/packages/core-compat-api/package.json index bbf131c761..dd954f3318 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.2.7", + "version": "0.2.8-next.0", "backstage": { "role": "web-library" }, diff --git a/packages/core-components/CHANGELOG.md b/packages/core-components/CHANGELOG.md index 3d46390597..a2463f594e 100644 --- a/packages/core-components/CHANGELOG.md +++ b/packages/core-components/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/core-components +## 0.14.10-next.0 + +### Patch Changes + +- 678971a: Move the `Link` component to the `RoutedTabs` instead of the `HeaderTabs` component +- Updated dependencies + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/theme@0.5.6 + - @backstage/version-bridge@1.0.8 + ## 0.14.9 ### Patch Changes diff --git a/packages/core-components/package.json b/packages/core-components/package.json index 55faac9dba..a2688a0037 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.14.9", + "version": "0.14.10-next.0", "publishConfig": { "access": "public" }, diff --git a/packages/create-app/CHANGELOG.md b/packages/create-app/CHANGELOG.md index d7ad8037e6..dea7ecb237 100644 --- a/packages/create-app/CHANGELOG.md +++ b/packages/create-app/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/create-app +## 0.5.18-next.0 + +### Patch Changes + +- c0a705d: Added the Kubernetes plugin to `create-app` +- Updated dependencies + - @backstage/cli-common@0.1.14 + ## 0.5.17 ### Patch Changes diff --git a/packages/create-app/package.json b/packages/create-app/package.json index 7d33d03a4b..b566cb53b1 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.17", + "version": "0.5.18-next.0", "publishConfig": { "access": "public" }, diff --git a/packages/dev-utils/CHANGELOG.md b/packages/dev-utils/CHANGELOG.md index f46a65827a..e6d6bf3ae4 100644 --- a/packages/dev-utils/CHANGELOG.md +++ b/packages/dev-utils/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/dev-utils +## 1.0.36-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-app-api@1.14.1-next.0 + - @backstage/app-defaults@1.5.9-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/theme@0.5.6 + ## 1.0.35 ### Patch Changes diff --git a/packages/dev-utils/package.json b/packages/dev-utils/package.json index 0902d7c322..72d35cd29c 100644 --- a/packages/dev-utils/package.json +++ b/packages/dev-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/dev-utils", - "version": "1.0.35", + "version": "1.0.36-next.0", "description": "Utilities for developing Backstage plugins.", "backstage": { "role": "web-library" diff --git a/packages/e2e-test/CHANGELOG.md b/packages/e2e-test/CHANGELOG.md index ad76bf8b75..3e346fdac8 100644 --- a/packages/e2e-test/CHANGELOG.md +++ b/packages/e2e-test/CHANGELOG.md @@ -1,5 +1,14 @@ # e2e-test +## 0.2.19-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.18-next.0 + - @backstage/cli-common@0.1.14 + - @backstage/errors@1.2.4 + ## 0.2.18 ### Patch Changes diff --git a/packages/e2e-test/package.json b/packages/e2e-test/package.json index 7fa0349a46..47fbd2ef1e 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.18", + "version": "0.2.19-next.0", "private": true, "backstage": { "role": "cli" diff --git a/packages/frontend-app-api/CHANGELOG.md b/packages/frontend-app-api/CHANGELOG.md index 7203efb8d8..0c7526d65e 100644 --- a/packages/frontend-app-api/CHANGELOG.md +++ b/packages/frontend-app-api/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/frontend-app-api +## 0.7.4-next.0 + +### Patch Changes + +- 7777b5f: Support icon overriding with the new `IconBundleBlueprint` API. +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-app-api@1.14.1-next.0 + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + ## 0.7.3 ### Patch Changes diff --git a/packages/frontend-app-api/package.json b/packages/frontend-app-api/package.json index a55284ff68..83127290f4 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.7.3", + "version": "0.7.4-next.0", "backstage": { "role": "web-library" }, diff --git a/packages/frontend-plugin-api/CHANGELOG.md b/packages/frontend-plugin-api/CHANGELOG.md index 4c0e6fe9f8..607883d5e0 100644 --- a/packages/frontend-plugin-api/CHANGELOG.md +++ b/packages/frontend-plugin-api/CHANGELOG.md @@ -1,5 +1,76 @@ # @backstage/frontend-plugin-api +## 0.6.8-next.0 + +### Patch Changes + +- 4e53ad6: Introduce a new way to encapsulate extension kinds that replaces the extension creator pattern with `createExtensionBlueprint` + + This allows the creation of extension instances with the following pattern: + + ```tsx + // create the extension blueprint which is used to create instances + const EntityCardBlueprint = createExtensionBlueprint({ + kind: 'entity-card', + attachTo: { id: 'test', input: 'default' }, + output: { + element: coreExtensionData.reactElement, + }, + factory(params: { text: string }) { + return { + element: <h1>{params.text}</h1>, + }; + }, + }); + + // create an instance of the extension blueprint with params + const testExtension = EntityCardBlueprint.make({ + name: 'foo', + params: { + text: 'Hello World', + }, + }); + ``` + +- 9b89b82: The `ExtensionBoundary` now by default infers whether it's routable from whether it outputs a route path. +- 7777b5f: Added a new `IconBundleBlueprint` that lets you create icon bundle extensions that can be installed in an App in order to override or add new app icons. + + ```tsx + import { IconBundleBlueprint } from '@backstage/frontend-plugin-api'; + + const exampleIconBundle = IconBundleBlueprint.make({ + name: 'example-bundle', + params: { + icons: { + user: MyOwnUserIcon, + }, + }, + }); + ``` + +- 31bfc44: Extension data references can now be defined in a way that encapsulates the ID string in the type, in addition to the data type itself. The old way of creating extension data references is deprecated and will be removed in a future release. + + For example, the following code: + + ```ts + export const myExtension = + createExtensionDataRef<MyType>('my-plugin.my-data'); + ``` + + Should be updated to the following: + + ```ts + export const myExtension = createExtensionDataRef<MyType>().with({ + id: 'my-plugin.my-data', + }); + ``` + +- Updated dependencies + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + ## 0.6.7 ### Patch Changes diff --git a/packages/frontend-plugin-api/package.json b/packages/frontend-plugin-api/package.json index f02f3fdedf..0206fece7e 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.6.7", + "version": "0.6.8-next.0", "backstage": { "role": "web-library" }, diff --git a/packages/frontend-test-utils/CHANGELOG.md b/packages/frontend-test-utils/CHANGELOG.md index de21194f4e..89deed057e 100644 --- a/packages/frontend-test-utils/CHANGELOG.md +++ b/packages/frontend-test-utils/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/frontend-test-utils +## 0.1.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/frontend-app-api@0.7.4-next.0 + - @backstage/test-utils@1.5.9-next.0 + - @backstage/types@1.1.1 + ## 0.1.10 ### Patch Changes diff --git a/packages/frontend-test-utils/package.json b/packages/frontend-test-utils/package.json index 0816a25443..1d0b00132b 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.10", + "version": "0.1.11-next.0", "backstage": { "role": "web-library" }, diff --git a/packages/integration-react/CHANGELOG.md b/packages/integration-react/CHANGELOG.md index ed54a92f5c..36ecf6f718 100644 --- a/packages/integration-react/CHANGELOG.md +++ b/packages/integration-react/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/integration-react +## 1.1.30-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.14.0-next.0 + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + ## 1.1.29 ### Patch Changes diff --git a/packages/integration-react/package.json b/packages/integration-react/package.json index b04b603327..de42eb2798 100644 --- a/packages/integration-react/package.json +++ b/packages/integration-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/integration-react", - "version": "1.1.29", + "version": "1.1.30-next.0", "description": "Frontend package for managing integrations towards external systems", "backstage": { "role": "web-library" diff --git a/packages/integration/CHANGELOG.md b/packages/integration/CHANGELOG.md index 3fb630ccfc..b49c3410ec 100644 --- a/packages/integration/CHANGELOG.md +++ b/packages/integration/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/integration +## 1.14.0-next.0 + +### Minor Changes + +- 78c1329: Updated `GitlabUrlReader.readUrl` and `GitlabUrlReader.readTree` to accept a user-provided token, supporting both bearer and private tokens. + +### Patch Changes + +- c591670: Updated functions for `getHarnessEditContentsUrl`, `getHarnessFileContentsUrl`, `getHarnessArchiveUrl`, `getHarnessLatestCommitUrl` and `parseHarnessUrl` to handle account and org level urls +- Updated dependencies + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 1.13.0 ### Minor Changes diff --git a/packages/integration/package.json b/packages/integration/package.json index 810150cf2d..0d1b733bbf 100644 --- a/packages/integration/package.json +++ b/packages/integration/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/integration", - "version": "1.13.0", + "version": "1.14.0-next.0", "description": "Helpers for managing integrations towards external systems", "backstage": { "role": "common-library" diff --git a/packages/repo-tools/CHANGELOG.md b/packages/repo-tools/CHANGELOG.md index 18c696a51c..7f90cb37e9 100644 --- a/packages/repo-tools/CHANGELOG.md +++ b/packages/repo-tools/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/repo-tools +## 0.9.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.8.2-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/cli-common@0.1.14 + - @backstage/cli-node@0.2.7 + - @backstage/errors@1.2.4 + ## 0.9.4 ### Patch Changes diff --git a/packages/repo-tools/package.json b/packages/repo-tools/package.json index 9f3a177b4f..f314dcc580 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.9.4", + "version": "0.9.5-next.0", "publishConfig": { "access": "public" }, diff --git a/packages/techdocs-cli-embedded-app/CHANGELOG.md b/packages/techdocs-cli-embedded-app/CHANGELOG.md index 6c8cc3f4ac..727cd20533 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.99-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.27.0-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-app-api@1.14.1-next.0 + - @backstage/app-defaults@1.5.9-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/test-utils@1.5.9-next.0 + - @backstage/theme@0.5.6 + - @backstage/plugin-catalog@1.21.2-next.0 + - @backstage/plugin-techdocs@1.10.8-next.0 + - @backstage/plugin-techdocs-react@1.2.7-next.0 + ## 0.2.98 ### Patch Changes diff --git a/packages/techdocs-cli-embedded-app/package.json b/packages/techdocs-cli-embedded-app/package.json index 6c395636b1..13aa5a1855 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.98", + "version": "0.2.99-next.0", "private": true, "backstage": { "role": "frontend" diff --git a/packages/techdocs-cli/CHANGELOG.md b/packages/techdocs-cli/CHANGELOG.md index 34f612932c..74fe37f0b1 100644 --- a/packages/techdocs-cli/CHANGELOG.md +++ b/packages/techdocs-cli/CHANGELOG.md @@ -1,5 +1,16 @@ # @techdocs/cli +## 1.8.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.4.2-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/plugin-techdocs-node@1.12.9-next.0 + ## 1.8.16 ### Patch Changes diff --git a/packages/techdocs-cli/package.json b/packages/techdocs-cli/package.json index a44213abb7..98eea44657 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.16", + "version": "1.8.17-next.0", "publishConfig": { "access": "public" }, diff --git a/packages/test-utils/CHANGELOG.md b/packages/test-utils/CHANGELOG.md index 3f40af6299..951efa799d 100644 --- a/packages/test-utils/CHANGELOG.md +++ b/packages/test-utils/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/test-utils +## 1.5.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.14.1-next.0 + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-react@0.4.24 + ## 1.5.8 ### Patch Changes diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index 9d36217b46..dac4827938 100644 --- a/packages/test-utils/package.json +++ b/packages/test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/test-utils", - "version": "1.5.8", + "version": "1.5.9-next.0", "description": "Utilities to test Backstage plugins and apps.", "backstage": { "role": "web-library" diff --git a/plugins/api-docs/CHANGELOG.md b/plugins/api-docs/CHANGELOG.md index b6d585c0f0..80b23769a0 100644 --- a/plugins/api-docs/CHANGELOG.md +++ b/plugins/api-docs/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-api-docs +## 0.11.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/core-compat-api@0.2.8-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/plugin-catalog@1.21.2-next.0 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-permission-react@0.4.24 + ## 0.11.7 ### Patch Changes diff --git a/plugins/api-docs/package.json b/plugins/api-docs/package.json index 7cda749423..c448b1dd9b 100644 --- a/plugins/api-docs/package.json +++ b/plugins/api-docs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-api-docs", - "version": "0.11.7", + "version": "0.11.8-next.0", "description": "A Backstage plugin that helps represent API entities in the frontend", "backstage": { "role": "frontend-plugin", diff --git a/plugins/app-backend/CHANGELOG.md b/plugins/app-backend/CHANGELOG.md index 63265e33d9..bb73548da8 100644 --- a/plugins/app-backend/CHANGELOG.md +++ b/plugins/app-backend/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-app-backend +## 0.3.72-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/config-loader@1.8.2-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-app-node@0.1.23-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + ## 0.3.71 ### Patch Changes diff --git a/plugins/app-backend/package.json b/plugins/app-backend/package.json index e6661f9d73..fcd9cd34b9 100644 --- a/plugins/app-backend/package.json +++ b/plugins/app-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-app-backend", - "version": "0.3.71", + "version": "0.3.72-next.0", "description": "A Backstage backend plugin that serves the Backstage frontend app", "backstage": { "role": "backend-plugin", diff --git a/plugins/app-node/CHANGELOG.md b/plugins/app-node/CHANGELOG.md index 4dce17870a..af94c02d84 100644 --- a/plugins/app-node/CHANGELOG.md +++ b/plugins/app-node/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-app-node +## 0.1.23-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.8.2-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + ## 0.1.22 ### Patch Changes diff --git a/plugins/app-node/package.json b/plugins/app-node/package.json index a846190f31..c8e4074899 100644 --- a/plugins/app-node/package.json +++ b/plugins/app-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-app-node", - "version": "0.1.22", + "version": "0.1.23-next.0", "description": "Node.js library for the app plugin", "backstage": { "role": "node-library", diff --git a/plugins/app-visualizer/CHANGELOG.md b/plugins/app-visualizer/CHANGELOG.md index ec24e1cc8b..4db02d9234 100644 --- a/plugins/app-visualizer/CHANGELOG.md +++ b/plugins/app-visualizer/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-app-visualizer +## 0.1.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + ## 0.1.8 ### Patch Changes diff --git a/plugins/app-visualizer/package.json b/plugins/app-visualizer/package.json index 6b10ffc220..a156ceef2e 100644 --- a/plugins/app-visualizer/package.json +++ b/plugins/app-visualizer/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-app-visualizer", - "version": "0.1.8", + "version": "0.1.9-next.0", "description": "Visualizes the Backstage app structure", "backstage": { "role": "frontend-plugin", diff --git a/plugins/auth-backend-module-atlassian-provider/CHANGELOG.md b/plugins/auth-backend-module-atlassian-provider/CHANGELOG.md index 55287ebd46..a683d8199b 100644 --- a/plugins/auth-backend-module-atlassian-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-atlassian-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-auth-backend-module-atlassian-provider +## 0.2.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + ## 0.2.3 ### Patch Changes diff --git a/plugins/auth-backend-module-atlassian-provider/package.json b/plugins/auth-backend-module-atlassian-provider/package.json index 309dff7f50..dc638ba86f 100644 --- a/plugins/auth-backend-module-atlassian-provider/package.json +++ b/plugins/auth-backend-module-atlassian-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-atlassian-provider", - "version": "0.2.3", + "version": "0.2.4-next.0", "description": "The atlassian-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-aws-alb-provider/CHANGELOG.md b/plugins/auth-backend-module-aws-alb-provider/CHANGELOG.md index cc2db5e210..45e5d75611 100644 --- a/plugins/auth-backend-module-aws-alb-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-aws-alb-provider/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-auth-backend-module-aws-alb-provider +## 0.1.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-backend@0.22.10-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + ## 0.1.14 ### Patch Changes diff --git a/plugins/auth-backend-module-aws-alb-provider/package.json b/plugins/auth-backend-module-aws-alb-provider/package.json index 9d15f0ea09..25e43952e4 100644 --- a/plugins/auth-backend-module-aws-alb-provider/package.json +++ b/plugins/auth-backend-module-aws-alb-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-aws-alb-provider", - "version": "0.1.14", + "version": "0.1.15-next.0", "description": "The aws-alb provider module for the Backstage auth backend.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-azure-easyauth-provider/CHANGELOG.md b/plugins/auth-backend-module-azure-easyauth-provider/CHANGELOG.md index 26eb0d17b4..88898de862 100644 --- a/plugins/auth-backend-module-azure-easyauth-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-azure-easyauth-provider/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-auth-backend-module-azure-easyauth-provider +## 0.1.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.18-next.0 + ## 0.1.5 ### Patch Changes diff --git a/plugins/auth-backend-module-azure-easyauth-provider/package.json b/plugins/auth-backend-module-azure-easyauth-provider/package.json index 52293f2480..5a94dd320a 100644 --- a/plugins/auth-backend-module-azure-easyauth-provider/package.json +++ b/plugins/auth-backend-module-azure-easyauth-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-azure-easyauth-provider", - "version": "0.1.5", + "version": "0.1.6-next.0", "description": "The azure-easyauth-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-bitbucket-provider/CHANGELOG.md b/plugins/auth-backend-module-bitbucket-provider/CHANGELOG.md index 86ec768727..60a7ecc458 100644 --- a/plugins/auth-backend-module-bitbucket-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-bitbucket-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-auth-backend-module-bitbucket-provider +## 0.1.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + ## 0.1.5 ### Patch Changes diff --git a/plugins/auth-backend-module-bitbucket-provider/package.json b/plugins/auth-backend-module-bitbucket-provider/package.json index 8ddb0f8acd..159069ad4f 100644 --- a/plugins/auth-backend-module-bitbucket-provider/package.json +++ b/plugins/auth-backend-module-bitbucket-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-bitbucket-provider", - "version": "0.1.5", + "version": "0.1.6-next.0", "description": "The bitbucket-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-cloudflare-access-provider/CHANGELOG.md b/plugins/auth-backend-module-cloudflare-access-provider/CHANGELOG.md index 2910ffccce..8000a1da90 100644 --- a/plugins/auth-backend-module-cloudflare-access-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-cloudflare-access-provider/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-auth-backend-module-cloudflare-access-provider +## 0.1.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.18-next.0 + ## 0.1.5 ### Patch Changes diff --git a/plugins/auth-backend-module-cloudflare-access-provider/package.json b/plugins/auth-backend-module-cloudflare-access-provider/package.json index 30c60ed6a4..bed6fc8094 100644 --- a/plugins/auth-backend-module-cloudflare-access-provider/package.json +++ b/plugins/auth-backend-module-cloudflare-access-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-cloudflare-access-provider", - "version": "0.1.5", + "version": "0.1.6-next.0", "description": "The cloudflare-access-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-gcp-iap-provider/CHANGELOG.md b/plugins/auth-backend-module-gcp-iap-provider/CHANGELOG.md index 19549dc23a..0e3949cfdc 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.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.0 + ## 0.2.17 ### 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 d0059e7a69..b106675e14 100644 --- a/plugins/auth-backend-module-gcp-iap-provider/package.json +++ b/plugins/auth-backend-module-gcp-iap-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-gcp-iap-provider", - "version": "0.2.17", + "version": "0.2.18-next.0", "description": "A GCP IAP auth provider module for the Backstage auth backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-github-provider/CHANGELOG.md b/plugins/auth-backend-module-github-provider/CHANGELOG.md index 5d9704a86b..8f2d91ce6f 100644 --- a/plugins/auth-backend-module-github-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-github-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-auth-backend-module-github-provider +## 0.1.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + ## 0.1.19 ### Patch Changes diff --git a/plugins/auth-backend-module-github-provider/package.json b/plugins/auth-backend-module-github-provider/package.json index 42ef2ccd4e..a986d04852 100644 --- a/plugins/auth-backend-module-github-provider/package.json +++ b/plugins/auth-backend-module-github-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-github-provider", - "version": "0.1.19", + "version": "0.1.20-next.0", "description": "The github-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-gitlab-provider/CHANGELOG.md b/plugins/auth-backend-module-gitlab-provider/CHANGELOG.md index 57a6aa189b..15265dcca3 100644 --- a/plugins/auth-backend-module-gitlab-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-gitlab-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-auth-backend-module-gitlab-provider +## 0.1.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + ## 0.1.19 ### Patch Changes diff --git a/plugins/auth-backend-module-gitlab-provider/package.json b/plugins/auth-backend-module-gitlab-provider/package.json index b0e0d2e647..be77920597 100644 --- a/plugins/auth-backend-module-gitlab-provider/package.json +++ b/plugins/auth-backend-module-gitlab-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-gitlab-provider", - "version": "0.1.19", + "version": "0.1.20-next.0", "description": "The gitlab-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-google-provider/CHANGELOG.md b/plugins/auth-backend-module-google-provider/CHANGELOG.md index 17efe0d1a5..eaeed7dbca 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.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + ## 0.1.19 ### Patch Changes diff --git a/plugins/auth-backend-module-google-provider/package.json b/plugins/auth-backend-module-google-provider/package.json index 1153cbb37a..524d1f3d90 100644 --- a/plugins/auth-backend-module-google-provider/package.json +++ b/plugins/auth-backend-module-google-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-google-provider", - "version": "0.1.19", + "version": "0.1.20-next.0", "description": "A Google auth provider module for the Backstage auth backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-guest-provider/CHANGELOG.md b/plugins/auth-backend-module-guest-provider/CHANGELOG.md index 7c9e48041d..7382ea2c19 100644 --- a/plugins/auth-backend-module-guest-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-guest-provider/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-auth-backend-module-guest-provider +## 0.1.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.18-next.0 + ## 0.1.8 ### Patch Changes diff --git a/plugins/auth-backend-module-guest-provider/package.json b/plugins/auth-backend-module-guest-provider/package.json index 1648ebea6a..db19f2e37b 100644 --- a/plugins/auth-backend-module-guest-provider/package.json +++ b/plugins/auth-backend-module-guest-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-guest-provider", - "version": "0.1.8", + "version": "0.1.9-next.0", "description": "The guest-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-microsoft-provider/CHANGELOG.md b/plugins/auth-backend-module-microsoft-provider/CHANGELOG.md index c4df7007f3..b2d8d704d5 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.18-next.0 + +### Patch Changes + +- 39f36a9: Updated the Microsoft authenticator to accurately define required scopes, but to also omit the required and additional scopes when requesting resource scopes. +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + ## 0.1.17 ### Patch Changes diff --git a/plugins/auth-backend-module-microsoft-provider/package.json b/plugins/auth-backend-module-microsoft-provider/package.json index b67fb8c447..bb2f82dc68 100644 --- a/plugins/auth-backend-module-microsoft-provider/package.json +++ b/plugins/auth-backend-module-microsoft-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-microsoft-provider", - "version": "0.1.17", + "version": "0.1.18-next.0", "description": "The microsoft-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md b/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md index edfcfa0bcb..4090d62d57 100644 --- a/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-auth-backend-module-oauth2-provider +## 0.2.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + ## 0.2.3 ### Patch Changes diff --git a/plugins/auth-backend-module-oauth2-provider/package.json b/plugins/auth-backend-module-oauth2-provider/package.json index c98a36d104..962362ce87 100644 --- a/plugins/auth-backend-module-oauth2-provider/package.json +++ b/plugins/auth-backend-module-oauth2-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-oauth2-provider", - "version": "0.2.3", + "version": "0.2.4-next.0", "description": "The oauth2-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-oauth2-proxy-provider/CHANGELOG.md b/plugins/auth-backend-module-oauth2-proxy-provider/CHANGELOG.md index 554468bcfe..33fd2b18d4 100644 --- a/plugins/auth-backend-module-oauth2-proxy-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-oauth2-proxy-provider/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-auth-backend-module-oauth2-proxy-provider +## 0.1.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.18-next.0 + ## 0.1.15 ### Patch Changes diff --git a/plugins/auth-backend-module-oauth2-proxy-provider/package.json b/plugins/auth-backend-module-oauth2-proxy-provider/package.json index 16b4126781..e07da7f6d4 100644 --- a/plugins/auth-backend-module-oauth2-proxy-provider/package.json +++ b/plugins/auth-backend-module-oauth2-proxy-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-oauth2-proxy-provider", - "version": "0.1.15", + "version": "0.1.16-next.0", "description": "The oauth2-proxy-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-oidc-provider/CHANGELOG.md b/plugins/auth-backend-module-oidc-provider/CHANGELOG.md index 5e0d6aeb5c..b8702dd3e4 100644 --- a/plugins/auth-backend-module-oidc-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-oidc-provider/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-auth-backend-module-oidc-provider +## 0.2.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-auth-backend@0.22.10-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + ## 0.2.3 ### Patch Changes diff --git a/plugins/auth-backend-module-oidc-provider/package.json b/plugins/auth-backend-module-oidc-provider/package.json index d825bd2986..89ef91181c 100644 --- a/plugins/auth-backend-module-oidc-provider/package.json +++ b/plugins/auth-backend-module-oidc-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-oidc-provider", - "version": "0.2.3", + "version": "0.2.4-next.0", "description": "The oidc-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-okta-provider/CHANGELOG.md b/plugins/auth-backend-module-okta-provider/CHANGELOG.md index 029892a34a..3f3ecdbffa 100644 --- a/plugins/auth-backend-module-okta-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-okta-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-auth-backend-module-okta-provider +## 0.0.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + ## 0.0.15 ### Patch Changes diff --git a/plugins/auth-backend-module-okta-provider/package.json b/plugins/auth-backend-module-okta-provider/package.json index 4070ffd31f..18cb4ce208 100644 --- a/plugins/auth-backend-module-okta-provider/package.json +++ b/plugins/auth-backend-module-okta-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-okta-provider", - "version": "0.0.15", + "version": "0.0.16-next.0", "description": "The okta-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-onelogin-provider/CHANGELOG.md b/plugins/auth-backend-module-onelogin-provider/CHANGELOG.md index 896f6b7e0c..cbaa2f2ad6 100644 --- a/plugins/auth-backend-module-onelogin-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-onelogin-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-auth-backend-module-onelogin-provider +## 0.1.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + ## 0.1.3 ### Patch Changes diff --git a/plugins/auth-backend-module-onelogin-provider/package.json b/plugins/auth-backend-module-onelogin-provider/package.json index 045dce0392..750fe96aab 100644 --- a/plugins/auth-backend-module-onelogin-provider/package.json +++ b/plugins/auth-backend-module-onelogin-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-onelogin-provider", - "version": "0.1.3", + "version": "0.1.4-next.0", "description": "The onelogin-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-pinniped-provider/CHANGELOG.md b/plugins/auth-backend-module-pinniped-provider/CHANGELOG.md index c3ea4665e8..f0c914c43a 100644 --- a/plugins/auth-backend-module-pinniped-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-pinniped-provider/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-auth-backend-module-pinniped-provider +## 0.1.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + ## 0.1.16 ### Patch Changes diff --git a/plugins/auth-backend-module-pinniped-provider/package.json b/plugins/auth-backend-module-pinniped-provider/package.json index e6f50e4008..73496380af 100644 --- a/plugins/auth-backend-module-pinniped-provider/package.json +++ b/plugins/auth-backend-module-pinniped-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-pinniped-provider", - "version": "0.1.16", + "version": "0.1.17-next.0", "description": "The pinniped-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-vmware-cloud-provider/CHANGELOG.md b/plugins/auth-backend-module-vmware-cloud-provider/CHANGELOG.md index f652d6135c..aa61e780c5 100644 --- a/plugins/auth-backend-module-vmware-cloud-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-vmware-cloud-provider/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-auth-backend-module-vmware-cloud-provider +## 0.2.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + ## 0.2.3 ### Patch Changes diff --git a/plugins/auth-backend-module-vmware-cloud-provider/package.json b/plugins/auth-backend-module-vmware-cloud-provider/package.json index 77dafe38e1..f75891634b 100644 --- a/plugins/auth-backend-module-vmware-cloud-provider/package.json +++ b/plugins/auth-backend-module-vmware-cloud-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-vmware-cloud-provider", - "version": "0.2.3", + "version": "0.2.4-next.0", "description": "The vmware-cloud-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend/CHANGELOG.md b/plugins/auth-backend/CHANGELOG.md index 393820ec27..2b74787a53 100644 --- a/plugins/auth-backend/CHANGELOG.md +++ b/plugins/auth-backend/CHANGELOG.md @@ -1,5 +1,35 @@ # @backstage/plugin-auth-backend +## 0.22.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/plugin-auth-backend-module-microsoft-provider@0.1.18-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-backend-module-atlassian-provider@0.2.4-next.0 + - @backstage/plugin-auth-backend-module-aws-alb-provider@0.1.15-next.0 + - @backstage/plugin-auth-backend-module-azure-easyauth-provider@0.1.6-next.0 + - @backstage/plugin-auth-backend-module-bitbucket-provider@0.1.6-next.0 + - @backstage/plugin-auth-backend-module-cloudflare-access-provider@0.1.6-next.0 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.18-next.0 + - @backstage/plugin-auth-backend-module-github-provider@0.1.20-next.0 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.1.20-next.0 + - @backstage/plugin-auth-backend-module-google-provider@0.1.20-next.0 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.2.4-next.0 + - @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.16-next.0 + - @backstage/plugin-auth-backend-module-oidc-provider@0.2.4-next.0 + - @backstage/plugin-auth-backend-module-okta-provider@0.0.16-next.0 + - @backstage/plugin-auth-backend-module-onelogin-provider@0.1.4-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + ## 0.22.9 ### Patch Changes diff --git a/plugins/auth-backend/package.json b/plugins/auth-backend/package.json index c9d437ceba..57591313f4 100644 --- a/plugins/auth-backend/package.json +++ b/plugins/auth-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend", - "version": "0.22.9", + "version": "0.22.10-next.0", "description": "A Backstage backend plugin that handles authentication", "backstage": { "role": "backend-plugin", diff --git a/plugins/auth-node/CHANGELOG.md b/plugins/auth-node/CHANGELOG.md index 298f0e4472..021d89b518 100644 --- a/plugins/auth-node/CHANGELOG.md +++ b/plugins/auth-node/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-auth-node +## 0.4.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 0.4.17 ### Patch Changes diff --git a/plugins/auth-node/package.json b/plugins/auth-node/package.json index 0f4b0f5a77..114491c06e 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.17", + "version": "0.4.18-next.0", "backstage": { "role": "node-library", "pluginId": "auth", diff --git a/plugins/auth-react/CHANGELOG.md b/plugins/auth-react/CHANGELOG.md index 4651cf7eae..f7d621164c 100644 --- a/plugins/auth-react/CHANGELOG.md +++ b/plugins/auth-react/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-auth-react +## 0.1.5-next.0 + +### Patch Changes + +- aeac3e9: feat: Hide visibility of CookieAuthRedirect +- Updated dependencies + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + ## 0.1.4 ### Patch Changes diff --git a/plugins/auth-react/package.json b/plugins/auth-react/package.json index 44a4ce9fd0..b68e581c74 100644 --- a/plugins/auth-react/package.json +++ b/plugins/auth-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-react", - "version": "0.1.4", + "version": "0.1.5-next.0", "description": "Web library for the auth plugin", "backstage": { "role": "web-library", diff --git a/plugins/bitbucket-cloud-common/CHANGELOG.md b/plugins/bitbucket-cloud-common/CHANGELOG.md index 7b2b8a936b..c4ce7148f4 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.22-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.14.0-next.0 + ## 0.2.21 ### Patch Changes diff --git a/plugins/bitbucket-cloud-common/package.json b/plugins/bitbucket-cloud-common/package.json index d52122f995..06fd4e6f3a 100644 --- a/plugins/bitbucket-cloud-common/package.json +++ b/plugins/bitbucket-cloud-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-bitbucket-cloud-common", - "version": "0.2.21", + "version": "0.2.22-next.0", "description": "Common functionalities for bitbucket-cloud plugins", "backstage": { "role": "common-library", diff --git a/plugins/catalog-backend-module-aws/CHANGELOG.md b/plugins/catalog-backend-module-aws/CHANGELOG.md index f2dd32b7f2..22a372051e 100644 --- a/plugins/catalog-backend-module-aws/CHANGELOG.md +++ b/plugins/catalog-backend-module-aws/CHANGELOG.md @@ -1,5 +1,24 @@ # @backstage/plugin-catalog-backend-module-aws +## 0.3.18-next.0 + +### Patch Changes + +- ba8571e: Setup user agent header for AWS sdk clients, this enables users to better track API calls made from Backstage to AWS APIs through things like CloudTrail. +- 90a7340: `AwsOrganizationCloudAccountProcessor` configuration field `roleArn` is deprecated in favor of new field `accountId` +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration-aws-node@0.1.12 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-kubernetes-common@0.8.1 + ## 0.3.17 ### Patch Changes diff --git a/plugins/catalog-backend-module-aws/package.json b/plugins/catalog-backend-module-aws/package.json index 91ac7c4eae..eeb26b2e1c 100644 --- a/plugins/catalog-backend-module-aws/package.json +++ b/plugins/catalog-backend-module-aws/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-aws", - "version": "0.3.17", + "version": "0.3.18-next.0", "description": "A Backstage catalog backend module that helps integrate towards AWS", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-azure/CHANGELOG.md b/plugins/catalog-backend-module-azure/CHANGELOG.md index e96ca2d650..1706dc02bf 100644 --- a/plugins/catalog-backend-module-azure/CHANGELOG.md +++ b/plugins/catalog-backend-module-azure/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-catalog-backend-module-azure +## 0.1.43-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/config@1.2.0 + - @backstage/plugin-catalog-common@1.0.25 + ## 0.1.42 ### Patch Changes diff --git a/plugins/catalog-backend-module-azure/package.json b/plugins/catalog-backend-module-azure/package.json index 05b920bcb0..5fdd95140d 100644 --- a/plugins/catalog-backend-module-azure/package.json +++ b/plugins/catalog-backend-module-azure/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-azure", - "version": "0.1.42", + "version": "0.1.43-next.0", "description": "A Backstage catalog backend module that helps integrate towards Azure", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-backstage-openapi/CHANGELOG.md b/plugins/catalog-backend-module-backstage-openapi/CHANGELOG.md index 620ab36c40..afdd92803f 100644 --- a/plugins/catalog-backend-module-backstage-openapi/CHANGELOG.md +++ b/plugins/catalog-backend-module-backstage-openapi/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-catalog-backend-module-backstage-openapi +## 0.2.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/backend-openapi-utils@0.1.16-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.2.5 ### Patch Changes diff --git a/plugins/catalog-backend-module-backstage-openapi/package.json b/plugins/catalog-backend-module-backstage-openapi/package.json index de6c2a8410..6da2d92d5f 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.2.5", + "version": "0.2.6-next.0", "backstage": { "role": "backend-plugin-module", "pluginId": "catalog", diff --git a/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md b/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md index 920d2bc111..2c01eb8857 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.2.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.22-next.0 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-events-node@0.3.9-next.0 + ## 0.2.9 ### Patch Changes diff --git a/plugins/catalog-backend-module-bitbucket-cloud/package.json b/plugins/catalog-backend-module-bitbucket-cloud/package.json index 9faa941fd6..234bfea5c5 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/package.json +++ b/plugins/catalog-backend-module-bitbucket-cloud/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-bitbucket-cloud", - "version": "0.2.9", + "version": "0.2.10-next.0", "description": "A Backstage catalog backend module that helps integrate towards Bitbucket Cloud", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md b/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md index 857d9a33d9..7f47be269c 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.37-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.1.36 ### Patch Changes diff --git a/plugins/catalog-backend-module-bitbucket-server/package.json b/plugins/catalog-backend-module-bitbucket-server/package.json index 793a4213f2..45d8c5cd33 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.36", + "version": "0.1.37-next.0", "backstage": { "role": "backend-plugin-module", "pluginId": "catalog", diff --git a/plugins/catalog-backend-module-gcp/CHANGELOG.md b/plugins/catalog-backend-module-gcp/CHANGELOG.md index 779039f858..ca2d4412b2 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.24-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/plugin-kubernetes-common@0.8.1 + ## 0.1.23 ### Patch Changes diff --git a/plugins/catalog-backend-module-gcp/package.json b/plugins/catalog-backend-module-gcp/package.json index 7ebe7cbefc..442c7540e3 100644 --- a/plugins/catalog-backend-module-gcp/package.json +++ b/plugins/catalog-backend-module-gcp/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-gcp", - "version": "0.1.23", + "version": "0.1.24-next.0", "description": "A Backstage catalog backend module that helps integrate towards GCP", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-gerrit/CHANGELOG.md b/plugins/catalog-backend-module-gerrit/CHANGELOG.md index 159c9bb550..63dcfa9562 100644 --- a/plugins/catalog-backend-module-gerrit/CHANGELOG.md +++ b/plugins/catalog-backend-module-gerrit/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-catalog-backend-module-gerrit +## 0.1.40-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + ## 0.1.39 ### Patch Changes diff --git a/plugins/catalog-backend-module-gerrit/package.json b/plugins/catalog-backend-module-gerrit/package.json index 0732db4465..61f2ac8dfd 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.39", + "version": "0.1.40-next.0", "backstage": { "role": "backend-plugin-module", "pluginId": "catalog", diff --git a/plugins/catalog-backend-module-github-org/CHANGELOG.md b/plugins/catalog-backend-module-github-org/CHANGELOG.md index 424465d813..72c80a97cd 100644 --- a/plugins/catalog-backend-module-github-org/CHANGELOG.md +++ b/plugins/catalog-backend-module-github-org/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-catalog-backend-module-github-org +## 0.1.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/config@1.2.0 + - @backstage/plugin-catalog-backend-module-github@0.6.6-next.0 + - @backstage/plugin-events-node@0.3.9-next.0 + ## 0.1.17 ### Patch Changes diff --git a/plugins/catalog-backend-module-github-org/package.json b/plugins/catalog-backend-module-github-org/package.json index 3fdcc2fedf..9a363613de 100644 --- a/plugins/catalog-backend-module-github-org/package.json +++ b/plugins/catalog-backend-module-github-org/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-github-org", - "version": "0.1.17", + "version": "0.1.18-next.0", "description": "The github-org backend module for the catalog plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-github/CHANGELOG.md b/plugins/catalog-backend-module-github/CHANGELOG.md index 661712456b..12e2d70eb1 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.6.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-backend@1.24.1-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-events-node@0.3.9-next.0 + ## 0.6.5 ### Patch Changes diff --git a/plugins/catalog-backend-module-github/package.json b/plugins/catalog-backend-module-github/package.json index 50b838be1d..aa1f750aef 100644 --- a/plugins/catalog-backend-module-github/package.json +++ b/plugins/catalog-backend-module-github/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-github", - "version": "0.6.5", + "version": "0.6.6-next.0", "description": "A Backstage catalog backend module that helps integrate towards GitHub", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-gitlab-org/CHANGELOG.md b/plugins/catalog-backend-module-gitlab-org/CHANGELOG.md index b36bcb4d71..8d1c8871ae 100644 --- a/plugins/catalog-backend-module-gitlab-org/CHANGELOG.md +++ b/plugins/catalog-backend-module-gitlab-org/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-catalog-backend-module-gitlab-org +## 0.0.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-catalog-backend-module-gitlab@0.3.22-next.0 + - @backstage/plugin-events-node@0.3.9-next.0 + ## 0.0.5 ### Patch Changes diff --git a/plugins/catalog-backend-module-gitlab-org/package.json b/plugins/catalog-backend-module-gitlab-org/package.json index 9c4c1f725f..16c492d849 100644 --- a/plugins/catalog-backend-module-gitlab-org/package.json +++ b/plugins/catalog-backend-module-gitlab-org/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-gitlab-org", - "version": "0.0.5", + "version": "0.0.6-next.0", "description": "The gitlab-org backend module for the catalog plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-gitlab/CHANGELOG.md b/plugins/catalog-backend-module-gitlab/CHANGELOG.md index 97ed683942..c4e8f25903 100644 --- a/plugins/catalog-backend-module-gitlab/CHANGELOG.md +++ b/plugins/catalog-backend-module-gitlab/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-catalog-backend-module-gitlab +## 0.3.22-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-events-node@0.3.9-next.0 + ## 0.3.21 ### Patch Changes diff --git a/plugins/catalog-backend-module-gitlab/package.json b/plugins/catalog-backend-module-gitlab/package.json index fa21798a62..ad5b8e88bd 100644 --- a/plugins/catalog-backend-module-gitlab/package.json +++ b/plugins/catalog-backend-module-gitlab/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-gitlab", - "version": "0.3.21", + "version": "0.3.22-next.0", "description": "A Backstage catalog backend module that helps integrate towards GitLab", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md b/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md index 0d04145063..c2b3835940 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md +++ b/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-catalog-backend-module-incremental-ingestion +## 0.4.28-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-backend@1.24.1-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-events-node@0.3.9-next.0 + - @backstage/plugin-permission-common@0.8.0 + ## 0.4.27 ### Patch Changes diff --git a/plugins/catalog-backend-module-incremental-ingestion/package.json b/plugins/catalog-backend-module-incremental-ingestion/package.json index 0180f36d03..cabacc7bd6 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/package.json +++ b/plugins/catalog-backend-module-incremental-ingestion/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-incremental-ingestion", - "version": "0.4.27", + "version": "0.4.28-next.0", "description": "An entity provider for streaming large asset sources into the catalog", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-ldap/CHANGELOG.md b/plugins/catalog-backend-module-ldap/CHANGELOG.md index 9168ce0991..1253404d2d 100644 --- a/plugins/catalog-backend-module-ldap/CHANGELOG.md +++ b/plugins/catalog-backend-module-ldap/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-catalog-backend-module-ldap +## 0.7.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.25 + ## 0.7.0 ### Minor Changes diff --git a/plugins/catalog-backend-module-ldap/package.json b/plugins/catalog-backend-module-ldap/package.json index 62b3328de7..e5f67d59c6 100644 --- a/plugins/catalog-backend-module-ldap/package.json +++ b/plugins/catalog-backend-module-ldap/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-ldap", - "version": "0.7.0", + "version": "0.7.1-next.0", "description": "A Backstage catalog backend module that helps integrate towards LDAP", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-logs/CHANGELOG.md b/plugins/catalog-backend-module-logs/CHANGELOG.md index 2712f4a134..83053dcf6b 100644 --- a/plugins/catalog-backend-module-logs/CHANGELOG.md +++ b/plugins/catalog-backend-module-logs/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-catalog-backend-module-logs +## 0.0.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.24.1-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-events-node@0.3.9-next.0 + ## 0.0.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-logs/package.json b/plugins/catalog-backend-module-logs/package.json index 560b93737e..0c4a78dfa4 100644 --- a/plugins/catalog-backend-module-logs/package.json +++ b/plugins/catalog-backend-module-logs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-logs", - "version": "0.0.1", + "version": "0.0.2-next.0", "description": "A module that subscribes to catalog releated events and logs them.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-msgraph/CHANGELOG.md b/plugins/catalog-backend-module-msgraph/CHANGELOG.md index a33bea94b8..d9b8da87d2 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.31-next.0 + +### Patch Changes + +- 58dff4d: Added option to ingest groups based on their group membership in Azure Entra ID +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/plugin-catalog-common@1.0.25 + ## 0.5.30 ### Patch Changes diff --git a/plugins/catalog-backend-module-msgraph/package.json b/plugins/catalog-backend-module-msgraph/package.json index 3f5fa722a8..087d4c4a82 100644 --- a/plugins/catalog-backend-module-msgraph/package.json +++ b/plugins/catalog-backend-module-msgraph/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-msgraph", - "version": "0.5.30", + "version": "0.5.31-next.0", "description": "A Backstage catalog backend module that helps integrate towards Microsoft Graph", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-openapi/CHANGELOG.md b/plugins/catalog-backend-module-openapi/CHANGELOG.md index 6cc947ee17..46d8c1319b 100644 --- a/plugins/catalog-backend-module-openapi/CHANGELOG.md +++ b/plugins/catalog-backend-module-openapi/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-catalog-backend-module-openapi +## 0.1.41-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-backend@1.24.1-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.25 + ## 0.1.40 ### Patch Changes diff --git a/plugins/catalog-backend-module-openapi/package.json b/plugins/catalog-backend-module-openapi/package.json index 2dbe6612ac..1cd250d884 100644 --- a/plugins/catalog-backend-module-openapi/package.json +++ b/plugins/catalog-backend-module-openapi/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-openapi", - "version": "0.1.40", + "version": "0.1.41-next.0", "description": "A Backstage catalog backend module that helps with OpenAPI specifications", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-puppetdb/CHANGELOG.md b/plugins/catalog-backend-module-puppetdb/CHANGELOG.md index cb4cd9664b..d85ad0ecf2 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.29-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 0.1.28 ### Patch Changes diff --git a/plugins/catalog-backend-module-puppetdb/package.json b/plugins/catalog-backend-module-puppetdb/package.json index cf2a739380..dadba558a5 100644 --- a/plugins/catalog-backend-module-puppetdb/package.json +++ b/plugins/catalog-backend-module-puppetdb/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-puppetdb", - "version": "0.1.28", + "version": "0.1.29-next.0", "description": "A Backstage catalog backend module that helps integrate towards PuppetDB", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md b/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md index 87299358b7..1ec7c01c6a 100644 --- a/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md +++ b/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-catalog-backend-module-scaffolder-entity-model +## 0.1.21-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-scaffolder-common@1.5.4 + ## 0.1.20 ### 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 3aaa768f76..09dfa63a91 100644 --- a/plugins/catalog-backend-module-scaffolder-entity-model/package.json +++ b/plugins/catalog-backend-module-scaffolder-entity-model/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-scaffolder-entity-model", - "version": "0.1.20", + "version": "0.1.21-next.0", "description": "Adds support for the scaffolder specific entity model (e.g. the Template kind) to the catalog backend plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-unprocessed/CHANGELOG.md b/plugins/catalog-backend-module-unprocessed/CHANGELOG.md index a7d74143a1..2abd4e32a3 100644 --- a/plugins/catalog-backend-module-unprocessed/CHANGELOG.md +++ b/plugins/catalog-backend-module-unprocessed/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-catalog-backend-module-unprocessed +## 0.4.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-catalog-unprocessed-entities-common@0.0.3 + - @backstage/plugin-permission-common@0.8.0 + ## 0.4.9 ### Patch Changes diff --git a/plugins/catalog-backend-module-unprocessed/package.json b/plugins/catalog-backend-module-unprocessed/package.json index 6f1f4bb6bc..b01fddef04 100644 --- a/plugins/catalog-backend-module-unprocessed/package.json +++ b/plugins/catalog-backend-module-unprocessed/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-unprocessed", - "version": "0.4.9", + "version": "0.4.10-next.0", "description": "Backstage Catalog module to view unprocessed entities", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend/CHANGELOG.md b/plugins/catalog-backend/CHANGELOG.md index 8f99ab1f4c..796611fa90 100644 --- a/plugins/catalog-backend/CHANGELOG.md +++ b/plugins/catalog-backend/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/plugin-catalog-backend +## 1.24.1-next.0 + +### Patch Changes + +- a629fb2: Added setAllowedLocationTypes while introducing a new extension point called CatalogLocationsExtensionPoint +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-openapi-utils@0.1.16-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-events-node@0.3.9-next.0 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.1-next.0 + - @backstage/plugin-search-backend-module-catalog@0.1.29-next.0 + ## 1.24.0 ### Minor Changes diff --git a/plugins/catalog-backend/package.json b/plugins/catalog-backend/package.json index 19d40bd34c..0c1983d1e2 100644 --- a/plugins/catalog-backend/package.json +++ b/plugins/catalog-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend", - "version": "1.24.0", + "version": "1.24.1-next.0", "description": "The Backstage backend plugin that provides the Backstage catalog", "backstage": { "role": "backend-plugin", diff --git a/plugins/catalog-graph/CHANGELOG.md b/plugins/catalog-graph/CHANGELOG.md index 332ea17dd0..5995074b53 100644 --- a/plugins/catalog-graph/CHANGELOG.md +++ b/plugins/catalog-graph/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-catalog-graph +## 0.4.8-next.0 + +### Patch Changes + +- fba7537: Memoize entity graph nodes when applying an `entityFilter` to prevent repeated redraws +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-compat-api@0.2.8-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/types@1.1.1 + ## 0.4.7 ### Patch Changes diff --git a/plugins/catalog-graph/package.json b/plugins/catalog-graph/package.json index 1e7c376436..51ed923a01 100644 --- a/plugins/catalog-graph/package.json +++ b/plugins/catalog-graph/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-graph", - "version": "0.4.7", + "version": "0.4.8-next.0", "backstage": { "role": "frontend-plugin", "pluginId": "catalog-graph", diff --git a/plugins/catalog-import/CHANGELOG.md b/plugins/catalog-import/CHANGELOG.md index 29ec3631b4..484676f245 100644 --- a/plugins/catalog-import/CHANGELOG.md +++ b/plugins/catalog-import/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-catalog-import +## 0.12.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-compat-api@0.2.8-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/plugin-catalog-common@1.0.25 + ## 0.12.1 ### Patch Changes diff --git a/plugins/catalog-import/package.json b/plugins/catalog-import/package.json index c3babc09a3..dfc07ddb43 100644 --- a/plugins/catalog-import/package.json +++ b/plugins/catalog-import/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-import", - "version": "0.12.1", + "version": "0.12.2-next.0", "description": "A Backstage plugin the helps you import entities into your catalog", "backstage": { "role": "frontend-plugin", diff --git a/plugins/catalog-node/CHANGELOG.md b/plugins/catalog-node/CHANGELOG.md index 74982e481f..3d1dbe07ba 100644 --- a/plugins/catalog-node/CHANGELOG.md +++ b/plugins/catalog-node/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-catalog-node +## 1.12.5-next.0 + +### Patch Changes + +- a629fb2: Added setAllowedLocationTypes while introducing a new extension point called CatalogLocationsExtensionPoint +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.1-next.0 + ## 1.12.4 ### Patch Changes diff --git a/plugins/catalog-node/package.json b/plugins/catalog-node/package.json index ccd83cd129..04a942f7b3 100644 --- a/plugins/catalog-node/package.json +++ b/plugins/catalog-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-node", - "version": "1.12.4", + "version": "1.12.5-next.0", "description": "The plugin-catalog-node module for @backstage/plugin-catalog-backend", "backstage": { "role": "node-library", diff --git a/plugins/catalog-react/CHANGELOG.md b/plugins/catalog-react/CHANGELOG.md index 38402e8824..982d3db031 100644 --- a/plugins/catalog-react/CHANGELOG.md +++ b/plugins/catalog-react/CHANGELOG.md @@ -1,5 +1,26 @@ # @backstage/plugin-catalog-react +## 1.12.3-next.0 + +### Patch Changes + +- 31bfc44: Updated alpha definitions of extension data references. +- 9b89b82: Internal refactor to remove unnecessary `routable` prop in the implementation of the `createEntityContentExtension` alpha export. +- bebd569: Fix extra divider displayed on user list picker component +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-react@0.4.24 + ## 1.12.2 ### Patch Changes diff --git a/plugins/catalog-react/package.json b/plugins/catalog-react/package.json index c6a725ecb6..dc5a80d4b7 100644 --- a/plugins/catalog-react/package.json +++ b/plugins/catalog-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-react", - "version": "1.12.2", + "version": "1.12.3-next.0", "description": "A frontend library that helps other Backstage plugins interact with the catalog", "backstage": { "role": "web-library", diff --git a/plugins/catalog-unprocessed-entities/CHANGELOG.md b/plugins/catalog-unprocessed-entities/CHANGELOG.md index e3fd1b6b76..2c2eb03f5e 100644 --- a/plugins/catalog-unprocessed-entities/CHANGELOG.md +++ b/plugins/catalog-unprocessed-entities/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-catalog-unprocessed-entities +## 0.2.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.10-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + ## 0.2.6 ### Patch Changes diff --git a/plugins/catalog-unprocessed-entities/package.json b/plugins/catalog-unprocessed-entities/package.json index 872ce7b11b..8ce8c8b0d3 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.2.6", + "version": "0.2.7-next.0", "backstage": { "role": "frontend-plugin", "pluginId": "catalog-unprocessed-entities", diff --git a/plugins/catalog/CHANGELOG.md b/plugins/catalog/CHANGELOG.md index 2667fdf638..e0b947b965 100644 --- a/plugins/catalog/CHANGELOG.md +++ b/plugins/catalog/CHANGELOG.md @@ -1,5 +1,26 @@ # @backstage/plugin-catalog +## 1.21.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/plugin-search-react@1.7.14-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-compat-api@0.2.8-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/plugin-scaffolder-common@1.5.4 + - @backstage/plugin-search-common@1.2.13 + ## 1.21.1 ### Patch Changes diff --git a/plugins/catalog/package.json b/plugins/catalog/package.json index fc49a8c36b..64f6b0d201 100644 --- a/plugins/catalog/package.json +++ b/plugins/catalog/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog", - "version": "1.21.1", + "version": "1.21.2-next.0", "description": "The Backstage plugin for browsing the Backstage catalog", "backstage": { "role": "frontend-plugin", diff --git a/plugins/config-schema/CHANGELOG.md b/plugins/config-schema/CHANGELOG.md index 2344473925..c11499f589 100644 --- a/plugins/config-schema/CHANGELOG.md +++ b/plugins/config-schema/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-config-schema +## 0.1.58-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + ## 0.1.57 ### Patch Changes diff --git a/plugins/config-schema/package.json b/plugins/config-schema/package.json index 6f91094e5f..ad98b78b98 100644 --- a/plugins/config-schema/package.json +++ b/plugins/config-schema/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-config-schema", - "version": "0.1.57", + "version": "0.1.58-next.0", "description": "A Backstage plugin that lets you browse the configuration schema of your app", "backstage": { "role": "frontend-plugin", diff --git a/plugins/devtools-backend/CHANGELOG.md b/plugins/devtools-backend/CHANGELOG.md index f027384637..d415b1bf65 100644 --- a/plugins/devtools-backend/CHANGELOG.md +++ b/plugins/devtools-backend/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-devtools-backend +## 0.3.9-next.0 + +### Patch Changes + +- 32a38e1: Removed unused code for lockfile analysis. +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/config-loader@1.8.2-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/cli-common@0.1.14 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-devtools-common@0.1.11 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.1-next.0 + ## 0.3.8 ### Patch Changes diff --git a/plugins/devtools-backend/package.json b/plugins/devtools-backend/package.json index ce5e143f24..1fe3330698 100644 --- a/plugins/devtools-backend/package.json +++ b/plugins/devtools-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-devtools-backend", - "version": "0.3.8", + "version": "0.3.9-next.0", "backstage": { "role": "backend-plugin", "pluginId": "devtools", diff --git a/plugins/devtools/CHANGELOG.md b/plugins/devtools/CHANGELOG.md index 3403b7f2fa..b7db4a95bc 100644 --- a/plugins/devtools/CHANGELOG.md +++ b/plugins/devtools/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-devtools +## 0.1.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-compat-api@0.2.8-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/plugin-devtools-common@0.1.11 + - @backstage/plugin-permission-react@0.4.24 + ## 0.1.16 ### Patch Changes diff --git a/plugins/devtools/package.json b/plugins/devtools/package.json index 83d2a6b352..2827110d4a 100644 --- a/plugins/devtools/package.json +++ b/plugins/devtools/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-devtools", - "version": "0.1.16", + "version": "0.1.17-next.0", "backstage": { "role": "frontend-plugin", "pluginId": "devtools", diff --git a/plugins/events-backend-module-aws-sqs/CHANGELOG.md b/plugins/events-backend-module-aws-sqs/CHANGELOG.md index e27fcefa6e..5e954c38ca 100644 --- a/plugins/events-backend-module-aws-sqs/CHANGELOG.md +++ b/plugins/events-backend-module-aws-sqs/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-events-backend-module-aws-sqs +## 0.3.9-next.0 + +### Patch Changes + +- ba8571e: Setup user agent header for AWS sdk clients, this enables users to better track API calls made from Backstage to AWS APIs through things like CloudTrail. +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + - @backstage/plugin-events-node@0.3.9-next.0 + ## 0.3.8 ### Patch Changes diff --git a/plugins/events-backend-module-aws-sqs/package.json b/plugins/events-backend-module-aws-sqs/package.json index 983e15567b..0135594bd6 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.3.8", + "version": "0.3.9-next.0", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-module-azure/CHANGELOG.md b/plugins/events-backend-module-azure/CHANGELOG.md index 225ee30beb..27060d63e4 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.2.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-events-node@0.3.9-next.0 + ## 0.2.8 ### Patch Changes diff --git a/plugins/events-backend-module-azure/package.json b/plugins/events-backend-module-azure/package.json index 49c9b9439f..eacae60bc2 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.2.8", + "version": "0.2.9-next.0", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-module-bitbucket-cloud/CHANGELOG.md b/plugins/events-backend-module-bitbucket-cloud/CHANGELOG.md index 4676feabbd..a411dcecaa 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.2.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-events-node@0.3.9-next.0 + ## 0.2.8 ### Patch Changes diff --git a/plugins/events-backend-module-bitbucket-cloud/package.json b/plugins/events-backend-module-bitbucket-cloud/package.json index 6fd443a3b1..084b3cb512 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.2.8", + "version": "0.2.9-next.0", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-module-gerrit/CHANGELOG.md b/plugins/events-backend-module-gerrit/CHANGELOG.md index eddce5d6c5..3cc3f4f3bf 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.2.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-events-node@0.3.9-next.0 + ## 0.2.8 ### Patch Changes diff --git a/plugins/events-backend-module-gerrit/package.json b/plugins/events-backend-module-gerrit/package.json index 7d870063df..99a1cba796 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.2.8", + "version": "0.2.9-next.0", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-module-github/CHANGELOG.md b/plugins/events-backend-module-github/CHANGELOG.md index 4597583ea8..3ba0e5de31 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.2.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/plugin-events-node@0.3.9-next.0 + ## 0.2.8 ### Patch Changes diff --git a/plugins/events-backend-module-github/package.json b/plugins/events-backend-module-github/package.json index 955793ee6d..bad39f8080 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.2.8", + "version": "0.2.9-next.0", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-module-gitlab/CHANGELOG.md b/plugins/events-backend-module-gitlab/CHANGELOG.md index f22f90405e..39fd274342 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.2.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/plugin-events-node@0.3.9-next.0 + ## 0.2.8 ### Patch Changes diff --git a/plugins/events-backend-module-gitlab/package.json b/plugins/events-backend-module-gitlab/package.json index c97a9e2f02..f2d76a5193 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.2.8", + "version": "0.2.9-next.0", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-test-utils/CHANGELOG.md b/plugins/events-backend-test-utils/CHANGELOG.md index 4fcbcfc172..be1e0f023c 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.33-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.3.9-next.0 + ## 0.1.32 ### Patch Changes diff --git a/plugins/events-backend-test-utils/package.json b/plugins/events-backend-test-utils/package.json index 09a36a7a1f..f6914c81c5 100644 --- a/plugins/events-backend-test-utils/package.json +++ b/plugins/events-backend-test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-test-utils", - "version": "0.1.32", + "version": "0.1.33-next.0", "description": "The plugin-events-backend-test-utils for @backstage/plugin-events-node", "backstage": { "role": "node-library", diff --git a/plugins/events-backend/CHANGELOG.md b/plugins/events-backend/CHANGELOG.md index 4840d9a623..6a6a17c13f 100644 --- a/plugins/events-backend/CHANGELOG.md +++ b/plugins/events-backend/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-events-backend +## 0.3.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/plugin-events-node@0.3.9-next.0 + ## 0.3.9 ### Patch Changes diff --git a/plugins/events-backend/package.json b/plugins/events-backend/package.json index f9f2a4b781..accb240c22 100644 --- a/plugins/events-backend/package.json +++ b/plugins/events-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend", - "version": "0.3.9", + "version": "0.3.10-next.0", "backstage": { "role": "backend-plugin", "pluginId": "events", diff --git a/plugins/events-node/CHANGELOG.md b/plugins/events-node/CHANGELOG.md index d5b1c98372..a3dfd8682d 100644 --- a/plugins/events-node/CHANGELOG.md +++ b/plugins/events-node/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-events-node +## 0.3.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + ## 0.3.8 ### Patch Changes diff --git a/plugins/events-node/package.json b/plugins/events-node/package.json index 965f317357..7387294d24 100644 --- a/plugins/events-node/package.json +++ b/plugins/events-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-node", - "version": "0.3.8", + "version": "0.3.9-next.0", "description": "The plugin-events-node module for @backstage/plugin-events-backend", "backstage": { "role": "node-library", diff --git a/plugins/example-todo-list-backend/CHANGELOG.md b/plugins/example-todo-list-backend/CHANGELOG.md index dd1a2087dc..3d3c9fd1bb 100644 --- a/plugins/example-todo-list-backend/CHANGELOG.md +++ b/plugins/example-todo-list-backend/CHANGELOG.md @@ -1,5 +1,15 @@ # @internal/plugin-todo-list-backend +## 1.0.30-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.18-next.0 + ## 1.0.29 ### Patch Changes diff --git a/plugins/example-todo-list-backend/package.json b/plugins/example-todo-list-backend/package.json index 0ca987d30b..1ea02728de 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.29", + "version": "1.0.30-next.0", "backstage": { "role": "backend-plugin", "pluginId": "todo-list", diff --git a/plugins/example-todo-list/CHANGELOG.md b/plugins/example-todo-list/CHANGELOG.md index e55f882b0a..51e2b93ef9 100644 --- a/plugins/example-todo-list/CHANGELOG.md +++ b/plugins/example-todo-list/CHANGELOG.md @@ -1,5 +1,13 @@ # @internal/plugin-todo-list +## 1.0.30-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + ## 1.0.29 ### Patch Changes diff --git a/plugins/example-todo-list/package.json b/plugins/example-todo-list/package.json index c8c0a90312..d950d8c406 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.29", + "version": "1.0.30-next.0", "backstage": { "role": "frontend-plugin", "pluginId": "todo-list", diff --git a/plugins/home-react/CHANGELOG.md b/plugins/home-react/CHANGELOG.md index c4db30307f..d810195e7f 100644 --- a/plugins/home-react/CHANGELOG.md +++ b/plugins/home-react/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-home-react +## 0.1.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + ## 0.1.15 ### Patch Changes diff --git a/plugins/home-react/package.json b/plugins/home-react/package.json index 433a91b475..00b0f29fca 100644 --- a/plugins/home-react/package.json +++ b/plugins/home-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-home-react", - "version": "0.1.15", + "version": "0.1.16-next.0", "description": "A Backstage plugin that contains react components helps you build a home page", "backstage": { "role": "web-library", diff --git a/plugins/home/CHANGELOG.md b/plugins/home/CHANGELOG.md index eb49e3217b..75c786c4de 100644 --- a/plugins/home/CHANGELOG.md +++ b/plugins/home/CHANGELOG.md @@ -1,5 +1,24 @@ # @backstage/plugin-home +## 0.7.8-next.0 + +### Patch Changes + +- 31bfc44: Updated alpha definitions of extension data references. +- fdcc059: Fixed a bug on the WelcomeTitle component where the welcome message wasn't correct when the language was set to Spanish +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-app-api@1.14.1-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-compat-api@0.2.8-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + - @backstage/plugin-home-react@0.1.16-next.0 + ## 0.7.7 ### Patch Changes diff --git a/plugins/home/package.json b/plugins/home/package.json index 189aeec2ac..d2f0c43a11 100644 --- a/plugins/home/package.json +++ b/plugins/home/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-home", - "version": "0.7.7", + "version": "0.7.8-next.0", "description": "A Backstage plugin that helps you build a home page", "backstage": { "role": "frontend-plugin", diff --git a/plugins/kubernetes-backend/CHANGELOG.md b/plugins/kubernetes-backend/CHANGELOG.md index 6a41d014f5..d749d8579e 100644 --- a/plugins/kubernetes-backend/CHANGELOG.md +++ b/plugins/kubernetes-backend/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-kubernetes-backend +## 0.18.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration-aws-node@0.1.12 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-kubernetes-common@0.8.1 + - @backstage/plugin-kubernetes-node@0.1.17-next.0 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.1-next.0 + ## 0.18.3 ### Patch Changes diff --git a/plugins/kubernetes-backend/package.json b/plugins/kubernetes-backend/package.json index 0e439ecd91..eb135d4f0f 100644 --- a/plugins/kubernetes-backend/package.json +++ b/plugins/kubernetes-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes-backend", - "version": "0.18.3", + "version": "0.18.4-next.0", "description": "A Backstage backend plugin that integrates towards Kubernetes", "backstage": { "role": "backend-plugin", diff --git a/plugins/kubernetes-cluster/CHANGELOG.md b/plugins/kubernetes-cluster/CHANGELOG.md index a4b12a0556..cd5b6772de 100644 --- a/plugins/kubernetes-cluster/CHANGELOG.md +++ b/plugins/kubernetes-cluster/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-kubernetes-cluster +## 0.0.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/plugin-kubernetes-common@0.8.1 + - @backstage/plugin-kubernetes-react@0.4.2-next.0 + ## 0.0.13 ### Patch Changes diff --git a/plugins/kubernetes-cluster/package.json b/plugins/kubernetes-cluster/package.json index af63bf4102..5549c8dcc5 100644 --- a/plugins/kubernetes-cluster/package.json +++ b/plugins/kubernetes-cluster/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes-cluster", - "version": "0.0.13", + "version": "0.0.14-next.0", "description": "A Backstage plugin that shows details of Kubernetes clusters", "backstage": { "role": "frontend-plugin", diff --git a/plugins/kubernetes-node/CHANGELOG.md b/plugins/kubernetes-node/CHANGELOG.md index 608fe97cd2..58c458da9c 100644 --- a/plugins/kubernetes-node/CHANGELOG.md +++ b/plugins/kubernetes-node/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-kubernetes-node +## 0.1.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/types@1.1.1 + - @backstage/plugin-kubernetes-common@0.8.1 + ## 0.1.16 ### Patch Changes diff --git a/plugins/kubernetes-node/package.json b/plugins/kubernetes-node/package.json index 798978b5d2..6d1d6d73f8 100644 --- a/plugins/kubernetes-node/package.json +++ b/plugins/kubernetes-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes-node", - "version": "0.1.16", + "version": "0.1.17-next.0", "description": "Node.js library for the kubernetes plugin", "backstage": { "role": "node-library", diff --git a/plugins/kubernetes-react/CHANGELOG.md b/plugins/kubernetes-react/CHANGELOG.md index 0fd0cfd07e..c84b5c01e3 100644 --- a/plugins/kubernetes-react/CHANGELOG.md +++ b/plugins/kubernetes-react/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-kubernetes-react +## 0.4.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.10-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-kubernetes-common@0.8.1 + ## 0.4.1 ### Patch Changes diff --git a/plugins/kubernetes-react/package.json b/plugins/kubernetes-react/package.json index 42ef4f7913..2f4ddd7415 100644 --- a/plugins/kubernetes-react/package.json +++ b/plugins/kubernetes-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes-react", - "version": "0.4.1", + "version": "0.4.2-next.0", "description": "Web library for the kubernetes-react plugin", "backstage": { "role": "web-library", diff --git a/plugins/kubernetes/CHANGELOG.md b/plugins/kubernetes/CHANGELOG.md index fcb80b7b26..26fbfffbdb 100644 --- a/plugins/kubernetes/CHANGELOG.md +++ b/plugins/kubernetes/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-kubernetes +## 0.11.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/plugin-kubernetes-common@0.8.1 + - @backstage/plugin-kubernetes-react@0.4.2-next.0 + ## 0.11.12 ### Patch Changes diff --git a/plugins/kubernetes/package.json b/plugins/kubernetes/package.json index 1ab92f5b3c..5469ff5724 100644 --- a/plugins/kubernetes/package.json +++ b/plugins/kubernetes/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes", - "version": "0.11.12", + "version": "0.11.13-next.0", "description": "A Backstage plugin that integrates towards Kubernetes", "backstage": { "role": "frontend-plugin", diff --git a/plugins/notifications-backend-module-email/CHANGELOG.md b/plugins/notifications-backend-module-email/CHANGELOG.md index 4bfbfbd05d..f13ba48616 100644 --- a/plugins/notifications-backend-module-email/CHANGELOG.md +++ b/plugins/notifications-backend-module-email/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-notifications-backend-module-email +## 0.1.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/integration-aws-node@0.1.12 + - @backstage/types@1.1.1 + - @backstage/plugin-notifications-common@0.0.5 + - @backstage/plugin-notifications-node@0.2.4-next.0 + ## 0.1.3 ### Patch Changes diff --git a/plugins/notifications-backend-module-email/package.json b/plugins/notifications-backend-module-email/package.json index b7107a4c6b..c024e6ad50 100644 --- a/plugins/notifications-backend-module-email/package.json +++ b/plugins/notifications-backend-module-email/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-notifications-backend-module-email", - "version": "0.1.3", + "version": "0.1.4-next.0", "description": "The email backend module for the notifications plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/notifications-backend/CHANGELOG.md b/plugins/notifications-backend/CHANGELOG.md index b4fe307f15..ef654d213c 100644 --- a/plugins/notifications-backend/CHANGELOG.md +++ b/plugins/notifications-backend/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-notifications-backend +## 0.3.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-events-node@0.3.9-next.0 + - @backstage/plugin-notifications-common@0.0.5 + - @backstage/plugin-notifications-node@0.2.4-next.0 + - @backstage/plugin-signals-node@0.1.9-next.0 + ## 0.3.3 ### Patch Changes diff --git a/plugins/notifications-backend/package.json b/plugins/notifications-backend/package.json index abd0a1bbfe..b59ae301f2 100644 --- a/plugins/notifications-backend/package.json +++ b/plugins/notifications-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-notifications-backend", - "version": "0.3.3", + "version": "0.3.4-next.0", "backstage": { "role": "backend-plugin", "pluginId": "notifications", diff --git a/plugins/notifications-node/CHANGELOG.md b/plugins/notifications-node/CHANGELOG.md index 764ee3affb..4344467104 100644 --- a/plugins/notifications-node/CHANGELOG.md +++ b/plugins/notifications-node/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-notifications-node +## 0.2.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/plugin-notifications-common@0.0.5 + - @backstage/plugin-signals-node@0.1.9-next.0 + ## 0.2.3 ### Patch Changes diff --git a/plugins/notifications-node/package.json b/plugins/notifications-node/package.json index 04564da21e..b71e5d954f 100644 --- a/plugins/notifications-node/package.json +++ b/plugins/notifications-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-notifications-node", - "version": "0.2.3", + "version": "0.2.4-next.0", "description": "Node.js library for the notifications plugin", "backstage": { "role": "node-library", diff --git a/plugins/notifications/CHANGELOG.md b/plugins/notifications/CHANGELOG.md index 263bd9ba70..42c55615b2 100644 --- a/plugins/notifications/CHANGELOG.md +++ b/plugins/notifications/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-notifications +## 0.2.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/plugin-notifications-common@0.0.5 + - @backstage/plugin-signals-react@0.0.4 + ## 0.2.3 ### Patch Changes diff --git a/plugins/notifications/package.json b/plugins/notifications/package.json index 1575c48c5e..5dbfd83255 100644 --- a/plugins/notifications/package.json +++ b/plugins/notifications/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-notifications", - "version": "0.2.3", + "version": "0.2.4-next.0", "backstage": { "role": "frontend-plugin", "pluginId": "notifications", diff --git a/plugins/org-react/CHANGELOG.md b/plugins/org-react/CHANGELOG.md index d6e117d579..9d0c722d80 100644 --- a/plugins/org-react/CHANGELOG.md +++ b/plugins/org-react/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-org-react +## 0.1.27-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + ## 0.1.26 ### Patch Changes diff --git a/plugins/org-react/package.json b/plugins/org-react/package.json index 9405b38b59..65d600b96f 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.26", + "version": "0.1.27-next.0", "backstage": { "role": "web-library", "pluginId": "org", diff --git a/plugins/org/CHANGELOG.md b/plugins/org/CHANGELOG.md index 6d1fb352f8..130a62d56d 100644 --- a/plugins/org/CHANGELOG.md +++ b/plugins/org/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-org +## 0.6.28-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/core-compat-api@0.2.8-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/plugin-catalog-common@1.0.25 + ## 0.6.27 ### Patch Changes diff --git a/plugins/org/package.json b/plugins/org/package.json index 2530ca2ea1..a3ed608aeb 100644 --- a/plugins/org/package.json +++ b/plugins/org/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-org", - "version": "0.6.27", + "version": "0.6.28-next.0", "description": "A Backstage plugin that helps you create entity pages for your organization", "backstage": { "role": "frontend-plugin", diff --git a/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md b/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md index e06db25a91..c2e00cf839 100644 --- a/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md +++ b/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-permission-backend-module-allow-all-policy +## 0.1.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.1-next.0 + ## 0.1.19 ### 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 27303483f7..85becb2b60 100644 --- a/plugins/permission-backend-module-policy-allow-all/package.json +++ b/plugins/permission-backend-module-policy-allow-all/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-permission-backend-module-allow-all-policy", - "version": "0.1.19", + "version": "0.1.20-next.0", "description": "Allow all policy backend module for the permission plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/permission-backend/CHANGELOG.md b/plugins/permission-backend/CHANGELOG.md index e5a826f67a..c5e9b7675f 100644 --- a/plugins/permission-backend/CHANGELOG.md +++ b/plugins/permission-backend/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-permission-backend +## 0.5.47-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.1-next.0 + ## 0.5.46 ### Patch Changes diff --git a/plugins/permission-backend/package.json b/plugins/permission-backend/package.json index 95647ba82b..11ad9538be 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.46", + "version": "0.5.47-next.0", "backstage": { "role": "backend-plugin", "pluginId": "permission", diff --git a/plugins/permission-node/CHANGELOG.md b/plugins/permission-node/CHANGELOG.md index 326dfb99d3..31d2f9145e 100644 --- a/plugins/permission-node/CHANGELOG.md +++ b/plugins/permission-node/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-permission-node +## 0.8.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-permission-common@0.8.0 + ## 0.8.0 ### Minor Changes diff --git a/plugins/permission-node/package.json b/plugins/permission-node/package.json index 4bbf4d5faf..630391f373 100644 --- a/plugins/permission-node/package.json +++ b/plugins/permission-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-permission-node", - "version": "0.8.0", + "version": "0.8.1-next.0", "description": "Common permission and authorization utilities for backend plugins", "backstage": { "role": "node-library", diff --git a/plugins/proxy-backend/CHANGELOG.md b/plugins/proxy-backend/CHANGELOG.md index 30cacb1d02..d906b17327 100644 --- a/plugins/proxy-backend/CHANGELOG.md +++ b/plugins/proxy-backend/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-proxy-backend +## 0.5.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + ## 0.5.3 ### Patch Changes diff --git a/plugins/proxy-backend/package.json b/plugins/proxy-backend/package.json index 2e7bd08550..ec3594f985 100644 --- a/plugins/proxy-backend/package.json +++ b/plugins/proxy-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-proxy-backend", - "version": "0.5.3", + "version": "0.5.4-next.0", "description": "A Backstage backend plugin that helps you set up proxy endpoints in the backend", "backstage": { "role": "backend-plugin", diff --git a/plugins/scaffolder-backend-module-azure/CHANGELOG.md b/plugins/scaffolder-backend-module-azure/CHANGELOG.md index e386b5d9b8..bb5b2644ae 100644 --- a/plugins/scaffolder-backend-module-azure/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-azure/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-scaffolder-backend-module-azure +## 0.1.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + ## 0.1.14 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-azure/package.json b/plugins/scaffolder-backend-module-azure/package.json index 205beae578..c2b7a39e0c 100644 --- a/plugins/scaffolder-backend-module-azure/package.json +++ b/plugins/scaffolder-backend-module-azure/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-azure", - "version": "0.1.14", + "version": "0.1.15-next.0", "description": "The azure module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/CHANGELOG.md b/plugins/scaffolder-backend-module-bitbucket-cloud/CHANGELOG.md index c8c79a302b..04236c2a4b 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-scaffolder-backend-module-bitbucket-cloud +## 0.1.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-bitbucket-cloud-common@0.2.22-next.0 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + ## 0.1.12 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/package.json b/plugins/scaffolder-backend-module-bitbucket-cloud/package.json index 67f275462b..39080241a0 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/package.json +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-bitbucket-cloud", - "version": "0.1.12", + "version": "0.1.13-next.0", "description": "The Bitbucket Cloud module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-bitbucket-server/CHANGELOG.md b/plugins/scaffolder-backend-module-bitbucket-server/CHANGELOG.md index 5d2a0754cd..93801a3012 100644 --- a/plugins/scaffolder-backend-module-bitbucket-server/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-bitbucket-server/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-scaffolder-backend-module-bitbucket-server +## 0.1.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + ## 0.1.12 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-bitbucket-server/package.json b/plugins/scaffolder-backend-module-bitbucket-server/package.json index a33bf90040..b995ef57da 100644 --- a/plugins/scaffolder-backend-module-bitbucket-server/package.json +++ b/plugins/scaffolder-backend-module-bitbucket-server/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-bitbucket-server", - "version": "0.1.12", + "version": "0.1.13-next.0", "description": "The Bitbucket Server module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-bitbucket/CHANGELOG.md b/plugins/scaffolder-backend-module-bitbucket/CHANGELOG.md index 414f8b7bd8..b905cc33e1 100644 --- a/plugins/scaffolder-backend-module-bitbucket/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-bitbucket/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-scaffolder-backend-module-bitbucket +## 0.2.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.1.13-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.1.13-next.0 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + ## 0.2.12 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-bitbucket/package.json b/plugins/scaffolder-backend-module-bitbucket/package.json index 95d92c39b8..a853f795af 100644 --- a/plugins/scaffolder-backend-module-bitbucket/package.json +++ b/plugins/scaffolder-backend-module-bitbucket/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-bitbucket", - "version": "0.2.12", + "version": "0.2.13-next.0", "description": "The bitbucket module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md b/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md index 1613f1881c..29677250a5 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.24-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + ## 0.2.23 ### 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 9fe6781eff..39fb5f49b9 100644 --- a/plugins/scaffolder-backend-module-confluence-to-markdown/package.json +++ b/plugins/scaffolder-backend-module-confluence-to-markdown/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-confluence-to-markdown", - "version": "0.2.23", + "version": "0.2.24-next.0", "description": "The confluence-to-markdown module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md b/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md index f2dc2a822d..865478ea2b 100644 --- a/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-scaffolder-backend-module-cookiecutter +## 0.2.47-next.0 + +### Patch Changes + +- dae85df: Add examples for `fetch:cookiecutter` scaffolder action & improve related tests +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + ## 0.2.46 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-cookiecutter/package.json b/plugins/scaffolder-backend-module-cookiecutter/package.json index b8ab34dbc9..2f21b89244 100644 --- a/plugins/scaffolder-backend-module-cookiecutter/package.json +++ b/plugins/scaffolder-backend-module-cookiecutter/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-cookiecutter", - "version": "0.2.46", + "version": "0.2.47-next.0", "description": "A module for the scaffolder backend that lets you template projects using cookiecutter", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-gcp/CHANGELOG.md b/plugins/scaffolder-backend-module-gcp/CHANGELOG.md index 51dd92b2cf..05843ee288 100644 --- a/plugins/scaffolder-backend-module-gcp/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-gcp/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-scaffolder-backend-module-gcp +## 0.1.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + ## 0.1.0 ### Minor Changes diff --git a/plugins/scaffolder-backend-module-gcp/package.json b/plugins/scaffolder-backend-module-gcp/package.json index ae64d1de61..f6355e93f4 100644 --- a/plugins/scaffolder-backend-module-gcp/package.json +++ b/plugins/scaffolder-backend-module-gcp/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-gcp", - "version": "0.1.0", + "version": "0.1.1-next.0", "description": "The GCP Bucket module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-gerrit/CHANGELOG.md b/plugins/scaffolder-backend-module-gerrit/CHANGELOG.md index 7b95a80811..d95047ba64 100644 --- a/plugins/scaffolder-backend-module-gerrit/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-gerrit/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-scaffolder-backend-module-gerrit +## 0.1.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + ## 0.1.14 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-gerrit/package.json b/plugins/scaffolder-backend-module-gerrit/package.json index 96c069ea97..4be6e4c56c 100644 --- a/plugins/scaffolder-backend-module-gerrit/package.json +++ b/plugins/scaffolder-backend-module-gerrit/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-gerrit", - "version": "0.1.14", + "version": "0.1.15-next.0", "description": "The gerrit module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-gitea/CHANGELOG.md b/plugins/scaffolder-backend-module-gitea/CHANGELOG.md index 4c03220562..6bc250f801 100644 --- a/plugins/scaffolder-backend-module-gitea/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-gitea/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-scaffolder-backend-module-gitea +## 0.1.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + ## 0.1.12 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-gitea/package.json b/plugins/scaffolder-backend-module-gitea/package.json index 69a84f43e7..22b6ab700f 100644 --- a/plugins/scaffolder-backend-module-gitea/package.json +++ b/plugins/scaffolder-backend-module-gitea/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-gitea", - "version": "0.1.12", + "version": "0.1.13-next.0", "description": "The gitea module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-github/CHANGELOG.md b/plugins/scaffolder-backend-module-github/CHANGELOG.md index 680cb0469d..0399be8de3 100644 --- a/plugins/scaffolder-backend-module-github/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-github/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-scaffolder-backend-module-github +## 0.4.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + ## 0.4.0 ### Minor Changes diff --git a/plugins/scaffolder-backend-module-github/package.json b/plugins/scaffolder-backend-module-github/package.json index 7732c7c11a..a43469d7e5 100644 --- a/plugins/scaffolder-backend-module-github/package.json +++ b/plugins/scaffolder-backend-module-github/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-github", - "version": "0.4.0", + "version": "0.4.1-next.0", "description": "The github module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md b/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md index 60e7f1bccf..41df7c2a60 100644 --- a/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/plugin-scaffolder-backend-module-gitlab +## 0.4.5-next.0 + +### Patch Changes + +- fad1b90: Allow the `createGitlabProjectVariableAction` to use oauth tokens +- aab708e: Added test cases for gitlab:issue:edit examples +- ef742dc: Added test cases for gitlab:projectAccessToken:create example +- 1ba4c2f: Added test cases for gitlab:pipeline:trigger examples +- a6603e4: Add custom action for merge request: **auto** + + The **Auto** action selects the committed action between _create_ and _update_. + + The **Auto** action fetches files using the **/projects/repository/tree endpoint**. + After fetching, it checks if the file exists locally and in the repository. If it does, it chooses **update**; otherwise, it chooses **create**. + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + ## 0.4.4 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-gitlab/package.json b/plugins/scaffolder-backend-module-gitlab/package.json index 8228a3ec0f..e4705e6206 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.4.4", + "version": "0.4.5-next.0", "backstage": { "role": "backend-plugin-module", "pluginId": "scaffolder", diff --git a/plugins/scaffolder-backend-module-notifications/CHANGELOG.md b/plugins/scaffolder-backend-module-notifications/CHANGELOG.md index db52ded0c8..f51473dd0c 100644 --- a/plugins/scaffolder-backend-module-notifications/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-notifications/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-scaffolder-backend-module-notifications +## 0.0.6-next.0 + +### Patch Changes + +- 6fc03c7: Add examples for notification:send scaffolder action & improve related tests +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/plugin-notifications-common@0.0.5 + - @backstage/plugin-notifications-node@0.2.4-next.0 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + ## 0.0.5 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-notifications/package.json b/plugins/scaffolder-backend-module-notifications/package.json index 4754cca488..15fe158651 100644 --- a/plugins/scaffolder-backend-module-notifications/package.json +++ b/plugins/scaffolder-backend-module-notifications/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-notifications", - "version": "0.0.5", + "version": "0.0.6-next.0", "description": "The notifications backend module for the scaffolder plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-rails/CHANGELOG.md b/plugins/scaffolder-backend-module-rails/CHANGELOG.md index cd34152910..f9ce2e1e6b 100644 --- a/plugins/scaffolder-backend-module-rails/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-rails/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-scaffolder-backend-module-rails +## 0.4.40-next.0 + +### Patch Changes + +- 449def7: Add examples for fetch:rails scaffolder action & improve related tests +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + ## 0.4.39 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-rails/package.json b/plugins/scaffolder-backend-module-rails/package.json index 910fb04636..a2e2a215dd 100644 --- a/plugins/scaffolder-backend-module-rails/package.json +++ b/plugins/scaffolder-backend-module-rails/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-rails", - "version": "0.4.39", + "version": "0.4.40-next.0", "description": "A module for the scaffolder backend that lets you template projects using Rails", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-sentry/CHANGELOG.md b/plugins/scaffolder-backend-module-sentry/CHANGELOG.md index 113a63222f..0dd4fb6c5b 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.31-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + ## 0.1.30 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-sentry/package.json b/plugins/scaffolder-backend-module-sentry/package.json index 264736692a..3eb11dc3e9 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.30", + "version": "0.1.31-next.0", "backstage": { "role": "backend-plugin-module", "pluginId": "scaffolder", diff --git a/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md b/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md index 53d2369d85..3c9fe7db6b 100644 --- a/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-scaffolder-backend-module-yeoman +## 0.3.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + - @backstage/plugin-scaffolder-node-test-utils@0.1.10-next.0 + ## 0.3.6 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-yeoman/package.json b/plugins/scaffolder-backend-module-yeoman/package.json index 5c65315e22..29f4d7c1aa 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.3.6", + "version": "0.3.7-next.0", "backstage": { "role": "backend-plugin-module", "pluginId": "scaffolder", diff --git a/plugins/scaffolder-backend/CHANGELOG.md b/plugins/scaffolder-backend/CHANGELOG.md index 27e4b4465e..8496dbf17b 100644 --- a/plugins/scaffolder-backend/CHANGELOG.md +++ b/plugins/scaffolder-backend/CHANGELOG.md @@ -1,5 +1,36 @@ # @backstage/plugin-scaffolder-backend +## 1.23.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.4.5-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.22-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.21-next.0 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.1-next.0 + - @backstage/plugin-scaffolder-backend-module-azure@0.1.15-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.2.13-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.1.13-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.1.13-next.0 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.1.15-next.0 + - @backstage/plugin-scaffolder-backend-module-gitea@0.1.13-next.0 + - @backstage/plugin-scaffolder-backend-module-github@0.4.1-next.0 + - @backstage/plugin-scaffolder-common@1.5.4 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + ## 1.23.0 ### Minor Changes diff --git a/plugins/scaffolder-backend/package.json b/plugins/scaffolder-backend/package.json index c86a048d46..af67447fed 100644 --- a/plugins/scaffolder-backend/package.json +++ b/plugins/scaffolder-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend", - "version": "1.23.0", + "version": "1.23.1-next.0", "description": "The Backstage backend plugin that helps you create new things", "backstage": { "role": "backend-plugin", diff --git a/plugins/scaffolder-node-test-utils/CHANGELOG.md b/plugins/scaffolder-node-test-utils/CHANGELOG.md index 7d578a2b14..9eb166062e 100644 --- a/plugins/scaffolder-node-test-utils/CHANGELOG.md +++ b/plugins/scaffolder-node-test-utils/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-scaffolder-node-test-utils +## 0.1.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-test-utils@0.4.5-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.4.9-next.0 + ## 0.1.9 ### Patch Changes diff --git a/plugins/scaffolder-node-test-utils/package.json b/plugins/scaffolder-node-test-utils/package.json index 827b654b4e..ef31d541f4 100644 --- a/plugins/scaffolder-node-test-utils/package.json +++ b/plugins/scaffolder-node-test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-node-test-utils", - "version": "0.1.9", + "version": "0.1.10-next.0", "backstage": { "role": "node-library", "pluginId": "scaffolder", diff --git a/plugins/scaffolder-node/CHANGELOG.md b/plugins/scaffolder-node/CHANGELOG.md index 59658dcb11..db361e0120 100644 --- a/plugins/scaffolder-node/CHANGELOG.md +++ b/plugins/scaffolder-node/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-scaffolder-node +## 0.4.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-common@1.5.4 + ## 0.4.8 ### Patch Changes diff --git a/plugins/scaffolder-node/package.json b/plugins/scaffolder-node/package.json index 07e468620b..2cb7198631 100644 --- a/plugins/scaffolder-node/package.json +++ b/plugins/scaffolder-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-node", - "version": "0.4.8", + "version": "0.4.9-next.0", "description": "The plugin-scaffolder-node module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "node-library", diff --git a/plugins/scaffolder-react/CHANGELOG.md b/plugins/scaffolder-react/CHANGELOG.md index 68f94ac3fd..f23a0e2425 100644 --- a/plugins/scaffolder-react/CHANGELOG.md +++ b/plugins/scaffolder-react/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-scaffolder-react +## 1.11.0-next.0 + +### Minor Changes + +- 8839381: Add scaffolder option to display object items in separate rows on review page + +### Patch Changes + +- d0e95a7: Add ability to customise form fields in the UI by exposing `uiSchema` and `formContext` in `FormProps` +- 4670f06: support `ajv-errors` for scaffolder validation to allow for customizing the error messages +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/plugin-scaffolder-common@1.5.4 + ## 1.10.0 ### Minor Changes diff --git a/plugins/scaffolder-react/package.json b/plugins/scaffolder-react/package.json index 9c50900c05..7c16c11c1a 100644 --- a/plugins/scaffolder-react/package.json +++ b/plugins/scaffolder-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-react", - "version": "1.10.0", + "version": "1.11.0-next.0", "description": "A frontend library that helps other Backstage plugins interact with the Scaffolder", "backstage": { "role": "web-library", diff --git a/plugins/scaffolder/CHANGELOG.md b/plugins/scaffolder/CHANGELOG.md index 2da2802808..e012f99928 100644 --- a/plugins/scaffolder/CHANGELOG.md +++ b/plugins/scaffolder/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/plugin-scaffolder +## 1.23.1-next.0 + +### Patch Changes + +- bbd9f56: Cleaned up codebase of RepoUrlPicker +- b8600fe: Fix issue with `RepoUrlPicker` not refreshing the credentials for a different host +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/plugin-scaffolder-react@1.11.0-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/core-compat-api@0.2.8-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-permission-react@0.4.24 + - @backstage/plugin-scaffolder-common@1.5.4 + ## 1.23.0 ### Minor Changes diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index 5cc587fe4d..ed1bb10e7a 100644 --- a/plugins/scaffolder/package.json +++ b/plugins/scaffolder/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder", - "version": "1.23.0", + "version": "1.23.1-next.0", "description": "The Backstage plugin that helps you create new things", "backstage": { "role": "frontend-plugin", diff --git a/plugins/search-backend-module-catalog/CHANGELOG.md b/plugins/search-backend-module-catalog/CHANGELOG.md index 29304c6cfd..1c6f7205f3 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.29-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-search-backend-node@1.2.28-next.0 + - @backstage/plugin-search-common@1.2.13 + ## 0.1.28 ### Patch Changes diff --git a/plugins/search-backend-module-catalog/package.json b/plugins/search-backend-module-catalog/package.json index 6ec054f10d..972a8b66d2 100644 --- a/plugins/search-backend-module-catalog/package.json +++ b/plugins/search-backend-module-catalog/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-backend-module-catalog", - "version": "0.1.28", + "version": "0.1.29-next.0", "description": "A module for the search backend that exports catalog modules", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/search-backend-module-elasticsearch/CHANGELOG.md b/plugins/search-backend-module-elasticsearch/CHANGELOG.md index d561b1127a..a78362a926 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.5.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/integration-aws-node@0.1.12 + - @backstage/plugin-search-backend-node@1.2.28-next.0 + - @backstage/plugin-search-common@1.2.13 + ## 1.5.3 ### Patch Changes diff --git a/plugins/search-backend-module-elasticsearch/package.json b/plugins/search-backend-module-elasticsearch/package.json index d96b4c924d..4107811cfd 100644 --- a/plugins/search-backend-module-elasticsearch/package.json +++ b/plugins/search-backend-module-elasticsearch/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-backend-module-elasticsearch", - "version": "1.5.3", + "version": "1.5.4-next.0", "description": "A module for the search backend that implements search using ElasticSearch", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/search-backend-module-explore/CHANGELOG.md b/plugins/search-backend-module-explore/CHANGELOG.md index f5b60fa87e..e14dd6c6c0 100644 --- a/plugins/search-backend-module-explore/CHANGELOG.md +++ b/plugins/search-backend-module-explore/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-search-backend-module-explore +## 0.1.29-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/config@1.2.0 + - @backstage/plugin-search-backend-node@1.2.28-next.0 + - @backstage/plugin-search-common@1.2.13 + ## 0.1.28 ### Patch Changes diff --git a/plugins/search-backend-module-explore/package.json b/plugins/search-backend-module-explore/package.json index 9fd252df66..8d531a6a37 100644 --- a/plugins/search-backend-module-explore/package.json +++ b/plugins/search-backend-module-explore/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-backend-module-explore", - "version": "0.1.28", + "version": "0.1.29-next.0", "description": "A module for the search backend that exports explore modules", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/search-backend-module-pg/CHANGELOG.md b/plugins/search-backend-module-pg/CHANGELOG.md index c19c797bde..b2fa9b818e 100644 --- a/plugins/search-backend-module-pg/CHANGELOG.md +++ b/plugins/search-backend-module-pg/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-search-backend-module-pg +## 0.5.33-next.0 + +### Patch Changes + +- 7251567: Removing `@backstage/backend-app-api` dependency +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/plugin-search-backend-node@1.2.28-next.0 + - @backstage/plugin-search-common@1.2.13 + ## 0.5.32 ### Patch Changes diff --git a/plugins/search-backend-module-pg/package.json b/plugins/search-backend-module-pg/package.json index 1693c14c8a..9679c5ddec 100644 --- a/plugins/search-backend-module-pg/package.json +++ b/plugins/search-backend-module-pg/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-backend-module-pg", - "version": "0.5.32", + "version": "0.5.33-next.0", "description": "A module for the search backend that implements search using PostgreSQL", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/search-backend-module-stack-overflow-collator/CHANGELOG.md b/plugins/search-backend-module-stack-overflow-collator/CHANGELOG.md index 6c86337062..ba1143e663 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.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/config@1.2.0 + - @backstage/plugin-search-backend-node@1.2.28-next.0 + - @backstage/plugin-search-common@1.2.13 + ## 0.1.15 ### 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 4d06f928a0..0fd6425e45 100644 --- a/plugins/search-backend-module-stack-overflow-collator/package.json +++ b/plugins/search-backend-module-stack-overflow-collator/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-backend-module-stack-overflow-collator", - "version": "0.1.15", + "version": "0.1.16-next.0", "description": "A module for the search backend that exports stack overflow modules", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/search-backend-module-techdocs/CHANGELOG.md b/plugins/search-backend-module-techdocs/CHANGELOG.md index 2c41ecda1f..26137e8eef 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.28-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/plugin-catalog-node@1.12.5-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-search-backend-node@1.2.28-next.0 + - @backstage/plugin-search-common@1.2.13 + - @backstage/plugin-techdocs-node@1.12.9-next.0 + ## 0.1.27 ### Patch Changes diff --git a/plugins/search-backend-module-techdocs/package.json b/plugins/search-backend-module-techdocs/package.json index a04f64756b..52f5d7252b 100644 --- a/plugins/search-backend-module-techdocs/package.json +++ b/plugins/search-backend-module-techdocs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-backend-module-techdocs", - "version": "0.1.27", + "version": "0.1.28-next.0", "description": "A module for the search backend that exports techdocs modules", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/search-backend-node/CHANGELOG.md b/plugins/search-backend-node/CHANGELOG.md index f43f3c4009..05d6d3dba2 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.28-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/backend-tasks@0.5.28-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-search-common@1.2.13 + ## 1.2.27 ### Patch Changes diff --git a/plugins/search-backend-node/package.json b/plugins/search-backend-node/package.json index a236eff6c0..f00a58b584 100644 --- a/plugins/search-backend-node/package.json +++ b/plugins/search-backend-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-backend-node", - "version": "1.2.27", + "version": "1.2.28-next.0", "description": "A library for Backstage backend plugins that want to interact with the search backend plugin", "backstage": { "role": "node-library", diff --git a/plugins/search-backend/CHANGELOG.md b/plugins/search-backend/CHANGELOG.md index eb391c6bba..018e049523 100644 --- a/plugins/search-backend/CHANGELOG.md +++ b/plugins/search-backend/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-search-backend +## 1.5.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-defaults@0.4.2-next.0 + - @backstage/backend-openapi-utils@0.1.16-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-permission-node@0.8.1-next.0 + - @backstage/plugin-search-backend-node@1.2.28-next.0 + - @backstage/plugin-search-common@1.2.13 + ## 1.5.14 ### Patch Changes diff --git a/plugins/search-backend/package.json b/plugins/search-backend/package.json index a0e7b48f5b..502bfd674e 100644 --- a/plugins/search-backend/package.json +++ b/plugins/search-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-backend", - "version": "1.5.14", + "version": "1.5.15-next.0", "description": "The Backstage backend plugin that provides your backstage app with search", "backstage": { "role": "backend-plugin", diff --git a/plugins/search-react/CHANGELOG.md b/plugins/search-react/CHANGELOG.md index 04d8bf312a..f90428a139 100644 --- a/plugins/search-react/CHANGELOG.md +++ b/plugins/search-react/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-search-react +## 1.7.14-next.0 + +### Patch Changes + +- 31bfc44: Updated alpha definitions of extension data references. +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + - @backstage/plugin-search-common@1.2.13 + ## 1.7.13 ### Patch Changes diff --git a/plugins/search-react/package.json b/plugins/search-react/package.json index b5c17c369a..4cf1e476e8 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.13", + "version": "1.7.14-next.0", "backstage": { "role": "web-library", "pluginId": "search", diff --git a/plugins/search/CHANGELOG.md b/plugins/search/CHANGELOG.md index bce322e95a..2c85c5bcf0 100644 --- a/plugins/search/CHANGELOG.md +++ b/plugins/search/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-search +## 1.4.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/plugin-search-react@1.7.14-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-compat-api@0.2.8-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.8 + - @backstage/plugin-search-common@1.2.13 + ## 1.4.14 ### Patch Changes diff --git a/plugins/search/package.json b/plugins/search/package.json index 56271eca58..d1aa27716a 100644 --- a/plugins/search/package.json +++ b/plugins/search/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search", - "version": "1.4.14", + "version": "1.4.15-next.0", "description": "The Backstage plugin that provides your backstage app with search", "backstage": { "role": "frontend-plugin", diff --git a/plugins/signals-backend/CHANGELOG.md b/plugins/signals-backend/CHANGELOG.md index e0525a0e78..844d2cc185 100644 --- a/plugins/signals-backend/CHANGELOG.md +++ b/plugins/signals-backend/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-signals-backend +## 0.1.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-events-node@0.3.9-next.0 + - @backstage/plugin-signals-node@0.1.9-next.0 + ## 0.1.8 ### Patch Changes diff --git a/plugins/signals-backend/package.json b/plugins/signals-backend/package.json index 1e0ac41fcb..f88e8825cd 100644 --- a/plugins/signals-backend/package.json +++ b/plugins/signals-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-signals-backend", - "version": "0.1.8", + "version": "0.1.9-next.0", "backstage": { "role": "backend-plugin", "pluginId": "signals", diff --git a/plugins/signals-node/CHANGELOG.md b/plugins/signals-node/CHANGELOG.md index 0353548fe5..769800350a 100644 --- a/plugins/signals-node/CHANGELOG.md +++ b/plugins/signals-node/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-signals-node +## 0.1.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-events-node@0.3.9-next.0 + ## 0.1.8 ### Patch Changes diff --git a/plugins/signals-node/package.json b/plugins/signals-node/package.json index 1cea62c21b..e4a4000120 100644 --- a/plugins/signals-node/package.json +++ b/plugins/signals-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-signals-node", - "version": "0.1.8", + "version": "0.1.9-next.0", "description": "Node.js library for the signals plugin", "backstage": { "role": "node-library", diff --git a/plugins/signals/CHANGELOG.md b/plugins/signals/CHANGELOG.md index a4a7daec35..1f6c9fccf7 100644 --- a/plugins/signals/CHANGELOG.md +++ b/plugins/signals/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-signals +## 0.0.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/plugin-signals-react@0.0.4 + ## 0.0.8 ### Patch Changes diff --git a/plugins/signals/package.json b/plugins/signals/package.json index 88ca252c1f..54af5cb9f6 100644 --- a/plugins/signals/package.json +++ b/plugins/signals/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-signals", - "version": "0.0.8", + "version": "0.0.9-next.0", "backstage": { "role": "frontend-plugin", "pluginId": "signals", diff --git a/plugins/techdocs-addons-test-utils/CHANGELOG.md b/plugins/techdocs-addons-test-utils/CHANGELOG.md index 3135cc5ffd..844ee41d30 100644 --- a/plugins/techdocs-addons-test-utils/CHANGELOG.md +++ b/plugins/techdocs-addons-test-utils/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-techdocs-addons-test-utils +## 1.0.36-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/plugin-search-react@1.7.14-next.0 + - @backstage/core-app-api@1.14.1-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/test-utils@1.5.9-next.0 + - @backstage/plugin-catalog@1.21.2-next.0 + - @backstage/plugin-techdocs@1.10.8-next.0 + - @backstage/plugin-techdocs-react@1.2.7-next.0 + ## 1.0.35 ### Patch Changes diff --git a/plugins/techdocs-addons-test-utils/package.json b/plugins/techdocs-addons-test-utils/package.json index 57cd4d06a6..6310ad03b8 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.35", + "version": "1.0.36-next.0", "backstage": { "role": "web-library", "pluginId": "techdocs-addons", diff --git a/plugins/techdocs-backend/CHANGELOG.md b/plugins/techdocs-backend/CHANGELOG.md index 571b0d68fc..44ab26cb79 100644 --- a/plugins/techdocs-backend/CHANGELOG.md +++ b/plugins/techdocs-backend/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-techdocs-backend +## 1.10.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-client@1.6.5 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/plugin-catalog-common@1.0.25 + - @backstage/plugin-permission-common@0.8.0 + - @backstage/plugin-search-backend-module-techdocs@0.1.28-next.0 + - @backstage/plugin-techdocs-node@1.12.9-next.0 + ## 1.10.9 ### Patch Changes diff --git a/plugins/techdocs-backend/package.json b/plugins/techdocs-backend/package.json index ce0df2ca78..0bf2381a8c 100644 --- a/plugins/techdocs-backend/package.json +++ b/plugins/techdocs-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs-backend", - "version": "1.10.9", + "version": "1.10.10-next.0", "description": "The Backstage backend plugin that renders technical documentation for your components", "backstage": { "role": "backend-plugin", diff --git a/plugins/techdocs-module-addons-contrib/CHANGELOG.md b/plugins/techdocs-module-addons-contrib/CHANGELOG.md index 4072d96d9f..8bfa4e9c49 100644 --- a/plugins/techdocs-module-addons-contrib/CHANGELOG.md +++ b/plugins/techdocs-module-addons-contrib/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-techdocs-module-addons-contrib +## 1.1.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.10-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/plugin-techdocs-react@1.2.7-next.0 + ## 1.1.12 ### Patch Changes diff --git a/plugins/techdocs-module-addons-contrib/package.json b/plugins/techdocs-module-addons-contrib/package.json index 3c226f6a50..8254dceaf5 100644 --- a/plugins/techdocs-module-addons-contrib/package.json +++ b/plugins/techdocs-module-addons-contrib/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs-module-addons-contrib", - "version": "1.1.12", + "version": "1.1.13-next.0", "description": "Plugin module for contributed TechDocs Addons", "backstage": { "role": "frontend-plugin-module", diff --git a/plugins/techdocs-node/CHANGELOG.md b/plugins/techdocs-node/CHANGELOG.md index d392e3e662..6fb8d7bd8d 100644 --- a/plugins/techdocs-node/CHANGELOG.md +++ b/plugins/techdocs-node/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-techdocs-node +## 1.12.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/integration-aws-node@0.1.12 + - @backstage/plugin-search-common@1.2.13 + ## 1.12.8 ### Patch Changes diff --git a/plugins/techdocs-node/package.json b/plugins/techdocs-node/package.json index 572b76e052..615a0b7235 100644 --- a/plugins/techdocs-node/package.json +++ b/plugins/techdocs-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs-node", - "version": "1.12.8", + "version": "1.12.9-next.0", "description": "Common node.js functionalities for TechDocs, to be shared between techdocs-backend plugin and techdocs-cli", "backstage": { "role": "node-library", diff --git a/plugins/techdocs-react/CHANGELOG.md b/plugins/techdocs-react/CHANGELOG.md index 5c9bd0004f..20301266cc 100644 --- a/plugins/techdocs-react/CHANGELOG.md +++ b/plugins/techdocs-react/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-techdocs-react +## 1.2.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.14.10-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/version-bridge@1.0.8 + ## 1.2.6 ### Patch Changes diff --git a/plugins/techdocs-react/package.json b/plugins/techdocs-react/package.json index e65079b212..2db27e2c60 100644 --- a/plugins/techdocs-react/package.json +++ b/plugins/techdocs-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs-react", - "version": "1.2.6", + "version": "1.2.7-next.0", "description": "Shared frontend utilities for TechDocs and Addons", "backstage": { "role": "web-library", diff --git a/plugins/techdocs/CHANGELOG.md b/plugins/techdocs/CHANGELOG.md index 08a841f25c..f2e16e331c 100644 --- a/plugins/techdocs/CHANGELOG.md +++ b/plugins/techdocs/CHANGELOG.md @@ -1,5 +1,26 @@ # @backstage/plugin-techdocs +## 1.10.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/plugin-search-react@1.7.14-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/integration@1.14.0-next.0 + - @backstage/plugin-auth-react@0.1.5-next.0 + - @backstage/catalog-model@1.5.0 + - @backstage/config@1.2.0 + - @backstage/core-compat-api@0.2.8-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/integration-react@1.1.30-next.0 + - @backstage/theme@0.5.6 + - @backstage/plugin-search-common@1.2.13 + - @backstage/plugin-techdocs-react@1.2.7-next.0 + ## 1.10.7 ### Patch Changes diff --git a/plugins/techdocs/package.json b/plugins/techdocs/package.json index 3a90078c72..b1717ce92e 100644 --- a/plugins/techdocs/package.json +++ b/plugins/techdocs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs", - "version": "1.10.7", + "version": "1.10.8-next.0", "description": "The Backstage plugin that renders technical documentation for your components", "backstage": { "role": "frontend-plugin", diff --git a/plugins/user-settings-backend/CHANGELOG.md b/plugins/user-settings-backend/CHANGELOG.md index 6a945081e8..05f426e57f 100644 --- a/plugins/user-settings-backend/CHANGELOG.md +++ b/plugins/user-settings-backend/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-user-settings-backend +## 0.2.22-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.23.4-next.0 + - @backstage/backend-plugin-api@0.7.1-next.0 + - @backstage/config@1.2.0 + - @backstage/errors@1.2.4 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.18-next.0 + - @backstage/plugin-signals-node@0.1.9-next.0 + - @backstage/plugin-user-settings-common@0.0.1 + ## 0.2.21 ### Patch Changes diff --git a/plugins/user-settings-backend/package.json b/plugins/user-settings-backend/package.json index e33bf0bd4b..1c28f1e90c 100644 --- a/plugins/user-settings-backend/package.json +++ b/plugins/user-settings-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-user-settings-backend", - "version": "0.2.21", + "version": "0.2.22-next.0", "description": "The Backstage backend plugin to manage user settings", "backstage": { "role": "backend-plugin", diff --git a/plugins/user-settings/CHANGELOG.md b/plugins/user-settings/CHANGELOG.md index f10a4c0ea3..84598558ee 100644 --- a/plugins/user-settings/CHANGELOG.md +++ b/plugins/user-settings/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-user-settings +## 0.8.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.6.8-next.0 + - @backstage/plugin-catalog-react@1.12.3-next.0 + - @backstage/core-components@0.14.10-next.0 + - @backstage/core-app-api@1.14.1-next.0 + - @backstage/core-compat-api@0.2.8-next.0 + - @backstage/core-plugin-api@1.9.3 + - @backstage/errors@1.2.4 + - @backstage/theme@0.5.6 + - @backstage/types@1.1.1 + - @backstage/plugin-signals-react@0.0.4 + - @backstage/plugin-user-settings-common@0.0.1 + ## 0.8.9 ### Patch Changes diff --git a/plugins/user-settings/package.json b/plugins/user-settings/package.json index 5ae95e0e45..7534c275d1 100644 --- a/plugins/user-settings/package.json +++ b/plugins/user-settings/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-user-settings", - "version": "0.8.9", + "version": "0.8.10-next.0", "description": "A Backstage plugin that provides a settings page", "backstage": { "role": "frontend-plugin", diff --git a/yarn.lock b/yarn.lock index 8755e05c25..2b3baa5b33 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3839,7 +3839,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/catalog-client@workspace:^, @backstage/catalog-client@workspace:packages/catalog-client": +"@backstage/catalog-client@^1.6.5, @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: @@ -3852,7 +3852,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/catalog-model@^1.4.3, @backstage/catalog-model@^1.4.5, @backstage/catalog-model@workspace:^, @backstage/catalog-model@workspace:packages/catalog-model": +"@backstage/catalog-model@^1.4.3, @backstage/catalog-model@^1.4.5, @backstage/catalog-model@^1.5.0, @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: @@ -4105,7 +4105,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/config@^1.1.1, @backstage/config@workspace:^, @backstage/config@workspace:packages/config": +"@backstage/config@^1.1.1, @backstage/config@^1.2.0, @backstage/config@workspace:^, @backstage/config@workspace:packages/config": version: 0.0.0-use.local resolution: "@backstage/config@workspace:packages/config" dependencies: @@ -4177,7 +4177,107 @@ __metadata: languageName: unknown linkType: soft -"@backstage/core-components@^0.14.4, @backstage/core-components@workspace:^, @backstage/core-components@workspace:packages/core-components": +"@backstage/core-components@npm:^0.13.10": + version: 0.13.10 + resolution: "@backstage/core-components@npm:0.13.10" + dependencies: + "@backstage/config": ^1.1.1 + "@backstage/core-plugin-api": ^1.8.2 + "@backstage/errors": ^1.2.3 + "@backstage/theme": ^0.5.0 + "@backstage/version-bridge": ^1.0.7 + "@date-io/core": ^1.3.13 + "@material-table/core": ^3.1.0 + "@material-ui/core": ^4.12.2 + "@material-ui/icons": ^4.9.1 + "@material-ui/lab": 4.0.0-alpha.61 + "@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 + ansi-regex: ^6.0.1 + classnames: ^2.2.6 + d3-selection: ^3.0.0 + d3-shape: ^3.0.0 + d3-zoom: ^3.0.0 + dagre: ^0.8.5 + linkify-react: 4.1.3 + linkifyjs: 4.1.3 + lodash: ^4.17.21 + pluralize: ^8.0.0 + qs: ^6.9.4 + rc-progress: 3.5.1 + react-helmet: 6.1.0 + react-hook-form: ^7.12.2 + react-idle-timer: 5.6.2 + react-markdown: ^8.0.0 + react-sparklines: ^1.7.0 + react-syntax-highlighter: ^15.4.5 + react-text-truncate: ^0.19.0 + react-use: ^17.3.2 + react-virtualized-auto-sizer: ^1.0.11 + react-window: ^1.8.6 + remark-gfm: ^3.0.1 + zen-observable: ^0.10.0 + zod: ^3.22.4 + peerDependencies: + 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 + checksum: ec2a0d0a27bc4d6b9d4da97f0b4df600148529ee51bf2c8e7d3adc45c3950adac662535d3beabc451db346f2c7e3c412ceaa756fc774012b43dff5e2695f2271 + languageName: node + linkType: hard + +"@backstage/core-components@npm:^0.14.4, @backstage/core-components@npm:^0.14.9": + version: 0.14.9 + resolution: "@backstage/core-components@npm:0.14.9" + dependencies: + "@backstage/config": ^1.2.0 + "@backstage/core-plugin-api": ^1.9.3 + "@backstage/errors": ^1.2.4 + "@backstage/theme": ^0.5.6 + "@backstage/version-bridge": ^1.0.8 + "@date-io/core": ^1.3.13 + "@material-table/core": ^3.1.0 + "@material-ui/core": ^4.12.2 + "@material-ui/icons": ^4.9.1 + "@material-ui/lab": 4.0.0-alpha.61 + "@react-hookz/web": ^24.0.0 + "@types/react": ^16.13.1 || ^17.0.0 || ^18.0.0 + "@types/react-sparklines": ^1.7.0 + ansi-regex: ^6.0.1 + classnames: ^2.2.6 + d3-selection: ^3.0.0 + d3-shape: ^3.0.0 + d3-zoom: ^3.0.0 + dagre: ^0.8.5 + linkify-react: 4.1.3 + linkifyjs: 4.1.3 + lodash: ^4.17.21 + pluralize: ^8.0.0 + qs: ^6.9.4 + rc-progress: 3.5.1 + react-helmet: 6.1.0 + react-hook-form: ^7.12.2 + react-idle-timer: 5.7.2 + react-markdown: ^8.0.0 + react-sparklines: ^1.7.0 + react-syntax-highlighter: ^15.4.5 + react-use: ^17.3.2 + react-virtualized-auto-sizer: ^1.0.11 + react-window: ^1.8.6 + remark-gfm: ^3.0.1 + zen-observable: ^0.10.0 + zod: ^3.22.4 + peerDependencies: + 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 + checksum: cf89c9e19dd33270bdc2bb9e7d89487c71b78e6645dcef9a6ac0d1df67b52e4eee61f2873abe093ed921d756a75f97e870c294aa5c2a730598e520b06e38b41f + languageName: node + linkType: hard + +"@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: @@ -4248,58 +4348,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/core-components@npm:^0.13.10": - version: 0.13.10 - resolution: "@backstage/core-components@npm:0.13.10" - dependencies: - "@backstage/config": ^1.1.1 - "@backstage/core-plugin-api": ^1.8.2 - "@backstage/errors": ^1.2.3 - "@backstage/theme": ^0.5.0 - "@backstage/version-bridge": ^1.0.7 - "@date-io/core": ^1.3.13 - "@material-table/core": ^3.1.0 - "@material-ui/core": ^4.12.2 - "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.61 - "@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 - ansi-regex: ^6.0.1 - classnames: ^2.2.6 - d3-selection: ^3.0.0 - d3-shape: ^3.0.0 - d3-zoom: ^3.0.0 - dagre: ^0.8.5 - linkify-react: 4.1.3 - linkifyjs: 4.1.3 - lodash: ^4.17.21 - pluralize: ^8.0.0 - qs: ^6.9.4 - rc-progress: 3.5.1 - react-helmet: 6.1.0 - react-hook-form: ^7.12.2 - react-idle-timer: 5.6.2 - react-markdown: ^8.0.0 - react-sparklines: ^1.7.0 - react-syntax-highlighter: ^15.4.5 - react-text-truncate: ^0.19.0 - react-use: ^17.3.2 - react-virtualized-auto-sizer: ^1.0.11 - react-window: ^1.8.6 - remark-gfm: ^3.0.1 - zen-observable: ^0.10.0 - zod: ^3.22.4 - peerDependencies: - 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 - checksum: ec2a0d0a27bc4d6b9d4da97f0b4df600148529ee51bf2c8e7d3adc45c3950adac662535d3beabc451db346f2c7e3c412ceaa756fc774012b43dff5e2695f2271 - languageName: node - linkType: hard - -"@backstage/core-plugin-api@^1.8.2, @backstage/core-plugin-api@^1.9.2, @backstage/core-plugin-api@workspace:^, @backstage/core-plugin-api@workspace:packages/core-plugin-api": +"@backstage/core-plugin-api@^1.8.2, @backstage/core-plugin-api@^1.9.2, @backstage/core-plugin-api@^1.9.3, @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: @@ -4446,6 +4495,26 @@ __metadata: languageName: unknown linkType: soft +"@backstage/frontend-plugin-api@npm:^0.6.7": + version: 0.6.7 + resolution: "@backstage/frontend-plugin-api@npm:0.6.7" + dependencies: + "@backstage/core-components": ^0.14.9 + "@backstage/core-plugin-api": ^1.9.3 + "@backstage/types": ^1.1.1 + "@backstage/version-bridge": ^1.0.8 + "@material-ui/core": ^4.12.4 + "@types/react": ^16.13.1 || ^17.0.0 || ^18.0.0 + lodash: ^4.17.21 + zod: ^3.22.4 + zod-to-json-schema: ^3.21.4 + peerDependencies: + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-router-dom: 6.0.0-beta.0 || ^6.3.0 + checksum: cf7485aedcae02c5855a62adea6fffcfad256d614731ade38d2bebd5f98e91aa5d1020cd9ac25b74d67d2681c010addff4a89d5be1e2deb2e688bf1915134c32 + languageName: node + linkType: hard + "@backstage/frontend-plugin-api@workspace:^, @backstage/frontend-plugin-api@workspace:packages/frontend-plugin-api": version: 0.0.0-use.local resolution: "@backstage/frontend-plugin-api@workspace:packages/frontend-plugin-api" @@ -4509,6 +4578,24 @@ __metadata: languageName: unknown linkType: soft +"@backstage/integration-react@npm:^1.1.29": + version: 1.1.29 + resolution: "@backstage/integration-react@npm:1.1.29" + dependencies: + "@backstage/config": ^1.2.0 + "@backstage/core-plugin-api": ^1.9.3 + "@backstage/integration": ^1.13.0 + "@material-ui/core": ^4.12.2 + "@material-ui/icons": ^4.9.1 + "@types/react": ^16.13.1 || ^17.0.0 + peerDependencies: + 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 + checksum: add10ad8c108933354037f9d74ec554174d2af53d74a031e12ed01e98bd51481413b93c694460cf045b3bae818dd18b5efa061fc60c210e145e4629e0cb227b7 + languageName: node + linkType: hard + "@backstage/integration-react@workspace:^, @backstage/integration-react@workspace:packages/integration-react": version: 0.0.0-use.local resolution: "@backstage/integration-react@workspace:packages/integration-react" @@ -4533,6 +4620,23 @@ __metadata: languageName: unknown linkType: soft +"@backstage/integration@npm:^1.13.0": + version: 1.13.0 + resolution: "@backstage/integration@npm:1.13.0" + dependencies: + "@azure/identity": ^4.0.0 + "@backstage/config": ^1.2.0 + "@backstage/errors": ^1.2.4 + "@octokit/auth-app": ^4.0.0 + "@octokit/rest": ^19.0.3 + cross-fetch: ^4.0.0 + git-url-parse: ^14.0.0 + lodash: ^4.17.21 + luxon: ^3.0.0 + checksum: 2b824261b0d30771e54515f8571c2af0b4c64f5cd3d1f990c234152b19e81d1e4ddbbbfae2a0b74f44abbfb67f52609c7eee9dc9fbb61d5f0076acaa80b3e670 + languageName: node + linkType: hard + "@backstage/integration@workspace:^, @backstage/integration@workspace:packages/integration": version: 0.0.0-use.local resolution: "@backstage/integration@workspace:packages/integration" @@ -5616,7 +5720,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-catalog-common@^1.0.20, @backstage/plugin-catalog-common@workspace:^, @backstage/plugin-catalog-common@workspace:plugins/catalog-common": +"@backstage/plugin-catalog-common@^1.0.20, @backstage/plugin-catalog-common@^1.0.25, @backstage/plugin-catalog-common@workspace:^, @backstage/plugin-catalog-common@workspace:plugins/catalog-common": version: 0.0.0-use.local resolution: "@backstage/plugin-catalog-common@workspace:plugins/catalog-common" dependencies: @@ -5725,7 +5829,43 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-catalog-react@^1.11.3, @backstage/plugin-catalog-react@^1.9.3, @backstage/plugin-catalog-react@workspace:^, @backstage/plugin-catalog-react@workspace:plugins/catalog-react": +"@backstage/plugin-catalog-react@npm:^1.11.3, @backstage/plugin-catalog-react@npm:^1.9.3": + version: 1.12.2 + resolution: "@backstage/plugin-catalog-react@npm:1.12.2" + dependencies: + "@backstage/catalog-client": ^1.6.5 + "@backstage/catalog-model": ^1.5.0 + "@backstage/core-components": ^0.14.9 + "@backstage/core-plugin-api": ^1.9.3 + "@backstage/errors": ^1.2.4 + "@backstage/frontend-plugin-api": ^0.6.7 + "@backstage/integration-react": ^1.1.29 + "@backstage/plugin-catalog-common": ^1.0.25 + "@backstage/plugin-permission-common": ^0.8.0 + "@backstage/plugin-permission-react": ^0.4.24 + "@backstage/types": ^1.1.1 + "@backstage/version-bridge": ^1.0.8 + "@material-ui/core": ^4.12.2 + "@material-ui/icons": ^4.9.1 + "@material-ui/lab": 4.0.0-alpha.61 + "@react-hookz/web": ^24.0.0 + "@types/react": ^16.13.1 || ^17.0.0 || ^18.0.0 + classnames: ^2.2.6 + lodash: ^4.17.21 + material-ui-popup-state: ^1.9.3 + qs: ^6.9.4 + react-use: ^17.2.4 + yaml: ^2.0.0 + zen-observable: ^0.10.0 + peerDependencies: + 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 + checksum: 8570e71e56e89cc8ba890ad9cd1f2ce22147635e9a326703291ee8a75d704086c4a31cd11b2b2c3eb54f3e1dc82822b1bc7b9317e8c6d81f6ab9758c2c01ec5a + languageName: node + linkType: hard + +"@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: @@ -6569,7 +6709,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-permission-common@workspace:^, @backstage/plugin-permission-common@workspace:plugins/permission-common": +"@backstage/plugin-permission-common@^0.8.0, @backstage/plugin-permission-common@workspace:^, @backstage/plugin-permission-common@workspace:plugins/permission-common": version: 0.0.0-use.local resolution: "@backstage/plugin-permission-common@workspace:plugins/permission-common" dependencies: @@ -6607,7 +6747,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-permission-react@workspace:^, @backstage/plugin-permission-react@workspace:plugins/permission-react": +"@backstage/plugin-permission-react@^0.4.24, @backstage/plugin-permission-react@workspace:^, @backstage/plugin-permission-react@workspace:plugins/permission-react": version: 0.0.0-use.local resolution: "@backstage/plugin-permission-react@workspace:plugins/permission-react" dependencies: @@ -7933,7 +8073,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/theme@^0.5.0, @backstage/theme@workspace:^, @backstage/theme@workspace:packages/theme": +"@backstage/theme@^0.5.0, @backstage/theme@^0.5.6, @backstage/theme@workspace:^, @backstage/theme@workspace:packages/theme": version: 0.0.0-use.local resolution: "@backstage/theme@workspace:packages/theme" dependencies: @@ -7964,7 +8104,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/version-bridge@^1.0.7, @backstage/version-bridge@workspace:^, @backstage/version-bridge@workspace:packages/version-bridge": +"@backstage/version-bridge@^1.0.7, @backstage/version-bridge@^1.0.8, @backstage/version-bridge@workspace:^, @backstage/version-bridge@workspace:packages/version-bridge": version: 0.0.0-use.local resolution: "@backstage/version-bridge@workspace:packages/version-bridge" dependencies: From fc45f68ecc2d7d3bc912a80fc39d64479722b858 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 23 Jul 2024 14:54:20 +0000 Subject: [PATCH 387/416] fix(deps): update dependency octokit to v3.2.1 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 53 ++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 40 insertions(+), 13 deletions(-) diff --git a/yarn.lock b/yarn.lock index 8755e05c25..80cea4fceb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12110,6 +12110,13 @@ __metadata: languageName: node linkType: hard +"@octokit/openapi-types@npm:^22.2.0": + version: 22.2.0 + resolution: "@octokit/openapi-types@npm:22.2.0" + checksum: eca41feac2b83298e0d95e253ac1c5b6d65155ac57f65c5fd8d4a485d9728922d85ff4bee0e815a1f3a5421311db092bdb6da9d6104a1b1843d8b274bcad9630 + languageName: node + linkType: hard + "@octokit/plugin-paginate-graphql@npm:^4.0.0": version: 4.0.0 resolution: "@octokit/plugin-paginate-graphql@npm:4.0.0" @@ -12119,6 +12126,17 @@ __metadata: languageName: node linkType: hard +"@octokit/plugin-paginate-rest@npm:11.3.1": + version: 11.3.1 + resolution: "@octokit/plugin-paginate-rest@npm:11.3.1" + dependencies: + "@octokit/types": ^13.5.0 + peerDependencies: + "@octokit/core": 5 + checksum: 42c7c08e7287b4b85d2ae47852d2ffeb238c134ad6bcff18bddc154b15f6bec31778816c0763181401c370198390db7f6b0c3c44750fdfeec459594f7f4b5933 + languageName: node + linkType: hard + "@octokit/plugin-paginate-rest@npm:^6.1.2": version: 6.1.2 resolution: "@octokit/plugin-paginate-rest@npm:6.1.2" @@ -12151,14 +12169,14 @@ __metadata: languageName: node linkType: hard -"@octokit/plugin-rest-endpoint-methods@npm:^10.0.0": - version: 10.2.0 - resolution: "@octokit/plugin-rest-endpoint-methods@npm:10.2.0" +"@octokit/plugin-rest-endpoint-methods@npm:13.2.2": + version: 13.2.2 + resolution: "@octokit/plugin-rest-endpoint-methods@npm:13.2.2" dependencies: - "@octokit/types": ^12.3.0 + "@octokit/types": ^13.5.0 peerDependencies: - "@octokit/core": ">=5" - checksum: 3209688bf508d22a525fe32d632ff928b048688c1859c7e4bbb08bd181aa07f580b375a502e34368628103e5d5cccf7f9fb0ff0c8fd4262470ac8eeffb80ac6b + "@octokit/core": ^5 + checksum: 347b3a891a561ed1dcc307a2dce42ca48c318c465ad91a26225d3d6493aef1b7ff868e6c56a0d7aa4170d028c7429ca1ec52aed6be34615a6ed701c3bcafdb17 languageName: node linkType: hard @@ -12291,7 +12309,7 @@ __metadata: languageName: node linkType: hard -"@octokit/types@npm:^12.0.0, @octokit/types@npm:^12.2.0, @octokit/types@npm:^12.3.0, @octokit/types@npm:^12.4.0": +"@octokit/types@npm:^12.0.0, @octokit/types@npm:^12.2.0, @octokit/types@npm:^12.4.0": version: 12.4.0 resolution: "@octokit/types@npm:12.4.0" dependencies: @@ -12300,6 +12318,15 @@ __metadata: languageName: node linkType: hard +"@octokit/types@npm:^13.0.0, @octokit/types@npm:^13.5.0": + version: 13.5.0 + resolution: "@octokit/types@npm:13.5.0" + dependencies: + "@octokit/openapi-types": ^22.2.0 + checksum: 8e92f2b145b3c28a35312f93714245824a7b6b7353caa88edfdc85fc2ed4108321ed0c3988001ea53449fbb212febe0e8e9582744e85c3574dabe9d0441af5a0 + languageName: node + linkType: hard + "@octokit/types@npm:^6.0.3, @octokit/types@npm:^6.10.0, @octokit/types@npm:^6.12.2, @octokit/types@npm:^6.16.1": version: 6.41.0 resolution: "@octokit/types@npm:6.41.0" @@ -35642,20 +35669,20 @@ __metadata: linkType: hard "octokit@npm:^3.0.0": - version: 3.2.0 - resolution: "octokit@npm:3.2.0" + version: 3.2.1 + resolution: "octokit@npm:3.2.1" dependencies: "@octokit/app": ^14.0.2 "@octokit/core": ^5.0.0 "@octokit/oauth-app": ^6.0.0 "@octokit/plugin-paginate-graphql": ^4.0.0 - "@octokit/plugin-paginate-rest": ^9.0.0 - "@octokit/plugin-rest-endpoint-methods": ^10.0.0 + "@octokit/plugin-paginate-rest": 11.3.1 + "@octokit/plugin-rest-endpoint-methods": 13.2.2 "@octokit/plugin-retry": ^6.0.0 "@octokit/plugin-throttling": ^8.0.0 "@octokit/request-error": ^5.0.0 - "@octokit/types": ^12.0.0 - checksum: 3ec8efe02144aa6210a5c846947245cbe58d31144fa8e6a1726782001d77fcd044b7e1498a56c5e47aba44c1f5726a37c261f474cb46b816579549f7a09db1f6 + "@octokit/types": ^13.0.0 + checksum: e5608f848fb11808d0c977d946c24bffa622179daf8566c4941f6050551d368aa750b362a95aea14647facd0919e4af392c67b2409f8642dc9f27c7b6c0f964e languageName: node linkType: hard From 6a55e52ff3fafeec2a4fe3ca633dc206e0a85a25 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 23 Jul 2024 15:08:53 +0000 Subject: [PATCH 388/416] chore(deps): bump ws from 8.14.2 to 8.18.0 Bumps [ws](https://github.com/websockets/ws) from 8.14.2 to 8.18.0. - [Release notes](https://github.com/websockets/ws/releases) - [Commits](https://github.com/websockets/ws/compare/8.14.2...8.18.0) --- updated-dependencies: - dependency-name: ws dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 2b3baa5b33..82cc4670b4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -44887,8 +44887,8 @@ __metadata: linkType: hard "ws@npm:*, ws@npm:^8.11.0, ws@npm:^8.12.0, ws@npm:^8.13.0, ws@npm:^8.14.2, ws@npm:^8.16.0, ws@npm:^8.17.0, ws@npm:^8.8.0": - version: 8.17.1 - resolution: "ws@npm:8.17.1" + version: 8.18.0 + resolution: "ws@npm:8.18.0" peerDependencies: bufferutil: ^4.0.1 utf-8-validate: ">=5.0.2" @@ -44897,7 +44897,7 @@ __metadata: optional: true utf-8-validate: optional: true - checksum: 442badcce1f1178ec87a0b5372ae2e9771e07c4929a3180321901f226127f252441e8689d765aa5cfba5f50ac60dd830954afc5aeae81609aefa11d3ddf5cecf + checksum: 91d4d35bc99ff6df483bdf029b9ea4bfd7af1f16fc91231a96777a63d263e1eabf486e13a2353970efc534f9faa43bdbf9ee76525af22f4752cbc5ebda333975 languageName: node linkType: hard From e6c15cc3045ca5ea28d2f944018ee857ff6b216d Mon Sep 17 00:00:00 2001 From: Nurit Izrailov <nuriti@spotify.com> Date: Tue, 23 Jul 2024 11:33:26 -0400 Subject: [PATCH 389/416] add support to the new frontend system Signed-off-by: Nurit Izrailov <nuriti@spotify.com> --- .changeset/mean-apricots-perform.md | 5 + packages/app-next/app-config.yaml | 2 + packages/app-next/src/App.tsx | 2 + plugins/kubernetes/README.md | 32 ++++- plugins/kubernetes/api-report-alpha.md | 19 +++ plugins/kubernetes/package.json | 17 +++ plugins/kubernetes/src/alpha.ts | 18 +++ .../src/alpha/KubernetesContentPage.tsx | 24 ++++ plugins/kubernetes/src/alpha/apis.tsx | 119 ++++++++++++++++++ .../kubernetes/src/alpha/entityContents.tsx | 34 +++++ plugins/kubernetes/src/alpha/index.ts | 17 +++ plugins/kubernetes/src/alpha/pages.tsx | 33 +++++ plugins/kubernetes/src/alpha/plugin.tsx | 40 ++++++ yarn.lock | 2 + 14 files changed, 363 insertions(+), 1 deletion(-) create mode 100644 .changeset/mean-apricots-perform.md create mode 100644 plugins/kubernetes/api-report-alpha.md create mode 100644 plugins/kubernetes/src/alpha.ts create mode 100644 plugins/kubernetes/src/alpha/KubernetesContentPage.tsx create mode 100644 plugins/kubernetes/src/alpha/apis.tsx create mode 100644 plugins/kubernetes/src/alpha/entityContents.tsx create mode 100644 plugins/kubernetes/src/alpha/index.ts create mode 100644 plugins/kubernetes/src/alpha/pages.tsx create mode 100644 plugins/kubernetes/src/alpha/plugin.tsx diff --git a/.changeset/mean-apricots-perform.md b/.changeset/mean-apricots-perform.md new file mode 100644 index 0000000000..089a3ea7a4 --- /dev/null +++ b/.changeset/mean-apricots-perform.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-kubernetes': minor +--- + +Adds support for Backstage's new frontend system diff --git a/packages/app-next/app-config.yaml b/packages/app-next/app-config.yaml index 271040ecec..f6d0174ca1 100644 --- a/packages/app-next/app-config.yaml +++ b/packages/app-next/app-config.yaml @@ -43,6 +43,8 @@ app: - entity-card:org/ownership - entity-card:org/user-profile + - entity-content:kubernetes/kubernetes + # scmAuthExtension: >- # createScmAuthExtension({ # id: 'apis.scmAuth.addons.ghe', diff --git a/packages/app-next/src/App.tsx b/packages/app-next/src/App.tsx index c911a01258..303d751338 100644 --- a/packages/app-next/src/App.tsx +++ b/packages/app-next/src/App.tsx @@ -48,6 +48,7 @@ import { } from '@backstage/integration-react'; import { createSignInPageExtension } from '@backstage/frontend-plugin-api'; import { SignInPage } from '@backstage/core-components'; +import kubernetesPlugin from '@backstage/plugin-kubernetes/alpha'; /* @@ -121,6 +122,7 @@ const app = createApp({ userSettingsPlugin, homePlugin, appVisualizerPlugin, + kubernetesPlugin, ...collectedLegacyPlugins, createExtensionOverrides({ extensions: [ diff --git a/plugins/kubernetes/README.md b/plugins/kubernetes/README.md index 15dfd16b17..4ffde719f2 100644 --- a/plugins/kubernetes/README.md +++ b/plugins/kubernetes/README.md @@ -26,8 +26,38 @@ For more information, see the [formal documentation about the Kubernetes feature ## Getting started -Your plugin has been added to the example app in this repository, meaning you'll be able to access it by running `yarn start` in the root directory, and then navigating to [/kubernetes](http://localhost:3000/kubernetes). +Your plugin has been added to the example app in this repository, meaning you'll be able to access it by running `yarn start` in the root directory, and then navigating to [/kubernetes](http://localhost:3000/catalog/default/component/:component-name/kubernetes). You can also serve the plugin in isolation by running `yarn start` in the plugin directory. This method of serving the plugin provides quicker iteration speed and a faster startup and hot reloads. It is only meant for local development, and the setup for it can be found inside the [/dev](./dev) directory. + +### Integrating with `EntityPage` (New Frontend System) + +Follow this section if you are using Backstage's [new frontend system](https://backstage.io/docs/frontend-system/). + +1. Import `kubernetesPlugin` in your `App.tsx` and add it to your app's `features` array: + +```typescript +import kubernetesPlugin from '@backstage/plugin-kubernetes/alpha'; + +// ... + +export const app = createApp({ + features: [ + // ... + kubernetesPlugin, + // ... + ], +}); +``` + +2. Next, enable your desired extensions in `app-config.yaml` + +```yaml +app: + extensions: + - entity-content:kubernetes/kubernetes +``` + +Now, the extension appears on your entity page as one of the tabs, which is called `KUBERNETES` diff --git a/plugins/kubernetes/api-report-alpha.md b/plugins/kubernetes/api-report-alpha.md new file mode 100644 index 0000000000..8bd6e98baa --- /dev/null +++ b/plugins/kubernetes/api-report-alpha.md @@ -0,0 +1,19 @@ +## API Report File for "@backstage/plugin-kubernetes" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { BackstagePlugin } from '@backstage/frontend-plugin-api'; +import { RouteRef } from '@backstage/frontend-plugin-api'; + +// @public (undocumented) +const _default: BackstagePlugin< + { + kubernetes: RouteRef<undefined>; + }, + {} +>; +export default _default; + +// (No @packageDocumentation comment for this package) +``` diff --git a/plugins/kubernetes/package.json b/plugins/kubernetes/package.json index 1ab92f5b3c..6a66e42a94 100644 --- a/plugins/kubernetes/package.json +++ b/plugins/kubernetes/package.json @@ -30,8 +30,23 @@ }, "license": "Apache-2.0", "sideEffects": false, + "exports": { + ".": "./src/index.ts", + "./alpha": "./src/alpha.ts", + "./package.json": "./package.json" + }, "main": "src/index.ts", "types": "src/index.ts", + "typesVersions": { + "*": { + "alpha": [ + "src/alpha.ts" + ], + "package.json": [ + "package.json" + ] + } + }, "files": [ "dist" ], @@ -46,8 +61,10 @@ }, "dependencies": { "@backstage/catalog-model": "workspace:^", + "@backstage/core-compat-api": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", + "@backstage/frontend-plugin-api": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", "@backstage/plugin-kubernetes-common": "workspace:^", "@backstage/plugin-kubernetes-react": "workspace:^", diff --git a/plugins/kubernetes/src/alpha.ts b/plugins/kubernetes/src/alpha.ts new file mode 100644 index 0000000000..e80f131817 --- /dev/null +++ b/plugins/kubernetes/src/alpha.ts @@ -0,0 +1,18 @@ +/* + * 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 './alpha/index'; +export { default } from './alpha/index'; diff --git a/plugins/kubernetes/src/alpha/KubernetesContentPage.tsx b/plugins/kubernetes/src/alpha/KubernetesContentPage.tsx new file mode 100644 index 0000000000..948a492e63 --- /dev/null +++ b/plugins/kubernetes/src/alpha/KubernetesContentPage.tsx @@ -0,0 +1,24 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { useEntity } from '@backstage/plugin-catalog-react'; +import { KubernetesContent } from '../KubernetesContent'; +import React from 'react'; + +export function KubernetesContentPage() { + const { entity } = useEntity(); + return <KubernetesContent entity={entity} />; +} diff --git a/plugins/kubernetes/src/alpha/apis.tsx b/plugins/kubernetes/src/alpha/apis.tsx new file mode 100644 index 0000000000..6c880d2f53 --- /dev/null +++ b/plugins/kubernetes/src/alpha/apis.tsx @@ -0,0 +1,119 @@ +/* + * Copyright 2024 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 { + createApiExtension, + createApiFactory, + discoveryApiRef, + fetchApiRef, +} from '@backstage/frontend-plugin-api'; +import { + KubernetesBackendClient, + kubernetesApiRef, + kubernetesProxyApiRef, + kubernetesAuthProvidersApiRef, + KubernetesAuthProviders, + KubernetesProxyClient, + kubernetesClusterLinkFormatterApiRef, + getDefaultFormatters, + KubernetesClusterLinkFormatter, + DEFAULT_FORMATTER_NAME, +} from '@backstage/plugin-kubernetes-react'; +import { + gitlabAuthApiRef, + googleAuthApiRef, + microsoftAuthApiRef, + oktaAuthApiRef, + oneloginAuthApiRef, +} from '@backstage/core-plugin-api'; + +export const kubernetesApiExtension = createApiExtension({ + factory: createApiFactory({ + api: kubernetesApiRef, + deps: { + discoveryApi: discoveryApiRef, + fetchApi: fetchApiRef, + kubernetesAuthProvidersApi: kubernetesAuthProvidersApiRef, + }, + factory: ({ discoveryApi, fetchApi, kubernetesAuthProvidersApi }) => + new KubernetesBackendClient({ + discoveryApi, + fetchApi, + kubernetesAuthProvidersApi, + }), + }), +}); + +export const kubernetesProxyApi = createApiExtension({ + factory: createApiFactory({ + api: kubernetesProxyApiRef, + deps: { + kubernetesApi: kubernetesApiRef, + }, + factory: ({ kubernetesApi }) => + new KubernetesProxyClient({ + kubernetesApi, + }), + }), +}); + +export const kubernetesAuthProvidersApi = createApiExtension({ + factory: createApiFactory({ + api: kubernetesAuthProvidersApiRef, + deps: { + gitlabAuthApi: gitlabAuthApiRef, + googleAuthApi: googleAuthApiRef, + microsoftAuthApi: microsoftAuthApiRef, + oktaAuthApi: oktaAuthApiRef, + oneloginAuthApi: oneloginAuthApiRef, + }, + factory: ({ + gitlabAuthApi, + googleAuthApi, + microsoftAuthApi, + oktaAuthApi, + oneloginAuthApi, + }) => { + const oidcProviders = { + gitlab: gitlabAuthApi, + google: googleAuthApi, + microsoft: microsoftAuthApi, + okta: oktaAuthApi, + onelogin: oneloginAuthApi, + }; + + return new KubernetesAuthProviders({ + microsoftAuthApi, + googleAuthApi, + oidcProviders, + }); + }, + }), +}); + +export const kubernetesClusterLinkFormatterApi = createApiExtension({ + factory: createApiFactory({ + api: kubernetesClusterLinkFormatterApiRef, + deps: { googleAuthApi: googleAuthApiRef }, + factory: deps => { + const formatters = getDefaultFormatters(deps); + return new KubernetesClusterLinkFormatter({ + formatters, + defaultFormatterName: DEFAULT_FORMATTER_NAME, + }); + }, + }), +}); diff --git a/plugins/kubernetes/src/alpha/entityContents.tsx b/plugins/kubernetes/src/alpha/entityContents.tsx new file mode 100644 index 0000000000..9ad0b6843f --- /dev/null +++ b/plugins/kubernetes/src/alpha/entityContents.tsx @@ -0,0 +1,34 @@ +/* + * Copyright 2024 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 { + compatWrapper, + convertLegacyRouteRef, +} from '@backstage/core-compat-api'; +import { createEntityContentExtension } from '@backstage/plugin-catalog-react/alpha'; +import { rootCatalogKubernetesRouteRef } from '../plugin'; + +export const entityKubernetesContent = createEntityContentExtension({ + defaultPath: 'kubernetes', + defaultTitle: 'Kubernetes', + name: 'kubernetes', + routeRef: convertLegacyRouteRef(rootCatalogKubernetesRouteRef), + loader: () => + import('./KubernetesContentPage').then(m => + compatWrapper(<m.KubernetesContentPage />), + ), +}); diff --git a/plugins/kubernetes/src/alpha/index.ts b/plugins/kubernetes/src/alpha/index.ts new file mode 100644 index 0000000000..2f137f09ee --- /dev/null +++ b/plugins/kubernetes/src/alpha/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 { default } from './plugin'; diff --git a/plugins/kubernetes/src/alpha/pages.tsx b/plugins/kubernetes/src/alpha/pages.tsx new file mode 100644 index 0000000000..8b5db150bd --- /dev/null +++ b/plugins/kubernetes/src/alpha/pages.tsx @@ -0,0 +1,33 @@ +/* + * Copyright 2024 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'; // Add this line to import React + +import { createPageExtension } from '@backstage/frontend-plugin-api'; +import { + compatWrapper, + convertLegacyRouteRef, +} from '@backstage/core-compat-api'; +import { rootCatalogKubernetesRouteRef } from '../plugin'; + +export const kubernetesPage = createPageExtension({ + defaultPath: '/kubernetes', + // you can reuse the existing routeRef + // by wrapping into the convertLegacyRouteRef. + routeRef: convertLegacyRouteRef(rootCatalogKubernetesRouteRef), + // these inputs usually match the props required by the component. + loader: () => import('../Router').then(m => compatWrapper(<m.Router />)), +}); diff --git a/plugins/kubernetes/src/alpha/plugin.tsx b/plugins/kubernetes/src/alpha/plugin.tsx new file mode 100644 index 0000000000..47433bce35 --- /dev/null +++ b/plugins/kubernetes/src/alpha/plugin.tsx @@ -0,0 +1,40 @@ +/* + * Copyright 2024 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 { convertLegacyRouteRefs } from '@backstage/core-compat-api'; +import { createPlugin } from '@backstage/frontend-plugin-api'; +import { kubernetesPage } from './pages'; +import { entityKubernetesContent } from './entityContents'; +import { rootCatalogKubernetesRouteRef } from '../plugin'; +import { + kubernetesApiExtension as kubernetesApi, + kubernetesAuthProvidersApi, + kubernetesClusterLinkFormatterApi, + kubernetesProxyApi, +} from './apis'; + +export default createPlugin({ + id: 'kubernetes', + extensions: [ + kubernetesPage, + entityKubernetesContent, + kubernetesApi, + kubernetesProxyApi, + kubernetesAuthProvidersApi, + kubernetesClusterLinkFormatterApi, + ], + routes: convertLegacyRouteRefs({ kubernetes: rootCatalogKubernetesRouteRef }), +}); diff --git a/yarn.lock b/yarn.lock index b63d8d7d63..ed5486f498 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6307,9 +6307,11 @@ __metadata: dependencies: "@backstage/catalog-model": "workspace:^" "@backstage/cli": "workspace:^" + "@backstage/core-compat-api": "workspace:^" "@backstage/core-components": "workspace:^" "@backstage/core-plugin-api": "workspace:^" "@backstage/dev-utils": "workspace:^" + "@backstage/frontend-plugin-api": "workspace:^" "@backstage/plugin-catalog-react": "workspace:^" "@backstage/plugin-kubernetes-common": "workspace:^" "@backstage/plugin-kubernetes-react": "workspace:^" From d31aa860eb6c2474e945b337181422507ceeb970 Mon Sep 17 00:00:00 2001 From: Nurit Izrailov <38442135+nuritizra@users.noreply.github.com> Date: Tue, 23 Jul 2024 13:41:14 -0400 Subject: [PATCH 390/416] Update .changeset/mean-apricots-perform.md Co-authored-by: Patrik Oldsberg <poldsberg@gmail.com> Signed-off-by: Nurit Izrailov <38442135+nuritizra@users.noreply.github.com> --- .changeset/mean-apricots-perform.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/mean-apricots-perform.md b/.changeset/mean-apricots-perform.md index 089a3ea7a4..26e547086e 100644 --- a/.changeset/mean-apricots-perform.md +++ b/.changeset/mean-apricots-perform.md @@ -1,5 +1,5 @@ --- -'@backstage/plugin-kubernetes': minor +'@backstage/plugin-kubernetes': patch --- Adds support for Backstage's new frontend system From 9397e8f175a0310d68b3be26c70db2fe137f4fe9 Mon Sep 17 00:00:00 2001 From: Nurit Izrailov <38442135+nuritizra@users.noreply.github.com> Date: Tue, 23 Jul 2024 13:41:22 -0400 Subject: [PATCH 391/416] Update .changeset/mean-apricots-perform.md Co-authored-by: Patrik Oldsberg <poldsberg@gmail.com> Signed-off-by: Nurit Izrailov <38442135+nuritizra@users.noreply.github.com> --- .changeset/mean-apricots-perform.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/mean-apricots-perform.md b/.changeset/mean-apricots-perform.md index 26e547086e..c93514cb7f 100644 --- a/.changeset/mean-apricots-perform.md +++ b/.changeset/mean-apricots-perform.md @@ -2,4 +2,4 @@ '@backstage/plugin-kubernetes': patch --- -Adds support for Backstage's new frontend system +Adds support for Backstage's new frontend system, available via the `/alpha` sub-path export. From 949083ddb41067368bc3638303683e1340614563 Mon Sep 17 00:00:00 2001 From: Isabel Tomb <isabelgtomb@gmail.com> Date: Mon, 8 Jul 2024 13:03:39 -0500 Subject: [PATCH 392/416] Update `patchMkdocsYmlPreBuild` Update the `patchMkdocsYmlPreBuild` function to modify `repo_url` and `edit_uri` independently of each other. Prior to this change both `repo_url` and `edit_uri` would have to be missing for either to be generated which caused an issue in the situation where `repo_url` is provided in the mkdocs.yml and `edit_uri` is not because the default `edit_uri` value from mkdocs would be used instead. This value uses `master` as the branch in the link which breaks the edit link for repos that don't use `master` as the default branch. Signed-off-by: Isabel Tomb <isabelgtomb@gmail.com> --- .changeset/mighty-geckos-kiss.md | 5 +++++ plugins/techdocs-node/src/stages/generate/mkdocsPatchers.ts | 6 +++--- 2 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 .changeset/mighty-geckos-kiss.md diff --git a/.changeset/mighty-geckos-kiss.md b/.changeset/mighty-geckos-kiss.md new file mode 100644 index 0000000000..0761d8b257 --- /dev/null +++ b/.changeset/mighty-geckos-kiss.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs-node': patch +--- + +Update `patchMkdocsYmlPrebuild` to modify `repo_url` and `edit_uri` independently. diff --git a/plugins/techdocs-node/src/stages/generate/mkdocsPatchers.ts b/plugins/techdocs-node/src/stages/generate/mkdocsPatchers.ts index 762a1c267a..fb95c19a9c 100644 --- a/plugins/techdocs-node/src/stages/generate/mkdocsPatchers.ts +++ b/plugins/techdocs-node/src/stages/generate/mkdocsPatchers.ts @@ -108,7 +108,7 @@ export const patchMkdocsYmlPreBuild = async ( scmIntegrations: ScmIntegrationRegistry, ) => { await patchMkdocsFile(mkdocsYmlPath, logger, mkdocsYml => { - if (!('repo_url' in mkdocsYml) && !('edit_uri' in mkdocsYml)) { + if (!('repo_url' in mkdocsYml) || !('edit_uri' in mkdocsYml)) { // Add edit_uri and/or repo_url to mkdocs.yml if it is missing. // This will enable the Page edit button generated by MkDocs. // If the either has been set, keep the original value @@ -119,8 +119,8 @@ export const patchMkdocsYmlPreBuild = async ( ); if (result.repo_url || result.edit_uri) { - mkdocsYml.repo_url = result.repo_url; - mkdocsYml.edit_uri = result.edit_uri; + mkdocsYml.repo_url = mkdocsYml.repo_url || result.repo_url; + mkdocsYml.edit_uri = mkdocsYml.edit_uri || result.edit_uri; logger.info( `Set ${JSON.stringify( From 839e888e3a7e348b200cb6eeda68b782a12e782c Mon Sep 17 00:00:00 2001 From: Isabel Tomb <isabelgtomb@gmail.com> Date: Mon, 8 Jul 2024 13:44:01 -0500 Subject: [PATCH 393/416] Add a test for new repo_url edit_uri scenario Add a test that checks that an edit_uri will be generated as expected if the mkdocs.yml contains a `repo_url` value but no `edit_uri` vlaue. Signed-off-by: Isabel Tomb <isabelgtomb@gmail.com> --- .../src/stages/generate/helpers.test.ts | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/plugins/techdocs-node/src/stages/generate/helpers.test.ts b/plugins/techdocs-node/src/stages/generate/helpers.test.ts index 3589b71c60..a40239c595 100644 --- a/plugins/techdocs-node/src/stages/generate/helpers.test.ts +++ b/plugins/techdocs-node/src/stages/generate/helpers.test.ts @@ -299,6 +299,31 @@ describe('helpers', () => { ); }); + it('should add edit_uri to mkdocs.yml with existing repo_url', async () => { + const parsedLocationAnnotation: ParsedLocationAnnotation = { + type: 'url', + target: 'https://github.com/neworg/newrepo/tree/main/', + }; + + await patchMkdocsYmlPreBuild( + mockDir.resolve('mkdocs_with_repo_url.yml'), + mockLogger, + parsedLocationAnnotation, + scmIntegrations, + ); + + const updatedMkdocsYml = await fs.readFile( + mockDir.resolve('mkdocs_with_repo_url.yml'), + ); + + expect(updatedMkdocsYml.toString()).toContain( + 'edit_uri: https://github.com/neworg/newrepo/edit/main/docs', + ); + expect(updatedMkdocsYml.toString()).toContain( + 'repo_url: https://github.com/backstage/backstage', + ); + }); + it('should not update mkdocs.yml if nothing should be changed', async () => { const parsedLocationAnnotation: ParsedLocationAnnotation = { type: 'dir', From 0afa044555655e07f9e31d3eceb32c2177a0c1db Mon Sep 17 00:00:00 2001 From: Isabel Tomb <isabelgtomb@gmail.com> Date: Mon, 8 Jul 2024 13:45:50 -0500 Subject: [PATCH 394/416] Update test Update the test that checks that the existing edit_uri value in a mkdocs.yml won't be overridden by `patchMkdocsYmlPreBuild` so that it checks the value of 'edit_uri' was not updated rather than just checking for the existence of the substring. This change is needed because the substring will exist in the file but as the `repo_url` value which is expected after the changes in the previous commits. Signed-off-by: Isabel Tomb <isabelgtomb@gmail.com> --- plugins/techdocs-node/src/stages/generate/helpers.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/techdocs-node/src/stages/generate/helpers.test.ts b/plugins/techdocs-node/src/stages/generate/helpers.test.ts index a40239c595..6ee3870845 100644 --- a/plugins/techdocs-node/src/stages/generate/helpers.test.ts +++ b/plugins/techdocs-node/src/stages/generate/helpers.test.ts @@ -295,7 +295,7 @@ describe('helpers', () => { 'edit_uri: https://github.com/backstage/backstage/edit/main/docs', ); expect(updatedMkdocsYml.toString()).not.toContain( - 'https://github.com/neworg/newrepo', + 'edit_uri: https://github.com/neworg/newrepo', ); }); From def53a7f9606550b5cd68744b8c11ab3c8a7cba0 Mon Sep 17 00:00:00 2001 From: Mikko Korhonen <mikko.korhonen@op.fi> Date: Wed, 24 Jul 2024 12:30:55 +0300 Subject: [PATCH 395/416] Change NotificationTemplateRenderer methods to return a promise Signed-off-by: Mikko Korhonen <mikko.korhonen@op.fi> --- .changeset/spicy-planets-provide.md | 46 +++++++++++++++++++ .../api-report.md | 6 +-- .../src/extensions.ts | 6 +-- .../processor/NotificationsEmailProcessor.ts | 6 +-- 4 files changed, 55 insertions(+), 9 deletions(-) create mode 100644 .changeset/spicy-planets-provide.md diff --git a/.changeset/spicy-planets-provide.md b/.changeset/spicy-planets-provide.md new file mode 100644 index 0000000000..f2929df850 --- /dev/null +++ b/.changeset/spicy-planets-provide.md @@ -0,0 +1,46 @@ +--- +'@backstage/plugin-notifications-backend-module-email': minor +--- + +**BREAKING** Following `NotificationTemplateRenderer` methods now return a Promise and **must** be awaited: `getSubject`, `getText` and `getHtml`. + +Required changes and example usage: + +```diff +import { notificationsEmailTemplateExtensionPoint } from '@backstage/plugin-notifications-backend-module-email'; +import { Notification } from '@backstage/plugin-notifications-common'; ++import { getNotificationSubject, getNotificationTextContent, getNotificationHtmlContent } from 'my-notification-processing-library` +export const notificationsModuleEmailDecorator = createBackendModule({ + pluginId: 'notifications', + moduleId: 'email.templates', + register(reg) { + reg.registerInit({ + deps: { + emailTemplates: notificationsEmailTemplateExtensionPoint, + }, + async init({ emailTemplates }) { + emailTemplates.setTemplateRenderer({ +- getSubject(notification) { ++ async getSubject(notification) { +- return `New notification from ${notification.source}`; ++ const subject = await getNotificationSubject(notification); ++ return `New notification from ${subject}`; + }, +- getText(notification) { ++ async getText(notification) { +- return notification.content; ++ const text = await getNotificationTextContent(notification); ++ return text; + }, +- getHtml(notification) { ++ async getHtml(notification) { +- return `<p>${notification.content}</p>`; ++ const html = await getNotificationHtmlContent(notification); ++ return html; + }, + }); + }, + }); + }, +}); +``` diff --git a/plugins/notifications-backend-module-email/api-report.md b/plugins/notifications-backend-module-email/api-report.md index 7e8eac6cb7..b105f15cba 100644 --- a/plugins/notifications-backend-module-email/api-report.md +++ b/plugins/notifications-backend-module-email/api-report.md @@ -23,10 +23,10 @@ export default notificationsModuleEmail; // @public (undocumented) export interface NotificationTemplateRenderer { // (undocumented) - getHtml?(notification: Notification_2): string; + getHtml?(notification: Notification_2): Promise<string>; // (undocumented) - getSubject?(notification: Notification_2): string; + getSubject?(notification: Notification_2): Promise<string>; // (undocumented) - getText?(notification: Notification_2): string; + getText?(notification: Notification_2): Promise<string>; } ``` diff --git a/plugins/notifications-backend-module-email/src/extensions.ts b/plugins/notifications-backend-module-email/src/extensions.ts index 454fe9b384..49795eadcf 100644 --- a/plugins/notifications-backend-module-email/src/extensions.ts +++ b/plugins/notifications-backend-module-email/src/extensions.ts @@ -20,9 +20,9 @@ import { Notification } from '@backstage/plugin-notifications-common'; * @public */ export interface NotificationTemplateRenderer { - getSubject?(notification: Notification): string; - getText?(notification: Notification): string; - getHtml?(notification: Notification): string; + getSubject?(notification: Notification): Promise<string>; + getText?(notification: Notification): Promise<string>; + getHtml?(notification: Notification): Promise<string>; } /** diff --git a/plugins/notifications-backend-module-email/src/processor/NotificationsEmailProcessor.ts b/plugins/notifications-backend-module-email/src/processor/NotificationsEmailProcessor.ts index 8689afc065..3bfccfcc90 100644 --- a/plugins/notifications-backend-module-email/src/processor/NotificationsEmailProcessor.ts +++ b/plugins/notifications-backend-module-email/src/processor/NotificationsEmailProcessor.ts @@ -280,10 +280,10 @@ export class NotificationsEmailProcessor implements NotificationProcessor { const mailOptions = { from: this.sender, subject: - this.templateRenderer?.getSubject?.(notification) ?? + (await this.templateRenderer?.getSubject?.(notification)) ?? notification.payload.title, - html: this.templateRenderer?.getHtml?.(notification), - text: this.templateRenderer?.getText?.(notification), + html: await this.templateRenderer?.getHtml?.(notification), + text: await this.templateRenderer?.getText?.(notification), replyTo: this.replyTo, }; From 7ca331cc2b07c4ee221c689493025f3c5881b975 Mon Sep 17 00:00:00 2001 From: Thomas Cardonne <thomas.cardonne@adevinta.com> Date: Wed, 24 Jul 2024 11:45:51 +0200 Subject: [PATCH 396/416] feat(catalog-react): correct alignment of EntityDisplayName's icon Signed-off-by: Thomas Cardonne <thomas.cardonne@adevinta.com> --- .changeset/few-wasps-hug.md | 5 +++++ .../src/components/EntityDisplayName/EntityDisplayName.tsx | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 .changeset/few-wasps-hug.md diff --git a/.changeset/few-wasps-hug.md b/.changeset/few-wasps-hug.md new file mode 100644 index 0000000000..66cf34fc0b --- /dev/null +++ b/.changeset/few-wasps-hug.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-react': patch +--- + +Correct `EntityDisplayName`'s icon alignment with the text. diff --git a/plugins/catalog-react/src/components/EntityDisplayName/EntityDisplayName.tsx b/plugins/catalog-react/src/components/EntityDisplayName/EntityDisplayName.tsx index e953f21afb..68d5ecefdb 100644 --- a/plugins/catalog-react/src/components/EntityDisplayName/EntityDisplayName.tsx +++ b/plugins/catalog-react/src/components/EntityDisplayName/EntityDisplayName.tsx @@ -38,7 +38,9 @@ const useStyles = makeStyles( icon: { marginRight: theme.spacing(0.5), color: theme.palette.text.secondary, - lineHeight: 0, + '& svg': { + verticalAlign: 'middle', + }, }, }), { name: 'CatalogReactEntityDisplayName' }, From 21b66b184dc88f744c69ead1744f4b4d5de4ff0a Mon Sep 17 00:00:00 2001 From: blam <ben@blam.sh> Date: Tue, 23 Jul 2024 12:37:43 +0200 Subject: [PATCH 397/416] chore: initial experiments Signed-off-by: blam <ben@blam.sh> wip Signed-off-by: blam <ben@blam.sh> wip2 Signed-off-by: blam <ben@blam.sh> wip3 Signed-off-by: blam <ben@blam.sh> wip3 Signed-off-by: blam <ben@blam.sh> --- packages/frontend-plugin-api/api-report.md | 41 ++++++--- .../src/extensions/IconBundleBlueprint.ts | 36 ++++++++ .../src/wiring/createExtension.ts | 18 +++- .../src/wiring/createExtensionBlueprint.ts | 92 ++++++++++++++----- .../src/app/createExtensionTester.tsx | 4 +- plugins/catalog-graph/api-report-alpha.md | 72 +++++++++++++++ plugins/catalog-graph/src/alpha.tsx | 79 ++++++++++++---- plugins/catalog-react/api-report-alpha.md | 56 +++++++++-- plugins/catalog-react/src/alpha.tsx | 51 ++++++++++ plugins/catalog/api-report-alpha.md | 35 ++++++- plugins/catalog/src/alpha/index.ts | 2 + plugins/search-react/api-report-alpha.md | 3 +- plugins/search/api-report-alpha.md | 26 ++++-- plugins/techdocs/api-report-alpha.md | 18 ++-- plugins/user-settings/api-report-alpha.md | 10 +- 15 files changed, 456 insertions(+), 87 deletions(-) diff --git a/packages/frontend-plugin-api/api-report.md b/packages/frontend-plugin-api/api-report.md index d6a91c0c99..0c7c3b1d92 100644 --- a/packages/frontend-plugin-api/api-report.md +++ b/packages/frontend-plugin-api/api-report.md @@ -89,6 +89,7 @@ import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; import { vmwareCloudAuthApiRef } from '@backstage/core-plugin-api'; import { withApis } from '@backstage/core-plugin-api'; import { z } from 'zod'; +import { ZodObject } from 'zod'; import { ZodSchema } from 'zod'; import { ZodTypeDef } from 'zod'; @@ -391,7 +392,7 @@ export function createApiExtension< configSchema?: PortableSchema<TConfig>; inputs?: TInputs; }, -): ExtensionDefinition<TConfig>; +): ExtensionDefinition<TConfig, ZodObject<any, any, any, any, any>>; // @public (undocumented) export namespace createApiExtension { @@ -487,7 +488,7 @@ export function createComponentExtension< inputs: Expand<ResolvedExtensionInputs<TInputs>>; }) => ComponentType<TProps>; }; -}): ExtensionDefinition<TConfig>; +}): ExtensionDefinition<TConfig, ZodObject<any, any, any, any, any>>; // @public (undocumented) export namespace createComponentExtension { @@ -511,10 +512,11 @@ export function createComponentRef<T extends {} = {}>(options: { export function createExtension< TOutput extends AnyExtensionDataMap, TInputs extends AnyExtensionInputMap, - TConfig = never, + TConfigSchema extends z.ZodObject<any, any, any, any, any>, + TConfig extends z.infer<TConfigSchema>, >( - options: CreateExtensionOptions<TOutput, TInputs, TConfig>, -): ExtensionDefinition<TConfig>; + options: CreateExtensionOptions<TOutput, TInputs, TConfigSchema, TConfig>, +): ExtensionDefinition<TConfig, TConfigSchema>; // @public export function createExtensionBlueprint< @@ -605,7 +607,8 @@ export function createExtensionInput< export interface CreateExtensionOptions< TOutput extends AnyExtensionDataMap, TInputs extends AnyExtensionInputMap, - TConfig, + TConfigSchema extends z.ZodObject<any, any, any, any, any>, + TConfig extends z.infer<TConfigSchema>, > { // (undocumented) attachTo: { @@ -613,6 +616,10 @@ export interface CreateExtensionOptions< input: string; }; // (undocumented) + config?: { + schema: (context: { z: typeof z }) => TConfigSchema; + }; + // @deprecated (undocumented) configSchema?: PortableSchema<TConfig>; // (undocumented) disabled?: boolean; @@ -672,9 +679,12 @@ export function createNavItemExtension(options: { routeRef: RouteRef<undefined>; title: string; icon: IconComponent_2; -}): ExtensionDefinition<{ - title: string; -}>; +}): ExtensionDefinition< + { + title: string; + }, + ZodObject<any, any, any, any, any> +>; // @public (undocumented) export namespace createNavItemExtension { @@ -696,7 +706,7 @@ export function createNavLogoExtension(options: { namespace?: string; logoIcon: JSX.Element; logoFull: JSX.Element; -}): ExtensionDefinition<never>; +}): ExtensionDefinition<any, ZodObject<any, any, any, any, any>>; // @public (undocumented) export namespace createNavLogoExtension { @@ -851,7 +861,7 @@ export function createSubRouteRef< // @public (undocumented) export function createThemeExtension( theme: AppTheme, -): ExtensionDefinition<never>; +): ExtensionDefinition<any, ZodObject<any, any, any, any, any>>; // @public (undocumented) export namespace createThemeExtension { @@ -867,7 +877,7 @@ export namespace createThemeExtension { export function createTranslationExtension(options: { name?: string; resource: TranslationResource | TranslationMessages; -}): ExtensionDefinition<never>; +}): ExtensionDefinition<any, ZodObject<any, any, any, any, any>>; // @public (undocumented) export namespace createTranslationExtension { @@ -1011,7 +1021,10 @@ export type ExtensionDataValues<TExtensionData extends AnyExtensionDataMap> = { }; // @public (undocumented) -export interface ExtensionDefinition<TConfig> { +export interface ExtensionDefinition< + TConfig, + TConfigSchema extends z.ZodObject<any, any, any, any, any> = any, +> { // (undocumented) $$type: '@backstage/ExtensionDefinition'; // (undocumented) @@ -1022,6 +1035,8 @@ export interface ExtensionDefinition<TConfig> { // (undocumented) readonly configSchema?: PortableSchema<TConfig>; // (undocumented) + readonly configSchema2?: TConfigSchema; + // (undocumented) readonly disabled: boolean; // (undocumented) readonly kind?: string; diff --git a/packages/frontend-plugin-api/src/extensions/IconBundleBlueprint.ts b/packages/frontend-plugin-api/src/extensions/IconBundleBlueprint.ts index 2ad1404102..aba3303f2f 100644 --- a/packages/frontend-plugin-api/src/extensions/IconBundleBlueprint.ts +++ b/packages/frontend-plugin-api/src/extensions/IconBundleBlueprint.ts @@ -33,3 +33,39 @@ export const IconBundleBlueprint = createExtensionBlueprint({ icons: iconsDataRef, }, }); + +IconBundleBlueprint.make({ + name: 'asd', + params: { + icons: { + 'icon-name': () => null, + }, + }, +}); + +IconBundleBlueprint.make({ + name: 'asd', + params: { + icons: { + 'icon-name': () => null, + }, + }, +}); + +IconBundleBlueprint.make({ + name: 'asd', + factory() { + return { + icons: { + 'icon-name': () => null, + }, + }; + }, +}); + +IconBundleBlueprint.make({ + name: 'asd', + factory(f) { + return f({ icons: { 'icon-name': () => null } }); + }, +}); diff --git a/packages/frontend-plugin-api/src/wiring/createExtension.ts b/packages/frontend-plugin-api/src/wiring/createExtension.ts index e87f3a638e..3733e44957 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtension.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtension.ts @@ -19,7 +19,7 @@ import { PortableSchema } from '../schema'; import { Expand } from '../types'; import { ExtensionDataRef } from './createExtensionDataRef'; import { ExtensionInput } from './createExtensionInput'; - +import { z } from 'zod'; /** @public */ export type AnyExtensionDataMap = { [name in string]: ExtensionDataRef<unknown, string, { optional?: true }>; @@ -82,6 +82,7 @@ export interface CreateExtensionOptions< TOutput extends AnyExtensionDataMap, TInputs extends AnyExtensionInputMap, TConfig, + TConfigSchema extends { [key: string]: (zImpl: typeof z) => z.ZodTypeAny }, > { kind?: string; namespace?: string; @@ -90,7 +91,11 @@ export interface CreateExtensionOptions< disabled?: boolean; inputs?: TInputs; output: TOutput; + /** @deprecated - use `config.schema` instead */ configSchema?: PortableSchema<TConfig>; + config?: { + schema: TConfigSchema; + }; factory(context: { node: AppNode; config: TConfig; @@ -99,7 +104,7 @@ export interface CreateExtensionOptions< } /** @public */ -export interface ExtensionDefinition<TConfig> { +export interface ExtensionDefinition<TConfig, TConfigSchema = {}> { $$type: '@backstage/ExtensionDefinition'; readonly kind?: string; readonly namespace?: string; @@ -107,6 +112,9 @@ export interface ExtensionDefinition<TConfig> { readonly attachTo: { id: string; input: string }; readonly disabled: boolean; readonly configSchema?: PortableSchema<TConfig>; + readonly config?: { + schema: TConfigSchema; + }; } /** @internal */ @@ -144,9 +152,10 @@ export function toInternalExtensionDefinition<TConfig>( export function createExtension< TOutput extends AnyExtensionDataMap, TInputs extends AnyExtensionInputMap, - TConfig = never, + TConfig, + TConfigSchema extends { [key: string]: (zImpl: typeof z) => z.ZodTypeAny }, >( - options: CreateExtensionOptions<TOutput, TInputs, TConfig>, + options: CreateExtensionOptions<TOutput, TInputs, TConfig, TConfigSchema>, ): ExtensionDefinition<TConfig> { return { $$type: '@backstage/ExtensionDefinition', @@ -159,6 +168,7 @@ export function createExtension< inputs: options.inputs ?? {}, output: options.output, configSchema: options.configSchema, + config: options.config, factory({ inputs, ...rest }) { // TODO: Simplify this, but TS wouldn't infer the input type for some reason return options.factory({ diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts index fb9081f7f8..61227c7dc1 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts @@ -15,7 +15,6 @@ */ import { AppNode } from '../apis'; -import { PortableSchema } from '../schema'; import { Expand } from '../types'; import { AnyExtensionDataMap, @@ -25,6 +24,7 @@ import { ResolvedExtensionInputs, createExtension, } from './createExtension'; +import { z } from 'zod'; /** * @public @@ -33,7 +33,7 @@ export interface CreateExtensionBlueprintOptions< TParams, TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, - TConfig, + TConfigSchema extends { [key: string]: (zImpl: typeof z) => z.ZodTypeAny }, TDataRefs extends AnyExtensionDataMap, > { kind: string; @@ -42,12 +42,16 @@ export interface CreateExtensionBlueprintOptions< disabled?: boolean; inputs?: TInputs; output: TOutput; - configSchema?: PortableSchema<TConfig>; + config?: { + schema: TConfigSchema; + }; factory( params: TParams, context: { node: AppNode; - config: TConfig; + config: { + [key in keyof TConfigSchema]: z.infer<ReturnType<TConfigSchema[key]>>; + }; inputs: Expand<ResolvedExtensionInputs<TInputs>>; }, ): Expand<ExtensionDataValues<TOutput>>; @@ -62,7 +66,7 @@ export interface ExtensionBlueprint< TParams, TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, - TConfig, + TConfigSchema extends { [key: string]: (zImpl: typeof z) => z.ZodTypeAny }, TDataRefs extends AnyExtensionDataMap, > { dataRefs: TDataRefs; @@ -73,7 +77,11 @@ export interface ExtensionBlueprint< * You must either pass `params` directly, or define a `factory` that can * optionally call the original factory with the same params. */ - make( + make< + TExtensionConfigSchema extends { + [key: string]: (zImpl: typeof z) => z.ZodTypeAny; + }, + >( args: { namespace?: string; name?: string; @@ -81,20 +89,30 @@ export interface ExtensionBlueprint< disabled?: boolean; inputs?: TInputs; output?: TOutput; - configSchema?: PortableSchema<TConfig>; + config?: { + schema: TExtensionConfigSchema; + }; } & ( | { factory( originalFactory: ( params: TParams, context?: { - config?: TConfig; + config?: { + [key in keyof TConfigSchema]: z.infer< + ReturnType<TConfigSchema[key]> + >; + }; inputs?: Expand<ResolvedExtensionInputs<TInputs>>; }, ) => Expand<ExtensionDataValues<TOutput>>, context: { node: AppNode; - config: TConfig; + config: { + [key in keyof TExtensionConfigSchema]: z.infer< + ReturnType<TExtensionConfigSchema[key]> + >; + }; inputs: Expand<ResolvedExtensionInputs<TInputs>>; }, ): Expand<ExtensionDataValues<TOutput>>; @@ -103,7 +121,14 @@ export interface ExtensionBlueprint< params: TParams; } ), - ): ExtensionDefinition<TConfig>; + ): ExtensionDefinition< + { + [key in keyof TExtensionConfigSchema]: z.infer< + ReturnType<TExtensionConfigSchema[key]> + >; + }, + TExtensionConfigSchema + >; } /** @@ -113,7 +138,7 @@ class ExtensionBlueprintImpl< TParams, TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, - TConfig, + TConfigSchema extends { [key: string]: (zImpl: typeof z) => z.ZodTypeAny }, TDataRefs extends AnyExtensionDataMap, > { constructor( @@ -121,7 +146,7 @@ class ExtensionBlueprintImpl< TParams, TInputs, TOutput, - TConfig, + TConfigSchema, TDataRefs >, ) { @@ -130,30 +155,49 @@ class ExtensionBlueprintImpl< dataRefs: TDataRefs; - public make(args: { + public make< + TExtensionConfigSchema extends TConfigSchema = TConfigSchema, + >(args: { namespace?: string; name?: string; attachTo?: { id: string; input: string }; disabled?: boolean; inputs?: TInputs; output?: TOutput; - configSchema?: PortableSchema<TConfig>; params?: TParams; + config?: { + schema: TConfigSchema; + }; factory?( originalFactory: ( params: TParams, context?: { - config?: TConfig; + config?: { + [key in keyof TConfigSchema]: z.infer< + ReturnType<TConfigSchema[key]> + >; + }; inputs?: Expand<ResolvedExtensionInputs<TInputs>>; }, ) => Expand<ExtensionDataValues<TOutput>>, context: { node: AppNode; - config: TConfig; + config: { + [key in keyof TExtensionConfigSchema]: z.infer< + ReturnType<TExtensionConfigSchema[key]> + >; + }; inputs: Expand<ResolvedExtensionInputs<TInputs>>; }, ): Expand<ExtensionDataValues<TOutput>>; - }): ExtensionDefinition<TConfig> { + }): ExtensionDefinition< + { + [key in keyof TExtensionConfigSchema]: z.infer< + ReturnType<TExtensionConfigSchema[key]> + >; + }, + TExtensionConfigSchema + > { return createExtension({ kind: this.options.kind, namespace: args.namespace ?? this.options.namespace, @@ -162,14 +206,18 @@ class ExtensionBlueprintImpl< disabled: args.disabled ?? this.options.disabled, inputs: args.inputs ?? this.options.inputs, output: args.output ?? this.options.output, - configSchema: args.configSchema ?? this.options.configSchema, // TODO: some config merging or smth + config: args.config, factory: ({ node, config, inputs }) => { if (args.factory) { return args.factory( ( innerParams: TParams, innerContext?: { - config?: TConfig; + config?: { + [key in keyof TConfigSchema]: z.infer< + ReturnType<TConfigSchema[key]> + >; + }; inputs?: Expand<ResolvedExtensionInputs<TInputs>>; }, ) => @@ -207,16 +255,16 @@ export function createExtensionBlueprint< TParams, TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, - TConfig, + TConfigSchema extends { [key: string]: (zImpl: typeof z) => z.ZodTypeAny }, TDataRefs extends AnyExtensionDataMap = never, >( options: CreateExtensionBlueprintOptions< TParams, TInputs, TOutput, - TConfig, + TConfigSchema, TDataRefs >, -): ExtensionBlueprint<TParams, TInputs, TOutput, TConfig, TDataRefs> { +): ExtensionBlueprint<TParams, TInputs, TOutput, TConfigSchema, TDataRefs> { return new ExtensionBlueprintImpl(options); } diff --git a/packages/frontend-test-utils/src/app/createExtensionTester.tsx b/packages/frontend-test-utils/src/app/createExtensionTester.tsx index a98879fbba..d6be346002 100644 --- a/packages/frontend-test-utils/src/app/createExtensionTester.tsx +++ b/packages/frontend-test-utils/src/app/createExtensionTester.tsx @@ -102,11 +102,11 @@ export class ExtensionTester { ...output, path: coreExtensionData.routePath, }, - factory: params => ({ + factory: (params: any) => ({ ...factory(params), path: '/', }), - }); + } as any); tester.add(extension, options); return tester; } diff --git a/plugins/catalog-graph/api-report-alpha.md b/plugins/catalog-graph/api-report-alpha.md index 3895f12fcf..afd03965ae 100644 --- a/plugins/catalog-graph/api-report-alpha.md +++ b/plugins/catalog-graph/api-report-alpha.md @@ -4,8 +4,76 @@ ```ts import { BackstagePlugin } from '@backstage/frontend-plugin-api'; +import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { ExternalRouteRef } from '@backstage/frontend-plugin-api'; +import { objectUtil } from 'zod'; import { RouteRef } from '@backstage/frontend-plugin-api'; +import { ZodArray } from 'zod'; +import { ZodBoolean } from 'zod'; +import { ZodEnum } from 'zod'; +import { ZodNativeEnum } from 'zod'; +import { ZodNumber } from 'zod'; +import { ZodOptional } from 'zod'; +import { ZodString } from 'zod'; +import { ZodTuple } from 'zod'; + +// Warning: (ae-missing-release-tag) "CatalogGraphEntityCard" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const CatalogGraphEntityCard: ExtensionDefinition< + { + filter?: string | undefined; + height?: number | undefined; + curve?: 'curveStepBefore' | 'curveMonotoneX' | undefined; + direction?: Direction | undefined; + title?: string | undefined; + zoom?: 'disabled' | 'enabled' | 'enable-on-click' | undefined; + relations?: string[] | undefined; + maxDepth?: number | undefined; + kinds?: string[] | undefined; + unidirectional?: boolean | undefined; + mergeRelations?: boolean | undefined; + relationPairs?: [string, string][] | undefined; + }, + objectUtil.extendShape< + objectUtil.extendShape< + { + filter: ZodOptional<ZodString>; + }, + { + title: ZodOptional<ZodString>; + height: ZodOptional<ZodNumber>; + } + >, + { + kinds: ZodOptional<ZodArray<ZodString, 'many'>>; + relations: ZodOptional<ZodArray<ZodString, 'many'>>; + maxDepth: ZodOptional<ZodNumber>; + unidirectional: ZodOptional<ZodBoolean>; + mergeRelations: ZodOptional<ZodBoolean>; + direction: ZodOptional<ZodNativeEnum<typeof Direction>>; + relationPairs: ZodOptional< + ZodArray<ZodTuple<[ZodString, ZodString], null>, 'many'> + >; + zoom: ZodOptional<ZodEnum<['enabled', 'disabled', 'enable-on-click']>>; + curve: ZodOptional<ZodEnum<['curveStepBefore', 'curveMonotoneX']>>; + } + >, + { + filter?: string | undefined; + height?: number | undefined; + curve?: 'curveStepBefore' | 'curveMonotoneX' | undefined; + direction?: Direction | undefined; + title?: string | undefined; + zoom?: 'disabled' | 'enabled' | 'enable-on-click' | undefined; + relations?: string[] | undefined; + maxDepth?: number | undefined; + kinds?: string[] | undefined; + unidirectional?: boolean | undefined; + mergeRelations?: boolean | undefined; + relationPairs?: [string, string][] | undefined; + } +>; // @public (undocumented) const _default: BackstagePlugin< @@ -25,5 +93,9 @@ const _default: BackstagePlugin< >; export default _default; +// Warnings were encountered during analysis: +// +// src/alpha.d.ts:6:5 - (ae-forgotten-export) The symbol "Direction" needs to be exported by the entry point alpha.d.ts + // (No @packageDocumentation comment for this package) ``` diff --git a/plugins/catalog-graph/src/alpha.tsx b/plugins/catalog-graph/src/alpha.tsx index 6d8429332e..cf663406fa 100644 --- a/plugins/catalog-graph/src/alpha.tsx +++ b/plugins/catalog-graph/src/alpha.tsx @@ -24,7 +24,7 @@ import { compatWrapper, convertLegacyRouteRef, } from '@backstage/core-compat-api'; -import { createEntityCardExtension } from '@backstage/plugin-catalog-react/alpha'; +import { EntityCardBlueprint } from '@backstage/plugin-catalog-react/alpha'; import { catalogGraphRouteRef, catalogEntityRouteRef } from './routes'; import { Direction } from './components'; @@ -46,24 +46,67 @@ function getEntityGraphRelationsConfigSchema( }); } -const CatalogGraphEntityCard = createEntityCardExtension({ +export const CatalogGraphEntityCard = EntityCardBlueprint.make({ name: 'relations', - configSchema: createSchemaFromZod(z => - z - .object({ - // Filter is a config required to all entity cards - filter: z.string().optional(), - title: z.string().optional(), - height: z.number().optional(), - // Skipping a "variant" config for now, defaulting to "gridItem" in the component - // For more details, see this comment: https://github.com/backstage/backstage/pull/22619#discussion_r1477333252 - }) - .merge(getEntityGraphRelationsConfigSchema(z)), - ), - loader: async ({ config: { filter, ...props } }) => - import('./components/CatalogGraphCard').then(m => - compatWrapper(<m.CatalogGraphCard {...props} />), - ), + // configSchema: origSchema => + // createSchemaFromZod(z => + // z + // .object({ + // // Filter is a config required to all entity cards + // // filter: z.string().optional(), + // title: z.string().optional(), + // height: z.number().optional(), + // // Skipping a "variant" config for now, defaulting to "gridItem" in the component + // // For more details, see this comment: https://github.com/backstage/backstage/pull/22619#discussion_r1477333252 + // }) + // .merge(getEntityGraphRelationsConfigSchema(z)) + // .merge(origSchema), + // ), + + // config: { + // schema: ({ z, parent }) => + // parent + // .merge({ + // title: z.string().optional(), + // height: z.number().optional(), + // }) + // .merge(getEntityGraphRelationsConfigSchema(z)), + // }, + + // config: { + // schema: ({ z, parent }) => + // parent + // .extend({ + // title: z.string().optional(), + // height: z.number().optional(), + // }) + // .merge(getEntityGraphRelationsConfigSchema(z)), + // // .merge(parent) + // }, + + // TODO: implement this and check the types. 👋 zod types. + config: { + schema: { + title: z => z.string().optional(), + height: z => z.number().optional(), + }, + }, + + // config: { + // schema: z => ({ + // title: z.string().optional(), + // height: z.number().optional(), + // }), + // }, + + factory(origFactory, { config: { filter: _, ...props } }) { + return origFactory({ + loader: async () => + import('./components/CatalogGraphCard').then(m => + compatWrapper(<m.CatalogGraphCard {...props} />), + ), + }); + }, }); const CatalogGraphPage = createPageExtension({ diff --git a/plugins/catalog-react/api-report-alpha.md b/plugins/catalog-react/api-report-alpha.md index d2bfb29458..ccf8205f59 100644 --- a/plugins/catalog-react/api-report-alpha.md +++ b/plugins/catalog-react/api-report-alpha.md @@ -3,17 +3,20 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts -/// <reference types="react" /> - import { AnyExtensionInputMap } from '@backstage/frontend-plugin-api'; import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; import { Entity } from '@backstage/catalog-model'; +import { ExtensionBlueprint } from '@backstage/frontend-plugin-api'; import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { PortableSchema } from '@backstage/frontend-plugin-api'; +import { default as React_2 } from 'react'; import { ResolvedExtensionInputs } from '@backstage/frontend-plugin-api'; import { ResourcePermission } from '@backstage/plugin-permission-common'; import { RouteRef } from '@backstage/frontend-plugin-api'; import { TranslationRef } from '@backstage/core-plugin-api/alpha'; +import { ZodOptional } from 'zod'; +import { ZodRawShape } from 'zod'; +import { ZodString } from 'zod'; // @alpha (undocumented) export const catalogExtensionData: { @@ -115,7 +118,7 @@ export function createEntityCardExtension< config: TConfig; inputs: Expand<ResolvedExtensionInputs<TInputs>>; }) => Promise<JSX.Element>; -}): ExtensionDefinition<TConfig>; +}): ExtensionDefinition<TConfig, ZodRawShape>; // @alpha (undocumented) export function createEntityContentExtension< @@ -138,11 +141,48 @@ export function createEntityContentExtension< loader: (options: { inputs: Expand<ResolvedExtensionInputs<TInputs>>; }) => Promise<JSX.Element>; -}): ExtensionDefinition<{ - title: string; - path: string; - filter?: string | undefined; -}>; +}): ExtensionDefinition< + { + title: string; + path: string; + filter?: string | undefined; + }, + ZodRawShape +>; + +// @alpha (undocumented) +export const EntityCardBlueprint: ExtensionBlueprint< + { + filter?: string | ((entity: Entity) => boolean) | undefined; + loader: () => Promise<JSX.Element>; + }, + AnyExtensionInputMap, + { + element: ConfigurableExtensionDataRef< + 'core.reactElement', + React_2.JSX.Element, + {} + >; + filterFunction: ConfigurableExtensionDataRef< + 'catalog.entity-filter-function', + (entity: Entity) => boolean, + ((entity: Entity) => boolean) & { + optional: true; + } + >; + filterExpression: ConfigurableExtensionDataRef< + 'catalog.entity-filter-expression', + string, + string & { + optional: true; + } + >; + }, + { + filter: ZodOptional<ZodString>; + }, + never +>; // @alpha export function isOwnerOf(owner: Entity, entity: Entity): boolean; diff --git a/plugins/catalog-react/src/alpha.tsx b/plugins/catalog-react/src/alpha.tsx index e81b8e5ebf..f397c76ce0 100644 --- a/plugins/catalog-react/src/alpha.tsx +++ b/plugins/catalog-react/src/alpha.tsx @@ -22,6 +22,7 @@ import { RouteRef, coreExtensionData, createExtension, + createExtensionBlueprint, createExtensionDataRef, createSchemaFromZod, } from '@backstage/frontend-plugin-api'; @@ -47,6 +48,49 @@ export const catalogExtensionData = { }), }; +/** @alpha */ +export const EntityCardBlueprint = createExtensionBlueprint({ + kind: 'entity-card', + attachTo: { id: 'entity-content:catalog/overview', input: 'cards' }, + // configSchema: createSchemaFromZod(z => + // z.object({ + // filter: z.string().optional(), + // }), + // ), + config: { + schema: { + filter: z => z.string().optional(), + }, + }, + output: { + element: coreExtensionData.reactElement, + filterFunction: catalogExtensionData.entityFilterFunction.optional(), + filterExpression: catalogExtensionData.entityFilterExpression.optional(), + }, + factory( + params: { + filter?: + | typeof catalogExtensionData.entityFilterFunction.T + | typeof catalogExtensionData.entityFilterExpression.T; + loader: () => Promise<JSX.Element>; + }, + { node, config }, + ) { + const ExtensionComponent = lazy(() => + params.loader().then(element => ({ default: () => element })), + ); + + return { + element: ( + <ExtensionBoundary node={node}> + <ExtensionComponent /> + </ExtensionBoundary> + ), + ...mergeFilters({ config, options: params }), + }; + }, +}); + // TODO: Figure out how to merge with provided config schema /** @alpha */ export function createEntityCardExtension< @@ -154,6 +198,13 @@ export function createEntityContentExtension< filter: z.string().optional(), }), ), + // config: { + // schema: ({ z }) => ({ + // path: z.string().default(options.defaultPath), + // title: z.string().default(options.defaultTitle), + // filter: z.string().optional(), + // }), + // }, factory({ config, inputs, node }) { const ExtensionComponent = lazy(() => options diff --git a/plugins/catalog/api-report-alpha.md b/plugins/catalog/api-report-alpha.md index 102e2a7aa3..03711b7d3d 100644 --- a/plugins/catalog/api-report-alpha.md +++ b/plugins/catalog/api-report-alpha.md @@ -12,6 +12,39 @@ import { ExternalRouteRef } from '@backstage/frontend-plugin-api'; import { PortableSchema } from '@backstage/frontend-plugin-api'; import { RouteRef } from '@backstage/frontend-plugin-api'; import { TranslationRef } from '@backstage/core-plugin-api/alpha'; +import { ZodObject } from 'zod'; + +// Warning: (ae-missing-release-tag) "catalogAboutEntityCard" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const catalogAboutEntityCard: ExtensionDefinition< + { + filter?: string | undefined; + }, + ZodObject<any, any, any, any, any> +>; + +// Warning: (ae-missing-release-tag) "catalogLinksEntityCard" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const catalogLinksEntityCard: ExtensionDefinition< + { + filter?: string | undefined; + }, + ZodObject<any, any, any, any, any> +>; + +// Warning: (ae-missing-release-tag) "catalogOverviewEntityContent" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const catalogOverviewEntityContent: ExtensionDefinition< + { + title: string; + path: string; + filter?: string | undefined; + }, + ZodObject<any, any, any, any, any> +>; // @alpha (undocumented) export const catalogTranslationRef: TranslationRef< @@ -106,7 +139,7 @@ export function createCatalogFilterExtension< inputs?: TInputs; configSchema?: PortableSchema<TConfig>; loader: (options: { config: TConfig }) => Promise<JSX.Element>; -}): ExtensionDefinition<TConfig>; +}): ExtensionDefinition<TConfig, ZodObject<any, any, any, any, any>>; // @alpha (undocumented) const _default: BackstagePlugin< diff --git a/plugins/catalog/src/alpha/index.ts b/plugins/catalog/src/alpha/index.ts index 06a78ec6ea..acf61865ba 100644 --- a/plugins/catalog/src/alpha/index.ts +++ b/plugins/catalog/src/alpha/index.ts @@ -16,3 +16,5 @@ export { default } from './plugin'; export { createCatalogFilterExtension } from './createCatalogFilterExtension'; +export { catalogAboutEntityCard, catalogLinksEntityCard } from './entityCards'; +export { catalogOverviewEntityContent } from './entityContents'; diff --git a/plugins/search-react/api-report-alpha.md b/plugins/search-react/api-report-alpha.md index aea85d0f81..6160759042 100644 --- a/plugins/search-react/api-report-alpha.md +++ b/plugins/search-react/api-report-alpha.md @@ -11,6 +11,7 @@ import { ListItemProps } from '@material-ui/core/ListItem'; import { PortableSchema } from '@backstage/frontend-plugin-api'; import { SearchDocument } from '@backstage/plugin-search-common'; import { SearchResult } from '@backstage/plugin-search-common'; +import { ZodObject } from 'zod'; // @alpha (undocumented) export type BaseSearchResultListItemProps<T = {}> = T & { @@ -25,7 +26,7 @@ export function createSearchResultListItemExtension< }, >( options: SearchResultItemExtensionOptions<TConfig>, -): ExtensionDefinition<TConfig>; +): ExtensionDefinition<TConfig, ZodObject<any, any, any, any, any>>; // @alpha (undocumented) export namespace createSearchResultListItemExtension { diff --git a/plugins/search/api-report-alpha.md b/plugins/search/api-report-alpha.md index db2999ba25..ade5f530ef 100644 --- a/plugins/search/api-report-alpha.md +++ b/plugins/search/api-report-alpha.md @@ -6,6 +6,7 @@ import { BackstagePlugin } from '@backstage/frontend-plugin-api'; import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { RouteRef } from '@backstage/frontend-plugin-api'; +import { ZodObject } from 'zod'; // @alpha (undocumented) const _default: BackstagePlugin< @@ -17,18 +18,27 @@ const _default: BackstagePlugin< export default _default; // @alpha (undocumented) -export const searchApi: ExtensionDefinition<{}>; +export const searchApi: ExtensionDefinition< + {}, + ZodObject<any, any, any, any, any> +>; // @alpha (undocumented) -export const searchNavItem: ExtensionDefinition<{ - title: string; -}>; +export const searchNavItem: ExtensionDefinition< + { + title: string; + }, + ZodObject<any, any, any, any, any> +>; // @alpha (undocumented) -export const searchPage: ExtensionDefinition<{ - path: string; - noTrack: boolean; -}>; +export const searchPage: ExtensionDefinition< + { + path: string; + noTrack: boolean; + }, + any +>; // (No @packageDocumentation comment for this package) ``` diff --git a/plugins/techdocs/api-report-alpha.md b/plugins/techdocs/api-report-alpha.md index cf9f5fa9a3..fc57370a53 100644 --- a/plugins/techdocs/api-report-alpha.md +++ b/plugins/techdocs/api-report-alpha.md @@ -6,6 +6,7 @@ import { BackstagePlugin } from '@backstage/frontend-plugin-api'; import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { RouteRef } from '@backstage/frontend-plugin-api'; +import { ZodObject } from 'zod'; // @alpha (undocumented) const _default: BackstagePlugin< @@ -23,13 +24,16 @@ const _default: BackstagePlugin< export default _default; // @alpha (undocumented) -export const techDocsSearchResultListItemExtension: ExtensionDefinition<{ - lineClamp: number; - noTrack: boolean; - asListItem: boolean; - asLink: boolean; - title?: string | undefined; -}>; +export const techDocsSearchResultListItemExtension: ExtensionDefinition< + { + lineClamp: number; + noTrack: boolean; + asListItem: boolean; + asLink: boolean; + title?: string | undefined; + }, + ZodObject<any, any, any, any, any> +>; // (No @packageDocumentation comment for this package) ``` diff --git a/plugins/user-settings/api-report-alpha.md b/plugins/user-settings/api-report-alpha.md index b06fd1e583..db4373fd43 100644 --- a/plugins/user-settings/api-report-alpha.md +++ b/plugins/user-settings/api-report-alpha.md @@ -7,6 +7,7 @@ import { BackstagePlugin } from '@backstage/frontend-plugin-api'; import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { RouteRef } from '@backstage/frontend-plugin-api'; import { TranslationRef } from '@backstage/core-plugin-api/alpha'; +import { ZodObject } from 'zod'; // @alpha (undocumented) const _default: BackstagePlugin< @@ -18,9 +19,12 @@ const _default: BackstagePlugin< export default _default; // @alpha (undocumented) -export const settingsNavItem: ExtensionDefinition<{ - title: string; -}>; +export const settingsNavItem: ExtensionDefinition< + { + title: string; + }, + ZodObject<any, any, any, any, any> +>; // @alpha (undocumented) export const userSettingsTranslationRef: TranslationRef< From 8e387301a4f27c17aa631005a8ec6634f495965b Mon Sep 17 00:00:00 2001 From: blam <ben@blam.sh> Date: Wed, 24 Jul 2024 10:56:12 +0200 Subject: [PATCH 398/416] chore: moving things around Signed-off-by: blam <ben@blam.sh> --- .../src/wiring/createExtension.ts | 13 +- .../src/wiring/createExtensionBlueprint.ts | 125 +++++++++++------- 2 files changed, 84 insertions(+), 54 deletions(-) diff --git a/packages/frontend-plugin-api/src/wiring/createExtension.ts b/packages/frontend-plugin-api/src/wiring/createExtension.ts index 3733e44957..61223ca8e8 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtension.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtension.ts @@ -82,7 +82,7 @@ export interface CreateExtensionOptions< TOutput extends AnyExtensionDataMap, TInputs extends AnyExtensionInputMap, TConfig, - TConfigSchema extends { [key: string]: (zImpl: typeof z) => z.ZodTypeAny }, + TConfigSchema extends { [key: string]: z.ZodTypeAny }, > { kind?: string; namespace?: string; @@ -94,7 +94,9 @@ export interface CreateExtensionOptions< /** @deprecated - use `config.schema` instead */ configSchema?: PortableSchema<TConfig>; config?: { - schema: TConfigSchema; + schema: { + [key in keyof TConfigSchema]: (zImpl: typeof z) => TConfigSchema[key]; + }; }; factory(context: { node: AppNode; @@ -104,7 +106,10 @@ export interface CreateExtensionOptions< } /** @public */ -export interface ExtensionDefinition<TConfig, TConfigSchema = {}> { +export interface ExtensionDefinition< + TConfig, + TConfigSchema = never /* TODO -> refactor */, +> { $$type: '@backstage/ExtensionDefinition'; readonly kind?: string; readonly namespace?: string; @@ -153,7 +158,7 @@ export function createExtension< TOutput extends AnyExtensionDataMap, TInputs extends AnyExtensionInputMap, TConfig, - TConfigSchema extends { [key: string]: (zImpl: typeof z) => z.ZodTypeAny }, + TConfigSchema extends { [key: string]: z.ZodTypeAny }, >( options: CreateExtensionOptions<TOutput, TInputs, TConfig, TConfigSchema>, ): ExtensionDefinition<TConfig> { diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts index 61227c7dc1..9cd5689a95 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts @@ -33,7 +33,7 @@ export interface CreateExtensionBlueprintOptions< TParams, TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, - TConfigSchema extends { [key: string]: (zImpl: typeof z) => z.ZodTypeAny }, + TConfigSchema extends { [key: string]: z.ZodTypeAny }, TDataRefs extends AnyExtensionDataMap, > { kind: string; @@ -43,15 +43,17 @@ export interface CreateExtensionBlueprintOptions< inputs?: TInputs; output: TOutput; config?: { - schema: TConfigSchema; + schema: { + [key in keyof TConfigSchema]: (zImpl: typeof z) => TConfigSchema[key]; + }; }; factory( params: TParams, context: { node: AppNode; - config: { - [key in keyof TConfigSchema]: z.infer<ReturnType<TConfigSchema[key]>>; - }; + config: Expand<{ + [key in keyof TConfigSchema]: z.infer<TConfigSchema[key]>; + }>; inputs: Expand<ResolvedExtensionInputs<TInputs>>; }, ): Expand<ExtensionDataValues<TOutput>>; @@ -66,7 +68,7 @@ export interface ExtensionBlueprint< TParams, TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, - TConfigSchema extends { [key: string]: (zImpl: typeof z) => z.ZodTypeAny }, + TConfigSchema extends { [key: string]: z.ZodTypeAny }, TDataRefs extends AnyExtensionDataMap, > { dataRefs: TDataRefs; @@ -77,11 +79,7 @@ export interface ExtensionBlueprint< * You must either pass `params` directly, or define a `factory` that can * optionally call the original factory with the same params. */ - make< - TExtensionConfigSchema extends { - [key: string]: (zImpl: typeof z) => z.ZodTypeAny; - }, - >( + make<TExtensionConfigSchema extends { [key: string]: z.ZodTypeAny }>( args: { namespace?: string; name?: string; @@ -90,7 +88,11 @@ export interface ExtensionBlueprint< inputs?: TInputs; output?: TOutput; config?: { - schema: TExtensionConfigSchema; + schema: { + [key in keyof TExtensionConfigSchema]: ( + zImpl: typeof z, + ) => TExtensionConfigSchema[key]; + }; }; } & ( | { @@ -98,21 +100,23 @@ export interface ExtensionBlueprint< originalFactory: ( params: TParams, context?: { - config?: { - [key in keyof TConfigSchema]: z.infer< - ReturnType<TConfigSchema[key]> - >; - }; + config?: Expand<{ + [key in keyof TConfigSchema]: z.infer<TConfigSchema[key]>; + }>; inputs?: Expand<ResolvedExtensionInputs<TInputs>>; }, ) => Expand<ExtensionDataValues<TOutput>>, context: { node: AppNode; - config: { - [key in keyof TExtensionConfigSchema]: z.infer< - ReturnType<TExtensionConfigSchema[key]> - >; - }; + config: Expand< + { + [key in keyof TExtensionConfigSchema]: z.infer< + TExtensionConfigSchema[key] + >; + } & { + [key in keyof TConfigSchema]: z.infer<TConfigSchema[key]>; + } + >; inputs: Expand<ResolvedExtensionInputs<TInputs>>; }, ): Expand<ExtensionDataValues<TOutput>>; @@ -124,7 +128,7 @@ export interface ExtensionBlueprint< ): ExtensionDefinition< { [key in keyof TExtensionConfigSchema]: z.infer< - ReturnType<TExtensionConfigSchema[key]> + TExtensionConfigSchema[key] >; }, TExtensionConfigSchema @@ -138,7 +142,7 @@ class ExtensionBlueprintImpl< TParams, TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, - TConfigSchema extends { [key: string]: (zImpl: typeof z) => z.ZodTypeAny }, + TConfigSchema extends { [key: string]: z.ZodTypeAny }, TDataRefs extends AnyExtensionDataMap, > { constructor( @@ -156,7 +160,7 @@ class ExtensionBlueprintImpl< dataRefs: TDataRefs; public make< - TExtensionConfigSchema extends TConfigSchema = TConfigSchema, + TExtensionConfigSchema extends { [key: string]: z.ZodTypeAny }, >(args: { namespace?: string; name?: string; @@ -166,37 +170,45 @@ class ExtensionBlueprintImpl< output?: TOutput; params?: TParams; config?: { - schema: TConfigSchema; + schema: { + [key in keyof TConfigSchema]: (zImpl: typeof z) => TConfigSchema[key]; + }; }; factory?( originalFactory: ( params: TParams, context?: { - config?: { - [key in keyof TConfigSchema]: z.infer< - ReturnType<TConfigSchema[key]> - >; - }; + config?: Expand<{ + [key in keyof TConfigSchema]: z.infer<TConfigSchema[key]>; + }>; inputs?: Expand<ResolvedExtensionInputs<TInputs>>; }, ) => Expand<ExtensionDataValues<TOutput>>, context: { node: AppNode; - config: { - [key in keyof TExtensionConfigSchema]: z.infer< - ReturnType<TExtensionConfigSchema[key]> - >; - }; + config: Expand< + { + [key in keyof TExtensionConfigSchema]: z.infer< + TExtensionConfigSchema[key] + >; + } & { + [key in keyof TConfigSchema]: z.infer<TConfigSchema[key]>; + } + >; inputs: Expand<ResolvedExtensionInputs<TInputs>>; }, ): Expand<ExtensionDataValues<TOutput>>; }): ExtensionDefinition< - { - [key in keyof TExtensionConfigSchema]: z.infer< - ReturnType<TExtensionConfigSchema[key]> - >; - }, - TExtensionConfigSchema + Expand< + { + [key in keyof TExtensionConfigSchema]: z.infer< + TExtensionConfigSchema[key] + >; + } & { + [key in keyof TConfigSchema]: z.infer<TConfigSchema[key]>; + } + >, + Expand<TConfigSchema & TExtensionConfigSchema> > { return createExtension({ kind: this.options.kind, @@ -206,18 +218,31 @@ class ExtensionBlueprintImpl< disabled: args.disabled ?? this.options.disabled, inputs: args.inputs ?? this.options.inputs, output: args.output ?? this.options.output, - config: args.config, + config: { + schema: { + ...this.options.config?.schema, + ...args.config, + } as Expand< + { + [key in keyof TConfigSchema]: ( + zImpl: typeof z, + ) => TConfigSchema[key]; + } & { + [key in keyof TExtensionConfigSchema]: ( + zImpl: typeof z, + ) => TExtensionConfigSchema[key]; + } + >, + }, factory: ({ node, config, inputs }) => { if (args.factory) { return args.factory( ( innerParams: TParams, innerContext?: { - config?: { - [key in keyof TConfigSchema]: z.infer< - ReturnType<TConfigSchema[key]> - >; - }; + config?: Expand<{ + [key in keyof TConfigSchema]: z.infer<TConfigSchema[key]>; + }>; inputs?: Expand<ResolvedExtensionInputs<TInputs>>; }, ) => @@ -255,7 +280,7 @@ export function createExtensionBlueprint< TParams, TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, - TConfigSchema extends { [key: string]: (zImpl: typeof z) => z.ZodTypeAny }, + TConfigSchema extends { [key: string]: z.ZodTypeAny }, TDataRefs extends AnyExtensionDataMap = never, >( options: CreateExtensionBlueprintOptions< @@ -266,5 +291,5 @@ export function createExtensionBlueprint< TDataRefs >, ): ExtensionBlueprint<TParams, TInputs, TOutput, TConfigSchema, TDataRefs> { - return new ExtensionBlueprintImpl(options); + return new ExtensionBlueprintImpl(options) as any; } From d22f1316c50da7ea5d767fd23d9c6acf9be9ba07 Mon Sep 17 00:00:00 2001 From: blam <ben@blam.sh> Date: Wed, 24 Jul 2024 11:25:11 +0200 Subject: [PATCH 399/416] chore: getting somewhere with portable schemas and zod types Signed-off-by: blam <ben@blam.sh> --- .../src/wiring/createExtension.ts | 25 ++-- .../src/wiring/createExtensionBlueprint.ts | 120 ++++++++---------- plugins/catalog-graph/api-report-alpha.md | 67 +--------- 3 files changed, 75 insertions(+), 137 deletions(-) diff --git a/packages/frontend-plugin-api/src/wiring/createExtension.ts b/packages/frontend-plugin-api/src/wiring/createExtension.ts index 61223ca8e8..6fa3a50634 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtension.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtension.ts @@ -15,7 +15,7 @@ */ import { AppNode } from '../apis'; -import { PortableSchema } from '../schema'; +import { PortableSchema, createSchemaFromZod } from '../schema'; import { Expand } from '../types'; import { ExtensionDataRef } from './createExtensionDataRef'; import { ExtensionInput } from './createExtensionInput'; @@ -106,10 +106,7 @@ export interface CreateExtensionOptions< } /** @public */ -export interface ExtensionDefinition< - TConfig, - TConfigSchema = never /* TODO -> refactor */, -> { +export interface ExtensionDefinition<TConfig> { $$type: '@backstage/ExtensionDefinition'; readonly kind?: string; readonly namespace?: string; @@ -117,9 +114,6 @@ export interface ExtensionDefinition< readonly attachTo: { id: string; input: string }; readonly disabled: boolean; readonly configSchema?: PortableSchema<TConfig>; - readonly config?: { - schema: TConfigSchema; - }; } /** @internal */ @@ -162,6 +156,18 @@ export function createExtension< >( options: CreateExtensionOptions<TOutput, TInputs, TConfig, TConfigSchema>, ): ExtensionDefinition<TConfig> { + // TODO: resovle configSchema from either configSchema or config.schema + const newConfigSchema = options.config?.schema; + const configSchema = newConfigSchema + ? createSchemaFromZod(innerZ => + innerZ.object( + Object.fromEntries( + Object.entries(newConfigSchema).map(([k, v]) => [k, v(innerZ)]), + ), + ), + ) + : options.configSchema; + return { $$type: '@backstage/ExtensionDefinition', version: 'v1', @@ -172,8 +178,7 @@ export function createExtension< disabled: options.disabled ?? false, inputs: options.inputs ?? {}, output: options.output, - configSchema: options.configSchema, - config: options.config, + configSchema, factory({ inputs, ...rest }) { // TODO: Simplify this, but TS wouldn't infer the input type for some reason return options.factory({ diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts index 9cd5689a95..c54131622f 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts @@ -33,7 +33,7 @@ export interface CreateExtensionBlueprintOptions< TParams, TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, - TConfigSchema extends { [key: string]: z.ZodTypeAny }, + TConfigSchema extends { [key in string]: z.ZodTypeAny }, TDataRefs extends AnyExtensionDataMap, > { kind: string; @@ -51,9 +51,9 @@ export interface CreateExtensionBlueprintOptions< params: TParams, context: { node: AppNode; - config: Expand<{ + config: { [key in keyof TConfigSchema]: z.infer<TConfigSchema[key]>; - }>; + }; inputs: Expand<ResolvedExtensionInputs<TInputs>>; }, ): Expand<ExtensionDataValues<TOutput>>; @@ -68,7 +68,7 @@ export interface ExtensionBlueprint< TParams, TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, - TConfigSchema extends { [key: string]: z.ZodTypeAny }, + TConfig extends { [key in string]: unknown }, TDataRefs extends AnyExtensionDataMap, > { dataRefs: TDataRefs; @@ -79,7 +79,7 @@ export interface ExtensionBlueprint< * You must either pass `params` directly, or define a `factory` that can * optionally call the original factory with the same params. */ - make<TExtensionConfigSchema extends { [key: string]: z.ZodTypeAny }>( + make<TExtensionConfigSchema extends { [key in string]: z.ZodTypeAny }>( args: { namespace?: string; name?: string; @@ -100,23 +100,17 @@ export interface ExtensionBlueprint< originalFactory: ( params: TParams, context?: { - config?: Expand<{ - [key in keyof TConfigSchema]: z.infer<TConfigSchema[key]>; - }>; + config?: TConfig; inputs?: Expand<ResolvedExtensionInputs<TInputs>>; }, ) => Expand<ExtensionDataValues<TOutput>>, context: { node: AppNode; - config: Expand< - { - [key in keyof TExtensionConfigSchema]: z.infer< - TExtensionConfigSchema[key] - >; - } & { - [key in keyof TConfigSchema]: z.infer<TConfigSchema[key]>; - } - >; + config: { + [key in keyof TExtensionConfigSchema]: z.infer< + TExtensionConfigSchema[key] + >; + } & TConfig; inputs: Expand<ResolvedExtensionInputs<TInputs>>; }, ): Expand<ExtensionDataValues<TOutput>>; @@ -130,8 +124,7 @@ export interface ExtensionBlueprint< [key in keyof TExtensionConfigSchema]: z.infer< TExtensionConfigSchema[key] >; - }, - TExtensionConfigSchema + } & TConfig >; } @@ -142,7 +135,7 @@ class ExtensionBlueprintImpl< TParams, TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, - TConfigSchema extends { [key: string]: z.ZodTypeAny }, + TConfigSchema extends { [key in string]: z.ZodTypeAny }, TDataRefs extends AnyExtensionDataMap, > { constructor( @@ -160,7 +153,7 @@ class ExtensionBlueprintImpl< dataRefs: TDataRefs; public make< - TExtensionConfigSchema extends { [key: string]: z.ZodTypeAny }, + TExtensionConfigSchema extends { [key in string]: z.ZodTypeAny }, >(args: { namespace?: string; name?: string; @@ -171,45 +164,53 @@ class ExtensionBlueprintImpl< params?: TParams; config?: { schema: { - [key in keyof TConfigSchema]: (zImpl: typeof z) => TConfigSchema[key]; + [key in keyof TExtensionConfigSchema]: ( + zImpl: typeof z, + ) => TExtensionConfigSchema[key]; }; }; factory?( originalFactory: ( params: TParams, context?: { - config?: Expand<{ + config?: { [key in keyof TConfigSchema]: z.infer<TConfigSchema[key]>; - }>; + }; inputs?: Expand<ResolvedExtensionInputs<TInputs>>; }, ) => Expand<ExtensionDataValues<TOutput>>, context: { node: AppNode; - config: Expand< - { - [key in keyof TExtensionConfigSchema]: z.infer< - TExtensionConfigSchema[key] - >; - } & { - [key in keyof TConfigSchema]: z.infer<TConfigSchema[key]>; - } - >; + config: { + [key in keyof TExtensionConfigSchema]: z.infer< + TExtensionConfigSchema[key] + >; + } & { + [key in keyof TConfigSchema]: z.infer<TConfigSchema[key]>; + }; inputs: Expand<ResolvedExtensionInputs<TInputs>>; }, ): Expand<ExtensionDataValues<TOutput>>; }): ExtensionDefinition< - Expand< - { - [key in keyof TExtensionConfigSchema]: z.infer< - TExtensionConfigSchema[key] - >; - } & { - [key in keyof TConfigSchema]: z.infer<TConfigSchema[key]>; - } - >, - Expand<TConfigSchema & TExtensionConfigSchema> + { + [key in keyof TExtensionConfigSchema]: z.infer< + TExtensionConfigSchema[key] + >; + } & { + [key in keyof TConfigSchema]: z.infer<TConfigSchema[key]>; + } > { + const schema = { + ...this.options.config?.schema, + ...args.config, + } as { + [key in keyof TConfigSchema]: (zImpl: typeof z) => TConfigSchema[key]; + } & { + [key in keyof TExtensionConfigSchema]: ( + zImpl: typeof z, + ) => TExtensionConfigSchema[key]; + }; + return createExtension({ kind: this.options.kind, namespace: args.namespace ?? this.options.namespace, @@ -218,31 +219,16 @@ class ExtensionBlueprintImpl< disabled: args.disabled ?? this.options.disabled, inputs: args.inputs ?? this.options.inputs, output: args.output ?? this.options.output, - config: { - schema: { - ...this.options.config?.schema, - ...args.config, - } as Expand< - { - [key in keyof TConfigSchema]: ( - zImpl: typeof z, - ) => TConfigSchema[key]; - } & { - [key in keyof TExtensionConfigSchema]: ( - zImpl: typeof z, - ) => TExtensionConfigSchema[key]; - } - >, - }, + config: Object.keys(schema).length === 0 ? undefined : { schema }, factory: ({ node, config, inputs }) => { if (args.factory) { return args.factory( ( innerParams: TParams, innerContext?: { - config?: Expand<{ + config?: { [key in keyof TConfigSchema]: z.infer<TConfigSchema[key]>; - }>; + }; inputs?: Expand<ResolvedExtensionInputs<TInputs>>; }, ) => @@ -280,7 +266,7 @@ export function createExtensionBlueprint< TParams, TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, - TConfigSchema extends { [key: string]: z.ZodTypeAny }, + TConfigSchema extends { [key in string]: z.ZodTypeAny }, TDataRefs extends AnyExtensionDataMap = never, >( options: CreateExtensionBlueprintOptions< @@ -290,6 +276,12 @@ export function createExtensionBlueprint< TConfigSchema, TDataRefs >, -): ExtensionBlueprint<TParams, TInputs, TOutput, TConfigSchema, TDataRefs> { - return new ExtensionBlueprintImpl(options) as any; +): ExtensionBlueprint< + TParams, + TInputs, + TOutput, + { [key in keyof TConfigSchema]: z.infer<TConfigSchema[key]> }, + TDataRefs +> { + return new ExtensionBlueprintImpl(options); } diff --git a/plugins/catalog-graph/api-report-alpha.md b/plugins/catalog-graph/api-report-alpha.md index afd03965ae..59a387adf0 100644 --- a/plugins/catalog-graph/api-report-alpha.md +++ b/plugins/catalog-graph/api-report-alpha.md @@ -6,72 +6,17 @@ import { BackstagePlugin } from '@backstage/frontend-plugin-api'; import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { ExternalRouteRef } from '@backstage/frontend-plugin-api'; -import { objectUtil } from 'zod'; import { RouteRef } from '@backstage/frontend-plugin-api'; -import { ZodArray } from 'zod'; -import { ZodBoolean } from 'zod'; -import { ZodEnum } from 'zod'; -import { ZodNativeEnum } from 'zod'; -import { ZodNumber } from 'zod'; -import { ZodOptional } from 'zod'; -import { ZodString } from 'zod'; -import { ZodTuple } from 'zod'; // Warning: (ae-missing-release-tag) "CatalogGraphEntityCard" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) export const CatalogGraphEntityCard: ExtensionDefinition< { - filter?: string | undefined; - height?: number | undefined; - curve?: 'curveStepBefore' | 'curveMonotoneX' | undefined; - direction?: Direction | undefined; - title?: string | undefined; - zoom?: 'disabled' | 'enabled' | 'enable-on-click' | undefined; - relations?: string[] | undefined; - maxDepth?: number | undefined; - kinds?: string[] | undefined; - unidirectional?: boolean | undefined; - mergeRelations?: boolean | undefined; - relationPairs?: [string, string][] | undefined; - }, - objectUtil.extendShape< - objectUtil.extendShape< - { - filter: ZodOptional<ZodString>; - }, - { - title: ZodOptional<ZodString>; - height: ZodOptional<ZodNumber>; - } - >, - { - kinds: ZodOptional<ZodArray<ZodString, 'many'>>; - relations: ZodOptional<ZodArray<ZodString, 'many'>>; - maxDepth: ZodOptional<ZodNumber>; - unidirectional: ZodOptional<ZodBoolean>; - mergeRelations: ZodOptional<ZodBoolean>; - direction: ZodOptional<ZodNativeEnum<typeof Direction>>; - relationPairs: ZodOptional< - ZodArray<ZodTuple<[ZodString, ZodString], null>, 'many'> - >; - zoom: ZodOptional<ZodEnum<['enabled', 'disabled', 'enable-on-click']>>; - curve: ZodOptional<ZodEnum<['curveStepBefore', 'curveMonotoneX']>>; - } - >, - { - filter?: string | undefined; - height?: number | undefined; - curve?: 'curveStepBefore' | 'curveMonotoneX' | undefined; - direction?: Direction | undefined; - title?: string | undefined; - zoom?: 'disabled' | 'enabled' | 'enable-on-click' | undefined; - relations?: string[] | undefined; - maxDepth?: number | undefined; - kinds?: string[] | undefined; - unidirectional?: boolean | undefined; - mergeRelations?: boolean | undefined; - relationPairs?: [string, string][] | undefined; + title: string | undefined; + height: number | undefined; + } & { + filter: string | undefined; } >; @@ -93,9 +38,5 @@ const _default: BackstagePlugin< >; export default _default; -// Warnings were encountered during analysis: -// -// src/alpha.d.ts:6:5 - (ae-forgotten-export) The symbol "Direction" needs to be exported by the entry point alpha.d.ts - // (No @packageDocumentation comment for this package) ``` From cac9c3f851221bebef7ae9a3a0b6cc3b816eb9a3 Mon Sep 17 00:00:00 2001 From: blam <ben@blam.sh> Date: Wed, 24 Jul 2024 11:48:07 +0200 Subject: [PATCH 400/416] chore: added some tests Signed-off-by: blam <ben@blam.sh> --- .../src/schema/createSchemaFromZod.ts | 5 +- .../src/wiring/createExtension.test.ts | 62 ++++++++++++++++++ .../src/wiring/createExtension.ts | 17 +++-- .../wiring/createExtensionBlueprint.test.tsx | 65 +++++++++++++++++++ .../src/wiring/createExtensionBlueprint.ts | 12 ++-- 5 files changed, 149 insertions(+), 12 deletions(-) diff --git a/packages/frontend-plugin-api/src/schema/createSchemaFromZod.ts b/packages/frontend-plugin-api/src/schema/createSchemaFromZod.ts index bfaf57f522..c69ef5dc60 100644 --- a/packages/frontend-plugin-api/src/schema/createSchemaFromZod.ts +++ b/packages/frontend-plugin-api/src/schema/createSchemaFromZod.ts @@ -19,7 +19,10 @@ import { z, ZodSchema, ZodTypeDef } from 'zod'; import zodToJsonSchema from 'zod-to-json-schema'; import { PortableSchema } from './types'; -/** @public */ +/** + * @public + * @deprecated Use the `config.schema` option of `createExtension` instead, or use `createExtensionBlueprint`. + */ export function createSchemaFromZod<TOutput, TInput>( schemaCreator: (zImpl: typeof z) => ZodSchema<TOutput, ZodTypeDef, TInput>, ): PortableSchema<TOutput> { diff --git a/packages/frontend-plugin-api/src/wiring/createExtension.test.ts b/packages/frontend-plugin-api/src/wiring/createExtension.test.ts index 4323737540..468da21eb7 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtension.test.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtension.test.ts @@ -291,4 +291,66 @@ describe('createExtension', () => { 'ExtensionDefinition{namespace=test,attachTo=root@default}', ); }); + + it('should create an extension with config', () => { + const extension = createExtension({ + namespace: 'test', + attachTo: { id: 'root', input: 'default' }, + config: { + schema: { + foo: z => z.string(), + bar: z => z.string().default('bar'), + baz: z => z.string().optional(), + }, + }, + output: { + foo: stringData, + }, + factory({ config }) { + const a1: string = config.foo; + const a2: string = config.bar; + // @ts-expect-error + const a3: string = config.baz; + // @ts-expect-error + const c1: number = config.foo; + // @ts-expect-error + const c2: number = config.bar; + // @ts-expect-error + const c3: number = config.baz; + unused(a1, a2, a3, c1, c2, c3); + + return { + foo: 'bar', + }; + }, + }); + expect(extension.namespace).toBe('test'); + expect(String(extension)).toBe( + 'ExtensionDefinition{namespace=test,attachTo=root@default}', + ); + + expect( + extension.configSchema?.parse({ + foo: 'x', + bar: 'y', + baz: 'z', + qux: 'w', + }), + ).toEqual({ + foo: 'x', + bar: 'y', + baz: 'z', + }); + expect( + extension.configSchema?.parse({ + foo: 'x', + }), + ).toEqual({ + foo: 'x', + bar: 'bar', + }); + expect(() => extension.configSchema?.parse({})).toThrow( + "Missing required value at 'foo'", + ); + }); }); diff --git a/packages/frontend-plugin-api/src/wiring/createExtension.ts b/packages/frontend-plugin-api/src/wiring/createExtension.ts index 6fa3a50634..7783f8e14d 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtension.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtension.ts @@ -82,7 +82,7 @@ export interface CreateExtensionOptions< TOutput extends AnyExtensionDataMap, TInputs extends AnyExtensionInputMap, TConfig, - TConfigSchema extends { [key: string]: z.ZodTypeAny }, + TConfigSchema extends { [key: string]: z.ZodType }, > { kind?: string; namespace?: string; @@ -100,7 +100,9 @@ export interface CreateExtensionOptions< }; factory(context: { node: AppNode; - config: TConfig; + config: TConfig & { + [key in keyof TConfigSchema]: z.infer<TConfigSchema[key]>; + }; inputs: Expand<ResolvedExtensionInputs<TInputs>>; }): Expand<ExtensionDataValues<TOutput>>; } @@ -152,12 +154,14 @@ export function createExtension< TOutput extends AnyExtensionDataMap, TInputs extends AnyExtensionInputMap, TConfig, - TConfigSchema extends { [key: string]: z.ZodTypeAny }, + TConfigSchema extends { [key: string]: z.ZodType }, >( options: CreateExtensionOptions<TOutput, TInputs, TConfig, TConfigSchema>, ): ExtensionDefinition<TConfig> { - // TODO: resovle configSchema from either configSchema or config.schema const newConfigSchema = options.config?.schema; + if (newConfigSchema && options.configSchema) { + throw new Error(`Cannot provide both configSchema and config.schema`); + } const configSchema = newConfigSchema ? createSchemaFromZod(innerZ => innerZ.object( @@ -179,10 +183,13 @@ export function createExtension< inputs: options.inputs ?? {}, output: options.output, configSchema, - factory({ inputs, ...rest }) { + factory({ inputs, config, ...rest }) { // TODO: Simplify this, but TS wouldn't infer the input type for some reason return options.factory({ inputs: inputs as Expand<ResolvedExtensionInputs<TInputs>>, + config: config as TConfig & { + [key in keyof TConfigSchema]: z.infer<TConfigSchema[key]>; + }, ...rest, }); }, diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.test.tsx b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.test.tsx index d2373518a3..cf7de0fed3 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.test.tsx +++ b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.test.tsx @@ -20,6 +20,8 @@ import { createExtensionBlueprint } from './createExtensionBlueprint'; import { createExtensionTester } from '@backstage/frontend-test-utils'; import { createExtensionDataRef } from './createExtensionDataRef'; +function unused(..._any: any[]) {} + describe('createExtensionBlueprint', () => { it('should allow creation of extension blueprints', () => { const TestExtensionBlueprint = createExtensionBlueprint({ @@ -124,4 +126,67 @@ describe('createExtensionBlueprint', () => { data: dataRef, }); }); + + it('should allow defining a config schema with additional properties in the instance', () => { + const TestExtensionBlueprint = createExtensionBlueprint({ + kind: 'test-extension', + attachTo: { id: 'test', input: 'default' }, + output: { + element: coreExtensionData.reactElement, + }, + config: { + schema: { + text: z => z.string(), + }, + }, + factory(_, { config }) { + // @ts-expect-error + const b = config.something; + + const a: string = config.text; + unused(a); + + expect(config.text).toBe('Hello, world!'); + + return { + element: <h1>{config.text}</h1>, + }; + }, + }); + + const extension = TestExtensionBlueprint.make({ + name: 'my-extension', + params: { + text: 'Hello, world!', + }, + config: { + schema: { + something: z => z.string(), + defaulted: z => z.string().optional().default('default'), + }, + }, + factory(origFactory, { config }) { + const b: string = config.something; + const c: string = config.text; + const d: string = config.defaulted; + + unused(b, c, d); + + expect(config.text).toBe('Hello, world!'); + expect(config.something).toBe('something new!'); + expect(config.defaulted).toBe('lolz'); + return origFactory({}); + }, + }); + + expect.assertions(4); + + createExtensionTester(extension, { + config: { + something: 'something new!', + text: 'Hello, world!', + defaulted: 'lolz', + }, + }).render(); + }); }); diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts index c54131622f..56edcd8141 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts @@ -33,7 +33,7 @@ export interface CreateExtensionBlueprintOptions< TParams, TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, - TConfigSchema extends { [key in string]: z.ZodTypeAny }, + TConfigSchema extends { [key in string]: z.ZodType }, TDataRefs extends AnyExtensionDataMap, > { kind: string; @@ -79,7 +79,7 @@ export interface ExtensionBlueprint< * You must either pass `params` directly, or define a `factory` that can * optionally call the original factory with the same params. */ - make<TExtensionConfigSchema extends { [key in string]: z.ZodTypeAny }>( + make<TExtensionConfigSchema extends { [key in string]: z.ZodType }>( args: { namespace?: string; name?: string; @@ -135,7 +135,7 @@ class ExtensionBlueprintImpl< TParams, TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, - TConfigSchema extends { [key in string]: z.ZodTypeAny }, + TConfigSchema extends { [key in string]: z.ZodType }, TDataRefs extends AnyExtensionDataMap, > { constructor( @@ -153,7 +153,7 @@ class ExtensionBlueprintImpl< dataRefs: TDataRefs; public make< - TExtensionConfigSchema extends { [key in string]: z.ZodTypeAny }, + TExtensionConfigSchema extends { [key in string]: z.ZodType }, >(args: { namespace?: string; name?: string; @@ -202,7 +202,7 @@ class ExtensionBlueprintImpl< > { const schema = { ...this.options.config?.schema, - ...args.config, + ...args.config?.schema, } as { [key in keyof TConfigSchema]: (zImpl: typeof z) => TConfigSchema[key]; } & { @@ -266,7 +266,7 @@ export function createExtensionBlueprint< TParams, TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, - TConfigSchema extends { [key in string]: z.ZodTypeAny }, + TConfigSchema extends { [key in string]: z.ZodType }, TDataRefs extends AnyExtensionDataMap = never, >( options: CreateExtensionBlueprintOptions< From 97157c547052fdd46e86c1a28f6c99387a3f89d7 Mon Sep 17 00:00:00 2001 From: blam <ben@blam.sh> Date: Wed, 24 Jul 2024 11:51:52 +0200 Subject: [PATCH 401/416] chore: do not allow redefing types from blueprint in make config schema Signed-off-by: blam <ben@blam.sh> --- .../wiring/createExtensionBlueprint.test.tsx | 36 +++++++++++++++++++ .../src/wiring/createExtensionBlueprint.ts | 2 ++ 2 files changed, 38 insertions(+) diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.test.tsx b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.test.tsx index cf7de0fed3..209e9759bd 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.test.tsx +++ b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.test.tsx @@ -189,4 +189,40 @@ describe('createExtensionBlueprint', () => { }, }).render(); }); + + it('should not allow overlapping config keys', () => { + const TestExtensionBlueprint = createExtensionBlueprint({ + kind: 'test-extension', + attachTo: { id: 'test', input: 'default' }, + output: { + element: coreExtensionData.reactElement, + }, + config: { + schema: { + text: z => z.string(), + }, + }, + factory(params: { text: string }) { + return { + element: <div>{params.text}</div>, + }; + }, + }); + + TestExtensionBlueprint.make({ + name: 'my-extension', + params: { + text: 'Hello, world!', + }, + config: { + schema: { + // @ts-expect-error + text: z => z.number(), + something: z => z.string(), + }, + }, + }); + + expect('test').toBe('test'); + }); }); diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts index 56edcd8141..21c10f3c0e 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts @@ -92,6 +92,8 @@ export interface ExtensionBlueprint< [key in keyof TExtensionConfigSchema]: ( zImpl: typeof z, ) => TExtensionConfigSchema[key]; + } & { + [key in keyof TConfig]?: never; }; }; } & ( From e59ff0b2bc1b637df7b476dc323aa44d7e92ca37 Mon Sep 17 00:00:00 2001 From: blam <ben@blam.sh> Date: Wed, 24 Jul 2024 12:06:53 +0200 Subject: [PATCH 402/416] chore: tidy up Signed-off-by: blam <ben@blam.sh> --- packages/frontend-plugin-api/api-report.md | 121 ++++++++++++------ .../src/extensions/IconBundleBlueprint.ts | 36 ------ .../src/app/createExtensionTester.tsx | 4 +- plugins/catalog-graph/api-report-alpha.md | 13 -- plugins/catalog-graph/src/alpha.tsx | 79 +++--------- plugins/catalog-react/api-report-alpha.md | 56 ++------ plugins/catalog-react/src/alpha.tsx | 51 -------- plugins/catalog/api-report-alpha.md | 35 +---- plugins/catalog/src/alpha/index.ts | 2 - plugins/search-react/api-report-alpha.md | 3 +- plugins/search/api-report-alpha.md | 26 ++-- plugins/techdocs/api-report-alpha.md | 18 +-- plugins/user-settings/api-report-alpha.md | 10 +- 13 files changed, 130 insertions(+), 324 deletions(-) diff --git a/packages/frontend-plugin-api/api-report.md b/packages/frontend-plugin-api/api-report.md index 0c7c3b1d92..33ac02437c 100644 --- a/packages/frontend-plugin-api/api-report.md +++ b/packages/frontend-plugin-api/api-report.md @@ -89,7 +89,6 @@ import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; import { vmwareCloudAuthApiRef } from '@backstage/core-plugin-api'; import { withApis } from '@backstage/core-plugin-api'; import { z } from 'zod'; -import { ZodObject } from 'zod'; import { ZodSchema } from 'zod'; import { ZodTypeDef } from 'zod'; @@ -392,7 +391,7 @@ export function createApiExtension< configSchema?: PortableSchema<TConfig>; inputs?: TInputs; }, -): ExtensionDefinition<TConfig, ZodObject<any, any, any, any, any>>; +): ExtensionDefinition<TConfig>; // @public (undocumented) export namespace createApiExtension { @@ -488,7 +487,7 @@ export function createComponentExtension< inputs: Expand<ResolvedExtensionInputs<TInputs>>; }) => ComponentType<TProps>; }; -}): ExtensionDefinition<TConfig, ZodObject<any, any, any, any, any>>; +}): ExtensionDefinition<TConfig>; // @public (undocumented) export namespace createComponentExtension { @@ -512,35 +511,49 @@ export function createComponentRef<T extends {} = {}>(options: { export function createExtension< TOutput extends AnyExtensionDataMap, TInputs extends AnyExtensionInputMap, - TConfigSchema extends z.ZodObject<any, any, any, any, any>, - TConfig extends z.infer<TConfigSchema>, + TConfig, + TConfigSchema extends { + [key: string]: z.ZodType; + }, >( - options: CreateExtensionOptions<TOutput, TInputs, TConfigSchema, TConfig>, -): ExtensionDefinition<TConfig, TConfigSchema>; + options: CreateExtensionOptions<TOutput, TInputs, TConfig, TConfigSchema>, +): ExtensionDefinition<TConfig>; // @public export function createExtensionBlueprint< TParams, TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, - TConfig, + TConfigSchema extends { + [key in string]: z.ZodType; + }, TDataRefs extends AnyExtensionDataMap = never, >( options: CreateExtensionBlueprintOptions< TParams, TInputs, TOutput, - TConfig, + TConfigSchema, TDataRefs >, -): ExtensionBlueprint<TParams, TInputs, TOutput, TConfig, TDataRefs>; +): ExtensionBlueprint< + TParams, + TInputs, + TOutput, + { + [key in keyof TConfigSchema]: z.infer<TConfigSchema[key]>; + }, + TDataRefs +>; // @public (undocumented) export interface CreateExtensionBlueprintOptions< TParams, TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, - TConfig, + TConfigSchema extends { + [key in string]: z.ZodType; + }, TDataRefs extends AnyExtensionDataMap, > { // (undocumented) @@ -549,7 +562,11 @@ export interface CreateExtensionBlueprintOptions< input: string; }; // (undocumented) - configSchema?: PortableSchema<TConfig>; + config?: { + schema: { + [key in keyof TConfigSchema]: (zImpl: typeof z) => TConfigSchema[key]; + }; + }; // (undocumented) dataRefs?: TDataRefs; // (undocumented) @@ -559,7 +576,9 @@ export interface CreateExtensionBlueprintOptions< params: TParams, context: { node: AppNode; - config: TConfig; + config: { + [key in keyof TConfigSchema]: z.infer<TConfigSchema[key]>; + }; inputs: Expand<ResolvedExtensionInputs<TInputs>>; }, ): Expand<ExtensionDataValues<TOutput>>; @@ -607,8 +626,10 @@ export function createExtensionInput< export interface CreateExtensionOptions< TOutput extends AnyExtensionDataMap, TInputs extends AnyExtensionInputMap, - TConfigSchema extends z.ZodObject<any, any, any, any, any>, - TConfig extends z.infer<TConfigSchema>, + TConfig, + TConfigSchema extends { + [key: string]: z.ZodType; + }, > { // (undocumented) attachTo: { @@ -617,7 +638,9 @@ export interface CreateExtensionOptions< }; // (undocumented) config?: { - schema: (context: { z: typeof z }) => TConfigSchema; + schema: { + [key in keyof TConfigSchema]: (zImpl: typeof z) => TConfigSchema[key]; + }; }; // @deprecated (undocumented) configSchema?: PortableSchema<TConfig>; @@ -626,7 +649,9 @@ export interface CreateExtensionOptions< // (undocumented) factory(context: { node: AppNode; - config: TConfig; + config: TConfig & { + [key in keyof TConfigSchema]: z.infer<TConfigSchema[key]>; + }; inputs: Expand<ResolvedExtensionInputs<TInputs>>; }): Expand<ExtensionDataValues<TOutput>>; // (undocumented) @@ -679,12 +704,9 @@ export function createNavItemExtension(options: { routeRef: RouteRef<undefined>; title: string; icon: IconComponent_2; -}): ExtensionDefinition< - { - title: string; - }, - ZodObject<any, any, any, any, any> ->; +}): ExtensionDefinition<{ + title: string; +}>; // @public (undocumented) export namespace createNavItemExtension { @@ -706,7 +728,7 @@ export function createNavLogoExtension(options: { namespace?: string; logoIcon: JSX.Element; logoFull: JSX.Element; -}): ExtensionDefinition<any, ZodObject<any, any, any, any, any>>; +}): ExtensionDefinition<unknown>; // @public (undocumented) export namespace createNavLogoExtension { @@ -814,7 +836,7 @@ export namespace createRouterExtension { >; } -// @public (undocumented) +// @public @deprecated (undocumented) export function createSchemaFromZod<TOutput, TInput>( schemaCreator: (zImpl: typeof z) => ZodSchema<TOutput, ZodTypeDef, TInput>, ): PortableSchema<TOutput>; @@ -861,7 +883,7 @@ export function createSubRouteRef< // @public (undocumented) export function createThemeExtension( theme: AppTheme, -): ExtensionDefinition<any, ZodObject<any, any, any, any, any>>; +): ExtensionDefinition<unknown>; // @public (undocumented) export namespace createThemeExtension { @@ -877,7 +899,7 @@ export namespace createThemeExtension { export function createTranslationExtension(options: { name?: string; resource: TranslationResource | TranslationMessages; -}): ExtensionDefinition<any, ZodObject<any, any, any, any, any>>; +}): ExtensionDefinition<unknown>; // @public (undocumented) export namespace createTranslationExtension { @@ -936,12 +958,18 @@ export interface ExtensionBlueprint< TParams, TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, - TConfig, + TConfig extends { + [key in string]: unknown; + }, TDataRefs extends AnyExtensionDataMap, > { // (undocumented) dataRefs: TDataRefs; - make( + make< + TExtensionConfigSchema extends { + [key in string]: z.ZodType; + }, + >( args: { namespace?: string; name?: string; @@ -952,7 +980,15 @@ export interface ExtensionBlueprint< disabled?: boolean; inputs?: TInputs; output?: TOutput; - configSchema?: PortableSchema<TConfig>; + config?: { + schema: { + [key in keyof TExtensionConfigSchema]: ( + zImpl: typeof z, + ) => TExtensionConfigSchema[key]; + } & { + [key in keyof TConfig]?: never; + }; + }; } & ( | { factory( @@ -965,7 +1001,11 @@ export interface ExtensionBlueprint< ) => Expand<ExtensionDataValues<TOutput>>, context: { node: AppNode; - config: TConfig; + config: { + [key in keyof TExtensionConfigSchema]: z.infer< + TExtensionConfigSchema[key] + >; + } & TConfig; inputs: Expand<ResolvedExtensionInputs<TInputs>>; }, ): Expand<ExtensionDataValues<TOutput>>; @@ -974,7 +1014,13 @@ export interface ExtensionBlueprint< params: TParams; } ), - ): ExtensionDefinition<TConfig>; + ): ExtensionDefinition< + { + [key in keyof TExtensionConfigSchema]: z.infer< + TExtensionConfigSchema[key] + >; + } & TConfig + >; } // @public (undocumented) @@ -1021,10 +1067,7 @@ export type ExtensionDataValues<TExtensionData extends AnyExtensionDataMap> = { }; // @public (undocumented) -export interface ExtensionDefinition< - TConfig, - TConfigSchema extends z.ZodObject<any, any, any, any, any> = any, -> { +export interface ExtensionDefinition<TConfig> { // (undocumented) $$type: '@backstage/ExtensionDefinition'; // (undocumented) @@ -1035,8 +1078,6 @@ export interface ExtensionDefinition< // (undocumented) readonly configSchema?: PortableSchema<TConfig>; // (undocumented) - readonly configSchema2?: TConfigSchema; - // (undocumented) readonly disabled: boolean; // (undocumented) readonly kind?: string; @@ -1134,7 +1175,9 @@ export const IconBundleBlueprint: ExtensionBlueprint< {} >; }, - unknown, + { + [x: string]: any; + }, { icons: ConfigurableExtensionDataRef< 'core.icons', diff --git a/packages/frontend-plugin-api/src/extensions/IconBundleBlueprint.ts b/packages/frontend-plugin-api/src/extensions/IconBundleBlueprint.ts index aba3303f2f..2ad1404102 100644 --- a/packages/frontend-plugin-api/src/extensions/IconBundleBlueprint.ts +++ b/packages/frontend-plugin-api/src/extensions/IconBundleBlueprint.ts @@ -33,39 +33,3 @@ export const IconBundleBlueprint = createExtensionBlueprint({ icons: iconsDataRef, }, }); - -IconBundleBlueprint.make({ - name: 'asd', - params: { - icons: { - 'icon-name': () => null, - }, - }, -}); - -IconBundleBlueprint.make({ - name: 'asd', - params: { - icons: { - 'icon-name': () => null, - }, - }, -}); - -IconBundleBlueprint.make({ - name: 'asd', - factory() { - return { - icons: { - 'icon-name': () => null, - }, - }; - }, -}); - -IconBundleBlueprint.make({ - name: 'asd', - factory(f) { - return f({ icons: { 'icon-name': () => null } }); - }, -}); diff --git a/packages/frontend-test-utils/src/app/createExtensionTester.tsx b/packages/frontend-test-utils/src/app/createExtensionTester.tsx index d6be346002..a98879fbba 100644 --- a/packages/frontend-test-utils/src/app/createExtensionTester.tsx +++ b/packages/frontend-test-utils/src/app/createExtensionTester.tsx @@ -102,11 +102,11 @@ export class ExtensionTester { ...output, path: coreExtensionData.routePath, }, - factory: (params: any) => ({ + factory: params => ({ ...factory(params), path: '/', }), - } as any); + }); tester.add(extension, options); return tester; } diff --git a/plugins/catalog-graph/api-report-alpha.md b/plugins/catalog-graph/api-report-alpha.md index 59a387adf0..3895f12fcf 100644 --- a/plugins/catalog-graph/api-report-alpha.md +++ b/plugins/catalog-graph/api-report-alpha.md @@ -4,22 +4,9 @@ ```ts import { BackstagePlugin } from '@backstage/frontend-plugin-api'; -import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { ExternalRouteRef } from '@backstage/frontend-plugin-api'; import { RouteRef } from '@backstage/frontend-plugin-api'; -// Warning: (ae-missing-release-tag) "CatalogGraphEntityCard" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export const CatalogGraphEntityCard: ExtensionDefinition< - { - title: string | undefined; - height: number | undefined; - } & { - filter: string | undefined; - } ->; - // @public (undocumented) const _default: BackstagePlugin< { diff --git a/plugins/catalog-graph/src/alpha.tsx b/plugins/catalog-graph/src/alpha.tsx index cf663406fa..6d8429332e 100644 --- a/plugins/catalog-graph/src/alpha.tsx +++ b/plugins/catalog-graph/src/alpha.tsx @@ -24,7 +24,7 @@ import { compatWrapper, convertLegacyRouteRef, } from '@backstage/core-compat-api'; -import { EntityCardBlueprint } from '@backstage/plugin-catalog-react/alpha'; +import { createEntityCardExtension } from '@backstage/plugin-catalog-react/alpha'; import { catalogGraphRouteRef, catalogEntityRouteRef } from './routes'; import { Direction } from './components'; @@ -46,67 +46,24 @@ function getEntityGraphRelationsConfigSchema( }); } -export const CatalogGraphEntityCard = EntityCardBlueprint.make({ +const CatalogGraphEntityCard = createEntityCardExtension({ name: 'relations', - // configSchema: origSchema => - // createSchemaFromZod(z => - // z - // .object({ - // // Filter is a config required to all entity cards - // // filter: z.string().optional(), - // title: z.string().optional(), - // height: z.number().optional(), - // // Skipping a "variant" config for now, defaulting to "gridItem" in the component - // // For more details, see this comment: https://github.com/backstage/backstage/pull/22619#discussion_r1477333252 - // }) - // .merge(getEntityGraphRelationsConfigSchema(z)) - // .merge(origSchema), - // ), - - // config: { - // schema: ({ z, parent }) => - // parent - // .merge({ - // title: z.string().optional(), - // height: z.number().optional(), - // }) - // .merge(getEntityGraphRelationsConfigSchema(z)), - // }, - - // config: { - // schema: ({ z, parent }) => - // parent - // .extend({ - // title: z.string().optional(), - // height: z.number().optional(), - // }) - // .merge(getEntityGraphRelationsConfigSchema(z)), - // // .merge(parent) - // }, - - // TODO: implement this and check the types. 👋 zod types. - config: { - schema: { - title: z => z.string().optional(), - height: z => z.number().optional(), - }, - }, - - // config: { - // schema: z => ({ - // title: z.string().optional(), - // height: z.number().optional(), - // }), - // }, - - factory(origFactory, { config: { filter: _, ...props } }) { - return origFactory({ - loader: async () => - import('./components/CatalogGraphCard').then(m => - compatWrapper(<m.CatalogGraphCard {...props} />), - ), - }); - }, + configSchema: createSchemaFromZod(z => + z + .object({ + // Filter is a config required to all entity cards + filter: z.string().optional(), + title: z.string().optional(), + height: z.number().optional(), + // Skipping a "variant" config for now, defaulting to "gridItem" in the component + // For more details, see this comment: https://github.com/backstage/backstage/pull/22619#discussion_r1477333252 + }) + .merge(getEntityGraphRelationsConfigSchema(z)), + ), + loader: async ({ config: { filter, ...props } }) => + import('./components/CatalogGraphCard').then(m => + compatWrapper(<m.CatalogGraphCard {...props} />), + ), }); const CatalogGraphPage = createPageExtension({ diff --git a/plugins/catalog-react/api-report-alpha.md b/plugins/catalog-react/api-report-alpha.md index ccf8205f59..d2bfb29458 100644 --- a/plugins/catalog-react/api-report-alpha.md +++ b/plugins/catalog-react/api-report-alpha.md @@ -3,20 +3,17 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +/// <reference types="react" /> + import { AnyExtensionInputMap } from '@backstage/frontend-plugin-api'; import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; import { Entity } from '@backstage/catalog-model'; -import { ExtensionBlueprint } from '@backstage/frontend-plugin-api'; import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { PortableSchema } from '@backstage/frontend-plugin-api'; -import { default as React_2 } from 'react'; import { ResolvedExtensionInputs } from '@backstage/frontend-plugin-api'; import { ResourcePermission } from '@backstage/plugin-permission-common'; import { RouteRef } from '@backstage/frontend-plugin-api'; import { TranslationRef } from '@backstage/core-plugin-api/alpha'; -import { ZodOptional } from 'zod'; -import { ZodRawShape } from 'zod'; -import { ZodString } from 'zod'; // @alpha (undocumented) export const catalogExtensionData: { @@ -118,7 +115,7 @@ export function createEntityCardExtension< config: TConfig; inputs: Expand<ResolvedExtensionInputs<TInputs>>; }) => Promise<JSX.Element>; -}): ExtensionDefinition<TConfig, ZodRawShape>; +}): ExtensionDefinition<TConfig>; // @alpha (undocumented) export function createEntityContentExtension< @@ -141,48 +138,11 @@ export function createEntityContentExtension< loader: (options: { inputs: Expand<ResolvedExtensionInputs<TInputs>>; }) => Promise<JSX.Element>; -}): ExtensionDefinition< - { - title: string; - path: string; - filter?: string | undefined; - }, - ZodRawShape ->; - -// @alpha (undocumented) -export const EntityCardBlueprint: ExtensionBlueprint< - { - filter?: string | ((entity: Entity) => boolean) | undefined; - loader: () => Promise<JSX.Element>; - }, - AnyExtensionInputMap, - { - element: ConfigurableExtensionDataRef< - 'core.reactElement', - React_2.JSX.Element, - {} - >; - filterFunction: ConfigurableExtensionDataRef< - 'catalog.entity-filter-function', - (entity: Entity) => boolean, - ((entity: Entity) => boolean) & { - optional: true; - } - >; - filterExpression: ConfigurableExtensionDataRef< - 'catalog.entity-filter-expression', - string, - string & { - optional: true; - } - >; - }, - { - filter: ZodOptional<ZodString>; - }, - never ->; +}): ExtensionDefinition<{ + title: string; + path: string; + filter?: string | undefined; +}>; // @alpha export function isOwnerOf(owner: Entity, entity: Entity): boolean; diff --git a/plugins/catalog-react/src/alpha.tsx b/plugins/catalog-react/src/alpha.tsx index f397c76ce0..e81b8e5ebf 100644 --- a/plugins/catalog-react/src/alpha.tsx +++ b/plugins/catalog-react/src/alpha.tsx @@ -22,7 +22,6 @@ import { RouteRef, coreExtensionData, createExtension, - createExtensionBlueprint, createExtensionDataRef, createSchemaFromZod, } from '@backstage/frontend-plugin-api'; @@ -48,49 +47,6 @@ export const catalogExtensionData = { }), }; -/** @alpha */ -export const EntityCardBlueprint = createExtensionBlueprint({ - kind: 'entity-card', - attachTo: { id: 'entity-content:catalog/overview', input: 'cards' }, - // configSchema: createSchemaFromZod(z => - // z.object({ - // filter: z.string().optional(), - // }), - // ), - config: { - schema: { - filter: z => z.string().optional(), - }, - }, - output: { - element: coreExtensionData.reactElement, - filterFunction: catalogExtensionData.entityFilterFunction.optional(), - filterExpression: catalogExtensionData.entityFilterExpression.optional(), - }, - factory( - params: { - filter?: - | typeof catalogExtensionData.entityFilterFunction.T - | typeof catalogExtensionData.entityFilterExpression.T; - loader: () => Promise<JSX.Element>; - }, - { node, config }, - ) { - const ExtensionComponent = lazy(() => - params.loader().then(element => ({ default: () => element })), - ); - - return { - element: ( - <ExtensionBoundary node={node}> - <ExtensionComponent /> - </ExtensionBoundary> - ), - ...mergeFilters({ config, options: params }), - }; - }, -}); - // TODO: Figure out how to merge with provided config schema /** @alpha */ export function createEntityCardExtension< @@ -198,13 +154,6 @@ export function createEntityContentExtension< filter: z.string().optional(), }), ), - // config: { - // schema: ({ z }) => ({ - // path: z.string().default(options.defaultPath), - // title: z.string().default(options.defaultTitle), - // filter: z.string().optional(), - // }), - // }, factory({ config, inputs, node }) { const ExtensionComponent = lazy(() => options diff --git a/plugins/catalog/api-report-alpha.md b/plugins/catalog/api-report-alpha.md index 03711b7d3d..102e2a7aa3 100644 --- a/plugins/catalog/api-report-alpha.md +++ b/plugins/catalog/api-report-alpha.md @@ -12,39 +12,6 @@ import { ExternalRouteRef } from '@backstage/frontend-plugin-api'; import { PortableSchema } from '@backstage/frontend-plugin-api'; import { RouteRef } from '@backstage/frontend-plugin-api'; import { TranslationRef } from '@backstage/core-plugin-api/alpha'; -import { ZodObject } from 'zod'; - -// Warning: (ae-missing-release-tag) "catalogAboutEntityCard" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export const catalogAboutEntityCard: ExtensionDefinition< - { - filter?: string | undefined; - }, - ZodObject<any, any, any, any, any> ->; - -// Warning: (ae-missing-release-tag) "catalogLinksEntityCard" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export const catalogLinksEntityCard: ExtensionDefinition< - { - filter?: string | undefined; - }, - ZodObject<any, any, any, any, any> ->; - -// Warning: (ae-missing-release-tag) "catalogOverviewEntityContent" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export const catalogOverviewEntityContent: ExtensionDefinition< - { - title: string; - path: string; - filter?: string | undefined; - }, - ZodObject<any, any, any, any, any> ->; // @alpha (undocumented) export const catalogTranslationRef: TranslationRef< @@ -139,7 +106,7 @@ export function createCatalogFilterExtension< inputs?: TInputs; configSchema?: PortableSchema<TConfig>; loader: (options: { config: TConfig }) => Promise<JSX.Element>; -}): ExtensionDefinition<TConfig, ZodObject<any, any, any, any, any>>; +}): ExtensionDefinition<TConfig>; // @alpha (undocumented) const _default: BackstagePlugin< diff --git a/plugins/catalog/src/alpha/index.ts b/plugins/catalog/src/alpha/index.ts index acf61865ba..06a78ec6ea 100644 --- a/plugins/catalog/src/alpha/index.ts +++ b/plugins/catalog/src/alpha/index.ts @@ -16,5 +16,3 @@ export { default } from './plugin'; export { createCatalogFilterExtension } from './createCatalogFilterExtension'; -export { catalogAboutEntityCard, catalogLinksEntityCard } from './entityCards'; -export { catalogOverviewEntityContent } from './entityContents'; diff --git a/plugins/search-react/api-report-alpha.md b/plugins/search-react/api-report-alpha.md index 6160759042..aea85d0f81 100644 --- a/plugins/search-react/api-report-alpha.md +++ b/plugins/search-react/api-report-alpha.md @@ -11,7 +11,6 @@ import { ListItemProps } from '@material-ui/core/ListItem'; import { PortableSchema } from '@backstage/frontend-plugin-api'; import { SearchDocument } from '@backstage/plugin-search-common'; import { SearchResult } from '@backstage/plugin-search-common'; -import { ZodObject } from 'zod'; // @alpha (undocumented) export type BaseSearchResultListItemProps<T = {}> = T & { @@ -26,7 +25,7 @@ export function createSearchResultListItemExtension< }, >( options: SearchResultItemExtensionOptions<TConfig>, -): ExtensionDefinition<TConfig, ZodObject<any, any, any, any, any>>; +): ExtensionDefinition<TConfig>; // @alpha (undocumented) export namespace createSearchResultListItemExtension { diff --git a/plugins/search/api-report-alpha.md b/plugins/search/api-report-alpha.md index ade5f530ef..db2999ba25 100644 --- a/plugins/search/api-report-alpha.md +++ b/plugins/search/api-report-alpha.md @@ -6,7 +6,6 @@ import { BackstagePlugin } from '@backstage/frontend-plugin-api'; import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { RouteRef } from '@backstage/frontend-plugin-api'; -import { ZodObject } from 'zod'; // @alpha (undocumented) const _default: BackstagePlugin< @@ -18,27 +17,18 @@ const _default: BackstagePlugin< export default _default; // @alpha (undocumented) -export const searchApi: ExtensionDefinition< - {}, - ZodObject<any, any, any, any, any> ->; +export const searchApi: ExtensionDefinition<{}>; // @alpha (undocumented) -export const searchNavItem: ExtensionDefinition< - { - title: string; - }, - ZodObject<any, any, any, any, any> ->; +export const searchNavItem: ExtensionDefinition<{ + title: string; +}>; // @alpha (undocumented) -export const searchPage: ExtensionDefinition< - { - path: string; - noTrack: boolean; - }, - any ->; +export const searchPage: ExtensionDefinition<{ + path: string; + noTrack: boolean; +}>; // (No @packageDocumentation comment for this package) ``` diff --git a/plugins/techdocs/api-report-alpha.md b/plugins/techdocs/api-report-alpha.md index fc57370a53..cf9f5fa9a3 100644 --- a/plugins/techdocs/api-report-alpha.md +++ b/plugins/techdocs/api-report-alpha.md @@ -6,7 +6,6 @@ import { BackstagePlugin } from '@backstage/frontend-plugin-api'; import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { RouteRef } from '@backstage/frontend-plugin-api'; -import { ZodObject } from 'zod'; // @alpha (undocumented) const _default: BackstagePlugin< @@ -24,16 +23,13 @@ const _default: BackstagePlugin< export default _default; // @alpha (undocumented) -export const techDocsSearchResultListItemExtension: ExtensionDefinition< - { - lineClamp: number; - noTrack: boolean; - asListItem: boolean; - asLink: boolean; - title?: string | undefined; - }, - ZodObject<any, any, any, any, any> ->; +export const techDocsSearchResultListItemExtension: ExtensionDefinition<{ + lineClamp: number; + noTrack: boolean; + asListItem: boolean; + asLink: boolean; + title?: string | undefined; +}>; // (No @packageDocumentation comment for this package) ``` diff --git a/plugins/user-settings/api-report-alpha.md b/plugins/user-settings/api-report-alpha.md index db4373fd43..b06fd1e583 100644 --- a/plugins/user-settings/api-report-alpha.md +++ b/plugins/user-settings/api-report-alpha.md @@ -7,7 +7,6 @@ import { BackstagePlugin } from '@backstage/frontend-plugin-api'; import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { RouteRef } from '@backstage/frontend-plugin-api'; import { TranslationRef } from '@backstage/core-plugin-api/alpha'; -import { ZodObject } from 'zod'; // @alpha (undocumented) const _default: BackstagePlugin< @@ -19,12 +18,9 @@ const _default: BackstagePlugin< export default _default; // @alpha (undocumented) -export const settingsNavItem: ExtensionDefinition< - { - title: string; - }, - ZodObject<any, any, any, any, any> ->; +export const settingsNavItem: ExtensionDefinition<{ + title: string; +}>; // @alpha (undocumented) export const userSettingsTranslationRef: TranslationRef< From 3fb421d1b05281ffdbdfbb42ceb5554931a0aa2f Mon Sep 17 00:00:00 2001 From: blam <ben@blam.sh> Date: Wed, 24 Jul 2024 12:48:49 +0200 Subject: [PATCH 403/416] chore: added changeset Signed-off-by: blam <ben@blam.sh> --- .changeset/sweet-oranges-buy.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/sweet-oranges-buy.md diff --git a/.changeset/sweet-oranges-buy.md b/.changeset/sweet-oranges-buy.md new file mode 100644 index 0000000000..d9f3343e3d --- /dev/null +++ b/.changeset/sweet-oranges-buy.md @@ -0,0 +1,5 @@ +--- +'@backstage/frontend-plugin-api': patch +--- + +Added support to be able to define `zod` config schema in Blueprints, with built in schema merging from the Blueprint and the extension instances. From e9673327852493d196430c0c4eddf12e2effe8bb Mon Sep 17 00:00:00 2001 From: blam <ben@blam.sh> Date: Wed, 24 Jul 2024 13:40:43 +0200 Subject: [PATCH 404/416] chore: small refactor and fixing some of the types Signed-off-by: blam <ben@blam.sh> --- packages/frontend-plugin-api/api-report.md | 51 +++++------ .../src/wiring/createExtension.ts | 12 ++- .../wiring/createExtensionBlueprint.test.tsx | 49 +++++++++++ .../src/wiring/createExtensionBlueprint.ts | 86 ++++++++++--------- 4 files changed, 122 insertions(+), 76 deletions(-) diff --git a/packages/frontend-plugin-api/api-report.md b/packages/frontend-plugin-api/api-report.md index 33ac02437c..45ed51b415 100644 --- a/packages/frontend-plugin-api/api-report.md +++ b/packages/frontend-plugin-api/api-report.md @@ -513,7 +513,7 @@ export function createExtension< TInputs extends AnyExtensionInputMap, TConfig, TConfigSchema extends { - [key: string]: z.ZodType; + [key: string]: (zImpl: typeof z) => z.ZodType; }, >( options: CreateExtensionOptions<TOutput, TInputs, TConfig, TConfigSchema>, @@ -525,7 +525,7 @@ export function createExtensionBlueprint< TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, TConfigSchema extends { - [key in string]: z.ZodType; + [key in string]: (zImpl: typeof z) => z.ZodType; }, TDataRefs extends AnyExtensionDataMap = never, >( @@ -540,9 +540,11 @@ export function createExtensionBlueprint< TParams, TInputs, TOutput, - { - [key in keyof TConfigSchema]: z.infer<TConfigSchema[key]>; - }, + string extends keyof TConfigSchema + ? {} + : { + [key in keyof TConfigSchema]: z.infer<ReturnType<TConfigSchema[key]>>; + }, TDataRefs >; @@ -552,7 +554,7 @@ export interface CreateExtensionBlueprintOptions< TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, TConfigSchema extends { - [key in string]: z.ZodType; + [key in string]: (zImpl: typeof z) => z.ZodType; }, TDataRefs extends AnyExtensionDataMap, > { @@ -563,9 +565,7 @@ export interface CreateExtensionBlueprintOptions< }; // (undocumented) config?: { - schema: { - [key in keyof TConfigSchema]: (zImpl: typeof z) => TConfigSchema[key]; - }; + schema: TConfigSchema; }; // (undocumented) dataRefs?: TDataRefs; @@ -577,7 +577,7 @@ export interface CreateExtensionBlueprintOptions< context: { node: AppNode; config: { - [key in keyof TConfigSchema]: z.infer<TConfigSchema[key]>; + [key in keyof TConfigSchema]: z.infer<ReturnType<TConfigSchema[key]>>; }; inputs: Expand<ResolvedExtensionInputs<TInputs>>; }, @@ -628,7 +628,7 @@ export interface CreateExtensionOptions< TInputs extends AnyExtensionInputMap, TConfig, TConfigSchema extends { - [key: string]: z.ZodType; + [key: string]: (zImpl: typeof z) => z.ZodType; }, > { // (undocumented) @@ -638,9 +638,7 @@ export interface CreateExtensionOptions< }; // (undocumented) config?: { - schema: { - [key in keyof TConfigSchema]: (zImpl: typeof z) => TConfigSchema[key]; - }; + schema: TConfigSchema; }; // @deprecated (undocumented) configSchema?: PortableSchema<TConfig>; @@ -650,7 +648,7 @@ export interface CreateExtensionOptions< factory(context: { node: AppNode; config: TConfig & { - [key in keyof TConfigSchema]: z.infer<TConfigSchema[key]>; + [key in keyof TConfigSchema]: z.infer<ReturnType<TConfigSchema[key]>>; }; inputs: Expand<ResolvedExtensionInputs<TInputs>>; }): Expand<ExtensionDataValues<TOutput>>; @@ -967,7 +965,7 @@ export interface ExtensionBlueprint< dataRefs: TDataRefs; make< TExtensionConfigSchema extends { - [key in string]: z.ZodType; + [key in string]: (zImpl: typeof z) => z.ZodType; }, >( args: { @@ -981,12 +979,9 @@ export interface ExtensionBlueprint< inputs?: TInputs; output?: TOutput; config?: { - schema: { - [key in keyof TExtensionConfigSchema]: ( - zImpl: typeof z, - ) => TExtensionConfigSchema[key]; - } & { - [key in keyof TConfig]?: never; + schema: TExtensionConfigSchema & { + [KName in keyof TConfig]?: `Error: Config key '${KName & + string}' is already defined in parent schema`; }; }; } & ( @@ -1001,11 +996,11 @@ export interface ExtensionBlueprint< ) => Expand<ExtensionDataValues<TOutput>>, context: { node: AppNode; - config: { + config: TConfig & { [key in keyof TExtensionConfigSchema]: z.infer< - TExtensionConfigSchema[key] + ReturnType<TExtensionConfigSchema[key]> >; - } & TConfig; + }; inputs: Expand<ResolvedExtensionInputs<TInputs>>; }, ): Expand<ExtensionDataValues<TOutput>>; @@ -1017,7 +1012,7 @@ export interface ExtensionBlueprint< ): ExtensionDefinition< { [key in keyof TExtensionConfigSchema]: z.infer< - TExtensionConfigSchema[key] + ReturnType<TExtensionConfigSchema[key]> >; } & TConfig >; @@ -1175,9 +1170,7 @@ export const IconBundleBlueprint: ExtensionBlueprint< {} >; }, - { - [x: string]: any; - }, + {}, { icons: ConfigurableExtensionDataRef< 'core.icons', diff --git a/packages/frontend-plugin-api/src/wiring/createExtension.ts b/packages/frontend-plugin-api/src/wiring/createExtension.ts index 7783f8e14d..ac91557906 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtension.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtension.ts @@ -82,7 +82,7 @@ export interface CreateExtensionOptions< TOutput extends AnyExtensionDataMap, TInputs extends AnyExtensionInputMap, TConfig, - TConfigSchema extends { [key: string]: z.ZodType }, + TConfigSchema extends { [key: string]: (zImpl: typeof z) => z.ZodType }, > { kind?: string; namespace?: string; @@ -94,14 +94,12 @@ export interface CreateExtensionOptions< /** @deprecated - use `config.schema` instead */ configSchema?: PortableSchema<TConfig>; config?: { - schema: { - [key in keyof TConfigSchema]: (zImpl: typeof z) => TConfigSchema[key]; - }; + schema: TConfigSchema; }; factory(context: { node: AppNode; config: TConfig & { - [key in keyof TConfigSchema]: z.infer<TConfigSchema[key]>; + [key in keyof TConfigSchema]: z.infer<ReturnType<TConfigSchema[key]>>; }; inputs: Expand<ResolvedExtensionInputs<TInputs>>; }): Expand<ExtensionDataValues<TOutput>>; @@ -154,7 +152,7 @@ export function createExtension< TOutput extends AnyExtensionDataMap, TInputs extends AnyExtensionInputMap, TConfig, - TConfigSchema extends { [key: string]: z.ZodType }, + TConfigSchema extends { [key: string]: (zImpl: typeof z) => z.ZodType }, >( options: CreateExtensionOptions<TOutput, TInputs, TConfig, TConfigSchema>, ): ExtensionDefinition<TConfig> { @@ -188,7 +186,7 @@ export function createExtension< return options.factory({ inputs: inputs as Expand<ResolvedExtensionInputs<TInputs>>, config: config as TConfig & { - [key in keyof TConfigSchema]: z.infer<TConfigSchema[key]>; + [key in keyof TConfigSchema]: z.infer<ReturnType<TConfigSchema[key]>>; }, ...rest, }); diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.test.tsx b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.test.tsx index 209e9759bd..cb8855d892 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.test.tsx +++ b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.test.tsx @@ -225,4 +225,53 @@ describe('createExtensionBlueprint', () => { expect('test').toBe('test'); }); + + it('should allow setting config when one was not already defined in the blueprint', () => { + const TestExtensionBlueprint = createExtensionBlueprint({ + kind: 'test-extension', + attachTo: { id: 'test', input: 'default' }, + output: { + element: coreExtensionData.reactElement, + }, + factory(_, { config }) { + // @ts-expect-error + const b = config.something; + + return { + element: <div />, + }; + }, + }); + + const extension = TestExtensionBlueprint.make({ + name: 'my-extension', + params: { + text: 'Hello, world!', + }, + config: { + schema: { + something: z => z.string(), + defaulted: z => z.string().optional().default('default'), + }, + }, + factory(origFactory, { config }) { + const b: string = config.something; + + unused(b); + + expect(config.something).toBe('something new!'); + expect(config.defaulted).toBe('lolz'); + return origFactory({}); + }, + }); + + expect.assertions(2); + + createExtensionTester(extension, { + config: { + something: 'something new!', + defaulted: 'lolz', + }, + }).render(); + }); }); diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts index 21c10f3c0e..ce3e650342 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts @@ -33,7 +33,7 @@ export interface CreateExtensionBlueprintOptions< TParams, TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, - TConfigSchema extends { [key in string]: z.ZodType }, + TConfigSchema extends { [key in string]: (zImpl: typeof z) => z.ZodType }, TDataRefs extends AnyExtensionDataMap, > { kind: string; @@ -43,16 +43,14 @@ export interface CreateExtensionBlueprintOptions< inputs?: TInputs; output: TOutput; config?: { - schema: { - [key in keyof TConfigSchema]: (zImpl: typeof z) => TConfigSchema[key]; - }; + schema: TConfigSchema; }; factory( params: TParams, context: { node: AppNode; config: { - [key in keyof TConfigSchema]: z.infer<TConfigSchema[key]>; + [key in keyof TConfigSchema]: z.infer<ReturnType<TConfigSchema[key]>>; }; inputs: Expand<ResolvedExtensionInputs<TInputs>>; }, @@ -79,7 +77,11 @@ export interface ExtensionBlueprint< * You must either pass `params` directly, or define a `factory` that can * optionally call the original factory with the same params. */ - make<TExtensionConfigSchema extends { [key in string]: z.ZodType }>( + make< + TExtensionConfigSchema extends { + [key in string]: (zImpl: typeof z) => z.ZodType; + }, + >( args: { namespace?: string; name?: string; @@ -88,12 +90,9 @@ export interface ExtensionBlueprint< inputs?: TInputs; output?: TOutput; config?: { - schema: { - [key in keyof TExtensionConfigSchema]: ( - zImpl: typeof z, - ) => TExtensionConfigSchema[key]; - } & { - [key in keyof TConfig]?: never; + schema: TExtensionConfigSchema & { + [KName in keyof TConfig]?: `Error: Config key '${KName & + string}' is already defined in parent schema`; }; }; } & ( @@ -108,11 +107,11 @@ export interface ExtensionBlueprint< ) => Expand<ExtensionDataValues<TOutput>>, context: { node: AppNode; - config: { + config: TConfig & { [key in keyof TExtensionConfigSchema]: z.infer< - TExtensionConfigSchema[key] + ReturnType<TExtensionConfigSchema[key]> >; - } & TConfig; + }; inputs: Expand<ResolvedExtensionInputs<TInputs>>; }, ): Expand<ExtensionDataValues<TOutput>>; @@ -124,7 +123,7 @@ export interface ExtensionBlueprint< ): ExtensionDefinition< { [key in keyof TExtensionConfigSchema]: z.infer< - TExtensionConfigSchema[key] + ReturnType<TExtensionConfigSchema[key]> >; } & TConfig >; @@ -137,7 +136,7 @@ class ExtensionBlueprintImpl< TParams, TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, - TConfigSchema extends { [key in string]: z.ZodType }, + TConfigSchema extends { [key in string]: (zImpl: typeof z) => z.ZodType }, TDataRefs extends AnyExtensionDataMap, > { constructor( @@ -155,7 +154,9 @@ class ExtensionBlueprintImpl< dataRefs: TDataRefs; public make< - TExtensionConfigSchema extends { [key in string]: z.ZodType }, + TExtensionConfigSchema extends { + [key in string]: (zImpl: typeof z) => z.ZodType; + }, >(args: { namespace?: string; name?: string; @@ -165,18 +166,16 @@ class ExtensionBlueprintImpl< output?: TOutput; params?: TParams; config?: { - schema: { - [key in keyof TExtensionConfigSchema]: ( - zImpl: typeof z, - ) => TExtensionConfigSchema[key]; - }; + schema: TExtensionConfigSchema; }; factory?( originalFactory: ( params: TParams, context?: { config?: { - [key in keyof TConfigSchema]: z.infer<TConfigSchema[key]>; + [key in keyof TConfigSchema]: z.infer< + ReturnType<TConfigSchema[key]> + >; }; inputs?: Expand<ResolvedExtensionInputs<TInputs>>; }, @@ -185,10 +184,10 @@ class ExtensionBlueprintImpl< node: AppNode; config: { [key in keyof TExtensionConfigSchema]: z.infer< - TExtensionConfigSchema[key] + ReturnType<TExtensionConfigSchema[key]> >; } & { - [key in keyof TConfigSchema]: z.infer<TConfigSchema[key]>; + [key in keyof TConfigSchema]: z.infer<ReturnType<TConfigSchema[key]>>; }; inputs: Expand<ResolvedExtensionInputs<TInputs>>; }, @@ -196,23 +195,16 @@ class ExtensionBlueprintImpl< }): ExtensionDefinition< { [key in keyof TExtensionConfigSchema]: z.infer< - TExtensionConfigSchema[key] + ReturnType<TExtensionConfigSchema[key]> >; } & { - [key in keyof TConfigSchema]: z.infer<TConfigSchema[key]>; + [key in keyof TConfigSchema]: z.infer<ReturnType<TConfigSchema[key]>>; } > { const schema = { ...this.options.config?.schema, ...args.config?.schema, - } as { - [key in keyof TConfigSchema]: (zImpl: typeof z) => TConfigSchema[key]; - } & { - [key in keyof TExtensionConfigSchema]: ( - zImpl: typeof z, - ) => TExtensionConfigSchema[key]; - }; - + } as TConfigSchema & TExtensionConfigSchema; return createExtension({ kind: this.options.kind, namespace: args.namespace ?? this.options.namespace, @@ -229,7 +221,9 @@ class ExtensionBlueprintImpl< innerParams: TParams, innerContext?: { config?: { - [key in keyof TConfigSchema]: z.infer<TConfigSchema[key]>; + [key in keyof TConfigSchema]: z.infer< + ReturnType<TConfigSchema[key]> + >; }; inputs?: Expand<ResolvedExtensionInputs<TInputs>>; }, @@ -268,7 +262,7 @@ export function createExtensionBlueprint< TParams, TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, - TConfigSchema extends { [key in string]: z.ZodType }, + TConfigSchema extends { [key in string]: (zImpl: typeof z) => z.ZodType }, TDataRefs extends AnyExtensionDataMap = never, >( options: CreateExtensionBlueprintOptions< @@ -282,8 +276,20 @@ export function createExtensionBlueprint< TParams, TInputs, TOutput, - { [key in keyof TConfigSchema]: z.infer<TConfigSchema[key]> }, + string extends keyof TConfigSchema + ? {} + : { [key in keyof TConfigSchema]: z.infer<ReturnType<TConfigSchema[key]>> }, TDataRefs > { - return new ExtensionBlueprintImpl(options); + return new ExtensionBlueprintImpl(options) as ExtensionBlueprint< + TParams, + TInputs, + TOutput, + string extends keyof TConfigSchema + ? {} + : { + [key in keyof TConfigSchema]: z.infer<ReturnType<TConfigSchema[key]>>; + }, + TDataRefs + >; } From 0ad542cbc7e144c45feb4c2b20babebae9a5c60d Mon Sep 17 00:00:00 2001 From: blam <ben@blam.sh> Date: Wed, 24 Jul 2024 14:36:22 +0200 Subject: [PATCH 405/416] feat: added input types for the config to the extensions Signed-off-by: blam <ben@blam.sh> --- .../src/collectLegacyRoutes.tsx | 4 +- .../extractRouteInfoFromAppNode.test.ts | 2 +- .../src/tree/createAppTree.ts | 2 +- .../src/tree/instantiateAppNodeTree.test.ts | 14 +-- .../src/tree/resolveAppTree.test.ts | 4 +- packages/frontend-plugin-api/api-report.md | 102 +++++++++++++----- .../src/apis/definitions/AppTreeApi.ts | 2 +- .../src/extensions/IconBundleBlueprint.ts | 6 ++ .../src/schema/createSchemaFromZod.test.ts | 15 ++- .../src/schema/createSchemaFromZod.ts | 2 +- .../frontend-plugin-api/src/schema/types.ts | 4 +- .../src/wiring/createExtension.test.ts | 8 +- .../src/wiring/createExtension.ts | 78 +++++++++++--- .../src/wiring/createExtensionBlueprint.ts | 38 ++++++- .../src/wiring/createExtensionOverrides.ts | 2 +- .../src/wiring/createPlugin.ts | 2 +- .../src/wiring/resolveExtensionDefinition.ts | 23 ++-- packages/frontend-test-utils/api-report.md | 6 +- .../src/app/createExtensionTester.tsx | 14 +-- plugins/catalog-react/api-report-alpha.md | 19 ++-- plugins/catalog/api-report-alpha.md | 4 +- .../alpha/createCatalogFilterExtension.tsx | 2 +- plugins/search-react/api-report-alpha.md | 2 +- plugins/search/api-report-alpha.md | 27 +++-- plugins/techdocs/api-report-alpha.md | 23 ++-- plugins/user-settings/api-report-alpha.md | 11 +- 26 files changed, 300 insertions(+), 116 deletions(-) diff --git a/packages/core-compat-api/src/collectLegacyRoutes.tsx b/packages/core-compat-api/src/collectLegacyRoutes.tsx index b9f4e5528c..3523b0a40b 100644 --- a/packages/core-compat-api/src/collectLegacyRoutes.tsx +++ b/packages/core-compat-api/src/collectLegacyRoutes.tsx @@ -101,7 +101,7 @@ function visitRouteChildren(options: { parentExtensionId: string; context: { pluginId: string; - extensions: ExtensionDefinition<unknown>[]; + extensions: ExtensionDefinition<any, any>[]; getUniqueName: () => string; discoverPlugin: (plugin: LegacyBackstagePlugin) => void; }; @@ -154,7 +154,7 @@ export function collectLegacyRoutes( ): BackstagePlugin[] { const pluginExtensions = new Map< LegacyBackstagePlugin, - ExtensionDefinition<unknown>[] + ExtensionDefinition<any, any>[] >(); const getUniqueName = (() => { diff --git a/packages/frontend-app-api/src/routing/extractRouteInfoFromAppNode.test.ts b/packages/frontend-app-api/src/routing/extractRouteInfoFromAppNode.test.ts index 1c332b331f..bdab2781e0 100644 --- a/packages/frontend-app-api/src/routing/extractRouteInfoFromAppNode.test.ts +++ b/packages/frontend-app-api/src/routing/extractRouteInfoFromAppNode.test.ts @@ -70,7 +70,7 @@ function createTestExtension(options: { }); } -function routeInfoFromExtensions(extensions: ExtensionDefinition<unknown>[]) { +function routeInfoFromExtensions(extensions: ExtensionDefinition<any, any>[]) { const plugin = createPlugin({ id: 'test', extensions, diff --git a/packages/frontend-app-api/src/tree/createAppTree.ts b/packages/frontend-app-api/src/tree/createAppTree.ts index 12c7f7fc3a..ee9704c3c3 100644 --- a/packages/frontend-app-api/src/tree/createAppTree.ts +++ b/packages/frontend-app-api/src/tree/createAppTree.ts @@ -25,7 +25,7 @@ import { instantiateAppNodeTree } from './instantiateAppNodeTree'; /** @internal */ export interface CreateAppTreeOptions { features: FrontendFeature[]; - builtinExtensions: Extension<unknown>[]; + builtinExtensions: Extension<any, any>[]; config: Config; } diff --git a/packages/frontend-app-api/src/tree/instantiateAppNodeTree.test.ts b/packages/frontend-app-api/src/tree/instantiateAppNodeTree.test.ts index c5c66e8319..a82c8d99ee 100644 --- a/packages/frontend-app-api/src/tree/instantiateAppNodeTree.test.ts +++ b/packages/frontend-app-api/src/tree/instantiateAppNodeTree.test.ts @@ -59,22 +59,22 @@ const simpleExtension = resolveExtensionDefinition( }), ); -function makeSpec<TConfig>( - extension: Extension<TConfig>, +function makeSpec<TConfig, TConfigInput>( + extension: Extension<TConfig, TConfigInput>, spec?: Partial<AppNodeSpec>, ): AppNodeSpec { return { id: extension.id, attachTo: extension.attachTo, disabled: extension.disabled, - extension, + extension: extension as Extension<unknown, unknown>, source: undefined, ...spec, }; } -function makeNode<TConfig>( - extension: Extension<TConfig>, +function makeNode<TConfig, TConfigInput>( + extension: Extension<TConfig, TConfigInput>, spec?: Partial<AppNodeSpec>, ): AppNode { return { @@ -85,8 +85,8 @@ function makeNode<TConfig>( }; } -function makeInstanceWithId<TConfig>( - extension: Extension<TConfig>, +function makeInstanceWithId<TConfig, TConfigInput>( + extension: Extension<TConfig, TConfigInput>, config?: TConfig, ): AppNode { const node = makeNode(extension, { config }); diff --git a/packages/frontend-app-api/src/tree/resolveAppTree.test.ts b/packages/frontend-app-api/src/tree/resolveAppTree.test.ts index f964fceb50..d9b65555fe 100644 --- a/packages/frontend-app-api/src/tree/resolveAppTree.test.ts +++ b/packages/frontend-app-api/src/tree/resolveAppTree.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { createExtension } from '@backstage/frontend-plugin-api'; +import { createExtension, Extension } 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'; @@ -26,7 +26,7 @@ const extension = resolveExtensionDefinition( output: {}, factory: () => ({}), }), -); +) as Extension<unknown, unknown>; const baseSpec = { extension, diff --git a/packages/frontend-plugin-api/api-report.md b/packages/frontend-plugin-api/api-report.md index 45ed51b415..c4a96cba59 100644 --- a/packages/frontend-plugin-api/api-report.md +++ b/packages/frontend-plugin-api/api-report.md @@ -230,7 +230,7 @@ export interface AppNodeSpec { // (undocumented) readonly disabled: boolean; // (undocumented) - readonly extension: Extension<unknown>; + readonly extension: Extension<unknown, unknown>; // (undocumented) readonly id: string; // (undocumented) @@ -391,7 +391,7 @@ export function createApiExtension< configSchema?: PortableSchema<TConfig>; inputs?: TInputs; }, -): ExtensionDefinition<TConfig>; +): ExtensionDefinition<TConfig & {}, TConfig & {}>; // @public (undocumented) export namespace createApiExtension { @@ -487,7 +487,7 @@ export function createComponentExtension< inputs: Expand<ResolvedExtensionInputs<TInputs>>; }) => ComponentType<TProps>; }; -}): ExtensionDefinition<TConfig>; +}): ExtensionDefinition<TConfig & {}, TConfig & {}>; // @public (undocumented) export namespace createComponentExtension { @@ -512,12 +512,34 @@ export function createExtension< TOutput extends AnyExtensionDataMap, TInputs extends AnyExtensionInputMap, TConfig, + TConfigInput, TConfigSchema extends { [key: string]: (zImpl: typeof z) => z.ZodType; }, >( - options: CreateExtensionOptions<TOutput, TInputs, TConfig, TConfigSchema>, -): ExtensionDefinition<TConfig>; + options: CreateExtensionOptions< + TOutput, + TInputs, + TConfig, + TConfigInput, + TConfigSchema + >, +): ExtensionDefinition< + TConfig & + (string extends keyof TConfigSchema + ? {} + : { + [key in keyof TConfigSchema]: z.infer<ReturnType<TConfigSchema[key]>>; + }), + TConfigInput & + (string extends keyof TConfigSchema + ? {} + : z.input< + z.ZodObject<{ + [key in keyof TConfigSchema]: ReturnType<TConfigSchema[key]>; + }> + >) +>; // @public export function createExtensionBlueprint< @@ -545,6 +567,13 @@ export function createExtensionBlueprint< : { [key in keyof TConfigSchema]: z.infer<ReturnType<TConfigSchema[key]>>; }, + string extends keyof TConfigSchema + ? {} + : z.input< + z.ZodObject<{ + [key in keyof TConfigSchema]: ReturnType<TConfigSchema[key]>; + }> + >, TDataRefs >; @@ -627,6 +656,7 @@ export interface CreateExtensionOptions< TOutput extends AnyExtensionDataMap, TInputs extends AnyExtensionInputMap, TConfig, + TConfigInput, TConfigSchema extends { [key: string]: (zImpl: typeof z) => z.ZodType; }, @@ -641,15 +671,20 @@ export interface CreateExtensionOptions< schema: TConfigSchema; }; // @deprecated (undocumented) - configSchema?: PortableSchema<TConfig>; + configSchema?: PortableSchema<TConfig, TConfigInput>; // (undocumented) disabled?: boolean; // (undocumented) factory(context: { node: AppNode; - config: TConfig & { - [key in keyof TConfigSchema]: z.infer<ReturnType<TConfigSchema[key]>>; - }; + config: TConfig & + (string extends keyof TConfigSchema + ? {} + : { + [key in keyof TConfigSchema]: z.infer< + ReturnType<TConfigSchema[key]> + >; + }); inputs: Expand<ResolvedExtensionInputs<TInputs>>; }): Expand<ExtensionDataValues<TOutput>>; // (undocumented) @@ -702,9 +737,14 @@ export function createNavItemExtension(options: { routeRef: RouteRef<undefined>; title: string; icon: IconComponent_2; -}): ExtensionDefinition<{ - title: string; -}>; +}): ExtensionDefinition< + { + title: string; + }, + { + title?: string | undefined; + } +>; // @public (undocumented) export namespace createNavItemExtension { @@ -726,7 +766,7 @@ export function createNavLogoExtension(options: { namespace?: string; logoIcon: JSX.Element; logoFull: JSX.Element; -}): ExtensionDefinition<unknown>; +}): ExtensionDefinition<{}, {}>; // @public (undocumented) export namespace createNavLogoExtension { @@ -837,7 +877,7 @@ export namespace createRouterExtension { // @public @deprecated (undocumented) export function createSchemaFromZod<TOutput, TInput>( schemaCreator: (zImpl: typeof z) => ZodSchema<TOutput, ZodTypeDef, TInput>, -): PortableSchema<TOutput>; +): PortableSchema<TOutput, TInput>; // @public (undocumented) export function createSignInPageExtension< @@ -881,7 +921,7 @@ export function createSubRouteRef< // @public (undocumented) export function createThemeExtension( theme: AppTheme, -): ExtensionDefinition<unknown>; +): ExtensionDefinition<{}, {}>; // @public (undocumented) export namespace createThemeExtension { @@ -897,7 +937,7 @@ export namespace createThemeExtension { export function createTranslationExtension(options: { name?: string; resource: TranslationResource | TranslationMessages; -}): ExtensionDefinition<unknown>; +}): ExtensionDefinition<{}, {}>; // @public (undocumented) export namespace createTranslationExtension { @@ -935,7 +975,7 @@ export { ErrorApiErrorContext }; export { errorApiRef }; // @public (undocumented) -export interface Extension<TConfig> { +export interface Extension<TConfig, TConfigInput = TConfig> { // (undocumented) $$type: '@backstage/Extension'; // (undocumented) @@ -944,7 +984,7 @@ export interface Extension<TConfig> { input: string; }; // (undocumented) - readonly configSchema?: PortableSchema<TConfig>; + readonly configSchema?: PortableSchema<TConfig, TConfigInput>; // (undocumented) readonly disabled: boolean; // (undocumented) @@ -959,6 +999,9 @@ export interface ExtensionBlueprint< TConfig extends { [key in string]: unknown; }, + TConfigInput extends { + [key in string]: unknown; + }, TDataRefs extends AnyExtensionDataMap, > { // (undocumented) @@ -1014,7 +1057,15 @@ export interface ExtensionBlueprint< [key in keyof TExtensionConfigSchema]: z.infer< ReturnType<TExtensionConfigSchema[key]> >; - } & TConfig + } & TConfig, + z.input< + z.ZodObject<{ + [key in keyof TExtensionConfigSchema]: ReturnType< + TExtensionConfigSchema[key] + >; + }> + > & + TConfigInput >; } @@ -1062,7 +1113,7 @@ export type ExtensionDataValues<TExtensionData extends AnyExtensionDataMap> = { }; // @public (undocumented) -export interface ExtensionDefinition<TConfig> { +export interface ExtensionDefinition<TConfig, TConfigInput = TConfig> { // (undocumented) $$type: '@backstage/ExtensionDefinition'; // (undocumented) @@ -1071,7 +1122,7 @@ export interface ExtensionDefinition<TConfig> { input: string; }; // (undocumented) - readonly configSchema?: PortableSchema<TConfig>; + readonly configSchema?: PortableSchema<TConfig, TConfigInput>; // (undocumented) readonly disabled: boolean; // (undocumented) @@ -1107,7 +1158,7 @@ export interface ExtensionOverrides { // @public (undocumented) export interface ExtensionOverridesOptions { // (undocumented) - extensions: ExtensionDefinition<unknown>[]; + extensions: ExtensionDefinition<any, any>[]; // (undocumented) featureFlags?: FeatureFlagConfig[]; } @@ -1171,6 +1222,7 @@ export const IconBundleBlueprint: ExtensionBlueprint< >; }, {}, + {}, { icons: ConfigurableExtensionDataRef< 'core.icons', @@ -1235,7 +1287,7 @@ export interface PluginOptions< ExternalRoutes extends AnyExternalRoutes, > { // (undocumented) - extensions?: ExtensionDefinition<unknown>[]; + extensions?: ExtensionDefinition<any, any>[]; // (undocumented) externalRoutes?: ExternalRoutes; // (undocumented) @@ -1247,8 +1299,8 @@ export interface PluginOptions< } // @public (undocumented) -export type PortableSchema<TOutput> = { - parse: (input: unknown) => TOutput; +export type PortableSchema<TOutput, TInput = TOutput> = { + parse: (input: TInput) => TOutput; schema: JsonObject; }; diff --git a/packages/frontend-plugin-api/src/apis/definitions/AppTreeApi.ts b/packages/frontend-plugin-api/src/apis/definitions/AppTreeApi.ts index 6c79a16964..4b5672f894 100644 --- a/packages/frontend-plugin-api/src/apis/definitions/AppTreeApi.ts +++ b/packages/frontend-plugin-api/src/apis/definitions/AppTreeApi.ts @@ -29,7 +29,7 @@ import { BackstagePlugin, Extension, ExtensionDataRef } from '../../wiring'; export interface AppNodeSpec { readonly id: string; readonly attachTo: { id: string; input: string }; - readonly extension: Extension<unknown>; + readonly extension: Extension<unknown, unknown>; readonly disabled: boolean; readonly config?: unknown; readonly source?: BackstagePlugin; diff --git a/packages/frontend-plugin-api/src/extensions/IconBundleBlueprint.ts b/packages/frontend-plugin-api/src/extensions/IconBundleBlueprint.ts index 2ad1404102..438da09b4a 100644 --- a/packages/frontend-plugin-api/src/extensions/IconBundleBlueprint.ts +++ b/packages/frontend-plugin-api/src/extensions/IconBundleBlueprint.ts @@ -28,6 +28,12 @@ export const IconBundleBlueprint = createExtensionBlueprint({ output: { icons: iconsDataRef, }, + config: { + schema: { + icons: z => z.string().default('blob'), + test: z => z.string(), + }, + }, factory: (params: { icons: { [key in string]: IconComponent } }) => params, dataRefs: { icons: iconsDataRef, diff --git a/packages/frontend-plugin-api/src/schema/createSchemaFromZod.test.ts b/packages/frontend-plugin-api/src/schema/createSchemaFromZod.test.ts index 90eba44249..477a1a58c6 100644 --- a/packages/frontend-plugin-api/src/schema/createSchemaFromZod.test.ts +++ b/packages/frontend-plugin-api/src/schema/createSchemaFromZod.test.ts @@ -25,10 +25,19 @@ describe('createSchemaFromZod', () => { }), ); - expect(() => parse({ derp: { bar: 'derp' } })).toThrow( + expect(() => { + // @ts-expect-error + return parse({ derp: { bar: 'derp' } }); + }).toThrow( `Missing required value at 'foo'; Expected number, received string at 'derp.bar'`, ); - expect(() => parse(undefined)).toThrow(`Missing required value`); - expect(() => parse('derp')).toThrow(`Expected object, received string`); + expect(() => { + // @ts-expect-error + return parse(undefined); + }).toThrow(`Missing required value`); + expect(() => { + // @ts-expect-error + return parse('derp'); + }).toThrow(`Expected object, received string`); }); }); diff --git a/packages/frontend-plugin-api/src/schema/createSchemaFromZod.ts b/packages/frontend-plugin-api/src/schema/createSchemaFromZod.ts index c69ef5dc60..9e63515ae4 100644 --- a/packages/frontend-plugin-api/src/schema/createSchemaFromZod.ts +++ b/packages/frontend-plugin-api/src/schema/createSchemaFromZod.ts @@ -25,7 +25,7 @@ import { PortableSchema } from './types'; */ export function createSchemaFromZod<TOutput, TInput>( schemaCreator: (zImpl: typeof z) => ZodSchema<TOutput, ZodTypeDef, TInput>, -): PortableSchema<TOutput> { +): PortableSchema<TOutput, TInput> { const schema = schemaCreator(z); return { // TODO: Types allow z.array etc here but it will break stuff diff --git a/packages/frontend-plugin-api/src/schema/types.ts b/packages/frontend-plugin-api/src/schema/types.ts index 9636d3b896..5644068e90 100644 --- a/packages/frontend-plugin-api/src/schema/types.ts +++ b/packages/frontend-plugin-api/src/schema/types.ts @@ -17,7 +17,7 @@ import { JsonObject } from '@backstage/types'; /** @public */ -export type PortableSchema<TOutput> = { - parse: (input: unknown) => TOutput; +export type PortableSchema<TOutput, TInput = TOutput> = { + parse: (input: TInput) => TOutput; schema: JsonObject; }; diff --git a/packages/frontend-plugin-api/src/wiring/createExtension.test.ts b/packages/frontend-plugin-api/src/wiring/createExtension.test.ts index 468da21eb7..5b737746c2 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtension.test.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtension.test.ts @@ -334,6 +334,7 @@ describe('createExtension', () => { foo: 'x', bar: 'y', baz: 'z', + // @ts-expect-error qux: 'w', }), ).toEqual({ @@ -349,8 +350,9 @@ describe('createExtension', () => { foo: 'x', bar: 'bar', }); - expect(() => extension.configSchema?.parse({})).toThrow( - "Missing required value at 'foo'", - ); + expect(() => { + // @ts-expect-error + return extension.configSchema?.parse({}); + }).toThrow("Missing required value at 'foo'"); }); }); diff --git a/packages/frontend-plugin-api/src/wiring/createExtension.ts b/packages/frontend-plugin-api/src/wiring/createExtension.ts index ac91557906..cc2bec91c9 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtension.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtension.ts @@ -82,6 +82,7 @@ export interface CreateExtensionOptions< TOutput extends AnyExtensionDataMap, TInputs extends AnyExtensionInputMap, TConfig, + TConfigInput, TConfigSchema extends { [key: string]: (zImpl: typeof z) => z.ZodType }, > { kind?: string; @@ -92,33 +93,38 @@ export interface CreateExtensionOptions< inputs?: TInputs; output: TOutput; /** @deprecated - use `config.schema` instead */ - configSchema?: PortableSchema<TConfig>; + configSchema?: PortableSchema<TConfig, TConfigInput>; config?: { schema: TConfigSchema; }; factory(context: { node: AppNode; - config: TConfig & { - [key in keyof TConfigSchema]: z.infer<ReturnType<TConfigSchema[key]>>; - }; + config: TConfig & + (string extends keyof TConfigSchema + ? {} + : { + [key in keyof TConfigSchema]: z.infer< + ReturnType<TConfigSchema[key]> + >; + }); inputs: Expand<ResolvedExtensionInputs<TInputs>>; }): Expand<ExtensionDataValues<TOutput>>; } /** @public */ -export interface ExtensionDefinition<TConfig> { +export interface ExtensionDefinition<TConfig, TConfigInput = TConfig> { $$type: '@backstage/ExtensionDefinition'; readonly kind?: string; readonly namespace?: string; readonly name?: string; readonly attachTo: { id: string; input: string }; readonly disabled: boolean; - readonly configSchema?: PortableSchema<TConfig>; + readonly configSchema?: PortableSchema<TConfig, TConfigInput>; } /** @internal */ -export interface InternalExtensionDefinition<TConfig> - extends ExtensionDefinition<TConfig> { +export interface InternalExtensionDefinition<TConfig, TConfigInput> + extends ExtensionDefinition<TConfig, TConfigInput> { readonly version: 'v1'; readonly inputs: AnyExtensionInputMap; readonly output: AnyExtensionDataMap; @@ -130,10 +136,13 @@ export interface InternalExtensionDefinition<TConfig> } /** @internal */ -export function toInternalExtensionDefinition<TConfig>( - overrides: ExtensionDefinition<TConfig>, -): InternalExtensionDefinition<TConfig> { - const internal = overrides as InternalExtensionDefinition<TConfig>; +export function toInternalExtensionDefinition<TConfig, TConfigInput>( + overrides: ExtensionDefinition<TConfig, TConfigInput>, +): InternalExtensionDefinition<TConfig, TConfigInput> { + const internal = overrides as InternalExtensionDefinition< + TConfig, + TConfigInput + >; if (internal.$$type !== '@backstage/ExtensionDefinition') { throw new Error( `Invalid extension definition instance, bad type '${internal.$$type}'`, @@ -152,10 +161,32 @@ export function createExtension< TOutput extends AnyExtensionDataMap, TInputs extends AnyExtensionInputMap, TConfig, + TConfigInput, TConfigSchema extends { [key: string]: (zImpl: typeof z) => z.ZodType }, >( - options: CreateExtensionOptions<TOutput, TInputs, TConfig, TConfigSchema>, -): ExtensionDefinition<TConfig> { + options: CreateExtensionOptions< + TOutput, + TInputs, + TConfig, + TConfigInput, + TConfigSchema + >, +): ExtensionDefinition< + TConfig & + (string extends keyof TConfigSchema + ? {} + : { + [key in keyof TConfigSchema]: z.infer<ReturnType<TConfigSchema[key]>>; + }), + TConfigInput & + (string extends keyof TConfigSchema + ? {} + : z.input< + z.ZodObject<{ + [key in keyof TConfigSchema]: ReturnType<TConfigSchema[key]>; + }> + >) +> { const newConfigSchema = options.config?.schema; if (newConfigSchema && options.configSchema) { throw new Error(`Cannot provide both configSchema and config.schema`); @@ -205,5 +236,22 @@ export function createExtension< parts.push(`attachTo=${options.attachTo.id}@${options.attachTo.input}`); return `ExtensionDefinition{${parts.join(',')}}`; }, - } as InternalExtensionDefinition<TConfig>; + } as InternalExtensionDefinition< + TConfig & + (string extends keyof TConfigSchema + ? {} + : { + [key in keyof TConfigSchema]: z.infer< + ReturnType<TConfigSchema[key]> + >; + }), + TConfigInput & + (string extends keyof TConfigSchema + ? {} + : z.input< + z.ZodObject<{ + [key in keyof TConfigSchema]: ReturnType<TConfigSchema[key]>; + }> + >) + >; } diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts index ce3e650342..7393ca233e 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts @@ -67,6 +67,7 @@ export interface ExtensionBlueprint< TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, TConfig extends { [key in string]: unknown }, + TConfigInput extends { [key in string]: unknown }, TDataRefs extends AnyExtensionDataMap, > { dataRefs: TDataRefs; @@ -125,7 +126,15 @@ export interface ExtensionBlueprint< [key in keyof TExtensionConfigSchema]: z.infer< ReturnType<TExtensionConfigSchema[key]> >; - } & TConfig + } & TConfig, + z.input< + z.ZodObject<{ + [key in keyof TExtensionConfigSchema]: ReturnType< + TExtensionConfigSchema[key] + >; + }> + > & + TConfigInput >; } @@ -199,7 +208,18 @@ class ExtensionBlueprintImpl< >; } & { [key in keyof TConfigSchema]: z.infer<ReturnType<TConfigSchema[key]>>; - } + }, + z.input< + z.ZodObject< + { + [key in keyof TExtensionConfigSchema]: ReturnType< + TExtensionConfigSchema[key] + >; + } & { + [key in keyof TConfigSchema]: ReturnType<TConfigSchema[key]>; + } + > + > > { const schema = { ...this.options.config?.schema, @@ -279,6 +299,13 @@ export function createExtensionBlueprint< string extends keyof TConfigSchema ? {} : { [key in keyof TConfigSchema]: z.infer<ReturnType<TConfigSchema[key]>> }, + string extends keyof TConfigSchema + ? {} + : z.input< + z.ZodObject<{ + [key in keyof TConfigSchema]: ReturnType<TConfigSchema[key]>; + }> + >, TDataRefs > { return new ExtensionBlueprintImpl(options) as ExtensionBlueprint< @@ -290,6 +317,13 @@ export function createExtensionBlueprint< : { [key in keyof TConfigSchema]: z.infer<ReturnType<TConfigSchema[key]>>; }, + string extends keyof TConfigSchema + ? {} + : z.input< + z.ZodObject<{ + [key in keyof TConfigSchema]: ReturnType<TConfigSchema[key]>; + }> + >, TDataRefs >; } diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionOverrides.ts b/packages/frontend-plugin-api/src/wiring/createExtensionOverrides.ts index 1f88038944..75c43a36d2 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtensionOverrides.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtensionOverrides.ts @@ -23,7 +23,7 @@ import { ExtensionOverrides, FeatureFlagConfig } from './types'; /** @public */ export interface ExtensionOverridesOptions { - extensions: ExtensionDefinition<unknown>[]; + extensions: ExtensionDefinition<any, any>[]; featureFlags?: FeatureFlagConfig[]; } diff --git a/packages/frontend-plugin-api/src/wiring/createPlugin.ts b/packages/frontend-plugin-api/src/wiring/createPlugin.ts index 797c46e58e..b671d95d2f 100644 --- a/packages/frontend-plugin-api/src/wiring/createPlugin.ts +++ b/packages/frontend-plugin-api/src/wiring/createPlugin.ts @@ -34,7 +34,7 @@ export interface PluginOptions< id: string; routes?: Routes; externalRoutes?: ExternalRoutes; - extensions?: ExtensionDefinition<unknown>[]; + extensions?: ExtensionDefinition<any, any>[]; featureFlags?: FeatureFlagConfig[]; } diff --git a/packages/frontend-plugin-api/src/wiring/resolveExtensionDefinition.ts b/packages/frontend-plugin-api/src/wiring/resolveExtensionDefinition.ts index 0a44de4ab4..eddd923702 100644 --- a/packages/frontend-plugin-api/src/wiring/resolveExtensionDefinition.ts +++ b/packages/frontend-plugin-api/src/wiring/resolveExtensionDefinition.ts @@ -26,16 +26,17 @@ import { import { PortableSchema } from '../schema'; /** @public */ -export interface Extension<TConfig> { +export interface Extension<TConfig, TConfigInput = TConfig> { $$type: '@backstage/Extension'; readonly id: string; readonly attachTo: { id: string; input: string }; readonly disabled: boolean; - readonly configSchema?: PortableSchema<TConfig>; + readonly configSchema?: PortableSchema<TConfig, TConfigInput>; } /** @internal */ -export interface InternalExtension<TConfig> extends Extension<TConfig> { +export interface InternalExtension<TConfig, TConfigInput> + extends Extension<TConfig, TConfigInput> { readonly version: 'v1'; readonly inputs: AnyExtensionInputMap; readonly output: AnyExtensionDataMap; @@ -47,10 +48,10 @@ export interface InternalExtension<TConfig> extends Extension<TConfig> { } /** @internal */ -export function toInternalExtension<TConfig>( - overrides: Extension<TConfig>, -): InternalExtension<TConfig> { - const internal = overrides as InternalExtension<TConfig>; +export function toInternalExtension<TConfig, TConfigInput>( + overrides: Extension<TConfig, TConfigInput>, +): InternalExtension<TConfig, TConfigInput> { + const internal = overrides as InternalExtension<TConfig, TConfigInput>; if (internal.$$type !== '@backstage/Extension') { throw new Error( `Invalid extension instance, bad type '${internal.$$type}'`, @@ -65,10 +66,10 @@ export function toInternalExtension<TConfig>( } /** @internal */ -export function resolveExtensionDefinition<TConfig>( - definition: ExtensionDefinition<TConfig>, +export function resolveExtensionDefinition<TConfig, TConfigInput>( + definition: ExtensionDefinition<TConfig, TConfigInput>, context?: { namespace?: string }, -): Extension<TConfig> { +): Extension<TConfig, TConfigInput> { const internalDefinition = toInternalExtensionDefinition(definition); const { name, kind, namespace: _, ...rest } = internalDefinition; const namespace = internalDefinition.namespace ?? context?.namespace; @@ -91,5 +92,5 @@ export function resolveExtensionDefinition<TConfig>( toString() { return `Extension{id=${id}}`; }, - } as Extension<TConfig>; + } as Extension<TConfig, TConfigInput>; } diff --git a/packages/frontend-test-utils/api-report.md b/packages/frontend-test-utils/api-report.md index 9629e13bfa..3b368394ca 100644 --- a/packages/frontend-test-utils/api-report.md +++ b/packages/frontend-test-utils/api-report.md @@ -39,10 +39,10 @@ export { ErrorWithContext }; // @public (undocumented) export class ExtensionTester { // (undocumented) - add<TConfig>( - extension: ExtensionDefinition<TConfig>, + add<TConfig, TConfigInput>( + extension: ExtensionDefinition<TConfig, TConfigInput>, options?: { - config?: TConfig; + config?: TConfigInput; }, ): ExtensionTester; // (undocumented) diff --git a/packages/frontend-test-utils/src/app/createExtensionTester.tsx b/packages/frontend-test-utils/src/app/createExtensionTester.tsx index a98879fbba..69c4b09d06 100644 --- a/packages/frontend-test-utils/src/app/createExtensionTester.tsx +++ b/packages/frontend-test-utils/src/app/createExtensionTester.tsx @@ -88,9 +88,9 @@ const TestAppNavExtension = createExtension({ /** @public */ export class ExtensionTester { /** @internal */ - static forSubject<TConfig>( - subject: ExtensionDefinition<TConfig>, - options?: { config?: TConfig }, + static forSubject<TConfig, TConfigInput>( + subject: ExtensionDefinition<TConfig, TConfigInput>, + options?: { config?: TConfigInput }, ): ExtensionTester { const tester = new ExtensionTester(); const { output, factory, ...rest } = toInternalExtensionDefinition(subject); @@ -107,7 +107,7 @@ export class ExtensionTester { path: '/', }), }); - tester.add(extension, options); + tester.add(extension, options as TConfigInput & {}); return tester; } @@ -117,9 +117,9 @@ export class ExtensionTester { config?: JsonValue; }>(); - add<TConfig>( - extension: ExtensionDefinition<TConfig>, - options?: { config?: TConfig }, + add<TConfig, TConfigInput>( + extension: ExtensionDefinition<TConfig, TConfigInput>, + options?: { config?: TConfigInput }, ): ExtensionTester { const { name, namespace } = extension; diff --git a/plugins/catalog-react/api-report-alpha.md b/plugins/catalog-react/api-report-alpha.md index d2bfb29458..1ffa67068f 100644 --- a/plugins/catalog-react/api-report-alpha.md +++ b/plugins/catalog-react/api-report-alpha.md @@ -115,7 +115,7 @@ export function createEntityCardExtension< config: TConfig; inputs: Expand<ResolvedExtensionInputs<TInputs>>; }) => Promise<JSX.Element>; -}): ExtensionDefinition<TConfig>; +}): ExtensionDefinition<TConfig & {}, TConfig & {}>; // @alpha (undocumented) export function createEntityContentExtension< @@ -138,11 +138,18 @@ export function createEntityContentExtension< loader: (options: { inputs: Expand<ResolvedExtensionInputs<TInputs>>; }) => Promise<JSX.Element>; -}): ExtensionDefinition<{ - title: string; - path: string; - filter?: string | undefined; -}>; +}): ExtensionDefinition< + { + title: string; + path: string; + filter?: string | undefined; + }, + { + filter?: string | undefined; + title?: string | undefined; + path?: string | undefined; + } +>; // @alpha export function isOwnerOf(owner: Entity, entity: Entity): boolean; diff --git a/plugins/catalog/api-report-alpha.md b/plugins/catalog/api-report-alpha.md index 102e2a7aa3..a62b047c4c 100644 --- a/plugins/catalog/api-report-alpha.md +++ b/plugins/catalog/api-report-alpha.md @@ -99,14 +99,14 @@ export const catalogTranslationRef: TranslationRef< // @alpha (undocumented) export function createCatalogFilterExtension< TInputs extends AnyExtensionInputMap, - TConfig = never, + TConfig, >(options: { namespace?: string; name?: string; inputs?: TInputs; configSchema?: PortableSchema<TConfig>; loader: (options: { config: TConfig }) => Promise<JSX.Element>; -}): ExtensionDefinition<TConfig>; +}): ExtensionDefinition<TConfig & {}, TConfig & {}>; // @alpha (undocumented) const _default: BackstagePlugin< diff --git a/plugins/catalog/src/alpha/createCatalogFilterExtension.tsx b/plugins/catalog/src/alpha/createCatalogFilterExtension.tsx index 48ee647b81..d8a218f8f3 100644 --- a/plugins/catalog/src/alpha/createCatalogFilterExtension.tsx +++ b/plugins/catalog/src/alpha/createCatalogFilterExtension.tsx @@ -26,7 +26,7 @@ import { /** @alpha */ export function createCatalogFilterExtension< TInputs extends AnyExtensionInputMap, - TConfig = never, + TConfig, >(options: { namespace?: string; name?: string; diff --git a/plugins/search-react/api-report-alpha.md b/plugins/search-react/api-report-alpha.md index aea85d0f81..3da9ac23a4 100644 --- a/plugins/search-react/api-report-alpha.md +++ b/plugins/search-react/api-report-alpha.md @@ -25,7 +25,7 @@ export function createSearchResultListItemExtension< }, >( options: SearchResultItemExtensionOptions<TConfig>, -): ExtensionDefinition<TConfig>; +): ExtensionDefinition<TConfig & {}, TConfig & {}>; // @alpha (undocumented) export namespace createSearchResultListItemExtension { diff --git a/plugins/search/api-report-alpha.md b/plugins/search/api-report-alpha.md index db2999ba25..e9b86f1f87 100644 --- a/plugins/search/api-report-alpha.md +++ b/plugins/search/api-report-alpha.md @@ -17,18 +17,29 @@ const _default: BackstagePlugin< export default _default; // @alpha (undocumented) -export const searchApi: ExtensionDefinition<{}>; +export const searchApi: ExtensionDefinition<{}, {}>; // @alpha (undocumented) -export const searchNavItem: ExtensionDefinition<{ - title: string; -}>; +export const searchNavItem: ExtensionDefinition< + { + title: string; + }, + { + title?: string | undefined; + } +>; // @alpha (undocumented) -export const searchPage: ExtensionDefinition<{ - path: string; - noTrack: boolean; -}>; +export const searchPage: ExtensionDefinition< + { + path: string; + noTrack: boolean; + }, + { + path: string; + noTrack: boolean; + } +>; // (No @packageDocumentation comment for this package) ``` diff --git a/plugins/techdocs/api-report-alpha.md b/plugins/techdocs/api-report-alpha.md index cf9f5fa9a3..04a0c5c512 100644 --- a/plugins/techdocs/api-report-alpha.md +++ b/plugins/techdocs/api-report-alpha.md @@ -23,13 +23,22 @@ const _default: BackstagePlugin< export default _default; // @alpha (undocumented) -export const techDocsSearchResultListItemExtension: ExtensionDefinition<{ - lineClamp: number; - noTrack: boolean; - asListItem: boolean; - asLink: boolean; - title?: string | undefined; -}>; +export const techDocsSearchResultListItemExtension: ExtensionDefinition< + { + lineClamp: number; + noTrack: boolean; + asListItem: boolean; + asLink: boolean; + title?: string | undefined; + }, + { + lineClamp: number; + noTrack: boolean; + asListItem: boolean; + asLink: boolean; + title?: string | undefined; + } +>; // (No @packageDocumentation comment for this package) ``` diff --git a/plugins/user-settings/api-report-alpha.md b/plugins/user-settings/api-report-alpha.md index b06fd1e583..fdb2c5f6bf 100644 --- a/plugins/user-settings/api-report-alpha.md +++ b/plugins/user-settings/api-report-alpha.md @@ -18,9 +18,14 @@ const _default: BackstagePlugin< export default _default; // @alpha (undocumented) -export const settingsNavItem: ExtensionDefinition<{ - title: string; -}>; +export const settingsNavItem: ExtensionDefinition< + { + title: string; + }, + { + title?: string | undefined; + } +>; // @alpha (undocumented) export const userSettingsTranslationRef: TranslationRef< From 634909993c888a0857fba702ad2b692c96858933 Mon Sep 17 00:00:00 2001 From: blam <ben@blam.sh> Date: Wed, 24 Jul 2024 14:37:38 +0200 Subject: [PATCH 406/416] chore: added changeset Signed-off-by: blam <ben@blam.sh> --- .changeset/young-games-visit.md | 14 ++++++++++++++ packages/frontend-plugin-api/api-report.md | 10 ++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 .changeset/young-games-visit.md diff --git a/.changeset/young-games-visit.md b/.changeset/young-games-visit.md new file mode 100644 index 0000000000..467abcec86 --- /dev/null +++ b/.changeset/young-games-visit.md @@ -0,0 +1,14 @@ +--- +'@backstage/frontend-plugin-api': patch +'@backstage/frontend-test-utils': patch +'@backstage/frontend-app-api': patch +'@backstage/core-compat-api': patch +'@backstage/plugin-catalog-react': patch +'@backstage/plugin-user-settings': patch +'@backstage/plugin-search-react': patch +'@backstage/plugin-techdocs': patch +'@backstage/plugin-catalog': patch +'@backstage/plugin-search': patch +--- + +Added config input type to the extensions diff --git a/packages/frontend-plugin-api/api-report.md b/packages/frontend-plugin-api/api-report.md index c4a96cba59..2c92f863e8 100644 --- a/packages/frontend-plugin-api/api-report.md +++ b/packages/frontend-plugin-api/api-report.md @@ -1221,8 +1221,14 @@ export const IconBundleBlueprint: ExtensionBlueprint< {} >; }, - {}, - {}, + { + icons: string; + test: string; + }, + { + test: string; + icons?: string | undefined; + }, { icons: ConfigurableExtensionDataRef< 'core.icons', From e6e7d862fec44754faac302e6e4d7021a19b9ef0 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg <poldsberg@gmail.com> Date: Wed, 24 Jul 2024 15:04:05 +0200 Subject: [PATCH 407/416] cli: use lowercase es2022 Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com> --- .changeset/shaggy-dodos-applaud.md | 5 +++++ packages/cli/src/lib/bundler/transforms.ts | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 .changeset/shaggy-dodos-applaud.md diff --git a/.changeset/shaggy-dodos-applaud.md b/.changeset/shaggy-dodos-applaud.md new file mode 100644 index 0000000000..b7f968aa39 --- /dev/null +++ b/.changeset/shaggy-dodos-applaud.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Switched the target from `'ES2022'` to `'es2022'` for better compatibility with older versions of `swc`. diff --git a/packages/cli/src/lib/bundler/transforms.ts b/packages/cli/src/lib/bundler/transforms.ts index 1be54f7a73..302b2fbe68 100644 --- a/packages/cli/src/lib/bundler/transforms.ts +++ b/packages/cli/src/lib/bundler/transforms.ts @@ -57,7 +57,7 @@ export const transforms = (options: TransformOptions): Transforms => { loader: require.resolve('swc-loader'), options: { jsc: { - target: 'ES2022', + target: 'es2022', externalHelpers: !isBackend, parser: { syntax: 'typescript', @@ -85,7 +85,7 @@ export const transforms = (options: TransformOptions): Transforms => { loader: require.resolve('swc-loader'), options: { jsc: { - target: 'ES2022', + target: 'es2022', externalHelpers: !isBackend, parser: { syntax: 'ecmascript', From 41fa9d58c50a12017dac05067e4ceb04d1748ee3 Mon Sep 17 00:00:00 2001 From: Nurit Izrailov <nuriti@spotify.com> Date: Wed, 24 Jul 2024 09:16:30 -0400 Subject: [PATCH 408/416] run yarn backstage-cli repo fix Signed-off-by: Nurit Izrailov <nuriti@spotify.com> --- plugins/kubernetes/package.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/plugins/kubernetes/package.json b/plugins/kubernetes/package.json index 6c5a65dddd..d44d175211 100644 --- a/plugins/kubernetes/package.json +++ b/plugins/kubernetes/package.json @@ -14,9 +14,7 @@ ] }, "publishConfig": { - "access": "public", - "main": "dist/index.esm.js", - "types": "dist/index.d.ts" + "access": "public" }, "keywords": [ "backstage", From 132529ae23a1295c294e42b55628d1fcc8cd033c Mon Sep 17 00:00:00 2001 From: raphtalia <59540801+raphtalia@users.noreply.github.com> Date: Wed, 24 Jul 2024 10:36:00 -0500 Subject: [PATCH 409/416] Add Cigna/Evernorth Signed-off-by: raphtalia <59540801+raphtalia@users.noreply.github.com> --- ADOPTERS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/ADOPTERS.md b/ADOPTERS.md index 870b4c93d4..3b534052f1 100644 --- a/ADOPTERS.md +++ b/ADOPTERS.md @@ -274,3 +274,4 @@ _You can do this by using the [Adopter form](https://info.backstage.spotify.com/ | [Grupo OLX](https://www.olx.com.br/) | [@marciorgb](https://github.com/marciorgb), [@jeffbraga](https://github.com/jeffbraga), [@rogerfernandes](https://github.com/rogerfernandes), [@stockrt](https://github.com/stockrt) | At Grupo OLX, we are using Backstage to reduce friction and enhance developer autonomy by creating Golden Paths, which automate previously manual processes. Additionally, Backstage's catalog integrates various views of our organizational structure and workflows, offering a comprehensive overview of how different components interconnect. | | [DPG Media](https://www.dpgmediagroup.com) | [@benjidotsh](https://github.com/benjidotsh), [@lvstb](https://github.com/lvstb), [@ssliman](https://github.com/ssliman), [@edewel-beep](https://github.com/edewel-beep) | Access to infrastructure, documentation and internal tooling | | [Baloise](https://www.baloise.ch) | [@dweber019](https://github.com/dweber019), [@mikevader](https://github.com/mikevader) | We are using Backstage as internal developer protal for use cases like software catalog, documentation, infrastructure. | +| [Cigna](https://www.cigna.com/) / [Evernorth](https://www.evernorth.com/) | [@raphtalia](https://github.com/raphtalia), [Devon Paluso](mailto:Devon.Paluso@evernorth.com), [Bryan Rego](mailto:Bryan.Rego@evernorth.com), [Ian Skillings](mailto:Ian.Skillings@evernorth.com) | Internal developer portal providing TechDocs, software templates, centralized secret management, with information consolidation from ServiceNow, Okta, GitHub, GitLab, and WebEx. | From 4cda00c9968835174bed5925e4e0c24548063daf Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg <poldsberg@gmail.com> Date: Wed, 24 Jul 2024 15:04:05 +0200 Subject: [PATCH 410/416] cli: use lowercase es2022 Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com> Signed-off-by: Nishkarsh Raj <nishkarshraj000@gmail.com> --- .changeset/shaggy-dodos-applaud.md | 5 +++++ packages/cli/src/lib/bundler/transforms.ts | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 .changeset/shaggy-dodos-applaud.md diff --git a/.changeset/shaggy-dodos-applaud.md b/.changeset/shaggy-dodos-applaud.md new file mode 100644 index 0000000000..b7f968aa39 --- /dev/null +++ b/.changeset/shaggy-dodos-applaud.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Switched the target from `'ES2022'` to `'es2022'` for better compatibility with older versions of `swc`. diff --git a/packages/cli/src/lib/bundler/transforms.ts b/packages/cli/src/lib/bundler/transforms.ts index 1be54f7a73..302b2fbe68 100644 --- a/packages/cli/src/lib/bundler/transforms.ts +++ b/packages/cli/src/lib/bundler/transforms.ts @@ -57,7 +57,7 @@ export const transforms = (options: TransformOptions): Transforms => { loader: require.resolve('swc-loader'), options: { jsc: { - target: 'ES2022', + target: 'es2022', externalHelpers: !isBackend, parser: { syntax: 'typescript', @@ -85,7 +85,7 @@ export const transforms = (options: TransformOptions): Transforms => { loader: require.resolve('swc-loader'), options: { jsc: { - target: 'ES2022', + target: 'es2022', externalHelpers: !isBackend, parser: { syntax: 'ecmascript', From 93e8169b053ff6c5eb48ac139f7e83a391cade81 Mon Sep 17 00:00:00 2001 From: Nishkarsh Raj <nishkarshraj000@gmail.com> Date: Wed, 24 Jul 2024 18:45:19 +0000 Subject: [PATCH 411/416] Adding StatusNeo as Commercial Partners for Backstage.io Signed-off-by: Nishkarsh Raj <nishkarshraj000@gmail.com> --- microsite/src/pages/community/index.tsx | 5 +++++ microsite/static/img/partner-logo-statusneo.png | Bin 0 -> 4663 bytes 2 files changed, 5 insertions(+) create mode 100644 microsite/static/img/partner-logo-statusneo.png diff --git a/microsite/src/pages/community/index.tsx b/microsite/src/pages/community/index.tsx index c331638c78..a32f5edd13 100644 --- a/microsite/src/pages/community/index.tsx +++ b/microsite/src/pages/community/index.tsx @@ -96,6 +96,11 @@ const Community = () => { url: 'https://tanzu.vmware.com/developer-portal', logo: 'img/partner-logo-tanzubybroadcom.png', }, + { + name: 'StatusNeo', + url: 'https://statusneo.com/backstage', + logo: 'img/partner-logo-statusneo.png', + }, ]; //#endregion diff --git a/microsite/static/img/partner-logo-statusneo.png b/microsite/static/img/partner-logo-statusneo.png new file mode 100644 index 0000000000000000000000000000000000000000..4209ecaca30647db6ea50cc2ceb4ad2d8e07aa92 GIT binary patch literal 4663 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 literal 0 HcmV?d00001 From 963106f8456ad5aa44cfb1ab58ddaf219111d9ab Mon Sep 17 00:00:00 2001 From: Chap Ambrose <cambrose@salesforce.com> Date: Wed, 24 Jul 2024 15:05:07 -0500 Subject: [PATCH 412/416] fix typo in heroku docs Signed-off-by: Chap Ambrose <cambrose@salesforce.com> --- docs/deployment/heroku.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/deployment/heroku.md b/docs/deployment/heroku.md index d285e4b397..51d0b4b439 100644 --- a/docs/deployment/heroku.md +++ b/docs/deployment/heroku.md @@ -104,7 +104,7 @@ heroku open -a <your-app> View logs: ```shell -heroku heroku -a <your-app> +heroku logs -a <your-app> ``` ## Docker From 51240ee9f790a9a54e851b8e359faf8dd470ce85 Mon Sep 17 00:00:00 2001 From: Thomas Cardonne <thomas.cardonne@adevinta.com> Date: Thu, 25 Jul 2024 00:18:15 +0200 Subject: [PATCH 413/416] fix(catalog-backend): preserve default allowedLocationTypes Signed-off-by: Thomas Cardonne <thomas.cardonne@adevinta.com> --- .changeset/odd-books-share.md | 5 +++++ plugins/catalog-backend/src/service/CatalogPlugin.ts | 10 ++++++---- 2 files changed, 11 insertions(+), 4 deletions(-) create mode 100644 .changeset/odd-books-share.md diff --git a/.changeset/odd-books-share.md b/.changeset/odd-books-share.md new file mode 100644 index 0000000000..858a2564ad --- /dev/null +++ b/.changeset/odd-books-share.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': patch +--- + +Preserve default `allowedLocationTypes` when `setAllowedLocationTypes()` of `CatalogLocationsExtensionPoint` is not called. diff --git a/plugins/catalog-backend/src/service/CatalogPlugin.ts b/plugins/catalog-backend/src/service/CatalogPlugin.ts index 2f5fd9103d..269100e586 100644 --- a/plugins/catalog-backend/src/service/CatalogPlugin.ts +++ b/plugins/catalog-backend/src/service/CatalogPlugin.ts @@ -46,7 +46,7 @@ import { ForwardedError } from '@backstage/errors'; class CatalogLocationsExtensionPointImpl implements CatalogLocationsExtensionPoint { - #locationTypes = new Array<string>(); + #locationTypes: string[] | undefined; setAllowedLocationTypes(locationTypes: Array<string>) { this.#locationTypes = locationTypes; @@ -293,9 +293,11 @@ export const catalogPlugin = createBackendPlugin({ builder.addPermissionRules(...permissionExtensions.permissionRules); builder.setFieldFormatValidators(modelExtensions.fieldValidators); - builder.setAllowedLocationTypes( - locationTypeExtensions.allowedLocationTypes, - ); + if (locationTypeExtensions.allowedLocationTypes) { + builder.setAllowedLocationTypes( + locationTypeExtensions.allowedLocationTypes, + ); + } const { processingEngine, router } = await builder.build(); From 7e5c374cfeb1161a99ab4467e267cf3faf2dea23 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 25 Jul 2024 09:00:53 +0000 Subject: [PATCH 414/416] chore(deps): update github/codeql-action action to v3.25.14 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/scorecard.yml | 2 +- .github/workflows/sync_snyk-monitor.yml | 2 +- .github/workflows/verify_codeql.yml | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index ecf18d71ad..354a76760b 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -67,6 +67,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: 'Upload to code-scanning' - uses: github/codeql-action/upload-sarif@23acc5c183826b7a8a97bce3cecc52db901f8251 # v3.25.10 + uses: github/codeql-action/upload-sarif@5cf07d8b700b67e235fbb65cbc84f69c0cf10464 # v3.25.14 with: sarif_file: results.sarif diff --git a/.github/workflows/sync_snyk-monitor.yml b/.github/workflows/sync_snyk-monitor.yml index b1e50397ce..44699964a6 100644 --- a/.github/workflows/sync_snyk-monitor.yml +++ b/.github/workflows/sync_snyk-monitor.yml @@ -58,6 +58,6 @@ jobs: SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} NODE_OPTIONS: --max-old-space-size=7168 - name: Upload Snyk report - uses: github/codeql-action/upload-sarif@23acc5c183826b7a8a97bce3cecc52db901f8251 # v3.25.10 + uses: github/codeql-action/upload-sarif@5cf07d8b700b67e235fbb65cbc84f69c0cf10464 # v3.25.14 with: sarif_file: snyk.sarif diff --git a/.github/workflows/verify_codeql.yml b/.github/workflows/verify_codeql.yml index e19187b6ce..b2fb2dc6ec 100644 --- a/.github/workflows/verify_codeql.yml +++ b/.github/workflows/verify_codeql.yml @@ -55,7 +55,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@23acc5c183826b7a8a97bce3cecc52db901f8251 # v3.25.10 + uses: github/codeql-action/init@5cf07d8b700b67e235fbb65cbc84f69c0cf10464 # v3.25.14 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -66,7 +66,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@23acc5c183826b7a8a97bce3cecc52db901f8251 # v3.25.10 + uses: github/codeql-action/autobuild@5cf07d8b700b67e235fbb65cbc84f69c0cf10464 # v3.25.14 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -80,4 +80,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@23acc5c183826b7a8a97bce3cecc52db901f8251 # v3.25.10 + uses: github/codeql-action/analyze@5cf07d8b700b67e235fbb65cbc84f69c0cf10464 # v3.25.14 From cc21fa8f4e599273357339eaaca378a840272754 Mon Sep 17 00:00:00 2001 From: Nishkarsh Raj <nishkarshraj000@gmail.com> Date: Thu, 25 Jul 2024 14:25:27 +0000 Subject: [PATCH 415/416] Making StatusNeo Partner logo consistent with color scheme Signed-off-by: Nishkarsh Raj <nishkarshraj000@gmail.com> --- .../static/img/partner-logo-statusneo.png | Bin 4663 -> 4396 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/microsite/static/img/partner-logo-statusneo.png b/microsite/static/img/partner-logo-statusneo.png index 4209ecaca30647db6ea50cc2ceb4ad2d8e07aa92..61a676a2207109feb905815cadd6735df1653f3a 100644 GIT binary patch literal 4396 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 SsCe!FmC)BV(n4w2hyM?ImwcB1 literal 4663 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 From 1383f4c98cb16ed97f1e5064b30beb94b934dcdf Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg <poldsberg@gmail.com> Date: Fri, 26 Jul 2024 10:04:55 +0200 Subject: [PATCH 416/416] Update .changeset/neat-bears-divide.md Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com> --- .changeset/neat-bears-divide.md | 27 ++------------------------- 1 file changed, 2 insertions(+), 25 deletions(-) diff --git a/.changeset/neat-bears-divide.md b/.changeset/neat-bears-divide.md index b40db6c7bd..a94b17f74d 100644 --- a/.changeset/neat-bears-divide.md +++ b/.changeset/neat-bears-divide.md @@ -1,28 +1,5 @@ --- -'@backstage/config-loader': major +'@backstage/config-loader': patch --- -**BREAKING** The `env` property on the `ConfigSourcesDefaultOptions` interface allows for undefined members. - -This change makes `ConfigSourcesDefaultOptions.env` consistent with other parts of this package and the wider -`node` ecosystem. Specifically, with this update `ConfigSourcesDefaultOptions.env`'s types match: - -#### EnvConfigSource - -- [`EnvConfigSource.constructor`](https://github.com/backstage/backstage/blob/c780320418b7775f18fc0d2cc279ee7db9c7cb25/packages/config-loader/src/sources/EnvConfigSource.ts#L68) -- [`EnvConfigSourceOptions`](https://github.com/backstage/backstage/blob/c780320418b7775f18fc0d2cc279ee7db9c7cb25/packages/config-loader/src/sources/EnvConfigSource.ts#L31) -- [`readEnvConfig`](https://github.com/backstage/backstage/blob/c780320418b7775f18fc0d2cc279ee7db9c7cb25/packages/config-loader/src/sources/EnvConfigSource.ts#L114) - -#### NodeJS process.env - -- [`ProcessEnv`](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/aa121ee3a7a3caa16433b66c1103df5904f612ea/types/node/v18/process.d.ts#L137) - which extends [`Dict`](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/aa121ee3a7a3caa16433b66c1103df5904f612ea/types/node/v18/globals.d.ts#L333-L335) - -While this is a somewhat trivial change, it does loosen typings on a public interface, so by definition it's a breaking -change and a major version bump. - -You may meed to update your backstage instance if you have built an implementation of `ConfigSources` or any other -functionality that relies on `ConfigSourcesDefaultOptions`. This change means you'll have to update that code to account -for the possibility of `undefined` values inside `ConfigSourcesDefaultOptions.env`, although it is very likely already -accounted for as the typings for [`process.env`](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/aa121ee3a7a3caa16433b66c1103df5904f612ea/types/node/v18/process.d.ts#L137) -already include the possibility of [`undefined`](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/aa121ee3a7a3caa16433b66c1103df5904f612ea/types/node/v18/globals.d.ts#L333-L335). +The `env` option of `ConfigSources.default` now correctly allows undefined members.